image

 

This blog presents a Universal Windows App that connects to an embedded Bluetooth device over the Bluetooth Serial Profile using a genetic Bluetooth USB dongle. This app will run on both a Windows 10 IoT-Core devices such as a Raspberry PI2 and a Windows 10 Desktop. The blog covers in detail the key issues with pairing including where a passkey is required with a RPI2 as well as a Bluetooth primer.Update 1.2: One bug fix (was writing send text twice) and and one code improvement (menu returns DeviceInformation so no need to requery for it.)

 

 

Bluetooth supports peer to peer networking over a short range. Unlike a Wi-Fi network, Bluetooth connectivity is one to one. Two devices can connect and interact.  For example, two devices may connect in a symmetric manner using the serial profile and pas raw data between them. Generally though, Bluetooth connectivity is asymmetric with one end generating a specific data format to be consumed at the other end. For example a mobile phone can implement the A2DP (Advanced Audio Distribution Profile) Profile and stream audio to a head set  that implements the HSP (Headset) Profile OBEX (Object Exchange) is a symmetric connection between two devices as they exchange data between them.

 

The Microsoft  IOT-Core Bluetooth Sample project uses the GATT (Generic Attribute Profile Profile). This provides profile discovery and description services for  the Bluetooth Low Energy protocol.With this protocol simple low power devices can be connected at one end generating data to be consumed by a complex processor. For example, the simple end can be sensors in say, a health or sporing context, connected to a mobile phone or telemetry unit. In the sample, the Windows IoT Core device is connected to a GATT device that has 6 sensors:.

  • Contactless IR temperature sensor

  • Humidity Sensor

  • Gyroscope

  • Accelerometer

  • Magnetometer

  • Barometric pressure Sensor

  •  

This blog is only concerned with the more generic SPP (Serial Port Profile) which is based upon the RFCOMM profile.

 

Bluetooth Serial

Bluetooth is implemented as a driver and protocol stack. Each driver implements a protocol interface going upwards and makes use one or more protocol interfaces from drivers one or more levels below it. At the bottom is the Bluetooth hardware/radios. In the stack as below (an earlier version: circa Bluetooth version 1.1) SDP is the service discovery and RFCOMM is the basis of many profiles as it is a serial interface. Many profiles directly dig deeper than RFCOMM though. Bluetooth serial is SPP (Serial Port Profile) making direct use of RFCOMM.

image

An early version of the Bluetooth Driver Stack.

 

Bluetooth is currently version 4.x which includes many additional protocol, profiles and drivers. For example, the stack above does not have the BLE and GATT (V4.0) profiles as used the Microsoft IoT-Core Bluetooth sample. See the full Windows Bluetooth Stack for the later version of the  stack. For this activity which only involves the SPP profile, which has been around since version 1.0, the stack above shows enough detail. Indeed the generic USB dongle used with the RPI2 is ten years old! Bluetooth Serial is an original, simple but basic Bluetooth profile.

 

Pairing

For two Bluetooth devices to connect they have to be “paired”. Generally you set one end in discovery mode and the other end initiates the paring by selecting the first device from a list generated by the pairing utility. Simple pairing doesn’t require a passkey and the pairing will proceed upon selection. If a passkey is required, it may be fixed in which case its in the documentation (often 0000 or 000000 or 1234) or in-situa generated. If fixed there will be a popup on the initiator into which you enter the passkey.  With some combinations of devices, a passkey appears on both and you just confirm on one that they match. For some combinations, such as a Bluetooth keyboard, the initator generates a passkey that you enter on the keyboard.

 

The default passkey for the Sparkfun Bluetooth Mate and the Freetronics Arduino Bluetooth shield is 1234.

 

Another option is where the MAC address of the target or device name is known, you might be able to programmatically or with a utility preconfigure the source device to be paired with the target. For example the btpair utility in  Bluetooth Command Line Tools facilitates doing this on a Windows desktop. I have used it successfully to so do on a Windows 10 desktop.

btpair examples

    1. Pair your computer and device Mac Address 00:01:02:03:FF:FF  PIN code 1234 :
	   btpair -b"00:01:02:03:FF:FF6" -p1234

    2. Unpair all remembered devices: 
            btpair -u

 

