Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: X_NUCLEO_IKS01A2
Revision 0:9c0e0ac79e75, committed 2020-04-29
- Comitter:
- jim_lsj
- Date:
- Wed Apr 29 10:42:44 2020 +0000
- Child:
- 1:b12ac7b02a21
- Commit message:
- 12_1
Changed in this revision
--- /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. + +  + + **figure 1.a** How to start scan using ST BLE Profile 2.0.0 + +  + + **figure 1.b** How to start scan using nRF Master Control Panel 4.0.5 + +1. Find your device; it should be named `HRM`. + +  + + **figure 2.a** Scan results using ST BLE Profile 2.0.0 + +  + + **figure 2.b** Scan results using nRF Master Control Panel 4.0.5 + +1. Establish a connection with your device. + +  + + **figure 3.a** How to establish a connection using ST BLE Profile 2.0.0 + +  + + **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`. + +  + + **figure 4.a** Representation of the Heart Rate service using ST BLE Profile 2.0.0 + +  + + **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. + +  + + **figure 5.a** How to register to notifications using ST BLE Profile 2.0.0 + +  + + **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. + +  + + **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. + +  + + **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";
+ }
+}