BluetoothRadio.PrimaryRadio
and/or BluetoothRadio.AllRadios
are non-empty, and that one has SoftwareManufacter
containing a BlueSoleil
value.BlueSoleil Btsdk_Init: OK=0x0000 Num factories: 1, Primary Factory: BlueSoleilFactory
This is a a summary see below for the details of each classes supported methods and properties.
There is good support for BluetoothRadio, BluetoothDeviceInfo including RSSI, and device discovery including ‘live’ discovery. There is no support for BluetoothListener (there seems to be no BlueSoleil API), and there is only partial support for SDP querying (returns both partial records and partial attributes). BluetoothSecurity.RemoveDevice is supported, but more work is needed for PairRequest.
BluetoothClient.Connect is supported for RFCOMM/SPP connections. However connections can’t be made to profiles that BlueSoleil supports directly, for instance an RFCOMM connection to OBEX Push isn’t possible. Nor is it it possible to make a connection to a specific RFCOMM port number. BluetoothClient.Authenticate, Encrypt are not supported (no API support), and we haven’t looked at support for SetPin.
BluetoothClient’s data transfer is somewhat lacking in comparison with the other stacks as it doesn’t use Sockets nor has it an data transfer API like Widcomm. Instead it creates a virtual COM port for each connection, and that’s what we have to use. It creates a number of problems, firstly when there’s no data in the buffer for Read we would expect Read to block but instead we get an IO error, so we have to workaround that. Then on Write there seems a lack of flow control, we now internally split any any big writes into smaller chunks and in testing that seems to stop data being lost.
Due to the various restrictions above ObexWebRequest and ObexListener are not supported currently. It should be possible at least to support ObexWebRequest by internally using the BlueSoleil OBEX API directly, something for the future, and volunteers welcomed.
To check if BlueSoleil support is being loaded, check whether BluetoothRadio.PrimaryRadio or AllRadios returns a radio and whether its SoftwareManufacturer is a enum value of IvtBlueSoleil.
Please let me have any feedback.
This stack does work when the Microsoft stack is present/active. However the Microsoft stack then seems not to work though. That's on a Windows 7 box with BlueSoleil version 5.X.X.X. Let me know if you find otherwise.
(Test) To Do:
Implementation To Do:
To Do:
Test | Result |
---|---|
Radio (dongle) is un-plugged | Stack is not loaded |
Radio is disabled |
It does not turn-on automatically. Instead use Radio.set_Mode to enable it. Note we don't turn the radio on at any operation (as of r78137+). |
To Do:
See the two tables after this one for the values of the properties when the radio is disabled or un-plugged.
Test | Expected (BlueSoleil UI) | Result |
---|---|---|
ClassOfDevice ClassOfDevice { get; } | 0x120104, from Remote Discovery |
120104 device: DesktopComputer / service: Network, ObjectTransfer |
IntPtr Handle { get; } | NotSupported | |
HardwareStatus HardwareStatus { get; } | ✔ | |
int LmpSubversion { get; } | 4203 => decimal 16910 | 16910 |
BluetoothAddress LocalAddress { get; } | 00:19:0E:02:C9:16 | 00:19:0E:02:C9:16 |
Manufacturer Manufacturer { get; } | Broadcom Corporation | Broadcom |
RadioMode Mode { get; … |
Connectable & Discoverable:
|
Results:
|
set; } |
Results:
|
|
string Name { get; … | alanlt2w | alanlt2w |
set; } | ✘ NotImplemented | |
Manufacturer SoftwareManufacturer { get; } | IvtBlueSoleilXxxx |
Property | Value |
---|---|
HardwareStatus | Shutdown |
Mode | PowerOff |
Name | empty (String.Empty) |
Address | empty (BluetoothAddress.None) |
Status of other properties is undefined. |
Property | Value |
---|---|
HardwareStatus | NotPresent |
Mode | PowerOff |
Name | empty (String.Empty) |
Address | empty (BluetoothAddress.None) |
Status of other properties is undefined. |
To Do:
To Do, for created-from:
Test Notes
Test | Result |
---|---|
bool Authenticated { get; } | ✔ |
ClassOfDevice ClassOfDevice { get; } | ✔ |
bool Connected { get; } | ✔ |
BluetoothAddress DeviceAddress { get; } | ✔ |
string DeviceName { get; … | ✔ |
set; } | ✔ |
byte[][] GetServiceRecordsUnparsed(Guid service); | ✘ NotSupported |
ServiceRecord[] GetServiceRecords(Guid service); | ✔ See below. |
Guid[] InstalledServices { get; } | ✘ NotImplemented |
DateTime LastSeen { get; } | ?????? |
DateTime LastUsed { get; } | ✘ Returns DateTime.MinValue. |
void Refresh(); | ✔ Resets DeviceName alone. |
bool Remembered { get; } | ✔ |
int Rssi { get; } | ✔ Needs a connection to the remote device to work. |
void SetServiceState(Guid service, bool state, bool throwOnError); |
✔ Tested working for SerialPort and PAN for both enabling and disabling —
can disable a connection created by the BlueSoleil UI (and presumably a connection
opened by BluetoothClient too, beware!! TODO fix). Test for HID, and others? |
void SetServiceState(Guid service, bool state); | |
void ShowDialog(); | ✘ NotImplemented |
void Update(); | ✘ NotImplemented |
* MSFT+Win32 to Widcomm(000aaa6865bb):1101
System.ComponentModel.Win32Exception: The specified service does not exist as an
installed service
at InTheHand.Net.Sockets.WindowsBluetoothDeviceInfo.SetServiceState(Guid service,
Boolean state, Boolean throwOnError)
*
To Do:
Known flaws:
Test | Result | Error code on MSFT+Win32 |
---|---|---|
Query for a SIG-format Class of a running remote service | ✔ | |
Query for no matching records (Use a UUID not present on the remote device, e.g. "ReferencePrinting 0x1119". Expect: See an empty result and not an exception). |
✔ | |
Query for a custom (non-SIG-format) Class of a running remote service | ✘ Returns zero records. | |
Device not in range | ✔ TimedOut SHOULD 10108 | 10108 (WSASERVICE_NOT_FOUND) |
Running SdpCreateTwoSppRecordsOneWithAvailAndBrowse e.g. on Widcomm, run SdpQuery/AllRecords on SdpBrowser BlueSoleil.
ServiceName: 'Bluetooth Serial Port' ServiceClasses: 0x1101 SerialPort Channel Num: 1 ServiceName: 'Network Access' ServiceClasses: 0x1117 GN Channel Num: <not assigned> ServiceName: 'Network Access' ServiceClasses: 0x1115 Panu Channel Num: <not assigned> ServiceName: 'Dial-up Networking' ServiceClasses: 0x1103 DialupNetworking Channel Num: 2 ServiceName: 'File Transfer' ServiceClasses: 0x1106 ObexFileTransfer Channel Num: 4 ServiceName: 'Fax' ServiceClasses: 0x1111 Fax Channel Num: 5 ServiceName: 'PIM Synchronization' ServiceClasses: 0x1104 IrMCSync Channel Num: 6 ServiceName: 'Sync Command Service' ServiceClasses: 0x1107 IrMCSyncCommand Channel Num: 6 ServiceName: 'Headset' ServiceClasses: 0x1108 Headset, 0x1203 GenericAudio Channel Num: 7 ServiceName: 'Headset' ServiceClasses: 0x111E Handsfree, 0x1203 GenericAudio Channel Num: 8 ServiceName: 'Audio Gateway' ServiceClasses: 0x1112 HeadsetAudioGateway, 0x1203 GenericAudio Channel Num: 9 ServiceName: <none> ServiceClasses: 0x1114 WapClient Channel Num: 22 ServiceName: <none> ServiceClasses: e665c159-4721-4e73-8e97-9a8be42423d9 Channel Num: 10 |
ServiceName: 'Bluetooth Serial Port' ServiceClasses: 0x1101 SerialPort Channel Num: 1 ServiceName: 'Network Access' ServiceClasses: 0x1117 GN Channel Num: <not assigned> ServiceName: 'Network Access' ServiceClasses: 0x1115 Panu Channel Num: <not assigned> ServiceName: 'Dial-up Networking' ServiceClasses: 0x1103 DialupNetworking Channel Num: 2 ServiceName: 'File Transfer' ServiceClasses: 0x1106 ObexFileTransfer Channel Num: 4 ServiceName: 'Fax' ServiceClasses: 0x1111 Fax Channel Num: 5 ServiceName: 'PIM Synchronization' ServiceClasses: 0x1104 IrMCSync Channel Num: 6 ServiceName: 'Sync Command Service' ServiceClasses: 0x1107 IrMCSyncCommand Channel Num: 6 ServiceName: 'Headset' ServiceClasses: 0x1108 Headset Channel Num: 7 ServiceName: 'Headset' ServiceClasses: 0x111E Handsfree Channel Num: 8 ServiceName: 'Audio Gateway' ServiceClasses: 0x1112 HeadsetAudioGateway Channel Num: 9 ServiceName: <none> ServiceClasses: 0x1114 WapClient Channel Num: <not assigned> |
Note: That's the result against Widcomm on WinXP. Against MSFT on WinXP the port for the WapClient service is correctly got.
To Do:
32feet.NET | |
---|---|
BluetoothDeviceInfo[] DiscoverDevices(…) | ✔ All/Rmbd/DiscoOnly/etc |
BluetoothDeviceInfo[] Begin-/EndDiscoverDevices(…) | ✔ |
TimeSpan InquiryLength { get; | ✔ |
int InquiryAccessCode { get; set; } | ✘ NotImplemented |
void Connect(…); | ✔ See details below. |
void Begin-/EndConnect(…); | ✔ |
bool Connected { get; } | ✔ See NetworkStream below. |
NetworkStream GetStream(); | ✔ |
Socket Client { get; set; } | ✘ NotSupported |
int Available { get; } | ✔ |
LingerOption LingerState { get; set; } | ✘ NotImplemented |
void Dispose(); | ✔ (ToDo disallow/abort device discovery ). |
bool Authenticate { get; … | ✔ returns false |
set; } | ✘ NotSupported |
bool Encrypt { get; … | ✔ returns false |
set; } | ✘ NotSupported |
void SetPin(string pin); | ✘ NotImplemented |
void SetPin(BluetoothAddress device, string pin); | ✘ NotImplemented |
Guid LinkKey { get; } | ✘ NotImplemented |
LinkPolicy LinkPolicy { get; } | ✘ NotImplemented |
string GetRemoteMachineName(BluetoothAddress) | ✔ |
string RemoteMachineName { get; } | ✔ |
BluetoothEndPoint RemoteEndPoint { get; } | ✔ |
See BluetoothDeviceInfo for discovery testing.
To Do:
Test | Result | Error code on MSFT+Win32 |
---|---|---|
To Do:
Test | Result | Error code on MSFT+Win32 |
---|---|---|
Service with SIG Class Id e.g. Wap | ✔ | |
Service with custom (non-SIG) Class Id (Use BtLsnr->ListSomeCustomUuids) |
✔ | |
Connect to a particular port number | ✘ Need to re-test/investigate. | |
No Service with given Class Id | ✔ [NO_SERVICE] todo! ...... | ?10049 |
No Device with given Address | ✔ SoEx TimedOut [PAGE_TIMEOUT] | 10060 TimedOut |
(Service doesn't have RFCOMM pdl) | ✔ [OPERATION_FAILURE] ! | 10064 HostDown |
Already a connection to the RFCOMM port/channel | ✔ [NO_SERVICE] Re-test TODO | 10048 AddressAlreadyInUse |
Connect to 0x1105 OBEX Push | ✘ Not supported by BlueSoleil | |
Connect to 0x1106 OBEX FTP | ✘ Not supported by BlueSoleil | |
Connect to server that has "require authentication" | ✐ [OPERATION_FAILURE] TODO Re-test |
Connecting to: 008098244CA4:00001105-0000-1000-8000-00805f9b34fb:-1 ...
Gonna Btsdk_ConnectAppExtSPPService with: BtSdkAppExtSPPAttrStru sdp_record_handle:
0x0 service_class_128: 00001105-0000-1000-8000-00805f9b34fb svc_name: "\x00..."
rf_svr_chnl: 0 com_index: 0.
HandleConnectionEventInd event: CONN_CFM, conn_hdl: 0x1C50FC8, arg.hDev: 0x1C60790
BlueSoleil LiveConns count: -2.
ret: OK, hConn: 0x1C50FC8, with: BtSdkAppExtSPPAttrStru sdp_record_handle: 0x0 service_class_128:
00001105-0000-1000-8000-00805f9b34fb svc_name: "\x00..." rf_svr_chnl: 0 com_index:
0.
Fail: sppAttr.rf_svr_chnl: 0
HandleConnectionEventInd event: DISC_CFM, conn_hdl: 0x1C50FC8, arg.hDev: 0x1C60790
InTheHand.Net.Bluetooth.BlueSoleil.BlueSoleilException: Exception of type 'InTheHand.Net.Bluetooth.BlueSoleil.BlueSoleilException'
was thrown. Error: OBEX_INDEX (0x600)
Fail: RemoveConnection
BlueSoleil LiveConns count: 0.
Gonna Btsdk_ConnectAppExtSPPService with: BtSdkAppExtSPPAttrStru sdp_record_handle:
0x0 service_class_128: 00001105-0000-1000-8000-00805f9b34fb svc_name: "\x00..."
rf_svr_chnl: 0 com_index: 0.
ret: REQUEST_TIMEOUT, hConn: 0x0, with: BtSdkAppExtSPPAttrStru sdp_record_handle:
0x0 service_class_128: 00001105-0000-1000-8000-00805f9b34fb svc_name: "\x00..."
rf_svr_chnl: 0 com_index: 0.
InTheHand.Net.Bluetooth.BlueSoleil.BlueSoleilException: Exception of type 'InTheHand.Net.Bluetooth.BlueSoleil.BlueSoleilException'
was thrown. Error: REQUEST_TIMEOUT (0x6C8)
Gonna Btsdk_ConnectAppExtSPPService with: BtSdkAppExtSPPAttrStru sdp_record_handle:
0x0 service_class_128: 00001106-0000-1000-8000-00805f9b34fb svc_name: "\x00..."
rf_svr_chnl: 0 com_index: 0.
ret: OPERATION_FAILURE, hConn: 0x0, with: BtSdkAppExtSPPAttrStru sdp_record_handle:
0x0 service_class_128: 00001106-0000-1000-8000-00805f9b34fb svc_name: "\x00..."
rf_svr_chnl: 0 com_index: 0.
InTheHand.Net.Bluetooth.BlueSoleil.BlueSoleilException: Exception of type 'InTheHand.Net.Bluetooth.BlueSoleil.BlueSoleilException'
was thrown. Error: OPERATION_FAILURE (0x302)
To Do:
Test | Expected | Result |
---|---|---|
Read when buffer empty. | On standard BlueSoleil (& System.IO.SerialPort) this fails... | ✔ |
Write an amount bigger than the buffer size. | On standard BlueSoleil (& System.IO.SerialPort) data is lost in this case... | ✔ |
Read thru/after Remote Close | Return zero. | ✔ |
Write thru(if poss)/after Remote Close | IOEx(SocketEx(WSAECONNABORTED)). | ✔ |
Flush when not-open | NetworkStream does not throw ObjectDisposedException. | ✔ |
Client.Connected after local close | ✔ | |
Client.Connected after network close | Should be false after the connection close and there's been a failing I/O operation. | ✔ We have Connected=false as *soon* as the connection closes rather than only after an I/O operation. |
Connections close at app exit? |
BlueSoleil doesn't automatically handle this. Oh, how I wish they and Widcomm used real Windows Handles, and not their own ids. (Maybe it’s by design however, so that you can keep using the connection through its COM port after the creating application exits). |
✔ We use a CriticalFinalizerObject to close each open connection. |
Connections close at Radio Off? |
BlueSoleil does NOT automatically handle this. Writes do fail, but Reads block waiting for data. |
✔ |
Connections close at Radio Unplugged? | BlueSoleil DOES automatically handle this. | ✔ |
Read thru Local Close | “System.IO.IOException: Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall. ---> System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall” | ✔ |
Read after Local Close |
“System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Sockets.NetworkStream'.” |
✔ |
Write after Local Close | ObjectDisposedEx. | ✔ |
Read after remote close when there is still data in the buffer. | ✘ Doesn't return the data, only returns zero-length! | |
Pending Read through remote close when the remote sends data immediately before close. | Get the data then zero-return. | ✔ |
xxxx | yyyy | ✔ / ✘ zzzz |
Not Supported. There seems to be no BlueSoleil API for server-side SPP/RFCOMM.
To Do:
Test | Expected | Result |
---|---|---|
PairRequest(BluetoothAddress device, string pin) | ||
RemoveDevice(BluetoothAddress device) | ✔ Does full remove: name and auth'd state etc are gone. | |
SetPin(BluetoothAddress device, string pin) | ✘ NotImplemented | |
RevokePin(BluetoothAddress device) | ✘ NotImplemented | |
BluetoothAddress GetPinRequest() | ✘ NotImplemented. Is it supportable?? | |
RefusePinRequest(BluetoothAddress device) | ✘ NotImplemented. Is it supportable?? | |
SetLinkKey(BluetoothAddress a, Guid linkkey) | ✘ NotImplemented. Is it supportable?? |
Not supported currently. Our default implementation doesn’t work because it uses a RFCOMM connection, and as noted above BlueSoleil doesn’t support such connections to don’t work to known Profiles. There might be a BlueSoleil OBEX API we could use instead. Volunteers welcomed.
Not supported currently. Our default implementation doesn’t work because as noted above there’s no BlueSoleil API for server-side SPP/RFCOMM. There might be a BlueSoleil OBEX-server API we could use instead. Volunteers welcomed.
- end of document -