Some Bluetooth serial devices can be configured to be paired with a utility independent of the host device to which they are serially connected. Once configured, you have pairing between any hosts without further pairing configuration as the pairing is endemic to the Bluetooth modules. No Bluetooth stack is required on the host/s. For example (blast from the past)  the EmbeddedBlue 500 (eb500) as used with the Parallax Basic Stamp boards and robots were so configurable. These have a native serial UART TTL level pins. Two such modules can be indelibly paired.

image

eb500 Bluetooth Serial Adapter

 

For Windows 10 IoT-Core you can pair two devices using the web portal ( http://<device ip address>:8080  administrator p@ssw0rd).

Unfortunately earlier versions of the OS (including the build at the the time of Windows 10 RTM, build 10256) did not support Passkey pairing with the  web portal.

image

The IoT-Core Web Portal with some paired devices and one waiting to pair.

SmileI can now report that latest build of the Windows 10 IoT-Core the web portal does support Passkey pairing.Smile

 

dialog

On initiating the pairing this dialog shows.

 

image

Because the other end requires a passkey, this dialog shows. (This was not available in previous builds.) ..Yeah!Smile

 

The Iot-Core Bluetooth sample project, the one using GATT, covers how to use an on-board utility (IoTBluetoothPairing.exe) to pair with or without a passkey, via an SSH shell or PowerShell: http://ms-iot.github.io/content/en-US/win10/samples/BLEGatt1.htm

pairing4 (2)

A pairing activity with IoTBluetoothPairing utility

 

Loopback Serial Functionality Test

Before getting into the code for the Universal Windows Bluetooth Serial App, lets deal with the test part first. I normally use a loopback to test a serial functionality. If I’m only testing a a microprocessor’s UART then I would simply connect Tx and and Rx and perform some writes followed by reads. On an Arduino device this is pins 0 and 1. On the RPI 2, as discussed in my previous blog Win 10 IoT Core- Raspberry PI 2 Native Serial is Live! , its pins 8 and 10 for the RPI 2 .. Yes, the UART is now available with IoT-Core on the RPI2. For The BeagleBone Black its pins J4 and J5 We were using this loopback configuration (“hammering it”) when investigating the interrupt issue with Compact 2013 (see this blog: Windows Embedded Compact 2013- Interrupt Issue Solved.

WP_20151025_01_00_10_Rich_LI (4)
Arduino Uno with RxTx Jumper


WP_20151025_00_57_42_Rich_LI (2)

RPI2 with RxTx Jumper

 

Where the serial port to be tested has a complete RS232 interface (ie a DB9 socket)I use a DB plug with the RxTx cross over wires connected plus the typical handshaking crossovers. eg

DB-9 RS-232 Loopback Connection (TIA-574)
Connect Pins:

2 to 3 (Rx to Tx)

1 to 4 to 6 (DCD to DTR to DSR)

7 to 8 to 9 (RTS to CTS to RI)

image
 Loopback connections reference.
RxTx in red

 

WP_20151025_00_55_09_Rich_LI (2)

C2102 USB-Serial with Loopback Adapter (DB9)

 

If the serial transport is to be tested rather than just the port, then a loop back app is implemented on the other end of the pipe. As a test bed for the UW Bluetooth Serial Test app in this blog,  the other end of the (Bluetooth) pipe is an Arduino (Uno) board. The Bluetooth adapter is connected to pins 0 and 1 on the Arduino board.See the following for information on setting this up.  (You could also use the Freetronics (or similar) Bluetooth shield.):

clip_image012_thumb1

Arduino Uno (Freetronics EtherTen) with Sparkfun Bluetooth Mate Gold
as used as a Bluetooth Serial endpoint for RPI2 Bluetooth Serial testing.

 

The following is the sketch for the Arduino device (this project is in the repository):

// A serial loop back app
// Past setup
// Initiated by connected system
// Note can be used with Bluetooth where the RxTx of the BT device
//   are connected to the TxRx of the Arduino  board.
// Need to disconnect BT adapter for programming though.

void setup() {
  // My adapter is set to this BAUD 115200
  // This is the Arduino to BT adapter port rate
  // Set when  the BT adapter is in command mode.
  // Its NOT the BT rate which you can't set.
  Serial.begin(115200);
  delay(333);
  while (!Serial)
    ;
   delay(1000);
  Serial.println("The quick brown fox jumps over the lazy dog!");
}

The comments above clarify the conceptual misunderstanding that in setting the BAUD rate of a Bluetooth serial adapter, you are only setting the rate for the rate for the physical or USB serial port to the adapter; not the Bluetooth bit rate which is fixed.

 

And the loop code (simple eh!):

void loop() {
  char ch = Serial.read();
  while ( 255 == (byte) ch)
  {
        ch = Serial.read();
  }
  Serial.print(ch);
}

 

This code just reads the serial in and ignores char(255) which means no input. When it gets a sent character it echoes it back.

 

Bluetooth Pairing with Raspberry PI2

As previously stated, I use an very old Bluetooth (V1.1) USB dongle plugged into a USB Host port on the RPI2. It shows as a Generic Bluetooth device. The dongle is of the CSR Chipset. I have been able to connect to:

  • Microsoft Bluetooth Mouse no passkey required
  • Microsoft Bluetooth Keyboard, passkey generated and required to be entered on keyboard.Sparkfun Bluetooth Mate Gold, passkey required on host end
    Freetronics Bluetooth shield, passkey required on host end

With some devices, the connectivity did not work until the RPI2 was rebooted.

I’ll add more to this list later

 

My Lumia 930 phone would not pair with the RPI2 as, I guess, it has no Serial Profile nor HID Profile .. the RPI2 doesn’t support any Audio.

As per http://ms-iot.github.io/content/en-US/win10/Bluetooth.htm  …

Bluetooth Support

Windows IoT Core currently supports Bluetooth 4.0.

Supported Bluetooth Profiles

Windows IoT Core currently supports the following Bluetooth profiles:

  • Bluetooth Basic Rate (BR): HID

  • Bluetooth Basic Rate (BR): RFCOMM.

  • Bluetooth Low Energy (LE): GATT


The Universal Windows App

 

This app was based upon three sources, but needed further development. The sources are:

  1. A Windows Forum example, the 5th reply (thx nio Pan)
  2. The IoT-Core Sample Serial app
  3. My adaptation of the later in my previous blog “Win 10 IoT Core Universal Windows App: Azure Sensors”

The code in the previous blog is a UW IoT-Core app, running on a RPI2 that uses USB-Serial collect sensor information hosted on an Arduino device and also has a protocol built upon the serial interface to interact with a 2 line LCD display hosted on the Arduino device. The final outcome (later) of this activity will be using Bluetooth instead of USB-Serial

 

The App Functionality

This app is a simple Bluetooth Serial Universal Windows (Windows 10) test app that enumerates (as a list) all devices Bluetooth paired to the device where the app is running. One is selected by double clicking which initiates connection. Text to send is entered in a Textbox and sent when a button is pressed. The app automatically receives any text sent to it ( and displays it). Hence when the endpoint (as above) simply echoes the the text its received. Tthe sent text should reappear in the reception box on the UW app. Of course, when the app is run Bluetooth must be enabled!

 

The app is created using in Visual Studio 2015 using the the a Universal Windows app template:
New Project Visual C#->Windows->Blank App (Universal Windows)

 

Creating the App UI

The UI is implemented in XAML:

image

The Universal Windows App UI

  • The UI is quite straight forward and is  created as follows:
  • All text elements are TextBlocks except the SendText which is a TextBox
  • SendText accepts CarriageReturn (ie is Multiline)
  • The Recvd text has WrapText enabled (ie is Multiline)
  • UI elements are organised in rows using a StackPanel set to horizontal orientation
  • These StackPanels are then stacked with a StackPanel set to vertical orientation, along with the ListBox.

You may prefer to layout the UI using Relative StackPanels or use Grid rows and columns etc.

The ConnectDevices is a ListBox with a Binding Source  set to PairedDevices(see later) and an ItemTemplate consisting of a TextBlock bound to the Name property of PairedDevices (see later).

<ListBox x:Name="ConnectDevices" ItemsSource="{Binding Source={StaticResource PairedDevices}}" 
Margin="10"
DoubleTapped="ConnectDevices_DoubleTapped" Width="Auto" Height="Auto"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

App Configuration

  • The app make no use of IOT-Core features so will not require any Extension References.

The app will need some specific capabilities for Bluetooth and Serial added to Package.appxmanifest.
Unfortunately the UI you get for this if you double click on that file in Solution Explorer doesn’t support adding these capabilities and so you need to add them manually by right clicking on the file in Solution Explorer and select Open With->XML Editor.

Modify the capabilities section (at the bottom) to:

  <Capabilities>
    <Capability Name="internetClient" />
    <DeviceCapability Name="bluetooth.rfcomm">
      <Device Id="any">
        <Function Type="name:serialPort"/>
      </Device>
    </DeviceCapability>
  </Capabilities>

The internetClient capability will already be there. Its not needed for this app so you may wish to remove it. I leave it in.

 

PairedDevice Information

At the app start the paired devices are enumerated using:

DeviceInformationCollection DeviceInfoCollection 
= await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));

