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

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

cross mob
GlWa_4058551
Level 1
Level 1

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.

0 Likes
1 Solution

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

View solution in original post

0 Likes
7 Replies
YatheeshD_36
Moderator
Moderator
Moderator
750 replies posted 500 replies posted 250 solutions authored

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

0 Likes

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;

            }

        }

    }

}

0 Likes

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.

pastedImage_0.png

Thanks,

Yatheesh

0 Likes

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

0 Likes

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

0 Likes

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

0 Likes

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

0 Likes