The Microsoft Bluetooth stack on Windows Vista added support for programming L2CAP and SCO connections.  Also added are a set of IOCTL codes for accessing the stack in various other ways.  Fifteen the codes are listed at http://msdn.microsoft.com/en-us/library/ff536601.aspx “Bluetooth Profile Driver I/O Function Codes” and are all supported from Vista onwards.  One more is defined at http://msdn.microsoft.com/en-us/library/ff536593.aspx “Bluetooth Vendor Commands and Events”, and is supported by “Microsoft Windows Vista SP2 and later operating system versions”

I have previously used the IOCTL_BTH_GET_LOCAL_INFO code for bug 30326 “Windows 7 BluetoothRadio HCI and LMP version numbers” which allows us to get the attached controllers HCI and LMP version numbers.

However when one looks at the Windows SDK header file (bthioctl.h) that defines these codes, we find more listed than are documented at MSDN.  The 15 above are as expected are defined for Vista (no service-pack) and later, these include IOCTL_BTH_GET_LOCAL_INFO, IOCTL_BTH_GET_DEVICE_INFO, IOCTL_BTH_SDP_CONNECT, also present are the ones for the L2CAP and SCO interfaces (e.g. IOCTL_INTERNAL_BTH_SUBMIT_BRB).  We then see the single code (IOCTL_BTH_HCI_VENDOR_COMMAND) which is included on Windows 7, and on Windows Vista with Service Pack 2 or with the Windows Vista Feature Pack for Wireless (KB942567).

Finally we see five that are defined there but not enabled in any current platform, these include IOCTL_BTH_EIR_GET_RECORDS and IOCTL_BTH_EIR_SUBMIT_RECORD.  These are disabled with the comment (sic):

#ifdef FULL_EIR_SUPPORT // in WUR this funcitonality is disabled

I’ve done some investigation to find out which codes are truly supported on which platforms.  I tested all user-level codes from 0 to 255 (i.e. 0x410300 to 0x4103FC).  On XP, as expected, all codes fail and return error 50 which is ERROR_NOT_SUPPORTED.  On Windows 7 again –we find the support matches the documentation.  All the ones disabled with that comment return that same error code, with only the sixteen documented working (all the others fail).

I guess this is not too surprising but i would have been nice to find that these extra features were present. :-,)

So to confirm on Windows 7 the supported user-level codes are:

0x410000 IOCTL_BTH_GET_LOCAL_INFO
0x410004 IOCTL_BTH_GET_RADIO_INFO
0x410008 IOCTL_BTH_GET_DEVICE_INFO
0×41000C IOCTL_BTH_DISCONNECT_DEVICE
0x410050 IOCTL_BTH_HCI_VENDOR_COMMAND
0x410200 IOCTL_BTH_SDP_CONNECT
0x410204 IOCTL_BTH_SDP_DISCONNECT
0x410208 IOCTL_BTH_SDP_SERVICE_SEARCH
0×41020C IOCTL_BTH_SDP_ATTRIBUTE_SEARCH
0x410210 IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH
0x410214 IOCTL_BTH_SDP_SUBMIT_RECORD
0x410218 IOCTL_BTH_SDP_REMOVE_RECORD
0×41021C IOCTL_BTH_SDP_SUBMIT_RECORD_WITH_INFO

Start-up, console/debug logging:

[Error 11:14:14.598] [UiaDbusBridge.RaiseAutomationEvent] Inconsistent provider -> wrapper mapping state
[Error 11:14:14.696] [UiaDbusBridge.RaiseAutomationEvent] Inconsistent provider -> wrapper mapping state
Exception creating factory 'InTheHand.Net.Bluetooth.SocketsBluetoothFactory, ex: System.DllNotFoundException: Irprops.cpl
  at (wrapper managed-to-native) InTheHand.Net.Bluetooth.Msft.NativeMethods:BluetoothFindFirstRadio (InTheHand.Net.Bluetooth.BLUETOOTH_FIND_RADIO_PARAMS&,intptr&)
  at InTheHand.Net.Bluetooth.Msft.WindowsBluetoothRadio.get_AllRadios () [0x00000] in <filename unknown>:0
  at InTheHand.Net.Bluetooth.Msft.WindowsBluetoothRadio.get_IsPlatformSupported () [0x00000] in <filename unknown>:0
  at InTheHand.Net.Bluetooth.SocketsBluetoothFactory..ctor () [0x00000] in <filename unknown>:0
  at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod*,object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00119] in /usr/src/packages/BUILD/mono-2.8/mcs/class/corlib/System.Reflection/MonoMethod.cs:523