This collection is then turned into an ObservableCollection that it can be used in the ListBox:

_pairedDevices = new ObservableCollection<PairedDeviceInfo>();

The DeviceInfoCollection is iterated through creating a PairedDeviceInfo object  for each item which is then added to the _pairedDevices collection.

 

PairedDeviceInfo is a class with properties:

Name <string>

Id <string>

DeviceInfo <DeviceInformation>

The class has an appropriate constructor.

DeviceInformation is Windows.Devices.Enumeration.DeviceInformation

In the listbox of paired devices, the name field is (bound) displayed.

When a device is selected (double clicked)  the Device Id is used to retrieve the full DeviceInformation (again!) 
    the endpoint’s DeviceInformation is actually part of the selected menu item.

ToDo: This code should be improved because we already have the DeviceInformation! (??)  Fixed Update1.2

This is then used to connect to the endpoint device:

 

Connection

The DeviceInformation is used to get the RFCOMM service. The connection is then established as a StreamSocket  using the Endpoint HostName (actually its Bluetooth Mac Address) and the ServiceName string.

_service = await RfcommDeviceService.FromIdAsync(DeviceInfo.Id);
_socket = new StreamSocket();
await _socket.ConnectAsync(_service.ConnectionHostName, _service.ConnectionServiceName);

