Denise Ackermann
/
mbed-os-example-ble-Advertising
Bluetooth
source/main.cpp@0:7373a1c9d5b4, 2021-01-14 (annotated)
- Committer:
- apalmieri
- Date:
- Thu Jan 14 11:25:30 2021 +0000
- Revision:
- 0:7373a1c9d5b4
Initial commit of BLE Advertising example for X-NUCLEO-IDB05A1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
apalmieri | 0:7373a1c9d5b4 | 1 | /* mbed Microcontroller Library |
apalmieri | 0:7373a1c9d5b4 | 2 | * Copyright (c) 2006-2019 ARM Limited |
apalmieri | 0:7373a1c9d5b4 | 3 | * |
apalmieri | 0:7373a1c9d5b4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
apalmieri | 0:7373a1c9d5b4 | 5 | * you may not use this file except in compliance with the License. |
apalmieri | 0:7373a1c9d5b4 | 6 | * You may obtain a copy of the License at |
apalmieri | 0:7373a1c9d5b4 | 7 | * |
apalmieri | 0:7373a1c9d5b4 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
apalmieri | 0:7373a1c9d5b4 | 9 | * |
apalmieri | 0:7373a1c9d5b4 | 10 | * Unless required by applicable law or agreed to in writing, software |
apalmieri | 0:7373a1c9d5b4 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
apalmieri | 0:7373a1c9d5b4 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
apalmieri | 0:7373a1c9d5b4 | 13 | * See the License for the specific language governing permissions and |
apalmieri | 0:7373a1c9d5b4 | 14 | * limitations under the License. |
apalmieri | 0:7373a1c9d5b4 | 15 | */ |
apalmieri | 0:7373a1c9d5b4 | 16 | |
apalmieri | 0:7373a1c9d5b4 | 17 | #include <events/mbed_events.h> |
apalmieri | 0:7373a1c9d5b4 | 18 | #include "ble/BLE.h" |
apalmieri | 0:7373a1c9d5b4 | 19 | #include "ble/Gap.h" |
apalmieri | 0:7373a1c9d5b4 | 20 | #include "pretty_printer.h" |
apalmieri | 0:7373a1c9d5b4 | 21 | |
apalmieri | 0:7373a1c9d5b4 | 22 | const static char DEVICE_NAME[] = "BATTERY"; |
apalmieri | 0:7373a1c9d5b4 | 23 | |
apalmieri | 0:7373a1c9d5b4 | 24 | using namespace std::literals::chrono_literals; |
apalmieri | 0:7373a1c9d5b4 | 25 | |
apalmieri | 0:7373a1c9d5b4 | 26 | static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); |
apalmieri | 0:7373a1c9d5b4 | 27 | |
apalmieri | 0:7373a1c9d5b4 | 28 | class BatteryDemo : ble::Gap::EventHandler { |
apalmieri | 0:7373a1c9d5b4 | 29 | public: |
apalmieri | 0:7373a1c9d5b4 | 30 | BatteryDemo(BLE &ble, events::EventQueue &event_queue) : |
apalmieri | 0:7373a1c9d5b4 | 31 | _ble(ble), |
apalmieri | 0:7373a1c9d5b4 | 32 | _event_queue(event_queue), |
apalmieri | 0:7373a1c9d5b4 | 33 | _battery_level(50), |
apalmieri | 0:7373a1c9d5b4 | 34 | _adv_data_builder(_adv_buffer) |
apalmieri | 0:7373a1c9d5b4 | 35 | { |
apalmieri | 0:7373a1c9d5b4 | 36 | } |
apalmieri | 0:7373a1c9d5b4 | 37 | |
apalmieri | 0:7373a1c9d5b4 | 38 | void start() |
apalmieri | 0:7373a1c9d5b4 | 39 | { |
apalmieri | 0:7373a1c9d5b4 | 40 | /* mbed will call on_init_complete when when ble is ready */ |
apalmieri | 0:7373a1c9d5b4 | 41 | _ble.init(this, &BatteryDemo::on_init_complete); |
apalmieri | 0:7373a1c9d5b4 | 42 | |
apalmieri | 0:7373a1c9d5b4 | 43 | /* this will never return */ |
apalmieri | 0:7373a1c9d5b4 | 44 | _event_queue.dispatch_forever(); |
apalmieri | 0:7373a1c9d5b4 | 45 | } |
apalmieri | 0:7373a1c9d5b4 | 46 | |
apalmieri | 0:7373a1c9d5b4 | 47 | private: |
apalmieri | 0:7373a1c9d5b4 | 48 | /** Callback triggered when the ble initialization process has finished */ |
apalmieri | 0:7373a1c9d5b4 | 49 | void on_init_complete(BLE::InitializationCompleteCallbackContext *params) |
apalmieri | 0:7373a1c9d5b4 | 50 | { |
apalmieri | 0:7373a1c9d5b4 | 51 | if (params->error != BLE_ERROR_NONE) { |
apalmieri | 0:7373a1c9d5b4 | 52 | print_error(params->error, "Ble initialization failed."); |
apalmieri | 0:7373a1c9d5b4 | 53 | return; |
apalmieri | 0:7373a1c9d5b4 | 54 | } |
apalmieri | 0:7373a1c9d5b4 | 55 | |
apalmieri | 0:7373a1c9d5b4 | 56 | print_mac_address(); |
apalmieri | 0:7373a1c9d5b4 | 57 | |
apalmieri | 0:7373a1c9d5b4 | 58 | start_advertising(); |
apalmieri | 0:7373a1c9d5b4 | 59 | } |
apalmieri | 0:7373a1c9d5b4 | 60 | |
apalmieri | 0:7373a1c9d5b4 | 61 | void start_advertising() |
apalmieri | 0:7373a1c9d5b4 | 62 | { |
apalmieri | 0:7373a1c9d5b4 | 63 | /* create advertising parameters and payload */ |
apalmieri | 0:7373a1c9d5b4 | 64 | |
apalmieri | 0:7373a1c9d5b4 | 65 | ble::AdvertisingParameters adv_parameters( |
apalmieri | 0:7373a1c9d5b4 | 66 | /* you cannot connect to this device, you can only read its advertising data, |
apalmieri | 0:7373a1c9d5b4 | 67 | * scannable means that the device has extra advertising data that the peer can receive if it |
apalmieri | 0:7373a1c9d5b4 | 68 | * "scans" it which means it is using active scanning (it sends a scan request) */ |
apalmieri | 0:7373a1c9d5b4 | 69 | ble::advertising_type_t::SCANNABLE_UNDIRECTED, |
apalmieri | 0:7373a1c9d5b4 | 70 | ble::adv_interval_t(ble::millisecond_t(1000)) |
apalmieri | 0:7373a1c9d5b4 | 71 | ); |
apalmieri | 0:7373a1c9d5b4 | 72 | |
apalmieri | 0:7373a1c9d5b4 | 73 | _adv_data_builder.setFlags(); |
apalmieri | 0:7373a1c9d5b4 | 74 | _adv_data_builder.setName(DEVICE_NAME); |
apalmieri | 0:7373a1c9d5b4 | 75 | |
apalmieri | 0:7373a1c9d5b4 | 76 | /* we add the battery level as part of the payload so it's visible to any device that scans */ |
apalmieri | 0:7373a1c9d5b4 | 77 | _adv_data_builder.setServiceData(GattService::UUID_BATTERY_SERVICE, {&_battery_level, 1}); |
apalmieri | 0:7373a1c9d5b4 | 78 | |
apalmieri | 0:7373a1c9d5b4 | 79 | /* setup advertising */ |
apalmieri | 0:7373a1c9d5b4 | 80 | |
apalmieri | 0:7373a1c9d5b4 | 81 | ble_error_t error = _ble.gap().setAdvertisingParameters( |
apalmieri | 0:7373a1c9d5b4 | 82 | ble::LEGACY_ADVERTISING_HANDLE, |
apalmieri | 0:7373a1c9d5b4 | 83 | adv_parameters |
apalmieri | 0:7373a1c9d5b4 | 84 | ); |
apalmieri | 0:7373a1c9d5b4 | 85 | |
apalmieri | 0:7373a1c9d5b4 | 86 | if (error) { |
apalmieri | 0:7373a1c9d5b4 | 87 | print_error(error, "_ble.gap().setAdvertisingParameters() failed"); |
apalmieri | 0:7373a1c9d5b4 | 88 | return; |
apalmieri | 0:7373a1c9d5b4 | 89 | } |
apalmieri | 0:7373a1c9d5b4 | 90 | |
apalmieri | 0:7373a1c9d5b4 | 91 | error = _ble.gap().setAdvertisingPayload( |
apalmieri | 0:7373a1c9d5b4 | 92 | ble::LEGACY_ADVERTISING_HANDLE, |
apalmieri | 0:7373a1c9d5b4 | 93 | _adv_data_builder.getAdvertisingData() |
apalmieri | 0:7373a1c9d5b4 | 94 | ); |
apalmieri | 0:7373a1c9d5b4 | 95 | |
apalmieri | 0:7373a1c9d5b4 | 96 | if (error) { |
apalmieri | 0:7373a1c9d5b4 | 97 | print_error(error, "_ble.gap().setAdvertisingPayload() failed"); |
apalmieri | 0:7373a1c9d5b4 | 98 | return; |
apalmieri | 0:7373a1c9d5b4 | 99 | } |
apalmieri | 0:7373a1c9d5b4 | 100 | |
apalmieri | 0:7373a1c9d5b4 | 101 | /* when advertising you can optionally add extra data that is only sent |
apalmieri | 0:7373a1c9d5b4 | 102 | * if the central requests it by doing active scanning */ |
apalmieri | 0:7373a1c9d5b4 | 103 | _adv_data_builder.clear(); |
apalmieri | 0:7373a1c9d5b4 | 104 | const uint8_t _vendor_specific_data[4] = { 0xAD, 0xDE, 0xBE, 0xEF }; |
apalmieri | 0:7373a1c9d5b4 | 105 | _adv_data_builder.setManufacturerSpecificData(_vendor_specific_data); |
apalmieri | 0:7373a1c9d5b4 | 106 | |
apalmieri | 0:7373a1c9d5b4 | 107 | _ble.gap().setAdvertisingScanResponse( |
apalmieri | 0:7373a1c9d5b4 | 108 | ble::LEGACY_ADVERTISING_HANDLE, |
apalmieri | 0:7373a1c9d5b4 | 109 | _adv_data_builder.getAdvertisingData() |
apalmieri | 0:7373a1c9d5b4 | 110 | ); |
apalmieri | 0:7373a1c9d5b4 | 111 | |
apalmieri | 0:7373a1c9d5b4 | 112 | /* start advertising */ |
apalmieri | 0:7373a1c9d5b4 | 113 | |
apalmieri | 0:7373a1c9d5b4 | 114 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); |
apalmieri | 0:7373a1c9d5b4 | 115 | |
apalmieri | 0:7373a1c9d5b4 | 116 | if (error) { |
apalmieri | 0:7373a1c9d5b4 | 117 | print_error(error, "_ble.gap().startAdvertising() failed"); |
apalmieri | 0:7373a1c9d5b4 | 118 | return; |
apalmieri | 0:7373a1c9d5b4 | 119 | } |
apalmieri | 0:7373a1c9d5b4 | 120 | |
apalmieri | 0:7373a1c9d5b4 | 121 | /* we simulate battery discharging by updating it every second */ |
apalmieri | 0:7373a1c9d5b4 | 122 | _event_queue.call_every( |
apalmieri | 0:7373a1c9d5b4 | 123 | 1000ms, |
apalmieri | 0:7373a1c9d5b4 | 124 | [this]() { |
apalmieri | 0:7373a1c9d5b4 | 125 | update_battery_level(); |
apalmieri | 0:7373a1c9d5b4 | 126 | } |
apalmieri | 0:7373a1c9d5b4 | 127 | ); |
apalmieri | 0:7373a1c9d5b4 | 128 | } |
apalmieri | 0:7373a1c9d5b4 | 129 | |
apalmieri | 0:7373a1c9d5b4 | 130 | void update_battery_level() |
apalmieri | 0:7373a1c9d5b4 | 131 | { |
apalmieri | 0:7373a1c9d5b4 | 132 | if (_battery_level-- == 10) { |
apalmieri | 0:7373a1c9d5b4 | 133 | _battery_level = 100; |
apalmieri | 0:7373a1c9d5b4 | 134 | } |
apalmieri | 0:7373a1c9d5b4 | 135 | |
apalmieri | 0:7373a1c9d5b4 | 136 | /* update the payload with the new value */ |
apalmieri | 0:7373a1c9d5b4 | 137 | ble_error_t error = _adv_data_builder.setServiceData(GattService::UUID_BATTERY_SERVICE, make_Span(&_battery_level, 1)); |
apalmieri | 0:7373a1c9d5b4 | 138 | |
apalmieri | 0:7373a1c9d5b4 | 139 | if (error) { |
apalmieri | 0:7373a1c9d5b4 | 140 | print_error(error, "_adv_data_builder.setServiceData() failed"); |
apalmieri | 0:7373a1c9d5b4 | 141 | return; |
apalmieri | 0:7373a1c9d5b4 | 142 | } |
apalmieri | 0:7373a1c9d5b4 | 143 | |
apalmieri | 0:7373a1c9d5b4 | 144 | /* set the new payload, we don't need to stop advertising */ |
apalmieri | 0:7373a1c9d5b4 | 145 | error = _ble.gap().setAdvertisingPayload( |
apalmieri | 0:7373a1c9d5b4 | 146 | ble::LEGACY_ADVERTISING_HANDLE, |
apalmieri | 0:7373a1c9d5b4 | 147 | _adv_data_builder.getAdvertisingData() |
apalmieri | 0:7373a1c9d5b4 | 148 | ); |
apalmieri | 0:7373a1c9d5b4 | 149 | |
apalmieri | 0:7373a1c9d5b4 | 150 | if (error) { |
apalmieri | 0:7373a1c9d5b4 | 151 | print_error(error, "_ble.gap().setAdvertisingPayload() failed"); |
apalmieri | 0:7373a1c9d5b4 | 152 | return; |
apalmieri | 0:7373a1c9d5b4 | 153 | } |
apalmieri | 0:7373a1c9d5b4 | 154 | } |
apalmieri | 0:7373a1c9d5b4 | 155 | |
apalmieri | 0:7373a1c9d5b4 | 156 | private: |
apalmieri | 0:7373a1c9d5b4 | 157 | BLE &_ble; |
apalmieri | 0:7373a1c9d5b4 | 158 | events::EventQueue &_event_queue; |
apalmieri | 0:7373a1c9d5b4 | 159 | |
apalmieri | 0:7373a1c9d5b4 | 160 | uint8_t _battery_level; |
apalmieri | 0:7373a1c9d5b4 | 161 | |
apalmieri | 0:7373a1c9d5b4 | 162 | uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; |
apalmieri | 0:7373a1c9d5b4 | 163 | ble::AdvertisingDataBuilder _adv_data_builder; |
apalmieri | 0:7373a1c9d5b4 | 164 | }; |
apalmieri | 0:7373a1c9d5b4 | 165 | |
apalmieri | 0:7373a1c9d5b4 | 166 | /* Schedule processing of events from the BLE middleware in the event queue. */ |
apalmieri | 0:7373a1c9d5b4 | 167 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) |
apalmieri | 0:7373a1c9d5b4 | 168 | { |
apalmieri | 0:7373a1c9d5b4 | 169 | event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents)); |
apalmieri | 0:7373a1c9d5b4 | 170 | } |
apalmieri | 0:7373a1c9d5b4 | 171 | |
apalmieri | 0:7373a1c9d5b4 | 172 | int main() |
apalmieri | 0:7373a1c9d5b4 | 173 | { |
apalmieri | 0:7373a1c9d5b4 | 174 | BLE &ble = BLE::Instance(); |
apalmieri | 0:7373a1c9d5b4 | 175 | ble.onEventsToProcess(schedule_ble_events); |
apalmieri | 0:7373a1c9d5b4 | 176 | |
apalmieri | 0:7373a1c9d5b4 | 177 | BatteryDemo demo(ble, event_queue); |
apalmieri | 0:7373a1c9d5b4 | 178 | demo.start(); |
apalmieri | 0:7373a1c9d5b4 | 179 | |
apalmieri | 0:7373a1c9d5b4 | 180 | return 0; |
apalmieri | 0:7373a1c9d5b4 | 181 | } |