BluezFactory platform: Unix = 0x00000004
got Manager
Dbus loop running
DefaultAdapter : ObjectPath
got Adapter
Now Registered2
InitRadios idPrimary: 0, dd: 14
Radio SUCCESS, addr: 001583B41BFA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
InitRadios curDd: 15
Radio SUCCESS, addr: 001583B41BFA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
Id: 0, DD: 16
Radio SUCCESS, addr: 001583B41BFA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
Done BluezFactory init.

Get All Radios (one present):

---- GetAllRadios ----
1)  Radio, address: 00:15:83:B4:1B:FA
Mode: Discoverable
Name: linux-0
HCI Version: v2_0wEdr, Revision: 1958
LMP Version: v2_0wEdr, Subversion: 1958
ClassOfDevice: 4A0100, device: Computer / service: Network, Capturing, Telephony
Software: BlueZXxxx,  Hardware: CambridgeSiliconRadio, status: Running
Remote: ''

Logging:

got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA
got Manager
got Adapter
  got addrStr: 00:15:83:B4:1B:FA

Get DeviceInfo (i.e. new BluetoothDeviceInfo(BluetoothAddress.Parse(…)):

---- GetDeviceInfo ----
* FREDPC1w
Address: 000A3A686599
Remembered: False, Authenticated: False, Connected: False
LastSeen: 01/01/0001 00:00:00 (Unspecified), LastUsed: 01/01/0001 00:00:00 (Unspecified)
CoD: (0x000000)
 Device:  Miscellaneous (0x00) / Miscellaneous (0x0000)
 Service: None (0x00)
Rssi: failed

Logging:

got Manager
DefaultAdapter : ObjectPath
got Adapter
gonna FindDevice
GetDevice_ error: org.bluez.Error.DoesNotExist: Device does not exist
No dbus device properties.
_name is null
hci_read_remote_name ret: 0.

Get DeviceInfo to non-existent device:

---- GetDeviceInfo ----
* 00:22:33:44:55:66
Address: 002233445566
Remembered: False, Authenticated: False, Connected: False
LastSeen: 01/01/0001 00:00:00 (Unspecified), LastUsed: 01/01/0001 00:00:00 (Unspecified)
CoD: (0x000000)
 Device:  Miscellaneous (0x00) / Miscellaneous (0x0000)
 Service: None (0x00)
Rssi: failed

Logging:

got Manager
DefaultAdapter : ObjectPath
got Adapter
gonna FindDevice
GetDevice_ error: org.bluez.Error.DoesNotExist: Device does not exist
No dbus device properties.
_name is null
hci_read_remote_name ret: -1.

Set Radio Mode; Success. Logging:

got Adapter
DONE SetAdapterMode.

BDI.GetServiceRecords; Success.  Logging:

got Manager
DefaultAdapter : ObjectPath
got Adapter
gonna FindDevice
GetDevice_ error: org.bluez.Error.DoesNotExist: Device does not exist
No dbus device properties.
Gonna sdp_connect (SafeHandle)...
xAdapter_PropertyChanged name: Devices, newValue: NDesk.DBus.ObjectPath[]
rfcommOnly: False
sdp_service_search_attr_req in: -1267215624, attrid_list: -1267271928
sdp_service_search_attr_req ret: 0, result: -1267467016
attr count: 8
record count: 1
xAdapter_PropertyChanged name: Devices, newValue: NDesk.DBus.ObjectPath[]

BluetoothClient fails!

---- NewBtCli ----
Swallowed Exception: System.PlatformNotSupportedException: 32feet.NET does not support the Bluetooth stack on this device. ---> System.Net.Sockets.SocketException: An address incompatible with the requested protocol was used
  at System.Net.Sockets.Socket..ctor (AddressFamily family, SocketType type, ProtocolType proto) [0x0005e] in /usr/src/packages/BUILD/mono-2.8/mcs/class/System/System.Net.Sockets/Socket_2_1.cs:212
  at InTheHand.Net.Bluetooth.Msft.SocketBluetoothClient.CreateSocket () [0x00000] in :0
  at InTheHand.Net.Bluetooth.Msft.SocketBluetoothClient..ctor (InTheHand.Net.Bluetooth.Factory.BluetoothFactory fcty) [0x00000] in :0
  --- End of inner exception stack trace ---
  at InTheHand.Net.Bluetooth.Msft.SocketBluetoothClient..ctor (InTheHand.Net.Bluetooth.Factory.BluetoothFactory fcty) [0x00000] in :0
  at InTheHand.Net.Bluetooth.BlueZ.BluezClient..ctor (InTheHand.Net.Bluetooth.BlueZ.BluezFactory fcty) [0x00000] in :0
  at InTheHand.Net.Bluetooth.BlueZ.BluezFactory.GetBluetoothClient () [0x00000] in :0
  at InTheHand.Net.Bluetooth.Factory.BluetoothFactory.DoGetBluetoothClient () [0x00000] in :0
  at InTheHand.Net.Sockets.BluetoothClient..ctor (InTheHand.Net.Bluetooth.Factory.BluetoothFactory factory) [0x00000] in :0
  at InTheHand.Net.Sockets.BluetoothClient..ctor () [0x00000] in :0
  at ConsoleMenuTesting.BluetoothTesting.Create_BluetoothClient () [0x00000] in :0
  at ConsoleMenuTesting.BluetoothTesting.NewBtCli () [0x00000] in :0
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod*,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000d0] in /usr/src/packages/BUILD/mono-2.8/mcs/class/corlib/System.Reflection/MonoMethod.cs:223

