Using BLE GATT services with Windows 10

Windows 10 brings nice update on the apps front by introducing Universal Windows app . With it you can create one app, and run it in all Windows 10 platforms, including phones & laptops.

To get started with development for it, you could first fetch the Windows-universal-samples  that allows you to get your old device update to Windows 10. I personally used my really old 920 for development & testing, simply because I do have access to few of special Developer device versions of them.

The Universal Windows app examples are for some reason not including any examples for using BLE GATT services, thus I decided to make one. Of course there is older 8.1 example, which indeed could be used as a base.

Additionally Windows 10 brings a new API that be used with BLE GATT services, and that is GattCharacteristicNotificationTriggerDetails, which can be used for monitoring single Characteristic while running in background.

Reading BLE characteristics values in Foreground

With Windows 10 devices, in order to connect to any BLE device, you need to pair them first. Thus you need to go to the Bluetooth settings, enable the Bluetooth. And then find the device you with to communicate with and get it paired. Which after you can find the device in your own code by searching for it with DeviceInformation.FindAllAsync():

 var devices = await DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.HeartRate));
 
if (devices != null)
{
   foreach (DeviceInformation device in devices)
   {
       // add device into your UI here
   }
}

After we have paired with the device, it will be shown in the list even when it’s out of range, thus it’s advisable to actually to monitor whether we have connection, before attempting to read any values, though you can of course set value changed event handlers for characteristics, but those won’t be called if you don’t have connection anyways.

Do note that it appears that the device is handling the connection, thus from your application point of view, you simply find then device service, and then you check the status of the connection to that device, and then simply subscribe for connection events, which will inform you if we get any changes on connection. From coding point of view it looks like this:

service = await GattDeviceService.FromIdAsync(device.Id);
DeviceConnectionUpdated((service.Device.ConnectionStatus == BluetoothConnectionStatus.Connected), null);
service.Device.ConnectionStatusChanged += OnConnectionStatusChanged;

Then to get the characteristics from the service, you simply use the GetCharacteristics() function:

characteristic = _service.GetCharacteristics(GattCharacteristicUuids.HeartRateMeasurement)[0];
characteristic.ValueChanged += Oncharacteristic_ValueChanged;

 

And to make sure you’ll get notifications for the characteristics value change, you do need to make sure Characteristic notifications are enabled by making sure that characteristics configuration is set to Notify:

var currentDescriptorValue = await _characteristic.ReadClientCharacteristicConfigurationDescriptorAsync();

if ((currentDescriptorValue.Status != GattCommunicationStatus.Success) ||(currentDescriptorValue.ClientCharacteristicConfigurationDescriptor != GattClientCharacteristicConfigurationDescriptorValue.Notify))
{
await _characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
}

After this, you are basically done. Then you just need to implement handling the events and updating your UI with the values. Full example for the foreground reading for heartbeat characteristics can be found under my github repo at: BLETestStuffWindows/HeartbeatFg

Background Characteristics monitoring

I also have full example for the background monitoring available under my github repo at: BLETestStuffWindows/HeartbeatBg, The Uis for both examples are exactly the same, but the usage of the BLE Api’s are quite different.

The main changes made for the foreground example were:

  1. The MainPage in addition to finding the device, also monitors connection to it. This is to make sure that we only attempt to display values for devices we actually have connection to.
  2. The HeartbeatPage gets the heartbeat value via progress event handler from background task, thus its simply listening the progress events, and showing the value in the UI controls
  3. We needed to remove any characteristics value monitoring etc. from the BLE engine, since the value reading is now handled in background. Only connection monitoring parts are still used in MainPage.

Additionally we needed to add new functionality

  1. There is now 3 modules in the app. In addition to the main application, there is background service part, and Common module which is hosting parts that needs to be accessed from both foreground & background parts.
  2. MainPage is also doing Background task registration. UnRegistratering is handled in App class (when going back from HeartbeatPage)
  3. When we launch the app while having active background task, the start page is changed to be the HeartbeatPage, since we don’t need to select any device for showing the values anymore. This has effected the navigation design in app class.

The Background registration  is handled in BackgroundManager class. This class also implements the functions for setting & removing progress events handlers needed by HeartbeatPage.

In MainPage we use the lighter version of the BLE engine to find the characteristic we want to monitor in background, then we use BackgroundTaskBuilder class to register it with the instance of GattCharacteristicNotificationTrigger:

BackgroundTaskBuilder backgroundTaskBuilder = new BackgroundTaskBuilder();

backgroundTaskBuilder.Name = HeartbeatMonitorBackgroundTaskName;

backgroundTaskBuilder.TaskEntryPoint = HeartbeatMonitorBackgroundTaskEntryPoint;

backgroundTaskBuilder.SetTrigger(new GattCharacteristicNotificationTrigger(characteristic));

BackgroundTaskRegistration backgroundTaskRegistration = backgroundTaskBuilder.Register();

The framework then should handle keeping the connection to the device, until we remove the background task. And any change in the characteristics value should cause our background task to be executed.

In the background task, we then simply get the value of the characteristic from the taskinstance, and set it to the Progress variable, and if we have the progress event handler set, our UI will be informed on the newly gotten value.

GattCharacteristicNotificationTriggerDetails details = (GattCharacteristicNotificationTriggerDetails)taskInstance.TriggerDetails;
byte[] ReceivedData = new byte[details.Value.Length];
DataReader.FromBuffer(details.Value).ReadBytes(ReceivedData);

HeartbeatMeasurement tmpMeasurement = HeartbeatMeasurement.GetHeartbeatMeasurementFromData(ReceivedData);

taskInstance.Progress = tmpMeasurement.HeartbeatValue;

In the example implementation for the background task, I also have additional ways on informing the user of the values:

  1. ToastNotificationManager is used to make notifications to inform user of the cancellation of the task (so they could click the notification and re-start the task from the UI app)
  2. TileUpdateManager is used to update the main tile of the application with the heartbeat value, so the user can see what the last value we got was without opening the UI app.
  3. System.Launcher.LaunchUriAsync() is used to start the UI application directly when we have the heartbeat value outside the defined range.