Richard Carpenter
/
BLE_HeartRate
test
Revision 0:a1e69a052b91, committed 2020-08-03
- Comitter:
- TRxStudio
- Date:
- Mon Aug 03 22:16:42 2020 +0000
- Commit message:
- test
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.mbed Mon Aug 03 22:16:42 2020 +0000 @@ -0,0 +1,3 @@ +TARGET=NRF51_DK +TOOLCHAIN=GCC_ARM +ROOT=.
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 Mon Aug 03 22:16:42 2020 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#a2ada74770f043aff3e61e29d164a8e78274fcd4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_app.json Mon Aug 03 22:16:42 2020 +0000 @@ -0,0 +1,20 @@ +{ + "target_overrides": { + "K64F": { + "target.components_add": ["BlueNRG_MS"], + "target.features_add": ["BLE"], + "target.extra_labels_add": ["CORDIO"] + }, + "NUCLEO_F401RE": { + "target.components_add": ["BlueNRG_MS"], + "target.features_add": ["BLE"], + "target.extra_labels_add": ["CORDIO"] + }, + "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 Mon Aug 03 22:16:42 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 Mon Aug 03 22:16:42 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/source/main.cpp Mon Aug 03 22:16:42 2020 +0000 @@ -0,0 +1,173 @@ +/* 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/HeartRateService.h" +#include "pretty_printer.h" + +const static char DEVICE_NAME[] = "Heartrate"; + +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_uuid(GattService::UUID_HEART_RATE_SERVICE), + _hr_counter(100), + _hr_service(ble, _hr_counter, HeartRateService::LOCATION_FINGER), + _adv_data_builder(_adv_buffer) { } + + 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_HEART_RATE_SENSOR); + _adv_data_builder.setLocalServiceList(mbed::make_Span(&_hr_uuid, 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. + _hr_counter++; + + // 100 <= HRM bps <=175 + if (_hr_counter == 175) { + _hr_counter = 100; + } + + _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 _hr_uuid; + + uint8_t _hr_counter; + HeartRateService _hr_service; + + 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() +{ + 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 Mon Aug 03 22:16:42 2020 +0000 @@ -0,0 +1,100 @@ +/* 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 failure"); + break; + case BLE_ERROR_NOT_FOUND: + printf("BLE_ERROR_NOT_FOUND"); + break; + default: + printf("Unknown error"); + } + printf("\r\n"); +} + +/** print device address to the terminal */ +inline void print_address(const ble::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*/ + ble::own_address_type_t addr_type; + ble::address_t address; + BLE::Instance().gap().getAddress(addr_type, address); + printf("DEVICE MAC ADDRESS: "); + print_address(address); +} + +inline const char* phy_to_string(ble::phy_t phy) { + switch(phy.value()) { + case ble::phy_t::LE_1M: + return "LE 1M"; + case ble::phy_t::LE_2M: + return "LE 2M"; + case ble::phy_t::LE_CODED: + return "LE coded"; + default: + return "invalid PHY"; + } +}