xx

See http://32feet.codeplex.com/releases/view/67702:-)

Summary

One of the things on my to-do list for our Widcomm support is that on some of the device platforms once the device has gone through a power-down-up change the stack needs to be restarted. On my Asus device in this case we find that some operations fail. Once we re-create the Widcomm objects they works again.

What fails when

On my older iPAQ with Widcomm version 1.7.1.1424 after a power-down-up, there is no problem: things works ok.

On my Asus with Widcomm version “1.8.0 build 4800”, the stack needs to be reset. If we don’t restart the stack then Device Discovery (CBtIf::StartInquiry) and Service Discovery (StartDiscovery) fail for instance (and the latter affects BtCli.Connect).

What we tried

So the obvious thing to do in this case is to close the existing Widcomm C++ objects and initialise new ones. So I implemented that: when the Stack-Down event has been seen, the next time we do an operation we dispose our instance of the CBtIf object and ‘new’ a new instance.

What works and doesn’t

On the Asus that works fine, StartInquiry etc work successfully after the dispose/re-create.

On the iPAQ that’s the case also, but only if we leave some time after the restart before using the stack again. Instead if we access the new instance too soon after the restart we get a crash. Well it looks like a crash in that the application just disappears, but it doesn’t look like a crash in that we get no crash dialog nor apparently any crash dump. Why not?? And we can inspect it with the debugger as we can’t have a debugger stay attached over the power-down-up and it takes too long for ActiveSync and/or a debugger to re-attach to be able to catch the crash.

Any suggestions about investigating this crash are welcomed…

Other thoughts

The other thought was to check the IsStackServerUp and IsDeviceReady methods provided by the Widcomm CBtIf class. We would check these and delay things until the stack was in a safe state. However these methods were added in a version after that that the problematic device has, they were added in 1.7.1.2700 but the iPAQ has 1.7.1.1424.  So they’re not available on the very platform that we need them on.

I had hoped anyway that closing the instance and creating a new one would make everything right — internally it would do a wait if necessary.  What we see of course that the new instance is returned, but then something unknown fails…

Events

