Lancaster University's fork of the mbed BLE API. Lives on github, https://github.com/lancaster-university/BLE_API

Dependents:   microbit-dal microbit-dal microbit-ble-open microbit-dal ... more

Fork of BLE_API by Bluetooth Low Energy

Files at this revision

API Documentation at this revision

Comitter:
LancasterUniversity
Date:
Wed Apr 06 18:40:33 2016 +0100
Parent:
1136:82ebef119484
Child:
1138:6aabbb5f81e6
Commit message:
Synchronized with git rev a5f6d4b8
Author: Joe Finney
microbit: Disabled default instantiation of DFUService.

micro:bit operates its own custom service for this purpose.

Changed in this revision

ble/BLE.h Show annotated file Show diff for this revision Revisions of this file
ble/BLEProtocol.h Show annotated file Show diff for this revision Revisions of this file
ble/CharacteristicDescriptorDiscovery.h Show annotated file Show diff for this revision Revisions of this file
ble/DiscoveredCharacteristic.h Show annotated file Show diff for this revision Revisions of this file
ble/DiscoveredCharacteristicDescriptor.h Show annotated file Show diff for this revision Revisions of this file
ble/Gap.h Show annotated file Show diff for this revision Revisions of this file
ble/GapAdvertisingData.h Show annotated file Show diff for this revision Revisions of this file
ble/GattClient.h Show annotated file Show diff for this revision Revisions of this file
ble/GattServer.h Show annotated file Show diff for this revision Revisions of this file
ble/SecurityManager.h Show annotated file Show diff for this revision Revisions of this file
ble/ServiceDiscovery.h Show annotated file Show diff for this revision Revisions of this file
ble/blecommon.h Show annotated file Show diff for this revision Revisions of this file
ble/deprecate.h Show annotated file Show diff for this revision Revisions of this file
module.json Show annotated file Show diff for this revision Revisions of this file
source/BLE.cpp Show annotated file Show diff for this revision Revisions of this file
source/DiscoveredCharacteristic.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/ble/BLE.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/BLE.h	Wed Apr 06 18:40:33 2016 +0100
@@ -196,7 +196,7 @@
      * directly, as it returns references to singletons.
      *
      * @param[in] id
-     *              Instance-ID. This should be less than NUM_INSTANCES 
+     *              Instance-ID. This should be less than NUM_INSTANCES
      *              for the returned BLE singleton to be useful.
      *
      * @return a reference to a single object.
@@ -239,7 +239,7 @@
      * ble.setAddress(...) should be replaced with
      * ble.gap().setAddress(...).
      */
