This example creates and updates a standard Battery Level service containing a single GATT characteristic. The battery service transmits a device's battery level in percentage, with 100% being a fully charged battery and 0% being a fully drained battery. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-ble/tree/master/BLE_BatteryLevel

This example creates and updates a standard Battery Level service containing a single GATT characteristic.

The battery service transmits a device's battery level in percentage, with 100% being a fully charged battery and 0% being a fully drained battery.

Although the sample application runs on a BLE device, it doesn't show the device's real battery level (because that changes very slowly and will make for a dull example). Instead, it transmits a fake battery level that starts at 50% (half charged). Every half second, it increments the battery level, going in single increments until reaching 100% (as if the battery is charging). It then drops down to 20% to start incrementing again.

Running the application

Requirements

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 :

- nRF Master Control Panel for Android.

- LightBlue for iPhone.

Hardware requirements are in the main readme.

Building instructions

Building with mbed CLI

If you'd like to use mbed CLI to build this, then you should refer to the main readme. The instructions here relate to using the developer.mbed.org Online Compiler

In order to build this example in the mbed Online Compiler, first import the example using the ‘Import’ button on the right hand side.

Next, select a platform to build for. This must either be a platform that supports BLE, for example the NRF51-DK, or one of the following:

List of platforms supporting Bluetooth Low Energy

Or you must also add a piece of hardware and the supporting library that includes a Bluetooth Low Energy driver for that hardware, for example the K64F or NUCLEO_F401RE with the X-NUCLEO-IDB05A1

List of components supporting Bluetooth Low Energy.

Once you have selected your platform, compile the example and drag and drop the resulting binary onto your board.

For general instructions on using the mbed Online Compiler, please see the mbed Handbook

Checking for success

Note: Screens captures depicted below show what is expected from this example if the scanner used is nRF Master Control Panel version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals.

  • Build the application and install it on your board as explained in the building instructions.
  • Open the BLE scanner on your phone.
  • Start a scan.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-BatteryLevel/raw-file/a5ac4bf2e468/img/start_scan.png

figure 1 How to start scan using nRF Master Control Panel 4.0.5

  • Find your device; it should be named `BATTERY`.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-BatteryLevel/raw-file/a5ac4bf2e468/img/scan_result.png

figure 2 Scan results using nRF Master Control Panel 4.0.5

  • Establish a connection with your device.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-BatteryLevel/raw-file/a5ac4bf2e468/img/connection.png

figure 3 How to establish a connection using Master Control Panel 4.0.5

  • Discover the services and the characteristics on the device. The *Battery service* has the UUID 0x180F and includes the *Battery level* characteristic which has the UUID 0x2A19.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-BatteryLevel/raw-file/a5ac4bf2e468/img/discovery.png

figure 4 Representation of the Battery service using Master Control Panel 4.0.5

  • Register for the notifications sent by the *Battery level* characteristic.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-BatteryLevel/raw-file/a5ac4bf2e468/img/register_to_notifications.png

figure 5 How to register to notifications using Master Control Panel 4.0.5

  • You should see the battery level value change every half second. It begins at 50, goes up to 100 (in steps of 1), resets to 20 and so on.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-BatteryLevel/raw-file/a5ac4bf2e468/img/notifications.png

figure 6 Notifications view using Master Control Panel 4.0.5

If you can see the characteristic, and if its value is incrementing correctly, the application is working properly.

Committer:
mbed_official
Date:
Thu Aug 15 17:00:38 2019 +0100
Revision:
81:99e70947653f
Parent:
76:e489712bcbcf
Merge pull request #252 from donatieng/mbed_os_update