If all is well then we have a connection .. the socket will be meaningful (not null).
Of course this is error trapped (try-catch)

Send text and Receive text make use of the socket’s InputStream and OutputStream properties.

 

Receive Text

Receiving text should be started first as it runs as a separate thread. It runs an async wait to get serial input, handles the input then runs another async serial receive .. all in a loop. This loops continuous until a cancellation is generated.

 

private async void Listen()
{
     ReadCancellationTokenSource = new CancellationTokenSource();
     if (_socket.InputStream != null)
     {
         dataReaderObject = new DataReader(_socket.InputStream);
         // keep reading the serial input
         while (true)
         {                 
               await ReadAsync(ReadCancellationTokenSource.Token);
         }
     }
}
.
DataReader dataReaderObject;
private CancellationTokenSource ReadCancellationTokenSource;








private async Task ReadAsync(CancellationToken cancellationToken) { uint ReadBufferLength = 1024; // If task cancellation was requested, comply cancellationToken.ThrowIfCancellationRequested();
// Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available dataReaderObject.InputStreamOptions = InputStreamOptions.Partial; // Create a task object to wait for data on the serialPort.InputStream loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken); // Launch the task and wait UInt32 bytesRead = await loadAsyncTask; if (bytesRead > 0) { string recvdtxt = dataReaderObject.ReadString(bytesRead); } }

 

Send Text

Whilst the received text is performed asynchronously as the arrival of text is nondeterministic from the app’s perspective,  sent text is actioned from the app’s UI and so is essentially synchronous (although a await is used to free up the UI).

private async void Send(string msg)
{
     Task<UInt32> storeAsyncTask;

     DataWriter dataWriteObject = new DataWriter(_socket.OutputStream);
     dataWriteObject.WriteString(msg);

     // Launch an async task to complete the write operation
     storeAsyncTask = dataWriteObject.StoreAsync().AsTask();

     UInt32 bytesWritten = await storeAsyncTask;
}

Button States

The command buttons are enabled and disabled depending upon the state of the app. For example Send and Start Recv buttons are disabled when the app isn’t connected but become enabled when the app is connected, etc.


Enjoy.

Please leave comments