(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows 8.1: Play with Bluetooth Rfcomm

(3 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
1 comments   /   posted on Nov 11, 2013
Categories:   Windows 8

Tweet

Scanning the new namespaces added to Windows 8.1 you'll find a new interesting surprise in the field of bluetooth support. The new operating system infact, adds support for the Bluetooth Rfcomm into the "Windows.Devices.Bluetooth.Rfcomm" namespace. The "Radio frequency communication" protocol, is a simple set of transport protocols that allow the comunication between devices using reliable data streams similar to the TCP protocol in the networking.

What this means is that the Rfcomm protocol allows you to establish a persistent connection between two devices with a real socket. This is interesting for remote controlling devices, to acquire continuous data streams and opens to a wide set of applications that takes advantage of custom peripherals sensor.

How it works

Creating a connection over a Rfcomm channel is not so easy as creating a socket between two machines on the network. The very first thing you need to understand is that pairing bluetooth devices is something completely out of your control. You can only create a connection between devices that have been already paired and also if this may seems a limitation, it takes out of your control a number of boring things like security checks. The pairing of devices already implements a way to create a secure identification and you do not need to enter in this area. So, when you will scan for available devices (I'll show you this later in the article) simply expect to find devices that have successfully completed the pairing process.

After you understand this point, the connection process is someway simple and depends on the role of the parts of the connection. Given A and B the connecting endpoints you will have a "server" (let say it is the A) and a client (B). First of all, the A endpoint needs to bind to the Bluetooth interface and opens a listening channel that await for an incoming connection. In this phase, called "advertising", the A endpoint simply signal its availability and awaits for some peer to connect. The B endpoint scans the paired devices and find the available peer. Then it try to open a socket to the listening host. At this point the server accept the connection, disposes the listener and gets the socket representing the established connection. From this point the connection is fully available and both the parts may read and write as if it is a normal ethernet connection.

So, there are some points that may vary in these steps. As an example the listener may keep working the listening channel after a connection has been received but at the proof of facts the process of creating the data stream over bluetooth is clear. It remains to put this in practice and for this purpose, what is better that try con connect a Windows 8.1 device with a Windows Phone 8 peer?

Connect WP8 and W8.1 over bluetooth

In the following example I'll explain the code required to create an established connection between my Lumia 925 (Windows Phone 8) and the ASUS VivoTab that I recently (and successfully) upgraded to Windows 8.1. In this scenario the tablet will be the server endpoint that listen for a single connection. On the other side the Lumia 925 will try to connect to the tablet. After the connection is established every tap on the screen of the phone will be transmitted to the tablet over the bluetooth channel and it will represents the tapped point on its screen. So let start with the server part. First of all you have to setup device capabilities in the manifest. These are represented by three elements that you should add partly by the editor and partly in XML manually. Here is the resulting XML:

   1: <Capabilities>
   2:   <Capability Name="privateNetworkClientServer" />
   3:   <Capability Name="internetClientServer" />
   4:   <m2:DeviceCapability Name="bluetooth.rfcomm">
   5:     <m2:Device Id="any">
   6:       <m2:Function Type="serviceId:A7EA96BB-4F95-4A91-9FDD-3CE3CFF1D8DA" />
   7:     </m2:Device>
   8:   </m2:DeviceCapability>
   9: </Capabilities>

The first two capabilities can be set directly into the editor of the manifest and represents the "Internet (Client & Server)" and the "Private Networks (Client & Server)". The other part identifies the Rfcomm protocol and the Identifier of the service we are creating. This identifier is a UUID (Guid) generated by the developer and it will be used to create the Rfcomm provider. Then in the page load of the MainPage we have to start the listening channel:

   1: private async Task StartListen()
   2: {
   3:     Provider = await RfcommServiceProvider.CreateAsync(
   4:         RfcommServiceId.FromUuid(RfcommServiceUuid));
   5:  
   6:     StreamSocketListener listener = new StreamSocketListener();
   7:     listener.ConnectionReceived += HandleConnectionReceived;
   8:  
   9:     await listener.BindServiceNameAsync(
  10:         Provider.ServiceId.AsString(),
  11:         SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
  12:  
  13:     var writer = new DataWriter();
  14:     writer.WriteByte(ServiceVersionAttributeType);
  15:     writer.WriteUInt32(ServiceVersion);
  16:  
  17:     var data = writer.DetachBuffer();
  18:     Provider.SdpRawAttributes.Add(ServiceVersionAttributeId, data);
  19:     Provider.StartAdvertising(listener);
  20: }

The very first action in this code is to create an instance of a RfcommServiceProvider. This provider identifies the protocol and it will be created using the RfcommServiceUuid that we wrote in the manifest. Then it is created a StremSocketListener and it is binded to the Bluetooth channel using the provider itself. Finally, using a DataWriter some info are associated with the provider to identify the connection. More info on these attributes in this link: https://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery

Once the provider has been put in advertising mode using the StartAdvertising method, a remote device can try to open a connection (I'll speak this part in a few). When a connection is detected the ConnectionReceived event is raised and it is handled as in the following snippet:

   1: private void HandleConnectionReceived(StreamSocketListener listener, StreamSocketListenerConnectionReceivedEventArgs args)
   2: {
   3:     Provider.StopAdvertising();
   4:     listener.Dispose();
   5:     listener = null;
   6:  
   7:     this.Socket = args.Socket;
   8:     this.Reader = new DataReader(this.Socket.InputStream);
   9:     this.Run();
  10: }

The provider's advertising is stopped and the listener is dropped. This is because I only want to handle a single connection. You can also try to handle multiple connections leaving the advertising alive. The received socket represents the established connection and it should be used to read and write data. On the side of the Windows Phone 8 the thing is someway easy

   1: private async Task Connect()
   2: {
   3:     PeerFinder.AlternateIdentities["Bluetooth:PAIRED"] = "";
   4:  
   5:     var devices = await PeerFinder.FindAllPeersAsync();
   6:     var device = devices.FirstOrDefault();
   7:  
   8:     if (device != null)
   9:     {
  10:         this.Socket = new StreamSocket();
  11:         await this.Socket.ConnectAsync(device.HostName, "1");
  12:         this.Writer = new DataWriter(this.Socket.OutputStream);
  13:         this.bConnect.Visibility = Visibility.Collapsed;
  14:         this.LayoutRoot.Tap += LayoutRoot_Tap;
  15:     }
  16: }

The PeerFinder class is used to scan the available devices, then the very first is taken. Here I assume that there is a single device available but in a real world case you should present a list of peers to the user that selects the one you want to connect to. When a device is found the socket is created and connected using the HostName. At this point the Windows 8.1 should ask the user if he accepts the connection. The rest of the code is to setup the device for the following communication. The implementation wait for taps on the screen and in case it collect the X and Y coordinates and send them along the established channel:

   1: private async void LayoutRoot_Tap(object sender, System.Windows.Input.GestureEventArgs e)
   2: {
   3:     if (this.Writer != null)
   4:     {
   5:         var position = e.GetPosition(this.LayoutRoot);
   6:         this.Writer.WriteInt32(1);
   7:         this.Writer.WriteInt32((int)position.X);
   8:         this.Writer.WriteInt32((int)position.Y);
   9:         await this.Writer.StoreAsync();
  10:     }
  11: }

The code sends three integers. The first represents the command, in case of future extensions, then the coordinates. Once the message has been queued the StoreAsync method send all the packet on the stream. On the other side:

   1: private async void Run()
   2: {
   3:     while (true)
   4:     {
   5:         try
   6:         {
   7:             Command command = (Command)await this.Reader.ReadInt32Async();
   8:  
   9:             switch (command)
  10:             {
  11:                 case Command.Tap:
  12:                     await this.HandleTap();
  13:                     break;
  14:             }
  15:         }
  16:         catch (PeerDisconnectedException)
  17:         {
  18:             return;
  19:         }
  20:     }
  21: }
  22:  
  23: private async Task HandleTap()
  24: {
  25:     int x = await this.Reader.ReadInt32Async();
  26:     int y = await this.Reader.ReadInt32Async();
  27:  
  28:     await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
  29:         () =>
  30:         {
  31:             Canvas.SetLeft(ellipse, x);
  32:             Canvas.SetTop(ellipse, y);
  33:         });
  34: }

The run method is an endless loop that listen for a integer. The integer is the command sent by the peer. Once a command is received the code selects the handler (HandleTap in this case) and it reads the following two integer. Then it moves a little circle in the given position using a canvas. Pay attention that the ReadInt32Async method is not part of the DataReader class but it is and extension method:

   1: public async static Task<Int32> ReadInt32Async(this DataReader reader)
   2: {
   3:     uint available = await reader.LoadAsync(sizeof(Int32));
   4:  
   5:     if (available < sizeof(Int32))
   6:         throw new PeerDisconnectedException();
   7:  
   8:     return reader.ReadInt32();
   9: }

When to use bluetooth?

As usual, after the technical troubles has been solved - and to prepare this example I had to solve a number of them - is it time to start thinking to possible application. Given that a number of devices supporting this protocol may already exists, I think the success it can partially depends on the ability of creating custom devices. This is not exactly my usual range of work but I hope that someone may take advantage of this article to build some astounding apps.


Subscribe

Comments

  • lightgis

    Re: Windows 8.1: Play with Bluetooth Rfcomm


    posted by lightgis on Apr 02, 2014 20:11

    THANKS! can you share the whole visual studio project?

Add Comment

Login to comment:
  *      *       

From this series