7 Replies Latest reply on Dec 2, 2020 7:22 AM by GlWa_4058551

    FX3 .Net  XferData call never exits when USB cable is disconnected.

    GlWa_4058551

      Our system  is working well with  FX3     - it is a C#.net application that we are migrating to USB3.

       

      We have found that when USB cable is pulled  bulkendpt XferData call never exits or throws an exception, even though timeout is set.

      ...

      try{

                      BulkOutEndPt.TimeOut = 500;

                      bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesToWrite_CommandRead);  // this line never exits !!

                  }

                  catch(Exception ex) {....

      ...

       

         Adding support for .DeviceRemoved event, allows to at least know this has happened but  the thread executing the Xfer remains blocked.

       

      Has anyone had a similar experience ?   any known workarounds ?  -  I presume we could move to asynchronous transfer but that seems a lot of work to deal with a rare fault condition, and I certainly wouldn't want to do that if I didn't know it would work.

        • 1. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
          YatheeshK_36

          Hello,

           

          Can you please post your application code here.

           

          This is not expected and we have not seen this issue so far.

          The control center application is based on C# and uses XferData call to transfer data.

           

          Thanks,

          Yatheesh

          • 2. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
            GlWa_4058551

            Thank you for your response     -    This is fully repeatable  the system works fine while USB connected but hangs when the cable is pulled

            -    the full application is a large application  that uses USB to communicate between PC and our servo-controller DSP product,   -    code below is full file at the bottom of the chain for FX3 USB comms.   

             

             

             

             

             

            using System;

            using System.Diagnostics;

            using System.Runtime.InteropServices;

            using System.Text;

            using System.IO;

            using System.Threading;

             

             

            using Servotest.D2R.CoreTypes;

            using Servotest.Foundation.Exceptions;

            using Servotest.Foundation.IO;

            using Servotest.Foundation.Logging;

            using Servotest.Foundation.Utils;

            using Servotest.Foundation.Ui.Controls;

            using Servotest.Foundation.Localization;

            using CyUSB;

            using System.Windows.Forms;

             

             

            namespace Servotest.D2R.DspUsb.Hub {

             

             

            // This makes use of the CyUSB.DLL to transfer data to and from the FX3

            // Uses XferData which points to and In/Out endpoint depending on the direction of the data transfer

            // The functions should be called from USBFPGA when in USB 3.0 mode

             

             

            using FPGAWord = UInt32;

            using FPGAWord_16 = UInt16;

            using FPGAWord_3 = UInt32;

             

             

                public class FX3_USB : IUSB {

             

             

                    bool bResult = false;

                    byte[] outData = new byte[1024*16], inData = new byte[1024 * 16];

                    int numberOfBytesReadIn = 16383;

                    int numberOfBytesReadIn_ReadData;

                    int numberOfBytesToWrite_CommandRead;

                    string HUB_Serial;

                  

                    UInt32[] inData_uint = new UInt32[1024*4];

                    byte[] inData_clear = new byte[1024*16];

                    CyUSBDevice myFX3Device = null;                                                 // Create a USB device for our application called myFX3Device

                    CyUSBDevice myDevice = null;                                                    // myDevice represents the bulkloop device in this example

                    USBDeviceList usbDevices = null;                                                // Dynamic list of USBdevcies bound to CyUSB.sys

                    CyBulkEndPoint BulkInEndPt = null;                                              // We need one Bulk IN endpoint

                    CyBulkEndPoint BulkOutEndPt = null;                                             // We need one Bulk OUT endpoint

                    CyControlEndPoint CtrlEndPt = null;

             

             

                    static int file_bytes;

                    byte[] file_buffer;

                    bool success;

             

                    const int VID_Boot = 0x04B4, PID_Boot = 0x00F3;

                    const int VID_FIFO = 0x04B4, PID_FIFO = 0x00F1;

             

             

                    internal const int MAX_BLOCK_SIZE_FOR_BOOTLOADER = 256;

                    internal const int FX3_EXTRA_READ_WORDS = 2;

             

             

                    private const string RBF_FILE_NAME_FOR_PROFINETFX3HUB = "ProfinetFX3Hub.rbf";

                    private const string RBF_FILE_NAME_FOR_FX3HUB = "FX3Hub.rbf";

                    private const string FX3_DOWNLOAD_IMAGE_FILE = "USB3_FPGA.img";

             

             

                    internal FX3_USB(out bool isColdBoot,ServotestFile fpgaExplicitFile)

                    {

                        isColdBoot = true;

                        if (usbDevices != null) usbDevices.Dispose();

                        usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

             

             

                        myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;             // Represents a hub that already has a configured FPGA

                        myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;          // Represents a hub that without a configured FPGA

                        int iTryCount =0;

                        while ((myFX3Device == null) && (myDevice == null))

                        {

                           if (iTryCount++ > 50) {

                                          throw new Exception ("Timeout looking for FX3 USB device #2");

                                    }

                            Thread.Sleep(10);

                            TraceHelper.WriteLine(TraceCategory.Info, "Looking for the FX3 as either Device  #1 ...");

                            usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

                            Thread.Sleep(100);

                            myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;

                            myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;

                        }

             

             

                        if ((myFX3Device == null) && (myDevice != null))   { // this is a warm boot as the FX3 is already running the FPGA/FIFO code

                            int len = 0;

                            byte[] buf = new byte[16];

                            CtrlEndPt = myDevice.ControlEndPt;

                            CtrlEndPt.Target = CyConst.TGT_DEVICE;

                            CtrlEndPt.ReqType = CyConst.REQ_VENDOR;

                            CtrlEndPt.Direction = CyConst.DIR_FROM_DEVICE;

                            CtrlEndPt.ReqCode = 0xB4; // reset FX3 from bootloader state

                            CtrlEndPt.Value = 0;

                            CtrlEndPt.Index = 1;

                            len = 16;

                            buf[0] = 0;

             

             

                            CtrlEndPt.XferData(ref buf, ref len);

             

             

                            TraceHelper.WriteLine(TraceCategory.Info, "Warm Boot. Rebooting FX3 to bootloader");

                  

                            System.Threading.Thread.Sleep(1000);

             

             

                            isColdBoot = false;

             

             

                            TraceHelper.WriteLine(TraceCategory.Info, "Renumerating FX3.");

             

             

                            if (usbDevices != null) usbDevices.Dispose();

                            usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

             

             

                            myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;

                            myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;

                            iTryCount = 0;

                            while ((myFX3Device == null) && (myDevice == null)) {

                                 if (iTryCount++ > 50) {

                                          throw new Exception ("Timeout looking for FX3 USB device #2");

                                    }

                                 Thread.Sleep(500);

                                 TraceHelper.WriteLine(TraceCategory.Info,"Looking for the FX3 as either Device #2 ...");

                                 usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

                                 Thread.Sleep(100);

                                 myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;

                                 myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;       

                            }

                        }

             

             

                        if ((myFX3Device != null) && (myDevice == null))

                        {   // If myFX3Device != null, then hub FPGA is not configured and FX3 is a Bootloader

                            // This is a cold boot, FX3 bootloader code is running and FPGA is unconfigured.

                            HUB_Serial = myFX3Device.SerialNumber;

                            TraceHelper.WriteLine(TraceCategory.Info, "Serial Number: " + myFX3Device.SerialNumber);

                            CyFX3Device fx = myFX3Device as CyFX3Device;

                            FX3_FWDWNLOAD_ERROR_CODE enmResult = FX3_FWDWNLOAD_ERROR_CODE.FAILED;//SUCCESS;

             

             

                            string download_image_file = FX3_DOWNLOAD_IMAGE_FILE;

                            string filename = Path.Combine(ApplicationData.ApplicationFileLibrary.FullName, download_image_file);

             

             

                            int retry = 0;

                         

                            while ((enmResult != FX3_FWDWNLOAD_ERROR_CODE.SUCCESS) && (retry < 5))

                            {

                                enmResult = fx.DownloadFw(filename, FX3_FWDWNLOAD_MEDIA_TYPE.RAM);

                                TraceHelper.WriteLine(TraceCategory.Info, "Programming of FX3 " + fx.GetFwErrorString(enmResult));

                                retry++;

                                if (retry > 0)

                                {                

                                    System.Threading.Thread.Sleep(100);

                                }

                            }

             

             

                            System.Threading.Thread.Sleep(1000);

                            //Getting rbf for FPGA and setting FX3 to serial out

                            long flen;

                            // there is only one type of Hub FPGA at the moment for USB3, combined function for 16port, demo and master slave

                            // in the future may have a way to select different types, possibly on Serial Number

                            //HubType = WorkOutUSBBaseBoardCombination(out var is300MHz, out var hasScramnet, out var hasProfinet, out var isdownloadable);

             

             

                            //if (HasProfinet) string rbf_name = RBF_FILE_NAME_FOR_PROFINETFX3HUB;

                            //else

                            string rbf_name = RBF_FILE_NAME_FOR_FX3HUB;

                            if (SerialNumber.Contains("P")) {

                                 rbf_name = RBF_FILE_NAME_FOR_PROFINETFX3HUB;

                            }

             

             

                            string fname = Path.Combine(ApplicationData.ApplicationFileLibrary.FullName, rbf_name);

                            if (fpgaExplicitFile != null) {  fname = fpgaExplicitFile.FullName;}  

                            FileStream file = new FileStream(fname, FileMode.Open, FileAccess.Read);

                            flen = file.Length;

             

             

                            file_bytes = (int)flen;

                            file_buffer = new byte[file_bytes];

             

             

                            file.Read(file_buffer, 0, file_bytes);

                            file.Close();

             

             

                            //Getting rbf for FPGA and setting FX3 to serial out

                            int len = 0;

                            byte[] buf = new byte[16];

                           

                            for (int iRetry = 0; iRetry < 4; iRetry++) {

                                usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

                                if (usbDevices.Count > 0) break;    //  success

                                System.Threading.Thread.Sleep(5000);

                                TraceHelper.WriteLine(TraceCategory.Info, "retrying to get devices");             

                              }

                    

                            if (usbDevices.Count == 0) { throw  new  Exception ("FX3 USB Device Not found"); }

             

             

                            myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;

             

             

                            BulkOutEndPt = myDevice.EndPointOf(0x01) as CyBulkEndPoint;

             

             

                            buf[0] = (Byte)(file_bytes & 0x000000FF);

                            buf[1] = (Byte)((file_bytes & 0x0000FF00) >> 8);

                            buf[2] = (Byte)((file_bytes & 0x00FF0000) >> 16);

                            buf[3] = (Byte)((file_bytes & 0xFF000000) >> 24);

             

             

                            if (myDevice != null)

                            {

                                TraceHelper.WriteLine(TraceCategory.Info, "Writing configuration data to FPGA...");

                                CtrlEndPt = myDevice.ControlEndPt;

                                CtrlEndPt.Target = CyConst.TGT_DEVICE;

                                CtrlEndPt.ReqType = CyConst.REQ_VENDOR;

                                CtrlEndPt.Direction = CyConst.DIR_TO_DEVICE;

                                CtrlEndPt.ReqCode = 0xB2; // move to FPGA config mode

                                CtrlEndPt.Value = 0;

                                CtrlEndPt.Index = 1;

                                len = 16;

                                CtrlEndPt.XferData(ref buf, ref len);//Send vendor command to start configuration of the FPGA

             

             

                                myDevice.BulkOutEndPt.XferSize = 4096;//Set the endpoint sizes to 4096 for Slave FIFO

             

             

                                success = myDevice.BulkOutEndPt.XferData(ref file_buffer, ref file_bytes); //Check if the FPGA has been successfully configured

                                if (success == true)

                                {

                                    TraceHelper.WriteLine(TraceCategory.Info, "Success");

                                }

                                else

                                {

                                    TraceHelper.WriteLine(TraceCategory.Info, "Failure");

                                }

                                if (success == true)

                                {

                                    TraceHelper.WriteLine(TraceCategory.Info, "FPGA configuration data has been sent to FPGA :"+ fname);

                                    System.Threading.Thread.Sleep(1000);

                                    CtrlEndPt.Target = CyConst.TGT_DEVICE;

                                    CtrlEndPt.ReqType = CyConst.REQ_VENDOR;

                                    CtrlEndPt.Direction = CyConst.DIR_FROM_DEVICE;

                                    CtrlEndPt.ReqCode = 0xB1; // move from FPGA config mode to FIFO operating mode

                                    CtrlEndPt.Value = 0;

                                    CtrlEndPt.Index = 1;

                                    len = 16;

                                    buf[0] = 0;

             

             

                                    CtrlEndPt.XferData(ref buf, ref len);   //Send vendor command to change the FX3 to Slave FIFO

             

             

                                    if (buf[0] == 1)

                                    {

                                        TraceHelper.WriteLine(TraceCategory.Info, "FX3 Slave FIFO interface is activated");

                                    }

                                    else

                                    {

                                        TraceHelper.WriteLine(TraceCategory.Info, "Configuration Failed");

                                    }

                                   

                                }

                            }

                            System.Threading.Thread.Sleep(1000);

                            BulkOutEndPt = myDevice.EndPointOf(0x01) as CyBulkEndPoint;      // Instantiating the endpoints

                            BulkInEndPt = myDevice.EndPointOf(0x81) as CyBulkEndPoint;

             

             

                            BulkOutEndPt.TimeOut = 500;  // 5 seconds

                            BulkInEndPt.TimeOut = 500;

             

             

                            numberOfBytesReadIn = 16383;

                            //numberOfBytesReadIn = 64;

                            bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesReadIn);

                            BulkInEndPt.XferData(ref inData, ref numberOfBytesReadIn);       // This DUMMY Read is needed to clear the endpoints after initialisation

             

             

                            numberOfBytesReadIn = 16383;

                            bResult = BulkInEndPt.XferData(ref inData, ref numberOfBytesReadIn);

                        }

                        else

                        {  

                            // not detected FX3 running FIFO/FPGA

                            TraceHelper.WriteLine(TraceCategory.Info, "FX3 Problem. Not in correct state.");

                        }

             

             

                        bool bIsFast = myDevice.bSuperSpeed;

                        if (bIsFast) {

                            TraceHelper.WriteLine(TraceCategory.Info, "Super Speed USB");

                        }

                        else {

                            TraceHelper.WriteLine(TraceCategory.Info, "Not Super Speed USB");

                        }

             

             

                      //  TraceHelper.WriteLine(TraceCategory.Info, "Press enter to send write block to FPGA");

                        usbDevices.DeviceRemoved += new EventHandler(usbDeviceRemoved);

                   

             

             

                    }

             

             

                    public FPGAWord[] ReadData(FPGAWord numberOfFPGAWords) {

                        numberOfBytesReadIn_ReadData = (int) (numberOfFPGAWords + FX3_EXTRA_READ_WORDS + 1) * 4;

             

             

                        try {

                            BulkInEndPt.TimeOut = 500;

                            bResult = BulkInEndPt.XferData(ref inData, ref numberOfBytesReadIn_ReadData);

                        }

                        catch (Exception ex) {

                            TraceHelper.WriteException(ex,"FX3 ReadData");

                            throw (ex);

                        }

             

             

                        Buffer.BlockCopy(inData, FX3_EXTRA_READ_WORDS * 4, inData_uint, 0, inData.Length - FX3_EXTRA_READ_WORDS * 4);

                        return inData_uint;

                    }

             

             

                    public bool CommandRead(FPGAWord[] outData_uint) {

                        Buffer.BlockCopy(outData_uint, 0, outData, 0, outData_uint.Length * 4);

                        numberOfBytesToWrite_CommandRead = 40;

             

             

                        try{

                            BulkOutEndPt.TimeOut = 500;

                            bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesToWrite_CommandRead);

                        }

                        catch(Exception ex) {

                           TraceHelper.WriteException(ex,"FX3 CommandRead");

                            throw (ex);

                        }

                        return bResult;

                    }

             

             

                    public  void CommandWriteAndData(FPGAWord[] Command, FPGAWord[] outData_uint) {

                        int numberOfBytesReadIn_clear = 16383; //RT     // does not actually read these words GD  

                        int CommandLength = Command.Length;

                        Array.Resize(ref Command, CommandLength + outData_uint.Length);

                        Array.Copy(outData_uint, 0,Command, CommandLength, outData_uint.Length);

                       

                        byte[] outData_write = new byte[(Command.Length * 4)];

                        Buffer.BlockCopy(Command, 0, outData_write, 0, (Command.Length * 4));

                        int numberOfBytesToWrite = outData_write.Length+32;

             

             

                        try {   

                            BulkOutEndPt.TimeOut = 500;

                            bResult = BulkOutEndPt.XferData(ref outData_write, ref numberOfBytesToWrite); 

                        }

                        catch(Exception ex) {

                            TraceHelper.WriteException(ex,"FX3 CommandWriteAndData");

                            throw (ex);

                        }

             

             

                        BulkInEndPt.TimeOut = 500;

                        bResult = BulkInEndPt.XferData(ref inData_clear, ref numberOfBytesReadIn_clear); //RT //GD dummy read to clear the endpoint, returns 0 length array

                    }

             

             

                    public void WriteCommand(FPGAWord[] outData_uint) {

                        int numberOfBytesReadIn_clear = 16383;  // does not actually read these words GD

             

             

                        Buffer.BlockCopy(outData_uint, 0, outData, 0, outData_uint.Length * 4);

                        Array.Resize(ref outData, outData_uint.Length * 4);

                        numberOfBytesToWrite_CommandRead = outData.Length + 32;

             

             

                        try {

                            BulkOutEndPt.TimeOut = 500;

                            bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesToWrite_CommandRead);

                        } catch(Exception ex) {

                             TraceHelper.WriteException(ex,"FX3 WriteCommand");

                            throw (ex);

                        }

             

             

                        BulkInEndPt.TimeOut = 500;

                        bResult = BulkInEndPt.XferData(ref inData_clear, ref numberOfBytesReadIn_clear); //RT //GD dummy read to clear the endpoint, returns 0 length array

                    }

             

             

                    public string SerialNumber{

                        get{

                            return HUB_Serial;

                        }

                    }

             

             

                    public FPGAWord_16 FPGAWordRead(FPGAWord[] outData_uint) {

             

             

                        CommandRead(outData_uint);

             

             

                        uint numberOfWordsToRead = 7;

                        FPGAWord_3[] allData = ReadData(numberOfWordsToRead);

                        FPGAWord_3[] result = new FPGAWord_3[numberOfWordsToRead];

                        Array.Copy(allData, 0, result, 0, numberOfWordsToRead);

             

             

                        FPGAWord_16 out_word;

                        out_word = (FPGAWord_16) (allData[3] & 0x0000FFFF);

                        return out_word;

                 

                    }

                    private void usbDeviceRemoved(object sender, EventArgs ea) {

                         USBEventArgs  args = (USBEventArgs) ea;

                         TraceHelper.WriteLine (TraceCategory.Error , " -----------------------------------" );

                         TraceHelper.WriteLine (TraceCategory.Error , " FX3 DEVICE REMOVED :" + args.FriendlyName );

                         TraceHelper.WriteLine (TraceCategory.Error , " -----------------------------------" );

                        // TODO   -  improve handling to abort transactions in progress

                        //   Need to find a way to terminate FX3 trasnaction in progres

                     

                        if (usbDevices != null) {

                            usbDevices.Dispose(); 

                         }

                            

                        //   Even system exception doesn't work well

                        

                        throw new Exception ("   FX3 device removed");

                     }

             

             

                    internal static bool ModulePresent {

                        get {

                            bool device = false;

                            int i = 0;

                            while((i < 3) && (device == false)) {

                                CyUSBDevice myFX3Device = null;                                                 // Create a USB device for our application called myFX3Device

                                CyUSBDevice myDevice = null;                                                    // myDevice represents the bulkloop device in this example

                                USBDeviceList usbDevices = null; 

                                Thread.Sleep(100);

                                usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);

                                myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;

                                myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;

             

             

                                if ((myFX3Device != null)||(myDevice != null)){

                                    device = true;

                                }

                                else {

                                    device = false;

                                }

                                i++;

                            }

                            if (!device) {

                                TraceHelper.WriteLine(TraceCategory.Info, "(" + i.ToString() + ") FX3 device not found"); // debug only

                            }

             

             

                            return device;

                        }

                    }

                }

            }

            • 3. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
              YatheeshK_36

              Hello,

               

              Thank you for the code.

              Can you try reproducing the same using the control center application?

              The control center also uses the a similar method.

               

              Thanks,

              Yatheesh

              • 4. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
                GlWa_4058551

                Many thanks   -   I have Cypress control center    but I am not very familiar with it.         Our DSP  only send blocks of data on request from the PC    -   is there a way within control centre to setup a continuous loop of  Write (BulkOut end point)  followed by Read (BulkIn end point) ?   - e.g. scripts

                 

                    Best regards

                 

                    Glen Wardrop

                • 5. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
                  YatheeshK_36

                  Hello Glen,

                   

                  You will have to do it manually from the control center.

                   

                  Also, can you try increasing the timeout in your application from 500 to 5000?

                   

                   

                  Thanks,

                  Yatheesh

                   

                  • 6. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
                    GlWa_4058551

                    Thanks for the rapid response    -   yes we have tested increasing  the timeout settings.   The timeout never expires.        The DeviceRemoved event fires when the device is removed,  but the  XferData call never exits .

                     

                    My colleagues are continuing to work with Control center to try to reproduce as you suggest.

                     

                     

                       Best regards

                     

                    Glen

                    • 7. Re: FX3 .Net  XferData call never exits when USB cable is disconnected.
                      GlWa_4058551

                      As a workaround to the problem I have now put the usb communications in a separate thread.   This prevents a hung XferData call  blocking the entire application.   It also allows for independent timeouts from the controlling thread.

                      While testing it became clear that timeouts work as expected during normal operation, if for example more data is requested than is available.

                      The problem only occurs when the cable is disconnected