We have new support for the BlueZ Bluetooth protocol stack on Linux. We running on the Mono CLR there.
Currently we have the following support:
- Radio: We list the values propertly (Address, Name, CoD). We do not get the Mode or HardwareStatus or allow setting them. We will list all the installed radios, but see below for multi-radio usage.
- Client.Connect: Supported. No support for Authenticate/Encrypt/SetPin etc.
- Data transfer: BlueZ uses Sockets for data transfer so everything should be fine. 🙂
- Listener: Supported, including advertising SDP record. Again no support for Auth/Encrypt/SetPin.
- Client.DiscoverDevices: we discover only in-range devices. There is no support currently for remembered devices and will return an error if they are requested — there doesn’t seem a ‘hci’ API. There is also currently no support for ‘live’ discovery.
- Security: No support currently.
As noted above BluetoothClient.Connect and BluetoothListener use Sockets. Current versions of Mono do not support opening or using Bluetooth sockets. My old pal Andy Hume and I have created a patch to Mono to enable this support, and have posted it as Mono/Novell bug id 655153.
Apply that patch to your Mono source code, rebuild, test and let me have your comments…
As noted above, unlike apparently every stack on Windows, BlueZ does support multiple radios. We do list all the radios and BluetoothClient and BluetoothListener will bind to a particular local address if requested to do so. However the other functionality does not currently ensure it runs on a particular radio, DiscoverDevices and GetServiceRecords (and as used internally by Connect) will use the primary radio.
We currently are using the original BlueZ ‘hci’ API. For many things their D-Bus based API is recommended instead, we will add support for that at some stage… There seems for instance no native API to get the list of remembered device, unless I’ve missed it…
In the Microsoft Bluetooth API on Win32 (desktop Windows) there’s no simple way to get only the in-range-discoverable devices (as I’ve noted previously one can specify whether one wants remembered and/or unknown devices, but the ‘unknown-only’ result has had any remembered devices removed from it!) This has prevented us from providing the DiscoverDevice(discoverableOnly=true) feature that we provide on every other platform. We also haven’t been able to provide the ‘live’ discovery feature for in-range devices as provided through class BluetoothComponent.
I’ve recently implemented support for using the native Bluetooth events on this platform (I first implemented this code a long time ago, and see below for why I didn’t use it earlier). So now that we have support for the events we can implement both of the features discussed above. Briefly the events are provided through the RegisterDeviceNotifications API and the events are raised as Window Messages. Thus we create a window on which to receive the messages, creating a new message-loop in most cases for the window, and call the API to enable the events.
Thus when ‘live’ discovery is requested via BluetoothComponent, we run a normal discovery process so that the Bluetooth hardware searches for devices, and we monitor the native events at the same time and use the resulting events to know which devices are in-range (and obviously in discoverable mode) and raise the respective BluetoothComponent events.
We also use this functionality to provided the “discoverableOnly” feature. By monitoring the native events we make a list of all the devices that are range, and at the same time we run a discovery asking for all remembered and unknown devices — which make Windows return the union of all remembered and in-range devices — then we filter that list leaving only the devices in it that we saw ‘in-range’ events for. Phew a lot of work for a simple thing. 😦
We should note however that this is useful only on Windows 7 (and perhaps Vista — I haven’t tested); it not useful on Windows XP. The native events aren’t raised there correctly so we can’t use them to provide this functionality. 😦
This code is in the repository now, please test it and let me hear your feedback. (Download the code from http://32feet.codeplex.com/SourceControl/list/changesets, build the FX2 project (only), and reference and use it with your application. Test BluetoothClient.DiscoverDevices(discoverableOnly=true) and BluetoothComponent.DiscoverDevicesAsync(discoverableOnly=true). One can see the native events directly with BluetoothWin32Events — currently it exposed the Radio-In-Range and Radio-Out-Of-Range event only, we don’t expose the HCI or L2CAP events etc.
Differences between Windows XP and 7
The Radio-In-Range event (on Window 7 at least) raises lots of apparently duplicate events, so we need to do some filtering to provide both functions. On Windows XP however the native event is not useful for device discovery; when a discovery process is run we do not see Radio-In-Range events for all discoverable devices, it seems like there are no events for devices we’ve seen before.
It seem that one only reliably gets Radio-In-Range events when a connection is made to a particular remote device (e.g. for BluetoothClient.Connect or BluetoothDeviceInfo.GetServiceRecords). So it seems that the event isn’t raised for discovered devices, but only for devices connected to. During discovery Windows connects to the newly seen devices to then to get their Device Name — which isn’t transferred in the discovery process in earlier Bluetooth versions. That’s why we do see events for new devices during discovery.
So that’s why this code has been “on the shelve” for a while. When tested on Windows XP no useful events were raised. With Windows 7 reliable events are raised during discovery so we can use it now!