Sergii Baidachnyi

Blog about technologies

Posts Tagged ‘Creators Update

UWP: Working with Bluetooth (part 4: Publishing GATT services)

leave a comment »

Thanks to new Bluetooth Low Energy API in Creators Update, UWP applications can publish GATT services playing a virtual peripheral role. It makes sense if you develop a hardware hub on Windows 10 that should be connected to different peripheral devices (not just Bluetooth, but ZigBee, Z-WAVE and even by wires) and want to use Bluetooth as a communication protocol between your phones, computers and the hub. In this case, the hub can read data from the peripheral devices and route these data as a set of Bluetooth services.

Of course, to publish anything as a BLE service you have to make sure that a radio module on your computer supports peripheral role. I didn’t find any list or recommendations yet, but it’s really not easy to find a device for tests. Even if a radio module based on a chip that can work as a transmitter, it means nothing. All my five computers including Surface Book don’t support peripheral role, but I could find at least one device: Raspberry Pi 3 that has embedded Bluetooth module. It’s strange, but using Raspberry Pi 3 you will not be able to implement beacons, but it works fine as a virtual peripheral device. If you have Raspberry Pi 2, it will not work, because both recommended external modules don’t support peripheral role.

To check if your computer supports the peripheral role, you can use the BluetoothAdapter class and check the IsPeripheralRoleSupported property. If it’s true, your device can work as a Bluetooth peripheral device.

Let’s discuss how to publish own services if your module supports the peripheral role. I will create a service that is similar to STEVAL-IDB007V1 default service that we discussed in the beginning. So, I am going to create two services. The first one will publish acceleration data and the second one will publish temperature and pressure. First of all we need to create an instance of the GattServiceProvider class. It’s possible to do using the CreateAsync static method of the class:

var serviceResult =
    await GattServiceProvider.CreateAsync(Guid.Parse(SensorUUIDs.UUID_ACC_SERV));
accService = serviceResult.ServiceProvider;
accService.AdvertisementStatusChanged += AccService_AdvertisementStatusChanged;

You can see that to use the CreateAsync method it’s enough to pass a GUID as a parameter. Pay attention that Bluetooth specification contains some reserved GUIDs for adopted services. So, if you create something from scratch, it’s better to check all reserved GUIDs. In the code above I declared an event handler for the AdvertisementStatusChanged event in order to make sure that my service is started.

Once our service is created, we can add characteristics to it. The following code shows how to do it:

var param = new GattLocalCharacteristicParameters();
param.CharacteristicProperties =
    GattCharacteristicProperties.Indicate |
    GattCharacteristicProperties.Read;
param.WriteProtectionLevel = GattProtectionLevel.Plain;
param.UserDescription = "accelerometer";
var charResult=
    await accService.Service.CreateCharacteristicAsync(
        Guid.Parse(SensorUUIDs.UUID_ACC_DATA),param);
accData = charResult.Characteristic;
accData.ReadRequested += AccData_ReadRequested;

To create a characteristic, you can use CreateCharacteristicAsync method, but prior to call it we need to prepare parameters for the characteristic. You can see that our characteristic is indicatable and supports Read operation. You can add Notify to support notification mechanism. Because our characteristic supports Read, we need to handle ReadRequested event to provide all needed data. Below you can see implementation for the handler:

private async void AccData_ReadRequested(GattLocalCharacteristic sender,
    GattReadRequestedEventArgs args)
{
    var deferral=args.GetDeferral();
    var request = await args.GetRequestAsync();
    var writer = new DataWriter();
    writer.WriteBytes(new byte[6] { 0x12, 0x12, 0x12, 0x12, 0x12, 0x12 });
    request.RespondWithValue(writer.DetachBuffer());
    deferral.Complete();
}

In this code if you forget to use deferral, the code will generate a runtime exception. In the beginning if the chapter my STEVAL-IDB007V1 board had some sensors, but Raspberry Pi 3 doesn’t contain accelerometer or temperature sensors. So, I generate fake values just to test if it works at all, but if you want, you can connect real sensors to your Raspberry Pi 3.

Finally, we are ready to advertise the service.

accService.StartAdvertising(
    new GattServiceProviderAdvertisingParameters() {
        IsDiscoverable = true, IsConnectable = true });

Using StartAdvertising method we need to initialize IsDiscoverable and IsConnectable to true.

Opening my code on github you can find implementation for the second service with similar implementation. To test this service, we can use our first application in this chapter or any BLE scanner.

Written by Sergiy Baydachnyy

05/18/2017 at 3:11 AM