Update Master branch to use Mbed OS 5.13.1
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-ble

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 4:52bffaff7f0b 1 /* mbed Microcontroller Library
mbed_official 4:52bffaff7f0b 2 * Copyright (c) 2006-2014 ARM Limited
mbed_official 4:52bffaff7f0b 3 *
mbed_official 4:52bffaff7f0b 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 4:52bffaff7f0b 5 * you may not use this file except in compliance with the License.
mbed_official 4:52bffaff7f0b 6 * You may obtain a copy of the License at
mbed_official 4:52bffaff7f0b 7 *
mbed_official 4:52bffaff7f0b 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 4:52bffaff7f0b 9 *
mbed_official 4:52bffaff7f0b 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 4:52bffaff7f0b 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 4:52bffaff7f0b 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 4:52bffaff7f0b 13 * See the License for the specific language governing permissions and
mbed_official 4:52bffaff7f0b 14 * limitations under the License.
mbed_official 4:52bffaff7f0b 15 */
mbed_official 4:52bffaff7f0b 16
mbed_official 13:eaa1343657a8 17 #include <events/mbed_events.h>
mbed_official 4:52bffaff7f0b 18 #include <mbed.h>
mbed_official 4:52bffaff7f0b 19 #include "ble/BLE.h"
mbed_official 4:52bffaff7f0b 20 #include "ble/Gap.h"
mbed_official 4:52bffaff7f0b 21 #include "ble/services/BatteryService.h"
mbed_official 76:e489712bcbcf 22 #include "pretty_printer.h"
mbed_official 4:52bffaff7f0b 23
mbed_official 76:e489712bcbcf 24 static DigitalOut led1(LED1, 1);
mbed_official 76:e489712bcbcf 25
mbed_official 76:e489712bcbcf 26 const static char DEVICE_NAME[] = "BATTERY";
mbed_official 76:e489712bcbcf 27
mbed_official 76:e489712bcbcf 28 static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE);
mbed_official 4:52bffaff7f0b 29
mbed_official 76:e489712bcbcf 30 class BatteryDemo : ble::Gap::EventHandler {
mbed_official 76:e489712bcbcf 31 public:
mbed_official 76:e489712bcbcf 32 BatteryDemo(BLE &ble, events::EventQueue &event_queue) :
mbed_official 76:e489712bcbcf 33 _ble(ble),
mbed_official 76:e489712bcbcf 34 _event_queue(event_queue),
mbed_official 76:e489712bcbcf 35 _battery_uuid(GattService::UUID_BATTERY_SERVICE),
mbed_official 76:e489712bcbcf 36 _battery_level(50),
mbed_official 76:e489712bcbcf 37 _battery_service(ble, _battery_level),
mbed_official 76:e489712bcbcf 38 _adv_data_builder(_adv_buffer) { }
mbed_official 4:52bffaff7f0b 39
mbed_official 76:e489712bcbcf 40 void start() {
mbed_official 76:e489712bcbcf 41 _ble.gap().setEventHandler(this);
mbed_official 76:e489712bcbcf 42
mbed_official 76:e489712bcbcf 43 _ble.init(this, &BatteryDemo::on_init_complete);
mbed_official 76:e489712bcbcf 44
mbed_official 76:e489712bcbcf 45 _event_queue.call_every(500, this, &BatteryDemo::blink);
mbed_official 76:e489712bcbcf 46 _event_queue.call_every(1000, this, &BatteryDemo::update_sensor_value);
mbed_official 76:e489712bcbcf 47
mbed_official 76:e489712bcbcf 48 _event_queue.dispatch_forever();
mbed_official 76:e489712bcbcf 49 }
mbed_official 4:52bffaff7f0b 50
mbed_official 76:e489712bcbcf 51 private:
mbed_official 76:e489712bcbcf 52 /** Callback triggered when the ble initialization process has finished */
mbed_official 76:e489712bcbcf 53 void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
mbed_official 76:e489712bcbcf 54 if (params->error != BLE_ERROR_NONE) {
mbed_official 76:e489712bcbcf 55 print_error(params->error, "Ble initialization failed.");
mbed_official 76:e489712bcbcf 56 return;
mbed_official 76:e489712bcbcf 57 }
mbed_official 4:52bffaff7f0b 58
mbed_official 76:e489712bcbcf 59 print_mac_address();
mbed_official 76:e489712bcbcf 60
mbed_official 76:e489712bcbcf 61 start_advertising();
mbed_official 4:52bffaff7f0b 62 }
mbed_official 4:52bffaff7f0b 63
mbed_official 76:e489712bcbcf 64 void start_advertising() {
mbed_official 76:e489712bcbcf 65 /* Create advertising parameters and payload */
mbed_official 4:52bffaff7f0b 66
mbed_official 76:e489712bcbcf 67 ble::AdvertisingParameters adv_parameters(
mbed_official 76:e489712bcbcf 68 ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
mbed_official 76:e489712bcbcf 69 ble::adv_interval_t(ble::millisecond_t(1000))
mbed_official 76:e489712bcbcf 70 );
mbed_official 4:52bffaff7f0b 71
mbed_official 76:e489712bcbcf 72 _adv_data_builder.setFlags();
mbed_official 76:e489712bcbcf 73 _adv_data_builder.setLocalServiceList(mbed::make_Span(&_battery_uuid, 1));
mbed_official 76:e489712bcbcf 74 _adv_data_builder.setName(DEVICE_NAME);
mbed_official 4:52bffaff7f0b 75
mbed_official 76:e489712bcbcf 76 /* Setup advertising */
mbed_official 76:e489712bcbcf 77
mbed_official 76:e489712bcbcf 78 ble_error_t error = _ble.gap().setAdvertisingParameters(
mbed_official 76:e489712bcbcf 79 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 76:e489712bcbcf 80 adv_parameters
mbed_official 76:e489712bcbcf 81 );
mbed_official 4:52bffaff7f0b 82
mbed_official 76:e489712bcbcf 83 if (error) {
mbed_official 76:e489712bcbcf 84 print_error(error, "_ble.gap().setAdvertisingParameters() failed");
mbed_official 76:e489712bcbcf 85 return;
mbed_official 76:e489712bcbcf 86 }
mbed_official 76:e489712bcbcf 87
mbed_official 76:e489712bcbcf 88 error = _ble.gap().setAdvertisingPayload(
mbed_official 76:e489712bcbcf 89 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 76:e489712bcbcf 90 _adv_data_builder.getAdvertisingData()
mbed_official 76:e489712bcbcf 91 );
mbed_official 46:6b66d08f304e 92
mbed_official 76:e489712bcbcf 93 if (error) {
mbed_official 76:e489712bcbcf 94 print_error(error, "_ble.gap().setAdvertisingPayload() failed");
mbed_official 76:e489712bcbcf 95 return;
mbed_official 76:e489712bcbcf 96 }
mbed_official 76:e489712bcbcf 97
mbed_official 76:e489712bcbcf 98 /* Start advertising */
mbed_official 4:52bffaff7f0b 99
mbed_official 76:e489712bcbcf 100 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 76:e489712bcbcf 101
mbed_official 76:e489712bcbcf 102 if (error) {
mbed_official 76:e489712bcbcf 103 print_error(error, "_ble.gap().startAdvertising() failed");
mbed_official 76:e489712bcbcf 104 return;
mbed_official 76:e489712bcbcf 105 }
mbed_official 4:52bffaff7f0b 106 }
mbed_official 4:52bffaff7f0b 107
mbed_official 76:e489712bcbcf 108 void update_sensor_value() {
mbed_official 76:e489712bcbcf 109 if (_ble.gap().getState().connected) {
mbed_official 76:e489712bcbcf 110 _battery_level++;
mbed_official 76:e489712bcbcf 111 if (_battery_level > 100) {
mbed_official 76:e489712bcbcf 112 _battery_level = 20;
mbed_official 76:e489712bcbcf 113 }
mbed_official 76:e489712bcbcf 114
mbed_official 76:e489712bcbcf 115 _battery_service.updateBatteryLevel(_battery_level);
mbed_official 76:e489712bcbcf 116 }
mbed_official 76:e489712bcbcf 117 }
mbed_official 76:e489712bcbcf 118
mbed_official 76:e489712bcbcf 119 void blink(void) {
mbed_official 76:e489712bcbcf 120 led1 = !led1;
mbed_official 4:52bffaff7f0b 121 }
mbed_official 4:52bffaff7f0b 122
mbed_official 76:e489712bcbcf 123 private:
mbed_official 76:e489712bcbcf 124 /* Event handler */
mbed_official 4:52bffaff7f0b 125
mbed_official 76:e489712bcbcf 126 void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
mbed_official 76:e489712bcbcf 127 _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 76:e489712bcbcf 128 }
mbed_official 76:e489712bcbcf 129
mbed_official 76:e489712bcbcf 130 private:
mbed_official 76:e489712bcbcf 131 BLE &_ble;
mbed_official 76:e489712bcbcf 132 events::EventQueue &_event_queue;
mbed_official 4:52bffaff7f0b 133
mbed_official 76:e489712bcbcf 134 UUID _battery_uuid;
mbed_official 76:e489712bcbcf 135
mbed_official 76:e489712bcbcf 136 uint8_t _battery_level;
mbed_official 76:e489712bcbcf 137 BatteryService _battery_service;
mbed_official 46:6b66d08f304e 138
mbed_official 76:e489712bcbcf 139 uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
mbed_official 76:e489712bcbcf 140 ble::AdvertisingDataBuilder _adv_data_builder;
mbed_official 76:e489712bcbcf 141 };
mbed_official 4:52bffaff7f0b 142
mbed_official 76:e489712bcbcf 143 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 76:e489712bcbcf 144 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
mbed_official 76:e489712bcbcf 145 event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
mbed_official 4:52bffaff7f0b 146 }
mbed_official 4:52bffaff7f0b 147
mbed_official 4:52bffaff7f0b 148 int main()
mbed_official 4:52bffaff7f0b 149 {
mbed_official 76:e489712bcbcf 150 BLE &ble = BLE::Instance();
mbed_official 76:e489712bcbcf 151 ble.onEventsToProcess(schedule_ble_events);
mbed_official 4:52bffaff7f0b 152
mbed_official 76:e489712bcbcf 153 BatteryDemo demo(ble, event_queue);
mbed_official 76:e489712bcbcf 154 demo.start();
mbed_official 4:52bffaff7f0b 155
mbed_official 4:52bffaff7f0b 156 return 0;
mbed_official 4:52bffaff7f0b 157 }