Async Discovery via DiscoverDevicesAsync()

Topics: Bluetooth - Microsoft
Nov 23, 2012 at 5:32 AM

I'm using .NET CF 3.5 on a Windows Mobile 6.5 device, and a 5.0 device.

For the life of me I cannot get this to work!

Private _discoveredDeviceQueue As New Queue(Of BluetoothDeviceInfo)

        Private Sub Discovery_Progress(ByVal sender As Object, ByVal e As InTheHand.Net.Bluetooth.DiscoverDevicesEventArgs)
            Dim bco As BluetoothComponent = CType(e.UserState, BluetoothComponent)
            _discoverProgressHandle.Set()

            Debug.WriteLine("Discovery Progress")

            ' Add the devices to the queue
            For Each info As BluetoothDeviceInfo In e.Devices
                _discoveredDeviceQueue.Enqueue(info)
            Next
        End Sub

        Private Sub Discovery_Complete(ByVal sender As Object, ByVal e As InTheHand.Net.Bluetooth.DiscoverDevicesEventArgs)
            Dim bco As BluetoothComponent = CType(e.UserState, BluetoothComponent)
            _discoverProgressHandle.Set()
            _discoverCompleteHandle.Set()

            Debug.WriteLine("Discovery Complete")

            For Each info As BluetoothDeviceInfo In e.Devices
                _discoveredDeviceQueue.Enqueue(info)
            Next

            ' Dispose down the bluetooth component
            bco.Dispose()
            _discoveryBtClient.Dispose()
        End Sub


        Private Sub DiscoverBluetoothCatProbes(ByVal state As Object)
            Dim finished As Boolean = False
            ' Create and hook in the relevant events
            Dim incomingSocketCancelationHandle As New ManualResetWaitEvent(False)

            If BluetoothRadio.IsSupported AndAlso BluetoothRadio.PrimaryRadio IsNot Nothing Then
                Try
                    ' Clear down any previous queues
                    _discoveredDeviceQueue.Clear()

                    ' Initialise a new bluetoothclient
                    _discoveryBtClient = New BluetoothClient()

                    ' Stop anything waiting on this running process
                    _discoverRunningWaitHandle.Reset()
                    _discoverProgressHandle.Reset()

                    ' Set the complete waithandle to blocked
                    _discoverCompleteHandle.Set()

                    ' Process any known devices initialy
                    Discovery_Process(_discoveryBtClient.DiscoverDevices(255, True, True, False))

                    ' Begin the listening process
                    ThreadPool.QueueUserWorkItem(AddressOf BeginAcceptClients, New Object() {incomingSocketCancelationHandle})

                    logger.Info("DiscoverBluetoothCatProbes|Discovery Started")

                    While Not finished
                        Select Case EventWaitHandle2.WaitAny(New EventWaitHandle2() {_discoverCancelHandle, _
                                                                                     _discoverCompleteHandle, _
                                                                                     _discoverProgressHandle}, -1)
                            Case 0 ' Cancelation
                                finished = True

                            Case 1 ' Discovery Complete, restart it
                                If _discoveryBtClient Is Nothing Then
                                    ' Initialise a new bluetoothclient
                                    _discoveryBtClient = New BluetoothClient()
                                End If

                                If _discoveryBtClient IsNot Nothing Then
                                    Try
                                        Dim bco As New BluetoothComponent(_discoveryBtClient)

                                        AddHandler bco.DiscoverDevicesProgress, AddressOf Discovery_Progress
                                        AddHandler bco.DiscoverDevicesComplete, AddressOf Discovery_Complete

                                        bco.DiscoverDevicesAsync(255, False, False, False, True, bco)

                                    Catch ex As Exception
                                        logger.WarnException("DiscoverBluetoothCatProbes|Discovery Complete Exception", ex)

                                    End Try
                                End If
                            Case 2 ' Discovery Progress

                                ' Process the discovered devices
                                Discovery_Process(_discoveredDeviceQueue.ToArray)
                                _discoveredDeviceQueue.Clear()

                                _discoverProgressHandle.Reset()

                        End Select
                    End While
                Finally
                    ' Set this flag saying we're responding to the cancelation request
                    _discoverCancelHandle.Reset()

                    ' Cancel the incoming socket request
                    incomingSocketCancelationHandle.Set()

                    If _discoveryBtClient IsNot Nothing Then
                        ' Close the btClient handle
                        _discoveryBtClient.Close()
                    End If

                    ' Tell other processes that we're ending by unblocking them
                    _discoverRunningWaitHandle.Set()
                End Try
            Else
                logger.Error("Bluetooth Radio is not supported on this device")
            End If
        End Sub

