6 Replies Latest reply on Oct 30, 2019 12:06 AM by YatheeshK_36

    .NET CyUSBDevice Recovery

      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.



        • 1. Re: .NET CyUSBDevice Recovery

          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

          • 2. Re: .NET CyUSBDevice Recovery

            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)



                    'Check if Driver Started

                    If Not Enabled Then Return


                    Dim commandBufferHandle As GCHandle = Nothing

                    Dim responseBufferHandle As GCHandle = Nothing



                        _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





                        ' 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



                        LastError = ex

                        Throw ex



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

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

                    End Try

                End Sub

            • 3. Re: .NET CyUSBDevice Recovery

              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




                          ' First check for new devices

                          For Each cyDev As CyUSB.CyUSBDevice In mCyUSBDevices


                              Dim devMutex = GetMutex(cyDev)



                              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)


                                      End If

                                  End If



                              ElseIf target.VendorID <> cyDev.VendorID OrElse target.ProductID <> cyDev.ProductID 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)


                                      End If

                                  End If


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

                                  ' The device was reconnected (?)

                                  target.CyFX2Device = cyDev

                              End If



                          ' 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



                              If devFound Then Continue For


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






                      Catch ex As Exception

              #If DEBUG Then


              #End If

                          Throw ex



                      End Try


                  End Sub

              • 4. Re: .NET CyUSBDevice Recovery

                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.

                • 5. Re: .NET CyUSBDevice Recovery

                  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.

                  • 6. Re: .NET CyUSBDevice Recovery



                    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,