BLE Advertising sample application

Dependents:   X_NUCLEO_IDB0XA1

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2019 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <events/mbed_events.h>
00018 #include "ble/BLE.h"
00019 #include "ble/Gap.h"
00020 #include "pretty_printer.h"
00021 
00022 const static char DEVICE_NAME[] = "BATTERY";
00023 
00024 using namespace std::literals::chrono_literals;
00025 
00026 static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE);
00027 
00028 class BatteryDemo : ble::Gap::EventHandler {
00029 public:
00030     BatteryDemo(BLE &ble, events::EventQueue &event_queue) :
00031         _ble(ble),
00032         _event_queue(event_queue),
00033         _battery_level(50),
00034         _adv_data_builder(_adv_buffer)
00035     {
00036     }
00037 
00038     void start()
00039     {
00040         /* mbed will call on_init_complete when when ble is ready */
00041         _ble.init(this, &BatteryDemo::on_init_complete);
00042 
00043         /* this will never return */
00044         _event_queue.dispatch_forever();
00045     }
00046 
00047 private:
00048     /** Callback triggered when the ble initialization process has finished */
00049     void on_init_complete(BLE::InitializationCompleteCallbackContext *params)
00050     {
00051         if (params->error != BLE_ERROR_NONE) {
00052             print_error(params->error, "Ble initialization failed.");
00053             return;
00054         }
00055 
00056         print_mac_address();
00057 
00058         start_advertising();
00059     }
00060 
00061     void start_advertising()
00062     {
00063         /* create advertising parameters and payload */
00064 
00065         ble::AdvertisingParameters adv_parameters(
00066             /* you cannot connect to this device, you can only read its advertising data,
00067              * scannable means that the device has extra advertising data that the peer can receive if it
00068              * "scans" it which means it is using active scanning (it sends a scan request) */
00069             ble::advertising_type_t::SCANNABLE_UNDIRECTED,
00070             ble::adv_interval_t(ble::millisecond_t(1000))
00071         );
00072 
00073         _adv_data_builder.setFlags();
00074         _adv_data_builder.setName(DEVICE_NAME);
00075 
00076         /* we add the battery level as part of the payload so it's visible to any device that scans */
00077         _adv_data_builder.setServiceData(GattService::UUID_BATTERY_SERVICE, {&_battery_level, 1});
00078 
00079         /* setup advertising */
00080 
00081         ble_error_t error = _ble.gap().setAdvertisingParameters(
00082             ble::LEGACY_ADVERTISING_HANDLE,
00083             adv_parameters
00084         );
00085 
00086         if (error) {
00087             print_error(error, "_ble.gap().setAdvertisingParameters() failed");
00088             return;
00089         }
00090 
00091         error = _ble.gap().setAdvertisingPayload(
00092             ble::LEGACY_ADVERTISING_HANDLE,
00093             _adv_data_builder.getAdvertisingData()
00094         );
00095 
00096         if (error) {
00097             print_error(error, "_ble.gap().setAdvertisingPayload() failed");
00098             return;
00099         }
00100 
00101         /* when advertising you can optionally add extra data that is only sent
00102          * if the central requests it by doing active scanning */
00103         _adv_data_builder.clear();
00104         const uint8_t _vendor_specific_data[4] = { 0xAD, 0xDE, 0xBE, 0xEF };
00105         _adv_data_builder.setManufacturerSpecificData(_vendor_specific_data);
00106 
00107         _ble.gap().setAdvertisingScanResponse(
00108             ble::LEGACY_ADVERTISING_HANDLE,
00109             _adv_data_builder.getAdvertisingData()
00110         );
00111 
00112         /* start advertising */
00113 
00114         error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
00115 
00116         if (error) {
00117             print_error(error, "_ble.gap().startAdvertising() failed");
00118             return;
00119         }
00120 
00121         /* we simulate battery discharging by updating it every second */
00122         _event_queue.call_every(
00123             1000ms,
00124             [this]() {
00125                 update_battery_level();
00126             }
00127         );
00128     }
00129 
00130     void update_battery_level()
00131     {
00132         if (_battery_level-- == 10) {
00133             _battery_level = 100;
00134         }
00135 
00136         /* update the payload with the new value */
00137         ble_error_t error = _adv_data_builder.setServiceData(GattService::UUID_BATTERY_SERVICE, make_Span(&_battery_level, 1));
00138 
00139         if (error) {
00140             print_error(error, "_adv_data_builder.setServiceData() failed");
00141             return;
00142         }
00143 
00144         /* set the new payload, we don't need to stop advertising */
00145         error = _ble.gap().setAdvertisingPayload(
00146             ble::LEGACY_ADVERTISING_HANDLE,
00147             _adv_data_builder.getAdvertisingData()
00148         );
00149 
00150         if (error) {
00151             print_error(error, "_ble.gap().setAdvertisingPayload() failed");
00152             return;
00153         }
00154     }
00155 
00156 private:
00157     BLE &_ble;
00158     events::EventQueue &_event_queue;
00159 
00160     uint8_t _battery_level;
00161 
00162     uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
00163     ble::AdvertisingDataBuilder _adv_data_builder;
00164 };
00165 
00166 /* Schedule processing of events from the BLE middleware in the event queue. */
00167 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
00168 {
00169     event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
00170 }
00171 
00172 int main()
00173 {
00174     BLE &ble = BLE::Instance();
00175     ble.onEventsToProcess(schedule_ble_events);
00176 
00177     BatteryDemo demo(ble, event_queue);
00178     demo.start();
00179 
00180     return 0;
00181 }