diff --git a/ble/BLE.h b/ble/BLE.h new file mode 100644 index 0000000..6eba551 --- /dev/null +++ b/ble/BLE.h @@ -0,0 +1,1342 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLE_H__ +#define __BLE_H__ + +#include "blecommon.h" +#include "Gap.h" +#include "GattServer.h" +#include "GattClient.h" +#include "BLEInstanceBase.h" + +/** + * The base class used to abstract away BLE capable radio transceivers or SOCs, + * to enable this BLE API to work with any radio transparently. + */ +class BLE +{ +public: + /** + * Initialize the BLE controller. This should be called before using + * anything else in the BLE_API. + * + * init() hands control to the underlying BLE module to accomplish + * initialization. This initialization may tacitly depend on other hardware + * setup (such as clocks or power-modes) which happens early on during + * system startup. It may not be safe to call init() from global static + * context where ordering is compiler specific and can't be guaranteed--it + * is safe to call BLE::init() from within main(). + */ + ble_error_t init(); + + /** + * Purge the BLE stack of GATT and GAP state. init() must be called + * afterwards to re-instate services and GAP state. This API offers a way to + * repopulate the GATT database with new services and characteristics. + */ + ble_error_t shutdown(void) { + clearAdvertisingPayload(); + return transport->shutdown(); + } + + /** + * This call allows the application to get the BLE stack version information. + * + * @return A pointer to a const string representing the version. + * Note: The string is owned by the BLE_API. + */ + const char *getVersion(void) { + return transport->getVersion(); + } + + /* + * Accessors to GAP. Please refer to Gap.h. All GAP related functionality requires + * going through this accessor. + */ + const Gap &gap() const { + return transport->getGap(); + } + Gap &gap() { + return transport->getGap(); + } + + /* + * Accessors to GATT Server. Please refer to GattServer.h. All GATTServer related + * functionality requires going through this accessor. + */ + const GattServer& gattServer() const { + return transport->getGattServer(); + } + GattServer& gattServer() { + return transport->getGattServer(); + } + + /* + * Accessors to GATT Client. Please refer to GattClient.h. All GATTClient related + * functionality requires going through this accessor. + */ + const GattClient& gattClient() const { + return transport->getGattClient(); + } + GattClient& gattClient() { + return transport->getGattClient(); + } + + /* + * Accessors to Security Manager. Please refer to SecurityManager.h. All + * SecurityManager related functionality requires going through this + * accessor. + */ + const SecurityManager& securityManager() const { + return transport->getSecurityManager(); + } + SecurityManager& securityManager() { + return transport->getSecurityManager(); + } + + /** + * Yield control to the BLE stack or to other tasks waiting for events. This + * is a sleep function which will return when there is an application + * specific interrupt, but the MCU might wake up several times before + * returning (to service the stack). This is not always interchangeable with + * WFE(). + */ + void waitForEvent(void) { + transport->waitForEvent(); + } + + /* + * Deprecation alert! + * All of the following are deprecated and may be dropped in a future + * release. Documentation should refer to alternative APIs. + */ + + /* GAP specific APIs. */ +public: + /** + * Set the BTLE MAC address and type. + * @return BLE_ERROR_NONE on success. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAddress(...) should be replaced with + * ble.gap().setAddress(...). + */ + ble_error_t setAddress(Gap::AddressType_t type, const Gap::Address_t address) { + return gap().setAddress(type, address); + } + + /** + * Fetch the BTLE MAC address and type. + * @return BLE_ERROR_NONE on success. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getAddress(...) should be replaced with + * ble.gap().getAddress(...). + */ + ble_error_t getAddress(Gap::AddressType_t *typeP, Gap::Address_t address) { + return gap().getAddress(typeP, address); + } + + /** + * Set the GAP advertising mode to use for this device. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAdvertisingType(...) should be replaced with + * ble.gap().setAdvertisingType(...). + */ + void setAdvertisingType(GapAdvertisingParams::AdvertisingType advType) { + gap().setAdvertisingType(advType); + } + + /** + * @param[in] interval + * Advertising interval in units of milliseconds. Advertising + * is disabled if interval is 0. If interval is smaller than + * the minimum supported value, then the minimum supported + * value is used instead. This minimum value can be discovered + * using getMinAdvertisingInterval(). + * + * This field must be set to 0 if connectionMode is equal + * to ADV_CONNECTABLE_DIRECTED. + * + * @note: Decreasing this value will allow central devices to detect a + * peripheral faster at the expense of more power being used by the radio + * due to the higher data transmit rate. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAdvertisingInterval(...) should be replaced with + * ble.gap().setAdvertisingInterval(...). + * + * @note: [WARNING] This API previously used 0.625ms as the unit for its + * 'interval' argument. That required an explicit conversion from + * milliseconds using Gap::MSEC_TO_GAP_DURATION_UNITS(). This conversion is + * no longer required as the new units are milliseconds. Any application + * code depending on the old semantics would need to be updated accordingly. + */ + void setAdvertisingInterval(uint16_t interval) { + gap().setAdvertisingInterval(interval); + } + + /** + * @return Minimum Advertising interval in milliseconds. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getMinAdvertisingInterval(...) should be replaced with + * ble.gap().getMinAdvertisingInterval(...). + */ + uint16_t getMinAdvertisingInterval(void) const { + return gap().getMinAdvertisingInterval(); + } + + /** + * @return Minimum Advertising interval in milliseconds for non-connectible mode. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getMinNonConnectableAdvertisingInterval(...) should be replaced with + * ble.gap().getMinNonConnectableAdvertisingInterval(...). + */ + uint16_t getMinNonConnectableAdvertisingInterval(void) const { + return gap().getMinNonConnectableAdvertisingInterval(); + } + + /** + * @return Maximum Advertising interval in milliseconds. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getMaxAdvertisingInterval(...) should be replaced with + * ble.gap().getMaxAdvertisingInterval(...). + */ + uint16_t getMaxAdvertisingInterval(void) const { + return gap().getMaxAdvertisingInterval(); + } + + /** + * @param[in] timeout + * Advertising timeout (in seconds) between 0x1 and 0x3FFF (1 + * and 16383). Use 0 to disable the advertising timeout. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAdvertisingTimeout(...) should be replaced with + * ble.gap().setAdvertisingTimeout(...). + */ + void setAdvertisingTimeout(uint16_t timeout) { + gap().setAdvertisingTimeout(timeout); + } + + /** + * Setup a particular, user-constructed set of advertisement parameters for + * the underlying stack. It would be uncommon for this API to be used + * directly; there are other APIs to tweak advertisement parameters + * individually (see above). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAdvertisingParams(...) should be replaced with + * ble.gap().setAdvertisingParams(...). + */ + void setAdvertisingParams(const GapAdvertisingParams &advParams) { + gap().setAdvertisingParams(advParams); + } + + /** + * @return Read back advertising parameters. Useful for storing and + * restoring parameters rapidly. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getAdvertisingParams(...) should be replaced with + * ble.gap().getAdvertisingParams(...). + */ + const GapAdvertisingParams &getAdvertisingParams(void) const { + return gap().getAdvertisingParams(); + } + + /** + * Accumulate an AD structure in the advertising payload. Please note that + * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used + * as an additional 31 bytes if the advertising payload proves to be too + * small. + * + * @param[in] flags + * The flags to be added. Please refer to + * GapAdvertisingData::Flags for valid flags. Multiple + * flags may be specified in combination. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.accumulateAdvertisingPayload(flags) should be replaced with + * ble.gap().accumulateAdvertisingPayload(flags). + */ + ble_error_t accumulateAdvertisingPayload(uint8_t flags) { + return gap().accumulateAdvertisingPayload(flags); + } + + /** + * Accumulate an AD structure in the advertising payload. Please note that + * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used + * as an additional 31 bytes if the advertising payload proves to be too + * small. + * + * @param[in] app + * The appearance of the peripheral. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.accumulateAdvertisingPayload(appearance) should be replaced with + * ble.gap().accumulateAdvertisingPayload(appearance). + */ + ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::Appearance app) { + return gap().accumulateAdvertisingPayload(app); + } + + /** + * Accumulate an AD structure in the advertising payload. Please note that + * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used + * as an additional 31 bytes if the advertising payload proves to be too + * small. + * + * @param[in] app + * The max transmit power to be used by the controller. This + * is only a hint. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.accumulateAdvertisingPayloadTxPower(txPower) should be replaced with + * ble.gap().accumulateAdvertisingPayloadTxPower(txPower). + */ + ble_error_t accumulateAdvertisingPayloadTxPower(int8_t power) { + return gap().accumulateAdvertisingPayloadTxPower(power); + } + + /** + * Accumulate a variable length byte-stream as an AD structure in the + * advertising payload. Please note that the payload is limited to 31 bytes. + * The SCAN_RESPONSE message may be used as an additional 31 bytes if the + * advertising payload proves to be too small. + * + * @param type The type which describes the variable length data. + * @param data data bytes. + * @param len length of data. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.accumulateAdvertisingPayload(...) should be replaced with + * ble.gap().accumulateAdvertisingPayload(...). + */ + ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) { + return gap().accumulateAdvertisingPayload(type, data, len); + } + + /** + * Setup a particular, user-constructed advertisement payload for the + * underlying stack. It would be uncommon for this API to be used directly; + * there are other APIs to build an advertisement payload (see above). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAdvertisingData(...) should be replaced with + * ble.gap().setAdvertisingPayload(...). + */ + ble_error_t setAdvertisingData(const GapAdvertisingData &advData) { + return gap().setAdvertisingPayload(advData); + } + + /** + * @return Read back advertising data. Useful for storing and + * restoring payload. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getAdvertisingData(...) should be replaced with + * ble.gap().getAdvertisingPayload()(...). + */ + const GapAdvertisingData &getAdvertisingData(void) const { + return gap().getAdvertisingPayload(); + } + + /** + * Reset any advertising payload prepared from prior calls to + * accumulateAdvertisingPayload(). This automatically propagates the re- + * initialized adv payload to the underlying stack. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.clearAdvertisingPayload(...) should be replaced with + * ble.gap().clearAdvertisingPayload(...). + */ + void clearAdvertisingPayload(void) { + gap().clearAdvertisingPayload(); + } + + /** + * This API is *deprecated* and resolves to a no-operation. It is left here + * to allow older code to compile. Please avoid using this API in new code. + * This API will be dropped in a future release. + * + * Formerly, it would be used to dynamically reset the accumulated advertising + * payload and scanResponse; to do this, the application would clear and re- + * accumulate a new advertising payload (and scanResponse) before using this + * API. Updates to the underlying advertisement payload now happen + * implicitly. + */ + ble_error_t setAdvertisingPayload(void) { + return BLE_ERROR_NONE; + } + + /** + * Accumulate a variable length byte-stream as an AD structure in the + * scanResponse payload. + * + * @param[in] type The type which describes the variable length data. + * @param[in] data data bytes. + * @param[in] len length of data. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.accumulateScanResponse(...) should be replaced with + * ble.gap().accumulateScanResponse(...). + */ + ble_error_t accumulateScanResponse(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) { + return gap().accumulateScanResponse(type, data, len); + } + + /** + * Reset any scan response prepared from prior calls to + * accumulateScanResponse(). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.clearScanResponse(...) should be replaced with + * ble.gap().clearScanResponse(...). + */ + void clearScanResponse(void) { + gap().clearScanResponse(); + } + + /** + * Start advertising. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.startAdvertising(...) should be replaced with + * ble.gap().startAdvertising(...). + */ + ble_error_t startAdvertising(void) { + return gap().startAdvertising(); + } + + /** + * Stop advertising. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.stopAdvertising(...) should be replaced with + * ble.gap().stopAdvertising(...). + */ + ble_error_t stopAdvertising(void) { + return gap().stopAdvertising(); + } + + /** + * Setup parameters for GAP scanning--i.e. observer mode. + * @param[in] interval + * Scan interval (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * @param[in] window + * Scan Window (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * @param[in] timeout + * Scan timeout (in seconds) between 0x0001 and 0xFFFF, 0x0000 disables timeout. + * @param[in] activeScanning + * Set to True if active-scanning is required. This is used to fetch the + * scan response from a peer if possible. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + * + * @Note: The scan interval and window are recommendations to the BLE stack. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setScanParams(...) should be replaced with + * ble.gap().setScanParams(...). + */ + ble_error_t setScanParams(uint16_t interval = GapScanningParams::SCAN_INTERVAL_MAX, + uint16_t window = GapScanningParams::SCAN_WINDOW_MAX, + uint16_t timeout = 0, + bool activeScanning = false) { + return gap().setScanParams(interval, window, timeout, activeScanning); + } + + /** + * Setup the scanInterval parameter for GAP scanning--i.e. observer mode. + * @param[in] interval + * Scan interval (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setScanInterval(interval) should be replaced with + * ble.gap().setScanInterval(interval). + */ + ble_error_t setScanInterval(uint16_t interval) { + return gap().setScanInterval(interval); + } + + /** + * Setup the scanWindow parameter for GAP scanning--i.e. observer mode. + * @param[in] window + * Scan Window (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setScanWindow(window) should be replaced with + * ble.gap().setScanWindow(window). + */ + ble_error_t setScanWindow(uint16_t window) { + return gap().setScanWindow(window); + } + + /** + * Setup parameters for GAP scanning--i.e. observer mode. + * @param[in] timeout + * Scan timeout (in seconds) between 0x0001 and 0xFFFF, 0x0000 disables timeout. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + * + * @Note: The scan interval and window are recommendations to the BLE stack. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setScanTimeout(...) should be replaced with + * ble.gap().setScanTimeout(...). + */ + ble_error_t setScanTimeout(uint16_t timeout) { + return gap().setScanTimeout(timeout); + } + + /** + * Setup parameters for GAP scanning--i.e. observer mode. + * @param[in] activeScanning + * Set to True if active-scanning is required. This is used to fetch the + * scan response from a peer if possible. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setActiveScan(...) should be replaced with + * ble.gap().setActiveScanning(...). + */ + void setActiveScan(bool activeScanning) { + gap().setActiveScanning(activeScanning); + } + + /** + * Start scanning (Observer Procedure) based on the parameters currently in + * effect. + * + * @param[in] callback + * The application specific callback to be invoked upon + * receiving every advertisement report. This can be passed in + * as NULL, in which case scanning may not be enabled at all. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.startScan(callback) should be replaced with + * ble.gap().startScan(callback). + */ + ble_error_t startScan(void (*callback)(const Gap::AdvertisementCallbackParams_t *params)) { + return gap().startScan(callback); + } + + /** + * Same as above, but this takes an (object, method) pair for a callback. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.startScan(callback) should be replaced with + * ble.gap().startScan(object, callback). + */ + template + ble_error_t startScan(T *object, void (T::*memberCallback)(const Gap::AdvertisementCallbackParams_t *params)); + + /** + * Stop scanning. The current scanning parameters remain in effect. + * + * @retval BLE_ERROR_NONE if successfully stopped scanning procedure. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.stopScan() should be replaced with + * ble.gap().stopScan(). + */ + ble_error_t stopScan(void) { + return gap().stopScan(); + } + + /** + * Create a connection (GAP Link Establishment). + * @param peerAddr + * 48-bit address, LSB format. + * @param peerAddrType + * Address type of the peer. + * @param connectionParams + * Connection parameters. + * @param scanParams + * Paramters to be used while scanning for the peer. + * @return BLE_ERROR_NONE if connection establishment procedure is started + * successfully. The onConnection callback (if set) will be invoked upon + * a connection event. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.connect(...) should be replaced with + * ble.gap().connect(...). + */ + ble_error_t connect(const Gap::Address_t peerAddr, + Gap::AddressType_t peerAddrType = Gap::ADDR_TYPE_RANDOM_STATIC, + const Gap::ConnectionParams_t *connectionParams = NULL, + const GapScanningParams *scanParams = NULL) { + return gap().connect(peerAddr, peerAddrType, connectionParams, scanParams); + } + + /** + * This call initiates the disconnection procedure, and its completion will + * be communicated to the application with an invocation of the + * onDisconnection callback. + * + * @param[in] connectionHandle + * @param[in] reason + * The reason for disconnection to be sent back to the peer. + */ + ble_error_t disconnect(Gap::Handle_t connectionHandle, Gap::DisconnectionReason_t reason) { + return gap().disconnect(connectionHandle, reason); + } + + /** + * This call initiates the disconnection procedure, and its completion will + * be communicated to the application with an invocation of the + * onDisconnection callback. + * + * @param reason + * The reason for disconnection to be sent back to the peer. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.disconnect(reason) should be replaced with + * ble.gap().disconnect(reason). + * + * @note: this version of disconnect() doesn't take a connection handle. It + * will work reliably only for stacks which are limited to a single + * connection. This API should be considered *deprecated* in favour of the + * alternative which takes a connection handle. It will be dropped in the future. + */ + ble_error_t disconnect(Gap::DisconnectionReason_t reason) { + return gap().disconnect(reason); + } + + /** + * Returns the current GAP state of the device using a bitmask which + * describes whether the device is advertising and/or connected. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getGapState() should be replaced with + * ble.gap().getState(). + */ + Gap::GapState_t getGapState(void) const { + return gap().getState(); + } + + /** + * Get the GAP peripheral preferred connection parameters. These are the + * defaults that the peripheral would like to have in a connection. The + * choice of the connection parameters is eventually up to the central. + * + * @param[out] params + * The structure where the parameters will be stored. Memory + * for this is owned by the caller. + * + * @return BLE_ERROR_NONE if the parameters were successfully filled into + * the given structure pointed to by params. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getPreferredConnectionParams() should be replaced with + * ble.gap().getPreferredConnectionParams(). + */ + ble_error_t getPreferredConnectionParams(Gap::ConnectionParams_t *params) { + return gap().getPreferredConnectionParams(params); + } + + /** + * Set the GAP peripheral preferred connection parameters. These are the + * defaults that the peripheral would like to have in a connection. The + * choice of the connection parameters is eventually up to the central. + * + * @param[in] params + * The structure containing the desired parameters. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setPreferredConnectionParams() should be replaced with + * ble.gap().setPreferredConnectionParams(). + */ + ble_error_t setPreferredConnectionParams(const Gap::ConnectionParams_t *params) { + return gap().setPreferredConnectionParams(params); + } + + /** + * Update connection parameters while in the peripheral role. + * @details In the peripheral role, this will send the corresponding L2CAP request to the connected peer and wait for + * the central to perform the procedure. + * @param[in] handle + * Connection Handle + * @param[in] params + * Pointer to desired connection parameters. If NULL is provided on a peripheral role, + * the parameters in the PPCP characteristic of the GAP service will be used instead. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.updateConnectionParams() should be replaced with + * ble.gap().updateConnectionParams(). + */ + ble_error_t updateConnectionParams(Gap::Handle_t handle, const Gap::ConnectionParams_t *params) { + return gap().updateConnectionParams(handle, params); + } + + /** + * Set the device name characteristic in the GAP service. + * @param[in] deviceName + * The new value for the device-name. This is a UTF-8 encoded, NULL-terminated string. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setDeviceName() should be replaced with + * ble.gap().setDeviceName(). + */ + ble_error_t setDeviceName(const uint8_t *deviceName) { + return gap().setDeviceName(deviceName); + } + + /** + * Get the value of the device name characteristic in the GAP service. + * @param[out] deviceName + * Pointer to an empty buffer where the UTF-8 *non NULL- + * terminated* string will be placed. Set this + * value to NULL in order to obtain the deviceName-length + * from the 'length' parameter. + * + * @param[in/out] lengthP + * (on input) Length of the buffer pointed to by deviceName; + * (on output) the complete device name length (without the + * null terminator). + * + * @note If the device name is longer than the size of the supplied buffer, + * length will return the complete device name length, and not the + * number of bytes actually returned in deviceName. The application may + * use this information to retry with a suitable buffer size. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getDeviceName() should be replaced with + * ble.gap().getDeviceName(). + */ + ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP) { + return gap().getDeviceName(deviceName, lengthP); + } + + /** + * Set the appearance characteristic in the GAP service. + * @param[in] appearance + * The new value for the device-appearance. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAppearance() should be replaced with + * ble.gap().setAppearance(). + */ + ble_error_t setAppearance(GapAdvertisingData::Appearance appearance) { + return gap().setAppearance(appearance); + } + + /** + * Get the appearance characteristic in the GAP service. + * @param[out] appearance + * The new value for the device-appearance. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getAppearance() should be replaced with + * ble.gap().getAppearance(). + */ + ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP) { + return gap().getAppearance(appearanceP); + } + + /** + * Set the radio's transmit power. + * @param[in] txPower Radio transmit power in dBm. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setTxPower() should be replaced with + * ble.gap().setTxPower(). + */ + ble_error_t setTxPower(int8_t txPower) { + return gap().setTxPower(txPower); + } + + /** + * Query the underlying stack for permitted arguments for setTxPower(). + * + * @param[out] valueArrayPP + * Out parameter to receive the immutable array of Tx values. + * @param[out] countP + * Out parameter to receive the array's size. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.getPermittedTxPowerValues() should be replaced with + * ble.gap().getPermittedTxPowerValues(). + */ + void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) { + gap().getPermittedTxPowerValues(valueArrayPP, countP); + } + + /** + * Add a service declaration to the local server ATT table. Also add the + * characteristics contained within. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.addService() should be replaced with + * ble.gattServer().addService(). + */ + ble_error_t addService(GattService &service) { + return gattServer().addService(service); + } + + /** + * Read the value of a characteristic from the local GattServer + * @param[in] attributeHandle + * Attribute handle for the value attribute of the characteristic. + * @param[out] buffer + * A buffer to hold the value being read. + * @param[in/out] lengthP + * Length of the buffer being supplied. If the attribute + * value is longer than the size of the supplied buffer, + * this variable will hold upon return the total attribute value length + * (excluding offset). The application may use this + * information to allocate a suitable buffer size. + * + * @return BLE_ERROR_NONE if a value was read successfully into the buffer. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.readCharacteristicValue() should be replaced with + * ble.gattServer().read(). + */ + ble_error_t readCharacteristicValue(GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) { + return gattServer().read(attributeHandle, buffer, lengthP); + } + + /** + * Read the value of a characteristic from the local GattServer + * @param[in] connectionHandle + * Connection Handle. + * @param[in] attributeHandle + * Attribute handle for the value attribute of the characteristic. + * @param[out] buffer + * A buffer to hold the value being read. + * @param[in/out] lengthP + * Length of the buffer being supplied. If the attribute + * value is longer than the size of the supplied buffer, + * this variable will hold upon return the total attribute value length + * (excluding offset). The application may use this + * information to allocate a suitable buffer size. + * + * @return BLE_ERROR_NONE if a value was read successfully into the buffer. + * + * @note This API is a version of above with an additional connection handle + * parameter to allow fetches for connection-specific multivalued + * attribtues (such as the CCCDs). + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.readCharacteristicValue() should be replaced with + * ble.gattServer().read(). + */ + ble_error_t readCharacteristicValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) { + return gattServer().read(connectionHandle, attributeHandle, buffer, lengthP); + } + + /** + * Update the value of a characteristic on the local GattServer. + * + * @param[in] attributeHandle + * Handle for the value attribute of the Characteristic. + * @param[in] value + * A pointer to a buffer holding the new value + * @param[in] size + * Size of the new value (in bytes). + * @param[in] localOnly + * Should this update be kept on the local + * GattServer regardless of the state of the + * notify/indicate flag in the CCCD for this + * Characteristic? If set to true, no notification + * or indication is generated. + * + * @return BLE_ERROR_NONE if we have successfully set the value of the attribute. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.updateCharacteristicValue() should be replaced with + * ble.gattServer().write(). + */ + ble_error_t updateCharacteristicValue(GattAttribute::Handle_t attributeHandle, + const uint8_t *value, + uint16_t size, + bool localOnly = false) { + return gattServer().write(attributeHandle, value, size, localOnly); + } + + /** + * Update the value of a characteristic on the local GattServer. A version + * of the same as above with connection handle parameter to allow updates + * for connection-specific multivalued attribtues (such as the CCCDs). + * + * @param[in] connectionHandle + * Connection Handle. + * @param[in] attributeHandle + * Handle for the value attribute of the Characteristic. + * @param[in] value + * A pointer to a buffer holding the new value + * @param[in] size + * Size of the new value (in bytes). + * @param[in] localOnly + * Should this update be kept on the local + * GattServer regardless of the state of the + * notify/indicate flag in the CCCD for this + * Characteristic? If set to true, no notification + * or indication is generated. + * + * @return BLE_ERROR_NONE if we have successfully set the value of the attribute. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.updateCharacteristicValue() should be replaced with + * ble.gattServer().write(). + */ + ble_error_t updateCharacteristicValue(Gap::Handle_t connectionHandle, + GattAttribute::Handle_t attributeHandle, + const uint8_t *value, + uint16_t size, + bool localOnly = false) { + return gattServer().write(connectionHandle, attributeHandle, value, size, localOnly); + } + + /** + * Enable the BLE stack's Security Manager. The Security Manager implements + * the actual cryptographic algorithms and protocol exchanges that allow two + * devices to securely exchange data and privately detect each other. + * Calling this API is a prerequisite for encryption and pairing (bonding). + * + * @param[in] enableBonding Allow for bonding. + * @param[in] requireMITM Require protection for man-in-the-middle attacks. + * @param[in] iocaps To specify IO capabilities of this peripheral, + * such as availability of a display or keyboard to + * support out-of-band exchanges of security data. + * @param[in] passkey To specify a static passkey. + * + * @return BLE_ERROR_NONE on success. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.initializeSecurity(...) should be replaced with + * ble.securityManager().init(...). + */ + ble_error_t initializeSecurity(bool enableBonding = true, + bool requireMITM = true, + SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE, + const SecurityManager::Passkey_t passkey = NULL) { + return securityManager().init(enableBonding, requireMITM, iocaps, passkey); + } + + /** + * Get the security status of a connection. + * + * @param[in] connectionHandle Handle to identify the connection. + * @param[out] securityStatusP security status. + * + * @return BLE_SUCCESS Or appropriate error code indicating reason for failure. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.getLinkSecurity(...) should be replaced with + * ble.securityManager().getLinkSecurity(...). + */ + ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP) { + return securityManager().getLinkSecurity(connectionHandle, securityStatusP); + } + + /** + * Delete all peer device context and all related bonding information from + * the database within the security manager. + * + * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure. + * @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization and/or + * application registration. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.purgeAllBondingState() should be replaced with + * ble.securityManager().purgeAllBondingState(). + */ + ble_error_t purgeAllBondingState(void) { + return securityManager().purgeAllBondingState(); + } + + /** + * Setup a callback for timeout events. Refer to Gap::TimeoutSource_t for + * possible event types. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onTimeout(callback) should be replaced with + * ble.gap().onTimeout(callback). + */ + void onTimeout(Gap::TimeoutEventCallback_t timeoutCallback) { + gap().onTimeout(timeoutCallback); + } + + /** + * Setup a callback for connection events. Refer to Gap::ConnectionEventCallback_t. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onConnection(callback) should be replaced with + * ble.gap().onConnection(callback). + */ + void onConnection(Gap::ConnectionEventCallback_t connectionCallback) { + gap().onConnection(connectionCallback); + } + + /** + * Used to setup a callback for GAP disconnection. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onDisconnection(callback) should be replaced with + * ble.gap().onDisconnection(callback). + */ + void onDisconnection(Gap::DisconnectionEventCallback_t disconnectionCallback) { + gap().onDisconnection(disconnectionCallback); + } + + /** + * Append to a chain of callbacks to be invoked upon disconnection; these + * callbacks receive no context and are therefore different from the + * onDisconnection callback. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.addToDisconnectionCallchain(...) should be replaced with + * ble.gap().addToDisconnectionCallchain(...). + */ + template + void addToDisconnectionCallChain(T *tptr, void (T::*mptr)(void)) { + gap().addToDisconnectionCallChain(tptr, mptr); + } + + /** + * Radio Notification is a feature that enables ACTIVE and INACTIVE + * (nACTIVE) signals from the stack that notify the application when the + * radio is in use. The signal is sent using software interrupt. + * + * The ACTIVE signal is sent before the Radio Event starts. The nACTIVE + * signal is sent at the end of the Radio Event. These signals can be used + * by the application programmer to synchronize application logic with radio + * activity. For example, the ACTIVE signal can be used to shut off external + * devices to manage peak current drawn during periods when the radio is on, + * or to trigger sensor data collection for transmission in the Radio Event. + * + * @param callback + * The application handler to be invoked in response to a radio + * ACTIVE/INACTIVE event. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onRadioNotification(...) should be replaced with + * ble.gap().onRadioNotification(...). + */ + void onRadioNotification(Gap::RadioNotificationEventCallback_t callback) { + gap().onRadioNotification(callback); + } + + /** + * Add a callback for the GATT event DATA_SENT (which is triggered when + * updates are sent out by GATT in the form of notifications). + * + * @Note: it is possible to chain together multiple onDataSent callbacks + * (potentially from different modules of an application) to receive updates + * to characteristics. + * + * @Note: it is also possible to setup a callback into a member function of + * some object. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onDataSent(...) should be replaced with + * ble.gattServer().onDataSent(...). + */ + void onDataSent(void (*callback)(unsigned count)) { + gattServer().onDataSent(callback); + } + template void onDataSent(T * objPtr, void (T::*memberPtr)(unsigned count)) { + gattServer().onDataSent(objPtr, memberPtr); + } + + /** + * Setup a callback for when an attribute has its value updated by or at the + * connected peer. For a peripheral, this callback triggered when the local + * GATT server has an attribute updated by a write command from the peer. + * For a Central, this callback is triggered when a response is received for + * a write request. + * + * @Note: it is possible to chain together multiple onDataWritten callbacks + * (potentially from different modules of an application) to receive updates + * to characteristics. Many services, such as DFU and UART add their own + * onDataWritten callbacks behind the scenes to trap interesting events. + * + * @Note: it is also possible to setup a callback into a member function of + * some object. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onDataWritten(...) should be replaced with + * ble.gattServer().onDataWritten(...). + */ + void onDataWritten(void (*callback)(const GattWriteCallbackParams *eventDataP)) { + gattServer().onDataWritten(callback); + } + template void onDataWritten(T * objPtr, void (T::*memberPtr)(const GattWriteCallbackParams *context)) { + gattServer().onDataWritten(objPtr, memberPtr); + } + + /** + * Setup a callback to be invoked on the peripheral when an attribute is + * being read by a remote client. + * + * @Note: this functionality may not be available on all underlying stacks. + * You could use GattCharacteristic::setReadAuthorizationCallback() as an + * alternative. + * + * @Note: it is possible to chain together multiple onDataRead callbacks + * (potentially from different modules of an application) to receive updates + * to characteristics. Services may add their own onDataRead callbacks + * behind the scenes to trap interesting events. + * + * @Note: it is also possible to setup a callback into a member function of + * some object. + * + * @return BLE_ERROR_NOT_IMPLEMENTED if this functionality isn't available; + * else BLE_ERROR_NONE. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onDataRead(...) should be replaced with + * ble.gattServer().onDataRead(...). + */ + ble_error_t onDataRead(void (*callback)(const GattReadCallbackParams *eventDataP)) { + return gattServer().onDataRead(callback); + } + template ble_error_t onDataRead(T * objPtr, void (T::*memberPtr)(const GattReadCallbackParams *context)) { + return gattServer().onDataRead(objPtr, memberPtr); + } + + /** + * Setup a callback for when notifications/indications are enabled for a + * characteristic on the local GattServer. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onUpdatesEnabled(callback) should be replaced with + * ble.gattServer().onUpdatesEnabled(callback). + */ + void onUpdatesEnabled(GattServer::EventCallback_t callback) { + gattServer().onUpdatesEnabled(callback); + } + + /** + * Setup a callback for when notifications/indications are disabled for a + * characteristic on the local GattServer. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onUpdatesEnabled(callback) should be replaced with + * ble.gattServer().onUpdatesEnabled(callback). + */ + void onUpdatesDisabled(GattServer::EventCallback_t callback) { + gattServer().onUpdatesDisabled(callback); + } + + /** + * Setup a callback for when the GATT server receives a response for an + * indication event sent previously. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from GattServer directly. A former call + * to ble.onConfirmationReceived(callback) should be replaced with + * ble.gattServer().onConfirmationReceived(callback). + */ + void onConfirmationReceived(GattServer::EventCallback_t callback) { + gattServer().onConfirmationReceived(callback); + } + + /** + * Setup a callback for when the security setup procedure (key generation + * and exchange) for a link has started. This will be skipped for bonded + * devices. The callback is passed in parameters received from the peer's + * security request: bool allowBonding, bool requireMITM, and + * SecurityIOCapabilities_t. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.onSecuritySetupInitiated(callback) should be replaced with + * ble.securityManager().onSecuritySetupInitiated(callback). + */ + void onSecuritySetupInitiated(SecurityManager::SecuritySetupInitiatedCallback_t callback) { + securityManager().onSecuritySetupInitiated(callback); + } + + /** + * Setup a callback for when the security setup procedure (key generation + * and exchange) for a link has completed. This will be skipped for bonded + * devices. The callback is passed in the success/failure status of the + * security setup procedure. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.onSecuritySetupCompleted(callback) should be replaced with + * ble.securityManager().onSecuritySetupCompleted(callback). + */ + void onSecuritySetupCompleted(SecurityManager::SecuritySetupCompletedCallback_t callback) { + securityManager().onSecuritySetupCompleted(callback); + } + + /** + * Setup a callback for when a link with the peer is secured. For bonded + * devices, subsequent reconnections with bonded peer will result only in + * this callback when the link is secured and setup procedures will not + * occur unless the bonding information is either lost or deleted on either + * or both sides. The callback is passed in a SecurityManager::SecurityMode_t according + * to the level of security in effect for the secured link. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.onLinkSecured(callback) should be replaced with + * ble.securityManager().onLinkSecured(callback). + */ + void onLinkSecured(SecurityManager::LinkSecuredCallback_t callback) { + securityManager().onLinkSecured(callback); + } + + /** + * Setup a callback for successful bonding; i.e. that link-specific security + * context is stored persistently for a peer device. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.onSecurityContextStored(callback) should be replaced with + * ble.securityManager().onSecurityContextStored(callback). + */ + void onSecurityContextStored(SecurityManager::HandleSpecificEvent_t callback) { + securityManager().onSecurityContextStored(callback); + } + + /** + * Setup a callback for when the passkey needs to be displayed on a + * peripheral with DISPLAY capability. This happens when security is + * configured to prevent Man-In-The-Middle attacks, and a PIN (or passkey) + * needs to be exchanged between the peers to authenticate the connection + * attempt. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from SecurityManager directly. A former + * call to ble.onPasskeyDisplay(callback) should be replaced with + * ble.securityManager().onPasskeyDisplay(callback). + */ + void onPasskeyDisplay(SecurityManager::PasskeyDisplayCallback_t callback) { + return securityManager().onPasskeyDisplay(callback); + } + +public: + BLE() : transport(createBLEInstance()) { + /* empty */ + } + +private: + BLEInstanceBase *const transport; /* the device specific backend */ +}; + +typedef BLE BLEDevice; /* DEPRECATED. This type alias is retained for the sake of compatibility with older + * code. Will be dropped at some point soon.*/ + +#endif // ifndef __BLE_H__ diff --git a/common/BLEDeviceInstanceBase.h b/ble/BLEInstanceBase.h similarity index 51% rename from common/BLEDeviceInstanceBase.h rename to ble/BLEInstanceBase.h index 2d7f45f..db050f5 100644 --- a/common/BLEDeviceInstanceBase.h +++ b/ble/BLEInstanceBase.h @@ -17,36 +17,40 @@ #ifndef __BLE_DEVICE_INSTANCE_BASE__ #define __BLE_DEVICE_INSTANCE_BASE__ +#include "Gap.h" + +/* forward declarations */ +class GattServer; +class GattClient; + /** * The interface for the transport object to be created by the target library's - * createBLEDeviceInstance(). + * createBLEInstance(). */ -class BLEDeviceInstanceBase +class BLEInstanceBase { public: - virtual const char *getVersion(void) = 0; - virtual Gap& getGap() = 0; - virtual GattServer& getGattServer() = 0; - virtual ble_error_t init(void) = 0; - virtual ble_error_t shutdown(void) = 0; - virtual ble_error_t reset(void) = 0; - virtual ble_error_t initializeSecurity(bool enableBonding = true, - bool requireMITM = true, - Gap::SecurityIOCapabilities_t iocaps = Gap::IO_CAPS_NONE, - const Gap::Passkey_t passkey = NULL) = 0; - virtual ble_error_t setTxPower(int8_t txPower) = 0; - virtual void getPermittedTxPowerValues(const int8_t **, size_t *) = 0; + virtual ble_error_t init(void) = 0; + virtual ble_error_t shutdown(void) = 0; + virtual const char *getVersion(void) = 0; + virtual Gap& getGap() = 0; + virtual const Gap& getGap() const = 0; + virtual GattServer& getGattServer() = 0; + virtual const GattServer& getGattServer() const = 0; + virtual GattClient& getGattClient() = 0; + virtual SecurityManager& getSecurityManager() = 0; + virtual const SecurityManager& getSecurityManager() const = 0; virtual void waitForEvent(void) = 0; }; /** - * BLEDevice uses composition to hide an interface object encapsulating the + * BLE uses composition to hide an interface object encapsulating the * backend transport. * * The following API is used to create the singleton interface object. An * implementation for this function must be provided by the device-specific * library, otherwise there will be a linker error. */ -extern BLEDeviceInstanceBase *createBLEDeviceInstance(void); +extern BLEInstanceBase *createBLEInstance(void); #endif // ifndef __BLE_DEVICE_INSTANCE_BASE__ diff --git a/public/CallChainOfFunctionPointersWithContext.h b/ble/CallChainOfFunctionPointersWithContext.h similarity index 100% rename from public/CallChainOfFunctionPointersWithContext.h rename to ble/CallChainOfFunctionPointersWithContext.h diff --git a/ble/DiscoveredCharacteristic.h b/ble/DiscoveredCharacteristic.h new file mode 100644 index 0000000..eeb0936 --- /dev/null +++ b/ble/DiscoveredCharacteristic.h @@ -0,0 +1,191 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DISCOVERED_CHARACTERISTIC_H__ +#define __DISCOVERED_CHARACTERISTIC_H__ + +#include "UUID.h" +#include "Gap.h" +#include "GattAttribute.h" +#include "GattClient.h" + +/** + * Structure for holding information about the service and the characteristics + * found during the discovery process. + */ +class DiscoveredCharacteristic { +public: + struct Properties_t { + uint8_t _broadcast :1; /**< Broadcasting of the value permitted. */ + uint8_t _read :1; /**< Reading the value permitted. */ + uint8_t _writeWoResp :1; /**< Writing the value with Write Command permitted. */ + uint8_t _write :1; /**< Writing the value with Write Request permitted. */ + uint8_t _notify :1; /**< Notications of the value permitted. */ + uint8_t _indicate :1; /**< Indications of the value permitted. */ + uint8_t _authSignedWrite :1; /**< Writing the value with Signed Write Command permitted. */ + + public: + bool broadcast(void) const {return _broadcast; } + bool read(void) const {return _read; } + bool writeWoResp(void) const {return _writeWoResp; } + bool write(void) const {return _write; } + bool notify(void) const {return _notify; } + bool indicate(void) const {return _indicate; } + bool authSignedWrite(void) const {return _authSignedWrite;} + + private: + operator uint8_t() const; /* disallow implicit conversion into an integer */ + operator unsigned() const; /* disallow implicit conversion into an integer */ + }; + + /** + * Structure for holding information about the service and the characteristics + * found during the discovery process. + */ + struct DiscoveredDescriptor { + GattAttribute::Handle_t handle; /**< Descriptor Handle. */ + UUID uuid; /**< Descriptor UUID. */ + }; + + /** + * Callback type for when a characteristic descriptor is found during descriptor- + * discovery. The receiving function is passed in a pointer to a + * DiscoveredDescriptor object which will remain valid for the lifetime + * of the callback. Memory for this object is owned by the BLE_API eventing + * framework. The application can safely make a persistent shallow-copy of + * this object in order to work with the characteristic beyond the callback. + */ + typedef void (*DescriptorCallback_t)(const DiscoveredDescriptor *); + + /** + * Initiate (or continue) a read for the value attribute, optionally at a + * given offset. If the Characteristic or Descriptor to be read is longer + * than ATT_MTU - 1, this function must be called multiple times with + * appropriate offset to read the complete value. + * + * @return BLE_ERROR_NONE if a read has been initiated, else + * BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or + * BLE_STACK_BUSY if some client procedure already in progress, or + * BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties. + */ + ble_error_t read(uint16_t offset = 0) const; + + /** + * Perform a write without response procedure. + * + * @param length + * The amount of data being written. + * @param value + * The bytes being written. + * + * @note It is important to note that a write without response will generate + * an onDataSent() callback when the packet has been transmitted. There + * will be a BLE-stack specific limit to the number of pending + * writeWoResponse operations; the user may want to use the onDataSent() + * callback for flow-control. + * + * @retval BLE_ERROR_NONE Successfully started the Write procedure, else + * BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or + * BLE_STACK_BUSY if some client procedure already in progress, or + * BLE_ERROR_NO_MEM if there are no available buffers left to process the request, or + * BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties. + */ + ble_error_t writeWoResponse(uint16_t length, const uint8_t *value) const; + + /** + * Initiate a GATT Characteristic Descriptor Discovery procedure for descriptors within this characteristic. + * + * @param callback + * @param matchingUUID + * filter for descriptors. Defaults to wildcard which will discover all descriptors. + * + * @return BLE_ERROR_NONE if descriptor discovery is launched successfully; else an appropriate error. + */ + ble_error_t discoverDescriptors(DescriptorCallback_t callback, const UUID &matchingUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) const; + + /** + * Perform a write procedure. + * + * @param length + * The amount of data being written. + * @param value + * The bytes being written. + * + * @note It is important to note that a write will generate + * an onDataWritten() callback when the peer acknowledges the request. + * + * @retval BLE_ERROR_NONE Successfully started the Write procedure, else + * BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or + * BLE_STACK_BUSY if some client procedure already in progress, or + * BLE_ERROR_NO_MEM if there are no available buffers left to process the request, or + * BLE_ERROR_OPERATION_NOT_PERMITTED due to the characteristic's properties. + */ + ble_error_t write(uint16_t length, const uint8_t *value) const; + + static void setupOnDataRead(GattClient::ReadCallback_t callback) { + onDataReadCallback = callback; + } + + static void setupOnDataWrite(GattClient::WriteCallback_t callback) { + onDataWriteCallback = callback; + } + + void setupLongUUID(UUID::LongUUIDBytes_t longUUID) { + uuid.setupLong(longUUID); + } + +public: + UUID::ShortUUIDBytes_t getShortUUID(void) const { + return uuid.getShortUUID(); + } + + const Properties_t& getProperties(void) const { + return props; + } + + const GattAttribute::Handle_t& getDeclHandle(void) const { + return declHandle; + } + const GattAttribute::Handle_t& getValueHandle(void) const { + return valueHandle; + } + +public: + DiscoveredCharacteristic() : gattc(NULL), + uuid(UUID::ShortUUIDBytes_t(0)), + props(), + declHandle(GattAttribute::INVALID_HANDLE), + valueHandle(GattAttribute::INVALID_HANDLE) { + /* empty */ + } + +protected: + GattClient *gattc; + +protected: + UUID uuid; + Properties_t props; + GattAttribute::Handle_t declHandle; + GattAttribute::Handle_t valueHandle; + + Gap::Handle_t connHandle; + +public: + static GattClient::ReadCallback_t onDataReadCallback; + static GattClient::WriteCallback_t onDataWriteCallback; +}; + +#endif /*__DISCOVERED_CHARACTERISTIC_H__*/ diff --git a/ble/DiscoveredService.h b/ble/DiscoveredService.h new file mode 100644 index 0000000..1295a2d --- /dev/null +++ b/ble/DiscoveredService.h @@ -0,0 +1,71 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DISCOVERED_SERVICE_H__ +#define __DISCOVERED_SERVICE_H__ + +#include "UUID.h" +#include "GattAttribute.h" + +/**@brief Type for holding information about the service and the characteristics found during + * the discovery process. + */ +class DiscoveredService { +public: + void setup(UUID uuidIn, GattAttribute::Handle_t startHandleIn, GattAttribute::Handle_t endHandleIn) { + uuid = uuidIn; + startHandle = startHandleIn; + endHandle = endHandleIn; + } + + void setup(GattAttribute::Handle_t startHandleIn, GattAttribute::Handle_t endHandleIn) { + startHandle = startHandleIn; + endHandle = endHandleIn; + } + + void setupLongUUID(UUID::LongUUIDBytes_t longUUID) { + uuid.setupLong(longUUID); + } + +public: + const UUID &getUUID(void) const { + return uuid; + } + + const GattAttribute::Handle_t& getStartHandle(void) const { + return startHandle; + } + const GattAttribute::Handle_t& getEndHandle(void) const { + return endHandle; + } + +public: + DiscoveredService() : uuid(UUID::ShortUUIDBytes_t(0)), + startHandle(GattAttribute::INVALID_HANDLE), + endHandle(GattAttribute::INVALID_HANDLE) { + /* empty */ + } + +private: + DiscoveredService(const DiscoveredService &); + +private: + UUID uuid; /**< UUID of the service. */ + GattAttribute::Handle_t startHandle; /**< Service Handle Range. */ + GattAttribute::Handle_t endHandle; /**< Service Handle Range. */ +}; + +#endif /*__DISCOVERED_SERVICE_H__*/ diff --git a/public/FunctionPointerWithContext.h b/ble/FunctionPointerWithContext.h similarity index 100% rename from public/FunctionPointerWithContext.h rename to ble/FunctionPointerWithContext.h diff --git a/ble/Gap.h b/ble/Gap.h new file mode 100644 index 0000000..e18fa75 --- /dev/null +++ b/ble/Gap.h @@ -0,0 +1,886 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __GAP_H__ +#define __GAP_H__ + +#include "GapAdvertisingData.h" +#include "GapAdvertisingParams.h" +#include "GapScanningParams.h" +#include "GapEvents.h" +#include "CallChain.h" +#include "FunctionPointerWithContext.h" + +using namespace mbed; + +/* Forward declarations for classes which will only be used for pointers or references in the following. */ +class GapAdvertisingParams; +class GapScanningParams; +class GapAdvertisingData; + +class Gap { +public: + enum AddressType_t { + ADDR_TYPE_PUBLIC = 0, + ADDR_TYPE_RANDOM_STATIC, + ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE, + ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE + }; + typedef enum AddressType_t addr_type_t; /* @Note: deprecated. Use AddressType_t instead. */ + + static const unsigned ADDR_LEN = 6; + typedef uint8_t Address_t[ADDR_LEN]; /* 48-bit address, LSB format. */ + typedef Address_t address_t; /* @Note: deprecated. Use Address_t instead. */ + + enum TimeoutSource_t { + TIMEOUT_SRC_ADVERTISING = 0x00, /**< Advertising timeout. */ + TIMEOUT_SRC_SECURITY_REQUEST = 0x01, /**< Security request timeout. */ + TIMEOUT_SRC_SCAN = 0x02, /**< Scanning timeout. */ + TIMEOUT_SRC_CONN = 0x03, /**< Connection timeout. */ + }; + + /** + * Enumeration for disconnection reasons. The values for these reasons are + * derived from Nordic's implementation; but the reasons are meant to be + * independent of the transport. If you are returned a reason which is not + * covered by this enumeration, then please refer to the underlying + * transport library. + */ + enum DisconnectionReason_t { + CONNECTION_TIMEOUT = 0x08, + REMOTE_USER_TERMINATED_CONNECTION = 0x13, + REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES = 0x14, /**< Remote Device Terminated Connection due to low resources.*/ + REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF = 0x15, /**< Remote Device Terminated Connection due to power off. */ + LOCAL_HOST_TERMINATED_CONNECTION = 0x16, + CONN_INTERVAL_UNACCEPTABLE = 0x3B, + }; + + /* Describes the current state of the device (more than one bit can be set) */ + struct GapState_t { + unsigned advertising : 1; /**< peripheral is currently advertising */ + unsigned connected : 1; /**< peripheral is connected to a central */ + }; + + typedef uint16_t Handle_t; /* Type for connection handle. */ + + typedef struct { + uint16_t minConnectionInterval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t maxConnectionInterval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t slaveLatency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t connectionSupervisionTimeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + } ConnectionParams_t; + + enum Role_t { + PERIPHERAL = 0x1, /**< Peripheral Role. */ + CENTRAL = 0x2, /**< Central Role. */ + }; + + struct AdvertisementCallbackParams_t { + Address_t peerAddr; + int8_t rssi; + bool isScanResponse; + GapAdvertisingParams::AdvertisingType_t type; + uint8_t advertisingDataLen; + const uint8_t *advertisingData; + }; + typedef FunctionPointerWithContext AdvertisementReportCallback_t; + + struct ConnectionCallbackParams_t { + Handle_t handle; + Role_t role; + AddressType_t peerAddrType; + Address_t peerAddr; + AddressType_t ownAddrType; + Address_t ownAddr; + const ConnectionParams_t *connectionParams; + + ConnectionCallbackParams_t(Handle_t handleIn, + Role_t roleIn, + AddressType_t peerAddrTypeIn, + const uint8_t *peerAddrIn, + AddressType_t ownAddrTypeIn, + const uint8_t *ownAddrIn, + const ConnectionParams_t *connectionParamsIn) : + handle(handleIn), + role(roleIn), + peerAddrType(peerAddrTypeIn), + peerAddr(), + ownAddrType(ownAddrTypeIn), + ownAddr(), + connectionParams(connectionParamsIn) { + memcpy(peerAddr, peerAddrIn, ADDR_LEN); + memcpy(ownAddr, ownAddrIn, ADDR_LEN); + } + }; + + static const uint16_t UNIT_1_25_MS = 1250; /**< Number of microseconds in 1.25 milliseconds. */ + static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */ + static uint16_t MSEC_TO_GAP_DURATION_UNITS(uint32_t durationInMillis) { + return (durationInMillis * 1000) / UNIT_1_25_MS; + } + static uint16_t MSEC_TO_ADVERTISEMENT_DURATION_UNITS(uint32_t durationInMillis) { + return (durationInMillis * 1000) / UNIT_0_625_MS; + } + static uint16_t ADVERTISEMENT_DURATION_UNITS_TO_MS(uint16_t gapUnits) { + return (gapUnits * UNIT_0_625_MS) / 1000; + } + + typedef void (*TimeoutEventCallback_t)(TimeoutSource_t source); + typedef void (*ConnectionEventCallback_t)(const ConnectionCallbackParams_t *params); + typedef void (*DisconnectionEventCallback_t)(Handle_t, DisconnectionReason_t); + typedef void (*RadioNotificationEventCallback_t)(bool radio_active); /* gets passed true for ACTIVE; false for INACTIVE. */ + + /* + * The following functions are meant to be overridden in the platform-specific sub-class. + */ +public: + /** + * Set the BTLE MAC address and type. Please note that the address format is + * LSB (least significant byte first). Please refer to Address_t. + * + * @return BLE_ERROR_NONE on success. + */ + virtual ble_error_t setAddress(AddressType_t type, const Address_t address) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Fetch the BTLE MAC address and type. + * + * @return BLE_ERROR_NONE on success. + */ + virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * @return Minimum Advertising interval in milliseconds. + */ + virtual uint16_t getMinAdvertisingInterval(void) const { + return 0; /* default implementation; override this API if this capability is supported. */ + } + + /** + * @return Minimum Advertising interval in milliseconds for non-connectible mode. + */ + virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const { + return 0; /* default implementation; override this API if this capability is supported. */ + } + + /** + * @return Maximum Advertising interval in milliseconds. + */ + virtual uint16_t getMaxAdvertisingInterval(void) const { + return 0xFFFF; /* default implementation; override this API if this capability is supported. */ + } + + virtual ble_error_t stopAdvertising(void) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Stop scanning. The current scanning parameters remain in effect. + * + * @retval BLE_ERROR_NONE if successfully stopped scanning procedure. + */ + virtual ble_error_t stopScan() { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Create a connection (GAP Link Establishment). + * + * @param peerAddr + * 48-bit address, LSB format. + * @param peerAddrType + * Address type of the peer. + * @param connectionParams + * Connection parameters. + * @param scanParams + * Paramters to be used while scanning for the peer. + * @return BLE_ERROR_NONE if connection establishment procedure is started + * successfully. The connectionCallback (if set) will be invoked upon + * a connection event. + */ + virtual ble_error_t connect(const Address_t peerAddr, + Gap::AddressType_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParams) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * This call initiates the disconnection procedure, and its completion will + * be communicated to the application with an invocation of the + * disconnectionCallback. + * + * @param reason + * The reason for disconnection to be sent back to the peer. + */ + virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * This call initiates the disconnection procedure, and its completion will + * be communicated to the application with an invocation of the + * disconnectionCallback. + * + * @param reason + * The reason for disconnection to be sent back to the peer. + * + * @note: this version of disconnect() doesn't take a connection handle. It + * will work reliably only for stacks which are limited to a single + * connection. This API should be considered *deprecated* in favour of the + * altertive which takes a connection handle. It will be dropped in the future. + */ + virtual ble_error_t disconnect(DisconnectionReason_t reason) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Get the GAP peripheral preferred connection parameters. These are the + * defaults that the peripheral would like to have in a connection. The + * choice of the connection parameters is eventually up to the central. + * + * @param[out] params + * The structure where the parameters will be stored. Memory + * for this is owned by the caller. + * + * @return BLE_ERROR_NONE if the parameters were successfully filled into + * the given structure pointed to by params. + */ + virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Set the GAP peripheral preferred connection parameters. These are the + * defaults that the peripheral would like to have in a connection. The + * choice of the connection parameters is eventually up to the central. + * + * @param[in] params + * The structure containing the desired parameters. + */ + virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Update connection parameters while in the peripheral role. + * @details In the peripheral role, this will send the corresponding L2CAP request to the connected peer and wait for + * the central to perform the procedure. + * @param[in] handle + * Connection Handle + * @param[in] params + * Pointer to desired connection parameters. If NULL is provided on a peripheral role, + * the parameters in the PPCP characteristic of the GAP service will be used instead. + */ + virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Set the device name characteristic in the GAP service. + * @param[in] deviceName + * The new value for the device-name. This is a UTF-8 encoded, NULL-terminated string. + */ + virtual ble_error_t setDeviceName(const uint8_t *deviceName) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Get the value of the device name characteristic in the GAP service. + * @param[out] deviceName + * Pointer to an empty buffer where the UTF-8 *non NULL- + * terminated* string will be placed. Set this + * value to NULL in order to obtain the deviceName-length + * from the 'length' parameter. + * + * @param[in/out] lengthP + * (on input) Length of the buffer pointed to by deviceName; + * (on output) the complete device name length (without the + * null terminator). + * + * @note If the device name is longer than the size of the supplied buffer, + * length will return the complete device name length, and not the + * number of bytes actually returned in deviceName. The application may + * use this information to retry with a suitable buffer size. + */ + virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Set the appearance characteristic in the GAP service. + * @param[in] appearance + * The new value for the device-appearance. + */ + virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Get the appearance characteristic in the GAP service. + * @param[out] appearance + * The new value for the device-appearance. + */ + virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Set the radio's transmit power. + * @param[in] txPower Radio transmit power in dBm. + */ + virtual ble_error_t setTxPower(int8_t txPower) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Query the underlying stack for permitted arguments for setTxPower(). + * + * @param[out] valueArrayPP + * Out parameter to receive the immutable array of Tx values. + * @param[out] countP + * Out parameter to receive the array's size. + */ + virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) { + *countP = 0; /* default implementation; override this API if this capability is supported. */ + } + +protected: + /* Override the following in the underlying adaptation layer to provide the functionality of scanning. */ + virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /* + * APIs with non-virtual implementations. + */ +public: + /** + * Returns the current GAP state of the device using a bitmask which + * describes whether the device is advertising and/or connected. + */ + GapState_t getState(void) const { + return state; + } + + /** + * Set the GAP advertising mode to use for this device. + */ + void setAdvertisingType(GapAdvertisingParams::AdvertisingType_t advType) { + _advParams.setAdvertisingType(advType); + } + + /** + * @param[in] interval + * Advertising interval in units of milliseconds. Advertising + * is disabled if interval is 0. If interval is smaller than + * the minimum supported value, then the minimum supported + * value is used instead. This minimum value can be discovered + * using getMinAdvertisingInterval(). + * + * This field must be set to 0 if connectionMode is equal + * to ADV_CONNECTABLE_DIRECTED. + * + * @note: Decreasing this value will allow central devices to detect a + * peripheral faster at the expense of more power being used by the radio + * due to the higher data transmit rate. + * + * @note: This API is now *deprecated* and will be dropped in the future. + * You should use the parallel API from Gap directly. A former call to + * ble.setAdvertisingInterval(...) should now be achieved using + * ble.gap().setAdvertisingInterval(...). + * + * @Note: [WARNING] This API previously used 0.625ms as the unit for its + * 'interval' argument. That required an explicit conversion from + * milliseconds using Gap::MSEC_TO_GAP_DURATION_UNITS(). This conversion is + * no longer required as the new units are milliseconds. Any application + * code depending on the old semantics would need to be updated accordingly. + */ + void setAdvertisingInterval(uint16_t interval) { + if (interval == 0) { + stopAdvertising(); + } else if (interval < getMinAdvertisingInterval()) { + interval = getMinAdvertisingInterval(); + } + _advParams.setInterval(MSEC_TO_ADVERTISEMENT_DURATION_UNITS(interval)); + } + + /** + * @param[in] timeout + * Advertising timeout (in seconds) between 0x1 and 0x3FFF (1 + * and 16383). Use 0 to disable the advertising timeout. + */ + void setAdvertisingTimeout(uint16_t timeout) { + _advParams.setTimeout(timeout); + } + + /** + * Start advertising. + */ + ble_error_t startAdvertising(void) { + setAdvertisingData(); /* update the underlying stack */ + return startAdvertising(_advParams); + } + + /** + * Reset any advertising payload prepared from prior calls to + * accumulateAdvertisingPayload(). This automatically propagates the re- + * initialized adv payload to the underlying stack. + * + * Note: This should be followed by a call to setAdvertisingPayload() or + * startAdvertising() before the update takes effect. + */ + void clearAdvertisingPayload(void) { + _advPayload.clear(); + setAdvertisingData(); + } + + /** + * Accumulate an AD structure in the advertising payload. Please note that + * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used + * as an additional 31 bytes if the advertising payload proves to be too + * small. + * + * @param[in] flags + * The flags to be added. Please refer to + * GapAdvertisingData::Flags for valid flags. Multiple + * flags may be specified in combination. + */ + ble_error_t accumulateAdvertisingPayload(uint8_t flags) { + ble_error_t rc; + if ((rc = _advPayload.addFlags(flags)) != BLE_ERROR_NONE) { + return rc; + } + + return setAdvertisingData(); + } + + /** + * Accumulate an AD structure in the advertising payload. Please note that + * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used + * as an additional 31 bytes if the advertising payload proves to be too + * small. + * + * @param app + * The appearance of the peripheral. + */ + ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::Appearance app) { + setAppearance(app); + + ble_error_t rc; + if ((rc = _advPayload.addAppearance(app)) != BLE_ERROR_NONE) { + return rc; + } + + return setAdvertisingData(); + } + + /** + * Accumulate an AD structure in the advertising payload. Please note that + * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used + * as an additional 31 bytes if the advertising payload proves to be too + * small. + * + * @param app + * The max transmit power to be used by the controller. This is + * only a hint. + */ + ble_error_t accumulateAdvertisingPayloadTxPower(int8_t power) { + ble_error_t rc; + if ((rc = _advPayload.addTxPower(power)) != BLE_ERROR_NONE) { + return rc; + } + + return setAdvertisingData(); + } + + /** + * Accumulate a variable length byte-stream as an AD structure in the + * advertising payload. Please note that the payload is limited to 31 bytes. + * The SCAN_RESPONSE message may be used as an additional 31 bytes if the + * advertising payload proves to be too small. + * + * @param type The type which describes the variable length data. + * @param data data bytes. + * @param len length of data. + */ + ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) { + if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { + setDeviceName(data); + } + + ble_error_t rc; + if ((rc = _advPayload.addData(type, data, len)) != BLE_ERROR_NONE) { + return rc; + } + + return setAdvertisingData(); + } + + /** + * Setup a particular, user-constructed advertisement payload for the + * underlying stack. It would be uncommon for this API to be used directly; + * there are other APIs to build an advertisement payload (see above). + */ + ble_error_t setAdvertisingPayload(const GapAdvertisingData &payload) { + _advPayload = payload; + return setAdvertisingData(); + } + + /** + * @return Read back advertising data. Useful for storing and + * restoring payload. + */ + const GapAdvertisingData &getAdvertisingPayload(void) const { + return _advPayload; + } + + /** + * Accumulate a variable length byte-stream as an AD structure in the + * scanResponse payload. + * + * @param[in] type The type which describes the variable length data. + * @param[in] data data bytes. + * @param[in] len length of data. + */ + ble_error_t accumulateScanResponse(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) { + ble_error_t rc; + if ((rc = _scanResponse.addData(type, data, len)) != BLE_ERROR_NONE) { + return rc; + } + + return setAdvertisingData(); + } + + /** + * Reset any scan response prepared from prior calls to + * accumulateScanResponse(). + * + * Note: This should be followed by a call to setAdvertisingPayload() or + * startAdvertising() before the update takes effect. + */ + void clearScanResponse(void) { + _scanResponse.clear(); + setAdvertisingData(); + } + + /** + * Setup parameters for GAP scanning--i.e. observer mode. + * @param[in] interval + * Scan interval (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * @param[in] window + * Scan Window (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * @param[in] timeout + * Scan timeout (in seconds) between 0x0001 and 0xFFFF, 0x0000 disables timeout. + * @param[in] activeScanning + * Set to True if active-scanning is required. This is used to fetch the + * scan response from a peer if possible. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + * + * @Note: The scan interval and window are recommendations to the BLE stack. + */ + ble_error_t setScanParams(uint16_t interval = GapScanningParams::SCAN_INTERVAL_MAX, + uint16_t window = GapScanningParams::SCAN_WINDOW_MAX, + uint16_t timeout = 0, + bool activeScanning = false) { + ble_error_t rc; + if (((rc = _scanningParams.setInterval(interval)) == BLE_ERROR_NONE) && + ((rc = _scanningParams.setWindow(window)) == BLE_ERROR_NONE) && + ((rc = _scanningParams.setTimeout(timeout)) == BLE_ERROR_NONE)) { + _scanningParams.setActiveScanning(activeScanning); + return BLE_ERROR_NONE; + } + + return rc; + } + + /** + * Setup the scanInterval parameter for GAP scanning--i.e. observer mode. + * @param[in] interval + * Scan interval (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + */ + ble_error_t setScanInterval(uint16_t interval) { + return _scanningParams.setInterval(interval); + } + + /** + * Setup the scanWindow parameter for GAP scanning--i.e. observer mode. + * @param[in] window + * Scan Window (in milliseconds) [valid values lie between 2.5ms and 10.24s]. + * + * The scanning window divided by the interval determines the duty cycle for + * scanning. For example, if the interval is 100ms and the window is 10ms, + * then the controller will scan for 10 percent of the time. It is possible + * to have the interval and window set to the same value. In this case, + * scanning is continuous, with a change of scanning frequency once every + * interval. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + */ + ble_error_t setScanWindow(uint16_t window) { + return _scanningParams.setWindow(window); + } + + /** + * Setup parameters for GAP scanning--i.e. observer mode. + * @param[in] timeout + * Scan timeout (in seconds) between 0x0001 and 0xFFFF, 0x0000 disables timeout. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + */ + ble_error_t setScanTimeout(uint16_t timeout) { + return _scanningParams.setTimeout(timeout); + } + + /** + * Setup parameters for GAP scanning--i.e. observer mode. + * @param[in] activeScanning + * Set to True if active-scanning is required. This is used to fetch the + * scan response from a peer if possible. + * + * Once the scanning parameters have been configured, scanning can be + * enabled by using startScan(). + */ + void setActiveScanning(bool activeScanning) { + _scanningParams.setActiveScanning(activeScanning); + } + + /** + * Start scanning (Observer Procedure) based on the parameters currently in + * effect. + * + * @param[in] callback + * The application specific callback to be invoked upon + * receiving every advertisement report. This can be passed in + * as NULL, in which case scanning may not be enabled at all. + */ + ble_error_t startScan(void (*callback)(const AdvertisementCallbackParams_t *params)) { + ble_error_t err = BLE_ERROR_NONE; + if (callback) { + if ((err = startRadioScan(_scanningParams)) == BLE_ERROR_NONE) { + onAdvertisementReport.attach(callback); + } + } + + return err; + } + + /** + * Same as above, but this takes an (object, method) pair for a callback. + */ + template + ble_error_t startScan(T *object, void (T::*callbackMember)(const AdvertisementCallbackParams_t *params)) { + ble_error_t err = BLE_ERROR_NONE; + if (object && callbackMember) { + if ((err = startRadioScan(_scanningParams)) == BLE_ERROR_NONE) { + onAdvertisementReport.attach(object, callbackMember); + } + } + + return err; + } + +private: + ble_error_t setAdvertisingData(void) { + return setAdvertisingData(_advPayload, _scanResponse); + } + +private: + virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &) = 0; + virtual ble_error_t startAdvertising(const GapAdvertisingParams &) = 0; + +public: + /** + * Accessors to read back currently active advertising params. + */ + GapAdvertisingParams &getAdvertisingParams(void) { + return _advParams; + } + const GapAdvertisingParams &getAdvertisingParams(void) const { + return _advParams; + } + + /** + * Setup a particular, user-constructed set of advertisement parameters for + * the underlying stack. It would be uncommon for this API to be used + * directly; there are other APIs to tweak advertisement parameters + * individually. + */ + void setAdvertisingParams(const GapAdvertisingParams &newParams) { + _advParams = newParams; + } + + /* Event callback handlers. */ +public: + /** + * Setup a callback for timeout events. Refer to TimeoutSource_t for + * possible event types. + */ + void onTimeout(TimeoutEventCallback_t callback) {timeoutCallback = callback;} + + /** + * Setup a callback for connection events. Refer to ConnectionEventCallback_t. + */ + void onConnection(ConnectionEventCallback_t callback) {connectionCallback = callback;} + + /** + * Set the application callback for disconnection events. + * @param callback + * Pointer to the unique callback. + */ + void onDisconnection(DisconnectionEventCallback_t callback) {disconnectionCallback = callback;} + + /** + * Append to a chain of callbacks to be invoked upon disconnection; these + * callbacks receive no context and are therefore different from the + * disconnectionCallback callback. + * @param callback + * function pointer to be invoked upon disconnection; receives no context. + */ + template + void addToDisconnectionCallChain(T *tptr, void (T::*mptr)(void)) {disconnectionCallChain.add(tptr, mptr);} + + /** + * Set the application callback for radio-notification events. + * + * Radio Notification is a feature that enables ACTIVE and INACTIVE + * (nACTIVE) signals from the stack that notify the application when the + * radio is in use. The signal is sent using software interrupt. + * + * The ACTIVE signal is sent before the Radio Event starts. The nACTIVE + * signal is sent at the end of the Radio Event. These signals can be used + * by the application programmer to synchronize application logic with radio + * activity. For example, the ACTIVE signal can be used to shut off external + * devices to manage peak current drawn during periods when the radio is on, + * or to trigger sensor data collection for transmission in the Radio Event. + * + * @param callback + * The application handler to be invoked in response to a radio + * ACTIVE/INACTIVE event. + */ + virtual void onRadioNotification(RadioNotificationEventCallback_t callback) {radioNotificationCallback = callback;} + +protected: + Gap() : + _advParams(), + _advPayload(), + _scanningParams(), + _scanResponse(), + state(), + timeoutCallback(NULL), + connectionCallback(NULL), + disconnectionCallback(NULL), + radioNotificationCallback(), + onAdvertisementReport(), + disconnectionCallChain() { + _advPayload.clear(); + _scanResponse.clear(); + } + + /* Entry points for the underlying stack to report events back to the user. */ +public: + void processConnectionEvent(Handle_t handle, + Role_t role, + AddressType_t peerAddrType, + const Address_t peerAddr, + AddressType_t ownAddrType, + const Address_t ownAddr, + const ConnectionParams_t *connectionParams) { + state.connected = 1; + if (connectionCallback) { + ConnectionCallbackParams_t callbackParams(handle, role, peerAddrType, peerAddr, ownAddrType, ownAddr, connectionParams); + connectionCallback(&callbackParams); + } + } + + void processDisconnectionEvent(Handle_t handle, DisconnectionReason_t reason) { + state.connected = 0; + if (disconnectionCallback) { + disconnectionCallback(handle, reason); + } + disconnectionCallChain.call(); + } + + void processAdvertisementReport(const Address_t peerAddr, + int8_t rssi, + bool isScanResponse, + GapAdvertisingParams::AdvertisingType_t type, + uint8_t advertisingDataLen, + const uint8_t *advertisingData) { + AdvertisementCallbackParams_t params; + memcpy(params.peerAddr, peerAddr, ADDR_LEN); + params.rssi = rssi; + params.isScanResponse = isScanResponse; + params.type = type; + params.advertisingDataLen = advertisingDataLen; + params.advertisingData = advertisingData; + onAdvertisementReport.call(¶ms); + } + + void processTimeoutEvent(TimeoutSource_t source) { + if (timeoutCallback) { + timeoutCallback(source); + } + } + +protected: + GapAdvertisingParams _advParams; + GapAdvertisingData _advPayload; + GapScanningParams _scanningParams; + GapAdvertisingData _scanResponse; + + GapState_t state; + +protected: + TimeoutEventCallback_t timeoutCallback; + ConnectionEventCallback_t connectionCallback; + DisconnectionEventCallback_t disconnectionCallback; + RadioNotificationEventCallback_t radioNotificationCallback; + AdvertisementReportCallback_t onAdvertisementReport; + CallChain disconnectionCallChain; + +private: + /* disallow copy and assignment */ + Gap(const Gap &); + Gap& operator=(const Gap &); +}; + +#endif // ifndef __GAP_H__ diff --git a/public/GapAdvertisingData.h b/ble/GapAdvertisingData.h similarity index 99% rename from public/GapAdvertisingData.h rename to ble/GapAdvertisingData.h index a904d0c..0c9bcc6 100644 --- a/public/GapAdvertisingData.h +++ b/ble/GapAdvertisingData.h @@ -17,6 +17,7 @@ #ifndef __GAP_ADVERTISING_DATA_H__ #define __GAP_ADVERTISING_DATA_H__ +#include #include #include "blecommon.h" diff --git a/public/GapAdvertisingParams.h b/ble/GapAdvertisingParams.h similarity index 69% rename from public/GapAdvertisingParams.h rename to ble/GapAdvertisingParams.h index 54791fd..8358ebd 100644 --- a/public/GapAdvertisingParams.h +++ b/ble/GapAdvertisingParams.h @@ -39,30 +39,22 @@ public: static const unsigned GAP_ADV_PARAMS_INTERVAL_MAX = 0x4000; static const unsigned GAP_ADV_PARAMS_TIMEOUT_MAX = 0x3FFF; - /**************************************************************************/ /*! - \brief - Encapsulates the peripheral advertising modes, which determine how - the device appears to other central devices in hearing range - - \par - See the following for more information on advertising types: - - \li \c Bluetooth Core Specification 4.0 (Vol. 6), Part B, Section 2.3.1 - \li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 9.3 - */ - /**************************************************************************/ - enum AdvertisingType { + * Encapsulates the peripheral advertising modes, which determine how + * the device appears to other central devices in hearing range + */ + enum AdvertisingType_t { ADV_CONNECTABLE_UNDIRECTED, /**< Vol 3, Part C, Section 9.3.4 and Vol 6, Part B, Section 2.3.1.1 */ ADV_CONNECTABLE_DIRECTED, /**< Vol 3, Part C, Section 9.3.3 and Vol 6, Part B, Section 2.3.1.2 */ ADV_SCANNABLE_UNDIRECTED, /**< Include support for Scan Response payloads, see Vol 6, Part B, Section 2.3.1.4 */ ADV_NON_CONNECTABLE_UNDIRECTED /**< Vol 3, Part C, Section 9.3.2 and Vol 6, Part B, Section 2.3.1.3 */ }; + typedef enum AdvertisingType_t AdvertisingType; /* deprecated type alias. */ public: - GapAdvertisingParams(AdvertisingType advType = GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED, - uint16_t interval = GAP_ADV_PARAMS_INTERVAL_MIN_NONCON, - uint16_t timeout = 0) : _advType(advType), _interval(interval), _timeout(timeout) { + GapAdvertisingParams(AdvertisingType_t advType = ADV_CONNECTABLE_UNDIRECTED, + uint16_t interval = GAP_ADV_PARAMS_INTERVAL_MIN_NONCON, + uint16_t timeout = 0) : _advType(advType), _interval(interval), _timeout(timeout) { /* Interval checks */ if (_advType == ADV_CONNECTABLE_DIRECTED) { /* Interval must be 0 in directed connectable mode */ @@ -94,18 +86,18 @@ public: } } - AdvertisingType getAdvertisingType(void) const {return _advType; } - uint16_t getInterval(void) const {return _interval;} - uint16_t getTimeout(void) const {return _timeout; } + AdvertisingType_t getAdvertisingType(void) const {return _advType; } + uint16_t getInterval(void) const {return _interval;} + uint16_t getTimeout(void) const {return _timeout; } - void setAdvertisingType(AdvertisingType newAdvType) {_advType = newAdvType; } - void setInterval(uint16_t newInterval) {_interval = newInterval;} - void setTimeout(uint16_t newTimeout) {_timeout = newTimeout; } + void setAdvertisingType(AdvertisingType_t newAdvType) {_advType = newAdvType; } + void setInterval(uint16_t newInterval) {_interval = newInterval;} + void setTimeout(uint16_t newTimeout) {_timeout = newTimeout; } private: - AdvertisingType _advType; - uint16_t _interval; - uint16_t _timeout; + AdvertisingType_t _advType; + uint16_t _interval; + uint16_t _timeout; }; #endif // ifndef __GAP_ADVERTISING_PARAMS_H__ diff --git a/public/GapEvents.h b/ble/GapEvents.h similarity index 100% rename from public/GapEvents.h rename to ble/GapEvents.h diff --git a/public/GapScanningParams.h b/ble/GapScanningParams.h similarity index 54% rename from public/GapScanningParams.h rename to ble/GapScanningParams.h index 274a46c..045f655 100644 --- a/public/GapScanningParams.h +++ b/ble/GapScanningParams.h @@ -17,8 +17,6 @@ #ifndef __GAP_SCANNING_PARAMS_H__ #define __GAP_SCANNING_PARAMS_H__ -#include "Gap.h" - class GapScanningParams { public: static const unsigned SCAN_INTERVAL_MIN = 0x0004; /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ @@ -29,58 +27,20 @@ public: static const unsigned SCAN_TIMEOUT_MAX = 0xFFFF; /**< Maximum Scan timeout in seconds. */ public: - GapScanningParams(uint16_t interval = SCAN_INTERVAL_MAX, - uint16_t window = SCAN_WINDOW_MAX, - uint16_t timeout = 0, - bool activeScanning = false) : _interval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(interval)), - _window(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(window)), - _timeout(timeout), - _activeScanning(activeScanning) { - /* stay within limits */ - if (_interval < SCAN_INTERVAL_MIN) { - _interval = SCAN_INTERVAL_MIN; - } - if (_interval > SCAN_INTERVAL_MAX) { - _interval = SCAN_INTERVAL_MAX; - } - if (_window < SCAN_WINDOW_MIN) { - _window = SCAN_WINDOW_MIN; - } - if (_window > SCAN_WINDOW_MAX) { - _window = SCAN_WINDOW_MAX; - } - } + GapScanningParams(uint16_t interval = SCAN_INTERVAL_MAX, + uint16_t window = SCAN_WINDOW_MAX, + uint16_t timeout = 0, + bool activeScanning = false); - ble_error_t setInterval(uint16_t newIntervalInMS) { - uint16_t newInterval = Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(newIntervalInMS); - if ((newInterval >= SCAN_INTERVAL_MIN) && (newInterval < SCAN_INTERVAL_MAX)) { - _interval = newInterval; - return BLE_ERROR_NONE; - } + ble_error_t setInterval(uint16_t newIntervalInMS); - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } + ble_error_t setWindow(uint16_t newWindowInMS); - ble_error_t setWindow(uint16_t newWindowInMS) { - uint16_t newWindow = Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(newWindowInMS); - if ((newWindow >= SCAN_WINDOW_MIN) && (newWindow < SCAN_WINDOW_MAX)) { - _window = newWindow; - return BLE_ERROR_NONE; - } - - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - ble_error_t setTimeout(uint16_t newTimeout) { - _timeout = newTimeout; - return BLE_ERROR_NONE; - } - - void setActiveScanning(bool activeScanning) { - _activeScanning = activeScanning; - } + ble_error_t setTimeout(uint16_t newTimeout); + void setActiveScanning(bool activeScanning); +public: /* @Note: The following return durations in units of 0.625 ms */ uint16_t getInterval(void) const {return _interval;} uint16_t getWindow(void) const {return _window; } diff --git a/public/GattAttribute.h b/ble/GattAttribute.h similarity index 99% rename from public/GattAttribute.h rename to ble/GattAttribute.h index fe07600..bf208e5 100644 --- a/public/GattAttribute.h +++ b/ble/GattAttribute.h @@ -17,6 +17,8 @@ #ifndef __GATT_ATTRIBUTE_H__ #define __GATT_ATTRIBUTE_H__ +#include "UUID.h" + class GattAttribute { public: typedef uint16_t Handle_t; diff --git a/public/GattCharacteristicCallbackParams.h b/ble/GattCallbackParamTypes.h similarity index 52% rename from public/GattCharacteristicCallbackParams.h rename to ble/GattCallbackParamTypes.h index 502c3d9..fd6d40e 100644 --- a/public/GattCharacteristicCallbackParams.h +++ b/ble/GattCallbackParamTypes.h @@ -14,37 +14,35 @@ * limitations under the License. */ -#ifndef __GATT_CHARACTERISTIC_CALLBACK_PARAMS_H__ -#define __GATT_CHARACTERISTIC_CALLBACK_PARAMS_H__ +#ifndef __GATT_CALLBACK_PARAM_TYPES_H__ +#define __GATT_CALLBACK_PARAM_TYPES_H__ -struct GattCharacteristicWriteCBParams { - GattAttribute::Handle_t charHandle; - enum Type { - GATTS_CHAR_OP_INVALID = 0x00, /**< Invalid Operation. */ - GATTS_CHAR_OP_WRITE_REQ = 0x01, /**< Write Request. */ - GATTS_CHAR_OP_WRITE_CMD = 0x02, /**< Write Command. */ - GATTS_CHAR_OP_SIGN_WRITE_CMD = 0x03, /**< Signed Write Command. */ - GATTS_CHAR_OP_PREP_WRITE_REQ = 0x04, /**< Prepare Write Request. */ - GATTS_CHAR_OP_EXEC_WRITE_REQ_CANCEL = 0x05, /**< Execute Write Request: Cancel all prepared writes. */ - GATTS_CHAR_OP_EXEC_WRITE_REQ_NOW = 0x06, /**< Execute Write Request: Immediately execute all prepared writes. */ - } op; /**< Type of write operation, */ - uint16_t offset; /**< Offset for the write operation. */ - uint16_t len; /**< Length of the incoming data. */ - const uint8_t *data; /**< Incoming data, variable length. */ +struct GattWriteCallbackParams { + enum WriteOp_t { + OP_INVALID = 0x00, /**< Invalid Operation. */ + OP_WRITE_REQ = 0x01, /**< Write Request. */ + OP_WRITE_CMD = 0x02, /**< Write Command. */ + OP_SIGN_WRITE_CMD = 0x03, /**< Signed Write Command. */ + OP_PREP_WRITE_REQ = 0x04, /**< Prepare Write Request. */ + OP_EXEC_WRITE_REQ_CANCEL = 0x05, /**< Execute Write Request: Cancel all prepared writes. */ + OP_EXEC_WRITE_REQ_NOW = 0x06, /**< Execute Write Request: Immediately execute all prepared writes. */ + }; + + GattAttribute::Handle_t handle; + WriteOp_t writeOp; /**< Type of write operation, */ + uint16_t offset; /**< Offset for the write operation. */ + uint16_t len; + const uint8_t *data; /* @note: data might not persist beyond the callback; make a local copy if needed. */ }; -struct GattCharacteristicReadCBParams { - GattAttribute::Handle_t charHandle; - enum Type { - GATTS_CHAR_OP_INVALID = 0x00, /**< Invalid Operation. */ - GATTS_CHAR_OP_READ_REQ = 0x0A, /**< Read Request. */ - } op; /**< Type of write operation, */ - uint16_t offset; /**< Offset for the read operation. */ - uint16_t *len; /**< Length of the outgoing data. */ - uint8_t *data; /**< Outgoing data, variable length. */ +struct GattReadCallbackParams { + GattAttribute::Handle_t handle; + uint16_t offset; /**< Offset for the read operation. */ + uint16_t len; + const uint8_t *data; /* @note: data might not persist beyond the callback; make a local copy if needed. */ }; -enum GattCharacteristicAuthCBReply_t { +enum GattAuthCallbackReply_t { AUTH_CALLBACK_REPLY_SUCCESS = 0x00, /**< Success. */ AUTH_CALLBACK_REPLY_ATTERR_INVALID_HANDLE = 0x0101, /**< ATT Error: Invalid Attribute Handle. */ AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED = 0x0102, /**< ATT Error: Read not permitted. */ @@ -59,22 +57,22 @@ enum GattCharacteristicAuthCBReply_t { AUTH_CALLBACK_REPLY_ATTERR_INSUF_RESOURCES = 0x0111, /**< ATT Error: Encrypted link required. */ }; -struct GattCharacteristicWriteAuthCBParams { - GattAttribute::Handle_t charHandle; +struct GattWriteAuthCallbackParams { + GattAttribute::Handle_t handle; uint16_t offset; /**< Offset for the write operation. */ uint16_t len; /**< Length of the incoming data. */ const uint8_t *data; /**< Incoming data, variable length. */ - GattCharacteristicAuthCBReply_t authorizationReply; /* This is the out parameter which needs to be set to true by the callback if the - * request is to proceed; false otherwise. */ + GattAuthCallbackReply_t authorizationReply; /* This is the out parameter which needs to be set to true by the callback if the + * request is to proceed; false otherwise. */ }; -struct GattCharacteristicReadAuthCBParams { - GattAttribute::Handle_t charHandle; +struct GattReadAuthCallbackParams { + GattAttribute::Handle_t handle; uint16_t offset; /**< Offset for the read operation. */ uint16_t len; /**< Optional: new length of the outgoing data. */ uint8_t *data; /**< Optional: new outgoing data. Leave at NULL if data is unchanged. */ - GattCharacteristicAuthCBReply_t authorizationReply; /* This is the out parameter which needs to be set to true by the callback if the - * request is to proceed; false otherwise. */ + GattAuthCallbackReply_t authorizationReply; /* This is the out parameter which needs to be set to true by the callback if the + * request is to proceed; false otherwise. */ }; -#endif /*__GATT_CHARACTERISTIC_CALLBACK_PARAMS_H__*/ +#endif /*__GATT_CALLBACK_PARAM_TYPES_H__*/ diff --git a/public/GattCharacteristic.h b/ble/GattCharacteristic.h similarity index 96% rename from public/GattCharacteristic.h rename to ble/GattCharacteristic.h index b2c86ad..5fb896c 100644 --- a/public/GattCharacteristic.h +++ b/ble/GattCharacteristic.h @@ -18,8 +18,9 @@ #define __GATT_CHARACTERISTIC_H__ #include "Gap.h" +#include "SecurityManager.h" #include "GattAttribute.h" -#include "GattCharacteristicCallbackParams.h" +#include "GattCallbackParamTypes.h" #include "FunctionPointerWithContext.h" class GattCharacteristic { @@ -331,7 +332,7 @@ public: unsigned numDescriptors = 0) : _valueAttribute(uuid, valuePtr, initialLen, maxLen), _properties(props), - _requiredSecurity(Gap::SECURITY_MODE_ENCRYPTION_OPEN_LINK), + _requiredSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK), _descriptors(descriptors), _descriptorCount(numDescriptors), enabledReadAuthorization(false), @@ -347,7 +348,7 @@ public: * * @param securityMode Can be one of encryption or signing, with or without protection for MITM (man in the middle attacks). */ - void requireSecurity(Gap::SecurityMode_t securityMode) { + void requireSecurity(SecurityManager::SecurityMode_t securityMode) { _requiredSecurity = securityMode; } @@ -355,21 +356,21 @@ public: /** * Authorization. */ - void setWriteAuthorizationCallback(void (*callback)(GattCharacteristicWriteAuthCBParams *)) { + void setWriteAuthorizationCallback(void (*callback)(GattWriteAuthCallbackParams *)) { writeAuthorizationCallback.attach(callback); enabledWriteAuthorization = true; } template - void setWriteAuthorizationCallback(T *object, void (T::*member)(GattCharacteristicWriteAuthCBParams *)) { + void setWriteAuthorizationCallback(T *object, void (T::*member)(GattWriteAuthCallbackParams *)) { writeAuthorizationCallback.attach(object, member); enabledWriteAuthorization = true; } - void setReadAuthorizationCallback(void (*callback)(GattCharacteristicReadAuthCBParams *)) { + void setReadAuthorizationCallback(void (*callback)(GattReadAuthCallbackParams *)) { readAuthorizationCallback.attach(callback); enabledReadAuthorization = true; } template - void setReadAuthorizationCallback(T *object, void (T::*member)(GattCharacteristicReadAuthCBParams *)) { + void setReadAuthorizationCallback(T *object, void (T::*member)(GattReadAuthCallbackParams *)) { readAuthorizationCallback.attach(object, member); enabledReadAuthorization = true; } @@ -380,7 +381,7 @@ public: * @param params to capture the context of the write-auth request; and also contains an out-parameter for reply. * @return true if the write is authorized to proceed. */ - GattCharacteristicAuthCBReply_t authorizeWrite(GattCharacteristicWriteAuthCBParams *params) { + GattAuthCallbackReply_t authorizeWrite(GattWriteAuthCallbackParams *params) { if (!isWriteAuthorizationEnabled()) { return AUTH_CALLBACK_REPLY_SUCCESS; } @@ -406,7 +407,7 @@ public: * * @return true if the read is authorized to proceed. */ - GattCharacteristicAuthCBReply_t authorizeRead(GattCharacteristicReadAuthCBParams *params) { + GattAuthCallbackReply_t authorizeRead(GattReadAuthCallbackParams *params) { if (!isReadAuthorizationEnabled()) { return AUTH_CALLBACK_REPLY_SUCCESS; } @@ -422,7 +423,7 @@ public: const GattAttribute& getValueAttribute() const {return _valueAttribute; } GattAttribute::Handle_t getValueHandle(void) const {return getValueAttribute().getHandle();} uint8_t getProperties(void) const {return _properties; } - Gap::SecurityMode_t getRequiredSecurity() const {return _requiredSecurity; } + SecurityManager::SecurityMode_t getRequiredSecurity() const {return _requiredSecurity; } uint8_t getDescriptorCount(void) const {return _descriptorCount; } bool isReadAuthorizationEnabled() const {return enabledReadAuthorization; } bool isWriteAuthorizationEnabled() const {return enabledWriteAuthorization; } @@ -436,16 +437,16 @@ public: } private: - GattAttribute _valueAttribute; - uint8_t _properties; - Gap::SecurityMode_t _requiredSecurity; - GattAttribute **_descriptors; - uint8_t _descriptorCount; + GattAttribute _valueAttribute; + uint8_t _properties; + SecurityManager::SecurityMode_t _requiredSecurity; + GattAttribute **_descriptors; + uint8_t _descriptorCount; bool enabledReadAuthorization; bool enabledWriteAuthorization; - FunctionPointerWithContext readAuthorizationCallback; - FunctionPointerWithContext writeAuthorizationCallback; + FunctionPointerWithContext readAuthorizationCallback; + FunctionPointerWithContext writeAuthorizationCallback; private: /* disallow copy and assignment */ diff --git a/ble/GattClient.h b/ble/GattClient.h new file mode 100644 index 0000000..ca36c19 --- /dev/null +++ b/ble/GattClient.h @@ -0,0 +1,229 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __GATT_CLIENT_H__ +#define __GATT_CLIENT_H__ + +#include "Gap.h" +#include "GattAttribute.h" +#include "ServiceDiscovery.h" + +#include "GattCallbackParamTypes.h" + +class GattClient { +public: + typedef void (*ReadCallback_t)(const GattReadCallbackParams *params); + + enum WriteOp_t { + GATT_OP_WRITE_REQ = 0x01, /**< Write Request. */ + GATT_OP_WRITE_CMD = 0x02, /**< Write Command. */ + }; + + typedef void (*WriteCallback_t)(const GattWriteCallbackParams *params); + + /* + * The following functions are meant to be overridden in the platform-specific sub-class. + */ +public: + /** + * Launch service discovery. Once launched, service discovery will remain + * active with callbacks being issued back into the application for matching + * services/characteristics. isServiceDiscoveryActive() can be used to + * determine status; and a termination callback (if setup) will be invoked + * at the end. Service discovery can be terminated prematurely if needed + * using terminateServiceDiscovery(). + * + * @param connectionHandle + * Handle for the connection with the peer. + * @param sc + * This is the application callback for matching service. Taken as + * NULL by default. Note: service discovery may still be active + * when this callback is issued; calling asynchronous BLE-stack + * APIs from within this application callback might cause the + * stack to abort service discovery. If this becomes an issue, it + * may be better to make local copy of the discoveredService and + * wait for service discovery to terminate before operating on the + * service. + * @param cc + * This is the application callback for matching characteristic. + * Taken as NULL by default. Note: service discovery may still be + * active when this callback is issued; calling asynchronous + * BLE-stack APIs from within this application callback might cause + * the stack to abort service discovery. If this becomes an issue, + * it may be better to make local copy of the discoveredCharacteristic + * and wait for service discovery to terminate before operating on the + * characteristic. + * @param matchingServiceUUID + * UUID based filter for specifying a service in which the application is + * interested. By default it is set as the wildcard UUID_UNKNOWN, + * in which case it matches all services. If characteristic-UUID + * filter (below) is set to the wildcard value, then a service + * callback will be invoked for the matching service (or for every + * service if the service filter is a wildcard). + * @param matchingCharacteristicUUIDIn + * UUID based filter for specifying characteristic in which the application + * is interested. By default it is set as the wildcard UUID_UKNOWN + * to match against any characteristic. If both service-UUID + * filter and characteristic-UUID filter are used with non- wildcard + * values, then only a single characteristic callback is + * invoked for the matching characteristic. + * + * @note Using wildcard values for both service-UUID and characteristic- + * UUID will result in complete service discovery--callbacks being + * called for every service and characteristic. + * + * @note Providing NULL for the characteristic callback will result in + * characteristic discovery being skipped for each matching + * service. This allows for an inexpensive method to discover only + * services. + * + * @return + * BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error. + */ + virtual ble_error_t launchServiceDiscovery(Gap::Handle_t connectionHandle, + ServiceDiscovery::ServiceCallback_t sc = NULL, + ServiceDiscovery::CharacteristicCallback_t cc = NULL, + const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN), + const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Launch service discovery for services. Once launched, service discovery will remain + * active with service-callbacks being issued back into the application for matching + * services. isServiceDiscoveryActive() can be used to + * determine status; and a termination callback (if setup) will be invoked + * at the end. Service discovery can be terminated prematurely if needed + * using terminateServiceDiscovery(). + * + * @param connectionHandle + * Handle for the connection with the peer. + * @param sc + * This is the application callback for matching service. Note: service discovery may still be active + * when this callback is issued; calling asynchronous BLE-stack + * APIs from within this application callback might cause the + * stack to abort service discovery. If this becomes an issue, it + * may be better to make local copy of the discoveredService and + * wait for service discovery to terminate before operating on the + * service. + * @param matchingServiceUUID + * UUID based filter for specifying a service in which the application is + * interested. By default it is set as the wildcard UUID_UNKNOWN, + * in which case it matches all services. + * + * @return + * BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error. + */ + virtual ble_error_t discoverServices(Gap::Handle_t connectionHandle, + ServiceDiscovery::ServiceCallback_t callback, + const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Launch service discovery for services. Once launched, service discovery will remain + * active with service-callbacks being issued back into the application for matching + * services. isServiceDiscoveryActive() can be used to + * determine status; and a termination callback (if setup) will be invoked + * at the end. Service discovery can be terminated prematurely if needed + * using terminateServiceDiscovery(). + * + * @param connectionHandle + * Handle for the connection with the peer. + * @param sc + * This is the application callback for matching service. Note: service discovery may still be active + * when this callback is issued; calling asynchronous BLE-stack + * APIs from within this application callback might cause the + * stack to abort service discovery. If this becomes an issue, it + * may be better to make local copy of the discoveredService and + * wait for service discovery to terminate before operating on the + * service. + * @param startHandle, endHandle + * Handle range within which to limit the search + * + * @return + * BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error. + */ + virtual ble_error_t discoverServices(Gap::Handle_t connectionHandle, + ServiceDiscovery::ServiceCallback_t callback, + GattAttribute::Handle_t startHandle, + GattAttribute::Handle_t endHandle) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Is service-discovery currently active? + */ + virtual bool isServiceDiscoveryActive(void) const { + return false; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Terminate an ongoing service-discovery. This should result in an + * invocation of the TerminationCallback if service-discovery is active. + */ + virtual void terminateServiceDiscovery(void) { + /* default implementation; override this API if this capability is supported. */ + } + + /* Initiate a Gatt Client read procedure by attribute-handle. */ + virtual ble_error_t read(Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, uint16_t offset) const { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Initiate a GATT Client write procedure. + * + * @param[in] cmd + * Command can be either a write-request (which generates a + * matching response from the peripheral), or a write-command, + * which doesn't require the connected peer to respond. + * @param[in] connHandle + * Connection handle. + * @param[in] attributeHandle + * handle for the target attribtue on the remote GATT server. + * @param[in] length + * length of the new value. + * @param[in] value + * new value being written. + */ + virtual ble_error_t write(GattClient::WriteOp_t cmd, + Gap::Handle_t connHandle, + GattAttribute::Handle_t attributeHandle, + size_t length, + const uint8_t *value) const { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Setup callback for when serviceDiscovery terminates. + */ + virtual void onServiceDiscoveryTermination(ServiceDiscovery::TerminationCallback_t callback) { + /* default implementation; override this API if this capability is supported. */ + } + +protected: + GattClient() { + /* empty */ + } + +private: + /* disallow copy and assignment */ + GattClient(const GattClient &); + GattClient& operator=(const GattClient &); +}; + +#endif // ifndef __GATT_CLIENT_H__ diff --git a/ble/GattServer.h b/ble/GattServer.h new file mode 100644 index 0000000..101f5f9 --- /dev/null +++ b/ble/GattServer.h @@ -0,0 +1,316 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __GATT_SERVER_H__ +#define __GATT_SERVER_H__ + +#include "Gap.h" +#include "GattService.h" +#include "GattAttribute.h" +#include "GattServerEvents.h" +#include "GattCallbackParamTypes.h" +#include "CallChainOfFunctionPointersWithContext.h" + +class GattServer { +public: + /* Event callback handlers. */ + typedef void (*EventCallback_t)(GattAttribute::Handle_t attributeHandle); + typedef void (*ServerEventCallback_t)(void); /**< independent of any particular attribute */ + +protected: + GattServer() : + serviceCount(0), + characteristicCount(0), + dataSentCallChain(), + dataWrittenCallChain(), + dataReadCallChain(), + updatesEnabledCallback(NULL), + updatesDisabledCallback(NULL), + confirmationReceivedCallback(NULL) { + /* empty */ + } + + /* + * The following functions are meant to be overridden in the platform-specific sub-class. + */ +public: + + /** + * Add a service declaration to the local server ATT table. Also add the + * characteristics contained within. + */ + virtual ble_error_t addService(GattService &) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Read the value of a characteristic from the local GattServer + * @param[in] attributeHandle + * Attribute handle for the value attribute of the characteristic. + * @param[out] buffer + * A buffer to hold the value being read. + * @param[in/out] lengthP + * Length of the buffer being supplied. If the attribute + * value is longer than the size of the supplied buffer, + * this variable will hold upon return the total attribute value length + * (excluding offset). The application may use this + * information to allocate a suitable buffer size. + * + * @return BLE_ERROR_NONE if a value was read successfully into the buffer. + */ + virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Read the value of a characteristic from the local GattServer + * @param[in] connectionHandle + * Connection Handle. + * @param[in] attributeHandle + * Attribute handle for the value attribute of the characteristic. + * @param[out] buffer + * A buffer to hold the value being read. + * @param[in/out] lengthP + * Length of the buffer being supplied. If the attribute + * value is longer than the size of the supplied buffer, + * this variable will hold upon return the total attribute value length + * (excluding offset). The application may use this + * information to allocate a suitable buffer size. + * + * @return BLE_ERROR_NONE if a value was read successfully into the buffer. + * + * @note This API is a version of above with an additional connection handle + * parameter to allow fetches for connection-specific multivalued + * attribtues (such as the CCCDs). + */ + virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Update the value of a characteristic on the local GattServer. + * + * @param[in] attributeHandle + * Handle for the value attribute of the Characteristic. + * @param[in] value + * A pointer to a buffer holding the new value + * @param[in] size + * Size of the new value (in bytes). + * @param[in] localOnly + * Should this update be kept on the local + * GattServer regardless of the state of the + * notify/indicate flag in the CCCD for this + * Characteristic? If set to true, no notification + * or indication is generated. + * + * @return BLE_ERROR_NONE if we have successfully set the value of the attribute. + */ + virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t *, uint16_t, bool localOnly = false) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * Update the value of a characteristic on the local GattServer. A version + * of the same as above with connection handle parameter to allow updates + * for connection-specific multivalued attribtues (such as the CCCDs). + * + * @param[in] connectionHandle + * Connection Handle. + * @param[in] attributeHandle + * Handle for the value attribute of the Characteristic. + * @param[in] value + * A pointer to a buffer holding the new value + * @param[in] size + * Size of the new value (in bytes). + * @param[in] localOnly + * Should this update be kept on the local + * GattServer regardless of the state of the + * notify/indicate flag in the CCCD for this + * Characteristic? If set to true, no notification + * or indication is generated. + * + * @return BLE_ERROR_NONE if we have successfully set the value of the attribute. + */ + virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t *, uint16_t, bool localOnly = false) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this API if this capability is supported. */ + } + + /** + * A virtual function to allow underlying stacks to indicate if they support + * onDataRead(). It should be overridden to return true as applicable. + */ + virtual bool isOnDataReadAvailable() const { + return false; /* default implementation; override this API if this capability is supported. */ + } + + /* + * APIs with non-virtual implementations. + */ +public: + /** + * Add a callback for the GATT event DATA_SENT (which is triggered when + * updates are sent out by GATT in the form of notifications). + * + * @Note: it is possible to chain together multiple onDataSent callbacks + * (potentially from different modules of an application) to receive updates + * to characteristics. + * + * @Note: it is also possible to setup a callback into a member function of + * some object. + */ + void onDataSent(void (*callback)(unsigned count)) {dataSentCallChain.add(callback);} + template + void onDataSent(T *objPtr, void (T::*memberPtr)(unsigned count)) { + dataSentCallChain.add(objPtr, memberPtr); + } + + /** + * Setup a callback for when an attribute has its value updated by or at the + * connected peer. For a peripheral, this callback triggered when the local + * GATT server has an attribute updated by a write command from the peer. + * For a Central, this callback is triggered when a response is received for + * a write request. + * + * @Note: it is possible to chain together multiple onDataWritten callbacks + * (potentially from different modules of an application) to receive updates + * to characteristics. Many services, such as DFU and UART add their own + * onDataWritten callbacks behind the scenes to trap interesting events. + * + * @Note: it is also possible to setup a callback into a member function of + * some object. + */ + void onDataWritten(void (*callback)(const GattWriteCallbackParams *eventDataP)) {dataWrittenCallChain.add(callback);} + template + void onDataWritten(T *objPtr, void (T::*memberPtr)(const GattWriteCallbackParams *context)) { + dataWrittenCallChain.add(objPtr, memberPtr); + } + + /** + * Setup a callback to be invoked on the peripheral when an attribute is + * being read by a remote client. + * + * @Note: this functionality may not be available on all underlying stacks. + * You could use GattCharacteristic::setReadAuthorizationCallback() as an + * alternative. + * + * @Note: it is possible to chain together multiple onDataRead callbacks + * (potentially from different modules of an application) to receive updates + * to characteristics. Services may add their own onDataRead callbacks + * behind the scenes to trap interesting events. + * + * @Note: it is also possible to setup a callback into a member function of + * some object. + * + * @return BLE_ERROR_NOT_IMPLEMENTED if this functionality isn't available; + * else BLE_ERROR_NONE. + */ + ble_error_t onDataRead(void (*callback)(const GattReadCallbackParams *eventDataP)) { + if (!isOnDataReadAvailable()) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + + dataReadCallChain.add(callback); + return BLE_ERROR_NONE; + } + template + ble_error_t onDataRead(T *objPtr, void (T::*memberPtr)(const GattReadCallbackParams *context)) { + if (!isOnDataReadAvailable()) { + return BLE_ERROR_NOT_IMPLEMENTED; + } + + dataReadCallChain.add(objPtr, memberPtr); + return BLE_ERROR_NONE; + } + + /** + * Setup a callback for when notifications/indications are enabled for a + * characteristic on the local GattServer. + */ + void onUpdatesEnabled(EventCallback_t callback) {updatesEnabledCallback = callback;} + + /** + * Setup a callback for when notifications/indications are disabled for a + * characteristic on the local GattServer. + */ + void onUpdatesDisabled(EventCallback_t callback) {updatesDisabledCallback = callback;} + + /** + * Setup a callback for when the GATT server receives a response for an + * indication event sent previously. + */ + void onConfirmationReceived(EventCallback_t callback) {confirmationReceivedCallback = callback;} + + /* Entry points for the underlying stack to report events back to the user. */ +protected: + void handleDataWrittenEvent(const GattWriteCallbackParams *params) { + if (dataWrittenCallChain.hasCallbacksAttached()) { + dataWrittenCallChain.call(params); + } + } + + void handleDataReadEvent(const GattReadCallbackParams *params) { + if (dataReadCallChain.hasCallbacksAttached()) { + dataReadCallChain.call(params); + } + } + + void handleEvent(GattServerEvents::gattEvent_e type, GattAttribute::Handle_t charHandle) { + switch (type) { + case GattServerEvents::GATT_EVENT_UPDATES_ENABLED: + if (updatesEnabledCallback) { + updatesEnabledCallback(charHandle); + } + break; + case GattServerEvents::GATT_EVENT_UPDATES_DISABLED: + if (updatesDisabledCallback) { + updatesDisabledCallback(charHandle); + } + break; + case GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED: + if (confirmationReceivedCallback) { + confirmationReceivedCallback(charHandle); + } + break; + default: + break; + } + } + + void handleDataSentEvent(unsigned count) { + if (dataSentCallChain.hasCallbacksAttached()) { + dataSentCallChain.call(count); + } + } + +protected: + uint8_t serviceCount; + uint8_t characteristicCount; + +private: + CallChainOfFunctionPointersWithContext dataSentCallChain; + CallChainOfFunctionPointersWithContext dataWrittenCallChain; + CallChainOfFunctionPointersWithContext dataReadCallChain; + EventCallback_t updatesEnabledCallback; + EventCallback_t updatesDisabledCallback; + EventCallback_t confirmationReceivedCallback; + +private: + /* disallow copy and assignment */ + GattServer(const GattServer &); + GattServer& operator=(const GattServer &); +}; + +#endif // ifndef __GATT_SERVER_H__ diff --git a/public/GattServerEvents.h b/ble/GattServerEvents.h similarity index 100% rename from public/GattServerEvents.h rename to ble/GattServerEvents.h diff --git a/public/GattService.h b/ble/GattService.h similarity index 100% rename from public/GattService.h rename to ble/GattService.h diff --git a/ble/SecurityManager.h b/ble/SecurityManager.h new file mode 100644 index 0000000..823adca --- /dev/null +++ b/ble/SecurityManager.h @@ -0,0 +1,215 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SECURITY_MANAGER_H__ +#define __SECURITY_MANAGER_H__ + +#include + +#include "Gap.h" + +class SecurityManager { +public: + enum SecurityMode_t { + SECURITY_MODE_NO_ACCESS, + SECURITY_MODE_ENCRYPTION_OPEN_LINK, /**< require no protection, open link. */ + SECURITY_MODE_ENCRYPTION_NO_MITM, /**< require encryption, but no MITM protection. */ + SECURITY_MODE_ENCRYPTION_WITH_MITM, /**< require encryption and MITM protection. */ + SECURITY_MODE_SIGNED_NO_MITM, /**< require signing or encryption, but no MITM protection. */ + SECURITY_MODE_SIGNED_WITH_MITM, /**< require signing or encryption, and MITM protection. */ + }; + + /** + * @brief Defines possible security status/states. + * + * @details Defines possible security status/states of a link when requested by getLinkSecurity(). + */ + enum LinkSecurityStatus_t { + NOT_ENCRYPTED, /**< The link is not secured. */ + ENCRYPTION_IN_PROGRESS, /**< Link security is being established.*/ + ENCRYPTED /**< The link is secure.*/ + }; + + enum SecurityIOCapabilities_t { + IO_CAPS_DISPLAY_ONLY = 0x00, /**< Display Only. */ + IO_CAPS_DISPLAY_YESNO = 0x01, /**< Display and Yes/No entry. */ + IO_CAPS_KEYBOARD_ONLY = 0x02, /**< Keyboard Only. */ + IO_CAPS_NONE = 0x03, /**< No I/O capabilities. */ + IO_CAPS_KEYBOARD_DISPLAY = 0x04, /**< Keyboard and Display. */ + }; + + enum SecurityCompletionStatus_t { + SEC_STATUS_SUCCESS = 0x00, /**< Procedure completed with success. */ + SEC_STATUS_TIMEOUT = 0x01, /**< Procedure timed out. */ + SEC_STATUS_PDU_INVALID = 0x02, /**< Invalid PDU received. */ + SEC_STATUS_PASSKEY_ENTRY_FAILED = 0x81, /**< Passkey entry failed (user canceled or other). */ + SEC_STATUS_OOB_NOT_AVAILABLE = 0x82, /**< Out of Band Key not available. */ + SEC_STATUS_AUTH_REQ = 0x83, /**< Authentication requirements not met. */ + SEC_STATUS_CONFIRM_VALUE = 0x84, /**< Confirm value failed. */ + SEC_STATUS_PAIRING_NOT_SUPP = 0x85, /**< Pairing not supported. */ + SEC_STATUS_ENC_KEY_SIZE = 0x86, /**< Encryption key size. */ + SEC_STATUS_SMP_CMD_UNSUPPORTED = 0x87, /**< Unsupported SMP command. */ + SEC_STATUS_UNSPECIFIED = 0x88, /**< Unspecified reason. */ + SEC_STATUS_REPEATED_ATTEMPTS = 0x89, /**< Too little time elapsed since last attempt. */ + SEC_STATUS_INVALID_PARAMS = 0x8A, /**< Invalid parameters. */ + }; + + /** + * Declaration of type containing a passkey to be used during pairing. This + * is passed into initializeSecurity() to specify a pre-programmed passkey + * for authentication instead of generating a random one. + */ + static const unsigned PASSKEY_LEN = 6; + typedef uint8_t Passkey_t[PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ + +public: + typedef void (*HandleSpecificEvent_t)(Gap::Handle_t handle); + typedef void (*SecuritySetupInitiatedCallback_t)(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps); + typedef void (*SecuritySetupCompletedCallback_t)(Gap::Handle_t, SecurityCompletionStatus_t status); + typedef void (*LinkSecuredCallback_t)(Gap::Handle_t handle, SecurityMode_t securityMode); + typedef void (*PasskeyDisplayCallback_t)(Gap::Handle_t handle, const Passkey_t passkey); + + /* + * The following functions are meant to be overridden in the platform-specific sub-class. + */ +public: + /** + * Enable the BLE stack's Security Manager. The Security Manager implements + * the actual cryptographic algorithms and protocol exchanges that allow two + * devices to securely exchange data and privately detect each other. + * Calling this API is a prerequisite for encryption and pairing (bonding). + * + * @param[in] enableBonding Allow for bonding. + * @param[in] requireMITM Require protection for man-in-the-middle attacks. + * @param[in] iocaps To specify IO capabilities of this peripheral, + * such as availability of a display or keyboard to + * support out-of-band exchanges of security data. + * @param[in] passkey To specify a static passkey. + * + * @return BLE_ERROR_NONE on success. + */ + virtual ble_error_t init(bool enableBonding = true, + bool requireMITM = true, + SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, + const Passkey_t passkey = NULL) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this if security is supported. */ + } + + /** + * Get the security status of a connection. + * + * @param[in] connectionHandle Handle to identify the connection. + * @param[out] securityStatusP security status. + * + * @return BLE_SUCCESS Or appropriate error code indicating reason for failure. + */ + virtual ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this if security is supported. */ + } + + /** + * Delete all peer device context and all related bonding information from + * the database within the security manager. + * + * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure. + * @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization and/or + * application registration. + */ + virtual ble_error_t purgeAllBondingState(void) { + return BLE_ERROR_NOT_IMPLEMENTED; /* default implementation; override this if security is supported. */ + } + + /* Event callback handlers. */ +public: + /** + * To indicate that security procedure for link has started. + */ + virtual void onSecuritySetupInitiated(SecuritySetupInitiatedCallback_t callback) {securitySetupInitiatedCallback = callback;} + + /** + * To indicate that security procedure for link has completed. + */ + virtual void onSecuritySetupCompleted(SecuritySetupCompletedCallback_t callback) {securitySetupCompletedCallback = callback;} + + /** + * To indicate that link with the peer is secured. For bonded devices, + * subsequent re-connections with bonded peer will result only in this callback + * when the link is secured and setup procedures will not occur unless the + * bonding information is either lost or deleted on either or both sides. + */ + virtual void onLinkSecured(LinkSecuredCallback_t callback) {linkSecuredCallback = callback;} + + /** + * To indicate that device context is stored persistently. + */ + virtual void onSecurityContextStored(HandleSpecificEvent_t callback) {securityContextStoredCallback = callback;} + + /** + * To set the callback for when the passkey needs to be displayed on a peripheral with DISPLAY capability. + */ + virtual void onPasskeyDisplay(PasskeyDisplayCallback_t callback) {passkeyDisplayCallback = callback;} + + /* Entry points for the underlying stack to report events back to the user. */ +public: + void processSecuritySetupInitiatedEvent(Gap::Handle_t handle, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps) { + if (securitySetupInitiatedCallback) { + securitySetupInitiatedCallback(handle, allowBonding, requireMITM, iocaps); + } + } + + void processSecuritySetupCompletedEvent(Gap::Handle_t handle, SecurityCompletionStatus_t status) { + if (securitySetupCompletedCallback) { + securitySetupCompletedCallback(handle, status); + } + } + + void processLinkSecuredEvent(Gap::Handle_t handle, SecurityMode_t securityMode) { + if (linkSecuredCallback) { + linkSecuredCallback(handle, securityMode); + } + } + + void processSecurityContextStoredEvent(Gap::Handle_t handle) { + if (securityContextStoredCallback) { + securityContextStoredCallback(handle); + } + } + + void processPasskeyDisplayEvent(Gap::Handle_t handle, const Passkey_t passkey) { + if (passkeyDisplayCallback) { + passkeyDisplayCallback(handle, passkey); + } + } + +protected: + SecurityManager() : + securitySetupInitiatedCallback(), + securitySetupCompletedCallback(), + linkSecuredCallback(), + securityContextStoredCallback(), + passkeyDisplayCallback() { + /* empty */ + } + +protected: + SecuritySetupInitiatedCallback_t securitySetupInitiatedCallback; + SecuritySetupCompletedCallback_t securitySetupCompletedCallback; + LinkSecuredCallback_t linkSecuredCallback; + HandleSpecificEvent_t securityContextStoredCallback; + PasskeyDisplayCallback_t passkeyDisplayCallback; +}; + +#endif /*__SECURITY_MANAGER_H__*/ diff --git a/ble/ServiceDiscovery.h b/ble/ServiceDiscovery.h new file mode 100644 index 0000000..d946e1b --- /dev/null +++ b/ble/ServiceDiscovery.h @@ -0,0 +1,143 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SERVICE_DISOVERY_H__ +#define __SERVICE_DISOVERY_H__ + +#include "UUID.h" +#include "Gap.h" +#include "GattAttribute.h" + +class DiscoveredService; +class DiscoveredCharacteristic; + +class ServiceDiscovery { +public: + /* + * Exposed application callback types. + */ + + /** + * Callback type for when a matching Service is found during service- + * discovery. The receiving function is passed in a pointer to a + * DiscoveredService object which will remain valid for the lifetime of the + * callback. Memory for this object is owned by the BLE_API eventing + * framework. The application can safely make a persistent shallow-copy of + * this object in order to work with the service beyond the callback. + */ + typedef void (*ServiceCallback_t)(const DiscoveredService *); + + /** + * Callback type for when a matching Characteristic is found during service- + * discovery. The receiving function is passed in a pointer to a + * DiscoveredCharacteristic object which will remain valid for the lifetime + * of the callback. Memory for this object is owned by the BLE_API eventing + * framework. The application can safely make a persistent shallow-copy of + * this object in order to work with the characteristic beyond the callback. + */ + typedef void (*CharacteristicCallback_t)(const DiscoveredCharacteristic *); + + /** + * Callback type for when serviceDiscovery terminates. + */ + typedef void (*TerminationCallback_t)(Gap::Handle_t connectionHandle); + +public: + /** + * Launch service discovery. Once launched, service discovery will remain + * active with callbacks being issued back into the application for matching + * services/characteristics. isActive() can be used to determine status; and + * a termination callback (if setup) will be invoked at the end. Service + * discovery can be terminated prematurely if needed using terminate(). + * + * @param connectionHandle + * Handle for the connection with the peer. + * @param sc + * This is the application callback for matching service. Taken as + * NULL by default. Note: service discovery may still be active + * when this callback is issued; calling asynchronous BLE-stack + * APIs from within this application callback might cause the + * stack to abort service discovery. If this becomes an issue, it + * may be better to make local copy of the discoveredService and + * wait for service discovery to terminate before operating on the + * service. + * @param cc + * This is the application callback for matching characteristic. + * Taken as NULL by default. Note: service discovery may still be + * active when this callback is issued; calling asynchronous + * BLE-stack APIs from within this application callback might cause + * the stack to abort service discovery. If this becomes an issue, + * it may be better to make local copy of the discoveredCharacteristic + * and wait for service discovery to terminate before operating on the + * characteristic. + * @param matchingServiceUUID + * UUID based filter for specifying a service in which the application is + * interested. By default it is set as the wildcard UUID_UNKNOWN, + * in which case it matches all services. If characteristic-UUID + * filter (below) is set to the wildcard value, then a service + * callback will be invoked for the matching service (or for every + * service if the service filter is a wildcard). + * @param matchingCharacteristicUUIDIn + * UUID based filter for specifying characteristic in which the application + * is interested. By default it is set as the wildcard UUID_UKNOWN + * to match against any characteristic. If both service-UUID + * filter and characteristic-UUID filter are used with non- wildcard + * values, then only a single characteristic callback is + * invoked for the matching characteristic. + * + * @note Using wildcard values for both service-UUID and characteristic- + * UUID will result in complete service discovery--callbacks being + * called for every service and characteristic. + * + * @note Providing NULL for the characteristic callback will result in + * characteristic discovery being skipped for each matching + * service. This allows for an inexpensive method to discover only + * services. + * + * @return + * BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error. + */ + virtual ble_error_t launch(Gap::Handle_t connectionHandle, + ServiceCallback_t sc = NULL, + CharacteristicCallback_t cc = NULL, + const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN), + const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) = 0; + + /** + * Is service-discovery currently active? + */ + virtual bool isActive(void) const = 0; + + /** + * Terminate an ongoing service-discovery. This should result in an + * invocation of the TerminationCallback if service-discovery is active. + */ + virtual void terminate(void) = 0; + + /** + * Setup callback to be invoked when service discovery is terminated. + */ + virtual void onTermination(TerminationCallback_t callback) = 0; + +protected: + Gap::Handle_t connHandle; /**< Connection handle as provided by the SoftDevice. */ + UUID matchingServiceUUID; + ServiceCallback_t serviceCallback; + UUID matchingCharacteristicUUID; + CharacteristicCallback_t characteristicCallback; +}; + +#endif // ifndef __SERVICE_DISOVERY_H__ diff --git a/public/UUID.h b/ble/UUID.h similarity index 97% rename from public/UUID.h rename to ble/UUID.h index 6a54f5e..fc32098 100644 --- a/public/UUID.h +++ b/ble/UUID.h @@ -17,6 +17,7 @@ #ifndef __UUID_H__ #define __UUID_H__ +#include #include #include "blecommon.h" @@ -28,9 +29,10 @@ public: UUID_TYPE_LONG = 1 // Full 128-bit UUID }; + typedef uint16_t ShortUUIDBytes_t; + static const unsigned LENGTH_OF_LONG_UUID = 16; - typedef uint16_t ShortUUIDBytes_t; - typedef uint8_t LongUUIDBytes_t[LENGTH_OF_LONG_UUID]; + typedef uint8_t LongUUIDBytes_t[LENGTH_OF_LONG_UUID]; public: /** diff --git a/common/blecommon.h b/ble/blecommon.h similarity index 90% rename from common/blecommon.h rename to ble/blecommon.h index d649bb0..1de64eb 100644 --- a/common/blecommon.h +++ b/ble/blecommon.h @@ -21,8 +21,6 @@ extern "C" { #endif -#include -#include /** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs * @{ */ @@ -115,18 +113,18 @@ enum { \brief Error codes for the BLE API */ /**************************************************************************/ -typedef enum ble_error_e -{ - BLE_ERROR_NONE = 0, /**< No error */ - BLE_ERROR_BUFFER_OVERFLOW = 1, /**< The requested action would cause a buffer overflow and has been aborted */ - BLE_ERROR_NOT_IMPLEMENTED = 2, /**< Requested a feature that isn't yet implement or isn't supported by the target HW */ - BLE_ERROR_PARAM_OUT_OF_RANGE = 3, /**< One of the supplied parameters is outside the valid range */ - BLE_ERROR_INVALID_PARAM = 4, /**< One of the supplied parameters is invalid */ - BLE_STACK_BUSY = 5, /**< The stack is busy */ - BLE_ERROR_INVALID_STATE = 6, /**< Invalid state. */ - BLE_ERROR_NO_MEM = 7, /**< Out of Memory */ - BLE_ERROR_UNSPECIFIED = 8, /**< Unknown error. */ -} ble_error_t; +enum ble_error_t { + BLE_ERROR_NONE = 0, /**< No error */ + BLE_ERROR_BUFFER_OVERFLOW = 1, /**< The requested action would cause a buffer overflow and has been aborted */ + BLE_ERROR_NOT_IMPLEMENTED = 2, /**< Requested a feature that isn't yet implement or isn't supported by the target HW */ + BLE_ERROR_PARAM_OUT_OF_RANGE = 3, /**< One of the supplied parameters is outside the valid range */ + BLE_ERROR_INVALID_PARAM = 4, /**< One of the supplied parameters is invalid */ + BLE_STACK_BUSY = 5, /**< The stack is busy */ + BLE_ERROR_INVALID_STATE = 6, /**< Invalid state. */ + BLE_ERROR_NO_MEM = 7, /**< Out of Memory */ + BLE_ERROR_OPERATION_NOT_PERMITTED = 8, + BLE_ERROR_UNSPECIFIED = 9, /**< Unknown error. */ +}; #ifdef __cplusplus } diff --git a/services/BatteryService.h b/ble/services/BatteryService.h similarity index 86% rename from services/BatteryService.h rename to ble/services/BatteryService.h index d229d25..6bc0723 100644 --- a/services/BatteryService.h +++ b/ble/services/BatteryService.h @@ -17,7 +17,7 @@ #ifndef __BLE_BATTERY_SERVICE_H__ #define __BLE_BATTERY_SERVICE_H__ -#include "BLEDevice.h" +#include "ble/BLE.h" /** * @class BatteryService @@ -29,25 +29,19 @@ class BatteryService { public: /** * @param[ref] _ble - * BLEDevice object for the underlying controller. + * BLE object for the underlying controller. * @param[in] level * 8bit batterly level. Usually used to represent percentage of batterly charge remaining. */ - BatteryService(BLEDevice &_ble, uint8_t level = 100) : + BatteryService(BLE &_ble, uint8_t level = 100) : ble(_ble), batteryLevel(level), batteryLevelCharacteristic(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, &batteryLevel, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) { - static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */ - if (serviceAdded) { - return; - } - GattCharacteristic *charTable[] = {&batteryLevelCharacteristic}; GattService batteryService(GattService::UUID_BATTERY_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(batteryService); - serviceAdded = true; } /** @@ -62,8 +56,8 @@ public: ble.updateCharacteristicValue(batteryLevelCharacteristic.getValueAttribute().getHandle(), &batteryLevel, 1); } -private: - BLEDevice &ble; +protected: + BLE &ble; uint8_t batteryLevel; ReadOnlyGattCharacteristic batteryLevelCharacteristic; diff --git a/services/DFUService.h b/ble/services/DFUService.h similarity index 91% rename from services/DFUService.h rename to ble/services/DFUService.h index e99da11..253890e 100644 --- a/services/DFUService.h +++ b/ble/services/DFUService.h @@ -17,8 +17,8 @@ #ifndef __BLE_DFU_SERVICE_H__ #define __BLE_DFU_SERVICE_H__ -#include "BLEDevice.h" -#include "UUID.h" +#include "ble/BLE.h" +#include "ble/UUID.h" extern "C" void bootloader_start(void); @@ -48,17 +48,17 @@ public: * @brief Adds Device Firmware Update service to an existing ble object. * * @param[ref] _ble - * BLEDevice object for the underlying controller. + * BLE object for the underlying controller. * @param[in] _handoverCallback * Application specific handover callback. */ - DFUService(BLEDevice &_ble, ResetPrepare_t _handoverCallback = NULL) : + DFUService(BLE &_ble, ResetPrepare_t _handoverCallback = NULL) : ble(_ble), - controlBytes(), - packetBytes(), controlPoint(DFUServiceControlCharacteristicUUID, controlBytes, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), packet(DFUServicePacketCharacteristicUUID, packetBytes, SIZEOF_PACKET_BYTES, SIZEOF_PACKET_BYTES, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) { + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), + controlBytes(), + packetBytes() { static bool serviceAdded = false; /* We should only ever need to add the DFU service once. */ if (serviceAdded) { return; @@ -94,8 +94,8 @@ public: * @param[in] params * Information about the characterisitc being updated. */ - virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { - if (params->charHandle == controlPoint.getValueHandle()) { + virtual void onDataWritten(const GattWriteCallbackParams *params) { + if (params->handle == controlPoint.getValueHandle()) { /* At present, writing anything will do the trick--this needs to be improved. */ if (handoverCallback) { handoverCallback(); @@ -105,16 +105,12 @@ public: } } -private: +protected: static const unsigned SIZEOF_CONTROL_BYTES = 2; static const unsigned SIZEOF_PACKET_BYTES = 20; - static ResetPrepare_t handoverCallback; /**< application specific handover callback. */ - -private: - BLEDevice &ble; - uint8_t controlBytes[SIZEOF_CONTROL_BYTES]; - uint8_t packetBytes[SIZEOF_PACKET_BYTES]; +protected: + BLE &ble; /**< Writing to the control characteristic triggers the handover to dfu- * bootloader. At present, writing anything will do the trick--this needs @@ -127,6 +123,11 @@ private: * FOTA clients might get confused as service definitions change after * handing control over to the bootloader. */ GattCharacteristic packet; + + uint8_t controlBytes[SIZEOF_CONTROL_BYTES]; + uint8_t packetBytes[SIZEOF_PACKET_BYTES]; + + static ResetPrepare_t handoverCallback; /**< application specific handover callback. */ }; #endif /* #ifndef __BLE_DFU_SERVICE_H__*/ diff --git a/services/DeviceInformationService.h b/ble/services/DeviceInformationService.h similarity index 97% rename from services/DeviceInformationService.h rename to ble/services/DeviceInformationService.h index 5481225..9e72233 100644 --- a/services/DeviceInformationService.h +++ b/ble/services/DeviceInformationService.h @@ -17,7 +17,7 @@ #ifndef __BLE_DEVICE_INFORMATION_SERVICE_H__ #define __BLE_DEVICE_INFORMATION_SERVICE_H__ -#include "BLEDevice.h" +#include "ble/BLE.h" /** * @class DeviceInformationService @@ -31,7 +31,7 @@ public: * @brief Device Information Service Constructor. * * @param[ref] _ble - * BLEDevice object for the underlying controller. + * BLE object for the underlying controller. * @param[in] manufacturersName * This characteristic represents the name of the * manufacturer of the device. The name is copied into the @@ -57,7 +57,7 @@ public: * the software within the device. The value is copied * into the BLE stack during this constructor. */ - DeviceInformationService(BLEDevice &_ble, + DeviceInformationService(BLE &_ble, const char *manufacturersName = NULL, const char *modelNumber = NULL, const char *serialNumber = NULL, @@ -114,8 +114,8 @@ public: serviceAdded = true; } -private: - BLEDevice &ble; +protected: + BLE &ble; GattCharacteristic manufacturersNameStringCharacteristic; GattCharacteristic modelNumberStringCharacteristic; GattCharacteristic serialNumberStringCharacteristic; diff --git a/services/HealthThermometerService.h b/ble/services/HealthThermometerService.h similarity index 97% rename from services/HealthThermometerService.h rename to ble/services/HealthThermometerService.h index 3557fd3..2afa1e5 100644 --- a/services/HealthThermometerService.h +++ b/ble/services/HealthThermometerService.h @@ -17,7 +17,7 @@ #ifndef __BLE_HEALTH_THERMOMETER_SERVICE_H__ #define __BLE_HEALTH_THERMOMETER_SERVICE_H__ -#include "BLEDevice.h" +#include "BLE.h" /** * @class HealthThermometerService @@ -51,7 +51,7 @@ public: * @param[in] initialTemp initial value in celsius * @param[in] _location */ - HealthThermometerService(BLEDevice &_ble, float initialTemp, uint8_t _location) : + HealthThermometerService(BLE &_ble, float initialTemp, uint8_t _location) : ble(_ble), valueBytes(initialTemp), tempMeasurement(GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, (TemperatureValueBytes *)valueBytes.getPointer(), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), @@ -141,7 +141,7 @@ private: }; private: - BLEDevice &ble; + BLE &ble; TemperatureValueBytes valueBytes; ReadOnlyGattCharacteristic tempMeasurement; ReadOnlyGattCharacteristic tempLocation; diff --git a/services/HeartRateService.h b/ble/services/HeartRateService.h similarity index 90% rename from services/HeartRateService.h rename to ble/services/HeartRateService.h index 8da7747..606dc9f 100644 --- a/services/HeartRateService.h +++ b/ble/services/HeartRateService.h @@ -17,7 +17,7 @@ #ifndef __BLE_HEART_RATE_SERVICE_H__ #define __BLE_HEART_RATE_SERVICE_H__ -#include "BLEDevice.h" +#include "ble/BLE.h" /** * @class HeartRateService @@ -47,13 +47,13 @@ public: * @brief Constructor with 8bit HRM Counter value. * * @param[ref] _ble - * Reference to the underlying BLEDevice. + * Reference to the underlying BLE. * @param[in] hrmCounter (8-bit) * initial value for the hrm counter. * @param[in] location * Sensor's location. */ - HeartRateService(BLEDevice &_ble, uint8_t hrmCounter, uint8_t location) : + HeartRateService(BLE &_ble, uint8_t hrmCounter, uint8_t location) : ble(_ble), valueBytes(hrmCounter), hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(), @@ -68,13 +68,13 @@ public: * @brief Constructor with a 16-bit HRM Counter value. * * @param[in] _ble - * Reference to the underlying BLEDevice. + * Reference to the underlying BLE. * @param[in] hrmCounter (8-bit) * initial value for the hrm counter. * @param[in] location * Sensor's location. */ - HeartRateService(BLEDevice &_ble, uint16_t hrmCounter, uint8_t location) : + HeartRateService(BLE &_ble, uint16_t hrmCounter, uint8_t location) : ble(_ble), valueBytes(hrmCounter), hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(), @@ -114,8 +114,8 @@ public: * @param[in] params * Information about the characterisitc being updated. */ - virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { - if (params->charHandle == controlPoint.getValueAttribute().getHandle()) { + virtual void onDataWritten(const GattWriteCallbackParams *params) { + if (params->handle == controlPoint.getValueAttribute().getHandle()) { /* Do something here if the new value is 1; else you can override this method by * extending this class. * @NOTE: if you are extending this class, be sure to also call @@ -125,23 +125,16 @@ public: } } -private: +protected: void setupService(void) { - static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */ - if (serviceAdded) { - return; - } - GattCharacteristic *charTable[] = {&hrmRate, &hrmLocation, &controlPoint}; GattService hrmService(GattService::UUID_HEART_RATE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(hrmService); - serviceAdded = true; - ble.onDataWritten(this, &HeartRateService::onDataWritten); } -private: +protected: /* Private internal representation for the bytes used to work with the vaulue of the heart-rate characteristic. */ struct HeartRateValueBytes { static const unsigned MAX_VALUE_BYTES = 3; /* FLAGS + up to two bytes for heart-rate */ @@ -181,14 +174,14 @@ private: return 1 + ((valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) ? sizeof(uint16_t) : sizeof(uint8_t)); } -private: + private: /* First byte = 8-bit values, no extra info, Second byte = uint8_t HRM value */ /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */ uint8_t valueBytes[MAX_VALUE_BYTES]; }; -private: - BLEDevice &ble; +protected: + BLE &ble; HeartRateValueBytes valueBytes; uint8_t controlPointValue; diff --git a/services/LinkLossService.h b/ble/services/LinkLossService.h similarity index 91% rename from services/LinkLossService.h rename to ble/services/LinkLossService.h index 6604b24..88a0e04 100644 --- a/services/LinkLossService.h +++ b/ble/services/LinkLossService.h @@ -37,9 +37,9 @@ public: /** * @param[ref] ble - * BLEDevice object for the underlying controller. + * BLE object for the underlying controller. */ - LinkLossService(BLEDevice &bleIn, callback_t callbackIn, AlertLevel_t levelIn = NO_ALERT) : + LinkLossService(BLE &bleIn, callback_t callbackIn, AlertLevel_t levelIn = NO_ALERT) : ble(bleIn), alertLevel(levelIn), callback(callbackIn), @@ -80,7 +80,7 @@ private: * @param[in] params * Information about the characterisitc being updated. */ - virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { + virtual void onDataWritten(const GattWriteCallbackParams *params) { if (params->charHandle == alertLevelChar.getValueHandle()) { alertLevel = *reinterpret_cast(params->data); } @@ -92,8 +92,8 @@ private: } } -private: - BLEDevice &ble; +protected: + BLE &ble; AlertLevel_t alertLevel; callback_t callback; diff --git a/services/UARTService.h b/ble/services/UARTService.h similarity index 96% rename from services/UARTService.h rename to ble/services/UARTService.h index fab5578..64676fe 100644 --- a/services/UARTService.h +++ b/ble/services/UARTService.h @@ -20,8 +20,8 @@ #include "mbed.h" #include "Stream.h" -#include "UUID.h" -#include "BLEDevice.h" +#include "ble/UUID.h" +#include "ble/BLE.h" extern const uint8_t UARTServiceBaseUUID[UUID::LENGTH_OF_LONG_UUID]; extern const uint16_t UARTServiceShortUUID; @@ -48,9 +48,9 @@ public: /** * @param[ref] ble - * BLEDevice object for the underlying controller. + * BLE object for the underlying controller. */ - UARTService(BLEDevice &_ble) : + UARTService(BLE &_ble) : ble(_ble), receiveBuffer(), sendBuffer(), @@ -167,8 +167,8 @@ private: * function from the global onDataWritten() callback handler; or if that's * not used, this method can be used as a callback directly. */ - void onDataWritten(const GattCharacteristicWriteCBParams *params) { - if (params->charHandle == getTXCharacteristicHandle()) { + void onDataWritten(const GattWriteCallbackParams *params) { + if (params->handle == getTXCharacteristicHandle()) { uint16_t bytesRead = params->len; if (bytesRead <= BLE_UART_SERVICE_MAX_DATA_LEN) { numBytesReceived = bytesRead; @@ -179,7 +179,7 @@ private: } private: - BLEDevice &ble; + BLE &ble; uint8_t receiveBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which we receive * inbound data before forwarding it to the diff --git a/services/URIBeaconConfigService.h b/ble/services/URIBeaconConfigService.h similarity index 86% rename from services/URIBeaconConfigService.h rename to ble/services/URIBeaconConfigService.h index 432f440..4ceaa05 100644 --- a/services/URIBeaconConfigService.h +++ b/ble/services/URIBeaconConfigService.h @@ -17,7 +17,7 @@ #ifndef SERVICES_URIBEACONCONFIGSERVICE_H_ #define SERVICES_URIBEACONCONFIGSERVICE_H_ -#include "BLEDevice.h" +#include "ble/BLE.h" #include "mbed.h" extern const uint8_t UUID_URI_BEACON_SERVICE[UUID::LENGTH_OF_LONG_UUID]; @@ -71,7 +71,7 @@ class URIBeaconConfigService { /** * @param[ref] ble - * BLEDevice object for the underlying controller. + * BLE object for the underlying controller. * @param[in/out] paramsIn * Reference to application-visible beacon state, loaded * from persistent storage at startup. @@ -85,7 +85,7 @@ class URIBeaconConfigService { * @param[in] defaultAdvPowerLevelsIn * Default power-levels array; applies only if the resetToDefaultsFlag is true. */ - URIBeaconConfigService(BLEDevice &bleIn, + URIBeaconConfigService(BLE &bleIn, Params_t ¶msIn, bool resetToDefaultsFlag, const char *defaultURIDataIn, @@ -159,26 +159,26 @@ class URIBeaconConfigService { { const char DEVICE_NAME[] = "mUriBeacon Config"; - ble.clearAdvertisingPayload(); + ble.gap().clearAdvertisingPayload(); - ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + ble.gap().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(&DEVICE_NAME), sizeof(DEVICE_NAME)); - ble.accumulateScanResponse(GapAdvertisingData::TX_POWER_LEVEL, - reinterpret_cast(&defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]), - sizeof(uint8_t)); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID)); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG); + ble.gap().accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast(&DEVICE_NAME), sizeof(DEVICE_NAME)); + ble.gap().accumulateScanResponse(GapAdvertisingData::TX_POWER_LEVEL, + reinterpret_cast(&defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW]), + sizeof(uint8_t)); - ble.setTxPower(params.advPowerLevels[params.txPowerMode]); - ble.setDeviceName(reinterpret_cast(&DEVICE_NAME)); - ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); - ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC)); + ble.gap().setTxPower(params.advPowerLevels[params.txPowerMode]); + ble.gap().setDeviceName(reinterpret_cast(&DEVICE_NAME)); + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + ble.gap().setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC)); } /* Helper function to switch to the non-connectible normal mode for URIBeacon. This gets called after a timeout. */ @@ -202,12 +202,12 @@ class URIBeaconConfigService { extern void saveURIBeaconConfigParams(const Params_t *paramsP); /* forward declaration; necessary to avoid a circular dependency. */ saveURIBeaconConfigParams(¶ms); - ble.clearAdvertisingPayload(); - ble.setTxPower(params.advPowerLevels[params.txPowerMode]); - ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); - ble.setAdvertisingInterval(beaconPeriod); - ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); + ble.gap().clearAdvertisingPayload(); + ble.gap().setTxPower(params.advPowerLevels[params.txPowerMode]); + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); + ble.gap().setAdvertisingInterval(beaconPeriod); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); serviceData[serviceDataLen++] = BEACON_UUID[0]; serviceData[serviceDataLen++] = BEACON_UUID[1]; @@ -216,7 +216,7 @@ class URIBeaconConfigService { for (unsigned j = 0; j < uriDataLength; j++) { serviceData[serviceDataLen++] = uriData[j]; } - ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen); } private: @@ -232,8 +232,8 @@ class URIBeaconConfigService { * characteristics of this service. Attempts to do so are also applied to * the internal state of this service object. */ - void onDataWrittenCallback(const GattCharacteristicWriteCBParams *writeParams) { - uint16_t handle = writeParams->charHandle; + void onDataWrittenCallback(const GattWriteCallbackParams *writeParams) { + uint16_t handle = writeParams->handle; if (handle == lockChar.getValueHandle()) { // Validated earlier @@ -259,11 +259,11 @@ class URIBeaconConfigService { /* Re-map beaconPeriod to within permissible bounds if necessary. */ if (params.beaconPeriod != 0) { bool paramsUpdated = false; - if (params.beaconPeriod < ble.getMinAdvertisingInterval()) { - params.beaconPeriod = ble.getMinAdvertisingInterval(); + if (params.beaconPeriod < ble.gap().getMinAdvertisingInterval()) { + params.beaconPeriod = ble.gap().getMinAdvertisingInterval(); paramsUpdated = true; - } else if (params.beaconPeriod > ble.getMaxAdvertisingInterval()) { - params.beaconPeriod = ble.getMaxAdvertisingInterval(); + } else if (params.beaconPeriod > ble.gap().getMaxAdvertisingInterval()) { + params.beaconPeriod = ble.gap().getMaxAdvertisingInterval(); paramsUpdated = true; } if (paramsUpdated) { @@ -305,8 +305,8 @@ class URIBeaconConfigService { reinterpret_cast(params.advPowerLevels), sizeof(PowerLevels_t)); } - private: - void lockAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) { +private: + void lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams) { if (lockedState) { authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION; } else if (authParams->len != sizeof(Lock_t)) { @@ -319,7 +319,7 @@ class URIBeaconConfigService { } - void unlockAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) { + void unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams) { if (!lockedState) { authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; } else if (authParams->len != sizeof(Lock_t)) { @@ -333,7 +333,7 @@ class URIBeaconConfigService { } } - void uriDataWriteAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) { + void uriDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams) { if (lockedState) { authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION; } else if (authParams->offset != 0) { @@ -343,7 +343,7 @@ class URIBeaconConfigService { } } - void powerModeAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) { + void powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams) { if (lockedState) { authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION; } else if (authParams->len != sizeof(uint8_t)) { @@ -358,7 +358,7 @@ class URIBeaconConfigService { } template - void basicAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) { + void basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams) { if (lockedState) { authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION; } else if (authParams->len != sizeof(T)) { @@ -370,7 +370,8 @@ class URIBeaconConfigService { } } - BLEDevice &ble; +protected: + BLE &ble; Params_t ¶ms; size_t defaultUriDataLength; // Default value that is restored on reset @@ -391,7 +392,7 @@ class URIBeaconConfigService { ReadWriteGattCharacteristic beaconPeriodChar; WriteOnlyGattCharacteristic resetChar; - public: +public: /* * Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification). */ diff --git a/services/iBeaconService.h b/ble/services/iBeaconService.h similarity index 93% rename from services/iBeaconService.h rename to ble/services/iBeaconService.h index 4ff7345..a3f6af7 100644 --- a/services/iBeaconService.h +++ b/ble/services/iBeaconService.h @@ -1,74 +1,74 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2015 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __BLE_IBEACON_SERVICE_H__ -#define __BLE_IBEACON_SERVICE_H__ - -#include "core_cmInstr.h" -#include "BLEDevice.h" - -/** -* @class iBeaconService -* @brief iBeacon Service. This service sets up a device to broadcast advertising packets to mimic an iBeacon
-*/ - -class iBeaconService -{ -public: - typedef const uint8_t LocationUUID_t[16]; - - union Payload { - uint8_t raw[25]; - struct { - uint16_t companyID; - uint8_t ID; - uint8_t len; - uint8_t proximityUUID[16]; - uint16_t majorNumber; - uint16_t minorNumber; - uint8_t txPower; - }; - - Payload(LocationUUID_t uuid, uint16_t majNum, uint16_t minNum, uint8_t transmitPower, uint16_t companyIDIn) : - companyID(companyIDIn), ID(0x02), len(0x15), majorNumber(__REV16(majNum)), minorNumber(__REV16(minNum)), txPower(transmitPower) - { - memcpy(proximityUUID, uuid, sizeof(LocationUUID_t)); - } - }; - -public: - iBeaconService(BLEDevice &_ble, - LocationUUID_t uuid, - uint16_t majNum, - uint16_t minNum, - uint8_t txP = 0xC8, - uint16_t compID = 0x004C) : - ble(_ble), data(uuid, majNum, minNum, txP, compID) - { - // Generate the 0x020106 part of the iBeacon Prefix - ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE ); - // Generate the 0x1AFF part of the iBeacon Prefix - ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, data.raw, sizeof(data.raw)); - - // Set advertising type - ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); - } - -private: - BLEDevice &ble; - Payload data; -}; - -#endif //__BLE_IBEACON_SERVICE_H__ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __BLE_IBEACON_SERVICE_H__ +#define __BLE_IBEACON_SERVICE_H__ + +#include "core_cmInstr.h" +#include "BLE.h" + +/** +* @class iBeaconService +* @brief iBeacon Service. This service sets up a device to broadcast advertising packets to mimic an iBeacon
+*/ + +class iBeaconService +{ +public: + typedef const uint8_t LocationUUID_t[16]; + + union Payload { + uint8_t raw[25]; + struct { + uint16_t companyID; + uint8_t ID; + uint8_t len; + uint8_t proximityUUID[16]; + uint16_t majorNumber; + uint16_t minorNumber; + uint8_t txPower; + }; + + Payload(LocationUUID_t uuid, uint16_t majNum, uint16_t minNum, uint8_t transmitPower, uint16_t companyIDIn) : + companyID(companyIDIn), ID(0x02), len(0x15), majorNumber(__REV16(majNum)), minorNumber(__REV16(minNum)), txPower(transmitPower) + { + memcpy(proximityUUID, uuid, sizeof(LocationUUID_t)); + } + }; + +public: + iBeaconService(BLE &_ble, + LocationUUID_t uuid, + uint16_t majNum, + uint16_t minNum, + uint8_t txP = 0xC8, + uint16_t compID = 0x004C) : + ble(_ble), data(uuid, majNum, minNum, txP, compID) + { + // Generate the 0x020106 part of the iBeacon Prefix + ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE ); + // Generate the 0x1AFF part of the iBeacon Prefix + ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, data.raw, sizeof(data.raw)); + + // Set advertising type + ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); + } + +private: + BLE &ble; + Payload data; +}; + +#endif //__BLE_IBEACON_SERVICE_H__ diff --git a/common/readme.txt b/common/readme.txt deleted file mode 100644 index df4d6e4..0000000 --- a/common/readme.txt +++ /dev/null @@ -1 +0,0 @@ -These files are common to all implementations of the BLE_API. \ No newline at end of file diff --git a/module.json b/module.json new file mode 100644 index 0000000..d3fa167 --- /dev/null +++ b/module.json @@ -0,0 +1,29 @@ +{ + "name": "ble", + "version": "0.0.0", + "description": "The BLE module offers a high level abstraction for using Bluetooth Low Energy on multiple platforms.", + "keywords": [ + "Bluetooth", + "BLE" + ], + "author": "Rohit Grover", + "repository": { + "url": "git@github.com:mbedmicro/BLE_API.git", + "type": "git" + }, + "homepage": "http://mbed.org/ble", + "licenses": [ + { + "url": "https://spdx.org/licenses/Apache-2.0", + "type": "Apache-2.0" + } + ], + "dependencies": { + "mbed": "^3.0.2" + }, + "targetDependencies": { + "nrf51822": { + "ble-nrf51822":"~0.0.1" + } + } +} diff --git a/public/BLEDevice.h b/public/BLEDevice.h deleted file mode 100644 index b902896..0000000 --- a/public/BLEDevice.h +++ /dev/null @@ -1,1090 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __BLE_DEVICE__ -#define __BLE_DEVICE__ - -#include "blecommon.h" -#include "Gap.h" -#include "GattServer.h" -#include "GapScanningParams.h" -#include "BLEDeviceInstanceBase.h" - -/** - * The base class used to abstract away BLE capable radio transceivers or SOCs, - * to enable this BLE API to work with any radio transparently. - */ -class BLEDevice -{ -public: - /** - * Initialize the BLE controller. This should be called before using - * anything else in the BLE_API. - * - * init() hands control to the underlying BLE module to accomplish - * initialization. This initialization may tacitly depend on other hardware - * setup (such as clocks or power-modes) which happens early on during - * system startup. It may not be safe to call init() from global static - * context where ordering is compiler specific and can't be guaranteed--it - * is safe to call BLEDevice::init() from within main(). - */ - ble_error_t init(); - - ble_error_t reset(void); - - /** - * Purge the BLE stack of GATT and GAP state. init() must be called afterwards to re-instate services and GAP state. - */ - ble_error_t shutdown(void); - - /* GAP specific APIs */ -public: - /** - * Set the BTLE MAC address and type. - * @return BLE_ERROR_NONE on success. - */ - ble_error_t setAddress(Gap::AddressType_t type, const Gap::Address_t address); - - /** - * Fetch the BTLE MAC address and type. - * @return BLE_ERROR_NONE on success. - */ - ble_error_t getAddress(Gap::AddressType_t *typeP, Gap::Address_t address); - - /** - * @param[in] advType - * The GAP advertising mode to use for this device. Valid - * values are defined in AdvertisingType: - * - * \par ADV_NON_CONNECTABLE_UNDIRECTED - * All connections to the peripheral device will be refused. - * - * \par ADV_CONNECTABLE_DIRECTED - * Only connections from a pre-defined central device will be - * accepted. - * - * \par ADV_CONNECTABLE_UNDIRECTED - * Any central device can connect to this peripheral. - * - * \par ADV_SCANNABLE_UNDIRECTED - * Include support for Scan Response payloads. - * - * \par - * See Bluetooth Core Specification 4.0 (Vol. 3), Part C, - * Section 9.3 and Core Specification 4.0 (Vol. 6), Part B, - * Section 2.3.1 for further information on GAP connection - * modes - */ - void setAdvertisingType(GapAdvertisingParams::AdvertisingType); - - /** - * @param[in] interval - * Advertising interval in units of milliseconds. Advertising - * is disabled if interval is 0. If interval is smaller than - * the minimum supported value, then the minimum supported - * value is used instead. - * - * \par - * Decreasing this value will allow central devices to detect - * your peripheral faster at the expense of more power being - * used by the radio due to the higher data transmit rate. - * - * \par - * This field must be set to 0 if connectionMode is equal - * to ADV_CONNECTABLE_DIRECTED - * - * \par - * See Bluetooth Core Specification, Vol 3., Part C, - * Appendix A for suggested advertising intervals. - * - * @Note: [WARNING] This API previously used 0.625ms as the unit for its - * 'interval' argument. That required an explicit conversion from - * milliseconds using Gap::MSEC_TO_GAP_DURATION_UNITS(). This conversion is - * no longer required as the new units are milliseconds. Any application - * code depending on the old semantics would need to be updated accordingly. - */ - void setAdvertisingInterval(uint16_t interval); - - /** - * @return Minimum Advertising interval in milliseconds. - */ - uint16_t getMinAdvertisingInterval(void) const; - /** - * @return Minimum Advertising interval in milliseconds for non connectible mode. - */ - uint16_t getMinNonConnectableAdvertisingInterval(void) const; - /** - * @return Maximum Advertising interval in milliseconds. - */ - uint16_t getMaxAdvertisingInterval(void) const; - - /** - * @param[in] timeout - * Advertising timeout between 0x1 and 0x3FFF (1 and 16383) - * in seconds. Enter 0 to disable the advertising timeout. - */ - void setAdvertisingTimeout(uint16_t timeout); - - /** - * Please refer to the APIs above. - */ - void setAdvertisingParams(const GapAdvertisingParams &advParams); - - /** - * @return Read back advertising parameters. Useful for storing and - * restoring parameters rapidly. - */ - const GapAdvertisingParams &getAdvertisingParams(void) const; - - /** - * This API is typically used as an internal helper to udpate the transport - * backend with advertising data before starting to advertise. It may also - * be explicity used to dynamically reset the accumulated advertising - * payload and scanResponse; to do this, the application can clear and re- - * accumulate a new advertising payload (and scanResponse) before using this - * API. - */ - ble_error_t setAdvertisingPayload(void); - - /** - * Set advertising data using object. - */ - ble_error_t setAdvertisingData(const GapAdvertisingData &advData); - - /** - * @return Read back advertising data. Useful for storing and - * restoring payload. - */ - const GapAdvertisingData &getAdvertisingData(void) const; - - /** - * Reset any advertising payload prepared from prior calls to - * accumulateAdvertisingPayload(). - * - * Note: This should be followed by a call to setAdvertisingPayload() or - * startAdvertising() before the update takes effect. - */ - void clearAdvertisingPayload(void); - - /** - * Accumulate an AD structure in the advertising payload. Please note that - * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used - * as an additional 31 bytes if the advertising payload proves to be too - * small. - * - * @param flags - * The flags to be added. Multiple flags may be specified in - * combination. - */ - ble_error_t accumulateAdvertisingPayload(uint8_t flags); - - /** - * Accumulate an AD structure in the advertising payload. Please note that - * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used - * as an additional 31 bytes if the advertising payload proves to be too - * small. - * - * @param app - * The appearance of the peripheral. - */ - ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::Appearance app); - - /** - * Accumulate an AD structure in the advertising payload. Please note that - * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used - * as an additional 31 bytes if the advertising payload proves to be too - * small. - * - * @param app - * The max transmit power to be used by the controller. This is - * only a hint. - */ - ble_error_t accumulateAdvertisingPayloadTxPower(int8_t power); - - /** - * Accumulate a variable length byte-stream as an AD structure in the - * advertising payload. Please note that the payload is limited to 31 bytes. - * The SCAN_RESPONSE message may be used as an additional 31 bytes if the - * advertising payload proves to be too small. - * - * @param type The type which describes the variable length data. - * @param data data bytes. - * @param len length of data. - */ - ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len); - - /** - * Accumulate a variable length byte-stream as an AD structure in the - * scanResponse payload. - * - * @param type The type which describes the variable length data. - * @param data data bytes. - * @param len length of data. - */ - ble_error_t accumulateScanResponse(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len); - - /** - * Reset any scan response prepared from prior calls to - * accumulateScanResponse(). - * - * Note: This should be followed by a call to setAdvertisingPayload() or - * startAdvertising() before the update takes effect. - */ - void clearScanResponse(void); - - /** - * Start advertising (GAP Discoverable, Connectable modes, Broadcast - * Procedure). - */ - ble_error_t startAdvertising(void); - - /** - * Stop advertising (GAP Discoverable, Connectable modes, Broadcast - * Procedure). - */ - ble_error_t stopAdvertising(void); - - /** - * Setup parameters for GAP scanning--i.e. observer mode. - * @param interval Scan interval (in milliseconds) [valid values lie between 2.5ms and 10.24s]. - * @param window Scan Window (in milliseconds) [valid values lie between 2.5ms and 10.24s]. - * @param timeout Scan timeout (in seconds) between 0x0001 and 0xFFFF, 0x0000 disables timeout. - * @param activeScanning Set to True if active-scanning is required. This is used to fetch the - * scan response from a peer if possible. - * - * The scanning window divided by the interval determines the duty cycle for - * scanning. For example, if the interval is 100ms and the window is 10ms, - * then the controller will scan for 10 percent of the time. It is possible - * to have the interval and window set to the same value. In this case, - * scanning is continuous, with a change of scanning frequency once every - * interval. - * - * Once the scanning parameters have been configured, scanning can be - * enabled by using startScan(). - * - * @Note: The scan interval and window are recommendations to the BLE stack. - */ - ble_error_t setScanParams(uint16_t interval = GapScanningParams::SCAN_INTERVAL_MAX, - uint16_t window = GapScanningParams::SCAN_WINDOW_MAX, - uint16_t timeout = 0, - bool activeScanning = false); - ble_error_t setScanInterval(uint16_t interval); - ble_error_t setScanWindow (uint16_t window); - ble_error_t setScanTimeout (uint16_t timeout); - void setActiveScan (bool activeScanning); - - /** - * Start scanning (Observer Procedure) based on the scan-params currently - * in effect. - * - * @param callback The application callback to be invoked upon receiving - * every advertisement report. Can be passed in as NULL, in which case - * scanning may not be enabled at all. - */ - ble_error_t startScan(void (*callback)(const Gap::AdvertisementCallbackParams_t *params)); - - /** - * Start scanning (Observer Procedure) based on the scan-params currently - * in effect. - * - * @param[in] object - * @param[in] callbackMember - * The above pair of parameters define the callback object - * and member function to receive the advertisement params. - */ - template - ble_error_t startScan(T *object, void (T::*memberCallback)(const Gap::AdvertisementCallbackParams_t *params)); - - /** - * Stop scanning. The current scanning parameters remain in effect. - * - * @retval BLE_ERROR_NONE if successfully stopped scanning procedure. - */ - ble_error_t stopScan(void); - - /** - * This call initiates the disconnection procedure, and its completion will - * be communicated to the application with an invocation of the - * onDisconnection callback. - * - * @param reason - * The reason for disconnection to be sent back to the peer. - */ - ble_error_t disconnect(Gap::DisconnectionReason_t reason); - - /* APIs to set GAP callbacks. */ - void onTimeout(Gap::EventCallback_t timeoutCallback); - - void onConnection(Gap::ConnectionEventCallback_t connectionCallback); - /** - * Used to setup a callback for GAP disconnection. - */ - void onDisconnection(Gap::DisconnectionEventCallback_t disconnectionCallback); - - /** - * Append to a chain of callbacks to be invoked upon disconnection; these - * callbacks receive no context and are therefore different from the - * onDisconnection callback. - */ - template - void addToDisconnectionCallChain(T *tptr, void (T::*mptr)(void)); - - /** - * Add a callback for the GATT event DATA_SENT (which is triggered when - * updates are sent out by GATT in the form of notifications). - * - * @Note: it is possible to chain together multiple onDataSent callbacks - * (potentially from different modules of an application) to receive updates - * to characteristics. - * - * @Note: it is also possible to setup a callback into a member function of - * some object. - */ - void onDataSent(void (*callback)(unsigned count)); - template void onDataSent(T * objPtr, void (T::*memberPtr)(unsigned count)); - - /** - * Setup a callback for when a characteristic has its value updated by a - * client. - * - * @Note: it is possible to chain together multiple onDataWritten callbacks - * (potentially from different modules of an application) to receive updates - * to characteristics. Many services, such as DFU and UART add their own - * onDataWritten callbacks behind the scenes to trap interesting events. - * - * @Note: it is also possible to setup a callback into a member function of - * some object. - */ - void onDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP)); - template void onDataWritten(T * objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context)); - - /** - * Setup a callback for when a characteristic is being read by a client. - * - * @Note: this functionality may not be available on all underlying stacks. - * You could use GattCharacteristic::setReadAuthorizationCallback() as an - * alternative. - * - * @Note: it is possible to chain together multiple onDataRead callbacks - * (potentially from different modules of an application) to receive updates - * to characteristics. Services may add their own onDataRead callbacks - * behind the scenes to trap interesting events. - * - * @Note: it is also possible to setup a callback into a member function of - * some object. - * - * @return BLE_ERROR_NOT_IMPLEMENTED if this functionality isn't available; - * else BLE_ERROR_NONE. - */ - ble_error_t onDataRead(void (*callback)(const GattCharacteristicReadCBParams *eventDataP)); - template ble_error_t onDataRead(T * objPtr, void (T::*memberPtr)(const GattCharacteristicReadCBParams *context)); - - void onUpdatesEnabled(GattServer::EventCallback_t callback); - void onUpdatesDisabled(GattServer::EventCallback_t callback); - void onConfirmationReceived(GattServer::EventCallback_t callback); - - /** - * Radio Notification is a feature that enables ACTIVE and INACTIVE - * (nACTIVE) signals from the stack that notify the application when the - * radio is in use. The signal is sent using software interrupt. - * - * The ACTIVE signal is sent before the Radio Event starts. The nACTIVE - * signal is sent at the end of the Radio Event. These signals can be used - * by the application programmer to synchronize application logic with radio - * activity. For example, the ACTIVE signal can be used to shut off external - * devices to manage peak current drawn during periods when the radio is on, - * or to trigger sensor data collection for transmission in the Radio Event. - * - * @param callback - * The application handler to be invoked in response to a radio - * ACTIVE/INACTIVE event. - */ - void onRadioNotification(Gap::RadioNotificationEventCallback_t callback); - - /** - * Add a service declaration to the local server ATT table. Also add the - * characteristics contained within. - */ - ble_error_t addService(GattService &service); - - /** - * Returns the current GAP state of the device using a bitmask which - * describes whether the device is advertising and/or connected. - */ - Gap::GapState_t getGapState(void) const; - - /** - * @param[in/out] lengthP - * input: Length in bytes to be read, - * output: Total length of attribute value upon successful return. - */ - ble_error_t readCharacteristicValue(GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP); - /** - * A version of the same as above with connection handle parameter to allow fetches for connection-specific multivalued attribtues (such as the CCCDs). - */ - ble_error_t readCharacteristicValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP); - - /** - * @param localOnly - * Only update the characteristic locally regardless of notify/indicate flags in the CCCD. - */ - ble_error_t updateCharacteristicValue(GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly = false); - /** - * A version of the same as above with connection handle parameter to allow updates for connection-specific multivalued attribtues (such as the CCCDs). - */ - ble_error_t updateCharacteristicValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly = false); - - /** - * Yield control to the BLE stack or to other tasks waiting for events. This - * is a sleep function which will return when there is an application - * specific interrupt, but the MCU might wake up several times before - * returning (to service the stack). This is not always interchangeable with - * WFE(). - */ - void waitForEvent(void); - - ble_error_t getPreferredConnectionParams(Gap::ConnectionParams_t *params); - ble_error_t setPreferredConnectionParams(const Gap::ConnectionParams_t *params); - ble_error_t updateConnectionParams(Gap::Handle_t handle, const Gap::ConnectionParams_t *params); - - /** - * This call allows the application to get the BLE stack version information. - * - * @return A pointer to a const string representing the version. - * Note: The string is owned by the BLE_API. - */ - const char *getVersion(void); - - /** - * Set the device name characteristic in the GAP service. - * @param deviceName The new value for the device-name. This is a UTF-8 encoded, NULL-terminated string. - */ - ble_error_t setDeviceName(const uint8_t *deviceName); - - /** - * Get the value of the device name characteristic in the GAP service. - * @param[out] deviceName Pointer to an empty buffer where the UTF-8 *non NULL- - * terminated* string will be placed. Set this - * value to NULL in order to obtain the deviceName-length - * from the 'length' parameter. - * - * @param[in/out] lengthP (on input) Length of the buffer pointed to by deviceName; - * (on output) the complete device name length (without the - * null terminator). - * - * @note If the device name is longer than the size of the supplied buffer, - * length will return the complete device name length, - * and not the number of bytes actually returned in deviceName. - * The application may use this information to retry with a suitable buffer size. - * - * Sample use: - * uint8_t deviceName[20]; - * unsigned length = sizeof(deviceName); - * ble.getDeviceName(deviceName, &length); - * if (length < sizeof(deviceName)) { - * deviceName[length] = 0; - * } - * DEBUG("length: %u, deviceName: %s\r\n", length, deviceName); - */ - ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); - - /** - * Set the appearance characteristic in the GAP service. - * @param[in] appearance The new value for the device-appearance. - */ - ble_error_t setAppearance(uint16_t appearance); - - /** - * Set the appearance characteristic in the GAP service. - * @param[out] appearance The new value for the device-appearance. - */ - ble_error_t getAppearance(uint16_t *appearanceP); - - /** - * Set the radio's transmit power. - * @param[in] txPower Radio transmit power in dBm. - */ - ble_error_t setTxPower(int8_t txPower); - - /** - * Query the underlying stack for permitted arguments for setTxPower(). - * - * @param[out] valueArrayPP - * Out parameter to receive the immutable array of Tx values. - * @param[out] countP - * Out parameter to receive the array's size. - */ - void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); - - /** - * Enable the BLE stack's Security Manager. The Security Manager implements - * the actual cryptographic algorithms and protocol exchanges that allow two - * devices to securely exchange data and privately detect each other. - * Calling this API is a prerequisite for encryption and pairing (bonding). - * - * @param[in] enableBonding Allow for bonding. - * @param[in] requireMITM Require protection for man-in-the-middle attacks. - * @param[in] iocaps To specify IO capabilities of this peripheral, - * such as availability of a display or keyboard to - * support out-of-band exchanges of security data. - * @param[in] passkey To specify a static passkey. - * - * @return BLE_ERROR_NONE on success. - */ - ble_error_t initializeSecurity(bool enableBonding = true, - bool requireMITM = true, - Gap::SecurityIOCapabilities_t iocaps = Gap::IO_CAPS_NONE, - const Gap::Passkey_t passkey = NULL); - - /** - * Setup a callback for when the security setup procedure (key generation - * and exchange) for a link has started. This will be skipped for bonded - * devices. The callback is passed in parameters received from the peer's - * security request: bool allowBonding, bool requireMITM, and - * SecurityIOCapabilities_t. - */ - void onSecuritySetupInitiated(Gap::SecuritySetupInitiatedCallback_t callback); - - /** - * Setup a callback for when the security setup procedure (key generation - * and exchange) for a link has completed. This will be skipped for bonded - * devices. The callback is passed in the success/failure status of the - * security setup procedure. - */ - void onSecuritySetupCompleted(Gap::SecuritySetupCompletedCallback_t callback); - - /** - * Setup a callback for when a link with the peer is secured. For bonded - * devices, subsequent reconnections with bonded peer will result only in - * this callback when the link is secured and setup procedures will not - * occur unless the bonding information is either lost or deleted on either - * or both sides. The callback is passed in a Gap::SecurityMode_t according - * to the level of security in effect for the secured link. - */ - void onLinkSecured(Gap::LinkSecuredCallback_t callback); - - /** - * Setup a callback for successful bonding; i.e. that link-specific security - * context is stored persistently for a peer device. - */ - void onSecurityContextStored(Gap::HandleSpecificEvent_t callback); - - /** - * Setup a callback for when the passkey needs to be displayed on a - * peripheral with DISPLAY capability. This happens when security is - * configured to prevent Man-In-The-Middle attacks, and a PIN (or passkey) - * needs to be exchanged between the peers to authenticate the connection - * attempt. - */ - void onPasskeyDisplay(Gap::PasskeyDisplayCallback_t callback); - - /** - * Get the security status of a connection. - * - * @param[in] connectionHandle Handle to identify the connection. - * @param[out] securityStatusP security status. - * - * @return BLE_SUCCESS Or appropriate error code indicating reason for failure. - */ - ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, Gap::LinkSecurityStatus_t *securityStatusP); - - /** - * Delete all peer device context and all related bonding information from - * the database within the security manager. - * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure. - * @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization and/or - * application registration. - */ - ble_error_t purgeAllBondingState(void); - -public: - BLEDevice() : transport(createBLEDeviceInstance()), advParams(), advPayload(), scanResponse(), needToSetAdvPayload(true), scanningParams() { - advPayload.clear(); - scanResponse.clear(); - } - -private: - BLEDeviceInstanceBase *const transport; /* the device specific backend */ - - GapAdvertisingParams advParams; - GapAdvertisingData advPayload; - GapAdvertisingData scanResponse; - - /* Accumulation of AD structures in the advertisement payload should - * eventually result in a call to the target's setAdvertisingData() before - * the server begins advertising. This flag marks the status of the pending update.*/ - bool needToSetAdvPayload; - - GapScanningParams scanningParams; -}; - -/* BLEDevice methods. Most of these simply forward the calls to the underlying - * transport.*/ - -inline ble_error_t -BLEDevice::reset(void) -{ - return transport->reset(); -} - -inline ble_error_t -BLEDevice::shutdown(void) -{ - clearAdvertisingPayload(); - return transport->shutdown(); -} - -inline ble_error_t -BLEDevice::setAddress(Gap::AddressType_t type, const Gap::Address_t address) -{ - return transport->getGap().setAddress(type, address); -} - -inline ble_error_t -BLEDevice::getAddress(Gap::AddressType_t *typeP, Gap::Address_t address) -{ - return transport->getGap().getAddress(typeP, address); -} - -inline void -BLEDevice::setAdvertisingType(GapAdvertisingParams::AdvertisingType advType) -{ - advParams.setAdvertisingType(advType); -} - -inline void -BLEDevice::setAdvertisingInterval(uint16_t interval) -{ - if (interval == 0) { - stopAdvertising(); - } else if (interval < getMinAdvertisingInterval()) { - interval = getMinAdvertisingInterval(); - } - advParams.setInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(interval)); -} - -inline uint16_t -BLEDevice::getMinAdvertisingInterval(void) const { - return transport->getGap().getMinAdvertisingInterval(); -} - -inline uint16_t -BLEDevice::getMinNonConnectableAdvertisingInterval(void) const { - return transport->getGap().getMinNonConnectableAdvertisingInterval(); -} - -inline uint16_t -BLEDevice::getMaxAdvertisingInterval(void) const { - return transport->getGap().getMaxAdvertisingInterval(); -} - -inline void -BLEDevice::setAdvertisingTimeout(uint16_t timeout) -{ - advParams.setTimeout(timeout); -} - -inline void -BLEDevice::setAdvertisingParams(const GapAdvertisingParams &newAdvParams) -{ - advParams = newAdvParams; -} - -inline const GapAdvertisingParams & -BLEDevice::getAdvertisingParams(void) const -{ - return advParams; -} - -inline void -BLEDevice::clearAdvertisingPayload(void) -{ - needToSetAdvPayload = true; - advPayload.clear(); -} - -inline ble_error_t -BLEDevice::accumulateAdvertisingPayload(uint8_t flags) -{ - needToSetAdvPayload = true; - return advPayload.addFlags(flags); -} - -inline ble_error_t -BLEDevice::accumulateAdvertisingPayload(GapAdvertisingData::Appearance app) -{ - needToSetAdvPayload = true; - transport->getGap().setAppearance(app); - return advPayload.addAppearance(app); -} - -inline ble_error_t -BLEDevice::accumulateAdvertisingPayloadTxPower(int8_t txPower) -{ - needToSetAdvPayload = true; - return advPayload.addTxPower(txPower); -} - -inline ble_error_t -BLEDevice::accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) -{ - needToSetAdvPayload = true; - if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { - transport->getGap().setDeviceName(data); - } - return advPayload.addData(type, data, len); -} - -inline ble_error_t -BLEDevice::accumulateScanResponse(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) -{ - needToSetAdvPayload = true; - return scanResponse.addData(type, data, len); -} - -inline void -BLEDevice::clearScanResponse(void) -{ - needToSetAdvPayload = true; - scanResponse.clear(); -} - -inline ble_error_t -BLEDevice::setAdvertisingPayload(void) { - needToSetAdvPayload = false; - return transport->getGap().setAdvertisingData(advPayload, scanResponse); -} - -inline ble_error_t -BLEDevice::setAdvertisingData(const GapAdvertisingData& newPayload) -{ - advPayload = newPayload; - - return setAdvertisingPayload(); -} - -inline const GapAdvertisingData & -BLEDevice::getAdvertisingData(void) const { - return advPayload; -} - -inline ble_error_t -BLEDevice::startAdvertising(void) -{ - ble_error_t rc; - if ((rc = transport->getGattServer().initializeGATTDatabase()) != BLE_ERROR_NONE) { - return rc; - } - if (needToSetAdvPayload) { - if ((rc = setAdvertisingPayload()) != BLE_ERROR_NONE) { - return rc; - } - } - - return transport->getGap().startAdvertising(advParams); -} - -inline ble_error_t -BLEDevice::stopAdvertising(void) -{ - return transport->getGap().stopAdvertising(); -} - -inline ble_error_t -BLEDevice::setScanParams(uint16_t interval, uint16_t window, uint16_t timeout, bool activeScanning) { - ble_error_t rc; - if (((rc = scanningParams.setInterval(interval)) == BLE_ERROR_NONE) && - ((rc = scanningParams.setWindow(window)) == BLE_ERROR_NONE) && - ((rc = scanningParams.setTimeout(timeout)) == BLE_ERROR_NONE)) { - scanningParams.setActiveScanning(activeScanning); - return BLE_ERROR_NONE; - } - - return rc; -} - -inline ble_error_t -BLEDevice::setScanInterval(uint16_t interval) { - return scanningParams.setInterval(interval); -} - -inline ble_error_t -BLEDevice::setScanWindow(uint16_t window) { - return scanningParams.setWindow(window); -} - -inline ble_error_t -BLEDevice::setScanTimeout(uint16_t timeout) { - return scanningParams.setTimeout(timeout); -} - -inline void -BLEDevice::setActiveScan(bool activeScanning) { - return scanningParams.setActiveScanning(activeScanning); -} - -inline ble_error_t -BLEDevice::startScan(void (*callback)(const Gap::AdvertisementCallbackParams_t *params)) { - return transport->getGap().startScan(scanningParams, callback); -} - -template -inline ble_error_t -BLEDevice::startScan(T *object, void (T::*memberCallback)(const Gap::AdvertisementCallbackParams_t *params)) { - return transport->getGap().startScan(scanningParams, object, memberCallback); -} - -inline ble_error_t -BLEDevice::stopScan(void) { - return transport->getGap().stopScan(); -} - -inline ble_error_t -BLEDevice::disconnect(Gap::DisconnectionReason_t reason) -{ - return transport->getGap().disconnect(reason); -} - -inline void -BLEDevice::onTimeout(Gap::EventCallback_t timeoutCallback) -{ - transport->getGap().setOnTimeout(timeoutCallback); -} - -inline void -BLEDevice::onConnection(Gap::ConnectionEventCallback_t connectionCallback) -{ - transport->getGap().setOnConnection(connectionCallback); -} - -inline void -BLEDevice::onDisconnection(Gap::DisconnectionEventCallback_t disconnectionCallback) -{ - transport->getGap().setOnDisconnection(disconnectionCallback); -} - -template -inline void -BLEDevice::addToDisconnectionCallChain(T *tptr, void (T::*mptr)(void)) { - transport->getGap().addToDisconnectionCallChain(tptr, mptr); -} - -inline void -BLEDevice::onDataSent(void (*callback)(unsigned count)) { - transport->getGattServer().setOnDataSent(callback); -} - -template inline void -BLEDevice::onDataSent(T *objPtr, void (T::*memberPtr)(unsigned count)) { - transport->getGattServer().setOnDataSent(objPtr, memberPtr); -} - -inline void -BLEDevice::onDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP)) { - transport->getGattServer().setOnDataWritten(callback); -} - -template inline void -BLEDevice::onDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context)) { - transport->getGattServer().setOnDataWritten(objPtr, memberPtr); -} - -inline ble_error_t -BLEDevice::onDataRead(void (*callback)(const GattCharacteristicReadCBParams *eventDataP)) { - return transport->getGattServer().setOnDataRead(callback); -} - -template inline ble_error_t -BLEDevice::onDataRead(T *objPtr, void (T::*memberPtr)(const GattCharacteristicReadCBParams *context)) { - return transport->getGattServer().setOnDataRead(objPtr, memberPtr); -} - -inline void -BLEDevice::onUpdatesEnabled(GattServer::EventCallback_t callback) -{ - transport->getGattServer().setOnUpdatesEnabled(callback); -} - -inline void -BLEDevice::onUpdatesDisabled(GattServer::EventCallback_t callback) -{ - transport->getGattServer().setOnUpdatesDisabled(callback); -} - -inline void -BLEDevice::onConfirmationReceived(GattServer::EventCallback_t callback) -{ - transport->getGattServer().setOnConfirmationReceived(callback); -} - -inline void -BLEDevice::onRadioNotification(Gap::RadioNotificationEventCallback_t callback) -{ - transport->getGap().setOnRadioNotification(callback); -} - -inline ble_error_t -BLEDevice::addService(GattService &service) -{ - return transport->getGattServer().addService(service); -} - -inline Gap::GapState_t -BLEDevice::getGapState(void) const -{ - return transport->getGap().getState(); -} - -inline ble_error_t BLEDevice::readCharacteristicValue(GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) -{ - return transport->getGattServer().readValue(attributeHandle, buffer, lengthP); -} - -inline ble_error_t BLEDevice::readCharacteristicValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) -{ - return transport->getGattServer().readValue(connectionHandle, attributeHandle, buffer, lengthP); -} - -inline ble_error_t -BLEDevice::updateCharacteristicValue(GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly) -{ - return transport->getGattServer().updateValue(attributeHandle, const_cast(value), size, localOnly); -} - -inline ble_error_t -BLEDevice::updateCharacteristicValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly) -{ - return transport->getGattServer().updateValue(connectionHandle, attributeHandle, const_cast(value), size, localOnly); -} - -inline void -BLEDevice::waitForEvent(void) -{ - transport->waitForEvent(); -} - -inline ble_error_t -BLEDevice::getPreferredConnectionParams(Gap::ConnectionParams_t *params) -{ - return transport->getGap().getPreferredConnectionParams(params); -} - -inline ble_error_t -BLEDevice::setPreferredConnectionParams(const Gap::ConnectionParams_t *params) -{ - return transport->getGap().setPreferredConnectionParams(params); -} - -inline ble_error_t -BLEDevice::updateConnectionParams(Gap::Handle_t handle, const Gap::ConnectionParams_t *params) { - return transport->getGap().updateConnectionParams(handle, params); -} - -inline const char * -BLEDevice::getVersion(void) -{ - return transport->getVersion(); -} - -inline ble_error_t -BLEDevice::setDeviceName(const uint8_t *deviceName) -{ - return transport->getGap().setDeviceName(deviceName); -} - -inline ble_error_t -BLEDevice::getDeviceName(uint8_t *deviceName, unsigned *lengthP) -{ - return transport->getGap().getDeviceName(deviceName, lengthP); -} - -inline ble_error_t -BLEDevice::setAppearance(uint16_t appearance) -{ - return transport->getGap().setAppearance(appearance); -} - -inline ble_error_t -BLEDevice::getAppearance(uint16_t *appearanceP) -{ - return transport->getGap().getAppearance(appearanceP); -} - -inline ble_error_t -BLEDevice::setTxPower(int8_t txPower) -{ - return transport->setTxPower(txPower); -} - -inline void -BLEDevice::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) -{ - transport->getPermittedTxPowerValues(valueArrayPP, countP); -} - -inline ble_error_t -BLEDevice::initializeSecurity(bool enableBonding, - bool requireMITM, - Gap::SecurityIOCapabilities_t iocaps, - const Gap::Passkey_t passkey) -{ - return transport->initializeSecurity(enableBonding, requireMITM, iocaps, passkey); -} - -inline void -BLEDevice::onSecuritySetupInitiated(Gap::SecuritySetupInitiatedCallback_t callback) -{ - transport->getGap().setOnSecuritySetupInitiated(callback); -} - -inline void -BLEDevice::onSecuritySetupCompleted(Gap::SecuritySetupCompletedCallback_t callback) -{ - transport->getGap().setOnSecuritySetupCompleted(callback); -} - -inline void -BLEDevice::onLinkSecured(Gap::LinkSecuredCallback_t callback) -{ - transport->getGap().setOnLinkSecured(callback); -} - -inline void -BLEDevice::onSecurityContextStored(Gap::HandleSpecificEvent_t callback) -{ - transport->getGap().setOnSecurityContextStored(callback); -} - -inline void -BLEDevice::onPasskeyDisplay(Gap::PasskeyDisplayCallback_t callback) -{ - return transport->getGap().setOnPasskeyDisplay(callback); -} - -inline ble_error_t -BLEDevice::getLinkSecurity(Gap::Handle_t connectionHandle, Gap::LinkSecurityStatus_t *securityStatusP) -{ - return transport->getGap().getLinkSecurity(connectionHandle, securityStatusP); -} - -inline ble_error_t -BLEDevice::purgeAllBondingState(void) -{ - return transport->getGap().purgeAllBondingState(); -} - -#endif // ifndef __BLE_DEVICE__ diff --git a/public/Gap.h b/public/Gap.h deleted file mode 100644 index 484d36a..0000000 --- a/public/Gap.h +++ /dev/null @@ -1,398 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __GAP_H__ -#define __GAP_H__ - -#include "GapAdvertisingData.h" -#include "GapAdvertisingParams.h" -#include "GapEvents.h" -#include "CallChain.h" -#include "FunctionPointerWithContext.h" - -using namespace mbed; - -class GapScanningParams; /* forward declaration */ - -class Gap { -public: - enum AddressType_t { - ADDR_TYPE_PUBLIC = 0, - ADDR_TYPE_RANDOM_STATIC, - ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE, - ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE - }; - typedef enum AddressType_t addr_type_t; /* @Note: deprecated. Use AddressType_t instead. */ - - static const unsigned ADDR_LEN = 6; - typedef uint8_t Address_t[ADDR_LEN]; /* 48-bit address, LSB format. */ - typedef Address_t address_t; /* @Note: deprecated. Use Address_t instead. */ - - enum AdvertisementType_t { - ADV_IND = 0x00, /**< Connectable undirected. */ - ADV_DIRECT_IND = 0x01, /**< Connectable directed. */ - ADV_SCAN_IND = 0x02, /**< Scannable undirected. */ - ADV_NONCONN_IND = 0x03, /**< Non connectable undirected. */ - }; - - /** - * Enumeration for disconnection reasons. The values for these reasons are - * derived from Nordic's implementation; but the reasons are meant to be - * independent of the transport. If you are returned a reason which is not - * covered by this enumeration, then please refer to the underlying - * transport library. - */ - enum DisconnectionReason_t { - REMOTE_USER_TERMINATED_CONNECTION = 0x13, - LOCAL_HOST_TERMINATED_CONNECTION = 0x16, - CONN_INTERVAL_UNACCEPTABLE = 0x3B, - }; - - /* Describes the current state of the device (more than one bit can be set) */ - struct GapState_t { - unsigned advertising : 1; /**< peripheral is currently advertising */ - unsigned connected : 1; /**< peripheral is connected to a central */ - }; - - typedef uint16_t Handle_t; - - typedef struct { - uint16_t minConnectionInterval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t maxConnectionInterval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t slaveLatency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t connectionSupervisionTimeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - } ConnectionParams_t; - - enum SecurityMode_t { - SECURITY_MODE_NO_ACCESS, - SECURITY_MODE_ENCRYPTION_OPEN_LINK, /**< require no protection, open link. */ - SECURITY_MODE_ENCRYPTION_NO_MITM, /**< require encryption, but no MITM protection. */ - SECURITY_MODE_ENCRYPTION_WITH_MITM, /**< require encryption and MITM protection. */ - SECURITY_MODE_SIGNED_NO_MITM, /**< require signing or encryption, but no MITM protection. */ - SECURITY_MODE_SIGNED_WITH_MITM, /**< require signing or encryption, and MITM protection. */ - }; - - /** - * @brief Defines possible security status/states. - * - * @details Defines possible security status/states of a link when requested by getLinkSecurity(). - */ - enum LinkSecurityStatus_t { - NOT_ENCRYPTED, /**< The link is not secured. */ - ENCRYPTION_IN_PROGRESS, /**< Link security is being established.*/ - ENCRYPTED /**< The link is secure.*/ - }; - - enum SecurityIOCapabilities_t { - IO_CAPS_DISPLAY_ONLY = 0x00, /**< Display Only. */ - IO_CAPS_DISPLAY_YESNO = 0x01, /**< Display and Yes/No entry. */ - IO_CAPS_KEYBOARD_ONLY = 0x02, /**< Keyboard Only. */ - IO_CAPS_NONE = 0x03, /**< No I/O capabilities. */ - IO_CAPS_KEYBOARD_DISPLAY = 0x04, /**< Keyboard and Display. */ - }; - - enum SecurityCompletionStatus_t { - SEC_STATUS_SUCCESS = 0x00, /**< Procedure completed with success. */ - SEC_STATUS_TIMEOUT = 0x01, /**< Procedure timed out. */ - SEC_STATUS_PDU_INVALID = 0x02, /**< Invalid PDU received. */ - SEC_STATUS_PASSKEY_ENTRY_FAILED = 0x81, /**< Passkey entry failed (user canceled or other). */ - SEC_STATUS_OOB_NOT_AVAILABLE = 0x82, /**< Out of Band Key not available. */ - SEC_STATUS_AUTH_REQ = 0x83, /**< Authentication requirements not met. */ - SEC_STATUS_CONFIRM_VALUE = 0x84, /**< Confirm value failed. */ - SEC_STATUS_PAIRING_NOT_SUPP = 0x85, /**< Pairing not supported. */ - SEC_STATUS_ENC_KEY_SIZE = 0x86, /**< Encryption key size. */ - SEC_STATUS_SMP_CMD_UNSUPPORTED = 0x87, /**< Unsupported SMP command. */ - SEC_STATUS_UNSPECIFIED = 0x88, /**< Unspecified reason. */ - SEC_STATUS_REPEATED_ATTEMPTS = 0x89, /**< Too little time elapsed since last attempt. */ - SEC_STATUS_INVALID_PARAMS = 0x8A, /**< Invalid parameters. */ - }; - - /** - * Declaration of type containing a passkey to be used during pairing. This - * is passed into initializeSecurity() to specify a pre-programmed passkey - * for authentication instead of generating a random one. - */ - static const unsigned PASSKEY_LEN = 6; - typedef uint8_t Passkey_t[PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ - - static const uint16_t UNIT_1_25_MS = 1250; /**< Number of microseconds in 1.25 milliseconds. */ - static const uint16_t UNIT_0_625_MS = 625; /**< Number of microseconds in 0.625 milliseconds. */ - static uint16_t MSEC_TO_GAP_DURATION_UNITS(uint32_t durationInMillis) { - return (durationInMillis * 1000) / UNIT_1_25_MS; - } - static uint16_t MSEC_TO_ADVERTISEMENT_DURATION_UNITS(uint32_t durationInMillis) { - return (durationInMillis * 1000) / UNIT_0_625_MS; - } - static uint16_t ADVERTISEMENT_DURATION_UNITS_TO_MS(uint16_t gapUnits) { - return (gapUnits * UNIT_0_625_MS) / 1000; - } - - typedef void (*EventCallback_t)(void); - typedef void (*ConnectionEventCallback_t)(Handle_t, - AddressType_t peerAddrType, const Address_t peerAddr, - AddressType_t ownAddrType, const Address_t ownAddr, - const ConnectionParams_t *); - typedef void (*HandleSpecificEvent_t)(Handle_t handle); - typedef void (*DisconnectionEventCallback_t)(Handle_t, DisconnectionReason_t); - typedef void (*RadioNotificationEventCallback_t) (bool radio_active); /* gets passed true for ACTIVE; false for INACTIVE. */ - typedef void (*SecuritySetupInitiatedCallback_t)(Handle_t, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps); - typedef void (*SecuritySetupCompletedCallback_t)(Handle_t, SecurityCompletionStatus_t status); - typedef void (*LinkSecuredCallback_t)(Handle_t handle, SecurityMode_t securityMode); - typedef void (*PasskeyDisplayCallback_t)(Handle_t handle, const Passkey_t passkey); - - struct AdvertisementCallbackParams_t { - Address_t peerAddr; - int8_t rssi; - bool isScanResponse; - AdvertisementType_t type; - uint8_t advertisingDataLen; - const uint8_t *advertisingData; - }; - typedef FunctionPointerWithContext AdvertisementReportCallback_t; - - friend class BLEDevice; - -private: - /* These functions must be defined in the sub-class */ - virtual ble_error_t setAddress(AddressType_t type, const Address_t address) = 0; - virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address) = 0; - virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &) = 0; - virtual ble_error_t startAdvertising(const GapAdvertisingParams &) = 0; - virtual ble_error_t stopAdvertising(void) = 0; - virtual ble_error_t stopScan() = 0; - virtual uint16_t getMinAdvertisingInterval(void) const = 0; - virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const = 0; - virtual uint16_t getMaxAdvertisingInterval(void) const = 0; - virtual ble_error_t disconnect(DisconnectionReason_t reason) = 0; - virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params) = 0; - virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params) = 0; - virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params) = 0; - - virtual ble_error_t purgeAllBondingState(void) = 0; - virtual ble_error_t getLinkSecurity(Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) = 0; - - virtual ble_error_t setDeviceName(const uint8_t *deviceName) = 0; - virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP) = 0; - virtual ble_error_t setAppearance(uint16_t appearance) = 0; - virtual ble_error_t getAppearance(uint16_t *appearanceP) = 0; - - ble_error_t startScan(const GapScanningParams &scanningParams, void (*callback)(const AdvertisementCallbackParams_t *params)) { - ble_error_t err = BLE_ERROR_NONE; - if (callback) { - if ((err = startRadioScan(scanningParams)) == BLE_ERROR_NONE) { - onAdvertisementReport.attach(callback); - } - } - - return err; - } - - template - ble_error_t startScan(const GapScanningParams &scanningParams, T *object, void (T::*callbackMember)(const AdvertisementCallbackParams_t *params)) { - ble_error_t err = BLE_ERROR_NONE; - if (object && callbackMember) { - if ((err = startRadioScan(scanningParams)) == BLE_ERROR_NONE) { - onAdvertisementReport.attach(object, callbackMember); - } - } - - return err; - } - -protected: - virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) = 0; - - /* Event callback handlers */ - void setOnTimeout(EventCallback_t callback) {onTimeout = callback;} - void setOnConnection(ConnectionEventCallback_t callback) {onConnection = callback;} - - /** - * Set the application callback for disconnection events. - * @param callback - * Pointer to the unique callback. - */ - void setOnDisconnection(DisconnectionEventCallback_t callback) {onDisconnection = callback;} - - /** - * Set the application callback for radio-notification events. - * @param callback - * Handler to be executed in response to a radio notification event. - */ - virtual void setOnRadioNotification(RadioNotificationEventCallback_t callback) {onRadioNotification = callback;} - - /** - * To indicate that security procedure for link has started. - */ - virtual void setOnSecuritySetupInitiated(SecuritySetupInitiatedCallback_t callback) {onSecuritySetupInitiated = callback;} - - /** - * To indicate that security procedure for link has completed. - */ - virtual void setOnSecuritySetupCompleted(SecuritySetupCompletedCallback_t callback) {onSecuritySetupCompleted = callback;} - - /** - * To indicate that link with the peer is secured. For bonded devices, - * subsequent re-connections with bonded peer will result only in this callback - * when the link is secured and setup procedures will not occur unless the - * bonding information is either lost or deleted on either or both sides. - */ - virtual void setOnLinkSecured(LinkSecuredCallback_t callback) {onLinkSecured = callback;} - - /** - * To indicate that device context is stored persistently. - */ - virtual void setOnSecurityContextStored(HandleSpecificEvent_t callback) {onSecurityContextStored = callback;} - - /** - * To set the callback for when the passkey needs to be displayed on a peripheral with DISPLAY capability. - */ - virtual void setOnPasskeyDisplay(PasskeyDisplayCallback_t callback) {onPasskeyDisplay = callback;} - - /** - * Append to a chain of callbacks to be invoked upon disconnection; these - * callbacks receive no context and are therefore different from the - * onDisconnection callback. - * @param callback - * function pointer to be invoked upon disconnection; receives no context. - * - * @note the disconnection CallChain should have been merged with - * onDisconnctionCallback; but this was not possible because - * FunctionPointer (which is a building block for CallChain) doesn't - * accept variadic templates. - */ - template - void addToDisconnectionCallChain(T *tptr, void (T::*mptr)(void)) {disconnectionCallChain.add(tptr, mptr);} - -private: - GapState_t getState(void) const { - return state; - } - -protected: - Gap() : - state(), - onTimeout(NULL), - onConnection(NULL), - onDisconnection(NULL), - onRadioNotification(), - onSecuritySetupInitiated(), - onSecuritySetupCompleted(), - onLinkSecured(), - onSecurityContextStored(), - onPasskeyDisplay(), - onAdvertisementReport(), - disconnectionCallChain() { - /* empty */ - } - -public: - void processConnectionEvent(Handle_t handle, AddressType_t peerAddrType, const Address_t peerAddr, AddressType_t ownAddrType, const Address_t ownAddr, const ConnectionParams_t *params) { - state.connected = 1; - if (onConnection) { - onConnection(handle, peerAddrType, peerAddr, ownAddrType, ownAddr, params); - } - } - - void processDisconnectionEvent(Handle_t handle, DisconnectionReason_t reason) { - state.connected = 0; - if (onDisconnection) { - onDisconnection(handle, reason); - } - disconnectionCallChain.call(); - } - - void processSecuritySetupInitiatedEvent(Handle_t handle, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps) { - if (onSecuritySetupInitiated) { - onSecuritySetupInitiated(handle, allowBonding, requireMITM, iocaps); - } - } - - void processSecuritySetupCompletedEvent(Handle_t handle, SecurityCompletionStatus_t status) { - if (onSecuritySetupCompleted) { - onSecuritySetupCompleted(handle, status); - } - } - - void processLinkSecuredEvent(Handle_t handle, SecurityMode_t securityMode) { - if (onLinkSecured) { - onLinkSecured(handle, securityMode); - } - } - - void processSecurityContextStoredEvent(Handle_t handle) { - if (onSecurityContextStored) { - onSecurityContextStored(handle); - } - } - - void processPasskeyDisplayEvent(Handle_t handle, const Passkey_t passkey) { - if (onPasskeyDisplay) { - onPasskeyDisplay(handle, passkey); - } - } - - void processAdvertisementReport(const Address_t peerAddr, - int8_t rssi, - bool isScanResponse, - AdvertisementType_t type, - uint8_t advertisingDataLen, - const uint8_t *advertisingData) { - AdvertisementCallbackParams_t params; - memcpy(params.peerAddr, peerAddr, ADDR_LEN); - params.rssi = rssi; - params.isScanResponse = isScanResponse; - params.type = type; - params.advertisingDataLen = advertisingDataLen; - params.advertisingData = advertisingData; - onAdvertisementReport.call(¶ms); - } - - void processEvent(GapEvents::gapEvent_e type) { - switch (type) { - case GapEvents::GAP_EVENT_TIMEOUT: - state.advertising = 0; - if (onTimeout) { - onTimeout(); - } - break; - default: - break; - } - } - -protected: - GapState_t state; - -protected: - EventCallback_t onTimeout; - ConnectionEventCallback_t onConnection; - DisconnectionEventCallback_t onDisconnection; - RadioNotificationEventCallback_t onRadioNotification; - SecuritySetupInitiatedCallback_t onSecuritySetupInitiated; - SecuritySetupCompletedCallback_t onSecuritySetupCompleted; - LinkSecuredCallback_t onLinkSecured; - HandleSpecificEvent_t onSecurityContextStored; - PasskeyDisplayCallback_t onPasskeyDisplay; - AdvertisementReportCallback_t onAdvertisementReport; - CallChain disconnectionCallChain; - -private: - /* disallow copy and assignment */ - Gap(const Gap &); - Gap& operator=(const Gap &); -}; - -#endif // ifndef __GAP_H__ diff --git a/public/GattServer.h b/public/GattServer.h deleted file mode 100644 index fd39235..0000000 --- a/public/GattServer.h +++ /dev/null @@ -1,159 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __GATT_SERVER_H__ -#define __GATT_SERVER_H__ - -#include "Gap.h" -#include "GattService.h" -#include "GattAttribute.h" -#include "GattServerEvents.h" -#include "GattCharacteristicCallbackParams.h" -#include "CallChainOfFunctionPointersWithContext.h" - -class GattServer { -public: - /* Event callback handlers. */ - typedef void (*EventCallback_t)(GattAttribute::Handle_t attributeHandle); - typedef void (*ServerEventCallback_t)(void); /**< independent of any particular attribute */ - -protected: - GattServer() : - serviceCount(0), - characteristicCount(0), - onDataSent(), - onDataWritten(), - onDataRead(), - onUpdatesEnabled(NULL), - onUpdatesDisabled(NULL), - onConfirmationReceived(NULL) { - /* empty */ - } - - friend class BLEDevice; -private: - /* These functions must be defined in the sub-class */ - virtual ble_error_t addService(GattService &) = 0; - virtual ble_error_t readValue(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) = 0; - virtual ble_error_t readValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) = 0; - virtual ble_error_t updateValue(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false) = 0; - virtual ble_error_t updateValue(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false) = 0; - virtual ble_error_t initializeGATTDatabase(void) = 0; - - // ToDo: For updateValue, check the CCCD to see if the value we are - // updating has the notify or indicate bits sent, and if BOTH are set - // be sure to call sd_ble_gatts_hvx() twice with notify then indicate! - // Strange use case, but valid and must be covered! - - void setOnDataSent(void (*callback)(unsigned count)) {onDataSent.add(callback);} - template - void setOnDataSent(T *objPtr, void (T::*memberPtr)(unsigned count)) { - onDataSent.add(objPtr, memberPtr); - } - void setOnDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP)) {onDataWritten.add(callback);} - template - void setOnDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context)) { - onDataWritten.add(objPtr, memberPtr); - } - - /** - * A virtual function to allow underlying stacks to indicate if they support - * onDataRead(). It should be overridden to return true as applicable. - */ - virtual bool isOnDataReadAvailable() const { - return false; - } - ble_error_t setOnDataRead(void (*callback)(const GattCharacteristicReadCBParams *eventDataP)) { - if (!isOnDataReadAvailable()) { - return BLE_ERROR_NOT_IMPLEMENTED; - } - - onDataRead.add(callback); - return BLE_ERROR_NONE; - } - template - ble_error_t setOnDataRead(T *objPtr, void (T::*memberPtr)(const GattCharacteristicReadCBParams *context)) { - if (!isOnDataReadAvailable()) { - return BLE_ERROR_NOT_IMPLEMENTED; - } - - onDataRead.add(objPtr, memberPtr); - return BLE_ERROR_NONE; - } - void setOnUpdatesEnabled(EventCallback_t callback) {onUpdatesEnabled = callback;} - void setOnUpdatesDisabled(EventCallback_t callback) {onUpdatesDisabled = callback;} - void setOnConfirmationReceived(EventCallback_t callback) {onConfirmationReceived = callback;} - -protected: - void handleDataWrittenEvent(const GattCharacteristicWriteCBParams *params) { - if (onDataWritten.hasCallbacksAttached()) { - onDataWritten.call(params); - } - } - - void handleDataReadEvent(const GattCharacteristicReadCBParams *params) { - if (onDataRead.hasCallbacksAttached()) { - onDataRead.call(params); - } - } - - void handleEvent(GattServerEvents::gattEvent_e type, GattAttribute::Handle_t charHandle) { - switch (type) { - case GattServerEvents::GATT_EVENT_UPDATES_ENABLED: - if (onUpdatesEnabled) { - onUpdatesEnabled(charHandle); - } - break; - case GattServerEvents::GATT_EVENT_UPDATES_DISABLED: - if (onUpdatesDisabled) { - onUpdatesDisabled(charHandle); - } - break; - case GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED: - if (onConfirmationReceived) { - onConfirmationReceived(charHandle); - } - break; - default: - break; - } - } - - void handleDataSentEvent(unsigned count) { - if (onDataSent.hasCallbacksAttached()) { - onDataSent.call(count); - } - } - -protected: - uint8_t serviceCount; - uint8_t characteristicCount; - -private: - CallChainOfFunctionPointersWithContext onDataSent; - CallChainOfFunctionPointersWithContext onDataWritten; - CallChainOfFunctionPointersWithContext onDataRead; - EventCallback_t onUpdatesEnabled; - EventCallback_t onUpdatesDisabled; - EventCallback_t onConfirmationReceived; - -private: - /* disallow copy and assignment */ - GattServer(const GattServer &); - GattServer& operator=(const GattServer &); -}; - -#endif // ifndef __GATT_SERVER_H__ diff --git a/public/readme.txt b/public/readme.txt deleted file mode 100644 index 1b278e8..0000000 --- a/public/readme.txt +++ /dev/null @@ -1 +0,0 @@ -The public API exposed through header files. \ No newline at end of file diff --git a/common/BLEDevice.cpp b/source/BLE.cpp similarity index 96% rename from common/BLEDevice.cpp rename to source/BLE.cpp index be02c7f..181e001 100644 --- a/common/BLEDevice.cpp +++ b/source/BLE.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ -#include "BLEDevice.h" +#include "ble/BLE.h" #if defined(TARGET_OTA_ENABLED) #include "DFUService.h" #endif ble_error_t -BLEDevice::init() +BLE::init() { ble_error_t err = transport->init(); if (err != BLE_ERROR_NONE) { diff --git a/source/DiscoveredCharacteristic.cpp b/source/DiscoveredCharacteristic.cpp new file mode 100644 index 0000000..3991421 --- /dev/null +++ b/source/DiscoveredCharacteristic.cpp @@ -0,0 +1,69 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ble/DiscoveredCharacteristic.h" +#include "ble/GattClient.h" + +GattClient::ReadCallback_t DiscoveredCharacteristic::onDataReadCallback; +GattClient::WriteCallback_t DiscoveredCharacteristic::onDataWriteCallback; + +ble_error_t +DiscoveredCharacteristic::read(uint16_t offset) const +{ + if (!props.read()) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; + } + + if (!gattc) { + return BLE_ERROR_INVALID_STATE; + } + + return gattc->read(connHandle, valueHandle, offset); +} + +ble_error_t +DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value) const +{ + if (!props.write()) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; + } + + if (!gattc) { + return BLE_ERROR_INVALID_STATE; + } + + return gattc->write(GattClient::GATT_OP_WRITE_REQ, connHandle, valueHandle, length, value); +} + +ble_error_t +DiscoveredCharacteristic::writeWoResponse(uint16_t length, const uint8_t *value) const +{ + if (!props.writeWoResp()) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; + } + + if (!gattc) { + return BLE_ERROR_INVALID_STATE; + } + + return gattc->write(GattClient::GATT_OP_WRITE_CMD, connHandle, valueHandle, length, value); +} + +ble_error_t +DiscoveredCharacteristic::discoverDescriptors(DescriptorCallback_t callback, const UUID &matchingUUID) const +{ + return BLE_ERROR_NOT_IMPLEMENTED; /* TODO: this needs to be filled in. */ +} diff --git a/source/GapScanningParams.cpp b/source/GapScanningParams.cpp new file mode 100644 index 0000000..e409745 --- /dev/null +++ b/source/GapScanningParams.cpp @@ -0,0 +1,75 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ble/Gap.h" +#include "ble/GapScanningParams.h" + +GapScanningParams::GapScanningParams(uint16_t interval, uint16_t window, uint16_t timeout, bool activeScanning) : + _interval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(interval)), + _window(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(window)), + _timeout(timeout), + _activeScanning(activeScanning) { + /* stay within limits */ + if (_interval < SCAN_INTERVAL_MIN) { + _interval = SCAN_INTERVAL_MIN; + } + if (_interval > SCAN_INTERVAL_MAX) { + _interval = SCAN_INTERVAL_MAX; + } + if (_window < SCAN_WINDOW_MIN) { + _window = SCAN_WINDOW_MIN; + } + if (_window > SCAN_WINDOW_MAX) { + _window = SCAN_WINDOW_MAX; + } +} + +ble_error_t +GapScanningParams::setInterval(uint16_t newIntervalInMS) +{ + uint16_t newInterval = Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(newIntervalInMS); + if ((newInterval >= SCAN_INTERVAL_MIN) && (newInterval < SCAN_INTERVAL_MAX)) { + _interval = newInterval; + return BLE_ERROR_NONE; + } + + return BLE_ERROR_PARAM_OUT_OF_RANGE; +} + +ble_error_t +GapScanningParams::setWindow(uint16_t newWindowInMS) +{ + uint16_t newWindow = Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(newWindowInMS); + if ((newWindow >= SCAN_WINDOW_MIN) && (newWindow < SCAN_WINDOW_MAX)) { + _window = newWindow; + return BLE_ERROR_NONE; + } + + return BLE_ERROR_PARAM_OUT_OF_RANGE; +} + +ble_error_t +GapScanningParams::setTimeout(uint16_t newTimeout) +{ + _timeout = newTimeout; + return BLE_ERROR_NONE; +} + +void +GapScanningParams::setActiveScanning(bool activeScanning) +{ + _activeScanning = activeScanning; +} diff --git a/services/DFUService.cpp b/source/services/DFUService.cpp similarity index 98% rename from services/DFUService.cpp rename to source/services/DFUService.cpp index ccecad6..a72e559 100644 --- a/services/DFUService.cpp +++ b/source/services/DFUService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "DFUService.h" +#include "ble/services/DFUService.h" const uint8_t DFUServiceBaseUUID[] = { 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0xEF, 0xDE, diff --git a/services/UARTService.cpp b/source/services/UARTService.cpp similarity index 98% rename from services/UARTService.cpp rename to source/services/UARTService.cpp index 592aac1..6d1edea 100644 --- a/services/UARTService.cpp +++ b/source/services/UARTService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "UARTService.h" +#include "ble/services/UARTService.h" const uint8_t UARTServiceBaseUUID[UUID::LENGTH_OF_LONG_UUID] = { 0x6E, 0x40, 0x00, 0x00, 0xB5, 0xA3, 0xF3, 0x93, diff --git a/services/URIBeaconConfigService.cpp b/source/services/URIBeaconConfigService.cpp similarity index 97% rename from services/URIBeaconConfigService.cpp rename to source/services/URIBeaconConfigService.cpp index 26cf535..bcdcbb0 100644 --- a/services/URIBeaconConfigService.cpp +++ b/source/services/URIBeaconConfigService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "URIBeaconConfigService.h" +#include "ble/services/URIBeaconConfigService.h" #define UUID_URI_BEACON(FIRST, SECOND) { \ 0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \