.NET CyUSBDevice Recovery

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hey all,

I'm working on making my wrapper around the the CyUSB interface very robust, including being thread and process safe. I've gotten the device to recove in most of my uses cases via code, but there are still some important edge cases that currently require manually unplugging and replugging in the device to make it reset, or else needing to restart an application - which is undesirable.

To simulate different scenarios where things can go awry I'm using the CyUSBDevice reset and reconnect routines. In one of my tests I launch a separate thread that writes and reads a bunch of bulk data.What I want to happen is for the thread performing these I/O transactions to fail when I reset/reconnect/disconnect the device (whether through a false return value or exception). Sometimes this works, but other times it does not. Rather what happens is the CyUSBEndPoint gets stuck in the WaitForIO routine underneath the XferData function and hangs there, never returning! The only way to recover at this point is to kill the application..


Note that i have set the End Point Timeouts to 1sec in these tests - so the I/O if failing to timeout.

Please advise on how to properly interact with the CyUSBDevice and the Bulk End points so that this does not occur. I am using a global mutex to provide thread and process safe access to the device when reading/writing - but there is always the potential for *something* to take down the device, even if just physically unplugging and replugging it back in. I should be able to recover without the CyUSB getting into a deadlock.

Thanks,
Ryan

0 Likes
1 Solution

Hello,

Please refer to the USB control center application present in the FX3 SDK under C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\application\c_sharp\controlcenter

This should give a clear idea in which default application is implemented.

Best Regards,

Yatheesh

View solution in original post

0 Likes
6 Replies
SrinathS_16
Moderator
Moderator
Moderator
1000 replies posted 750 replies posted 500 replies posted

Hello Ryan,

- Please post the code snippet of the host application if possible

- Have you tried using the Cypress USB Control Center with a large bunch of data to be transferred during which the device is removed? I tested this on the FX3 Super Speed Explorer Kit and found that the XferData() call either returns success or it fails but does not get stuck.

- Also, kindly, let me know if you have implemented the DeviceRemoved() event handler in your application.

Best regards,

Srinath S

0 Likes
Anonymous
Not applicable

Hi Srinath,

Below is the common routine used by my code for sending bulk requests (using a request-response model), let me know if you see anything odd. Note that currently the invoker will supply a ResponseBuffer of the appropriate length. If you have a good example of how to figure out how large the response is dynamically that would be helpful:

----------------------------------------------------------------------------------------------

Public Overloads Sub USBIO(ByVal CommandName As String, ByVal CommandBuffer() As Byte, ByVal ResponseBuffer() As Byte, Optional ByVal TimeOutInSec As Single = 1)

        ThrowIfDisposed()

        'Check if Driver Started

        If Not Enabled Then Return

        Dim commandBufferHandle As GCHandle = Nothing

        Dim responseBufferHandle As GCHandle = Nothing

        Try

            _deviceMutex.WaitOne() ' Only one thread in one process may work with this FIC2USB Device at a time

        Catch ex As AbandonedMutexException

            ' TO DO: Adding diagnostics to note that the mutex was abandoned by another process (such as from a crash)

            ' NOTE: Even if this exception occurs, we still successfully acquired the mutex

        End Try

        Try

            ThrowIfDisposed()

            ' BEWARE OF CATASTROPHIC CYUSB BUG: We must pin the command and response buffers prior to passing them off to the unmanaged code,

            ' lest we risk a fatal excepion that will crash the app (regardless of any try...catch block). This bug can be seen when doing

            ' a lot of I/O in very tight loops.

            commandBufferHandle = GCHandle.Alloc(CommandBuffer, GCHandleType.Pinned)

            responseBufferHandle = GCHandle.Alloc(ResponseBuffer, GCHandleType.Pinned)

            'Set Timeout (of input buffer only)

            Me.CyFX2Device.BulkInEndPt.TimeOut = CUInt(TimeOutInSec * 1000)

            'Send Command

            If Me.CyFX2Device.BulkOutEndPt.XferData(CommandBuffer, CommandBuffer.Length) = False Then

                Throw New System.IO.IOException(String.Format("Failed to XferData to BulkOutEndPt 0x{0}", Hex(CyFX2Device.BulkOutEndPt.Address)))

            End If

            'Read Response

            If Me.CyFX2Device.BulkInEndPt.XferData(ResponseBuffer, ResponseBuffer.Length) = False Then

                Throw New System.IO.IOException(String.Format("Failed to XferData from BulkInEndPt 0x{0}", Hex(CyFX2Device.BulkInEndPt.Address)))

            End If

        Catch ex As Exception

            Me.CyFX2Device.BulkOutEndPt.Reset()

            Me.CyFX2Device.BulkInEndPt.Reset()

            LastError = ex

            Throw ex

        Finally

            _deviceMutex.ReleaseMutex()

            If Not IsNothing(commandBufferHandle) Then commandBufferHandle.Free()

            If Not IsNothing(responseBufferHandle) Then responseBufferHandle.Free()

        End Try

    End Sub

