├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── build_examples.yml │ └── run_conditional_ble_feature_compilation.yml ├── .gitignore ├── BLE_Advertising ├── CMakeLists.txt ├── img │ ├── scan_result.png │ └── start_scan.png ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json ├── readme.md └── source │ └── main.cpp ├── BLE_GAP ├── CMakeLists.txt ├── README.md ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json └── source │ └── main.cpp ├── BLE_GattClient_CharacteristicUpdates ├── CMakeLists.txt ├── README.md ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json └── source │ └── main.cpp ├── BLE_GattClient_CharacteristicWrite ├── CMakeLists.txt ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json ├── readme.md └── source │ └── main.cpp ├── BLE_GattServer_AddService ├── CMakeLists.txt ├── img │ ├── connection.png │ ├── connection_ble_profile.png │ ├── discovery.png │ ├── discovery_ble_profile.png │ ├── notifications.png │ ├── notifications_ble_profile.png │ ├── register_to_notifications.png │ ├── register_to_notifications_ble_profile.png │ ├── scan_result.png │ ├── scan_result_ble_profile.png │ ├── start_scan.png │ └── start_scan_ble_profile.png ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json ├── readme.md └── source │ └── main.cpp ├── BLE_GattServer_CharacteristicUpdates ├── CMakeLists.txt ├── README.md ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json └── source │ └── main.cpp ├── BLE_GattServer_CharacteristicWrite ├── CMakeLists.txt ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json ├── readme.md └── source │ └── main.cpp ├── BLE_GattServer_ExperimentalServices ├── CMakeLists.txt ├── README.md ├── img │ ├── connect.png │ ├── interact_alert_level.png │ ├── interact_current_time.png │ ├── read_alert_level.png │ ├── read_current_time.png │ ├── select_cts.png │ ├── select_lls.png │ ├── write_alert_level.png │ └── write_current_time.png ├── mbed-os-ble-utils.lib ├── mbed-os-experimental-ble-services.lib ├── mbed-os.lib ├── mbed_app.json └── source │ └── main.cpp ├── BLE_PeriodicAdvertising ├── CMakeLists.txt ├── README.md ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json └── source │ └── main.cpp ├── BLE_SecurityAndPrivacy ├── CMakeLists.txt ├── README.md ├── mbed-os-ble-utils.lib ├── mbed-os.lib ├── mbed_app.json └── source │ └── main.cpp ├── BLE_SupportedFeatures ├── CMakeLists.txt ├── mbed-os.lib ├── mbed_app.json ├── readme.md └── source │ └── main.cpp ├── CONTRIBUTING.md ├── Jenkinsfile ├── LICENSE ├── README.md └── resources ├── official_armmbed_example_badge.png └── test_configs ├── mbed_app_features_00.json ├── mbed_app_features_01.json ├── mbed_app_features_02.json ├── mbed_app_features_03.json ├── mbed_app_features_04.json ├── mbed_app_features_05.json ├── mbed_app_features_06.json ├── mbed_app_features_07.json ├── mbed_app_features_08.json ├── mbed_app_features_09.json ├── mbed_app_features_10.json ├── mbed_app_features_11.json ├── mbed_app_features_12.json └── mbed_app_features_13.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'type: bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Description of defect 11 | 12 | 16 | 17 | #### Target(s) and toolchain(s) (name and version) displaying this defect ? 18 | 19 | 20 | #### What version of the example and mbed-os are you using (tag or sha) ? 21 | 22 | 26 | 27 | #### How is this defect reproduced ? 28 | 29 | #### Please attach a file containing the log with traces enabled. 30 | 31 | 44 | -------------------------------------------------------------------------------- /.github/workflows/build_examples.yml: -------------------------------------------------------------------------------- 1 | name: Build examples 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '0 1 * * 6' 6 | pull_request: 7 | jobs: 8 | run-conditional-feature-compilation-test: 9 | name: Build BLE examples 10 | runs-on: ubuntu-latest 11 | container: mbedos/mbed-os-env:latest 12 | strategy: 13 | matrix: 14 | MBED_TARGET: ["DISCO_L475VG_IOT01A", "NRF52840_DK"] 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | 19 | - name: Deploy 20 | run: | 21 | git clone https://github.com/ARMmbed/mbed-os.git 22 | for i in BLE_* ; do cd $i ; mbed config root . ; rm -rf mbed-os ; ln -s $PWD/../mbed-os mbed-os ; mbed update ; cd .. ; done 23 | 24 | - name: Build mbed-cli v1 25 | run: | 26 | for i in BLE_* ; do cd $i ; mbed compile -t GCC_ARM -m ${{ matrix.MBED_TARGET }} || exit 1 ; cd .. ; done 27 | 28 | - name: Build cmake 29 | run: | 30 | python3 -m pip install mbed-tools --upgrade # remove after docker image is updated to contain new tools 31 | for i in BLE_* ; do cd $i ; mbed-tools compile -t GCC_ARM -m ${{ matrix.MBED_TARGET }} || exit 1 ; cd .. ; done 32 | -------------------------------------------------------------------------------- /.github/workflows/run_conditional_ble_feature_compilation.yml: -------------------------------------------------------------------------------- 1 | name: run conditional BLE feature compilation 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '0 1 * * 6' 6 | jobs: 7 | run-conditional-feature-compilation-test: 8 | name: Conditional BLE features compilation tested 9 | runs-on: ubuntu-latest 10 | container: mbedos/mbed-os-env:latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | 15 | - name: Build 16 | run: | 17 | cd BLE_SupportedFeatures 18 | mbed deploy 19 | for f in ../resources/test_configs/*; do 20 | echo "Configuration file ${f}: " 21 | echo "-------------------------------------------------------------------------" 22 | cat "${f}" 23 | echo "-------------------------------------------------------------------------" 24 | mbed compile -t GCC_ARM -m NRF52840_DK --app-config "${f}" 25 | done 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | 24 | # Executables 25 | *.exe 26 | *.out 27 | *.app 28 | 29 | # clion 30 | .idea/ 31 | cmake-build-*/ 32 | 33 | # exporters 34 | GettingStarted.html 35 | 36 | # mbed build system 37 | mbed-os-experimental-ble-services/ 38 | mbed-os-ble-utils/ 39 | mbed-os/ 40 | mbed_settings.py 41 | mbed_config.h 42 | *.pyc 43 | BUILD/ 44 | cmake_build/ 45 | .mbedls* 46 | 47 | -------------------------------------------------------------------------------- /BLE_Advertising/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_Advertising) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_Advertising/img/scan_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_Advertising/img/scan_result.png -------------------------------------------------------------------------------- /BLE_Advertising/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_Advertising/img/start_scan.png -------------------------------------------------------------------------------- /BLE_Advertising/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_Advertising/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_Advertising/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_Advertising/readme.md: -------------------------------------------------------------------------------- 1 | This example shows how to advertise a value of battery service data. The battery value is simulated. 2 | The battery level is a percentage, with 100% being a fully charged battery and 0% being a fully drained battery. 3 | The level starts at 50% and drains every second second, until it hits 10% when it jumps to 100% and continues draining. 4 | 5 | # Running the application 6 | 7 | ## Requirements 8 | 9 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 10 | 11 | ## Building instructions 12 | 13 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 14 | 15 | ## Checking for success 16 | 17 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Connect for Mobile* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Connect for Mobile. Alternative scanners may require reference to their manuals. 18 | 19 | 1. Build the application and install it on your board as explained in the building instructions. 20 | 1. Open the BLE scanner on your phone. 21 | 1. Start a scan. 22 | 23 | ![](img/start_scan.png) 24 | 25 | **figure 1** How to start scan using nRF Connect for Mobile 4.0.5 26 | 27 | 1. Find your device; it should be named `BATTERY`. 28 | 29 | ![](img/scan_result.png) 30 | 31 | **figure 2** Scan results using nRF Connect for Mobile 4.0.5 32 | 33 | 1. Click on the entry to see the payload details 34 | 35 | 36 | If you can see the battery level, and if its value is changing, the application is working properly. 37 | 38 | -------------------------------------------------------------------------------- /BLE_Advertising/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2019 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "ble/BLE.h" 19 | #include "ble/Gap.h" 20 | #include "pretty_printer.h" 21 | #include "mbed-trace/mbed_trace.h" 22 | 23 | const static char DEVICE_NAME[] = "BATTERY"; 24 | 25 | using namespace std::literals::chrono_literals; 26 | 27 | static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); 28 | 29 | class BatteryDemo : ble::Gap::EventHandler { 30 | public: 31 | BatteryDemo(BLE &ble, events::EventQueue &event_queue) : 32 | _ble(ble), 33 | _event_queue(event_queue), 34 | _battery_level(50), 35 | _adv_data_builder(_adv_buffer) 36 | { 37 | } 38 | 39 | void start() 40 | { 41 | /* mbed will call on_init_complete when when ble is ready */ 42 | _ble.init(this, &BatteryDemo::on_init_complete); 43 | 44 | /* this will never return */ 45 | _event_queue.dispatch_forever(); 46 | } 47 | 48 | private: 49 | /** Callback triggered when the ble initialization process has finished */ 50 | void on_init_complete(BLE::InitializationCompleteCallbackContext *params) 51 | { 52 | if (params->error != BLE_ERROR_NONE) { 53 | print_error(params->error, "Ble initialization failed."); 54 | return; 55 | } 56 | 57 | print_mac_address(); 58 | 59 | start_advertising(); 60 | } 61 | 62 | void start_advertising() 63 | { 64 | /* create advertising parameters and payload */ 65 | 66 | ble::AdvertisingParameters adv_parameters( 67 | /* you cannot connect to this device, you can only read its advertising data, 68 | * scannable means that the device has extra advertising data that the peer can receive if it 69 | * "scans" it which means it is using active scanning (it sends a scan request) */ 70 | ble::advertising_type_t::SCANNABLE_UNDIRECTED, 71 | ble::adv_interval_t(ble::millisecond_t(1000)) 72 | ); 73 | 74 | /* when advertising you can optionally add extra data that is only sent 75 | * if the central requests it by doing active scanning (sending scan requests), 76 | * in this example we set this payload first because we want to later reuse 77 | * the same _adv_data_builder builder for payload updates */ 78 | 79 | const uint8_t _vendor_specific_data[4] = { 0xAD, 0xDE, 0xBE, 0xEF }; 80 | _adv_data_builder.setManufacturerSpecificData(_vendor_specific_data); 81 | 82 | _ble.gap().setAdvertisingScanResponse( 83 | ble::LEGACY_ADVERTISING_HANDLE, 84 | _adv_data_builder.getAdvertisingData() 85 | ); 86 | 87 | /* now we set the advertising payload that gets sent during advertising without any scan requests */ 88 | 89 | _adv_data_builder.clear(); 90 | _adv_data_builder.setFlags(); 91 | _adv_data_builder.setName(DEVICE_NAME); 92 | 93 | /* we add the battery level as part of the payload so it's visible to any device that scans, 94 | * this part of the payload will be updated periodically without affecting the rest of the payload */ 95 | _adv_data_builder.setServiceData(GattService::UUID_BATTERY_SERVICE, {&_battery_level, 1}); 96 | 97 | /* setup advertising */ 98 | 99 | ble_error_t error = _ble.gap().setAdvertisingParameters( 100 | ble::LEGACY_ADVERTISING_HANDLE, 101 | adv_parameters 102 | ); 103 | 104 | if (error) { 105 | print_error(error, "_ble.gap().setAdvertisingParameters() failed"); 106 | return; 107 | } 108 | 109 | error = _ble.gap().setAdvertisingPayload( 110 | ble::LEGACY_ADVERTISING_HANDLE, 111 | _adv_data_builder.getAdvertisingData() 112 | ); 113 | 114 | if (error) { 115 | print_error(error, "_ble.gap().setAdvertisingPayload() failed"); 116 | return; 117 | } 118 | 119 | /* start advertising */ 120 | 121 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 122 | 123 | if (error) { 124 | print_error(error, "_ble.gap().startAdvertising() failed"); 125 | return; 126 | } 127 | 128 | /* we simulate battery discharging by updating it every second */ 129 | _event_queue.call_every( 130 | 1000ms, 131 | [this]() { 132 | update_battery_level(); 133 | } 134 | ); 135 | } 136 | 137 | void update_battery_level() 138 | { 139 | if (_battery_level-- == 10) { 140 | _battery_level = 100; 141 | } 142 | 143 | /* update the payload with the new value of the bettery level, the rest of the payload remains the same */ 144 | ble_error_t error = _adv_data_builder.setServiceData(GattService::UUID_BATTERY_SERVICE, make_Span(&_battery_level, 1)); 145 | 146 | if (error) { 147 | print_error(error, "_adv_data_builder.setServiceData() failed"); 148 | return; 149 | } 150 | 151 | /* set the new payload, we don't need to stop advertising */ 152 | error = _ble.gap().setAdvertisingPayload( 153 | ble::LEGACY_ADVERTISING_HANDLE, 154 | _adv_data_builder.getAdvertisingData() 155 | ); 156 | 157 | if (error) { 158 | print_error(error, "_ble.gap().setAdvertisingPayload() failed"); 159 | return; 160 | } 161 | } 162 | 163 | private: 164 | BLE &_ble; 165 | events::EventQueue &_event_queue; 166 | 167 | uint8_t _battery_level; 168 | 169 | uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 170 | ble::AdvertisingDataBuilder _adv_data_builder; 171 | }; 172 | 173 | /* Schedule processing of events from the BLE middleware in the event queue. */ 174 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 175 | { 176 | event_queue.call(Callback(&context->ble, &BLE::processEvents)); 177 | } 178 | 179 | int main() 180 | { 181 | mbed_trace_init(); 182 | 183 | BLE &ble = BLE::Instance(); 184 | ble.onEventsToProcess(schedule_ble_events); 185 | 186 | BatteryDemo demo(ble, event_queue); 187 | demo.start(); 188 | 189 | return 0; 190 | } 191 | -------------------------------------------------------------------------------- /BLE_GAP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GAP) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_GAP/README.md: -------------------------------------------------------------------------------- 1 | # GAP - Advertising, Scanning, Connecting 2 | 3 | Demo of the GAP profile. It shows advertising, scanning and connecting. The demo will cycle through several modes 4 | and print over the serial connection information about current activity. 5 | 6 | # Running the application 7 | 8 | ## Requirements 9 | 10 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 11 | 12 | - [nRF Connect for Mobile](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 13 | 14 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 15 | 16 | Information about activity is printed over the serial connection - please have a client open. You may use: 17 | 18 | - [Tera Term](https://ttssh2.osdn.jp/index.html.en) 19 | 20 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 21 | 22 | ## Building instructions 23 | 24 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 25 | -------------------------------------------------------------------------------- /BLE_GAP/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GAP/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GAP/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicUpdates/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GattClient_CharacteristicUpdates) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicUpdates/README.md: -------------------------------------------------------------------------------- 1 | # BLE Gatt Client example of characteristic and service discovery 2 | 3 | This application demonstrates detailed use of the `GattClient` APIs. 4 | 5 | When the application is started it advertises itself to its environment with the device name "GattClient" 6 | and also tries to connect to any device with the name "GattServer". Once connection has been achieved 7 | it will start a discovery of the GATT server exposed by the peer. 8 | 9 | After the discovery, this application reads the value of the characteristics discovered and subscribes 10 | to the characteristics emitting notifications or indications. 11 | 12 | The device prints the value of any indication or notification received from the peer's GATT Server. 13 | 14 | # Running the application 15 | 16 | ## Requirements 17 | 18 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 19 | 20 | ## Building instructions 21 | 22 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 23 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicUpdates/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicUpdates/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicUpdates/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicUpdates/source/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* mbed Microcontroller Library 3 | * Copyright (c) 2006-2019 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "events/EventQueue.h" 19 | #include "platform/NonCopyable.h" 20 | 21 | #include "ble/GattClient.h" 22 | 23 | #include "gatt_client_process.h" 24 | #include "mbed-trace/mbed_trace.h" 25 | 26 | /** 27 | * Handle discovery of the GATT server. 28 | * 29 | * First the GATT server is discovered in its entirety then each readable 30 | * characteristic is read and the client register to characteristic 31 | * notifications or indication when available. The client report server 32 | * indications and notification until the connection end. 33 | */ 34 | class GattClientDemo : private mbed::NonCopyable, public GattClient::EventHandler 35 | { 36 | // Internal typedef to this class type. 37 | // It is used as a shorthand to pass member function as callbacks. 38 | typedef GattClientDemo Self; 39 | 40 | typedef CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t DiscoveryCallbackParams_t; 41 | typedef CharacteristicDescriptorDiscovery::TerminationCallbackParams_t TerminationCallbackParams_t; 42 | typedef DiscoveredCharacteristic::Properties_t Properties_t; 43 | 44 | public: 45 | 46 | /** 47 | * Construct an empty client process. 48 | * 49 | * The function start() shall be called to initiate the discovery process. 50 | */ 51 | GattClientDemo() { } 52 | 53 | ~GattClientDemo() 54 | { 55 | stop(); 56 | } 57 | 58 | void start(BLE &ble, events::EventQueue &event_queue) 59 | { 60 | _ble = &ble; 61 | _event_queue = &event_queue; 62 | _client = &_ble->gattClient(); 63 | } 64 | 65 | /** 66 | * Start the discovery process. 67 | * 68 | * @param[in] client The GattClient instance which will discover the distant 69 | * GATT server. 70 | * @param[in] connection_handle Reference of the connection to the GATT 71 | * server which will be discovered. 72 | */ 73 | void start_discovery(BLE &ble_interface, events::EventQueue &event_queue, const ble::ConnectionCompleteEvent &event) 74 | { 75 | _connection_handle = event.getConnectionHandle(); 76 | 77 | // setup the event handlers called during the process 78 | _client->onDataWritten().add(as_cb(&Self::when_descriptor_written)); 79 | _client->onHVX().add(as_cb(&Self::when_characteristic_changed)); 80 | 81 | // The discovery process will invoke when_service_discovered when a 82 | // service is discovered, when_characteristic_discovered when a 83 | // characteristic is discovered and when_service_discovery_ends once the 84 | // discovery process has ended. 85 | _client->onServiceDiscoveryTermination(as_cb(&Self::when_service_discovery_ends)); 86 | ble_error_t error = _client->launchServiceDiscovery( 87 | _connection_handle, 88 | as_cb(&Self::when_service_discovered), 89 | as_cb(&Self::when_characteristic_discovered) 90 | ); 91 | 92 | if (error) { 93 | printf("Error %u returned by _client->launchServiceDiscovery.\r\n", error); 94 | return; 95 | } 96 | 97 | // register as a handler for GattClient events 98 | _client->setEventHandler(this); 99 | 100 | // this might not result in a new value but if it does we will be informed through 101 | // an call in the event handler we just registered 102 | _client->negotiateAttMtu(_connection_handle); 103 | 104 | printf("Client process started: initiate service discovery.\r\n"); 105 | } 106 | 107 | /** 108 | * Stop the discovery process and clean the instance. 109 | */ 110 | void stop() 111 | { 112 | if (!_client) { 113 | return; 114 | } 115 | 116 | // unregister event handlers 117 | _client->onDataWritten().detach(as_cb(&Self::when_descriptor_written)); 118 | _client->onHVX().detach(as_cb(&Self::when_characteristic_changed)); 119 | _client->onServiceDiscoveryTermination(nullptr); 120 | 121 | // remove discovered characteristics 122 | clear_characteristics(); 123 | 124 | // clean up the instance 125 | _connection_handle = 0; 126 | _characteristics = nullptr; 127 | _it = nullptr; 128 | _descriptor_handle = 0; 129 | 130 | printf("Client process stopped.\r\n"); 131 | } 132 | 133 | private: 134 | /** 135 | * Implementation of GattClient::EventHandler::onAttMtuChange event 136 | */ 137 | virtual void onAttMtuChange( 138 | ble::connection_handle_t connectionHandle, 139 | uint16_t attMtuSize 140 | ) 141 | { 142 | printf( 143 | "ATT_MTU changed on the connection %d to a new value of %d.\r\n", 144 | connectionHandle, 145 | attMtuSize 146 | /* maximum size of an attribute written in a single operation is one less */ 147 | ); 148 | } 149 | 150 | private: 151 | //////////////////////////////////////////////////////////////////////////////// 152 | // Service and characteristic discovery process. 153 | 154 | /** 155 | * Handle services discovered. 156 | * 157 | * The GattClient invokes this function when a service has been discovered. 158 | * 159 | * @see GattClient::launchServiceDiscovery 160 | */ 161 | void when_service_discovered(const DiscoveredService *discovered_service) 162 | { 163 | // print information of the service discovered 164 | printf("Service discovered: value = "); 165 | print_uuid(discovered_service->getUUID()); 166 | printf(", start = %u, end = %u.\r\n", 167 | discovered_service->getStartHandle(), 168 | discovered_service->getEndHandle() 169 | ); 170 | } 171 | 172 | /** 173 | * Handle characteristics discovered. 174 | * 175 | * The GattClient invoke this function when a characteristic has been 176 | * discovered. 177 | * 178 | * @see GattClient::launchServiceDiscovery 179 | */ 180 | void when_characteristic_discovered(const DiscoveredCharacteristic *discovered_characteristic) 181 | { 182 | // print characteristics properties 183 | printf("\tCharacteristic discovered: uuid = "); 184 | print_uuid(discovered_characteristic->getUUID()); 185 | printf(", properties = "); 186 | print_properties(discovered_characteristic->getProperties()); 187 | printf( 188 | ", decl handle = %u, value handle = %u, last handle = %u.\r\n", 189 | discovered_characteristic->getDeclHandle(), 190 | discovered_characteristic->getValueHandle(), 191 | discovered_characteristic->getLastHandle() 192 | ); 193 | 194 | // add the characteristic into the list of discovered characteristics 195 | bool success = add_characteristic(discovered_characteristic); 196 | if (!success) { 197 | printf("Error: memory allocation failure while adding the discovered characteristic.\r\n"); 198 | _client->terminateServiceDiscovery(); 199 | stop(); 200 | return; 201 | } 202 | } 203 | 204 | /** 205 | * Handle termination of the service and characteristic discovery process. 206 | * 207 | * The GattClient invokes this function when the service and characteristic 208 | * discovery process ends. 209 | * 210 | * @see GattClient::onServiceDiscoveryTermination 211 | */ 212 | void when_service_discovery_ends(ble::connection_handle_t connection_handle) 213 | { 214 | if (!_characteristics) { 215 | printf("No characteristics discovered, end of the process.\r\n"); 216 | return; 217 | } 218 | 219 | printf("All services and characteristics discovered, process them.\r\n"); 220 | 221 | // reset iterator and start processing characteristics in order 222 | _it = nullptr; 223 | _event_queue->call(mbed::callback(this, &Self::process_next_characteristic)); 224 | } 225 | 226 | //////////////////////////////////////////////////////////////////////////////// 227 | // Processing of characteristics based on their properties. 228 | 229 | /** 230 | * Process the characteristics discovered. 231 | * 232 | * - If the characteristic is readable then read its value and print it. Then 233 | * - If the characteristic can emit notification or indication then discover 234 | * the characteristic CCCD and subscribe to the server initiated event. 235 | * - Otherwise skip the characteristic processing. 236 | */ 237 | void process_next_characteristic(void) 238 | { 239 | if (!_it) { 240 | _it = _characteristics; 241 | } else { 242 | _it = _it->next; 243 | } 244 | 245 | while (_it) { 246 | Properties_t properties = _it->value.getProperties(); 247 | 248 | if (properties.read()) { 249 | read_characteristic(_it->value); 250 | return; 251 | } else if(properties.notify() || properties.indicate()) { 252 | discover_descriptors(_it->value); 253 | return; 254 | } else { 255 | printf( 256 | "Skip processing of characteristic %u\r\n", 257 | _it->value.getValueHandle() 258 | ); 259 | _it = _it->next; 260 | } 261 | } 262 | 263 | printf("All characteristics discovered have been processed.\r\n"); 264 | } 265 | 266 | /** 267 | * Initate the read of the characteristic in input. 268 | * 269 | * The completion of the operation will happens in when_characteristic_read() 270 | */ 271 | void read_characteristic(const DiscoveredCharacteristic &characteristic) 272 | { 273 | printf("Initiating read at %u.\r\n", characteristic.getValueHandle()); 274 | ble_error_t error = characteristic.read(0, as_cb(&Self::when_characteristic_read)); 275 | 276 | if (error) { 277 | printf( 278 | "Error: cannot initiate read at %u due to %u\r\n", 279 | characteristic.getValueHandle(), error 280 | ); 281 | stop(); 282 | } 283 | } 284 | 285 | /** 286 | * Handle the reception of a read response. 287 | * 288 | * If the characteristic can emit notification or indication then start the 289 | * discovery of the the characteristic descriptors then subscribe to the 290 | * server initiated event by writing the CCCD discovered. Otherwise start 291 | * the processing of the next characteristic discovered in the server. 292 | */ 293 | void when_characteristic_read(const GattReadCallbackParams *read_event) 294 | { 295 | printf("\tCharacteristic value at %u equal to: ", read_event->handle); 296 | for (size_t i = 0; i < read_event->len; ++i) { 297 | printf("0x%02X ", read_event->data[i]); 298 | } 299 | printf(".\r\n"); 300 | 301 | Properties_t properties = _it->value.getProperties(); 302 | 303 | if(properties.notify() || properties.indicate()) { 304 | discover_descriptors(_it->value); 305 | } else { 306 | process_next_characteristic(); 307 | } 308 | } 309 | 310 | /** 311 | * Initiate the discovery of the descriptors of the characteristic in input. 312 | * 313 | * When a descriptor is discovered, the function when_descriptor_discovered 314 | * is invoked. 315 | */ 316 | void discover_descriptors(const DiscoveredCharacteristic &characteristic) 317 | { 318 | printf("Initiating descriptor discovery of %u.\r\n", characteristic.getValueHandle()); 319 | 320 | _descriptor_handle = 0; 321 | ble_error_t error = characteristic.discoverDescriptors( 322 | as_cb(&Self::when_descriptor_discovered), 323 | as_cb(&Self::when_descriptor_discovery_ends) 324 | ); 325 | 326 | if (error) { 327 | printf( 328 | "Error: cannot initiate discovery of %04X due to %u.\r\n", 329 | characteristic.getValueHandle(), error 330 | ); 331 | stop(); 332 | } 333 | } 334 | 335 | /** 336 | * Handle the discovery of the characteristic descriptors. 337 | * 338 | * If the descriptor found is a CCCD then stop the discovery. Once the 339 | * process has ended subscribe to server initiated events by writing the 340 | * value of the CCCD. 341 | */ 342 | void when_descriptor_discovered(const DiscoveryCallbackParams_t* event) 343 | { 344 | printf("\tDescriptor discovered at %u, UUID: ", event->descriptor.getAttributeHandle()); 345 | print_uuid(event->descriptor.getUUID()); 346 | printf(".\r\n"); 347 | 348 | if (event->descriptor.getUUID() == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG) { 349 | _descriptor_handle = event->descriptor.getAttributeHandle(); 350 | _client->terminateCharacteristicDescriptorDiscovery( 351 | event->characteristic 352 | ); 353 | } 354 | } 355 | 356 | /** 357 | * If a CCCD has been found subscribe to server initiated events by writing 358 | * its value. 359 | */ 360 | void when_descriptor_discovery_ends(const TerminationCallbackParams_t *event) 361 | { 362 | // shall never happen but happen with android devices ... 363 | // process the next charateristic 364 | if (!_descriptor_handle) { 365 | printf("\tWarning: characteristic with notify or indicate attribute without CCCD.\r\n"); 366 | process_next_characteristic(); 367 | return; 368 | } 369 | 370 | Properties_t properties = _it->value.getProperties(); 371 | 372 | uint16_t cccd_value = 373 | (properties.notify() << 0) | (properties.indicate() << 1); 374 | 375 | ble_error_t error = _client->write( 376 | GattClient::GATT_OP_WRITE_REQ, 377 | _connection_handle, 378 | _descriptor_handle, 379 | sizeof(cccd_value), 380 | reinterpret_cast(&cccd_value) 381 | ); 382 | 383 | if (error) { 384 | printf( 385 | "Error: cannot initiate write of CCCD %u due to %u.\r\n", 386 | _descriptor_handle, error 387 | ); 388 | stop(); 389 | } 390 | } 391 | 392 | /** 393 | * Called when the CCCD has been written. 394 | */ 395 | void when_descriptor_written(const GattWriteCallbackParams* event) 396 | { 397 | // should never happen 398 | if (!_descriptor_handle) { 399 | printf("\tError: received write response to unsolicited request.\r\n"); 400 | stop(); 401 | return; 402 | } 403 | 404 | printf("\tCCCD at %u written.\r\n", _descriptor_handle); 405 | _descriptor_handle = 0; 406 | process_next_characteristic(); 407 | } 408 | 409 | /** 410 | * Print the updated value of the characteristic. 411 | * 412 | * This function is called when the server emits a notification or an 413 | * indication of a characteristic value the client has subscribed to. 414 | * 415 | * @see GattClient::onHVX() 416 | */ 417 | void when_characteristic_changed(const GattHVXCallbackParams* event) 418 | { 419 | printf("Change on attribute %u: new value = ", event->handle); 420 | for (size_t i = 0; i < event->len; ++i) { 421 | printf("0x%02X ", event->data[i]); 422 | } 423 | printf(".\r\n"); 424 | } 425 | 426 | struct DiscoveredCharacteristicNode { 427 | DiscoveredCharacteristicNode(const DiscoveredCharacteristic &c) : 428 | value(c), next(nullptr) { } 429 | 430 | DiscoveredCharacteristic value; 431 | DiscoveredCharacteristicNode *next; 432 | }; 433 | 434 | /** 435 | * Add a discovered characteristic into the list of discovered characteristics. 436 | */ 437 | bool add_characteristic(const DiscoveredCharacteristic *characteristic) 438 | { 439 | DiscoveredCharacteristicNode* new_node = 440 | new(std::nothrow) DiscoveredCharacteristicNode(*characteristic); 441 | 442 | if (new_node == nullptr) { 443 | printf("Error while allocating a new characteristic.\r\n"); 444 | return false; 445 | } 446 | 447 | if (_characteristics == nullptr) { 448 | _characteristics = new_node; 449 | } else { 450 | DiscoveredCharacteristicNode* c = _characteristics; 451 | while(c->next) { 452 | c = c->next; 453 | } 454 | c->next = new_node; 455 | } 456 | 457 | return true; 458 | } 459 | 460 | /** 461 | * Clear the list of discovered characteristics. 462 | */ 463 | void clear_characteristics(void) 464 | { 465 | DiscoveredCharacteristicNode *c= _characteristics; 466 | 467 | while (c) { 468 | DiscoveredCharacteristicNode *n = c->next; 469 | delete c; 470 | c = n; 471 | } 472 | } 473 | 474 | /** 475 | * Helper to construct an event handler from a member function of this 476 | * instance. 477 | */ 478 | template 479 | FunctionPointerWithContext as_cb(void (Self::*member)(ContextType context)) 480 | { 481 | return makeFunctionPointer(this, member); 482 | } 483 | 484 | /** 485 | * Print the value of a UUID. 486 | */ 487 | static void print_uuid(const UUID &uuid) 488 | { 489 | const uint8_t *uuid_value = uuid.getBaseUUID(); 490 | 491 | // UUIDs are in little endian, print them in big endian 492 | for (size_t i = 0; i < uuid.getLen(); ++i) { 493 | printf("%02X", uuid_value[(uuid.getLen() - 1) - i]); 494 | } 495 | } 496 | 497 | /** 498 | * Print the value of a characteristic properties. 499 | */ 500 | static void print_properties(const Properties_t &properties) 501 | { 502 | const struct { 503 | bool (Properties_t::*fn)() const; 504 | const char* str; 505 | } prop_to_str[] = { 506 | { &Properties_t::broadcast, "broadcast" }, 507 | { &Properties_t::read, "read" }, 508 | { &Properties_t::writeWoResp, "writeWoResp" }, 509 | { &Properties_t::write, "write" }, 510 | { &Properties_t::notify, "notify" }, 511 | { &Properties_t::indicate, "indicate" }, 512 | { &Properties_t::authSignedWrite, "authSignedWrite" } 513 | }; 514 | 515 | printf("["); 516 | for (size_t i = 0; i < (sizeof(prop_to_str) / sizeof(prop_to_str[0])); ++i) { 517 | if ((properties.*(prop_to_str[i].fn))()) { 518 | printf(" %s", prop_to_str[i].str); 519 | } 520 | } 521 | printf(" ]"); 522 | } 523 | 524 | private: 525 | BLE *_ble = nullptr; 526 | events::EventQueue *_event_queue = nullptr; 527 | GattClient *_client = nullptr; 528 | 529 | ble::connection_handle_t _connection_handle = 0; 530 | DiscoveredCharacteristicNode *_characteristics = nullptr; 531 | DiscoveredCharacteristicNode *_it = nullptr; 532 | GattAttribute::Handle_t _descriptor_handle = 0; 533 | }; 534 | 535 | 536 | int main() 537 | { 538 | mbed_trace_init(); 539 | 540 | BLE &ble = BLE::Instance(); 541 | events::EventQueue event_queue; 542 | 543 | GattClientDemo demo; 544 | 545 | /* this process will handle basic ble setup and advertising for us */ 546 | GattClientProcess ble_process(event_queue, ble); 547 | 548 | /* once it's done it will let us continue with our demo */ 549 | ble_process.on_init(mbed::callback(&demo, &GattClientDemo::start)); 550 | ble_process.on_connect(mbed::callback(&demo, &GattClientDemo::start_discovery)); 551 | 552 | ble_process.start(); 553 | 554 | return 0; 555 | } 556 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicWrite/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GattClient_CharacteristicWrite) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicWrite/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicWrite/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicWrite/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicWrite/readme.md: -------------------------------------------------------------------------------- 1 | # Write characteristic with GattClient 2 | 3 | This example demonstrates using the `GattClient` API to write to remote `GattServer`. 4 | 5 | This example works best with the `BLE_GattServer_CharacteristicWrite` examples which provides the characteristic to write to. 6 | Alternatively you can create your own GATT Server with a writable characteristic with UUID `0xA001` of size 1 byte. 7 | 8 | This demo will run a GattClient and attempt to find a device with a name "GattServer". It will also accept a connection, 9 | advertising as "GattClient". 10 | 11 | After connection completes it will attempt to discover all services and characteristics, looking for the writable 12 | characteristic. If it finds it, it will read and write the characteristic every 5 seconds, incrementing the byte value 13 | every time. 14 | 15 | Both applications should print the changing value in sync. 16 | 17 | # Running the application 18 | 19 | ## Requirements 20 | 21 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 22 | 23 | ## Building instructions 24 | 25 | Building instructions for all mbed OS samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 26 | -------------------------------------------------------------------------------- /BLE_GattClient_CharacteristicWrite/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "events/mbed_events.h" 18 | #include "ble/BLE.h" 19 | #include "ble_app.h" 20 | #include "mbed-trace/mbed_trace.h" 21 | 22 | /* GATT server needs free functions */ 23 | void service_discovery(const DiscoveredService *service); 24 | void characteristic_discovery(const DiscoveredCharacteristic *characteristic); 25 | void discovery_termination(ble::connection_handle_t connectionHandle); 26 | void on_read(const GattReadCallbackParams *response); 27 | void on_write(const GattWriteCallbackParams *response); 28 | 29 | class GattClientDemo : public ble::Gap::EventHandler { 30 | const static uint16_t EXAMPLE_SERVICE_UUID = 0xA000; 31 | const static uint16_t WRITABLE_CHARACTERISTIC_UUID = 0xA001; 32 | 33 | friend void service_discovery(const DiscoveredService *service); 34 | friend void characteristic_discovery(const DiscoveredCharacteristic *characteristic); 35 | friend void discovery_termination(ble::connection_handle_t connectionHandle); 36 | friend void on_read(const GattReadCallbackParams *response); 37 | friend void on_write(const GattWriteCallbackParams *response); 38 | 39 | public: 40 | static GattClientDemo &get_instance() { 41 | static GattClientDemo instance; 42 | return instance; 43 | } 44 | 45 | void start() { 46 | _ble_app.add_gap_event_handler(this); 47 | _ble_app.set_target_name("GattServer"); 48 | 49 | /* once it's done it will let us continue with our demo by calling on_init */ 50 | _ble_app.start(callback(this, &GattClientDemo::on_init)); 51 | /* the above function does not return until we call _ble_app.stop() somewhere else */ 52 | } 53 | 54 | private: 55 | /** Callback triggered when the ble initialization process has finished */ 56 | void on_init(BLE &ble, events::EventQueue &event_queue) { 57 | _ble = &ble; 58 | _event_queue = &event_queue; 59 | _ble->gattClient().onDataRead(::on_read); 60 | _ble->gattClient().onDataWritten(::on_write); 61 | } 62 | 63 | void onConnectionComplete(const ble::ConnectionCompleteEvent &event) { 64 | printf("We are looking for a service with UUID 0xA000\r\n"); 65 | printf("And a characteristic with UUID 0xA001\r\n"); 66 | 67 | _ble->gattClient().onServiceDiscoveryTermination(::discovery_termination); 68 | _ble->gattClient().launchServiceDiscovery( 69 | event.getConnectionHandle(), 70 | ::service_discovery, 71 | ::characteristic_discovery, 72 | EXAMPLE_SERVICE_UUID, 73 | WRITABLE_CHARACTERISTIC_UUID 74 | ); 75 | } 76 | 77 | private: 78 | void service_discovery(const DiscoveredService *service) { 79 | if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { 80 | if (service->getUUID().getShortUUID() == EXAMPLE_SERVICE_UUID) { 81 | printf("We found the service we were looking for\r\n"); 82 | } 83 | } 84 | } 85 | 86 | void characteristic_discovery(const DiscoveredCharacteristic *characteristic) { 87 | if (characteristic->getUUID().getShortUUID() == WRITABLE_CHARACTERISTIC_UUID) { 88 | printf("We found the characteristic we were looking for\r\n"); 89 | writable_characteristic = *characteristic; 90 | writable_characteristic_found = true; 91 | } 92 | } 93 | 94 | void discovery_termination(ble::connection_handle_t connectionHandle) { 95 | if (writable_characteristic_found) { 96 | writable_characteristic_found = false; 97 | _event_queue->call([this]{ writable_characteristic.read(); }); 98 | } 99 | } 100 | 101 | void on_read(const GattReadCallbackParams *response) { 102 | if (response->handle == writable_characteristic.getValueHandle()) { 103 | /* increment the value we just read */ 104 | uint8_t value = response->data[0]; 105 | value++; 106 | 107 | /* and write it back */ 108 | writable_characteristic.write(1, &value); 109 | 110 | printf("Written new value of %x\r\n", value); 111 | } 112 | } 113 | 114 | void on_write(const GattWriteCallbackParams *response) { 115 | if (response->handle == writable_characteristic.getValueHandle()) { 116 | /* this concludes the example, we stop the app running the ble process in the background */ 117 | _ble_app.stop(); 118 | } 119 | } 120 | 121 | private: 122 | GattClientDemo() {}; 123 | ~GattClientDemo() {}; 124 | 125 | private: 126 | /** Simplified BLE application that automatically advertises and scans. It will 127 | * initialise BLE and run the event queue */ 128 | BLEApp _ble_app; 129 | 130 | BLE *_ble = nullptr; 131 | events::EventQueue *_event_queue = nullptr; 132 | 133 | DiscoveredCharacteristic writable_characteristic; 134 | bool writable_characteristic_found = false; 135 | }; 136 | 137 | /* redirect to demo instance functions */ 138 | void service_discovery(const DiscoveredService *service) { 139 | GattClientDemo::get_instance().service_discovery(service); 140 | } 141 | 142 | void characteristic_discovery(const DiscoveredCharacteristic *characteristic) { 143 | GattClientDemo::get_instance().characteristic_discovery(characteristic); 144 | } 145 | 146 | void discovery_termination(ble::connection_handle_t connectionHandle) { 147 | GattClientDemo::get_instance().discovery_termination(connectionHandle); 148 | } 149 | 150 | void on_read(const GattReadCallbackParams *response) { 151 | GattClientDemo::get_instance().on_read(response); 152 | } 153 | 154 | void on_write(const GattWriteCallbackParams *response) { 155 | GattClientDemo::get_instance().on_write(response); 156 | } 157 | 158 | int main() 159 | { 160 | printf("\r\nGattClient demo of a writable characteristic\r\n"); 161 | 162 | mbed_trace_init(); 163 | 164 | GattClientDemo &demo = GattClientDemo::get_instance(); 165 | 166 | /* this demo will run and sleep for 5 seconds, during which time ble will be shut down */ 167 | while (1) { 168 | demo.start(); 169 | printf("Sleeping...\r\n"); 170 | ThisThread::sleep_for(5s); 171 | } 172 | 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /BLE_GattServer_AddService/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GattServer_AddService) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/connection.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/connection_ble_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/connection_ble_profile.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/discovery.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/discovery_ble_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/discovery_ble_profile.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/notifications.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/notifications_ble_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/notifications_ble_profile.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/register_to_notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/register_to_notifications.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/register_to_notifications_ble_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/register_to_notifications_ble_profile.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/scan_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/scan_result.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/scan_result_ble_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/scan_result_ble_profile.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/start_scan.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/img/start_scan_ble_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_AddService/img/start_scan_ble_profile.png -------------------------------------------------------------------------------- /BLE_GattServer_AddService/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_AddService/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_AddService/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_GattServer_AddService/readme.md: -------------------------------------------------------------------------------- 1 | # BLE Service Example 2 | 3 | This application shows how to add a new service and allow clients to interact with it. 4 | This application transmits a heart rate value using the [Bluetooth SIG Heart Rate Profile](https://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx). 5 | The heart rate value is simulated by the application itself, not by a sensor, so that you don't have to get a sensor just to run the example. 6 | The demo will advertise connectable advertising. Upon connection the client will be able to subscribe to heart rate value updates. 7 | 8 | # Running the application 9 | 10 | ## Requirements 11 | 12 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 13 | 14 | ## Building instructions 15 | 16 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 17 | 18 | ## Checking for success 19 | 20 | **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 Connect for Mobile* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Connect for Mobile. Alternative scanners may require reference to their manuals. 21 | 22 | 1. Build the application and install it on your board as explained in the building instructions. 23 | 1. Open the BLE scanner on your phone. 24 | 1. Start a scan. 25 | 26 | ![](img/start_scan_ble_profile.png) 27 | 28 | **figure 1.a** How to start scan using ST BLE Profile 2.0.0 29 | 30 | ![](img/start_scan.png) 31 | 32 | **figure 1.b** How to start scan using nRF Connect for Mobile 4.0.5 33 | 34 | 1. Find your device; it should be named `HRM`. 35 | 36 | ![](img/scan_result_ble_profile.png) 37 | 38 | **figure 2.a** Scan results using ST BLE Profile 2.0.0 39 | 40 | ![](img/scan_result.png) 41 | 42 | **figure 2.b** Scan results using nRF Connect for Mobile 4.0.5 43 | 44 | 1. Establish a connection with your device. 45 | 46 | ![](img/connection_ble_profile.png) 47 | 48 | **figure 3.a** How to establish a connection using ST BLE Profile 2.0.0 49 | 50 | ![](img/connection.png) 51 | 52 | **figure 3.b** How to establish a connection using Master Control Panel 4.0.5 53 | 54 | 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`. 55 | 56 | ![](img/discovery_ble_profile.png) 57 | 58 | **figure 4.a** Representation of the Heart Rate service using ST BLE Profile 2.0.0 59 | 60 | ![](img/discovery.png) 61 | 62 | **figure 4.b** Representation of the Heart Rate service using Master Control Panel 4.0.5 63 | 64 | 1. Register for the notifications sent by the *Heart Rate Measurement* characteristic. 65 | 66 | ![](img/register_to_notifications_ble_profile.png) 67 | 68 | **figure 5.a** How to register to notifications using ST BLE Profile 2.0.0 69 | 70 | ![](img/register_to_notifications.png) 71 | 72 | **figure 5.b** How to register to notifications using Master Control Panel 4.0.5 73 | 74 | 75 | 1. You should see the heart rate value change every half second.
For ST BLE Profile, it begins at 60, goes up to 100 (in steps of 1), resets to 60 and so on. 76 | 77 | ![](img/notifications_ble_profile.png) 78 | 79 | **figure 6.a** Notifications view using ST BLE Profile 2.0.0 80 | 81 | For Master Control Panel, it begins at 100, goes up to 175 (in steps of 1), resets to 100 and so on. 82 | 83 | ![](img/notifications.png) 84 | 85 | **figure 6.b** Notifications view using Master Control Panel 4.0.5 86 | -------------------------------------------------------------------------------- /BLE_GattServer_AddService/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "ble/BLE.h" 19 | #include "ble/gap/Gap.h" 20 | #include "ble/services/HeartRateService.h" 21 | #include "pretty_printer.h" 22 | #include "mbed-trace/mbed_trace.h" 23 | 24 | using namespace std::literals::chrono_literals; 25 | 26 | const static char DEVICE_NAME[] = "Heartrate"; 27 | 28 | static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); 29 | 30 | class HeartrateDemo : ble::Gap::EventHandler { 31 | public: 32 | HeartrateDemo(BLE &ble, events::EventQueue &event_queue) : 33 | _ble(ble), 34 | _event_queue(event_queue), 35 | _heartrate_uuid(GattService::UUID_HEART_RATE_SERVICE), 36 | _heartrate_value(100), 37 | _heartrate_service(ble, _heartrate_value, HeartRateService::LOCATION_FINGER), 38 | _adv_data_builder(_adv_buffer) 39 | { 40 | } 41 | 42 | void start() 43 | { 44 | _ble.init(this, &HeartrateDemo::on_init_complete); 45 | 46 | _event_queue.dispatch_forever(); 47 | } 48 | 49 | private: 50 | /** Callback triggered when the ble initialization process has finished */ 51 | void on_init_complete(BLE::InitializationCompleteCallbackContext *params) 52 | { 53 | if (params->error != BLE_ERROR_NONE) { 54 | printf("Ble initialization failed."); 55 | return; 56 | } 57 | 58 | print_mac_address(); 59 | 60 | /* this allows us to receive events like onConnectionComplete() */ 61 | _ble.gap().setEventHandler(this); 62 | 63 | /* heart rate value updated every second */ 64 | _event_queue.call_every( 65 | 1000ms, 66 | [this] { 67 | update_sensor_value(); 68 | } 69 | ); 70 | 71 | start_advertising(); 72 | } 73 | 74 | void start_advertising() 75 | { 76 | /* Create advertising parameters and payload */ 77 | 78 | ble::AdvertisingParameters adv_parameters( 79 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED, 80 | ble::adv_interval_t(ble::millisecond_t(100)) 81 | ); 82 | 83 | _adv_data_builder.setFlags(); 84 | _adv_data_builder.setAppearance(ble::adv_data_appearance_t::GENERIC_HEART_RATE_SENSOR); 85 | _adv_data_builder.setLocalServiceList({&_heartrate_uuid, 1}); 86 | _adv_data_builder.setName(DEVICE_NAME); 87 | 88 | /* Setup advertising */ 89 | 90 | ble_error_t error = _ble.gap().setAdvertisingParameters( 91 | ble::LEGACY_ADVERTISING_HANDLE, 92 | adv_parameters 93 | ); 94 | 95 | if (error) { 96 | printf("_ble.gap().setAdvertisingParameters() failed\r\n"); 97 | return; 98 | } 99 | 100 | error = _ble.gap().setAdvertisingPayload( 101 | ble::LEGACY_ADVERTISING_HANDLE, 102 | _adv_data_builder.getAdvertisingData() 103 | ); 104 | 105 | if (error) { 106 | printf("_ble.gap().setAdvertisingPayload() failed\r\n"); 107 | return; 108 | } 109 | 110 | /* Start advertising */ 111 | 112 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 113 | 114 | if (error) { 115 | printf("_ble.gap().startAdvertising() failed\r\n"); 116 | return; 117 | } 118 | 119 | printf("Heart rate sensor advertising, please connect\r\n"); 120 | } 121 | 122 | void update_sensor_value() 123 | { 124 | /* you can read in the real value but here we just simulate a value */ 125 | _heartrate_value++; 126 | 127 | /* 60 <= bpm value < 110 */ 128 | if (_heartrate_value == 110) { 129 | _heartrate_value = 60; 130 | } 131 | 132 | _heartrate_service.updateHeartRate(_heartrate_value); 133 | } 134 | 135 | /* these implement ble::Gap::EventHandler */ 136 | private: 137 | /* when we connect we stop advertising, restart advertising so others can connect */ 138 | virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) 139 | { 140 | if (event.getStatus() == ble_error_t::BLE_ERROR_NONE) { 141 | printf("Client connected, you may now subscribe to updates\r\n"); 142 | } 143 | } 144 | 145 | /* when we connect we stop advertising, restart advertising so others can connect */ 146 | virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) 147 | { 148 | printf("Client disconnected, restarting advertising\r\n"); 149 | 150 | ble_error_t error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 151 | 152 | if (error) { 153 | printf("_ble.gap().startAdvertising() failed\r\n"); 154 | return; 155 | } 156 | } 157 | 158 | private: 159 | BLE &_ble; 160 | events::EventQueue &_event_queue; 161 | 162 | UUID _heartrate_uuid; 163 | uint16_t _heartrate_value; 164 | HeartRateService _heartrate_service; 165 | 166 | uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 167 | ble::AdvertisingDataBuilder _adv_data_builder; 168 | }; 169 | 170 | /* Schedule processing of events from the BLE middleware in the event queue. */ 171 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 172 | { 173 | event_queue.call(Callback(&context->ble, &BLE::processEvents)); 174 | } 175 | 176 | int main() 177 | { 178 | mbed_trace_init(); 179 | 180 | BLE &ble = BLE::Instance(); 181 | ble.onEventsToProcess(schedule_ble_events); 182 | 183 | HeartrateDemo demo(ble, event_queue); 184 | demo.start(); 185 | 186 | return 0; 187 | } 188 | 189 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicUpdates/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GattServer_CharacteristicUpdates) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicUpdates/README.md: -------------------------------------------------------------------------------- 1 | # BLE Gatt Server example 2 | 3 | This application demonstrates detailed uses of the GattServer APIs. 4 | 5 | It starts by advertising to its environment with the device name "GattServer". Once you connect to the device with 6 | a BLE scanner on your phone, the scanner shows a service with three characteristics - each representing the hour, 7 | minute and second of a clock. 8 | 9 | To see the clock values updating subscribe to the service using the "Enable CCCDs" (or similar) option provided 10 | by the scanner. Now the values get updated once a second. 11 | 12 | # Running the application 13 | 14 | ## Requirements 15 | 16 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 17 | 18 | ## Building instructions 19 | 20 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 21 | 22 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicUpdates/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicUpdates/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicUpdates/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicUpdates/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2017-2019 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "platform/Callback.h" 18 | #include "events/EventQueue.h" 19 | #include "ble/BLE.h" 20 | #include "gatt_server_process.h" 21 | #include "mbed-trace/mbed_trace.h" 22 | 23 | using mbed::callback; 24 | using namespace std::literals::chrono_literals; 25 | 26 | /** 27 | * A Clock service that demonstrate the GattServer features. 28 | * 29 | * The clock service host three characteristics that model the current hour, 30 | * minute and second of the clock. The value of the second characteristic is 31 | * incremented automatically by the system. 32 | * 33 | * A client can subscribe to updates of the clock characteristics and get 34 | * notified when one of the value is changed. Clients can also change value of 35 | * the second, minute and hour characteristric. 36 | */ 37 | class ClockService : public ble::GattServer::EventHandler { 38 | public: 39 | ClockService() : 40 | _hour_char("485f4145-52b9-4644-af1f-7a6b9322490f", 0), 41 | _minute_char("0a924ca7-87cd-4699-a3bd-abdcd9cf126a", 0), 42 | _second_char("8dd6a1b7-bc75-4741-8a26-264af75807de", 0), 43 | _clock_service( 44 | /* uuid */ "51311102-030e-485f-b122-f8f381aa84ed", 45 | /* characteristics */ _clock_characteristics, 46 | /* numCharacteristics */ sizeof(_clock_characteristics) / 47 | sizeof(_clock_characteristics[0]) 48 | ) 49 | { 50 | /* update internal pointers (value, descriptors and characteristics array) */ 51 | _clock_characteristics[0] = &_hour_char; 52 | _clock_characteristics[1] = &_minute_char; 53 | _clock_characteristics[2] = &_second_char; 54 | 55 | /* setup authorization handlers */ 56 | _hour_char.setWriteAuthorizationCallback(this, &ClockService::authorize_client_write); 57 | _minute_char.setWriteAuthorizationCallback(this, &ClockService::authorize_client_write); 58 | _second_char.setWriteAuthorizationCallback(this, &ClockService::authorize_client_write); 59 | } 60 | 61 | void start(BLE &ble, events::EventQueue &event_queue) 62 | { 63 | _server = &ble.gattServer(); 64 | _event_queue = &event_queue; 65 | 66 | printf("Registering demo service\r\n"); 67 | ble_error_t err = _server->addService(_clock_service); 68 | 69 | if (err) { 70 | printf("Error %u during demo service registration.\r\n", err); 71 | return; 72 | } 73 | 74 | /* register handlers */ 75 | _server->setEventHandler(this); 76 | 77 | printf("clock service registered\r\n"); 78 | printf("service handle: %u\r\n", _clock_service.getHandle()); 79 | printf("hour characteristic value handle %u\r\n", _hour_char.getValueHandle()); 80 | printf("minute characteristic value handle %u\r\n", _minute_char.getValueHandle()); 81 | printf("second characteristic value handle %u\r\n", _second_char.getValueHandle()); 82 | 83 | _event_queue->call_every(1000ms, callback(this, &ClockService::increment_second)); 84 | } 85 | 86 | /* GattServer::EventHandler */ 87 | private: 88 | /** 89 | * Handler called when a notification or an indication has been sent. 90 | */ 91 | void onDataSent(const GattDataSentCallbackParams ¶ms) override 92 | { 93 | printf("sent updates\r\n"); 94 | } 95 | 96 | /** 97 | * Handler called after an attribute has been written. 98 | */ 99 | void onDataWritten(const GattWriteCallbackParams ¶ms) override 100 | { 101 | printf("data written:\r\n"); 102 | printf("connection handle: %u\r\n", params.connHandle); 103 | printf("attribute handle: %u", params.handle); 104 | if (params.handle == _hour_char.getValueHandle()) { 105 | printf(" (hour characteristic)\r\n"); 106 | } else if (params.handle == _minute_char.getValueHandle()) { 107 | printf(" (minute characteristic)\r\n"); 108 | } else if (params.handle == _second_char.getValueHandle()) { 109 | printf(" (second characteristic)\r\n"); 110 | } else { 111 | printf("\r\n"); 112 | } 113 | printf("write operation: %u\r\n", params.writeOp); 114 | printf("offset: %u\r\n", params.offset); 115 | printf("length: %u\r\n", params.len); 116 | printf("data: "); 117 | 118 | for (size_t i = 0; i < params.len; ++i) { 119 | printf("%02X", params.data[i]); 120 | } 121 | 122 | printf("\r\n"); 123 | } 124 | 125 | /** 126 | * Handler called after an attribute has been read. 127 | */ 128 | void onDataRead(const GattReadCallbackParams ¶ms) override 129 | { 130 | printf("data read:\r\n"); 131 | printf("connection handle: %u\r\n", params.connHandle); 132 | printf("attribute handle: %u", params.handle); 133 | if (params.handle == _hour_char.getValueHandle()) { 134 | printf(" (hour characteristic)\r\n"); 135 | } else if (params.handle == _minute_char.getValueHandle()) { 136 | printf(" (minute characteristic)\r\n"); 137 | } else if (params.handle == _second_char.getValueHandle()) { 138 | printf(" (second characteristic)\r\n"); 139 | } else { 140 | printf("\r\n"); 141 | } 142 | } 143 | 144 | /** 145 | * Handler called after a client has subscribed to notification or indication. 146 | * 147 | * @param handle Handle of the characteristic value affected by the change. 148 | */ 149 | void onUpdatesEnabled(const GattUpdatesEnabledCallbackParams ¶ms) override 150 | { 151 | printf("update enabled on handle %d\r\n", params.attHandle); 152 | } 153 | 154 | /** 155 | * Handler called after a client has cancelled his subscription from 156 | * notification or indication. 157 | * 158 | * @param handle Handle of the characteristic value affected by the change. 159 | */ 160 | void onUpdatesDisabled(const GattUpdatesDisabledCallbackParams ¶ms) override 161 | { 162 | printf("update disabled on handle %d\r\n", params.attHandle); 163 | } 164 | 165 | /** 166 | * Handler called when an indication confirmation has been received. 167 | * 168 | * @param handle Handle of the characteristic value that has emitted the 169 | * indication. 170 | */ 171 | void onConfirmationReceived(const GattConfirmationReceivedCallbackParams ¶ms) override 172 | { 173 | printf("confirmation received on handle %d\r\n", params.attHandle); 174 | } 175 | 176 | private: 177 | /** 178 | * Handler called when a write request is received. 179 | * 180 | * This handler verify that the value submitted by the client is valid before 181 | * authorizing the operation. 182 | */ 183 | void authorize_client_write(GattWriteAuthCallbackParams *e) 184 | { 185 | printf("characteristic %u write authorization\r\n", e->handle); 186 | 187 | if (e->offset != 0) { 188 | printf("Error invalid offset\r\n"); 189 | e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET; 190 | return; 191 | } 192 | 193 | if (e->len != 1) { 194 | printf("Error invalid len\r\n"); 195 | e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH; 196 | return; 197 | } 198 | 199 | if ((e->data[0] >= 60) || 200 | ((e->data[0] >= 24) && (e->handle == _hour_char.getValueHandle()))) { 201 | printf("Error invalid data\r\n"); 202 | e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED; 203 | return; 204 | } 205 | 206 | e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; 207 | } 208 | 209 | /** 210 | * Increment the second counter. 211 | */ 212 | void increment_second(void) 213 | { 214 | uint8_t second = 0; 215 | ble_error_t err = _second_char.get(*_server, second); 216 | if (err) { 217 | printf("read of the second value returned error %u\r\n", err); 218 | return; 219 | } 220 | 221 | second = (second + 1) % 60; 222 | 223 | err = _second_char.set(*_server, second); 224 | if (err) { 225 | printf("write of the second value returned error %u\r\n", err); 226 | return; 227 | } 228 | 229 | if (second == 0) { 230 | increment_minute(); 231 | } 232 | } 233 | 234 | /** 235 | * Increment the minute counter. 236 | */ 237 | void increment_minute(void) 238 | { 239 | uint8_t minute = 0; 240 | ble_error_t err = _minute_char.get(*_server, minute); 241 | if (err) { 242 | printf("read of the minute value returned error %u\r\n", err); 243 | return; 244 | } 245 | 246 | minute = (minute + 1) % 60; 247 | 248 | err = _minute_char.set(*_server, minute); 249 | if (err) { 250 | printf("write of the minute value returned error %u\r\n", err); 251 | return; 252 | } 253 | 254 | if (minute == 0) { 255 | increment_hour(); 256 | } 257 | } 258 | 259 | /** 260 | * Increment the hour counter. 261 | */ 262 | void increment_hour(void) 263 | { 264 | uint8_t hour = 0; 265 | ble_error_t err = _hour_char.get(*_server, hour); 266 | if (err) { 267 | printf("read of the hour value returned error %u\r\n", err); 268 | return; 269 | } 270 | 271 | hour = (hour + 1) % 24; 272 | 273 | err = _hour_char.set(*_server, hour); 274 | if (err) { 275 | printf("write of the hour value returned error %u\r\n", err); 276 | return; 277 | } 278 | } 279 | 280 | private: 281 | /** 282 | * Read, Write, Notify, Indicate Characteristic declaration helper. 283 | * 284 | * @tparam T type of data held by the characteristic. 285 | */ 286 | template 287 | class ReadWriteNotifyIndicateCharacteristic : public GattCharacteristic { 288 | public: 289 | /** 290 | * Construct a characteristic that can be read or written and emit 291 | * notification or indication. 292 | * 293 | * @param[in] uuid The UUID of the characteristic. 294 | * @param[in] initial_value Initial value contained by the characteristic. 295 | */ 296 | ReadWriteNotifyIndicateCharacteristic(const UUID & uuid, const T& initial_value) : 297 | GattCharacteristic( 298 | /* UUID */ uuid, 299 | /* Initial value */ &_value, 300 | /* Value size */ sizeof(_value), 301 | /* Value capacity */ sizeof(_value), 302 | /* Properties */ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | 303 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | 304 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | 305 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE, 306 | /* Descriptors */ nullptr, 307 | /* Num descriptors */ 0, 308 | /* variable len */ false 309 | ), 310 | _value(initial_value) { 311 | } 312 | 313 | /** 314 | * Get the value of this characteristic. 315 | * 316 | * @param[in] server GattServer instance that contain the characteristic 317 | * value. 318 | * @param[in] dst Variable that will receive the characteristic value. 319 | * 320 | * @return BLE_ERROR_NONE in case of success or an appropriate error code. 321 | */ 322 | ble_error_t get(GattServer &server, T& dst) const 323 | { 324 | uint16_t value_length = sizeof(dst); 325 | return server.read(getValueHandle(), &dst, &value_length); 326 | } 327 | 328 | /** 329 | * Assign a new value to this characteristic. 330 | * 331 | * @param[in] server GattServer instance that will receive the new value. 332 | * @param[in] value The new value to set. 333 | * @param[in] local_only Flag that determine if the change should be kept 334 | * locally or forwarded to subscribed clients. 335 | */ 336 | ble_error_t set(GattServer &server, const uint8_t &value, bool local_only = false) const 337 | { 338 | return server.write(getValueHandle(), &value, sizeof(value), local_only); 339 | } 340 | 341 | private: 342 | uint8_t _value; 343 | }; 344 | 345 | private: 346 | GattServer *_server = nullptr; 347 | events::EventQueue *_event_queue = nullptr; 348 | 349 | GattService _clock_service; 350 | GattCharacteristic* _clock_characteristics[3]; 351 | 352 | ReadWriteNotifyIndicateCharacteristic _hour_char; 353 | ReadWriteNotifyIndicateCharacteristic _minute_char; 354 | ReadWriteNotifyIndicateCharacteristic _second_char; 355 | }; 356 | 357 | int main() 358 | { 359 | mbed_trace_init(); 360 | 361 | BLE &ble = BLE::Instance(); 362 | events::EventQueue event_queue; 363 | ClockService demo_service; 364 | 365 | /* this process will handle basic ble setup and advertising for us */ 366 | GattServerProcess ble_process(event_queue, ble); 367 | 368 | /* once it's done it will let us continue with our demo */ 369 | ble_process.on_init(callback(&demo_service, &ClockService::start)); 370 | 371 | ble_process.start(); 372 | 373 | return 0; 374 | } 375 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicWrite/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GattServer_CharacteristicWrite) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicWrite/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicWrite/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicWrite/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicWrite/readme.md: -------------------------------------------------------------------------------- 1 | # Create a writable characteristic on GattServer 2 | 3 | This example creates a writable characteristic and notifies the user of any writes by printing to the serial. 4 | The example will advertise as "GattServer" and await connection. 5 | 6 | This example can be used together with `BLE_GattClient_CharacteristicWrite` running on another board or with 7 | a phone running a BLE scanner application. Either one can connect and write a new value to the writable 8 | characteristic with UUID `0xA001`. 9 | 10 | As the application runs it will update you about its progress over serial and then proceed to print the value 11 | of the writable characteristic every time it's updated. 12 | 13 | # Running the application 14 | 15 | ## Requirements 16 | 17 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 18 | 19 | ## Building instructions 20 | 21 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 22 | -------------------------------------------------------------------------------- /BLE_GattServer_CharacteristicWrite/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "ble/BLE.h" 19 | #include "gatt_server_process.h" 20 | #include "mbed-trace/mbed_trace.h" 21 | 22 | static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE); 23 | 24 | class GattServerDemo : ble::GattServer::EventHandler { 25 | 26 | const static uint16_t EXAMPLE_SERVICE_UUID = 0xA000; 27 | const static uint16_t WRITABLE_CHARACTERISTIC_UUID = 0xA001; 28 | 29 | public: 30 | GattServerDemo() 31 | { 32 | const UUID uuid = WRITABLE_CHARACTERISTIC_UUID; 33 | _writable_characteristic = new ReadWriteGattCharacteristic (uuid, &_characteristic_value); 34 | 35 | if (!_writable_characteristic) { 36 | printf("Allocation of ReadWriteGattCharacteristic failed\r\n"); 37 | } 38 | } 39 | 40 | ~GattServerDemo() 41 | { 42 | } 43 | 44 | void start(BLE &ble, events::EventQueue &event_queue) 45 | { 46 | const UUID uuid = EXAMPLE_SERVICE_UUID; 47 | GattCharacteristic* charTable[] = { _writable_characteristic }; 48 | GattService example_service(uuid, charTable, 1); 49 | 50 | ble.gattServer().addService(example_service); 51 | 52 | ble.gattServer().setEventHandler(this); 53 | 54 | printf("Example service added with UUID 0xA000\r\n"); 55 | printf("Connect and write to characteristic 0xA001\r\n"); 56 | } 57 | 58 | private: 59 | /** 60 | * This callback allows the LEDService to receive updates to the ledState Characteristic. 61 | * 62 | * @param[in] params Information about the characterisitc being updated. 63 | */ 64 | virtual void onDataWritten(const GattWriteCallbackParams ¶ms) 65 | { 66 | if ((params.handle == _writable_characteristic->getValueHandle()) && (params.len == 1)) { 67 | printf("New characteristic value written: %x\r\n", *(params.data)); 68 | } 69 | } 70 | 71 | private: 72 | ReadWriteGattCharacteristic *_writable_characteristic = nullptr; 73 | uint8_t _characteristic_value = 0; 74 | }; 75 | 76 | int main() 77 | { 78 | mbed_trace_init(); 79 | 80 | BLE &ble = BLE::Instance(); 81 | 82 | printf("\r\nGattServer demo of a writable characteristic\r\n"); 83 | 84 | GattServerDemo demo; 85 | 86 | /* this process will handle basic setup and advertising for us */ 87 | GattServerProcess ble_process(event_queue, ble); 88 | 89 | /* once it's done it will let us continue with our demo*/ 90 | ble_process.on_init(callback(&demo, &GattServerDemo::start)); 91 | 92 | ble_process.start(); 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_GattServer_ExperimentalServices) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | add_subdirectory(mbed-os-experimental-ble-services/services/CurrentTime) 18 | add_subdirectory(mbed-os-experimental-ble-services/services/LinkLoss) 19 | 20 | add_executable(${APP_TARGET}) 21 | 22 | target_sources(${APP_TARGET} 23 | PRIVATE 24 | source/main.cpp 25 | ) 26 | 27 | target_link_libraries(${APP_TARGET} 28 | PRIVATE 29 | mbed-os 30 | mbed-events 31 | mbed-ble 32 | mbed-ble-utils 33 | ble-service-link-loss 34 | ble-service-current-time 35 | ) 36 | 37 | mbed_set_post_build(${APP_TARGET}) 38 | 39 | option(VERBOSE_BUILD "Have a verbose build process") 40 | if(VERBOSE_BUILD) 41 | set(CMAKE_VERBOSE_MAKEFILE ON) 42 | endif() 43 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/README.md: -------------------------------------------------------------------------------- 1 | # Experimental Services 2 | This example demonstrates the Link Loss and Current Time Services from the [Experimental BLE Services](https://github.com/ARMmbed/mbed-os-experimental-ble-services) repository. 3 | 4 | ## Overview 5 | 6 | ### Link Loss Service 7 | The application sends an alert message over a serial terminal once the connection to the client is lost without prior warning. 8 | The client sets the alert level by writing a valid byte to the alert level characteristic inside the Link Loss Service (LLS): 9 | 10 | * 0x00 ("No Alert") 11 | * 0x01 ("Mild Alert") 12 | * 0x02 ("High Alert") 13 | 14 | The alert ends after a user-defined timeout (= 1 minute). 15 | 16 | ### Current Time Service 17 | The application permits reading/writing of the device's current time. 18 | In the latter case, the client sets the current time by writing a stream of bytes to the current time characteristic inside the Current Time Service (CTS). 19 | Table 1 shows the byte stream required to set the device's current time to Wed, 28 Oct 2009 11:35:37. 20 | 21 | | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 | B9 | 22 | |:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:| 23 | | 0xD9 | 0x07 | 0x0A | 0x1C | 0x0B | 0x23 | 0x25 | 0x03 | 0x00 | 0x00 | 24 | 25 | **Table 1. Byte stream required to set the device's current time to Wed, 28 Oct 2009 11:35:37** 26 | 27 | ## Usage 28 | 29 | ### Hardware Requirements 30 | Please refer to the main [README](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 31 | 32 | ### Build Instructions 33 | Please refer to the main [README](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 34 | 35 | ### Demonstration 36 | **Note:** The steps given below demonstrate the application using an Android smartphone running nRF Connect 4.24.3. 37 | The illustrations will be different for other clients. 38 | * Build the application and flash the board 39 | * Open a serial terminal on your host to receive serial prints from the application: 40 | `mbed term -b 115200` 41 | * Open nRF Connect, locate your device and press connect (Fig. 1) 42 | 43 | ![](img/connect.png) 44 | 45 | **Fig. 1 Connecting to the device** 46 | 47 | #### Link Loss Service 48 | 49 | * Select the Link Loss Service from the list of available services (Fig. 2) 50 | 51 | ![](img/select_lls.png) 52 | 53 | **Fig. 2 Selecting the Link Loss Service** 54 | 55 | * Press the upward pointing arrow to interact with the alert level characteristic (Fig. 3) 56 | 57 | ![](img/interact_alert_level.png) 58 | 59 | **Fig. 3. Interacting with the alert level characteristic** 60 | 61 | * Select an appropriate alert level from the dropdown menu and press send (Fig. 4) 62 | 63 | ![](img/write_alert_level.png) 64 | 65 | **Fig. 4. Writing the alert level characteristic** 66 | 67 | * Confirm that the value parameter was updated after the write (Fig. 5) 68 | 69 | ![](img/read_alert_level.png) 70 | 71 | **Fig. 5. Reading the alert level characteristic** 72 | 73 | * Go far enough away from the device so that nRF Connect disconnects in an ungraceful fashion 74 | * The alert level should appear at your terminal, e.g. "High Alert!" 75 | 76 | #### Current Time Service 77 | 78 | * Select the Current Time Service from the list of available services (Fig. 6) 79 | 80 | ![](img/select_cts.png) 81 | 82 | **Fig. 6. Selecting the Current Time Service** 83 | 84 | * Press the upward pointing arrow to interact with the current time characteristic (Fig. 7) 85 | 86 | ![](img/interact_current_time.png) 87 | 88 | **Fig. 7. Interacting with the current time characteristic** 89 | 90 | * Create a new write value for the byte stream in Table 1, save and load it, and press send (Fig. 8) 91 | 92 | ![](img/write_current_time.png) 93 | 94 | **Fig. 8. Writing the current time characteristic** 95 | 96 | * Confirm that the value parameter was updated with the correct date/time after the write (Fig. 9) 97 | 98 | ![](img/read_current_time.png) 99 | 100 | **Fig. 9. Reading the current time characteristic** 101 | 102 | * The current time in seconds should appear at your terminal, i.e. "1256729737" 103 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/connect.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/interact_alert_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/interact_alert_level.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/interact_current_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/interact_current_time.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/read_alert_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/read_alert_level.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/read_current_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/read_current_time.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/select_cts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/select_cts.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/select_lls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/select_lls.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/write_alert_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/write_alert_level.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/img/write_current_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/BLE_GattServer_ExperimentalServices/img/write_current_time.png -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/mbed-os-experimental-ble-services.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-experimental-ble-services 2 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200 5 | }, 6 | "K64F": { 7 | "target.components_add": ["BlueNRG_MS"], 8 | "target.features_add": ["BLE"], 9 | "target.extra_labels_add": ["CORDIO"] 10 | }, 11 | "NUCLEO_F401RE": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NRF52840_DK": { 17 | "target.features_add": ["BLE"] 18 | }, 19 | "NRF52_DK": { 20 | "target.features_add": ["BLE"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BLE_GattServer_ExperimentalServices/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2020 ARM Limited 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "ble/BLE.h" 19 | #include "ble/gap/Gap.h" 20 | #include "pretty_printer.h" 21 | #include "ble-service-link-loss/LinkLossService.h" 22 | #include "ble-service-current-time/CurrentTimeService.h" 23 | #include "mbed-trace/mbed_trace.h" 24 | 25 | using namespace std::literals::chrono_literals; 26 | 27 | const static char DEVICE_NAME[] = "ExperimentalServices"; 28 | 29 | static events::EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE); 30 | static ChainableGapEventHandler chainable_gap_event_handler; 31 | 32 | class ExperimentalServicesDemo : ble::Gap::EventHandler, LinkLossService::EventHandler, CurrentTimeService::EventHandler { 33 | public: 34 | ExperimentalServicesDemo(BLE &ble, events::EventQueue &event_queue, ChainableGapEventHandler &chainable_gap_event_handler) : 35 | _ble(ble), 36 | _event_queue(event_queue), 37 | _chainable_gap_event_handler(chainable_gap_event_handler), 38 | _link_loss_service(_ble, _event_queue, _chainable_gap_event_handler), 39 | _current_time_service(_ble, _event_queue), 40 | _adv_data_builder(_adv_buffer) 41 | { 42 | } 43 | 44 | void start() 45 | { 46 | _ble.init(this, &ExperimentalServicesDemo::on_init_complete); 47 | 48 | _event_queue.dispatch_forever(); 49 | } 50 | 51 | private: 52 | void on_init_complete(BLE::InitializationCompleteCallbackContext *params) 53 | { 54 | if (params->error != BLE_ERROR_NONE) { 55 | printf("Ble initialization failed."); 56 | return; 57 | } 58 | 59 | print_mac_address(); 60 | 61 | /* The ChainableGapEventHandler allows us to dispatch events from GAP to more than a single event handler */ 62 | _chainable_gap_event_handler.addEventHandler(this); 63 | _ble.gap().setEventHandler(&_chainable_gap_event_handler); 64 | 65 | _link_loss_service.init(); 66 | 67 | _link_loss_service.set_event_handler(this); 68 | _link_loss_service.set_alert_timeout(60000ms); 69 | 70 | _current_time_service.init(); 71 | 72 | _current_time_service.set_event_handler(this); 73 | 74 | start_advertising(); 75 | } 76 | 77 | void start_advertising() 78 | { 79 | ble::AdvertisingParameters adv_parameters( 80 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED, 81 | ble::adv_interval_t(ble::millisecond_t(100)) 82 | ); 83 | 84 | _adv_data_builder.setFlags(); 85 | _adv_data_builder.setAppearance(ble::adv_data_appearance_t::UNKNOWN); 86 | _adv_data_builder.setName(DEVICE_NAME); 87 | 88 | ble_error_t error = _ble.gap().setAdvertisingParameters( 89 | ble::LEGACY_ADVERTISING_HANDLE, 90 | adv_parameters 91 | ); 92 | 93 | if (error) { 94 | printf("_ble.gap().setAdvertisingParameters() failed\r\n"); 95 | return; 96 | } 97 | 98 | error = _ble.gap().setAdvertisingPayload( 99 | ble::LEGACY_ADVERTISING_HANDLE, 100 | _adv_data_builder.getAdvertisingData() 101 | ); 102 | 103 | if (error) { 104 | printf("_ble.gap().setAdvertisingPayload() failed\r\n"); 105 | return; 106 | } 107 | 108 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 109 | 110 | if (error) { 111 | printf("_ble.gap().startAdvertising() failed\r\n"); 112 | return; 113 | } 114 | 115 | printf("Device advertising, please connect\r\n"); 116 | } 117 | 118 | void on_alert_requested(LinkLossService::AlertLevel level) final 119 | { 120 | if (level == LinkLossService::AlertLevel::MILD_ALERT) { 121 | printf("Mild Alert!\r\n"); 122 | } else { 123 | printf("High Alert!\r\n"); 124 | } 125 | } 126 | 127 | void on_alert_end() final 128 | { 129 | printf("Alert ended\r\n"); 130 | } 131 | 132 | void on_current_time_changed(time_t current_time, uint8_t adjust_reason) final 133 | { 134 | printf("Current time: %ld - Adjust reason: %d\r\n", (long)current_time, adjust_reason); 135 | } 136 | 137 | private: 138 | void onConnectionComplete(const ble::ConnectionCompleteEvent &event) override 139 | { 140 | if (event.getStatus() == ble_error_t::BLE_ERROR_NONE) { 141 | printf("Client connected, you may now subscribe to updates\r\n"); 142 | } 143 | } 144 | 145 | void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override 146 | { 147 | printf("Client disconnected, restarting advertising\r\n"); 148 | 149 | ble_error_t error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 150 | 151 | if (error) { 152 | printf("_ble.gap().startAdvertising() failed\r\n"); 153 | return; 154 | } 155 | } 156 | 157 | private: 158 | BLE &_ble; 159 | events::EventQueue &_event_queue; 160 | ChainableGapEventHandler &_chainable_gap_event_handler; 161 | 162 | LinkLossService _link_loss_service; 163 | CurrentTimeService _current_time_service; 164 | 165 | uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 166 | ble::AdvertisingDataBuilder _adv_data_builder; 167 | }; 168 | 169 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 170 | { 171 | event_queue.call(Callback(&context->ble, &BLE::processEvents)); 172 | } 173 | 174 | int main() 175 | { 176 | mbed_trace_init(); 177 | 178 | BLE &ble = BLE::Instance(); 179 | ble.onEventsToProcess(schedule_ble_events); 180 | 181 | set_time(1256729737); // Set RTC time to Wed, 28 Oct 2009 11:35:37 182 | 183 | ExperimentalServicesDemo demo(ble, event_queue, chainable_gap_event_handler); 184 | demo.start(); 185 | 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /BLE_PeriodicAdvertising/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_PeriodicAdvertising) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_PeriodicAdvertising/README.md: -------------------------------------------------------------------------------- 1 | Demo of the periodic advertising. This requires two devices to run. Both devices run the same program. 2 | They attempt to find find each other after which they adopt complementary roles. One sets up periodic advertising. 3 | The other attempts to scan and sync with the periodic advertising. 4 | 5 | The role of the scanner device can also be performed by a BLE scanner on a smartphone. 6 | Connect to the advertiser. This will establish it as the advertiser. After you disconnect the device will begin periodic 7 | advertising. 8 | 9 | # Running the application 10 | 11 | ## Requirements 12 | 13 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 14 | 15 | Devices must support extended advertising and periodic advertising (Bluetooth version 5+). 16 | 17 | ## Building instructions 18 | 19 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 20 | -------------------------------------------------------------------------------- /BLE_PeriodicAdvertising/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_PeriodicAdvertising/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_PeriodicAdvertising/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "mbed-trace.enable": false, 6 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 7 | "cordio.trace-hci-packets": false, 8 | "cordio.trace-cordio-wsf-traces": false, 9 | "ble.trace-human-readable-enums": false 10 | }, 11 | "K64F": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NUCLEO_F401RE": { 17 | "target.components_add": ["BlueNRG_MS"], 18 | "target.features_add": ["BLE"], 19 | "target.extra_labels_add": ["CORDIO"] 20 | }, 21 | "NRF52840_DK": { 22 | "target.features_add": ["BLE"] 23 | }, 24 | "NRF52_DK": { 25 | "target.features_add": ["BLE"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BLE_PeriodicAdvertising/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2018 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "ble/BLE.h" 19 | #include "pretty_printer.h" 20 | #include "mbed-trace/mbed_trace.h" 21 | 22 | /** This example demonstrates extended and periodic advertising 23 | */ 24 | 25 | using namespace std::literals::chrono_literals; 26 | 27 | events::EventQueue event_queue; 28 | 29 | static const char DEVICE_NAME[] = "Periodic"; 30 | 31 | static const uint16_t MAX_ADVERTISING_PAYLOAD_SIZE = 50; 32 | 33 | /** Demonstrate periodic advertising and scanning and syncing with the advertising 34 | */ 35 | class PeriodicDemo : private mbed::NonCopyable, public ble::Gap::EventHandler 36 | { 37 | public: 38 | PeriodicDemo(BLE& ble, events::EventQueue& event_queue) : 39 | _ble(ble), 40 | _event_queue(event_queue), 41 | _adv_data_builder(_adv_buffer) 42 | { 43 | } 44 | 45 | ~PeriodicDemo() 46 | { 47 | if (_ble.hasInitialized()) { 48 | _ble.shutdown(); 49 | } 50 | } 51 | 52 | /** Start BLE interface initialisation */ 53 | void run() 54 | { 55 | /* handle gap events */ 56 | _ble.gap().setEventHandler(this); 57 | 58 | ble_error_t error = _ble.init(this, &PeriodicDemo::on_init_complete); 59 | if (error) { 60 | print_error(error, "Error returned by BLE::init\r\n"); 61 | return; 62 | } 63 | 64 | /* this will not return until shutdown */ 65 | _event_queue.dispatch_forever(); 66 | } 67 | 68 | private: 69 | /** This is called when BLE interface is initialised and starts the first mode */ 70 | void on_init_complete(BLE::InitializationCompleteCallbackContext *event) 71 | { 72 | if (event->error) { 73 | print_error(event->error, "Error during the initialisation\r\n"); 74 | return; 75 | } 76 | 77 | if (!_ble.gap().isFeatureSupported(ble::controller_supported_features_t::LE_EXTENDED_ADVERTISING) || 78 | !_ble.gap().isFeatureSupported(ble::controller_supported_features_t::LE_PERIODIC_ADVERTISING)) { 79 | printf("Periodic advertising not supported, cannot run example.\r\n"); 80 | return; 81 | } 82 | 83 | print_mac_address(); 84 | 85 | /* all calls are serialised on the user thread through the event queue */ 86 | start_role(); 87 | } 88 | 89 | void start_role() 90 | { 91 | /* This example is designed to be run on two boards at the same time, 92 | * depending on our role we will either be the advertiser or scanner, 93 | * until the roles are established we will cycle the roles until we find each other */ 94 | if (_role_established) { 95 | if (_is_scanner) { 96 | _event_queue.call(this, &PeriodicDemo::scan_periodic); 97 | } else { 98 | _event_queue.call(this, &PeriodicDemo::advertise_periodic); 99 | } 100 | } else { 101 | _is_scanner = !_is_scanner; 102 | 103 | if (_is_scanner) { 104 | _event_queue.call(this, &PeriodicDemo::scan); 105 | } else { 106 | _event_queue.call(this, &PeriodicDemo::advertise); 107 | } 108 | } 109 | } 110 | 111 | /** Set up and start advertising */ 112 | void advertise() 113 | { 114 | ble_error_t error; 115 | 116 | /* only create the set first time we advertise */ 117 | if (_adv_handle == ble::INVALID_ADVERTISING_HANDLE) { 118 | ble::AdvertisingParameters adv_parameters( 119 | ble::advertising_type_t::CONNECTABLE_NON_SCANNABLE_UNDIRECTED, 120 | ble::adv_interval_t(ble::millisecond_t(10)) 121 | ); 122 | 123 | adv_parameters.setUseLegacyPDU(false); 124 | 125 | error = _ble.gap().createAdvertisingSet( 126 | &_adv_handle, 127 | adv_parameters 128 | ); 129 | 130 | if (error) { 131 | print_error(error, "Gap::createAdvertisingSet() failed\r\n"); 132 | return; 133 | } 134 | 135 | _adv_data_builder.setFlags(); 136 | _adv_data_builder.setName(DEVICE_NAME); 137 | 138 | /* Set payload for the set */ 139 | error = _ble.gap().setAdvertisingPayload( 140 | _adv_handle, 141 | _adv_data_builder.getAdvertisingData() 142 | ); 143 | 144 | if (error) { 145 | print_error(error, "Gap::setAdvertisingPayload() failed\r\n"); 146 | return; 147 | } 148 | } 149 | 150 | /* since we have two boards which might start running this example at the same time 151 | * we randomise the interval of advertising to have them meet when one is advertising 152 | * and the other one is scanning (we use their random address as source of randomness) */ 153 | ble::millisecond_t random_duration_ms((2 + rand() % 5) * 1000); 154 | ble::adv_duration_t random_duration(random_duration_ms); 155 | 156 | error = _ble.gap().startAdvertising( 157 | _adv_handle, 158 | random_duration 159 | ); 160 | 161 | if (error) { 162 | print_error(error, "Gap::startAdvertising() failed\r\n"); 163 | return; 164 | } 165 | 166 | printf("Advertising started for %dms\r\n", random_duration_ms); 167 | } 168 | 169 | void advertise_periodic() 170 | { 171 | ble::AdvertisingParameters adv_parameters( 172 | ble::advertising_type_t::NON_CONNECTABLE_UNDIRECTED, 173 | ble::adv_interval_t(ble::millisecond_t(200)) 174 | ); 175 | 176 | adv_parameters.setUseLegacyPDU(false); 177 | 178 | ble_error_t error = _ble.gap().setAdvertisingParameters(_adv_handle, adv_parameters); 179 | 180 | if (error) { 181 | print_error(error, "Gap::setAdvertisingParameters() failed\r\n"); 182 | return; 183 | } 184 | 185 | /* Start advertising the set as the advertising needs to be active 186 | * before we start periodic advertising */ 187 | error = _ble.gap().startAdvertising(_adv_handle); 188 | 189 | if (error) { 190 | print_error(error, "Gap::startAdvertising() failed\r\n"); 191 | return; 192 | } 193 | 194 | /* periodic advertising will be enabled when advertising starts */ 195 | } 196 | 197 | /** Set up and start scanning */ 198 | void scan() 199 | { 200 | _is_connecting_or_syncing = false; 201 | 202 | ble::ScanParameters scan_params; 203 | scan_params.setOwnAddressType(ble::own_address_type_t::RANDOM); 204 | 205 | ble_error_t error = _ble.gap().setScanParameters(scan_params); 206 | 207 | if (error) { 208 | print_error(error, "Error caused by Gap::setScanParameters\r\n"); 209 | return; 210 | } 211 | 212 | error = _ble.gap().startScan(ble::scan_duration_t(500)); 213 | 214 | if (error) { 215 | print_error(error, "Error caused by Gap::startScan\r\n"); 216 | return; 217 | } 218 | 219 | printf("Scanning started\r\n"); 220 | } 221 | 222 | void scan_periodic() 223 | { 224 | _is_connecting_or_syncing = false; 225 | 226 | ble_error_t error = _ble.gap().startScan(); 227 | 228 | if (error) { 229 | print_error(error, "Error caused by Gap::startScan\r\n"); 230 | return; 231 | } 232 | 233 | printf("Scanning for periodic advertising started\r\n"); 234 | } 235 | 236 | /* also updates periodic advertising payload */ 237 | void update_sensor_value() 238 | { 239 | /* simulate battery level */ 240 | _battery_level--; 241 | if (_battery_level < 1) { 242 | _battery_level = 100; 243 | } 244 | 245 | /* update the level in the payload */ 246 | ble_error_t error = _adv_data_builder.setServiceData( 247 | GattService::UUID_BATTERY_SERVICE, 248 | mbed::make_Span(&_battery_level, 1) 249 | ); 250 | 251 | if (error) { 252 | print_error(error, "AdvertisingDataBuilder::setServiceData() failed\r\n"); 253 | return; 254 | } 255 | 256 | /* the data in the local host buffer has been updated but now 257 | * we have to update the data in the controller */ 258 | error = _ble.gap().setPeriodicAdvertisingPayload( 259 | _adv_handle, 260 | _adv_data_builder.getAdvertisingData() 261 | ); 262 | 263 | if (error) { 264 | print_error(error, "Gap::setPeriodicAdvertisingPayload() failed\r\n"); 265 | } 266 | } 267 | 268 | private: 269 | /* Gap::EventHandler */ 270 | 271 | void onAdvertisingStart(const ble::AdvertisingStartEvent &event) override 272 | { 273 | /* start periodic advertising only if we're already advertising after roles established */ 274 | if (_role_established) { 275 | ble_error_t error = _ble.gap().setPeriodicAdvertisingParameters( 276 | _adv_handle, 277 | ble::periodic_interval_t(100), 278 | ble::periodic_interval_t(1000) 279 | ); 280 | 281 | if (error) { 282 | print_error(error, "Gap::setPeriodicAdvertisingParameters() failed\r\n"); 283 | return; 284 | } 285 | 286 | error = _ble.gap().startPeriodicAdvertising(_adv_handle); 287 | 288 | if (error) { 289 | print_error(error, "Gap::startPeriodicAdvertising() failed\r\n"); 290 | return; 291 | } 292 | 293 | printf("Periodic advertising started\r\n"); 294 | 295 | /* tick over our fake battery data, this will also update the advertising payload */ 296 | _event_queue.call_every(1000ms, this, &PeriodicDemo::update_sensor_value); 297 | } 298 | } 299 | 300 | /** Look at scan payload to find a peer device and connect to it */ 301 | void onAdvertisingReport(const ble::AdvertisingReportEvent &event) override 302 | { 303 | /* don't bother with analysing scan result if we're already connecting */ 304 | if (_is_connecting_or_syncing) { 305 | return; 306 | } 307 | 308 | /* if we're looking for periodic advertising don't bother unless it's present */ 309 | if (_role_established && !event.isPeriodicIntervalPresent()) { 310 | return; 311 | } 312 | 313 | ble::AdvertisingDataParser adv_parser(event.getPayload()); 314 | 315 | /* parse the advertising payload, looking for a discoverable device */ 316 | while (adv_parser.hasNext()) { 317 | ble::AdvertisingDataParser::element_t field = adv_parser.next(); 318 | 319 | /* identify peer by name */ 320 | if (field.type == ble::adv_data_type_t::COMPLETE_LOCAL_NAME && 321 | field.value.size() == strlen(DEVICE_NAME) && 322 | (memcmp(field.value.data(), DEVICE_NAME, field.value.size()) == 0)) { 323 | /* if we haven't established our roles connect, otherwise sync with advertising */ 324 | if (_role_established) { 325 | printf("We found the peer, syncing with SID %d" 326 | " and periodic interval %dms\r\n", 327 | event.getSID(), event.getPeriodicInterval().valueInMs()); 328 | 329 | ble_error_t error = _ble.gap().createSync( 330 | event.getPeerAddressType(), 331 | event.getPeerAddress(), 332 | event.getSID(), 333 | 2, 334 | ble::sync_timeout_t(ble::millisecond_t(5000)) 335 | ); 336 | 337 | if (error) { 338 | print_error(error, "Error caused by Gap::createSync\r\n"); 339 | return; 340 | } 341 | } else { 342 | printf("We found the peer, connecting\r\n"); 343 | 344 | ble_error_t error = _ble.gap().connect( 345 | event.getPeerAddressType(), 346 | event.getPeerAddress(), 347 | ble::ConnectionParameters() // use the default connection parameters 348 | ); 349 | 350 | if (error) { 351 | print_error(error, "Error caused by Gap::connect\r\n"); 352 | return; 353 | } 354 | } 355 | 356 | /* we may have already scan events waiting to be processed 357 | * so we need to remember that we are already connecting 358 | * or syncing and ignore them */ 359 | _is_connecting_or_syncing = true; 360 | 361 | return; 362 | } 363 | } 364 | } 365 | 366 | void onAdvertisingEnd(const ble::AdvertisingEndEvent &event) override 367 | { 368 | printf("Advertising ended.\r\n"); 369 | if (!event.isConnected()) { 370 | printf("No device connected to us, switch modes.\r\n"); 371 | start_role(); 372 | } 373 | } 374 | 375 | void onScanTimeout(const ble::ScanTimeoutEvent&) override 376 | { 377 | printf("Scanning ended\r\n"); 378 | if (!_is_connecting_or_syncing) { 379 | printf("Failed to find peer\r\n"); 380 | start_role(); 381 | } 382 | } 383 | 384 | /** This is called by Gap to notify the application we connected */ 385 | void onConnectionComplete(const ble::ConnectionCompleteEvent &event) override 386 | { 387 | if (event.getStatus() == BLE_ERROR_NONE) { 388 | printf("Connected to: "); 389 | print_address(event.getPeerAddress().data()); 390 | printf("Roles established\r\n"); 391 | _role_established = true; 392 | 393 | if (_is_scanner) { 394 | printf("I will synchronise with periodic advertising\r\n"); 395 | _event_queue.call_in( 396 | 1000ms, 397 | [this, handle = event.getConnectionHandle()] { 398 | _ble.gap().disconnect( 399 | handle, 400 | ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) 401 | ); 402 | } 403 | ); 404 | } else { 405 | printf("I will advertise periodic advertising\r\n"); 406 | } 407 | } else { 408 | printf("Failed to connect\r\n"); 409 | start_role(); 410 | } 411 | } 412 | 413 | /** This is called by Gap to notify the application we disconnected */ 414 | void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override 415 | { 416 | printf("Disconnected\r\n"); 417 | start_role(); 418 | } 419 | 420 | /** Called when first advertising packet in periodic advertising is received. */ 421 | void onPeriodicAdvertisingSyncEstablished(const ble::PeriodicAdvertisingSyncEstablishedEvent &event) override 422 | { 423 | if (event.getStatus() == BLE_ERROR_NONE) { 424 | printf("Synced with periodic advertising\r\n"); 425 | _sync_handle = event.getSyncHandle(); 426 | } else { 427 | printf("Sync with periodic advertising failed\r\n"); 428 | } 429 | } 430 | 431 | /** Called when a periodic advertising packet is received. */ 432 | void onPeriodicAdvertisingReport(const ble::PeriodicAdvertisingReportEvent &event) override 433 | { 434 | ble::AdvertisingDataParser adv_parser(event.getPayload()); 435 | 436 | /* parse the advertising payload, looking for a battery level */ 437 | while (adv_parser.hasNext()) { 438 | ble::AdvertisingDataParser::element_t field = adv_parser.next(); 439 | 440 | if (field.type == ble::adv_data_type_t::SERVICE_DATA) { 441 | GattService::UUID_BATTERY_SERVICE; 442 | if (*((uint16_t*)field.value.data()) != GattService::UUID_BATTERY_SERVICE) { 443 | printf("Unexpected service data\r\n"); 444 | } else { 445 | /* battery level is right after the UUID */ 446 | const uint8_t *battery_level = field.value.data() + sizeof(uint16_t); 447 | printf("Peer battery level: %d\r\n", *battery_level); 448 | } 449 | } 450 | } 451 | } 452 | 453 | /** Called when a periodic advertising sync has been lost. */ 454 | void onPeriodicAdvertisingSyncLoss(const ble::PeriodicAdvertisingSyncLoss &event) override 455 | { 456 | printf("Sync to periodic advertising lost\r\n"); 457 | _sync_handle = ble::INVALID_ADVERTISING_HANDLE; 458 | _event_queue.call(this, &PeriodicDemo::scan_periodic); 459 | } 460 | 461 | private: 462 | BLE &_ble; 463 | events::EventQueue &_event_queue; 464 | 465 | uint8_t _adv_buffer[MAX_ADVERTISING_PAYLOAD_SIZE]; 466 | ble::AdvertisingDataBuilder _adv_data_builder; 467 | 468 | ble::advertising_handle_t _adv_handle = ble::INVALID_ADVERTISING_HANDLE; 469 | ble::periodic_sync_handle_t _sync_handle = ble::INVALID_ADVERTISING_HANDLE; 470 | 471 | uint8_t _battery_level = 100; 472 | 473 | bool _is_scanner = false; 474 | bool _is_connecting_or_syncing = false; 475 | bool _role_established = false; 476 | }; 477 | 478 | /** Schedule processing of events from the BLE middleware in the event queue. */ 479 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 480 | { 481 | event_queue.call(Callback(&context->ble, &BLE::processEvents)); 482 | } 483 | 484 | int main() 485 | { 486 | mbed_trace_init(); 487 | 488 | BLE &ble = BLE::Instance(); 489 | 490 | /* this will inform us off all events so we can schedule their handling 491 | * using our event queue */ 492 | ble.onEventsToProcess(schedule_ble_events); 493 | 494 | /* look for other device and then settle on a role and sync periodic advertising */ 495 | PeriodicDemo demo(ble, event_queue); 496 | 497 | demo.run(); 498 | 499 | return 0; 500 | } 501 | -------------------------------------------------------------------------------- /BLE_SecurityAndPrivacy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_SecurityAndPrivacy) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_subdirectory(mbed-os-ble-utils) 17 | 18 | add_executable(${APP_TARGET}) 19 | 20 | target_include_directories(${APP_TARGET} 21 | PRIVATE 22 | ./source 23 | ) 24 | 25 | target_sources(${APP_TARGET} 26 | PRIVATE 27 | source/main.cpp 28 | ) 29 | 30 | target_link_libraries(${APP_TARGET} 31 | PRIVATE 32 | mbed-os 33 | mbed-events 34 | mbed-ble 35 | mbed-ble-utils 36 | ) 37 | 38 | mbed_set_post_build(${APP_TARGET}) 39 | 40 | option(VERBOSE_BUILD "Have a verbose build process") 41 | if(VERBOSE_BUILD) 42 | set(CMAKE_VERBOSE_MAKEFILE ON) 43 | endif() 44 | -------------------------------------------------------------------------------- /BLE_SecurityAndPrivacy/README.md: -------------------------------------------------------------------------------- 1 | # Example using Security and Privacy 2 | 3 | Demonstration of Security Manager features. It shows how pairing and encryption works and how to use private addresses 4 | when advertising and connecting and how filtering ties in with these operations. 5 | 6 | The application will start by repeatedly trying to connect to the same application running on another board. 7 | It will do this by advertising and scanning for random intervals waiting until the difference in intervals 8 | between the boards will make them meet when one is advertising and the other scanning. 9 | 10 | Two devices will be operating using resolvable private addresses. The application will connect to the peer and pair. 11 | 12 | Subsequent connections will turn on filtering based on peers identity addresses. 13 | 14 | # Running the application 15 | 16 | ## Requirements 17 | 18 | Application requires two devices. Each one should be loaded with the same example. You may try to emulate the second 19 | device with your phone. The demo advertise with the name "SecurityDemo". You must advertise with the same name. 20 | 21 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 22 | 23 | ## Building instructions 24 | 25 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 26 | 27 | Note: example currently doesn't use ST provided stack and instead uses a Cordio port for the ST. 28 | -------------------------------------------------------------------------------- /BLE_SecurityAndPrivacy/mbed-os-ble-utils.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os-ble-utils/ 2 | -------------------------------------------------------------------------------- /BLE_SecurityAndPrivacy/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_SecurityAndPrivacy/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "filesystem-support": false 4 | }, 5 | "target_overrides": { 6 | "*": { 7 | "platform.stdio-baud-rate": 115200, 8 | "mbed-trace.enable": false, 9 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 10 | "cordio.trace-hci-packets": false, 11 | "cordio.trace-cordio-wsf-traces": false, 12 | "ble.trace-human-readable-enums": false 13 | 14 | }, 15 | "K64F": { 16 | "target.components_add": ["BlueNRG_MS"], 17 | "target.features_add": ["BLE"], 18 | "target.extra_labels_add": ["CORDIO"] 19 | }, 20 | "NUCLEO_F401RE": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NRF52840_DK": { 26 | "target.features_add": ["BLE"] 27 | }, 28 | "NRF52_DK": { 29 | "target.features_add": ["BLE"] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /BLE_SecurityAndPrivacy/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "ble/BLE.h" 19 | #include "pretty_printer.h" 20 | #include "mbed-trace/mbed_trace.h" 21 | 22 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT 23 | #include "LittleFileSystem.h" 24 | #include "HeapBlockDevice.h" 25 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT 26 | 27 | /** This example demonstrates all the basic setup required for pairing and setting 28 | * up link security both as a central and peripheral. It also demonstrates privacy 29 | * features in Gap. It shows how to use private addresses when advertising and 30 | * connecting and how filtering ties in with these operations. 31 | * 32 | * The application will start by repeatedly trying to connect to the same 33 | * application running on another board. It will do this by advertising and 34 | * scanning for random intervals waiting until the difference in intervals 35 | * between the boards will make them meet when one is advertising and the 36 | * other scanning. 37 | * 38 | * Two devices will be operating using random resolvable addresses. The 39 | * applications will connect to the peer and pair. It will attempt bonding 40 | * to store the IRK that resolve the peer. Subsequent connections will 41 | * turn on filtering based on stored IRKs. 42 | */ 43 | 44 | static const char DEVICE_NAME[] = "SecurityDemo"; 45 | 46 | using std::literals::chrono_literals::operator""ms; 47 | 48 | /* Delay between steps */ 49 | static const std::chrono::milliseconds delay = 3000ms; 50 | 51 | /** Base class for both peripheral and central. The same class that provides 52 | * the logic for the application also implements the SecurityManagerEventHandler 53 | * which is the interface used by the Security Manager to communicate events 54 | * back to the applications. You can provide overrides for a selection of events 55 | * your application is interested in. 56 | */ 57 | class SecurityDemo : private mbed::NonCopyable, 58 | public SecurityManager::EventHandler, 59 | public ble::Gap::EventHandler 60 | { 61 | public: 62 | SecurityDemo(BLE &ble, events::EventQueue &event_queue) : 63 | _ble(ble), _event_queue(event_queue) { }; 64 | 65 | virtual ~SecurityDemo() 66 | { 67 | _ble.onEventsToProcess(nullptr); 68 | }; 69 | 70 | /** Start BLE interface initialisation */ 71 | void run() 72 | { 73 | /* this will inform us off all events so we can schedule their handling 74 | * using our event queue */ 75 | _ble.onEventsToProcess(makeFunctionPointer(this, &SecurityDemo::schedule_ble_events)); 76 | 77 | /* handle gap events */ 78 | _ble.gap().setEventHandler(this); 79 | 80 | if (_ble.hasInitialized()) { 81 | /* ble instance already initialised, skip init and start activity */ 82 | start(); 83 | } else { 84 | ble_error_t error = _ble.init(this, &SecurityDemo::on_init_complete); 85 | 86 | if (error) { 87 | print_error(error, "Error returned by BLE::init.\r\n"); 88 | return; 89 | } 90 | } 91 | 92 | /* this will not return until shutdown */ 93 | _event_queue.dispatch_forever(); 94 | }; 95 | 96 | /** Override to start chosen activity when the system starts */ 97 | virtual void start() = 0; 98 | 99 | /* callbacks */ 100 | 101 | /** This is called when BLE interface is initialised and starts the demonstration */ 102 | void on_init_complete(BLE::InitializationCompleteCallbackContext *event) 103 | { 104 | ble_error_t error; 105 | 106 | if (event->error) { 107 | printf("Error during the initialisation\r\n"); 108 | return; 109 | } 110 | 111 | /* for use by tools we print out own address and also use it 112 | * to seed RNG as the address is unique */ 113 | print_local_address(); 114 | 115 | 116 | /* This path will be used to store bonding information but will fallback 117 | * to storing in memory if file access fails (for example due to lack of a filesystem) */ 118 | const char* db_path = "/fs/bt_sec_db"; 119 | 120 | error = _ble.securityManager().init( 121 | /* enableBonding */ true, 122 | /* requireMITM */ false, 123 | /* iocaps */ SecurityManager::IO_CAPS_NONE, 124 | /* passkey */ nullptr, 125 | /* signing */ false, 126 | /* dbFilepath */ db_path 127 | ); 128 | 129 | if (error) { 130 | print_error(error, "Error during initialising security manager\r\n"); 131 | return; 132 | } 133 | 134 | /* This tells the stack to generate a pairingRequest event which will require 135 | * this application to respond before pairing can proceed. Setting it to false 136 | * will automatically accept pairing. */ 137 | _ble.securityManager().setPairingRequestAuthorisation(true); 138 | 139 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT 140 | error = _ble.securityManager().preserveBondingStateOnReset(true); 141 | 142 | if (error) { 143 | print_error(error, "Error during preserveBondingStateOnReset %d\r\n"); 144 | } 145 | #endif // MBED_CONF_APP_FILESYSTEM_SUPPORT 146 | 147 | /* this demo switches between being master and slave */ 148 | _ble.securityManager().setHintFutureRoleReversal(true); 149 | 150 | /* Tell the security manager to use methods in this class to inform us 151 | * of any events. Class needs to implement SecurityManagerEventHandler. */ 152 | _ble.securityManager().setSecurityManagerEventHandler(this); 153 | 154 | /* gap events also handled by this class */ 155 | _ble.gap().setEventHandler(this); 156 | 157 | error = _ble.gap().enablePrivacy(true); 158 | if (error) { 159 | print_error(error, "Error enabling privacy.\r\n"); 160 | return; 161 | } 162 | 163 | /* continuation is in onPrivacyEnabled() */ 164 | }; 165 | 166 | /** Schedule processing of events from the BLE in the event queue. */ 167 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 168 | { 169 | _event_queue.call([&ble_instance = context->ble] { ble_instance.processEvents(); }); 170 | }; 171 | 172 | private: 173 | /* SecurityManager Event handler */ 174 | 175 | /** Respond to a pairing request. This will be called by the stack 176 | * when a pairing request arrives and expects the application to 177 | * call acceptPairingRequest or cancelPairingRequest */ 178 | void pairingRequest(ble::connection_handle_t connectionHandle) override 179 | { 180 | printf("Pairing requested - authorising\r\n"); 181 | _ble.securityManager().acceptPairingRequest(connectionHandle); 182 | } 183 | 184 | /** Inform the application of pairing */ 185 | void pairingResult( 186 | ble::connection_handle_t connectionHandle, 187 | SecurityManager::SecurityCompletionStatus_t result 188 | ) override 189 | { 190 | if (result == SecurityManager::SEC_STATUS_SUCCESS) { 191 | printf("Pairing successful\r\n"); 192 | _bonded = true; 193 | } else { 194 | printf("Pairing failed\r\n"); 195 | } 196 | 197 | _event_queue.call_in( 198 | delay, 199 | [this, connectionHandle] { 200 | _ble.gap().disconnect(connectionHandle, ble::local_disconnection_reason_t::USER_TERMINATION); 201 | } 202 | ); 203 | } 204 | 205 | /** Inform the application of change in encryption status. This will be 206 | * communicated through the serial port */ 207 | void linkEncryptionResult(ble::connection_handle_t connectionHandle, ble::link_encryption_t result) override 208 | { 209 | if (result == ble::link_encryption_t::ENCRYPTED) { 210 | printf("Link ENCRYPTED\r\n"); 211 | } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { 212 | printf("Link ENCRYPTED_WITH_MITM\r\n"); 213 | } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) { 214 | printf("Link NOT_ENCRYPTED\r\n"); 215 | } 216 | } 217 | 218 | void onPrivacyEnabled() override 219 | { 220 | /* all initialisation complete, start our main activity */ 221 | start(); 222 | } 223 | 224 | /* Gap Event handler */ 225 | 226 | /** This is called by Gap to notify the application we connected */ 227 | void onConnectionComplete(const ble::ConnectionCompleteEvent &event) override 228 | { 229 | printf("Connected to peer: "); 230 | print_address(event.getPeerAddress().data()); 231 | if (event.getPeerResolvablePrivateAddress() != ble::address_t()) { 232 | printf("Peer random resolvable address: "); 233 | print_address(event.getPeerResolvablePrivateAddress().data()); 234 | } 235 | 236 | _handle = event.getConnectionHandle(); 237 | 238 | if (_bonded) { 239 | /* disconnect in 2s */ 240 | _event_queue.call_in( 241 | delay, 242 | [this] { 243 | _ble.gap().disconnect(_handle, ble::local_disconnection_reason_t::USER_TERMINATION); 244 | } 245 | ); 246 | } else { 247 | /* start bonding */ 248 | ble_error_t error = _ble.securityManager().setLinkSecurity( 249 | _handle, 250 | SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM 251 | ); 252 | if (error) { 253 | print_error(error, "Failed to set link security\r\n"); 254 | _ble.gap().disconnect(_handle, ble::local_disconnection_reason_t::USER_TERMINATION); 255 | } 256 | } 257 | }; 258 | 259 | /** This is called by Gap to notify the application we disconnected */ 260 | void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override 261 | { 262 | if (_bonded) { 263 | /* we have connected to and bonded with the other device, from now 264 | * on we will use the second start function and stay in the same role 265 | * as peripheral or central */ 266 | printf("Disconnected.\r\n\r\n"); 267 | _event_queue.call_in(delay, [this] { start(); }); 268 | } else { 269 | printf("Failed to bond.\r\n"); 270 | _event_queue.break_dispatch(); 271 | } 272 | }; 273 | 274 | void onScanTimeout(const ble::ScanTimeoutEvent &) override 275 | { 276 | /* if we failed to find the other device, abort so that we change roles */ 277 | printf("Haven't seen other device, switch modes.\r\n"); 278 | _event_queue.break_dispatch(); 279 | } 280 | 281 | void onAdvertisingEnd(const ble::AdvertisingEndEvent &event) override 282 | { 283 | if (!event.isConnected()) { 284 | printf("No device connected to us, switch modes.\r\n"); 285 | _event_queue.break_dispatch(); 286 | } 287 | } 288 | 289 | private: 290 | void print_local_address() 291 | { 292 | /* show what address we are using now */ 293 | ble::own_address_type_t addr_type; 294 | ble::address_t addr; 295 | _ble.gap().getAddress(addr_type, addr); 296 | printf("Device address: "); 297 | print_address(addr); 298 | static bool _seeded = false; 299 | if (!_seeded) { 300 | _seeded = true; 301 | /* use the address as a seed */ 302 | uint8_t* random_data = addr.data(); 303 | srand(*((unsigned int*)random_data)); 304 | } 305 | } 306 | 307 | protected: 308 | BLE &_ble; 309 | events::EventQueue &_event_queue; 310 | ble::connection_handle_t _handle = 0; 311 | bool _bonded = false; 312 | }; 313 | 314 | /** A peripheral device will advertise and accept the connections */ 315 | class SecurityPeripheral : public SecurityDemo { 316 | public: 317 | SecurityPeripheral(BLE &ble, events::EventQueue &event_queue) 318 | : SecurityDemo(ble, event_queue) { } 319 | 320 | /** Set up and start advertising accepting anyone */ 321 | void start() override 322 | { 323 | ble::peripheral_privacy_configuration_t privacy_configuration = { 324 | /* use_non_resolvable_random_address */ false, 325 | ble::peripheral_privacy_configuration_t::PERFORM_PAIRING_PROCEDURE 326 | }; 327 | 328 | if (_bonded) { 329 | /** advertise and filter based on known devices */ 330 | printf("We are bonded, we will only accept known devices\r\n"); 331 | privacy_configuration.resolution_strategy = 332 | ble::peripheral_privacy_configuration_t::REJECT_NON_RESOLVED_ADDRESS; 333 | } 334 | 335 | _ble.gap().setPeripheralPrivacyConfiguration(&privacy_configuration); 336 | 337 | start_advertising(); 338 | }; 339 | 340 | private: 341 | void start_advertising() 342 | { 343 | uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 344 | /* use the helper to build the payload */ 345 | ble::AdvertisingDataBuilder adv_data_builder(adv_buffer); 346 | 347 | adv_data_builder.setFlags(); 348 | adv_data_builder.setName(DEVICE_NAME); 349 | 350 | /* Set payload for the set */ 351 | ble_error_t error = _ble.gap().setAdvertisingPayload( 352 | ble::LEGACY_ADVERTISING_HANDLE, 353 | adv_data_builder.getAdvertisingData() 354 | ); 355 | 356 | if (error) { 357 | print_error(error, "Gap::setAdvertisingPayload() failed"); 358 | return; 359 | } 360 | 361 | ble::AdvertisingParameters adv_parameters( 362 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED 363 | ); 364 | 365 | error = _ble.gap().setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_parameters); 366 | 367 | if (error) { 368 | print_error(error, "Gap::setAdvertisingParameters() failed"); 369 | return; 370 | } 371 | 372 | if (_bonded) { 373 | /* if we bonded it means we have found the other device, from now on 374 | * wait at each step until completion */ 375 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 376 | } else { 377 | /* since we have two boards which might start running this example at the same time 378 | * we randomise the interval of advertising to have them meet when one is advertising 379 | * and the other one is scanning (we use their random address as source of randomness) */ 380 | ble::millisecond_t random_duration_ms((5 + rand() % 6) * 1000); 381 | ble::adv_duration_t random_duration(random_duration_ms); 382 | 383 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE, random_duration); 384 | } 385 | 386 | if (error) { 387 | print_error(error, "Gap::startAdvertising() failed"); 388 | return; 389 | } 390 | 391 | printf("Advertising...\r\n"); 392 | } 393 | 394 | }; 395 | 396 | /** A central device will scan and connect to a peer. */ 397 | class SecurityCentral : public SecurityDemo { 398 | public: 399 | SecurityCentral(BLE &ble, events::EventQueue &event_queue) 400 | : SecurityDemo(ble, event_queue) { } 401 | 402 | /** start scanning and attach a callback that will handle advertisements 403 | * and scan requests responses */ 404 | void start() override 405 | { 406 | ble::central_privacy_configuration_t privacy_configuration = { 407 | /* use_non_resolvable_random_address */ false, 408 | ble::central_privacy_configuration_t::DO_NOT_RESOLVE 409 | }; 410 | if (_bonded) { 411 | printf("We are bonded - we will only see known devices\r\n"); 412 | privacy_configuration.resolution_strategy = ble::central_privacy_configuration_t::RESOLVE_AND_FILTER; 413 | } 414 | 415 | _ble.gap().setCentralPrivacyConfiguration(&privacy_configuration); 416 | 417 | start_scanning(); 418 | } 419 | 420 | /* helper functions */ 421 | private: 422 | bool start_scanning() 423 | { 424 | ble_error_t error; 425 | ble::ScanParameters scan_params; 426 | _ble.gap().setScanParameters(scan_params); 427 | 428 | _is_connecting = false; 429 | 430 | if (_bonded) { 431 | /* if we bonded it means we have found the other device, from now on 432 | * wait at each step until completion */ 433 | error = _ble.gap().startScan(ble::scan_duration_t::forever()); 434 | } else { 435 | /* otherwise only scan for a limited time before changing roles again 436 | * if we fail to find the other device */ 437 | error = _ble.gap().startScan(ble::scan_duration_t(ble::millisecond_t(5000))); 438 | } 439 | 440 | if (error) { 441 | print_error(error, "Error during Gap::startScan\r\n"); 442 | return false; 443 | } 444 | 445 | printf("Scanning...\r\n"); 446 | 447 | return true; 448 | } 449 | 450 | private: 451 | /* Event handler */ 452 | 453 | /** Look at scan payload to find a peer device and connect to it */ 454 | void onAdvertisingReport(const ble::AdvertisingReportEvent &event) override 455 | { 456 | /* don't bother with analysing scan result if we're already connecting */ 457 | if (_is_connecting) { 458 | return; 459 | } 460 | 461 | ble::AdvertisingDataParser adv_data(event.getPayload()); 462 | 463 | /* parse the advertising payload, looking for a discoverable device */ 464 | while (adv_data.hasNext()) { 465 | ble::AdvertisingDataParser::element_t field = adv_data.next(); 466 | 467 | /* connect to a known device by name */ 468 | if (field.type == ble::adv_data_type_t::COMPLETE_LOCAL_NAME && 469 | field.value.size() == strlen(DEVICE_NAME) && 470 | (memcmp(field.value.data(), DEVICE_NAME, field.value.size()) == 0)) { 471 | 472 | printf("We found a connectable device: \r\n"); 473 | print_address(event.getPeerAddress().data()); 474 | 475 | ble_error_t error = _ble.gap().stopScan(); 476 | 477 | if (error) { 478 | print_error(error, "Error caused by Gap::stopScan"); 479 | return; 480 | } 481 | 482 | error = _ble.gap().connect( 483 | event.getPeerAddressType(), 484 | event.getPeerAddress(), 485 | ble::ConnectionParameters() 486 | ); 487 | 488 | printf("Connecting...\r\n"); 489 | 490 | if (error) { 491 | print_error(error, "Error caused by Gap::connect"); 492 | return; 493 | } 494 | 495 | /* we may have already scan events waiting 496 | * to be processed so we need to remember 497 | * that we are already connecting and ignore them */ 498 | _is_connecting = true; 499 | 500 | return; 501 | } 502 | } 503 | } 504 | 505 | private: 506 | bool _is_connecting = false; 507 | }; 508 | 509 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT 510 | bool create_filesystem() 511 | { 512 | static LittleFileSystem fs("fs"); 513 | 514 | /* replace this with any physical block device your board supports (like an SD card) */ 515 | static HeapBlockDevice bd(4096, 256); 516 | 517 | int err = bd.init(); 518 | 519 | if (err) { 520 | return false; 521 | } 522 | 523 | err = bd.erase(0, bd.size()); 524 | 525 | if (err) { 526 | return false; 527 | } 528 | 529 | err = fs.mount(&bd); 530 | 531 | if (err) { 532 | /* Reformat if we can't mount the filesystem */ 533 | printf("No filesystem found, formatting...\r\n"); 534 | 535 | err = fs.reformat(&bd); 536 | 537 | if (err) { 538 | return false; 539 | } 540 | } 541 | 542 | return true; 543 | } 544 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT 545 | 546 | int main() 547 | { 548 | mbed_trace_init(); 549 | 550 | BLE& ble = BLE::Instance(); 551 | events::EventQueue queue; 552 | 553 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT 554 | /* if filesystem creation fails or there is no filesystem the security manager 555 | * will fallback to storing the security database in memory */ 556 | if (!create_filesystem()) { 557 | printf("Filesystem creation failed, will use memory storage\r\n"); 558 | } 559 | #endif 560 | 561 | while(true) { 562 | { 563 | printf("\r\n * Device is a peripheral *\r\n\r\n"); 564 | SecurityPeripheral peripheral(ble, queue); 565 | peripheral.run(); 566 | } 567 | { 568 | printf("\r\n * Device is a central *\r\n\r\n"); 569 | SecurityCentral central(ble, queue); 570 | central.run(); 571 | } 572 | } 573 | 574 | return 0; 575 | } 576 | -------------------------------------------------------------------------------- /BLE_SupportedFeatures/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 ARM Limited. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) 5 | 6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") 7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") 8 | set(APP_TARGET BLE_SupportedFeatures) 9 | 10 | include(${MBED_PATH}/tools/cmake/app.cmake) 11 | 12 | project(${APP_TARGET}) 13 | 14 | add_subdirectory(${MBED_PATH}) 15 | 16 | add_executable(${APP_TARGET}) 17 | 18 | target_include_directories(${APP_TARGET} 19 | PRIVATE 20 | ./source 21 | ) 22 | 23 | target_sources(${APP_TARGET} 24 | PRIVATE 25 | source/main.cpp 26 | ) 27 | 28 | target_link_libraries(${APP_TARGET} 29 | PRIVATE 30 | mbed-os 31 | mbed-events 32 | mbed-ble 33 | ) 34 | 35 | mbed_set_post_build(${APP_TARGET}) 36 | 37 | option(VERBOSE_BUILD "Have a verbose build process") 38 | if(VERBOSE_BUILD) 39 | set(CMAKE_VERBOSE_MAKEFILE ON) 40 | endif() 41 | -------------------------------------------------------------------------------- /BLE_SupportedFeatures/mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/ 2 | -------------------------------------------------------------------------------- /BLE_SupportedFeatures/mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200 5 | }, 6 | "K64F": { 7 | "target.components_add": ["BlueNRG_MS"], 8 | "target.features_add": ["BLE"], 9 | "target.extra_labels_add": ["CORDIO"] 10 | }, 11 | "NUCLEO_F401RE": { 12 | "target.components_add": ["BlueNRG_MS"], 13 | "target.features_add": ["BLE"], 14 | "target.extra_labels_add": ["CORDIO"] 15 | }, 16 | "NRF52840_DK": { 17 | "target.features_add": ["BLE"] 18 | }, 19 | "NRF52_DK": { 20 | "target.features_add": ["BLE"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BLE_SupportedFeatures/readme.md: -------------------------------------------------------------------------------- 1 | # BLE Supported Features 2 | 3 | This application will list BLE features supported by your device. Knowing which features 4 | are supported, might have an influence on how exactly you implement BLE feature of your applications. 5 | 6 | # Running the application 7 | 8 | ## Requirements 9 | 10 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 11 | 12 | ## Building instructions 13 | 14 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/mbed-os-example-ble/blob/master/README.md). 15 | 16 | ## Checking for success 17 | 18 | After flashing your device open up a serial monitor and start your device to find out which optional BLE 19 | features it supports. 20 | -------------------------------------------------------------------------------- /BLE_SupportedFeatures/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2021 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "ble/BLE.h" 19 | #include "mbed-trace/mbed_trace.h" 20 | 21 | static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); 22 | 23 | class SupportedFeatures : ble::Gap::EventHandler { 24 | public: 25 | SupportedFeatures(BLE &ble, events::EventQueue &event_queue) : 26 | _ble(ble), 27 | _event_queue(event_queue) 28 | { 29 | } 30 | 31 | void start() 32 | { 33 | _ble.init(this, &SupportedFeatures::on_init_complete); 34 | 35 | _event_queue.dispatch_forever(); 36 | } 37 | 38 | private: 39 | /** Callback triggered when the ble initialization process has finished */ 40 | void on_init_complete(BLE::InitializationCompleteCallbackContext *params) 41 | { 42 | if (params->error != BLE_ERROR_NONE) { 43 | printf("Ble initialization failed."); 44 | return; 45 | } 46 | 47 | /* display basic info and optional BLE features supported by our device */ 48 | 49 | printf("\r\nList of optional BLE features that are supported/unsupported by this board:\r\n"); 50 | feature_support("LE_ENCRYPTION", ble::controller_supported_features_t::LE_ENCRYPTION); 51 | feature_support("CONNECTION_PARAMETERS_REQUEST_PROCEDURE", ble::controller_supported_features_t::CONNECTION_PARAMETERS_REQUEST_PROCEDURE); 52 | feature_support("EXTENDED_REJECT_INDICATION", ble::controller_supported_features_t::EXTENDED_REJECT_INDICATION); 53 | feature_support("SLAVE_INITIATED_FEATURES_EXCHANGE", ble::controller_supported_features_t::SLAVE_INITIATED_FEATURES_EXCHANGE); 54 | feature_support("SLAVE_INITIATED_FEATURES_EXCHANGE", ble::controller_supported_features_t::SLAVE_INITIATED_FEATURES_EXCHANGE); 55 | feature_support("LE_PING", ble::controller_supported_features_t::LE_PING); 56 | feature_support("LE_DATA_PACKET_LENGTH_EXTENSION", ble::controller_supported_features_t::LE_DATA_PACKET_LENGTH_EXTENSION); 57 | feature_support("LL_PRIVACY", ble::controller_supported_features_t::LL_PRIVACY); 58 | feature_support("EXTENDED_SCANNER_FILTER_POLICIES", ble::controller_supported_features_t::EXTENDED_SCANNER_FILTER_POLICIES); 59 | feature_support("LE_2M_PHY", ble::controller_supported_features_t::LE_2M_PHY); 60 | feature_support("STABLE_MODULATION_INDEX_TRANSMITTER", ble::controller_supported_features_t::STABLE_MODULATION_INDEX_TRANSMITTER); 61 | feature_support("STABLE_MODULATION_INDEX_RECEIVER", ble::controller_supported_features_t::STABLE_MODULATION_INDEX_RECEIVER); 62 | feature_support("LE_CODED_PHY", ble::controller_supported_features_t::LE_CODED_PHY); 63 | feature_support("LE_EXTENDED_ADVERTISING", ble::controller_supported_features_t::LE_EXTENDED_ADVERTISING); 64 | feature_support("LE_PERIODIC_ADVERTISING", ble::controller_supported_features_t::LE_PERIODIC_ADVERTISING); 65 | feature_support("CHANNEL_SELECTION_ALGORITHM_2", ble::controller_supported_features_t::CHANNEL_SELECTION_ALGORITHM_2); 66 | feature_support("LE_POWER_CLASS", ble::controller_supported_features_t::LE_POWER_CLASS); 67 | } 68 | 69 | private: 70 | /* pretty prints feature support */ 71 | void feature_support(const char* feature_name, ble::controller_supported_features_t feature) 72 | { 73 | const bool supported = _ble.gap().isFeatureSupported(feature); 74 | 75 | if (supported) { 76 | printf("+ %s feature supported\r\n", feature_name); 77 | } else { 78 | printf("- %s feature not supported\r\n", feature_name); 79 | } 80 | } 81 | 82 | private: 83 | BLE &_ble; 84 | events::EventQueue &_event_queue; 85 | }; 86 | 87 | /* Schedule processing of events from the BLE middleware in the event queue. */ 88 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 89 | { 90 | event_queue.call(mbed::Callback(&context->ble, &BLE::processEvents)); 91 | } 92 | 93 | int main() 94 | { 95 | mbed_trace_init(); 96 | 97 | BLE &ble = BLE::Instance(); 98 | ble.onEventsToProcess(schedule_ble_events); 99 | 100 | SupportedFeatures demo(ble, event_queue); 101 | demo.start(); 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Mbed OS 2 | 3 | Mbed OS is an open-source, device software platform for the Internet of Things. Contributions are an important part of the platform, and our goal is to make it as simple as possible to become a contributor. 4 | 5 | To encourage productive collaboration, as well as robust, consistent and maintainable code, we have a set of guidelines for [contributing to Mbed OS](https://os.mbed.com/docs/mbed-os/latest/contributing/index.html). 6 | 7 | ## Branches 8 | 9 | `Master` branch is for releases only. Please target the `development` branch for all your PRs. 10 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | // This is internal file to run tests in internal Jenkins 2 | ble_ci.run_job() 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](./resources/official_armmbed_example_badge.png) 2 | # BLE Examples 3 | 4 | This repo contains a collection of BLE example applications based on Mbed OS. Each example subdirectory contains a separate Mbed OS project, along with a description of the example and additional instructions for running it. 5 | 6 | You can build each project with all supported [Mbed OS build tools](https://os.mbed.com/docs/mbed-os/latest/tools/index.html). However, this file specifically refers to the command-line interface tools, [Arm Mbed CLI 1](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli) and [Mbed CLI 2](https://github.com/ARMmbed/mbed-tools#installation). 7 | 8 | The [BLE documentation](https://os.mbed.com/docs/latest/reference/bluetooth.html) describes the BLE APIs on Mbed OS. 9 | 10 | ## Mbed OS build tools 11 | 12 | ### Mbed CLI 2 13 | Starting with version 6.5, Mbed OS uses Mbed CLI 2. It uses Ninja as a build system, and CMake to generate the build environment and manage the build process in a compiler-independent manner. If you are working with Mbed OS version prior to 6.5 then check the section [Mbed CLI 1](#mbed-cli-1). 14 | 15 | [Install Mbed CLI 2](https://os.mbed.com/docs/mbed-os/latest/build-tools/install-or-upgrade.html). 16 | 17 | ### Mbed CLI 1 18 | [Install Mbed CLI 1](https://os.mbed.com/docs/mbed-os/latest/quick-start/offline-with-mbed-cli.html). 19 | 20 | ## Pre-Requisites 21 | 22 | 23 | In order to use BLE in Mbed OS you need one of the following hardware combinations: 24 | 25 | * A supported target, such as the [NUCLEO-F401RE](https://os.mbed.com/platforms/ST-Nucleo-F401RE/), with a BLE shield or an external BLE peripheral, such as an [X-NUCLEO-BNRG2A1](https://os.mbed.com/components/X-NUCLEO-BNRG2A1/) or an [X-NUCLEO-IDB05A1](https://os.mbed.com/components/X-NUCLEO-IDB05A1/) ST BLE expansion board. 26 | * A [DISCO_L475VG_IOT01A (ref B-L475E-IOT01A)](https://os.mbed.com/platforms/ST-Discovery-L475E-IOT01A/) board. 27 | * A [DISCO_L562QE (ref STM32L562E-DK)](https://os.mbed.com/platforms/ST-Discovery-L562QE/) board. 28 | * A [NUCLEO_WB55RG](https://os.mbed.com/platforms/ST-Nucleo-WB55RG/) board. 29 | * A Nordic nRF52-based board such as [nRF52DK](https://os.mbed.com/platforms/Nordic-nRF52-DK/). 30 | * An Embedded Planet [Agora](https://os.mbed.com/platforms/agora-dev/) board. 31 | 32 | The [BLE documentation](https://os.mbed.com/docs/latest/reference/bluetooth.html) describes the BLE APIs on mbed OS. 33 | 34 | ### Targets for BLE 35 | 36 | The following targets have been tested and work with these examples: 37 | 38 | * Targets with an ST BLE expansion board plugged in: 39 | * NUCLEO_F401RE 40 | * NUCLEO_L476RG 41 | * NUCLEO_L446RE 42 | * K64F 43 | 44 | * ST boards with embedded SPBTLE-RF module (BlueNRG-MS): 45 | * DISCO_L475VG_IOT01A (ref B-L475E-IOT01A) 46 | * DISCO_L562QE (ref STM32L562E-DK) 47 | 48 | * Board with wireless STM32WB microcontrollers: 49 | * NUCLEO_WB55RG 50 | 51 | * Nordic: 52 | * NRF52_DK 53 | * NRF52840_DK 54 | 55 | * Embedded Planet: 56 | * EP_AGORA 57 | 58 | **Important:** If an ST BLE expansion is used with the K64F board, a hardware patch is required. Check out [X-NUCLEO-BNRG2A1](https://github.com/ARMmbed/mbed-os/tree/master/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_2) or [X-NUCLEO-IDB05A1](https://os.mbed.com/components/X-NUCLEO-IDB05A1/) for more information. 59 | 60 | The following board is currently not supported as it doesn't yet support the Cordio stack: 61 | * NRF51_DK 62 | 63 | ### Using ST BLE expansion board on other targets 64 | 65 | It is possible to use the ST BLE expansion on boards not directly supported by these examples as long as the board has an Arduino UNO R3 connector. 66 | 67 | To make the board compatible with the ST BLE expansion three things are required: 68 | * Add the BLE feature to your target. 69 | * Add the BLE implementation for the ST BLE expansion to the list of modules which have to be compiled. 70 | * Indicate to the BLE implementation that your board uses an Arduino connector. 71 | 72 | All these operations can be done in the file `mbed_app.json` present in every example. 73 | 74 | In the section `target_overrides`, add a new object named after your target with the following three fields: 75 | * `"target.components_add": ["BlueNRG_2"]` Add the BlueNRG-2 component to the target. 76 | * `"target.features_add": ["BLE"]` Add the BLE feature to the target. 77 | * `"target.extra_labels_add": ["CORDIO"]`: Add the BLE implementation of the ST BLE expansion to the list of the application modules. 78 | 79 | Below is an example of the JSON to be added in the `target_overrides` section of `mbed_app.json`, with the `NUCLEO_F401RE` board. 80 | 81 | ```json 82 | "NUCLEO_F401RE": { 83 | "target.components_add": ["BlueNRG_2"], 84 | "target.features_add": ["BLE"], 85 | "target.extra_labels_add": ["CORDIO"] 86 | }, 87 | ``` 88 | 89 | **Note:** Further information about the configuration system is available in the [documentation](https://os.mbed.com/docs/latest/reference/configuration.html). 90 | 91 | **Important:** It is required to apply an hardware patch to the ST BLE expansion if it is used on a board with an Arduino connector. Check out [X-NUCLEO-BNRG2A1](https://github.com/ARMmbed/mbed-os/tree/master/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_2) or [X-NUCLEO-IDB05A1](https://os.mbed.com/components/X-NUCLEO-IDB05A1/) for more information. 92 | 93 | 94 | ## Building the examples 95 | 96 | 1. Clone the repository containing the collection of examples: 97 | 98 | ```bash 99 | $ git clone https://github.com/ARMmbed/mbed-os-example-ble.git 100 | ``` 101 | 102 | 103 | **Tip:** If you don't have git installed, you can [download a zip file](https://github.com/ARMmbed/mbed-os-example-ble/archive/master.zip) of the repository. 104 | 105 | 1. Using a command-line tool, navigate to any of the example directories, like BLE_Advertising: 106 | 107 | ```bash 108 | $ cd mbed-os-example-ble 109 | $ cd BLE_Advertising 110 | ``` 111 | 112 | 1. Update the source tree: 113 | 114 | * Mbed CLI 2 115 | 116 | ```bash 117 | $ mbed-tools deploy 118 | ``` 119 | 120 | * Mbed CLI 1 121 | 122 | ```bash 123 | $ mbed deploy 124 | ``` 125 | 126 | 1. Connect a USB cable between the USB port on the board and the host computer. 127 | 128 | 1. Run the following command: this will build the example project, program the microcontroller flash memory, and then 129 | open a serial terminal to the device. 130 | 131 | * Mbed CLI 2 132 | 133 | ```bash 134 | $ mbed-tools compile -m -t --flash --sterm --baudrate 115200 135 | ``` 136 | 137 | * Mbed CLI 1 138 | 139 | ```bash 140 | $ mbed compile -m -t --flash --sterm --baudrate 115200 141 | ``` 142 | 143 | Your PC may take a few minutes to compile your code. 144 | 145 | The binary will be located in the following directory: 146 | * **Mbed CLI 2** - `./cmake_build////` 147 | * **Mbed CLI 1** - `./BUILD///` 148 | 149 | You can manually copy the binary to the target, which gets mounted on the host computer through USB, rather than using the `--flash` option. 150 | 151 | You can also open a serial terminal separately, as explained below, rather than using the `--sterm` and `--baudrate` options. 152 | 153 | ## Running the examples 154 | 155 | When example application is running, information about activity is printed over the serial connection. 156 | The default serial baudrate has been set to 115200 for these examples. 157 | 158 | If not using the `--sterm` and `--baudrate` options when flashing, have a client 159 | open and connected to the board. You may use: 160 | 161 | - Mbed CLI 2 162 | ```bash 163 | $ mbed-tools sterm -b 115200 164 | ``` 165 | 166 | - Mbed CLI 1 167 | ```bash 168 | $ mbed sterm -b 115200 169 | ``` 170 | 171 | - [Tera Term](https://ttssh2.osdn.jp/index.html.en) for Windows 172 | 173 | - screen or minicom for Linux 174 | ```bash 175 | screen /dev/serial/ 115200 176 | ``` 177 | 178 | To observe and/or interact with example applications please use any BLE scanner on a smartphone. 179 | If you don't have a scanner on your phone, please install: 180 | 181 | - [nRF Connect for Mobile](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android and iOS. 182 | 183 | - [ST BLE Profile](https://play.google.com/store/apps/details?id=com.stm.bluetoothlevalidation) for Android. 184 | 185 | 186 | ## Using bare metal profile 187 | 188 | MBED BLE can support bare metal profile: https://os.mbed.com/docs/mbed-os/v6.10/bare-metal/using-the-bare-metal-profile.html 189 | 190 | 191 | Here is an example with NUCLEO_WB55RG, update your local mbed_app.json: 192 | ``` 193 | { 194 | "requires": ["bare-metal", "events", "cordio-stm32wb"], 195 | ``` 196 | 197 | ## How to reduce application size 198 | 199 | Here are few tips to reduce further application size (this could be in addition of baremetal) 200 | 201 | Update in mbed_app.json: 202 | 203 | ``` 204 | { 205 | "target_overrides": { 206 | "*": { 207 | "target.c_lib": "small", 208 | "target.printf_lib": "minimal-printf", 209 | "platform.minimal-printf-enable-floating-point": false, 210 | "platform.stdio-minimal-console-only": true, 211 | ... 212 | ``` 213 | 214 | 215 | ## Troubleshooting 216 | 217 | If you encounter problems with running the example, first try to update to the `development` branch of the example and 218 | see if the problem persists. Make sure to run `mbed update` after you checkout the `development` branch to update the 219 | libraries to the versions in that branch. 220 | 221 | If the problem persists, try turning on traces in the example. This is done by changing the config in `mbed_app.json`: 222 | 223 | ``` 224 | "mbed-trace.enable": true, 225 | "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", 226 | "cordio.trace-hci-packets": true, 227 | "cordio.trace-cordio-wsf-traces": true, 228 | "ble.trace-human-readable-enums": true 229 | ``` 230 | 231 | Compile with `--profile debug` and run with the serial connected to your PC. 232 | 233 | This will enable all the traces in BLE. If the number of traces is too big for the serial to handle or the image 234 | doesn't fit try turning off all except the first one (`mbed-trace.enable`) and/or lowering the `max-level` to 235 | `"TRACE_LEVEL_WARNING"`. 236 | 237 | Save the output of the serial to a file. Please open an issue in this repo, describe the problem and attach the file 238 | containing the trace output. 239 | 240 | ## License and contributions 241 | 242 | The software is provided under Apache-2.0 license. Contributions to this project are accepted under the same license. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more info. 243 | 244 | ## Branches 245 | 246 | `Master` branch is for releases only. Please target the `development` branch for all your PRs. 247 | -------------------------------------------------------------------------------- /resources/official_armmbed_example_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-os-example-ble/a558ccfa4f0c8cb6651f9b323742c96c325c2dc6/resources/official_armmbed_example_badge.png -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_00.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": true, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": true 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_01.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_02.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": false, 16 | "ble.ble-feature-phy-management": true, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": true 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_03.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": true, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": true 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_04.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": true, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": true 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_05.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": false, 12 | "ble.ble-feature-secure-connections": false, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": false, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_06.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": false, 7 | "ble.ble-role-central": false, 8 | "ble.ble-role-peripheral": false, 9 | "ble.ble-feature-gatt-client": false, 10 | "ble.ble-feature-gatt-server": false, 11 | "ble.ble-feature-security": false, 12 | "ble.ble-feature-secure-connections": false, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": false, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_07.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": false, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": false, 8 | "ble.ble-role-peripheral": false, 9 | "ble.ble-feature-gatt-client": false, 10 | "ble.ble-feature-gatt-server": false, 11 | "ble.ble-feature-security": false, 12 | "ble.ble-feature-secure-connections": false, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": false, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_08.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": false, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": false, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": false, 10 | "ble.ble-feature-gatt-server": false, 11 | "ble.ble-feature-security": false, 12 | "ble.ble-feature-secure-connections": false, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": false, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_09.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": false, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": false, 9 | "ble.ble-feature-gatt-client": false, 10 | "ble.ble-feature-gatt-server": false, 11 | "ble.ble-feature-security": false, 12 | "ble.ble-feature-secure-connections": false, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": false, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_10.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": false, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": true, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": true 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_11.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": false, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": true, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": true 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_12.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": true, 13 | "ble.ble-feature-signing": true, 14 | "ble.ble-feature-whitelist": true, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": true, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/test_configs/mbed_app_features_13.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "ble.ble-role-observer": true, 6 | "ble.ble-role-broadcaster": true, 7 | "ble.ble-role-central": true, 8 | "ble.ble-role-peripheral": true, 9 | "ble.ble-feature-gatt-client": true, 10 | "ble.ble-feature-gatt-server": true, 11 | "ble.ble-feature-security": true, 12 | "ble.ble-feature-secure-connections": false, 13 | "ble.ble-feature-signing": false, 14 | "ble.ble-feature-whitelist": false, 15 | "ble.ble-feature-privacy": true, 16 | "ble.ble-feature-phy-management": false, 17 | "ble.ble-feature-extended-advertising": false, 18 | "ble.ble-feature-periodic-advertising": false 19 | }, 20 | "K64F": { 21 | "target.components_add": ["BlueNRG_MS"], 22 | "target.features_add": ["BLE"], 23 | "target.extra_labels_add": ["CORDIO"] 24 | }, 25 | "NUCLEO_F401RE": { 26 | "target.components_add": ["BlueNRG_MS"], 27 | "target.features_add": ["BLE"], 28 | "target.extra_labels_add": ["CORDIO"] 29 | }, 30 | "NRF52840_DK": { 31 | "target.features_add": ["BLE"] 32 | }, 33 | "NRF52_DK": { 34 | "target.features_add": ["BLE"] 35 | } 36 | } 37 | } 38 | --------------------------------------------------------------------------------