32feet.NET: 'InTheHand.Net.Personal, Version=3.5.605.0, Culture=neutral'   versions: '3.5.605.0' and '3.5.0605.0'.

The progress functions and complete functions never get called.

This is with the complete list of discovered devices cleared or populated.

My only alternative is

 

Private Sub DiscoverBluetoothCatProbes(ByVal state As Object)
            Dim finished As Boolean = False
            ' Create and hook in the relevant events
            Dim incomingSocketCancelationHandle As New ManualResetWaitEvent(False)

            If BluetoothRadio.IsSupported AndAlso BluetoothRadio.PrimaryRadio IsNot Nothing Then
                Try
                    ' Initialise a new bluetoothclient
                    _discoveryBtClient = New BluetoothClient()

                    ' Set the discovery time right down to 3 seconds
                    _discoveryBtClient.InquiryLength = TimeSpan.FromSeconds(10)

                    ' Stop anything waiting on this running process
                    _discoverRunningWaitHandle.Reset()

                    ' Set the complete waithandle to blocked
                    _discoverCompleteHandle.Set()

                    ' Connect any disconnected interfaces on start of discovery
                    For Each dev As ICatHardwareInterface In Me.HardwareInterfaces
                        If dev.Connected = eCatConnectionStatus.Disconnected Then
                            dev.Connect()
                        End If
                    Next

                    ' Process any known devices initialy
                    Discovery_Process(_discoveryBtClient.DiscoverDevices(255, True, True, False))

                    ' Begin the listening process
                    ThreadPool.QueueUserWorkItem(AddressOf BeginAcceptClients, New Object() {incomingSocketCancelationHandle})

                    logger.Info("DiscoverBluetoothCatProbes|Discovery Started")

                    While Not finished
                        Select Case EventWaitHandle2.WaitAny(New EventWaitHandle2() {_discoverCancelHandle, _
                                                                                     _discoverCompleteHandle}, -1)
                            Case 0 ' Cancelation
                                finished = True

                            Case 1 ' Discover any discoverable probes, exclude all the already discovered probes
                                Try
                                    ' Attempt to lock
                                    If Monitor.TryEnter(_syncBluetooth) Then
                                        ' Lets just try finding one device and processing it immediately
                                        Discovery_Process(_discoveryBtClient.DiscoverDevices(255, False, False, False, True))

                                        Monitor.Exit(_syncBluetooth)
                                    End If

                                    '' Pause
                                    If _discoverCancelHandle.WaitOne((Rnd() * 3000) + 2000) Then
                                        finished = True
                                    End If

                                Catch ex As Exception
                                    logger.WarnException("DiscoverBluetoothCatProbes|Discovery Complete Exception", ex)

                                    ' Refresh the bluetooth client component if there was nothing detected
                                    _discoveryBtClient.Dispose()

                                    _discoveryBtClient = New BluetoothClient()

                                    ' Set the discovery time right down to 3 seconds
                                    _discoveryBtClient.InquiryLength = TimeSpan.FromSeconds(10)

                                    '' Pause
                                    If _discoverCancelHandle.WaitOne((Rnd() * 3000) + 2000) Then
                                        finished = True
                                    End If

                                Finally

                                    ' Loop around again
                                    _discoverCompleteHandle.Set()

                                End Try

                        End Select

                    End While

                    logger.Info("DiscoverBluetoothCatProbes|Discovery complete")

                Finally
                    ' Set this flag saying we're responding to the cancelation request
                    _discoverCancelHandle.Reset()

                    ' Cancel the incoming socket request
                    incomingSocketCancelationHandle.Set()

                    If _discoveryBtClient IsNot Nothing Then
                        ' Close the btClient handle
                        _discoveryBtClient.Close()
                    End If

                    ' Tell other processes that we're ending by unblocking them
                    _discoverRunningWaitHandle.Set()
                End Try
            Else
                logger.Error("Bluetooth Radio is not supported on this device")
            End If
        End Sub