0 Likes
Anonymous
Not applicable

Also, here is the code that handles the device attached/detached events (both call the same function). This is executed under a singleton manager class that wraps the CyUSBDeviceList instance for the process. It will in turn create wrappers for the individual CyUSBDevices that we care about. If you have any suggestions for improvement here let me know.
------------------------------------------------------------------

Private Sub UpdateDeviceList()

        ' Go through the CyUSB.USBDeviceList to identify anything that has been added/removed

        _deviceListMutex.WaitOne()

        Try

            ' First check for new devices

            For Each cyDev As CyUSB.CyUSBDevice In mCyUSBDevices

                Dim devMutex = GetMutex(cyDev)

                'Try

                Dim target = myDeviceList.Values.FirstOrDefault(Function(ByVal wrapper As USBDeviceWrapper) wrapper.USBAddress = cyDev.USBAddress)

                If IsNothing(target) Then

                    If (cyDev.VendorID = MY_VID) Then

                        If (cyDev.ProductID >= MY_PID_LOW) And (cyDev.ProductID <= MY_PID_HIGH) Then

                            Dim newDev As New USBDeviceWrapper(cyDev, devMutex)

                            myDeviceList.Add(newDev.USBAddress, newDev)

                            NotifyDeviceAttached(newDev)

                        End If

                    End If

                ElseIf target.VendorID <> cyDev.VendorID OrElse target.ProductID <> cyDev.ProductID Then

                    myDeviceList.Remove(target.USBAddress)

                    target.Dispose()

                    NotifyDeviceRemoved(cyDev.USBAddress)

                    If (cyDev.VendorID = MY_VID) Then

                        If (cyDev.ProductID >= MY_PID_LOW) And (cyDev.ProductID <= MY_PID_HIGH) Then

                            Dim newDev As New USBDeviceWrapper(cyDev, devMutex)

                            myDeviceList.Add(newDev.USBAddress, newDev)

                            NotifyDeviceAttached(newDev)

                        End If

                    End If

                ElseIf target.CyFX2Device.DeviceHandle <> target.CyFX2Device.DeviceHandle Then

                    ' The device was reconnected (?)

                    target.CyFX2Device = cyDev

                End If

            Next

            ' Second check for removed devices

            Dim wrapperList = myDeviceList.Values.ToArray()

            For Each curr As usbFIC2USB In wrapperList

                Dim devFound As Boolean = False

                Dim devIndex As Integer = 0

                For devIndex = 0 To mCyUSBDevices.Count - 1

                    If curr.USBAddress = mCyUSBDevices(devIndex).USBAddress Then

                        devFound = True

                        Exit For

                    End If

                Next

                If devFound Then Continue For

                ' The wrapper did not have a corresponding cyUSBDevice, so dispose of it

                myDeviceList.Remove(curr.USBAddress)

                NotifyDeviceRemoved(curr.USBAddress)

                curr.Dispose()

            Next

        Catch ex As Exception

#If DEBUG Then

            Debugger.Launch()

#End If

            Throw ex

        Finally

            _deviceListMutex.ReleaseMutex()

        End Try

    End Sub

0 Likes
Anonymous
Not applicable

Also, after I fixed a small bug in my NotifyDeviceRemoved function that was preventing listeners from being notified that the device had been removed, the problem appears to have gone away. However, this shouldn't make any difference. Even if other code incorrectly tries to access a disposed CyUSBDevice object (since they weren't notified about it being removed), any requests should still ultimately return with either a false return value or by means of an exception and not hang. However, perhaps this will help focus the investigation into fixing this off-case.

Is there perhaps some use of a WeakReference under the covers that is being checked for disposal purposes?

EDIT: I confirmed that I could re-create the problem by commenting out the few lines of code above that are responsible for notifying listeners that a device was removed and for removing the device from the local list of devices and disposing the wrapper object. So likely a reference counting issue going on here.

0 Likes
Anonymous
Not applicable

The CyUSB Device hanging issue continues to intermittently pop up. This time I'm seeing it hang after a Bulk XFER fails and I attempt to Reset the BulkInEndPt. The reset command hangs.

0 Likes

Hello,

Please refer to the USB control center application present in the FX3 SDK under C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\application\c_sharp\controlcenter

This should give a clear idea in which default application is implemented.

Best Regards,

Yatheesh

0 Likes