Using Bluetooth with Windows 10

I went through Using BLE GATT services with Windows 10 in previous post, and in this I’m going to go through the codes used for creating serial communication through the Bluetooth connection.

Full examples for the use cases can be found under BLETestStuffWindows section under my GitHub repos. An application handling the communications on foreground is called BluetoothApp, and application implementing background Bluetooth listener is called BluetoothAppBG.

In connecting device side the code is pretty much as it is with any other service with Windows 10, i.e. you need to use the DeviceInformation.FindAllAsync() to find the device you want to connect to. And in order to get your destination device into the returned list, you do need to pair it beforehand, thus do remember to do that before you start connection process, though do remember to start advertising for the service before pairing, otherwise its not included in the cached pairing information.

The filter string is created with  RfcommDeviceService GetDeviceSelector function with your own GUID:

Guid btUuid = Guid.Parse("6f5b75e8-be27-4684-a776-3238826d1a91");
string deviceFilter = RfcommDeviceService.GetDeviceSelector(RfcommServiceId.FromUuid(btUuid)); 
var devices = await DeviceInformation.FindAllAsync(deviceFilter); 

The devices array then includes all paired devices which did implement a listener to the specified GUID in the time of pairing the device. Then to fetch bluetooth related information and to be able to connect to the device, you need to  RfcommDeviceService instance for a selected device.

RfcommDeviceService service = await RfcommDeviceService.FromIdAsync(selectedDevice.Id);

 

Then in case the selected device did add SDP attributes for advertising, you could actually fetch them here, even before you do any connection to the device.

var attributes = await service.GetSdpRawAttributesAsync(BluetoothCacheMode.Uncached);

You could use the DataReader to read the actual attributes. Do note that if the service uses static SDP attributes, then you don’t need to use the BluetoothCacheMode.Uncached attribute. In this case you would get the attributes read from the device, while it was paired.

Using BluetoothCacheMode.Uncached attribute allows the service to update the attributes when needed, this could be used for example to tell any clients the last update on any data the service is proving, thus devices who have already connected after the last update, would not need to do actual connection to the service to find that out.

Then the actual connection to the remote device is handled with StreamSocket, and once the connection is established, the StreamSocket  instance is used for reading & writing data between the devices.

StreamSocket streamSocket = new StreamSocket();
await streamSocket.ConnectAsync(
 service.ConnectionHostName,
 service.ConnectionServiceName,
 SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);

On the receiving side, you can use RfcommServiceProvider to make the Bluetooth service visible to other devices, and then use StreamSocketListener to listen for incoming connections. The usage of these classes is pretty strait forward, you simply create a provider with your own GUID, bind it to your listener instance, and then call  StartAdvertising.

Guid btUuid = Guid.Parse("6f5b75e8-be27-4684-a776-3238826d1a91");
RfcommServiceProvider provider = await RfcommServiceProvider.CreateAsync(RfcommServiceId.FromUuid(btUuid));

StreamSocketListener listener = new StreamSocketListener();
listener.ConnectionReceived += Listener_ConnectionReceived;

await listener.BindServiceNameAsync(provider.ServiceId.AsString(), SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);

provider.StartAdvertising(listener);

Do note that before you call the StartAdvertising, you could also use the SdpRawAttributes method from RfcommServiceProvider to gain access to the SDP attribute dictionary, and use it to add your service specific SDP attributes.

Any incoming connection is then received with the ConnectionReceived event handler. In it you simply take the StreamSocket from the argument, store it, and read/write data to it.

void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
 StreamSocket socket = args.Socket;
 ...
}

 

Receiving Bluetooth connections in Background

Full example for background usage  is available under BLETestStuffWindows at my GitHub repos. And it is called BluetoothAppBG.

For background processing you need to implement a background task. The general idea is explained in  Create and register a background task article, then to handle Bluetooth connections, you need to use specific trigger. And in this case it is RfcommConnectionTrigger.

With the RfcommConnectionTrigger, in general you would only need to set your own GUID to it, but as with the RfcommServiceProvider, you can also add you own custom SDP attributes, the only difference here is that you don’t get access to a Dictionary instance, instead you would need to write the attributes into an instance of IBuffer. For reference implementation, do check the getsdpRecordBlob function that starts at line 131 in BackgroundManager.cs file.

Creating the trigger part of the code then looks like this:

Guid btUuid = Guid.Parse("6f5b75e8-be27-4684-a776-3238826d1a91");

RfcommConnectionTrigger trigger = new RfcommConnectionTrigger();
trigger.InboundConnection.LocalServiceId = RfcommServiceId.FromUuid(btUuid);
trigger.InboundConnection.SdpRecord = getsdpRecordBlob(serviceName, serviceDescriptor);
backgroundTaskBuilder.SetTrigger(trigger);

Then once there would be incoming connection, then in your IBackgroundTask, you would get the Run  called with taskInstance.TriggerDetails set to instance of RfcommConnectionTriggerDetails. And with that instance, you could simply use the Socket method to gain access to StreamSocket instance for the connection, and use it for reading & writing data.

 
RfcommConnectionTriggerDetails details = (RfcommConnectionTriggerDetails)taskInstance.TriggerDetails;
 if (details != null)
 {
 socket = details.Socket;
 writer = new DataWriter(socket.OutputStream);
 reader = new DataReader(socket.InputStream);
 } 

Connecting to the service from Android App

If you would want to connect to the Bluetooth service running inside Windows 10 device from android, you could use any Bluetooth example (that works with Bluetooth Serial communications), for example the bluetoothchat available via SDK examples.

All you need to do, is to change the GUID to be the one used by Windows 10 service, and then, as the Windows side coding expects to get lenght of the message before the actual message starts, you would need to modify the sending part to do that in android. And with the SDK example, I did this by adding four lines of code into the write() function defined in BluetoothChatService.java file:

mmOutStream.write(((buffer.length >> 24) & 0xFF));
mmOutStream.write(((buffer.length >> 16) & 0xFF));
mmOutStream.write(((buffer.length >> 8) & 0xFF));
mmOutStream.write((buffer.length & 0xFF));