-    ble_error_t setAddress(Gap::AddressType_t type, const Gap::Address_t address) {
+    ble_error_t setAddress(BLEProtocol::AddressType_t type, const BLEProtocol::AddressBytes_t address) {
         return gap().setAddress(type, address);
     }
 
@@ -252,7 +252,7 @@
      * ble.getAddress(...) should be replaced with
      * ble.gap().getAddress(...).
      */
-    ble_error_t getAddress(Gap::AddressType_t *typeP, Gap::Address_t address) {
+    ble_error_t getAddress(BLEProtocol::AddressType_t *typeP, BLEProtocol::AddressBytes_t address) {
         return gap().getAddress(typeP, address);
     }
 
@@ -752,10 +752,10 @@
      * 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) {
+    ble_error_t connect(const BLEProtocol::AddressBytes_t  peerAddr,
+                        BLEProtocol::AddressType_t         peerAddrType = BLEProtocol::AddressType::RANDOM_STATIC,
+                        const Gap::ConnectionParams_t     *connectionParams = NULL,
+                        const GapScanningParams           *scanParams = NULL) {
         return gap().connect(peerAddr, peerAddrType, connectionParams, scanParams);
     }
 
@@ -773,7 +773,7 @@
     }
 
     /**
-     * This call initiates the disconnection procedure, and its completion 
+     * This call initiates the disconnection procedure, and its completion
      * is communicated to the application with an invocation of the
      * onDisconnection callback.
      *
@@ -1407,7 +1407,7 @@
     /**
      * Set up 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 the peers need to exchange 
+     * configured to prevent Man-In-The-Middle attacks, and the peers need to exchange
      * a passkey (or PIN) to authenticate the connection
      * attempt.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ble/BLEProtocol.h	Wed Apr 06 18:40:33 2016 +0100
@@ -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.
+ */
+
+#ifndef __BLE_PROTOCOL_H__
+#define __BLE_PROTOCOL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+
+/**
+ * A common namespace for types and constants used everywhere in BLE API.
+ */
+namespace BLEProtocol {
+    /**<
+     * A simple container for the enumeration of address-types for Protocol addresses.
+     *
+     * Adding a struct to encapsulate the contained enumeration prevents
+     * polluting the BLEProtocol namespace with the enumerated values. It also
+     * allows type-aliases for the enumeration while retaining the enumerated
+     * values. i.e. doing:
+     *       typedef AddressType AliasedType;
+     *
+     * would allow the use of AliasedType::PUBLIC in code.
+     */
+    struct AddressType {
+        /**< Address-types for Protocol addresses. */
+        enum Type {
+            PUBLIC = 0,
+            RANDOM_STATIC,
+            RANDOM_PRIVATE_RESOLVABLE,
+            RANDOM_PRIVATE_NON_RESOLVABLE
+        };
+    };
+    typedef AddressType::Type AddressType_t;  /**< Alias for AddressType::Type */
+
+    static const size_t ADDR_LEN = 6;         /**< Length (in octets) of the BLE MAC address. */
+    typedef uint8_t AddressBytes_t[ADDR_LEN]; /**< 48-bit address, in LSB format. */
+
+    /**
+     * BLE address. It contains an address-type (@ref AddressType_t) and bytes (@ref AddressBytes_t).
+     */
+    struct Address_t {
+        AddressType_t  type;    /**< @ref AddressType_t */
+        AddressBytes_t address; /**< @ref AddressBytes_t */
+
+        Address_t(AddressType_t typeIn, const AddressBytes_t& addressIn) : type(typeIn) {
+            std::copy(addressIn, addressIn + ADDR_LEN, address);
+        }
+
+        Address_t() : type(), address() {
+        }
+    };
+};
+
+#endif /* __BLE_PROTOCOL_H__ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ble/CharacteristicDescriptorDiscovery.h	Wed Apr 06 18:40:33 2016 +0100
@@ -0,0 +1,99 @@
+/* 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 __CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
+#define __CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
+
+#include "FunctionPointerWithContext.h"
+
+class DiscoveredCharacteristic;                         // forward declaration
+class DiscoveredCharacteristicDescriptor;               // forward declaration
+
+/**
+ * @brief Contain all definitions of callbacks and callbacks parameters types
+ * related to characteristic descriptor discovery.
+ *
+ * @details This class act like a namespace for characteristic descriptor discovery
+ * types. It act like ServiceDiscovery by providing callbacks and callbacks
+ * parameters types related to the characteristic descriptor discovery process but
+ * contrary to ServiceDiscovery class, it does not force the porter to use a
+ * specific interface for the characteristic descriptor discovery process.
+ */
+class CharacteristicDescriptorDiscovery {
+public:
+    /**
+     * @brief Parameter type of CharacteristicDescriptorDiscovery::DiscoveryCallback_t.
+     * @detail Every time a characteristic descriptor has been discovered, the callback
+     * registered for the discovery operation through GattClient::discoverCharacteristicDescriptors
+     * or DiscoveredCharacteristic::discoverDescriptors will be called with this parameter.
+     *
+     */
+    struct DiscoveryCallbackParams_t {
+        /**
+         * The characteristic owning the DiscoveredCharacteristicDescriptor
+         */
+        const DiscoveredCharacteristic& characteristic;
+
+        /**
+         * The characteristic descriptor discovered
+         */
+        const DiscoveredCharacteristicDescriptor& descriptor;
+    };
+
+    /**
+     * @brief Parameter type of CharacteristicDescriptorDiscovery::TerminationCallback_t.
+     * @details Once a characteristic descriptor discovery process terminate, the termination
+     * callback registered for the discovery operation through
+     * GattClient::discoverCharacteristicDescriptors or DiscoveredCharacteristic::discoverDescriptors
+     * will be called with this parameter.
+     */
+    struct TerminationCallbackParams_t {
+        /**
+         * The characteristic for which the descriptors has been discovered
+         */
+        const DiscoveredCharacteristic& characteristic;
+
+        /**
+         * status of the discovery operation
+         */
+        ble_error_t status;
+    };
+
+    /**
+     * @brief Callback type for when a matching characteristic descriptor is found during
+     * characteristic descriptor discovery.
+     *
+     * @param param A pointer to a DiscoveryCallbackParams_t 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 FunctionPointerWithContext<const DiscoveryCallbackParams_t*> DiscoveryCallback_t;
+
+    /**
+     * @brief Callback type for when characteristic descriptor discovery terminates.
+     *
+     * @param param A pointer to a TerminationCallbackParams_t 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 FunctionPointerWithContext<const TerminationCallbackParams_t*> TerminationCallback_t;
+};
+
+#endif // ifndef __CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
\ No newline at end of file
--- a/ble/DiscoveredCharacteristic.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/DiscoveredCharacteristic.h	Wed Apr 06 18:40:33 2016 +0100
@@ -21,10 +21,24 @@
 #include "Gap.h"
 #include "GattAttribute.h"
 #include "GattClient.h"
+#include "CharacteristicDescriptorDiscovery.h"
+#include "ble/DiscoveredCharacteristicDescriptor.h"
 
 /**
- * Structure for holding information about the service and the characteristics
- * found during the discovery process.
+ * @brief Representation of a characteristic discovered during a GattClient
+ * discovery procedure (see GattClient::launchServiceDiscovery ).
+ *
+ * @detail Provide detailed informations about a discovered characteristic like:
+ *     - Its UUID (see #getUUID).
+ *     - The most important handles of the characteristic definition
+ *       (see #getDeclHandle, #getValueHandle, #getLastHandle )
+ *     - Its properties (see #getProperties).
+ * This class also provide functions to operate on the characteristic:
+ *     - Read the characteristic value (see #read)
+ *     - Writing a characteristic value (see #write or #writeWoResponse)
+ *     - Discover descriptors inside the characteristic definition. These descriptors
+ *       extends the characteristic. More information about descriptor usage is
+ *       available in DiscoveredCharacteristicDescriptor class.
  */
 class DiscoveredCharacteristic {
 public:
@@ -33,7 +47,7 @@
         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 _notify          :1; /**< Notifications 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. */
 
@@ -46,36 +60,50 @@
         bool indicate(void)        const {return _indicate;       }
         bool authSignedWrite(void) const {return _authSignedWrite;}
 
+        /**
+         * @brief "Equal to" operator for DiscoveredCharacteristic::Properties_t
+         *
+         * @param lhs[in] The left hand side of the equality expression
+         * @param rhs[in] The right hand side of the equality expression
+         *
+         * @return true if operands are equals, false otherwise.
+         */
+        friend bool operator==(Properties_t lhs, Properties_t rhs) {
+            return lhs._broadcast == rhs._broadcast &&
+                   lhs._read == rhs._read &&
+                   lhs._writeWoResp == rhs._writeWoResp &&
+                   lhs._write == rhs._write &&
+                   lhs._notify == rhs._notify &&
+                   lhs._indicate == rhs._indicate &&
+                   lhs._authSignedWrite == rhs._authSignedWrite;
+        }
+
+        /**
+         * @brief "Not equal to" operator for DiscoveredCharacteristic::Properties_t
+         *
+         * @param lhs The right hand side of the expression
+         * @param rhs The left hand side of the expression
+         *
+         * @return true if operands are not equals, false otherwise.
+         */
+        friend bool operator!=(Properties_t lhs, Properties_t rhs) {
+            return !(lhs == rhs);
+        }
+
     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.
      *
+     * @param offset[in] The position - in the characteristic value bytes stream - where
+     * the read operation begin.
+     *
      * @return BLE_ERROR_NONE if a read has been initiated, or
      *         BLE_ERROR_INVALID_STATE if some internal state about the connection is invalid, or
      *         BLE_STACK_BUSY if some client procedure is already in progress, or
@@ -83,14 +111,22 @@
      */
     ble_error_t read(uint16_t offset = 0) const;
 
+    /**
+     * @brief Same as #read(uint16_t) const but allow the user to register a callback
+     * which will be fired once the read is done.
+     *
+     * @param offset[in] The position - in the characteristic value bytes stream - where
+     * the read operation begin.
+     * @param onRead[in] Continuation of the read operation
+     */
     ble_error_t read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const;
 
     /**
      * Perform a write without response procedure.
      *
-     * @param  length
+     * @param[in]  length
      *           The amount of data being written.
-     * @param  value
+     * @param[in]  value
      *           The bytes being written.
      *
      * @note   It is important to note that a write without response will generate
@@ -110,20 +146,20 @@
     /**
      * 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.
+     * @param[in] onDescriptorDiscovered This callback will be called every time a descriptor is discovered
+     * @param[in] onTermination This callback will be called when the discovery process is over.
      *
-     * @return  BLE_ERROR_NONE if descriptor discovery is launched successfully; else an appropriate error.
+     * @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;
+    ble_error_t discoverDescriptors(const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& onDescriptorDiscovered,
+                                    const CharacteristicDescriptorDiscovery::TerminationCallback_t& onTermination) const;
 
     /**
      * Perform a write procedure.
      *
-     * @param  length
+     * @param[in]  length
      *           The amount of data being written.
-     * @param  value
+     * @param[in]  value
      *           The bytes being written.
      *
      * @note   It is important to note that a write will generate
@@ -138,36 +174,142 @@
     ble_error_t write(uint16_t length, const uint8_t *value) const;
 
     /**
-     * Same as above but register the callback wich will be called once the data has been written
+     * Same as #write(uint16_t, const uint8_t *) const but register a callback
+     * which will be called once the data has been written.
+     *
+     * @param[in] length The amount of bytes to write.
+     * @param[in] value The bytes to write.
+     * @param[in] onRead Continuation callback for the write operation
      */
-    ble_error_t write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onRead) const;
+    ble_error_t write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onWrite) const;
 
     void setupLongUUID(UUID::LongUUIDBytes_t longUUID, UUID::ByteOrder_t order = UUID::MSB) {
         uuid.setupLong(longUUID, order);
     }
 
 public:
+    /**
+     * @brief Get the UUID of the discovered characteristic
+     * @return the UUID of this characteristic
+     */
     const UUID& getUUID(void) const {
         return uuid;
     }
 
+    /**
+     * @brief Get the properties of this characteristic
+     * @return the set of properties of this characteristic
+     */
     const Properties_t& getProperties(void) const {
         return props;
     }
 
-    const GattAttribute::Handle_t& getDeclHandle(void) const {
+    /**
+     * @brief Get the declaration handle of this characteristic.
+     * @detail The declaration handle is the first handle of a characteristic
+     * definition. The value accessible at this handle contains the following
+     * informations:
+     *    - The characteristics properties (see Properties_t). This value can
+     *      be accessed by using #getProperties .
+     *    - The characteristic value attribute handle. This field can be accessed
+     *      by using #getValueHandle .
+     *    - The characteristic UUID, this value can be accessed by using the
+     *      function #getUUID .
+     * @return the declaration handle of this characteristic.
+     */
+    GattAttribute::Handle_t getDeclHandle(void) const {
         return declHandle;
     }
-    const GattAttribute::Handle_t& getValueHandle(void) const {
+
+    /**
+     * @brief Return the handle used to access the value of this characteristic.
+     * @details This handle is the one provided in the characteristic declaration
+     * value. Usually, it is equal to #getDeclHandle() + 1. But it is not always
+     * the case. Anyway, users are allowed to use #getDeclHandle() + 1 to access
+     * the value of a characteristic.
+     * @return The handle to access the value of this characteristic.
+     */
+    GattAttribute::Handle_t getValueHandle(void) const {
         return valueHandle;
     }
 
+    /**
+     * @brief Return the last handle of the characteristic definition.
+     * @details A Characteristic definition can contain a lot of handles:
+     *     - one for the declaration (see #getDeclHandle)
+     *     - one for the value (see #getValueHandle)
+     *     - zero of more for the characteristic descriptors.
+     * This handle is the last handle of the characteristic definition.
+     * @return The last handle of this characteristic definition.
+     */
+    GattAttribute::Handle_t getLastHandle(void) const {
+        return lastHandle;
+    }
+
+    /**
+     * @brief Return the GattClient which can operate on this characteristic.
+     * @return The GattClient which can operate on this characteristic.
+     */
+    GattClient* getGattClient() {
+        return gattc;
+    }
+
+    /**
+     * @brief Return the GattClient which can operate on this characteristic.
+     * @return The GattClient which can operate on this characteristic.
+     */
+    const GattClient* getGattClient() const {
+        return gattc;
+    }
+
+    /**
+     * @brief Return the connection handle to the GattServer which contain
+     * this characteristic.
+     * @return the connection handle to the GattServer which contain
+     * this characteristic.
+     */
+    Gap::Handle_t getConnectionHandle() const {
+        return connHandle;
+    }
+
+    /**
+     * @brief "Equal to" operator for DiscoveredCharacteristic
+     *
+     * @param lhs[in] The left hand side of the equality expression
+     * @param rhs[in] The right hand side of the equality expression
+     *
+     * @return true if operands are equals, false otherwise.
+     */
+    friend bool operator==(const DiscoveredCharacteristic& lhs, const DiscoveredCharacteristic& rhs) {
+        return lhs.gattc == rhs.gattc &&
+               lhs.uuid == rhs.uuid &&
+               lhs.props == rhs.props &&
+               lhs.declHandle == rhs.declHandle &&
+               lhs.valueHandle == rhs.valueHandle &&
+               lhs.lastHandle == rhs.lastHandle &&
+               lhs.connHandle == rhs.connHandle;
+    }
+
+    /**
+     * @brief "Not equal to" operator for DiscoveredCharacteristic
+     *
+     * @param lhs[in] The right hand side of the expression
+     * @param rhs[in] The left hand side of the expression
+     *
+     * @return true if operands are not equals, false otherwise.
+     */
+    friend bool operator !=(const DiscoveredCharacteristic& lhs, const DiscoveredCharacteristic& rhs) {
+        return !(lhs == rhs);
+    }
+
 public:
     DiscoveredCharacteristic() : gattc(NULL),
                                  uuid(UUID::ShortUUIDBytes_t(0)),
                                  props(),
                                  declHandle(GattAttribute::INVALID_HANDLE),
-                                 valueHandle(GattAttribute::INVALID_HANDLE) {
+                                 valueHandle(GattAttribute::INVALID_HANDLE),
+                                 lastHandle(GattAttribute::INVALID_HANDLE),
+                                 connHandle() {
         /* empty */
     }
 
@@ -179,6 +321,7 @@
     Properties_t             props;
     GattAttribute::Handle_t  declHandle;
     GattAttribute::Handle_t  valueHandle;
+    GattAttribute::Handle_t  lastHandle;
 
     Gap::Handle_t            connHandle;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ble/DiscoveredCharacteristicDescriptor.h	Wed Apr 06 18:40:33 2016 +0100
@@ -0,0 +1,111 @@
+/* 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_DESCRIPTOR_H__
+#define __DISCOVERED_CHARACTERISTIC_DESCRIPTOR_H__
+
+#include "UUID.h"
+#include "Gap.h"
+#include "GattAttribute.h"
+#include "GattClient.h"
+#include "CharacteristicDescriptorDiscovery.h"
+
+/**
+ * @brief Representation of a descriptor discovered during a GattClient
+ * discovery procedure (see GattClient::discoverCharacteristicDescriptors or
+ * DiscoveredCharacteristic::discoverDescriptors ).
+ *
+ * @detail Provide detailed informations about a discovered characteristic descriptor
+ * like:
+ *     - Its UUID (see #getUUID).
+ *     - Its handle (see #getAttributeHandle)
+ * Basic read (see GattClient::read) and write (see GattClient::write) procedure from
+ * GattClient can be used access the value of the descriptor.
+ *
+ * @todo read member function
+ * @todo write member function
+ * @todo enumeration of standard descriptors
+ */
+class DiscoveredCharacteristicDescriptor {
+
+public:
+
+    /**
+     * @brief construct a new instance of a DiscoveredCharacteristicDescriptor
+     *
+     * @param client The client from where the descriptor has been discovered
+     * @param connectionHandle The connection handle on which the descriptor has
+     * been discovered
+     * @param attributeHandle The handle of the attribute containing this descriptor
+     * @param uuid The UUID of the descriptor
+     */
+    DiscoveredCharacteristicDescriptor(
+        GattClient* client, Gap::Handle_t connectionHandle,  GattAttribute::Handle_t attributeHandle, const UUID& uuid) :
+        _client(client), _connectionHandle(connectionHandle), _uuid(uuid), _gattHandle(attributeHandle) {
+
+    }
+
+    /**
+     * @brief Return the GattClient which can operate on this descriptor.
+     * @return The GattClient which can operate on this descriptor.
+     */
+    GattClient* getGattClient() {
+        return _client;
+    }
+
+    /**
+     * @brief Return the GattClient which can operate on this descriptor.
+     * @return The GattClient which can operate on this descriptor.
+     */
+    const GattClient* getGattClient() const {
+        return _client;
+    }
+
+    /**
+     * @brief Return the connection handle to the GattServer which contain
+     * this descriptor.
+     * @return the connection handle to the GattServer which contain
+     * this descriptor.
+     */
+    Gap::Handle_t getConnectionHandle() const {
+        return _connectionHandle;
+    }
+
+    /**
+     * @brief Return the UUID of this descriptor
+     * @return the UUID of this descriptor
+     */
+    const UUID& getUUID(void) const {
+        return _uuid;
+    }
+
+    /**
+     * @brief Return the attribute handle to use to access to this descriptor
+     * on the gatt server.
+     * @return The attribute handle of the descriptor
+     */
+    GattAttribute::Handle_t getAttributeHandle() const {
+        return _gattHandle;
+    }
+
+private:
+    GattClient  *_client;
+    Gap::Handle_t _connectionHandle;
+    UUID _uuid;
+    GattAttribute::Handle_t _gattHandle;
+};
+
+#endif /*__DISCOVERED_CHARACTERISTIC_DESCRIPTOR_H__*/
\ No newline at end of file
--- a/ble/Gap.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/Gap.h	Wed Apr 06 18:40:33 2016 +0100
@@ -17,12 +17,14 @@
 #ifndef __GAP_H__
 #define __GAP_H__
 
+#include "ble/BLEProtocol.h"
 #include "GapAdvertisingData.h"
 #include "GapAdvertisingParams.h"
 #include "GapScanningParams.h"
 #include "GapEvents.h"
 #include "CallChainOfFunctionPointersWithContext.h"
 #include "FunctionPointerWithContext.h"
+#include "deprecate.h"
 
 /* Forward declarations for classes that will only be used for pointers or references in the following. */
 class GapAdvertisingParams;
@@ -30,19 +32,44 @@
 class GapAdvertisingData;
 
 class Gap {
+    /*
+     * DEPRECATION ALERT: all of the APIs in this `public` block are deprecated.
+     * They have been relocated to the class BLEProtocol.
+     */
 public:
-    enum AddressType_t {
-        ADDR_TYPE_PUBLIC = 0,
-        ADDR_TYPE_RANDOM_STATIC,
-        ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE,
-        ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE
+    /**
+     * Address-type for BLEProtocol addresses.
+     *
+     * @note: deprecated. Use BLEProtocol::AddressType_t instead.
+     */
+    typedef BLEProtocol::AddressType_t AddressType_t;
+
+    /**
+     * Address-type for BLEProtocol addresses.
+     * @note: deprecated. Use BLEProtocol::AddressType_t instead.
+     */
+    typedef BLEProtocol::AddressType_t addr_type_t;
+
+    /**
+     * Address-type for BLEProtocol addresses.
+     * \deprecated: Use BLEProtocol::AddressType_t instead.
+     *
+     * DEPRECATION ALERT: The following constants have been left in their
+     * deprecated state to transparenly support existing applications which may
+     * have used Gap::ADDR_TYPE_*.
+     */
+    enum DeprecatedAddressType_t {
+        ADDR_TYPE_PUBLIC                        = BLEProtocol::AddressType::PUBLIC,
+        ADDR_TYPE_RANDOM_STATIC                 = BLEProtocol::AddressType::RANDOM_STATIC,
+        ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE     = BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE,
+        ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = BLEProtocol::AddressType::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. */
+    static const unsigned ADDR_LEN = BLEProtocol::ADDR_LEN; /**< Length (in octets) of the BLE MAC address. */
+    typedef BLEProtocol::AddressBytes_t Address_t; /**< 48-bit address, LSB format. @Note: Deprecated. Use BLEProtocol::AddressBytes_t instead. */
+    typedef BLEProtocol::AddressBytes_t address_t; /**< 48-bit address, LSB format. @Note: Deprecated. Use BLEProtocol::AddressBytes_t instead. */
 
+public:
     enum TimeoutSource_t {
         TIMEOUT_SRC_ADVERTISING      = 0x00, /**< Advertising timeout. */
         TIMEOUT_SRC_SECURITY_REQUEST = 0x01, /**< Security request timeout. */
@@ -66,6 +93,56 @@
         CONN_INTERVAL_UNACCEPTABLE                  = 0x3B,
     };
 
+    /**
+     * Enumeration for whitelist advertising policy filter modes. The possible
+     * filter modes were obtained from the Bluetooth Core Specification
+     * 4.2 (Vol. 6), Part B, Section 4.3.2.
+     *
+     * @experimental
+     */
+    enum AdvertisingPolicyMode_t {
+        ADV_POLICY_IGNORE_WHITELIST = 0,
+        ADV_POLICY_FILTER_SCAN_REQS = 1,
+        ADV_POLICY_FILTER_CONN_REQS = 2,
+        ADV_POLICY_FILTER_ALL_REQS  = 3,
+    };
+
+    /**
+     * Enumeration for whitelist scanning policy filter modes. The possible
+     * filter modes were obtained from the Bluetooth Core Specification
+     * 4.2 (Vol. 6), Part B, Section 4.3.3.
+     *
+     * @experimental
+     */
+    enum ScanningPolicyMode_t {
+        SCAN_POLICY_IGNORE_WHITELIST = 0,
+        SCAN_POLICY_FILTER_ALL_ADV   = 1,
+    };
+
+    /**
+     * Enumeration for the whitelist initiator policy fiter modes. The possible
+     * filter modes were obtained from the Bluetooth Core Specification
+     * 4.2 (vol. 6), Part B, Section 4.4.4.
+     *
+     * @experimental
+     */
+    enum InitiatorPolicyMode_t {
+        INIT_POLICY_IGNORE_WHITELIST = 0,
+        INIT_POLICY_FILTER_ALL_ADV   = 1,
+    };
+
+    /**
+     * Representation of a Bluetooth Low Enery Whitelist containing addresses.
+     *
+     * @experimental
+     */
+    struct Whitelist_t {
+        BLEProtocol::Address_t *addresses;
+        uint8_t                 size;
+        uint8_t                 capacity;
+    };
+
+
     /* Describes the current state of the device (more than one bit can be set). */
     struct GapState_t {
         unsigned advertising : 1; /**< Peripheral is currently advertising. */
@@ -75,9 +152,9 @@
     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 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;
 
@@ -87,31 +164,31 @@
     };
 
     struct AdvertisementCallbackParams_t {
-        Address_t            peerAddr;
-        int8_t               rssi;
-        bool                 isScanResponse;
-        GapAdvertisingParams::AdvertisingType_t type;
-        uint8_t              advertisingDataLen;
-        const uint8_t       *advertisingData;
+        BLEProtocol::AddressBytes_t              peerAddr;
+        int8_t                                   rssi;
+        bool                                     isScanResponse;
+        GapAdvertisingParams::AdvertisingType_t  type;
+        uint8_t                                  advertisingDataLen;
+        const uint8_t                           *advertisingData;
     };
     typedef FunctionPointerWithContext<const AdvertisementCallbackParams_t *> 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;
+        Handle_t                    handle;
+        Role_t                      role;
+        BLEProtocol::AddressType_t  peerAddrType;
+        BLEProtocol::AddressBytes_t peerAddr;
+        BLEProtocol::AddressType_t  ownAddrType;
+        BLEProtocol::AddressBytes_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) :
+        ConnectionCallbackParams_t(Handle_t                    handleIn,
+                                   Role_t                      roleIn,
+                                   BLEProtocol::AddressType_t  peerAddrTypeIn,
+                                   const uint8_t              *peerAddrIn,
+                                   BLEProtocol::AddressType_t  ownAddrTypeIn,
+                                   const uint8_t              *ownAddrIn,
+                                   const ConnectionParams_t   *connectionParamsIn) :
             handle(handleIn),
             role(roleIn),
             peerAddrType(peerAddrTypeIn),
@@ -151,17 +228,20 @@
 
     typedef FunctionPointerWithContext<bool> RadioNotificationEventCallback_t;
 
+    typedef FunctionPointerWithContext<const Gap *> GapShutdownCallback_t;
+    typedef CallChainOfFunctionPointersWithContext<const Gap *> GapShutdownCallbackChain_t;
+
     /*
      * 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
-     * least significant byte first (LSB). Please refer to Address_t.
+     * least significant byte first (LSB). Please refer to BLEProtocol::AddressBytes_t.
      *
      * @return BLE_ERROR_NONE on success.
      */
-    virtual ble_error_t setAddress(AddressType_t type, const Address_t address) {
+    virtual ble_error_t setAddress(BLEProtocol::AddressType_t type, const BLEProtocol::AddressBytes_t address) {
         /* avoid compiler warnings about unused variables */
         (void)type;
         (void)address;
@@ -174,7 +254,7 @@
      *
      * @return BLE_ERROR_NONE on success.
      */
-    virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address) {
+    virtual ble_error_t getAddress(BLEProtocol::AddressType_t *typeP, BLEProtocol::AddressBytes_t address) {
         /* Avoid compiler warnings about unused variables. */
         (void)typeP;
         (void)address;
@@ -233,10 +313,10 @@
      *     successfully. The connectionCallChain (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) {
+    virtual ble_error_t connect(const BLEProtocol::AddressBytes_t  peerAddr,
+                                BLEProtocol::AddressType_t         peerAddrType,
+                                const ConnectionParams_t          *connectionParams,
+                                const GapScanningParams           *scanParams) {
         /* Avoid compiler warnings about unused variables. */
         (void)peerAddr;
         (void)peerAddrType;
@@ -247,6 +327,23 @@
     }
 
     /**
+     * Create a connection (GAP Link Establishment).
+     *
+     * \deprecated: This funtion overloads Gap::connect(const BLEProtocol::Address_t  peerAddr,
+                                                        BLEProtocol::AddressType_t    peerAddrType,
+                                                        const ConnectionParams_t     *connectionParams,
+                                                        const GapScanningParams      *scanParams)
+     *      to maintain backward compatibility for change from Gap::AddressType_t to BLEProtocol::AddressType_t
+     */
+    ble_error_t connect(const BLEProtocol::AddressBytes_t  peerAddr,
+                        DeprecatedAddressType_t            peerAddrType,
+                        const ConnectionParams_t          *connectionParams,
+                        const GapScanningParams           *scanParams)
+    __deprecated_message("Gap::DeprecatedAddressType_t is deprecated, use BLEProtocol::AddressType_t instead") {
+        return connect(peerAddr, (BLEProtocol::AddressType_t) peerAddrType, connectionParams, scanParams);
+    }
+
+    /**
      * This call initiates the disconnection procedure, and its completion will
      * be communicated to the application with an invocation of the
      * disconnectionCallback.
@@ -425,6 +522,156 @@
         *countP = 0; /* Requesting action from porter(s): override this API if this capability is supported. */
     }
 
+    /**
+     * @return Maximum size of the whitelist.
+     *
+     * @experimental
+     */
+    virtual uint8_t getMaxWhitelistSize(void) const
+    {
+        return 0;
+    }
+
+    /**
+     * Get the internal whitelist to be used by the Link Layer when scanning,
+     * advertising or initiating a connection depending on the filter policies.
+     *
+     * @param[in/out]   whitelist
+     *                  (on input) whitelist.capacity contains the maximum number
+     *                  of addresses to be returned.
+     *                  (on output) The populated whitelist with copies of the
+     *                  addresses in the implementation's whitelist.
+     *
+     * @return BLE_ERROR_NONE if the implementation's whitelist was successfully
+     *         copied into the supplied reference.
+     *
+     * @experimental
+     */
+    virtual ble_error_t getWhitelist(Whitelist_t &whitelist) const
+    {
+        (void) whitelist;
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Set the internal whitelist to be used by the Link Layer when scanning,
+     * advertising or initiating a connection depending on the filter policies.
+     *
+     * @param[in]     whitelist
+     *                  A reference to a whitelist containing the addresses to
+     *                  be added to the internal whitelist.
+     *
+     * @return BLE_ERROR_NONE if the implementation's whitelist was successfully
+     *         populated with the addresses in the given whitelist.
+     *
+     * @note The whitelist must not contain addresses of type @ref
+     *       BLEProtocol::AddressType_t::RANDOM_PRIVATE_NON_RESOLVABLE, this
+     *       this will result in a @ref BLE_ERROR_INVALID_PARAM since the
+     *       remote peer might change its private address at any time and it
+     *       is not possible to resolve it.
+     * @note If the input whitelist is larger than @ref getMaxWhitelistSize()
+     *       the @ref BLE_ERROR_PARAM_OUT_OF_RANGE is returned.
+     *
+     * @experimental
+     */
+    virtual ble_error_t setWhitelist(const Whitelist_t &whitelist)
+    {
+        (void) whitelist;
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Set the advertising policy filter mode to be used in the next call
+     * to startAdvertising().
+     *
+     * @param[in] mode
+     *              The new advertising policy filter mode.
+     *
+     * @return BLE_ERROR_NONE if the specified policy filter mode was set
+     *         successfully.
+     *
+     * @experimental
+     */
+    virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode)
+    {
+        (void) mode;
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Set the scan policy filter mode to be used in the next call
+     * to startScan().
+     *
+     * @param[in] mode
+     *              The new scan policy filter mode.
+     *
+     * @return BLE_ERROR_NONE if the specified policy filter mode was set
+     *         successfully.
+     *
+     * @experimental
+     */
+    virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode)
+    {
+        (void) mode;
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Set the initiator policy filter mode to be used.
+     *
+     * @param[in] mode
+     *              The new initiator policy filter mode.
+     *
+     * @return BLE_ERROR_NONE if the specified policy filter mode was set
+     *         successfully.
+     *
+     * @experimental
+     */
+    virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode)
+    {
+        (void) mode;
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Get the advertising policy filter mode that will be used in the next
+     * call to startAdvertising().
+     *
+     * @return The set advertising policy filter mode.
+     *
+     * @experimental
+     */
+    virtual AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const
+    {
+        return ADV_POLICY_IGNORE_WHITELIST;
+    }
+
+    /**
+     * Get the scan policy filter mode that will be used in the next
+     * call to startScan().
+     *
+     * @return The set scan policy filter mode.
+     *
+     * @experimental
+     */
+    virtual ScanningPolicyMode_t getScanningPolicyMode(void) const
+    {
+        return SCAN_POLICY_IGNORE_WHITELIST;
+    }
+
+    /**
+     * Get the initiator policy filter mode that will be used.
+     *
+     * @return The set scan policy filter mode.
+     *
+     * @experimental
+     */
+    virtual InitiatorPolicyMode_t getInitiatorPolicyMode(void) const
+    {
+        return INIT_POLICY_IGNORE_WHITELIST;
+    }
+
+
 protected:
     /* Override the following in the underlying adaptation layer to provide the functionality of scanning. */
     virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) {
@@ -575,6 +822,16 @@
      * @param  type The type describing the variable length data.
      * @param  data Data bytes.
      * @param  len  Length of data.
+     *
+     * @return BLE_ERROR_NONE if the advertisement payload was updated based on
+     *         matching AD type; otherwise, an appropriate error.
+     *
+     * @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
+     *       supplied value is appended to the values previously added to the
+     *       payload.
      */
     ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) {
         if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
@@ -591,8 +848,7 @@
 
     /**
      * Update a particular ADV field in the advertising payload (based on
-     * matching type and length). Note: the length of the new data must be the
-     * same as the old one.
+     * matching type).
      *
      * @param[in] type  The ADV type field describing the variable length data.
      * @param[in] data  Data bytes.
@@ -601,7 +857,7 @@
      * @note: If advertisements are enabled, then the update will take effect immediately.
      *
      * @return BLE_ERROR_NONE if the advertisement payload was updated based on
-     *         a <type, len> match; otherwise, an appropriate error.
+     *         matching AD type; otherwise, an appropriate error.
      */
     ble_error_t updateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) {
         if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
@@ -983,6 +1239,80 @@
         radioNotificationCallback.attach(tptr, mptr);
     }
 
+    /**
+     * Setup a callback to be invoked to notify the user application that the
+     * Gap instance is about to shutdown (possibly as a result of a call
+     * to BLE::shutdown()).
+     *
+     * @Note: It is possible to chain together multiple onShutdown callbacks
+     * (potentially from different modules of an application) to be notified
+     * before the Gap instance is shutdown.
+     *
+     * @Note: It is also possible to set up a callback into a member function of
+     * some object.
+     *
+     * @Note It is possible to unregister a callback using onShutdown().detach(callback)
+     */
+    void onShutdown(const GapShutdownCallback_t& callback) {
+        shutdownCallChain.add(callback);
+    }
+    template <typename T>
+    void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
+        shutdownCallChain.add(objPtr, memberPtr);
+    }
+
+    /**
+     * @brief provide access to the callchain of shutdown event callbacks
+     * It is possible to register callbacks using onShutdown().add(callback);
+     * It is possible to unregister callbacks using onShutdown().detach(callback)
+     * @return The shutdown event callbacks chain
+     */
+    GapShutdownCallbackChain_t& onShutdown() {
+        return shutdownCallChain;
+    }
+
+public:
+    /**
+     * Notify all registered onShutdown callbacks that the Gap instance is
+     * about to be shutdown and clear all Gap state of the
+     * associated object.
+     *
+     * This function is meant to be overridden in the platform-specific
+     * sub-class. Nevertheless, the sub-class is only expected to reset its
+     * state and not the data held in Gap members. This shall be achieved by a
+     * call to Gap::reset() from the sub-class' reset() implementation.
+     *
+     * @return BLE_ERROR_NONE on success.
+     *
+     * @note: Currently a call to reset() does not reset the advertising and
+     * scan parameters to default values.
+     */
+    virtual ble_error_t reset(void) {
+        /* Notify that the instance is about to shutdown */
+        shutdownCallChain.call(this);
+        shutdownCallChain.clear();
+
+        /* Clear Gap state */
+        state.advertising = 0;
+        state.connected   = 0;
+
+        /* Clear scanning state */
+        scanningActive = false;
+
+        /* Clear advertising and scanning data */
+        _advPayload.clear();
+        _scanResponse.clear();
+
+        /* Clear callbacks */
+        timeoutCallbackChain.clear();
+        connectionCallChain.clear();
+        disconnectionCallChain.clear();
+        radioNotificationCallback = NULL;
+        onAdvertisementReport     = NULL;
+
+        return BLE_ERROR_NONE;
+    }
+
 protected:
     Gap() :
         _advParams(),
@@ -1002,13 +1332,13 @@
 
     /* 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) {
+    void processConnectionEvent(Handle_t                           handle,
+                                Role_t                             role,
+                                BLEProtocol::AddressType_t         peerAddrType,
+                                const BLEProtocol::AddressBytes_t  peerAddr,
+                                BLEProtocol::AddressType_t         ownAddrType,
+                                const BLEProtocol::AddressBytes_t  ownAddr,
+                                const ConnectionParams_t          *connectionParams) {
         state.connected = 1;
         ConnectionCallbackParams_t callbackParams(handle, role, peerAddrType, peerAddr, ownAddrType, ownAddr, connectionParams);
         connectionCallChain.call(&callbackParams);
@@ -1020,12 +1350,12 @@
         disconnectionCallChain.call(&callbackParams);
     }
 
-    void processAdvertisementReport(const Address_t    peerAddr,
-                                    int8_t             rssi,
-                                    bool               isScanResponse,
+    void processAdvertisementReport(const BLEProtocol::AddressBytes_t        peerAddr,
+                                    int8_t                                   rssi,
+                                    bool                                     isScanResponse,
                                     GapAdvertisingParams::AdvertisingType_t  type,
-                                    uint8_t            advertisingDataLen,
-                                    const uint8_t     *advertisingData) {
+                                    uint8_t                                  advertisingDataLen,
+                                    const uint8_t                           *advertisingData) {
         AdvertisementCallbackParams_t params;
         memcpy(params.peerAddr, peerAddr, ADDR_LEN);
         params.rssi               = rssi;
@@ -1059,6 +1389,9 @@
     DisconnectionEventCallbackChain_t disconnectionCallChain;
 
 private:
+    GapShutdownCallbackChain_t shutdownCallChain;
+
+private:
     /* Disallow copy and assignment. */
     Gap(const Gap &);
     Gap& operator=(const Gap &);
--- a/ble/GapAdvertisingData.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/GapAdvertisingData.h	Wed Apr 06 18:40:33 2016 +0100
@@ -187,6 +187,7 @@
         PULSE_OXIMETER_GENERIC                         = 3136,  /**< Generic Pulse Oximeter. */
         PULSE_OXIMETER_FINGERTIP                       = 3137,  /**< Fingertip Pulse Oximeter. */
         PULSE_OXIMETER_WRIST_WORN                      = 3138,  /**< Wrist Worn Pulse Oximeter. */
+        GENERIC_WEIGHT_SCALE                           = 3200,  /**< Generic Weight Scale. */
         OUTDOOR_GENERIC                                = 5184,  /**< Generic Outdoor. */
         OUTDOOR_LOCATION_DISPLAY_DEVICE                = 5185,  /**< Outdoor Location Display Device. */
         OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186,  /**< Outdoor Location and Navigation Display Device. */
@@ -201,149 +202,63 @@
 
     /**
      * Adds advertising data based on the specified AD type (see DataType).
-     *
-     * @param  advDataType The Advertising 'DataType' to add.
-     * @param  payload     Pointer to the payload contents.
-     * @param  len         Size of the payload in bytes.
-     *
-     * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
-     * advertising buffer to overflow, else BLE_ERROR_NONE.
-     */
-    ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
-    {
-        ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
-
-        // find field
-        uint8_t* field = findField(advDataType);
-
-        // Field type already exist, either add to field or replace
-        if (field) {
-            switch(advDataType) {
-                //  These fields will be overwritten with the new value
-                case FLAGS:
-                case SHORTENED_LOCAL_NAME:
-                case COMPLETE_LOCAL_NAME:
-                case TX_POWER_LEVEL:
-                case DEVICE_ID:
-                case SLAVE_CONNECTION_INTERVAL_RANGE:
-                case SERVICE_DATA:
-                case APPEARANCE:
-                case ADVERTISING_INTERVAL:
-                case MANUFACTURER_SPECIFIC_DATA: {
-                    // current field length, with the type subtracted
-                    uint8_t dataLength = field[0] - 1;
-
-                    // new data has same length, do in-order replacement
-                    if (len == dataLength) {
-                        for (uint8_t idx = 0; idx < dataLength; idx++) {
-                            field[2 + idx] = payload[idx];
-                        }
-                    } else {
-                        // check if data fits
-                        if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
-
-                            // remove old field
-                            while ((field + dataLength + 2) < &_payload[_payloadLen]) {
-                                *field = field[dataLength + 2];
-                                field++;
-                            }
-
-                            // reduce length
-                            _payloadLen -= dataLength + 2;
-
-                            // add new field
-                            result = appendField(advDataType, payload, len);
-                        }
-                    }
-
-                    break;
-                }
-                // These fields will have the new data appended if there is sufficient space
-                case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
-                case COMPLETE_LIST_16BIT_SERVICE_IDS:
-                case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
-                case COMPLETE_LIST_32BIT_SERVICE_IDS:
-                case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
-                case COMPLETE_LIST_128BIT_SERVICE_IDS:
-                case LIST_128BIT_SOLICITATION_IDS: {
-                    // check if data fits
-                    if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
-                        // make room for new field by moving the remainder of the
-                        // advertisement payload "to the right" starting after the
-                        // TYPE field.
-                        uint8_t* end = &_payload[_payloadLen];
-
-                        while (&field[1] < end) {
-                            end[len] = *end;
-                            end--;
-                        }
-
-                        // insert new data
-                        for (uint8_t idx = 0; idx < len; idx++) {
-                            field[2 + idx] = payload[idx];
-                        }
-
-                        // increment lengths
-                        field[0] += len;
-                        _payloadLen += len;
-
-                        result = BLE_ERROR_NONE;
-                    }
-
-                    break;
-                }
-                // Field exists but updating it is not supported. Abort operation.
-                default:
-                    result = BLE_ERROR_NOT_IMPLEMENTED;
-                    break;
-            }
-        } else {
-            // field doesn't exists, insert new
-            result = appendField(advDataType, payload, len);
-        }
-
-        return result;
-    }
-
-    /**
-     * Update a particular ADV field in the advertising payload (based on
-     * matching type and length). Note: the length of the new data must be the
-     * same as the old one.
+     * If the supplied AD type is already present in the advertising
+     * payload, then the value is updated.
      *
      * @param[in] advDataType  The Advertising 'DataType' to add.
      * @param[in] payload      Pointer to the payload contents.
      * @param[in] len          Size of the payload in bytes.
      *
-     * @return BLE_ERROR_UNSPECIFIED if the specified field is not found, else
-     * BLE_ERROR_NONE.
+     * @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
+     *         advertising buffer to overflow. BLE_ERROR_NONE is returned
+     *         on success.
+     *
+     * @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
+     *       supplied value is appended to the values previously added to the
+     *       payload.
+     */
+    ble_error_t addData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
+    {
+        // find field
+        uint8_t* field = findField(advDataType);
+
+        if (field) {
+            // Field type already exist, either add to field or replace
+            return addField(advDataType, payload, len, field);
+        } else {
+            // field doesn't exists, insert new
+            return appendField(advDataType, payload, len);
+        }
+    }
+
+    /**
+     * Update a particular ADV field in the advertising payload (based on
+     * matching type).
+     *
+     * @param[in] advDataType  The Advertising 'DataType' to add.
+     * @param[in] payload      Pointer to the payload contents.
+     * @param[in] len          Size of the payload in bytes.
+     *
+     * @return BLE_ERROR_UNSPECIFIED if the specified field is not found,
+     *         BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
+     *         advertising buffer to overflow. BLE_ERROR_NONE is returned
+     *         on success.
      */
     ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
     {
-        if ((payload == NULL) || (len == 0)) {
-            return BLE_ERROR_INVALID_PARAM;
-        }
-
-        /* A local struct to describe an ADV field. This definition comes from the Bluetooth Core Spec. (v4.2) Part C, Section 11. */
-        struct ADVField_t {
-            uint8_t  len;      /* Describes the length (in bytes) of the following type and bytes. */
-            uint8_t  type;     /* Should have the same representation of DataType_t (above). */
-            uint8_t  bytes[0]; /* A placeholder for variable length data. */
-        };
+        // find field
+        uint8_t* field = findField(advDataType);
 
-        /* Iterate over the adv fields looking for the first match. */
-        uint8_t byteIndex = 0;
-        while (byteIndex < _payloadLen) {
-            ADVField_t *currentADV = (ADVField_t *)&_payload[byteIndex];
-            if ((currentADV->len  == (len + 1)) && /* Incoming len only describes the payload, whereas ADV->len describes [type + payload]. */
-                (currentADV->type == advDataType)) {
-                memcpy(currentADV->bytes, payload, len);
-                return BLE_ERROR_NONE;
-            }
-
-            byteIndex += (currentADV->len + 1); /* Advance by len+1; '+1' is needed to span the len field itself. */
+        if (field) {
+            // Field type already exist, replace field contents
+            return updateField(advDataType, payload, len, field);
+        } else {
+            // field doesn't exists, return an error
+            return BLE_ERROR_UNSPECIFIED;
         }
-
-        return BLE_ERROR_UNSPECIFIED;
     }
 
     /**
@@ -474,6 +389,107 @@
         return NULL;
     }
 
+    /**
+     * Given the a pointer to a field in the advertising payload it replaces
+     * the existing data in the field with the supplied data.
+     *
+     * When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
+     * COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
+     * COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
+     * COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
+     * supplied value is appended to the values previously added to the
+     * payload.
+     *
+     * Returns BLE_ERROR_NONE on success.
+     */
+    ble_error_t addField(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
+    {
+        ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
+
+        switch(advDataType) {
+            // These fields will have the new data appended if there is sufficient space
+            case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
+            case COMPLETE_LIST_16BIT_SERVICE_IDS:
+            case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
+            case COMPLETE_LIST_32BIT_SERVICE_IDS:
+            case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
+            case COMPLETE_LIST_128BIT_SERVICE_IDS:
+            case LIST_128BIT_SOLICITATION_IDS: {
+                // check if data fits
+                if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
+                    // make room for new field by moving the remainder of the
+                    // advertisement payload "to the right" starting after the
+                    // TYPE field.
+                    uint8_t* end = &_payload[_payloadLen];
+
+                    while (&field[1] < end) {
+                        end[len] = *end;
+                        end--;
+                    }
+
+                    // insert new data
+                    for (uint8_t idx = 0; idx < len; idx++) {
+                        field[2 + idx] = payload[idx];
+                    }
+
+                    // increment lengths
+                    field[0] += len;
+                    _payloadLen += len;
+
+                    result = BLE_ERROR_NONE;
+                }
+
+                break;
+            }
+            //  These fields will be overwritten with the new value
+            default: {
+                result = updateField(advDataType, payload, len, field);
+
+                break;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Given the a pointer to a field in the advertising payload it replaces
+     * the existing data in the field with the supplied data.
+     * Returns BLE_ERROR_NONE on success.
+     */
+    ble_error_t updateField(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
+    {
+        ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
+        uint8_t dataLength = field[0] - 1;
+
+        // new data has same length, do in-order replacement
+        if (len == dataLength) {
+            for (uint8_t idx = 0; idx < dataLength; idx++) {
+                field[2 + idx] = payload[idx];
+            }
+
+            result = BLE_ERROR_NONE;
+        } else {
+            // check if data fits
+            if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
+
+                // remove old field
+                while ((field + dataLength + 2) < &_payload[_payloadLen]) {
+                    *field = field[dataLength + 2];
+                    field++;
+                }
+
+                // reduce length
+                _payloadLen -= dataLength + 2;
+
+                // add new field
+                result = appendField(advDataType, payload, len);
+            }
+        }
+
+        return result;
+    }
+
     uint8_t  _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
     uint8_t  _payloadLen;
     uint16_t _appearance;
--- a/ble/GattClient.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/GattClient.h	Wed Apr 06 18:40:33 2016 +0100
@@ -20,6 +20,7 @@
 #include "Gap.h"
 #include "GattAttribute.h"
 #include "ServiceDiscovery.h"
+#include "CharacteristicDescriptorDiscovery.h"
 
 #include "GattCallbackParamTypes.h"
 
@@ -41,6 +42,9 @@
     typedef FunctionPointerWithContext<const GattHVXCallbackParams*> HVXCallback_t;
     typedef CallChainOfFunctionPointersWithContext<const GattHVXCallbackParams*> HVXCallbackChain_t;
 
+    typedef FunctionPointerWithContext<const GattClient *> GattClientShutdownCallback_t;
+    typedef CallChainOfFunctionPointersWithContext<const GattClient *> GattClientShutdownCallbackChain_t;
+
     /*
      * The following functions are meant to be overridden in the platform-specific sub-class.
      */
@@ -216,8 +220,8 @@
      * 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 
+     *              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.
@@ -246,8 +250,8 @@
     /* Event callback handlers. */
 public:
     /**
-     * Set up a callback for read response events. 
-     * It is possible to remove registered callbacks using 
+     * Set up a callback for read response events.
+     * It is possible to remove registered callbacks using
      * onDataRead().detach(callbackToRemove)
      */
     void onDataRead(ReadCallback_t callback) {
@@ -257,7 +261,7 @@
     /**
      * @brief provide access to the callchain of read callbacks
      * It is possible to register callbacks using onDataRead().add(callback);
-     * It is possible to unregister callbacks using onDataRead().detach(callback) 
+     * It is possible to unregister callbacks using onDataRead().detach(callback)
      * @return The read callbacks chain
      */
     ReadCallbackChain_t& onDataRead() {
@@ -266,7 +270,7 @@
 
     /**
      * Set up a callback for write response events.
-     * It is possible to remove registered callbacks using 
+     * It is possible to remove registered callbacks using
      * onDataWritten().detach(callbackToRemove).
      * @Note: Write commands (issued using writeWoResponse) don't generate a response.
      */
@@ -277,10 +281,10 @@
     /**
      * @brief provide access to the callchain of data written callbacks
      * It is possible to register callbacks using onDataWritten().add(callback);
-     * It is possible to unregister callbacks using onDataWritten().detach(callback) 
+     * It is possible to unregister callbacks using onDataWritten().detach(callback)
      * @return The data written callbacks chain
      */
-    WriteCallbackChain_t& onDataWritten() { 
+    WriteCallbackChain_t& onDataWritten() {
         return onDataWriteCallbackChain;
     }
 
@@ -305,6 +309,59 @@
     }
 
     /**
+     * @brief launch discovery of descriptors for a given characteristic
+     * @details This function will discover all descriptors available for a
+     * specific characteristic.
+     *
+     * @param characteristic[in] The characteristic targeted by this discovery
+     * procedure
+     * @param discoveryCallback[in] User function called each time a descriptor
+     * is found during the procedure.
+     * @param terminationCallback[in] User provided function which will be called
+     * once the discovery procedure is terminating. This will get called when all
+     * the descriptors have been discovered or if an error occur during the discovery
+     * procedure.
+     *
+     * @return
+     *   BLE_ERROR_NONE if characteristic descriptor discovery is launched
+     *   successfully; else an appropriate error.
+     */
+    virtual ble_error_t discoverCharacteristicDescriptors(
+        const DiscoveredCharacteristic& characteristic,
+        const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
+        const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback) {
+        (void) characteristic;
+        (void) discoveryCallback;
+        (void) terminationCallback;
+        /* Requesting action from porter(s): override this API if this capability is supported. */
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * @brief Indicate if the discovery of characteristic descriptors is active for a given characteristic
+     * or not.
+     * @param characteristic[in] The characteristic concerned by the descriptors discovery.
+     * @return true if a descriptors discovery is active for the characteristic in input; otherwise false.
+     */
+    virtual bool isCharacteristicDescriptorDiscoveryActive(const DiscoveredCharacteristic& characteristic) const
+     {
+        (void) characteristic;
+        return false; /* Requesting action from porter(s): override this API if this capability is supported. */
+    }
+
+    /**
+     * @brief Terminate an ongoing characteristic descriptor discovery.
+     * @detail This should result in an invocation of the TerminationCallback if
+     * the characteristic descriptor discovery is active.
+     * @param characteristic[in] The characteristic on which the running descriptors
+     * discovery should be stopped.
+     */
+    virtual void terminateCharacteristicDescriptorDiscovery(const DiscoveredCharacteristic& characteristic) {
+        /* Requesting action from porter(s): override this API if this capability is supported. */
+        (void) characteristic;
+    }
+
+    /**
      * Set up a callback for when the GATT client receives an update event
      * corresponding to a change in the value of a characteristic on the remote
      * GATT server.
@@ -314,17 +371,74 @@
         onHVXCallbackChain.add(callback);
     }
 
+    /**
+     * Setup a callback to be invoked to notify the user application that the
+     * GattClient instance is about to shutdown (possibly as a result of a call
+     * to BLE::shutdown()).
+     *
+     * @Note: It is possible to chain together multiple onShutdown callbacks
+     * (potentially from different modules of an application) to be notified
+     * before the GattClient is shutdown.
+     *
+     * @Note: It is also possible to set up a callback into a member function of
+     * some object.
+     *
+     * @Note It is possible to unregister a callback using onShutdown().detach(callback)
+     */
+    void onShutdown(const GattClientShutdownCallback_t& callback) {
+        shutdownCallChain.add(callback);
+    }
+    template <typename T>
+    void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
+        shutdownCallChain.add(objPtr, memberPtr);
+    }
+
+    /**
+     * @brief provide access to the callchain of shutdown event callbacks
+     * It is possible to register callbacks using onShutdown().add(callback);
+     * It is possible to unregister callbacks using onShutdown().detach(callback)
+     * @return The shutdown event callbacks chain
+     */
+    GattClientShutdownCallbackChain_t& onShutdown() {
+        return shutdownCallChain;
+    }
 
     /**
      * @brief provide access to the callchain of HVX callbacks
      * It is possible to register callbacks using onHVX().add(callback);
-     * It is possible to unregister callbacks using onHVX().detach(callback) 
+     * It is possible to unregister callbacks using onHVX().detach(callback)
      * @return The HVX callbacks chain
      */
-    HVXCallbackChain_t& onHVX() { 
+    HVXCallbackChain_t& onHVX() {
         return onHVXCallbackChain;
     }
 
+public:
+    /**
+     * Notify all registered onShutdown callbacks that the GattClient is
+     * about to be shutdown and clear all GattClient state of the
+     * associated object.
+     *
+     * This function is meant to be overridden in the platform-specific
+     * sub-class. Nevertheless, the sub-class is only expected to reset its
+     * state and not the data held in GattClient members. This shall be achieved
+     * by a call to GattClient::reset() from the sub-class' reset()
+     * implementation.
+     *
+     * @return BLE_ERROR_NONE on success.
+     */
+    virtual ble_error_t reset(void) {
+        /* Notify that the instance is about to shutdown */
+        shutdownCallChain.call(this);
+        shutdownCallChain.clear();
+
+        onDataReadCallbackChain.clear();
+        onDataWriteCallbackChain.clear();
+        onHVXCallbackChain.clear();
+
+        return BLE_ERROR_NONE;
+    }
+
 protected:
     GattClient() {
         /* Empty */
@@ -347,9 +461,10 @@
     }
 
 protected:
-    ReadCallbackChain_t  onDataReadCallbackChain;
-    WriteCallbackChain_t onDataWriteCallbackChain;
-    HVXCallbackChain_t   onHVXCallbackChain;
+    ReadCallbackChain_t               onDataReadCallbackChain;
+    WriteCallbackChain_t              onDataWriteCallbackChain;
+    HVXCallbackChain_t                onHVXCallbackChain;
+    GattClientShutdownCallbackChain_t shutdownCallChain;
 
 private:
     /* Disallow copy and assignment. */
--- a/ble/GattServer.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/GattServer.h	Wed Apr 06 18:40:33 2016 +0100
@@ -26,17 +26,19 @@
 
 class GattServer {
 public:
-
     /* Event callback handlers. */
     typedef FunctionPointerWithContext<unsigned> DataSentCallback_t;
     typedef CallChainOfFunctionPointersWithContext<unsigned> DataSentCallbackChain_t;
 
     typedef FunctionPointerWithContext<const GattWriteCallbackParams*> DataWrittenCallback_t;
-    typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> DataWrittenCallbackChain_t;    
+    typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> DataWrittenCallbackChain_t;
 
     typedef FunctionPointerWithContext<const GattReadCallbackParams*> DataReadCallback_t;
     typedef CallChainOfFunctionPointersWithContext<const GattReadCallbackParams *> DataReadCallbackChain_t;
 
+    typedef FunctionPointerWithContext<const GattServer *> GattServerShutdownCallback_t;
+    typedef CallChainOfFunctionPointersWithContext<const GattServer *> GattServerShutdownCallbackChain_t;
+
     typedef FunctionPointerWithContext<GattAttribute::Handle_t> EventCallback_t;
 
 protected:
@@ -185,27 +187,6 @@
     }
 
     /**
-     * Perform an explicit BLE notification of a given attribute.
-     *
-     * @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).
-     *
-     * @return BLE_ERROR_NONE if we have successfully set the value of the attribute.
-     */
-    virtual ble_error_t notify(GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size)
-    {
-        (void)attributeHandle;
-        (void)value;
-        (void)size;
-
-        return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porter(s): override this API if this capability is supported. */
-    }
-
-    /**
      * Determine the updates-enabled status (notification or indication) for the current connection from a characteristic's CCCD.
      *
      * @param       characteristic
@@ -275,9 +256,9 @@
     }
 
     /**
-     * @brief get the callback chain called when the event DATA_EVENT is triggered. 
+     * @brief get the callback chain called when the event DATA_EVENT is triggered.
      */
-    DataSentCallbackChain_t& onDataSent() { 
+    DataSentCallbackChain_t& onDataSent() {
         return dataSentCallChain;
     }
 
@@ -295,7 +276,7 @@
      *
      * @Note: It is also possible to set up a callback into a member function of
      * some object.
-     * 
+     *
      * @Note It is possible to unregister a callback using onDataWritten().detach(callback)
      */
     void onDataWritten(const DataWrittenCallback_t& callback) {dataWrittenCallChain.add(callback);}
@@ -307,9 +288,9 @@
     /**
      * @brief provide access to the callchain of data written event callbacks
      * It is possible to register callbacks using onDataWritten().add(callback);
-     * It is possible to unregister callbacks using onDataWritten().detach(callback) 
+     * It is possible to unregister callbacks using onDataWritten().detach(callback)
      * @return The data written event callbacks chain
-     */    
+     */
     DataWrittenCallbackChain_t& onDataWritten() {
         return dataWrittenCallChain;
     }
@@ -356,7 +337,7 @@
     /**
      * @brief provide access to the callchain of data read event callbacks
      * It is possible to register callbacks using onDataRead().add(callback);
-     * It is possible to unregister callbacks using onDataRead().detach(callback) 
+     * It is possible to unregister callbacks using onDataRead().detach(callback)
      * @return The data read event callbacks chain
      */
     DataReadCallbackChain_t& onDataRead() {
@@ -364,6 +345,38 @@
     }
 
     /**
+     * Setup a callback to be invoked to notify the user application that the
+     * GattServer instance is about to shutdown (possibly as a result of a call
+     * to BLE::shutdown()).
+     *
+     * @Note: It is possible to chain together multiple onShutdown callbacks
+     * (potentially from different modules of an application) to be notified
+     * before the GattServer is shutdown.
+     *
+     * @Note: It is also possible to set up a callback into a member function of
+     * some object.
+     *
+     * @Note It is possible to unregister a callback using onShutdown().detach(callback)
+     */
+    void onShutdown(const GattServerShutdownCallback_t& callback) {
+        shutdownCallChain.add(callback);
+    }
+    template <typename T>
+    void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
+        shutdownCallChain.add(objPtr, memberPtr);
+    }
+
+    /**
+     * @brief provide access to the callchain of shutdown event callbacks
+     * It is possible to register callbacks using onShutdown().add(callback);
+     * It is possible to unregister callbacks using onShutdown().detach(callback)
+     * @return The shutdown event callbacks chain
+     */
+    GattServerShutdownCallbackChain_t& onShutdown() {
+        return shutdownCallChain;
+    }
+
+    /**
      * Set up a callback for when notifications or indications are enabled for a
      * characteristic on the local GATT server.
      */
@@ -417,17 +430,50 @@
         dataSentCallChain.call(count);
     }
 
+public:
+    /**
+     * Notify all registered onShutdown callbacks that the GattServer is
+     * about to be shutdown and clear all GattServer state of the
+     * associated object.
+     *
+     * This function is meant to be overridden in the platform-specific
+     * sub-class. Nevertheless, the sub-class is only expected to reset its
+     * state and not the data held in GattServer members. This shall be achieved
+     * by a call to GattServer::reset() from the sub-class' reset()
+     * implementation.
+     *
+     * @return BLE_ERROR_NONE on success.
+     */
+    virtual ble_error_t reset(void) {
+        /* Notify that the instance is about to shutdown */
+        shutdownCallChain.call(this);
+        shutdownCallChain.clear();
+
+        serviceCount = 0;
+        characteristicCount = 0;
+
+        dataSentCallChain.clear();
+        dataWrittenCallChain.clear();
+        dataReadCallChain.clear();
+        updatesEnabledCallback       = NULL;
+        updatesDisabledCallback      = NULL;
+        confirmationReceivedCallback = NULL;
+
+        return BLE_ERROR_NONE;
+    }
+
 protected:
     uint8_t serviceCount;
     uint8_t characteristicCount;
 
 private:
-    DataSentCallbackChain_t    dataSentCallChain;
-    DataWrittenCallbackChain_t dataWrittenCallChain;
-    DataReadCallbackChain_t    dataReadCallChain;
-    EventCallback_t            updatesEnabledCallback;
-    EventCallback_t            updatesDisabledCallback;
-    EventCallback_t            confirmationReceivedCallback;
+    DataSentCallbackChain_t           dataSentCallChain;
+    DataWrittenCallbackChain_t        dataWrittenCallChain;
+    DataReadCallbackChain_t           dataReadCallChain;
+    GattServerShutdownCallbackChain_t shutdownCallChain;
+    EventCallback_t                   updatesEnabledCallback;
+    EventCallback_t                   updatesDisabledCallback;
+    EventCallback_t                   confirmationReceivedCallback;
 
 private:
     /* Disallow copy and assignment. */
--- a/ble/SecurityManager.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/SecurityManager.h	Wed Apr 06 18:40:33 2016 +0100
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include "Gap.h"
+#include "CallChainOfFunctionPointersWithContext.h"
 
 class SecurityManager {
 public:
@@ -82,6 +83,9 @@
     typedef void (*LinkSecuredCallback_t)(Gap::Handle_t handle, SecurityMode_t securityMode);
     typedef void (*PasskeyDisplayCallback_t)(Gap::Handle_t handle, const Passkey_t passkey);
 
+    typedef FunctionPointerWithContext<const SecurityManager *> SecurityManagerShutdownCallback_t;
+    typedef CallChainOfFunctionPointersWithContext<const SecurityManager *> SecurityManagerShutdownCallbackChain_t;
+
     /*
      * The following functions are meant to be overridden in the platform-specific sub-class.
      */
@@ -120,7 +124,7 @@
      * @param[in]  connectionHandle   Handle to identify the connection.
      * @param[out] securityStatusP    Security status.
      *
-     * @return BLE_SUCCESS or appropriate error code indicating the failure reason.
+     * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
      */
     virtual ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) {
         /* Avoid compiler warnings about unused variables. */
@@ -131,6 +135,23 @@
     }
 
     /**
+     * Set the security mode on a connection. Useful for elevating the security mode
+     * once certain conditions are met, e.g., a particular service is found.
+     *
+     * @param[in]  connectionHandle   Handle to identify the connection.
+     * @param[in]  securityMode       Requested security mode.
+     *
+     * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
+     */
+    virtual ble_error_t setLinkSecurity(Gap::Handle_t connectionHandle, SecurityMode_t securityMode) {
+        /* Avoid compiler warnings about unused variables. */
+        (void)connectionHandle;
+        (void)securityMode;
+
+        return BLE_ERROR_NOT_IMPLEMENTED;
+    }
+
+    /**
      * Delete all peer device context and all related bonding information from
      * the database within the security manager.
      *
@@ -142,9 +163,63 @@
         return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
     }
 
+    /**
+     * Get a list of addresses from all peers in the bond table.
+     *
+     * @param[in/out]   addresses
+     *                  (on input) addresses.capacity contains the maximum
+     *                  number of addresses to be returned.
+     *                  (on output) The populated table with copies of the
+     *                  addresses in the implementation's whitelist.
+     *
+     * @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 or
+     *                                    application registration.
+     *
+     * @experimental
+     */
+    virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
+        /* Avoid compiler warnings about unused variables */
+        (void) addresses;
+
+        return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
+    }
+
     /* Event callback handlers. */
 public:
     /**
+     * Setup a callback to be invoked to notify the user application that the
+     * SecurityManager instance is about to shutdown (possibly as a result of a call
+     * to BLE::shutdown()).
+     *
+     * @Note: It is possible to chain together multiple onShutdown callbacks
+     * (potentially from different modules of an application) to be notified
+     * before the SecurityManager is shutdown.
+     *
+     * @Note: It is also possible to set up a callback into a member function of
+     * some object.
+     *
+     * @Note It is possible to unregister a callback using onShutdown().detach(callback)
+     */
+    void onShutdown(const SecurityManagerShutdownCallback_t& callback) {
+        shutdownCallChain.add(callback);
+    }
+    template <typename T>
+    void onShutdown(T *objPtr, void (T::*memberPtr)(void)) {
+        shutdownCallChain.add(objPtr, memberPtr);
+    }
+
+    /**
+     * @brief provide access to the callchain of shutdown event callbacks
+     * It is possible to register callbacks using onShutdown().add(callback);
+     * It is possible to unregister callbacks using onShutdown().detach(callback)
+     * @return The shutdown event callbacks chain
+     */
+    SecurityManagerShutdownCallbackChain_t& onShutdown() {
+        return shutdownCallChain;
+    }
+
+    /**
      * To indicate that a security procedure for the link has started.
      */
     virtual void onSecuritySetupInitiated(SecuritySetupInitiatedCallback_t callback) {securitySetupInitiatedCallback = callback;}
@@ -214,12 +289,43 @@
         /* empty */
     }
 
+public:
+    /**
+     * Notify all registered onShutdown callbacks that the SecurityManager is
+     * about to be shutdown and clear all SecurityManager state of the
+     * associated object.
+     *
+     * This function is meant to be overridden in the platform-specific
+     * sub-class. Nevertheless, the sub-class is only expected to reset its
+     * state and not the data held in SecurityManager members. This shall be
+     * achieved by a call to SecurityManager::reset() from the sub-class'
+     * reset() implementation.
+     *
+     * @return BLE_ERROR_NONE on success.
+     */
+    virtual ble_error_t reset(void) {
+        /* Notify that the instance is about to shutdown */
+        shutdownCallChain.call(this);
+        shutdownCallChain.clear();
+
+        securitySetupInitiatedCallback = NULL;
+        securitySetupCompletedCallback = NULL;
+        linkSecuredCallback            = NULL;
+        securityContextStoredCallback  = NULL;
+        passkeyDisplayCallback         = NULL;
+
+        return BLE_ERROR_NONE;
+    }
+
 protected:
     SecuritySetupInitiatedCallback_t securitySetupInitiatedCallback;
     SecuritySetupCompletedCallback_t securitySetupCompletedCallback;
     LinkSecuredCallback_t            linkSecuredCallback;
     HandleSpecificEvent_t            securityContextStoredCallback;
     PasskeyDisplayCallback_t         passkeyDisplayCallback;
+
+private:
+    SecurityManagerShutdownCallbackChain_t shutdownCallChain;
 };
 
 #endif /*__SECURITY_MANAGER_H__*/
\ No newline at end of file
--- a/ble/ServiceDiscovery.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/ServiceDiscovery.h	Wed Apr 06 18:40:33 2016 +0100
@@ -132,6 +132,27 @@
      */
     virtual void        onTermination(TerminationCallback_t callback) = 0;
 
+    /**
+     * Clear all ServiceDiscovery state of the associated object.
+     *
+     * This function is meant to be overridden in the platform-specific
+     * sub-class. Nevertheless, the sub-class is only expected to reset its
+     * state and not the data held in ServiceDiscovery members. This shall be
+     * achieved by a call to ServiceDiscovery::reset() from the sub-class'
+     * reset() implementation.
+     *
+     * @return BLE_ERROR_NONE on success.
+     */
+    virtual ble_error_t reset(void) {
+        connHandle                 = 0;
+        matchingServiceUUID        = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN);
+        serviceCallback            = NULL;
+        matchingCharacteristicUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN);
+        characteristicCallback     = NULL;
+
+        return BLE_ERROR_NONE;
+    }
+
 protected:
     Gap::Handle_t            connHandle; /**< Connection handle as provided by the SoftDevice. */
     UUID                     matchingServiceUUID;
--- a/ble/blecommon.h	Wed Apr 06 18:40:32 2016 +0100
+++ b/ble/blecommon.h	Wed Apr 06 18:40:33 2016 +0100
@@ -49,62 +49,6 @@
     BLE_UUID_GAP_CHARACTERISTIC_PPCP             = 0x2A04, /**< Peripheral Preferred Connection Parameters Characteristic. */
 };
 
-/*! Bluetooth appearance values.
- *  @note Retrieved from http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
- */
-enum {
-    BLE_APPEARANCE_UNKNOWN                             =    0, /**< Unknown. */
-    BLE_APPEARANCE_GENERIC_PHONE                       =   64, /**< Generic Phone. */
-    BLE_APPEARANCE_GENERIC_COMPUTER                    =  128, /**< Generic Computer. */
-    BLE_APPEARANCE_GENERIC_WATCH                       =  192, /**< Generic Watch. */
-    BLE_APPEARANCE_WATCH_SPORTS_WATCH                  =  193, /**< Watch: Sports Watch. */
-    BLE_APPEARANCE_GENERIC_CLOCK                       =  256, /**< Generic Clock. */
-    BLE_APPEARANCE_GENERIC_DISPLAY                     =  320, /**< Generic Display. */
-    BLE_APPEARANCE_GENERIC_REMOTE_CONTROL              =  384, /**< Generic Remote Control. */
-    BLE_APPEARANCE_GENERIC_EYE_GLASSES                 =  448, /**< Generic Eye-glasses. */
-    BLE_APPEARANCE_GENERIC_TAG                         =  512, /**< Generic Tag. */
-    BLE_APPEARANCE_GENERIC_KEYRING                     =  576, /**< Generic Keyring. */
-    BLE_APPEARANCE_GENERIC_MEDIA_PLAYER                =  640, /**< Generic Media Player. */
-    BLE_APPEARANCE_GENERIC_BARCODE_SCANNER             =  704, /**< Generic Barcode Scanner. */
-    BLE_APPEARANCE_GENERIC_THERMOMETER                 =  768, /**< Generic Thermometer. */
-    BLE_APPEARANCE_THERMOMETER_EAR                     =  769, /**< Thermometer: Ear. */
-    BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR           =  832, /**< Generic Heart Rate Sensor. */
-    BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT   =  833, /**< Heart Rate Sensor: Heart Rate Belt. */
-    BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE              =  896, /**< Generic Blood Pressure. */
-    BLE_APPEARANCE_BLOOD_PRESSURE_ARM                  =  897, /**< Blood Pressure: Arm. */
-    BLE_APPEARANCE_BLOOD_PRESSURE_WRIST                =  898, /**< Blood Pressure: Wrist. */
-    BLE_APPEARANCE_GENERIC_HID                         =  960, /**< Human Interface Device (HID). */
-    BLE_APPEARANCE_HID_KEYBOARD                        =  961, /**< Keyboard (HID subtype). */
-    BLE_APPEARANCE_HID_MOUSE                           =  962, /**< Mouse (HID subtype). */
-    BLE_APPEARANCE_HID_JOYSTICK                        =  963, /**< Joystick (HID subtype). */
-    BLE_APPEARANCE_HID_GAMEPAD                         =  964, /**< Gamepad (HID subtype). */
-    BLE_APPEARANCE_HID_DIGITIZERSUBTYPE                =  965, /**< Digitizer Tablet (HID subtype). */
-    BLE_APPEARANCE_HID_CARD_READER                     =  966, /**< Card Reader (HID subtype). */
-    BLE_APPEARANCE_HID_DIGITAL_PEN                     =  967, /**< Digital Pen (HID subtype). */
-    BLE_APPEARANCE_HID_BARCODE                         =  968, /**< Barcode Scanner (HID subtype). */
-    BLE_APPEARANCE_GENERIC_GLUCOSE_METER               = 1024, /**< Generic Glucose Meter. */
-    BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR      = 1088, /**< Generic Running Walking Sensor. */
-    BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE      = 1089, /**< Running Walking Sensor: In-Shoe. */
-    BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE      = 1090, /**< Running Walking Sensor: On-Shoe. */
-    BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP       = 1091, /**< Running Walking Sensor: On-Hip. */
-    BLE_APPEARANCE_GENERIC_CYCLING                     = 1152, /**< Generic Cycling. */
-    BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER            = 1153, /**< Cycling: Cycling Computer. */
-    BLE_APPEARANCE_CYCLING_SPEED_SENSOR                = 1154, /**< Cycling: Speed Sensor. */
-    BLE_APPEARANCE_CYCLING_CADENCE_SENSOR              = 1155, /**< Cycling: Cadence Sensor. */
-    BLE_APPEARANCE_CYCLING_POWER_SENSOR                = 1156, /**< Cycling: Power Sensor. */
-    BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR        = 1157, /**< Cycling: Speed and Cadence Sensor. */
-    BLE_APPEARANCE_GENERIC_PULSE_OXIMETER              = 3136, /**< Generic Pulse Oximeter. */
-    BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP            = 3137, /**< Fingertip (Pulse Oximeter subtype). */
-    BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN           = 3138, /**< Wrist Worn (Pulse Oximeter subtype). */
-    BLE_APPEARANCE_GENERIC_WEIGHT_SCALE                = 3200, /**< Generic Weight Scale. */
-    BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT          = 5184, /**< Generic Outdoor Sports Activity. */
-    BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP         = 5185, /**< Location Display Device (Outdoor Sports Activity subtype). */
-    BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP = 5186, /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */
-    BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD          = 5187, /**< Location Pod (Outdoor Sports Activity subtype). */
-    BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD  = 5188, /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */
-};
-
-
 /*! @brief Error codes for the BLE API. */
 enum ble_error_t {
     BLE_ERROR_NONE                      = 0, /**< No error. */
@@ -119,6 +63,7 @@
     BLE_ERROR_INITIALIZATION_INCOMPLETE = 9,
     BLE_ERROR_ALREADY_INITIALIZED       = 10,
     BLE_ERROR_UNSPECIFIED               = 11, /**< Unknown error. */
+    BLE_ERROR_INTERNAL_STACK_FAILURE    = 12, /**< The platform-specific stack failed */
 };
 
 /** @brief Default MTU size. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ble/deprecate.h	Wed Apr 06 18:40:33 2016 +0100
@@ -0,0 +1,26 @@
+/* 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 __DEPRECATE_H__
+#define __DEPRECATE_H__
+
+#ifdef YOTTA_CFG_MBED_OS
+	#include "compiler-polyfill/attributes.h"
+#else
+	#define __deprecated_message(msg)
+#endif
+
+#endif
\ No newline at end of file
--- a/module.json	Wed Apr 06 18:40:32 2016 +0100
+++ b/module.json	Wed Apr 06 18:40:33 2016 +0100
@@ -1,6 +1,6 @@
 {
   "name": "ble",
-  "version": "2.1.11",
+  "version": "2.5.0",
   "description": "The BLE module offers a high level abstraction for using Bluetooth Low Energy on multiple platforms.",
   "keywords": [
     "Bluetooth",
@@ -23,10 +23,10 @@
   "dependencies": {},
   "targetDependencies": {
     "st-ble-shield": {
-      "x-nucleo-idb0xa1": "ARMmbed/ble-x-nucleo-idb0xa1"
+      "x-nucleo-idb0xa1": "^2.0.0"
     },
     "nrf51822": {
-      "ble-nrf51822": "^2.1.3"
+      "ble-nrf51822": "^2.2.8"
     },
     "cordio": {
       "ble-wicentric": "~0.0.4"
@@ -35,7 +35,8 @@
       "mbed-classic": "~0.0.1"
     },
     "mbed-os": {
-      "mbed-drivers": "*"
+      "mbed-drivers": "*",
+      "compiler-polyfill": "^1.2.1"
     }
   }
 }
\ No newline at end of file
--- a/source/BLE.cpp	Wed Apr 06 18:40:32 2016 +0100
+++ b/source/BLE.cpp	Wed Apr 06 18:40:33 2016 +0100
@@ -131,7 +131,6 @@
 
 ble_error_t BLE::shutdown(void)
 {
-    clearAdvertisingPayload();
     if (!transport) {
         error("bad handle to underlying transport");
     }
--- a/source/DiscoveredCharacteristic.cpp	Wed Apr 06 18:40:32 2016 +0100
+++ b/source/DiscoveredCharacteristic.cpp	Wed Apr 06 18:40:33 2016 +0100
@@ -31,29 +31,29 @@
     return gattc->read(connHandle, valueHandle, offset);
 }
 
-struct OneShotReadCallback { 
-    static void launch(GattClient* client, Gap::Handle_t connHandle, 
-                       GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) { 
+struct OneShotReadCallback {
+    static void launch(GattClient* client, Gap::Handle_t connHandle,
+                       GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) {
         OneShotReadCallback* oneShot = new OneShotReadCallback(client, connHandle, handle, cb);
         oneShot->attach();
         // delete will be made when this callback is called
     }
 
 private:
-    OneShotReadCallback(GattClient* client, Gap::Handle_t connHandle, 
-                        GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) : 
+    OneShotReadCallback(GattClient* client, Gap::Handle_t connHandle,
+                        GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) :
         _client(client),
         _connHandle(connHandle),
-        _handle(handle), 
-        _callback(cb) { } 
+        _handle(handle),
+        _callback(cb) { }
 
-    void attach() { 
+    void attach() {
         _client->onDataRead(makeFunctionPointer(this, &OneShotReadCallback::call));
     }
 
     void call(const GattReadCallbackParams* params) {
         // verifiy that it is the right characteristic on the right connection
-        if (params->connHandle == _connHandle && params->handle == _handle) { 
+        if (params->connHandle == _connHandle && params->handle == _handle) {
             _callback(params);
             _client->onDataRead().detach(makeFunctionPointer(this, &OneShotReadCallback::call));
             delete this;
@@ -68,7 +68,7 @@
 
 ble_error_t DiscoveredCharacteristic::read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const {
     ble_error_t error = read(offset);
-    if (error) { 
+    if (error) {
         return error;
     }
 
@@ -105,29 +105,29 @@
     return gattc->write(GattClient::GATT_OP_WRITE_CMD, connHandle, valueHandle, length, value);
 }
 
-struct OneShotWriteCallback { 
-    static void launch(GattClient* client, Gap::Handle_t connHandle, 
-                       GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) { 
+struct OneShotWriteCallback {
+    static void launch(GattClient* client, Gap::Handle_t connHandle,
+                       GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) {
         OneShotWriteCallback* oneShot = new OneShotWriteCallback(client, connHandle, handle, cb);
         oneShot->attach();
         // delete will be made when this callback is called
     }
 
 private:
-    OneShotWriteCallback(GattClient* client, Gap::Handle_t connHandle, 
-                        GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) : 
+    OneShotWriteCallback(GattClient* client, Gap::Handle_t connHandle,
+                        GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) :
         _client(client),
         _connHandle(connHandle),
-        _handle(handle), 
-        _callback(cb) { } 
+        _handle(handle),
+        _callback(cb) { }
 
-    void attach() { 
+    void attach() {
         _client->onDataWritten(makeFunctionPointer(this, &OneShotWriteCallback::call));
     }
 
     void call(const GattWriteCallbackParams* params) {
         // verifiy that it is the right characteristic on the right connection
-        if (params->connHandle == _connHandle && params->handle == _handle) { 
+        if (params->connHandle == _connHandle && params->handle == _handle) {
             _callback(params);
             _client->onDataWritten().detach(makeFunctionPointer(this, &OneShotWriteCallback::call));
             delete this;
@@ -142,7 +142,7 @@
 
 ble_error_t DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onRead) const {
     ble_error_t error = write(length, value);
-    if (error) { 
+    if (error) {
         return error;
     }
 
@@ -151,8 +151,17 @@
     return error;
 }
 
-ble_error_t
-DiscoveredCharacteristic::discoverDescriptors(DescriptorCallback_t callback, const UUID &matchingUUID) const
-{
-    return BLE_ERROR_NOT_IMPLEMENTED; /* TODO: this needs to be filled in. */
+ble_error_t DiscoveredCharacteristic::discoverDescriptors(
+    const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& onCharacteristicDiscovered, 
+    const CharacteristicDescriptorDiscovery::TerminationCallback_t& onTermination) const {
+
+    if(!gattc) {
+        return BLE_ERROR_INVALID_STATE;
+    }
+
+    ble_error_t err = gattc->discoverCharacteristicDescriptors(
+        *this, onCharacteristicDiscovered, onTermination
+    );
+
+    return err;
 }
\ No newline at end of file