Connecting to a Bluetooth Serial Port Profile with BlueZ and Mono

Once you have paired your bluetooth device with BlueZ, the next step depends on what type of device it is.

One of the most common bluetooth profiles is the Serial port profile. I could write quite a lengthy article about RFCOMM, L2CAPP, SDP, and various other bluetooth protocols and profiles, but the reality is that BlueZ5 does quite a nice job of abstracting these details so that you really don't need to be concerned with them for most use cases.

The first step to creating a connection to our device is to get the instance of the profile manager.


var profileManager =  _connection.System.GetObject("org.bluez", new ObjectPath("/org/bluez"));

Next, we need to implement our own profile to register with the profile manager.


public class MyProfile:Profile1

There are 3 methods we need to define in our profile. First, and perhaps most interestingly, the NewConnection method which is called when the device connects.


public void NewConnection(ObjectPath device, FileDescriptor fd, IDictionary properties)
{
    var stream = fd.OpenAsStream(true);
    byte[] someDataToSend = new byte[0];
    stream.Write(someDataToSend,0,someDataToSend.Length);
    stream.Flush();
}

The same profile can be used to connect multiple devices, so if you intend to use multiple devices then you will need to implement your methods accordingly. One method I have used is to create a Dictionary which uses the device ObjectPath as the key, this way you can lookup the FileDescriptor again when the disconnection request comes.

The next method is RequestDisconnection, which is called when the device disconnects. The purpose if this method is to close the FileDescriptor since BlueZ no longer owns it.


public void RequestDisconnection(ObjectPath device)
{
  //find our reference to the stream
  stream.Close();
  stream.Dispose();
}

The last method is Release, and this will be called when your profile is unregistered, and should be used to clean up any remaining resources or file descriptors.

With your profile defined, next you will instantiate it, register it on dbus, and register it with BlueZ. When you register it with BlueZ, you will also specify an array of UUIDs which your Profile will accept connections from. The UUIDs can be found on your instance of the device at device.UUIDs.

To register the profile once you have selected which UUID to use:


var profile = new MyProfile();
_system.Register(new ObjectPath("/profiles"), profile);
profileManager.RegisterProfile(new ObjectPath("/profiles"), "", properties);

Next, you will signal the device to connect.


device.ConnectProfile("");

At this point you will either receive an exception, or a callback to the NewConnection method in your profile. Interaction from this point using the stream will vary greatly depending upon which type of device you are connecting to. When you are done communicating, you will call device.DisconnectProfile("<your uuid"), which will then indirectly cause a callback to RequestDisconnection on your profile implementation which should then close the file descriptor.

While it is not trivial, it is MUCH cleaner and easier doing this on BlueZ 5 with dbus than it was using native calls against BlueZ 4. The main errors you can encounter during this process are best captured by tailing syslog and filtering to lines that contain "bluetooth".