士鈞 林 / Mbed OS 12_1

Dependencies:   X_NUCLEO_IKS01A2

Files at this revision

API Documentation at this revision

Comitter:
jim_lsj
Date:
Wed Apr 29 10:42:44 2020 +0000
Child:
1:b12ac7b02a21
Commit message:
12_1

Changed in this revision

X_NUCLEO_IKS01A2.lib Show annotated file Show diff for this revision Revisions of this file
img/connection.png Show annotated file Show diff for this revision Revisions of this file
img/connection_ble_profile.png Show annotated file Show diff for this revision Revisions of this file
img/discovery.png Show annotated file Show diff for this revision Revisions of this file
img/discovery_ble_profile.png Show annotated file Show diff for this revision Revisions of this file
img/notifications.png Show annotated file Show diff for this revision Revisions of this file
img/notifications_ble_profile.png Show annotated file Show diff for this revision Revisions of this file
img/register_to_notifications.png Show annotated file Show diff for this revision Revisions of this file
img/register_to_notifications_ble_profile.png Show annotated file Show diff for this revision Revisions of this file
img/scan_result.png Show annotated file Show diff for this revision Revisions of this file
img/scan_result_ble_profile.png Show annotated file Show diff for this revision Revisions of this file
img/start_scan.png Show annotated file Show diff for this revision Revisions of this file
img/start_scan_ble_profile.png Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json 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
readme.md Show annotated file Show diff for this revision Revisions of this file
shields/TARGET_CORDIO_BLUENRG.lib Show annotated file Show diff for this revision Revisions of this file
source/BLEDevice.h Show annotated file Show diff for this revision Revisions of this file
source/BLEDeviceInstanceBase.h Show annotated file Show diff for this revision Revisions of this file
source/ESS.h Show annotated file Show diff for this revision Revisions of this file
source/ESS2.h Show annotated file Show diff for this revision Revisions of this file
source/main.cpp Show annotated file Show diff for this revision Revisions of this file
source/pretty_printer.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/X_NUCLEO_IKS01A2.lib	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/teams/ST/code/X_NUCLEO_IKS01A2/#138a7a28bd21
Binary file img/connection.png has changed
Binary file img/connection_ble_profile.png has changed
Binary file img/discovery.png has changed
Binary file img/discovery_ble_profile.png has changed
Binary file img/notifications.png has changed
Binary file img/notifications_ble_profile.png has changed
Binary file img/register_to_notifications.png has changed
Binary file img/register_to_notifications_ble_profile.png has changed
Binary file img/scan_result.png has changed
Binary file img/scan_result_ble_profile.png has changed
Binary file img/start_scan.png has changed
Binary file img/start_scan_ble_profile.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#565ab149819481224ab43f878c3921b14b11d180
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,22 @@
+{
+    "target_overrides": {
+        "K64F": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "NUCLEO_F401RE": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "DISCO_L475VG_IOT01A": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "NRF52840_DK": {
+            "target.features_add": ["BLE"]
+        },
+        "NRF52_DK": {
+            "target.features_add": ["BLE"]
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/module.json	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,16 @@
+{
+  "name": "ble-heartrate",
+  "version": "0.0.1",
+  "description": "BLE Heartreate example, building with yotta",
+  "licenses": [
+    {
+      "url": "https://spdx.org/licenses/Apache-2.0",
+      "type": "Apache-2.0"
+    }
+  ],
+  "dependencies": {
+    "ble": "^2.0.0"
+  },
+  "targetDependencies": {},
+  "bin": "./source"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.md	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,94 @@
+# BLE Heart Rate Monitor
+
+This application transmits a heart rate value using the [Bluetooth SIG Heart Rate Profile](https://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx). The heart rate value is provided by the application itself, not by a sensor, so that you don't have to get a sensor just to run the example.
+
+Technical details are better presented [in the mbed Classic equivalent of this example](https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/).
+
+# Running the application
+
+## Requirements
+
+To see the heart rate information on your phone, use the BLE Profiles App by ST:
+
+- [ST BLE Profile](https://play.google.com/store/apps/details?id=com.stm.bluetoothlevalidation) for Android.
+
+Alternatively, use a BLE scanner:
+
+- [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android.
+
+- [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone.
+
+Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md).
+
+## Building instructions
+
+Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md).
+
+## Checking for success
+
+**Note:** Screens captures depicted below show what is expected from this example if the scanner used is *ST BLE Profile* version 2.0.0 or *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals.
+
+1. Build the application and install it on your board as explained in the building instructions.
+1. Open the BLE scanner on your phone.
+1. Start a scan.
+
+    ![](img/start_scan_ble_profile.png)
+
+    **figure 1.a** How to start scan using ST BLE Profile 2.0.0
+
+    ![](img/start_scan.png)
+
+    **figure 1.b** How to start scan using nRF Master Control Panel 4.0.5
+
+1. Find your device; it should be named `HRM`.
+
+    ![](img/scan_result_ble_profile.png)
+
+    **figure 2.a** Scan results using ST BLE Profile 2.0.0
+
+    ![](img/scan_result.png)
+
+    **figure 2.b** Scan results using nRF Master Control Panel 4.0.5
+
+1. Establish a connection with your device.
+
+    ![](img/connection_ble_profile.png)
+
+    **figure 3.a**  How to establish a connection using ST BLE Profile 2.0.0
+
+    ![](img/connection.png)
+
+    **figure 3.b**  How to establish a connection using Master Control Panel 4.0.5
+
+1. Discover the services and the characteristics on the device. The *Heart Rate* service has the UUID `0x180D` and includes the *Heart Rate Measurement* characteristic which has the UUID `0x2A37`.
+
+    ![](img/discovery_ble_profile.png)
+
+    **figure 4.a** Representation of the Heart Rate service using ST BLE Profile 2.0.0
+
+    ![](img/discovery.png)
+
+    **figure 4.b** Representation of the Heart Rate service using Master Control Panel 4.0.5
+
+1. Register for the notifications sent by the *Heart Rate Measurement* characteristic.
+
+    ![](img/register_to_notifications_ble_profile.png)
+
+    **figure 5.a** How to register to notifications using ST BLE Profile 2.0.0
+
+    ![](img/register_to_notifications.png)
+
+    **figure 5.b** How to register to notifications using Master Control Panel 4.0.5
+
+
+1. You should see the heart rate value change every half second.<br/>For ST BLE Profile, it begins at 60, goes up to 100 (in steps of 1), resets to 60 and so on.
+
+    ![](img/notifications_ble_profile.png)
+
+    **figure 6.a** Notifications view using ST BLE Profile 2.0.0
+
+    For Master Control Panel, it begins at 100, goes up to 175 (in steps of 1), resets to 100 and so on.
+
+    ![](img/notifications.png)
+
+    **figure 6.b** Notifications view using Master Control Panel 4.0.5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shields/TARGET_CORDIO_BLUENRG.lib	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/cordio-ble-x-nucleo-idb0xa1/#811f3fea7aa8083c0bbf378e1b51a8b131d7efcc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/BLEDevice.h	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,626 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLE_DEVICE__
+#define __BLE_DEVICE__
+
+#include "mbed.h"
+#include "blecommon.h"
+#include "Gap.h"
+#include "GattServer.h"
+#include "BLEDeviceInstanceBase.h"
+
+/**
+ * The base class used to abstract away BLE capable radio transceivers or SOCs,
+ * to enable this BLE API to work with any radio transparently.
+ */
+class BLEDevice
+{
+public:
+    /**
+     * Initialize the BLE controller. This should be called before using
+     * anything else in the BLE_API.
+     */
+    ble_error_t init();
+    ble_error_t reset(void);
+
+    /* GAP specific APIs */
+public:
+    /**
+     * Set the BTLE MAC address and type.
+     * @return
+     */
+    ble_error_t setAddress(Gap::addr_type_t type, const uint8_t address[6]);
+
+    /**
+     * @param[in] advType
+     *              The GAP advertising mode to use for this device. Valid
+     *              values are defined in AdvertisingType:
+     *
+     *              \par ADV_NON_CONNECTABLE_UNDIRECTED
+     *              All connections to the peripheral device will be refused.
+     *
+     *              \par ADV_CONNECTABLE_DIRECTED
+     *              Only connections from a pre-defined central device will be
+     *              accepted.
+     *
+     *              \par ADV_CONNECTABLE_UNDIRECTED
+     *              Any central device can connect to this peripheral.
+     *
+     *              \par ADV_SCANNABLE_UNDIRECTED
+     *              Any central device can connect to this peripheral, and
+     *              the secondary Scan Response payload will be included or
+     *              available to central devices.
+     *
+     *              \par
+     *              See Bluetooth Core Specification 4.0 (Vol. 3), Part C,
+     *              Section 9.3 and Core Specification 4.0 (Vol. 6), Part B,
+     *              Section 2.3.1 for further information on GAP connection
+     *              modes
+     */
+    void        setAdvertisingType(GapAdvertisingParams::AdvertisingType);
+
+    /**
+     * @param[in] interval
+     *              Advertising interval between 0x0020 and 0x4000 in 0.625ms
+     *              units (20ms to 10.24s).  If using non-connectable mode
+     *              (ADV_NON_CONNECTABLE_UNDIRECTED) this min value is
+     *              0x00A0 (100ms). To reduce the likelihood of collisions, the
+     *              link layer perturbs this interval by a pseudo-random delay
+     *              with a range of 0 ms to 10 ms for each advertising event.
+     *
+     *              \par
+     *              Decreasing this value will allow central devices to detect
+     *              your peripheral faster at the expense of more power being
+     *              used by the radio due to the higher data transmit rate.
+     *
+     *              \par
+     *              This field must be set to 0 if connectionMode is equal
+     *              to ADV_CONNECTABLE_DIRECTED
+     *
+     *              \par
+     *              See Bluetooth Core Specification, Vol 3., Part C,
+     *              Appendix A for suggested advertising intervals.
+     */
+    void        setAdvertisingInterval(uint16_t interval);
+
+    /**
+     * @param[in] timeout
+     *              Advertising timeout between 0x1 and 0x3FFF (1 and 16383)
+     *              in seconds.  Enter 0 to disable the advertising timeout.
+     */
+    void        setAdvertisingTimeout(uint16_t timeout);
+
+    /**
+     * Please refer to the APIs above.
+     */
+    void        setAdvertisingParams(const GapAdvertisingParams &advParams);
+
+    /**
+     * This API is typically used as an internal helper to udpate the transport
+     * backend with advertising data before starting to advertise. It may also
+     * be explicity used to dynamically reset the accumulated advertising
+     * payload and scanResponse; to do this, the application can clear and re-
+     * accumulate a new advertising payload (and scanResponse) before using this
+     * API.
+     */
+    ble_error_t setAdvertisingPayload(void);
+
+    /**
+     * Reset any advertising payload prepared from prior calls to
+     * accumulateAdvertisingPayload().
+     */
+    void        clearAdvertisingPayload(void);
+
+    /**
+     * Accumulate an AD structure in the advertising payload. Please note that
+     * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used
+     * as an additional 31 bytes if the advertising payload proves to be too
+     * small.
+     *
+     * @param  flags
+     *         The flags to be added. Multiple flags may be specified in
+     *         combination.
+     */
+    ble_error_t accumulateAdvertisingPayload(uint8_t flags);
+
+    /**
+     * Accumulate an AD structure in the advertising payload. Please note that
+     * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used
+     * as an additional 31 bytes if the advertising payload proves to be too
+     * small.
+     *
+     * @param  app
+     *         The appearance of the peripheral.
+     */
+    ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::Appearance app);
+
+    /**
+     * Accumulate an AD structure in the advertising payload. Please note that
+     * the payload is limited to 31 bytes. The SCAN_RESPONSE message may be used
+     * as an additional 31 bytes if the advertising payload proves to be too
+     * small.
+     *
+     * @param  app
+     *         The max transmit power to be used by the controller. This is
+     *         only a hint.
+     */
+    ble_error_t accumulateAdvertisingPayloadTxPower(int8_t power);
+
+    /**
+     * Accumulate a variable length byte-stream as an AD structure in the
+     * advertising payload. Please note that the payload is limited to 31 bytes.
+     * The SCAN_RESPONSE message may be used as an additional 31 bytes if the
+     * advertising payload proves to be too small.
+     *
+     * @param  type The type which describes the variable length data.
+     * @param  data data bytes.
+     * @param  len  length of data.
+     */
+    ble_error_t accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len);
+
+    /**
+     * Accumulate a variable length byte-stream as an AD structure in the
+     * scanResponse payload.
+     *
+     * @param  type The type which describes the variable length data.
+     * @param  data data bytes.
+     * @param  len  length of data.
+     */
+    ble_error_t accumulateScanResponse(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len);
+
+    /**
+     * Start advertising (GAP Discoverable, Connectable modes, Broadcast
+     * Procedure).
+     */
+    ble_error_t startAdvertising(void);
+
+    /**
+     * Stop advertising (GAP Discoverable, Connectable modes, Broadcast
+     * Procedure).
+     */
+    ble_error_t stopAdvertising(void);
+
+    ble_error_t disconnect(Gap::DisconnectionReason_t reason);
+
+    /* APIs to set GAP callbacks. */
+    void onTimeout(Gap::EventCallback_t timeoutCallback);
+
+    void onConnection(Gap::ConnectionEventCallback_t connectionCallback);
+    /**
+     * Used to setup a callback for GAP disconnection.
+     */
+    void onDisconnection(Gap::DisconnectionEventCallback_t disconnectionCallback);
+
+    /**
+     * Setup a callback for the GATT event DATA_SENT.
+     */
+    void onDataSent(GattServer::ServerEventCallbackWithCount_t callback);
+
+    /**
+     * Setup a callback for when a characteristic has its value updated by a
+     * client.
+     *
+     * @Note: it is possible to chain together multiple onDataWritten callbacks
+     * (potentially from different modules of an application) to receive updates
+     * to characteristics. Many services, such as DFU and UART add their own
+     * onDataWritten callbacks behind the scenes to trap interesting events.
+     *
+     * @Note: it is also possible to setup a callback into a member function of
+     * some object.
+     */
+    void onDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP));
+    template <typename T> void onDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context));
+
+    void onUpdatesEnabled(GattServer::EventCallback_t callback);
+    void onUpdatesDisabled(GattServer::EventCallback_t callback);
+    void onConfirmationReceived(GattServer::EventCallback_t callback);
+
+    /**
+     * Add a service declaration to the local server ATT table. Also add the
+     * characteristics contained within.
+     */
+    ble_error_t addService(GattService &service);
+
+    Gap::GapState_t getGapState(void) const;
+
+    /**
+     * @param[in/out]  lengthP
+     *     input:  Length in bytes to be read,
+     *     output: Total length of attribute value upon successful return.
+     */
+    ble_error_t readCharacteristicValue(uint16_t handle, uint8_t *const buffer, uint16_t *const lengthP);
+
+    /**
+     * @param  localOnly
+     *         Only update the characteristic locally regardless of notify/indicate flags in the CCCD.
+     */
+    ble_error_t updateCharacteristicValue(uint16_t handle, const uint8_t* value, uint16_t size, bool localOnly = false);
+
+    /**
+     * Yield control to the BLE stack or to other tasks waiting for events. This
+     * is a sleep function which will return when there is an application
+     * specific interrupt, but the MCU might wake up several times before
+     * returning (to service the stack). This is not always interchangeable with
+     * WFE().
+     */
+    void waitForEvent(void);
+
+    ble_error_t getPreferredConnectionParams(Gap::ConnectionParams_t *params);
+    ble_error_t setPreferredConnectionParams(const Gap::ConnectionParams_t *params);
+    ble_error_t updateConnectionParams(Gap::Handle_t handle, const Gap::ConnectionParams_t *params);
+
+    /**
+     * This call allows the application to get the BLE stack version information.
+     *
+     * @return  A pointer to a const string representing the version.
+     *          Note: The string is owned by the BLE_API.
+     */
+    const char *getVersion(void);
+
+     /**
+      * Set the device name characteristic in the GAP service.
+      * @param  deviceName The new value for the device-name. This is a UTF-8 encoded, <b>NULL-terminated</b> string.
+      */
+     ble_error_t setDeviceName(const uint8_t *deviceName);
+
+     /**
+      * Get the value of the device name characteristic in the GAP service.
+      * @param[out]    deviceName Pointer to an empty buffer where the UTF-8 *non NULL-
+      *                           terminated* string will be placed. Set this
+      *                           value to NULL in order to obtain the deviceName-length
+      *                           from the 'length' parameter.
+      *
+      * @param[in/out] lengthP    (on input) Length of the buffer pointed to by deviceName;
+      *                           (on output) the complete device name length (without the
+      *                           null terminator).
+      *
+      * @note          If the device name is longer than the size of the supplied buffer,
+      *                length will return the complete device name length,
+      *                and not the number of bytes actually returned in deviceName.
+      *                The application may use this information to retry with a suitable buffer size.
+      *
+      * Sample use:
+      *     uint8_t deviceName[20];
+      *     unsigned length = sizeof(deviceName);
+      *     ble.getDeviceName(deviceName, &length);
+      *     if (length < sizeof(deviceName)) {
+      *         deviceName[length] = 0;
+      *     }
+      *     DEBUG("length: %u, deviceName: %s\r\n", length, deviceName);
+      */
+     ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
+
+     /**
+      * Set the appearance characteristic in the GAP service.
+      * @param[in]  appearance The new value for the device-appearance.
+      */
+     ble_error_t setAppearance(uint16_t appearance);
+
+     /**
+      * Set the appearance characteristic in the GAP service.
+      * @param[out]  appearance The new value for the device-appearance.
+      */
+     ble_error_t getAppearance(uint16_t *appearanceP);
+
+     /**
+      * Set the radio's transmit power.
+      * @param[in] txPower Radio transmit power in dBm.
+      */
+     ble_error_t setTxPower(int8_t txPower);
+
+public:
+    BLEDevice() : transport(createBLEDeviceInstance()), advParams(), advPayload(), scanResponse(), needToSetAdvPayload(true) {
+        advPayload.clear();
+        scanResponse.clear();
+    }
+
+private:
+    BLEDeviceInstanceBase *const transport; /* the device specific backend */
+
+    GapAdvertisingParams advParams;
+    GapAdvertisingData   advPayload;
+    GapAdvertisingData   scanResponse;
+
+    /* Accumulation of AD structures in the advertisement payload should
+     * eventually result in a call to the target's setAdvertisingData() before
+     * the server begins advertising. This flag marks the status of the pending update.*/
+    bool                 needToSetAdvPayload;
+
+    /**
+     * DEPRECATED
+     */
+public:
+    ble_error_t setAdvertisingData(const GapAdvertisingData &ADStructures, const GapAdvertisingData &scanResponse);
+    ble_error_t setAdvertisingData(const GapAdvertisingData &ADStructures);
+
+    ble_error_t startAdvertising(const GapAdvertisingParams &advParams);
+};
+
+/* BLEDevice methods. Most of these simply forward the calls to the underlying
+ * transport.*/
+
+inline ble_error_t
+BLEDevice::reset(void)
+{
+    return transport->reset();
+}
+
+inline ble_error_t
+BLEDevice::setAddress(Gap::addr_type_t type, const uint8_t address[6])
+{
+    return transport->getGap().setAddress(type, address);
+}
+
+inline void
+BLEDevice::setAdvertisingType(GapAdvertisingParams::AdvertisingType advType)
+{
+    advParams.setAdvertisingType(advType);
+}
+
+inline void
+BLEDevice::setAdvertisingInterval(uint16_t interval)
+{
+    advParams.setInterval(interval);
+}
+
+inline void
+BLEDevice::setAdvertisingTimeout(uint16_t timeout)
+{
+    advParams.setTimeout(timeout);
+}
+
+inline void
+BLEDevice::setAdvertisingParams(const GapAdvertisingParams &newAdvParams)
+{
+    advParams = newAdvParams;
+}
+
+inline void
+BLEDevice::clearAdvertisingPayload(void)
+{
+    needToSetAdvPayload = true;
+    advPayload.clear();
+}
+
+inline ble_error_t
+BLEDevice::accumulateAdvertisingPayload(uint8_t flags)
+{
+    needToSetAdvPayload = true;
+    return advPayload.addFlags(flags);
+}
+
+inline ble_error_t
+BLEDevice::accumulateAdvertisingPayload(GapAdvertisingData::Appearance app)
+{
+    needToSetAdvPayload = true;
+    return advPayload.addAppearance(app);
+}
+
+inline ble_error_t
+BLEDevice::accumulateAdvertisingPayloadTxPower(int8_t txPower)
+{
+    needToSetAdvPayload = true;
+    return advPayload.addTxPower(txPower);
+}
+
+inline ble_error_t
+BLEDevice::accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
+{
+    needToSetAdvPayload = true;
+    return advPayload.addData(type, data, len);
+}
+
+inline ble_error_t
+BLEDevice::accumulateScanResponse(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
+{
+    needToSetAdvPayload = true;
+    return scanResponse.addData(type, data, len);
+}
+
+inline ble_error_t
+BLEDevice::setAdvertisingPayload(void) {
+    needToSetAdvPayload = false;
+    return transport->getGap().setAdvertisingData(advPayload, scanResponse);
+}
+
+inline ble_error_t
+BLEDevice::startAdvertising(void)
+{
+    if (needToSetAdvPayload) {
+        ble_error_t rc;
+        if ((rc = setAdvertisingPayload()) != BLE_ERROR_NONE) {
+            return rc;
+        }
+    }
+
+    return transport->getGap().startAdvertising(advParams);
+}
+
+inline ble_error_t
+BLEDevice::stopAdvertising(void)
+{
+    return transport->getGap().stopAdvertising();
+}
+
+inline ble_error_t
+BLEDevice::disconnect(Gap::DisconnectionReason_t reason)
+{
+    return transport->getGap().disconnect(reason);
+}
+
+inline void
+BLEDevice::onTimeout(Gap::EventCallback_t timeoutCallback)
+{
+    transport->getGap().setOnTimeout(timeoutCallback);
+}
+
+inline void
+BLEDevice::onConnection(Gap::ConnectionEventCallback_t connectionCallback)
+{
+    transport->getGap().setOnConnection(connectionCallback);
+}
+
+inline void
+BLEDevice::onDisconnection(Gap::DisconnectionEventCallback_t disconnectionCallback)
+{
+    transport->getGap().setOnDisconnection(disconnectionCallback);
+}
+
+inline void
+BLEDevice::onDataSent(GattServer::ServerEventCallbackWithCount_t callback)
+{
+    transport->getGattServer().setOnDataSent(callback);
+}
+
+inline void
+BLEDevice::onDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP)) {
+    transport->getGattServer().setOnDataWritten(callback);
+}
+
+template <typename T> inline void
+BLEDevice::onDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context)) {
+    transport->getGattServer().setOnDataWritten(objPtr, memberPtr);
+}
+
+
+inline void
+BLEDevice::onUpdatesEnabled(GattServer::EventCallback_t callback)
+{
+    transport->getGattServer().setOnUpdatesEnabled(callback);
+}
+
+inline void
+BLEDevice::onUpdatesDisabled(GattServer::EventCallback_t callback)
+{
+    transport->getGattServer().setOnUpdatesDisabled(callback);
+}
+
+inline void
+BLEDevice::onConfirmationReceived(GattServer::EventCallback_t callback)
+{
+    transport->getGattServer().setOnConfirmationReceived(callback);
+}
+
+inline ble_error_t
+BLEDevice::addService(GattService &service)
+{
+    return transport->getGattServer().addService(service);
+}
+
+inline Gap::GapState_t
+BLEDevice::getGapState(void) const
+{
+    return transport->getGap().getState();
+}
+
+inline ble_error_t BLEDevice::readCharacteristicValue(uint16_t handle, uint8_t *const buffer, uint16_t *const lengthP)
+{
+    return transport->getGattServer().readValue(handle, buffer, lengthP);
+}
+
+inline ble_error_t
+BLEDevice::updateCharacteristicValue(uint16_t handle, const uint8_t* value, uint16_t size, bool localOnly)
+{
+    return transport->getGattServer().updateValue(handle, const_cast<uint8_t *>(value), size, localOnly);
+}
+
+inline void
+BLEDevice::waitForEvent(void)
+{
+    transport->waitForEvent();
+}
+
+inline ble_error_t
+BLEDevice::getPreferredConnectionParams(Gap::ConnectionParams_t *params)
+{
+    return transport->getGap().getPreferredConnectionParams(params);
+}
+
+inline ble_error_t
+BLEDevice::setPreferredConnectionParams(const Gap::ConnectionParams_t *params)
+{
+    return transport->getGap().setPreferredConnectionParams(params);
+}
+
+inline ble_error_t
+BLEDevice::updateConnectionParams(Gap::Handle_t handle, const Gap::ConnectionParams_t *params) {
+    return transport->getGap().updateConnectionParams(handle, params);
+}
+
+inline const char *
+BLEDevice::getVersion(void)
+{
+    return transport->getVersion();
+}
+
+inline ble_error_t
+BLEDevice::setDeviceName(const uint8_t *deviceName)
+{
+    return transport->getGap().setDeviceName(deviceName);
+}
+
+inline ble_error_t
+BLEDevice::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
+{
+    return transport->getGap().getDeviceName(deviceName, lengthP);
+}
+
+inline ble_error_t
+BLEDevice::setAppearance(uint16_t appearance)
+{
+    return transport->getGap().setAppearance(appearance);
+}
+
+inline ble_error_t
+BLEDevice::getAppearance(uint16_t *appearanceP)
+{
+    return transport->getGap().getAppearance(appearanceP);
+}
+
+inline ble_error_t
+BLEDevice::setTxPower(int8_t txPower)
+{
+    return transport->setTxPower(txPower);
+}
+
+/*
+ * ALL OF THE FOLLOWING METHODS ARE DEPRECATED
+ */
+
+inline ble_error_t
+BLEDevice::setAdvertisingData(const GapAdvertisingData &ADStructures, const GapAdvertisingData &scanResponse)
+{
+    needToSetAdvPayload = false;
+    return transport->getGap().setAdvertisingData(ADStructures, scanResponse);
+}
+
+inline ble_error_t
+BLEDevice::setAdvertisingData(const GapAdvertisingData &ADStructures)
+{
+    GapAdvertisingData scanResponse;
+
+    needToSetAdvPayload = false;
+    return transport->getGap().setAdvertisingData(ADStructures, scanResponse);
+}
+
+inline ble_error_t
+BLEDevice::startAdvertising(const GapAdvertisingParams &_advParams)
+{
+    return transport->getGap().startAdvertising(_advParams);
+}
+
+#endif // ifndef __BLE_DEVICE__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/BLEDeviceInstanceBase.h	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,46 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLE_DEVICE_INSTANCE_BASE__
+#define __BLE_DEVICE_INSTANCE_BASE__
+
+/**
+ *  The interface for the transport object to be created by the target library's
+ *  createBLEDeviceInstance().
+ */
+class BLEDeviceInstanceBase
+{
+public:
+    virtual const char *getVersion(void)           = 0;
+    virtual Gap&        getGap()                   = 0;
+    virtual GattServer& getGattServer()            = 0;
+    virtual ble_error_t init(void)                 = 0;
+    virtual ble_error_t reset(void)                = 0;
+    virtual ble_error_t setTxPower(int8_t txPower) = 0;
+    virtual void        waitForEvent(void)         = 0;
+};
+
+/**
+ * BLEDevice uses composition to hide an interface object encapsulating the
+ * backend transport.
+ *
+ * The following API is used to create the singleton interface object. An
+ * implementation for this function must be provided by the device-specific
+ * library, otherwise there will be a linker error.
+ */
+extern BLEDeviceInstanceBase *createBLEDeviceInstance(void);
+
+#endif // ifndef __BLE_DEVICE_INSTANCE_BASE__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/ESS.h	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,82 @@
+/* ARM University Program Microcontroller Library
+ * 
+ * Environmental Sensing Service
+ *
+ * This software is distributed under an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ */
+
+#ifndef __BLE_ENVIRONMENTAL_SENSING_SERVICE_H__
+#define __BLE_ENVIRONMENTAL_SENSING_SERVICE_H__
+
+#include "mbed.h"
+#include "blecommon.h"
+#include "Gap.h"
+#include "GattServer.h"
+#include "BLEDeviceInstanceBase.h"
+
+//#include "BLEDevice.h"
+
+/* Environmental Sensing Service */
+/* Service:  https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.environmental_sensing.xml */
+/* Humidity characteristic: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.humidity.xml */
+/* Temperature: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature.xml */
+
+class EnvironmentalSensingService {
+
+public:
+    /**
+     * Constructor.
+     *
+     * param[in] _ble
+     *               Reference to the underlying BLEDevice.
+     * param[in] humidity percentage (16-bit unsigned, 2 decimals).
+     *               initial value for the humidity value.
+     * param[in] temperature in degrees Celsius (16-bit signed, 2 decimals).
+     *               initial value for the temperature
+     */
+    EnvironmentalSensingService(BLEDevice &_ble, uint16_t humidity, int16_t temperature) :
+        ble(_ble),
+
+                humiditychar(GattCharacteristic::UUID_HUMIDITY_CHAR, (uint8_t *)&humidity,
+                sizeof(uint16_t), sizeof(uint16_t),
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
+
+                temperaturechar(GattCharacteristic::UUID_TEMPERATURE_CHAR, (uint8_t *)&temperature,
+                sizeof(int16_t), sizeof(int16_t),
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)
+                
+
+                {   // Setup Service
+                    
+        GattCharacteristic *charTable[] = {&humiditychar, &temperaturechar, }; // 2 services. humidity and temp
+
+                GattService      EnvironmentalService(0x181A, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+
+        ble.addService(EnvironmentalService);
+    }
+
+
+    /* Set a new 16-bit value for the humidity measurement.  */
+    void updateHumidity(uint16_t humidity) {
+        ble.updateCharacteristicValue(humiditychar.getValueAttribute().getHandle(), (uint8_t *)&humidity, sizeof(uint16_t));
+    }
+
+                 /* Set a new 16-bit value for the temperature measurement.  */
+    void updateTemperature(int16_t temperature) {
+        ble.updateCharacteristicValue(temperaturechar.getValueAttribute().getHandle(), (uint8_t *)&temperature, sizeof(int16_t));
+    }
+
+
+        
+private:
+    BLEDevice                   &ble;
+    GattCharacteristic          humiditychar;
+    GattCharacteristic          temperaturechar;
+
+};
+
+#endif /* #ifndef __BLE_ENVIRONMENTAL_SENSING_SERVICE_H__*/
+
+
+// *******************************ARM University Program Copyright © ARM Ltd 2015*************************************//
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/ESS2.h	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,81 @@
+/* ARM University Program Microcontroller Library
+ * 
+ * Environmental Sensing Service
+ *
+ * This software is distributed under an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ */
+
+#ifndef __BLE_ENVIRONMENTAL_SENSING_SERVICE2_H__
+#define __BLE_ENVIRONMENTAL_SENSING_SERVICE2_H__
+
+#include "mbed.h"
+#include "blecommon.h"
+#include "Gap.h"
+#include "GattServer.h"
+#include "BLEDeviceInstanceBase.h"
+//#include "BLEDevice.h"
+
+/* Environmental Sensing Service */
+/* Service:  https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.environmental_sensing.xml */
+/* True wind direction characteristic: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.true_wind_direction.xml*/
+/* Pressure characteristic: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.pressure.xml */
+
+
+class EnvironmentalSensingService2 {
+
+public:
+    /**
+     * Constructor.
+     *
+     * param[in] _ble
+     *               Reference to the underlying BLEDevice.
+         * param[in] True Wind Direction in degrees (16-bit unsigned, 2 decimals). Wind coming from: 0=North, 90=East, 180=South and 270=West.
+     *               initial value for the temperature
+         * param[in] pressure in Pascals (32-bit unsigned, 1 decimal).
+         *                           initial value for the pressure value.
+     */
+    EnvironmentalSensingService2(BLEDevice &_ble, uint16_t winddirection, uint32_t pressure) :
+        ble(_ble),
+
+
+                
+                winddirectionchar(0x2A71, (uint8_t *)&winddirection,
+                sizeof(uint16_t), sizeof(uint16_t),
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
+                
+                pressurechar(GattCharacteristic::UUID_PRESSURE_CHAR, (uint8_t *)&pressure,
+                sizeof(uint32_t), sizeof(uint32_t),
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)
+                
+                {   // Setup Service
+                    
+
+                GattCharacteristic *charTable[] = {  &winddirectionchar, &pressurechar };
+
+                GattService      EnvironmentalService(0x181A, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+
+        ble.addService(EnvironmentalService);
+    }
+
+
+        /* Set a new 16-bit value for the wind direction measurement.  */
+    void updateWinddirection(uint16_t winddirection) {
+        ble.updateCharacteristicValue(winddirectionchar.getValueAttribute().getHandle(), (uint8_t *)&winddirection, sizeof(uint16_t));
+    }       
+    /* Set a new 32-bit value for the pressure measurement.  */
+    void updatePressure(uint32_t pressure) {
+        ble.updateCharacteristicValue(pressurechar.getValueAttribute().getHandle(), (uint8_t *)&pressure, sizeof(uint32_t));
+    }
+
+        
+private:
+    BLEDevice                   &ble;
+    GattCharacteristic          winddirectionchar;
+    GattCharacteristic          pressurechar;
+};
+
+#endif /* #ifndef __BLE_ENVIRONMENTAL_SENSING_SERVICE2_H__*/
+
+
+// *******************************ARM University Program Copyright © ARM Ltd 2015*************************************//
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.cpp	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,223 @@
+/* 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.
+ */
+
+#include <events/mbed_events.h>
+#include <mbed.h>
+#include "ble/BLE.h"
+#include "ble/gap/Gap.h"
+//#include "ble/services/EnvironmentalSensingService2.h"
+#include "ble/services/BatteryService.h"
+#include "ble/services/HeartRateService.h"
+#include "ble/services/DeviceInformationService.h"
+#include "pretty_printer.h"
+
+//#include "BLEDevice.h"
+#include "blecommon.h"
+#include "Gap.h"
+#include "GattServer.h"
+//#include "BLEDeviceInstanceBase.h"
+
+#include "XNucleoIKS01A2.h"
+#include "ESS.h"
+#include "ESS2.h"
+
+const static char DEVICE_NAME[] = "Heartrate";
+
+
+
+// new code
+static XNucleoIKS01A2 *Sensors = XNucleoIKS01A2::instance(D14, D15, D4, D5);
+float TEMPERATURE_C = 20;
+float HUMIDITY = 50;
+float PRESSURE = 1000;
+float WIND_DIRECTION = 0;
+int16_t MagRaw[3];
+AxesRaw_TypeDef MAGNETIC;
+const static char     DEVICE_NAME[]        = "WEATHER";
+static const uint16_t uuid16_list[]        = {0x181A};
+
+static volatile bool  triggerSensorPolling = false;
+//end
+
+static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE);
+
+class HeartrateDemo : ble::Gap::EventHandler {
+public:
+    HeartrateDemo(BLE &ble, events::EventQueue &event_queue) :
+        _ble(ble),
+        _event_queue(event_queue),
+        _led1(LED1, 1),
+        _connected(false),
+        _hr_counter(100),
+        _bt_service(ble, 25),
+        _hr_service(ble, _hr_counter, HeartRateService::LOCATION_FINGER),
+        _deviceInfo(ble, "ST", "Nucleo", "SN1" ),
+        _adv_data_builder(_adv_buffer),
+        
+        _air (ble, (uint16_t) HUMIDITY, (int16_t) TEMPERATURE_C ),
+        _wind (ble, (uint16_t) WIND_DIRECTION, (uint32_t) PRESSURE)
+        { 
+            //_uuid_list = new UUID(3);
+//            _uuid_list[0] = GattService::UUID_HEART_RATE_SERVICE;
+//            _uuid_list[1] = GattService::UUID_BATTERY_SERVICE;
+//            _uuid_list[2] = GattService::UUID_DEVICE_INFORMATION_SERVICE;
+        }
+    ~HeartrateDemo(){
+        delete [] _uuid_list;
+    }
+
+    void start() {
+        _ble.gap().setEventHandler(this);
+
+        _ble.init(this, &HeartrateDemo::on_init_complete);
+
+        _event_queue.call_every(500, this, &HeartrateDemo::blink);
+        _event_queue.call_every(1000, this, &HeartrateDemo::update_sensor_value);
+
+        _event_queue.dispatch_forever();
+    }
+
+private:
+    /** Callback triggered when the ble initialization process has finished */
+    void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
+        if (params->error != BLE_ERROR_NONE) {
+            printf("Ble initialization failed.");
+            return;
+        }
+
+        print_mac_address();
+
+        start_advertising();
+    }
+
+    void start_advertising() {
+        /* Create advertising parameters and payload */
+
+        ble::AdvertisingParameters adv_parameters(
+            ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
+            ble::adv_interval_t(ble::millisecond_t(1000))
+        );
+
+        _adv_data_builder.setFlags();
+        _adv_data_builder.setAppearance(ble::adv_data_appearance_t::GENERIC_THERMOMETER);
+        _adv_data_builder.setLocalServiceList(mbed::make_Span(&uuid16_list, 1));
+        _adv_data_builder.setName(DEVICE_NAME);
+
+        /* Setup advertising */
+
+        ble_error_t error = _ble.gap().setAdvertisingParameters(
+            ble::LEGACY_ADVERTISING_HANDLE,
+            adv_parameters
+        );
+
+        if (error) {
+            printf("_ble.gap().setAdvertisingParameters() failed\r\n");
+            return;
+        }
+
+        error = _ble.gap().setAdvertisingPayload(
+            ble::LEGACY_ADVERTISING_HANDLE,
+            _adv_data_builder.getAdvertisingData()
+        );
+
+        if (error) {
+            printf("_ble.gap().setAdvertisingPayload() failed\r\n");
+            return;
+        }
+
+        /* Start advertising */
+
+        error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
+
+        if (error) {
+            printf("_ble.gap().startAdvertising() failed\r\n");
+            return;
+        }
+    }
+
+    void update_sensor_value() {
+        if (_connected) {
+            // Do blocking calls or whatever is necessary for sensor polling.
+            // In our case, we simply update the HRM measurement.
+            Sensors->hts221.GetTemperature((float *)&TEMPERATURE_C);
+            Sensors->hts221.GetHumidity((float *)&HUMIDITY);
+            Sensors->lps25h.GetPressure((float *)&PRESSURE);
+            Sensors->lis3mdl.GetAxes((AxesRaw_TypeDef *)&MAGNETIC);
+
+            _hr_service.updateHeartRate(_hr_counter);
+        }
+    }
+
+    void blink(void) {
+        _led1 = !_led1;
+    }
+
+private:
+    /* Event handler */
+
+    void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
+        _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
+        _connected = false;
+    }
+
+    virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) {
+        if (event.getStatus() == BLE_ERROR_NONE) {
+            _connected = true;
+        }
+    }
+
+private:
+    BLE &_ble;
+    events::EventQueue &_event_queue;
+    DigitalOut _led1;
+
+    bool _connected;
+
+    UUID * _uuid_list;
+
+    uint8_t _hr_counter;
+    HeartRateService _hr_service;
+    
+    uint8_t _battery_level;
+    BatteryService _bt_service;
+    
+    ESS _air;
+    ESS2 _wind;
+
+    
+    DeviceInformationService _deviceInfo;    
+
+    uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
+    ble::AdvertisingDataBuilder _adv_data_builder;
+};
+
+/** Schedule processing of events from the BLE middleware in the event queue. */
+void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
+    event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
+}
+
+int main()
+{
+    static XNucleoIKS01A2 *Sensors = XNucleoIKS01A2::instance(D14, D15, D4, D5);
+    BLE &ble = BLE::Instance();
+    ble.onEventsToProcess(schedule_ble_events);
+
+    HeartrateDemo demo(ble, event_queue);
+    demo.start();
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/pretty_printer.h	Wed Apr 29 10:42:44 2020 +0000
@@ -0,0 +1,95 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mbed.h>
+#include "ble/BLE.h"
+
+inline void print_error(ble_error_t error, const char* msg)
+{
+    printf("%s: ", msg);
+    switch(error) {
+        case BLE_ERROR_NONE:
+            printf("BLE_ERROR_NONE: No error");
+            break;
+        case BLE_ERROR_BUFFER_OVERFLOW:
+            printf("BLE_ERROR_BUFFER_OVERFLOW: The requested action would cause a buffer overflow and has been aborted");
+            break;
+        case BLE_ERROR_NOT_IMPLEMENTED:
+            printf("BLE_ERROR_NOT_IMPLEMENTED: Requested a feature that isn't yet implement or isn't supported by the target HW");
+            break;
+        case BLE_ERROR_PARAM_OUT_OF_RANGE:
+            printf("BLE_ERROR_PARAM_OUT_OF_RANGE: One of the supplied parameters is outside the valid range");
+            break;
+        case BLE_ERROR_INVALID_PARAM:
+            printf("BLE_ERROR_INVALID_PARAM: One of the supplied parameters is invalid");
+            break;
+        case BLE_STACK_BUSY:
+            printf("BLE_STACK_BUSY: The stack is busy");
+            break;
+        case BLE_ERROR_INVALID_STATE:
+            printf("BLE_ERROR_INVALID_STATE: Invalid state");
+            break;
+        case BLE_ERROR_NO_MEM:
+            printf("BLE_ERROR_NO_MEM: Out of Memory");
+            break;
+        case BLE_ERROR_OPERATION_NOT_PERMITTED:
+            printf("BLE_ERROR_OPERATION_NOT_PERMITTED");
+            break;
+        case BLE_ERROR_INITIALIZATION_INCOMPLETE:
+            printf("BLE_ERROR_INITIALIZATION_INCOMPLETE");
+            break;
+        case BLE_ERROR_ALREADY_INITIALIZED:
+            printf("BLE_ERROR_ALREADY_INITIALIZED");
+            break;
+        case BLE_ERROR_UNSPECIFIED:
+            printf("BLE_ERROR_UNSPECIFIED: Unknown error");
+            break;
+        case BLE_ERROR_INTERNAL_STACK_FAILURE:
+            printf("BLE_ERROR_INTERNAL_STACK_FAILURE: internal stack faillure");
+            break;
+    }
+    printf("\r\n");
+}
+
+/** print device address to the terminal */
+inline void print_address(const Gap::Address_t &addr)
+{
+    printf("%02x:%02x:%02x:%02x:%02x:%02x\r\n",
+           addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
+}
+
+inline void print_mac_address()
+{
+    /* Print out device MAC address to the console*/
+    Gap::AddressType_t addr_type;
+    Gap::Address_t address;
+    BLE::Instance().gap().getAddress(&addr_type, address);
+    printf("DEVICE MAC ADDRESS: ");
+    print_address(address);
+}
+
+inline const char* phy_to_string(Gap::Phy_t phy) {
+    switch(phy.value()) {
+        case Gap::Phy_t::LE_1M:
+            return "LE 1M";
+        case Gap::Phy_t::LE_2M:
+            return "LE 2M";
+        case Gap::Phy_t::LE_CODED:
+            return "LE coded";
+        default:
+            return "invalid PHY";
+    }
+}