One begins to consider whether we need to add some some of version check hack: if (version < 1.8.0.xxxx) then delay-new-instance-creation.  Or something like that…

Or, looking at the logs maybe we can maybe use the different events produced to fingerprint the version.

iPAQ log
At 15:50:20: StackStatusChange: Unloaded
At 15:50:27: StackStatusChange: Reloaded

Asus log
At 15:52:44: StackStatusChange: Down
At 15:53:11: StackStatusChange: Unloaded

Note the difference: iPAQ: Unloaded+Reloaded, Asus: Down+Unloaded with no Reloaded.

Out of interest: Firstly, why no Reloaded in the latter case?  Because the stack is detached on that platform??  Secondly the Widcomm docs say: “DEVST_DOWN indicates that the Bluetooth stack server has been shut down and is not expected to be restarted.”, but that’s not the case here.  Hmm, they seem a bit confused…:-)

I think we’ll have a think about using the Down+Unloaded case to find that the platform needs reset and don’t do the reset in the other cases.  I’ll try and test this on other devices and see what I find.

Other thoughts welcome…

A page from the BlueCove Java Bluetooth library documentation showing how to identify which Bluetooth stack is installed http://www.bluecove.org/bluecove-examples/bluetooth-stack.html It shows screenshots of the device driver info on Windows XP for the Microsoft, Widcomm, and BlueSoleil stacks.

I’ve just checked in support for Widcomm’s COM Port creation classes. Access WidcommSerialPort.CreateClient and store the result and once you’ve finished with the COM port Dispose it, it’ll be Finalized if not referenced.  I’ll look at integrating the functionality into the BluetoothSerialPort class sometime.

I’ve tested it on my Asus WM Classic device and it work fine there. The Widcomm documentation implies that it should work on Win32 too but it doesn’t work on my WinXP Widcomm v3 installation.

Download the library code (revision 85315 or later) from http://32feet.codeplex.com/SourceControl/list/changesets and compile the CF2 project to get the library code to use in your project. You’ll also need the new native Widcomm mapping DLL, get it from http://32feet.codeplex.com/releases/view/61443

Testing shows that if the connected devices go out of range then the connection is lost however (we see DISCONNECT event in the code, and the remote socket server sees close). Presumably we need to implement code to repeatedly retry to reconnect?

I’ve done about a day’s work on that. I’d be glad of a wee ‘reward’ for adding this new feature, particularly if it saves you time on your projects.:-) I’ve Amazon wishlist or paypal for instance.

 I’ve added support for Secure Simple Pairing (SSP) for Windows 7 and Vista SP2 using the Microsoft stack.  When a Windows 7/etc PC has a Bluetooth version 2.1 dongle (radio/controller) attached and a version 2.1 device is to be atempts to authenticate then one of the new SSP authentication methods will be used.  Previously we had support only for the original Bluetooth PIN authentication method and thus BluetoothWin32Authentication would ignore SSP authentication attempts.  It aims to supports all the authentication methods, although I’ve managed to test only the NumericalComparison/JustWorks methods, and not Passkey, PasskeyNotification and OutOfBand methods.

From the BluetoothWin32Authentication class documentation:

[…] the callback includes a parameter of type BluetoothWin32AuthenticationEventArgs. Various authentication methods are available in Bluetooth version 2.1 and later. Which one is being used is indicated by the AuthenticationMethod property. If it is Legacy then the callback method should set the Pin property.

For the other authentication methods e.g. NumericComparison or OutOfBand the callback method should use one or more of the other properties and methods e.g. NumberOrPasskeyAsString, NumberOrPasskey, Confirm, ResponseNumberOrPasskey, ConfirmOob etc.

For more information see the class documentation and the user guide (http://32feet.codeplex.com/wikipage?title=BluetoothWin32Authentication)

Let me have your feedback.

No changes to BluetoothSecurity.PairRequest nor BluetoothWin32Authentication.New(BluetoothAddress,String).  Those will be considered in the future based on your feedback.  This also affects BluetoothClient.SetPin etc.



UPDATED: Renamed to NumberOrPasskey from  NumberOrPasscode etc

Follow

Get every new post delivered to your Inbox.