Bluetooth Serial Ports
By far the easiest and best way to use a serial port connection is to use BluetoothClient
with service class BluetoothService.SerialPort
, i.e. using code very much like shown in General Bluetooth Data Connections
. That gets one a .NET Stream
to read and write from. Both BluetoothClient and virtual serial ports use the RFCOMM protocol so the two are equivalent. This method is much easier to set-up that a virtual serial port, there is no global state to configure etc; and is also more robust, for instance if the peer device is taken out of range or turned-off one learns this directly soon after, whereas with a serial port one has to use timeouts and retries to detect it.
However there are cases where a virtual serial port is required, for instance where another program needs to access the connection — a common case is where your program is configuring a connection that will be used by a printer driver utility.
Note that RFCOMM/SPP only allows one connection from a remote device to each service. So do not use BluetoothClient and a virtual Serial port to connect to the same service at the same time; the second one will fail to connect.
Win32 + Microsoft Bluetooth stack
On Win32, to create a Bluetooth virtual serial port one can use BluetoothDeviceInfo.SetServiceState
, passing in service class SerialPort
. Unfortunately the name of the COM port created is not returned — that’s because the native API does not tell! One way to find the name of the port created is to call the System.IO.Ports.SerialPort.GetPortNames method before and after the SetServiceState call and see which name is new.
BluetoothAddress addr = ... // e.g. BluetoothAddress.Parse("002233445566");
BluetoothDeviceInfo device = new BluetoothDeviceInfo(addr); // Or from discovery etc
bool state = true;
device.SetServiceState(BluetoothService.SerialPort, state, true);
Windows Mobile/CE + Microsoft Bluetooth stack
On Windows Mobile, two methods to create a port exist in the library, the first is class BluetoothSerialPort
, this creates a connection immediately but the underlying API it uses is rather unreliable, and it seems not to work at all on various device types. The second is BluetoothDeviceInfo.SetServiceState
as for Win32, this manually configures the necessary Registry settings and is reliable but might require a reboot before the port becomes available, and again the name of the new port is not returned.
On Widcomm, we recently added support for their CSppClient
class. Currently this is exposed by method WidcommSerialPort.Create
-- I'll integrate it with BluetoothSerialPort
sometime. I haven't used the serial ports on the other platforms very much, but on testing the support on Widcomm I found some specific behaviour when the connection is broken -- by the two devices going out of range or similar. When that happens the connection is broken (e.g. a BluetoothListener connection at the other end see End-Of-Stream) and we see a DISCONNECT event raised by the CSppClient class. The port does not
seems to reconnect. If one closes and reopens the SerialPort
(e.g. COM8) from the client program then the Widcomm "choose device dialog" is shown to the user when we might have hoped that the connection was made back to the previous service.
We will probably need to have some way to reconnect this. If we reconnect automatically internally inside WidcommSerialPort can we be sure that we'll get the same COM port number assigned. Or should we provide an event which is raised when the connection is lost and let the consumer program redo the connection manually. Or somewhere in between?
However this code does not work when I tested it on the Win32 installation -- maybe because my installation version is too old or something. Let me know if you get it to work for you. There is also a different API in Widcomm Win32 with method CBtIf::CreateCOMPortAssociation
etc, I'd be happy to accept patches for that -- probably in WidcommBluetoothDeviceInfo.SetServiceState