This does work. I find that if I do not lock out the discovery process from working while i'm actively attempting to connect to devices then I get alot of connection issues.

Any suggestion as to why i'm not getting call backs from the async function?

 

My connection functions use ;

Bluetooth.BluetoothSecurity.RemoveDevice(_adc)

Bluetooth.BluetoothSecurity.PairRequest(_adr,_code)

 

Developer
Nov 26, 2012 at 9:02 PM

> I'm using .NET CF 3.5 on a Windows Mobile 6.5 device, and a 5.0 device.

What Bluetooth stack on each? Microsoft, or Widcomm, or?

So you check that you call DiscoverDevicesAsync, but you find that neither Discovery_Progress nor Discovery_Complete are called?

Nov 30, 2012 at 6:22 AM

I've put the debugger on line;

bco.DiscoverDevicesAsync(255, False, False, False, True, bco)

and thats definately called

I've also put the debugger on the Discovery_Progress and Discovery_Complete lines, nothing...

PrimaryRadio.Manufacturer = Qualcomm {29}
PrimaryRadio.SoftwareManufacturer Microsoft {6}
Developer
Dec 11, 2012 at 8:22 PM

So its the Microsoft stack.

Does the non-async method return? e.g bcli.DiscoverDevices(255, False, False, False, True)

Dec 12, 2012 at 5:15 AM

I'll have to give the false,false,false,true a quick spin

Developer
Dec 12, 2012 at 4:44 PM

Make sure you try the call BluetoothClient.DiscoverDevices

Dec 13, 2012 at 4:22 AM
Edited Dec 13, 2012 at 4:22 AM

I do this first;

_discoveryBtClient.DiscoverDevices(255, True, True, False)

then loop while in "discovery" mode;

_discoveryBtClient.DiscoverDevices(255, False, False, False, True)

This does work and produces the result I expect.

Developer
Dec 13, 2012 at 5:05 PM

What DiscoveryDevicesAsync does is use BluetoothClient.BeginDiscoverDevices and EndDiscoverDevices, and it runs the Progress and Completed event on the UI thread. I presume you app is WinForms. I haven't fully understood your code above. Is the UI thread blocked or is it running?

Dec 13, 2012 at 11:24 PM

The UI thread starts up a background thread which does all my incoming port requests and device discoveries.

So the thread that starts the live discovery is already a background thread, and not the UI thread. Would this be the source of the problem?

Should I be using a form.invoke to start the discovery process from the background thread? that way any code you call inside DiscoveryDeviceAsync knowns the UI thread ID?

furthermore, any discovered device is then passed off to further background threads which initialize my devices, connects, get stuff and monitors the connected IO.stream for errors.

 

UI Thread -> Kick off background incoming and discovery thread

Discovery thread -> kick off IO.Stream and application protocol monitor thread per discovered device

Monitor thread(s) -> call btClient.Connect().. fires off all up/down events to UI thread. Takes requests to start streaming data and doing all the socket read/writes.

I've also had to put a mutex lock between the monitor threads doing the Connect() call and the DeviceDiscover() calls. Otherwise nothing worked.. so i'm not sure if the library doesn't handle these two being called by different threads?

The UI thread shouldn't be blocked under any case, its idle doing only updates to text boxes and alike.