Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LibUSBDotNet: Strange errors after working with USB device for awhile

I'm using the LibUSBDotNet library in a WPF application that communicates with a simple USB device. I'm only sending 3 bytes to the device as a command, there's no response to be expected from it and my code works like a charm:

MyUsbFinder = new UsbDeviceFinder(vid, pid);
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
    wholeUsbDevice.SetConfiguration(1);
    wholeUsbDevice.ClaimInterface(0);
}

writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);

And then the process of writing to the device:

byte[] update = { 0x21, some_code_generated_byte, some_code_generated_byte };
int bytesWritten;

if (MyUsbDevice != null)
{
     ec = writer.Write(update, 2000, out bytesWritten);
}

I'm relatively new to working with USB but I got thus far and it all works. However, after awhile, every now and then, upon attempting to write again to the device I would get one of the following two errors:

Win32Error:GetOverlappedResult Ep 0x01
31:The parameter is incorrect.

Win32Error:PipeTransferSubmit Ep 0x01
87:The parameter is incorrect.

Often I need to restart the device/application several times before it starts working again and then it goes another several hours working like a charm before it happens again... I have not been able to replicate the crash so far in a testing environment either.

I did a lot of research trying to find a problem/solution similar to mine with no success. The only suggestion that I have left is that at some point the device does not have enough power and it goes into this error mode but even that seems unlikely as it has a separate 12V power supply and all that it does is to switch on and off several relays...

I've also tried flooding the device with a lot of consecutive commands one after another, including garbage ones but it still works and behaves properly only to crash a little bit later.

Open to any suggestions or ideas, thank you!

EDIT: After many attempts I'm still not able to identify the root cause of the issue but I managed to get to a point where my code is working and is able to recover from the OverlappedResult error using reconnect functions that try to reset the device once it starts failing. I'm posting some code below and hopefully someone will be able to narrow down the issue and identify the cause of the error.

Some code during initialization:

        UsbDeviceFinder MyUsbFinder;
        UsbDevice MyUsbDevice;
        IUsbDevice wholeUsbDevice;

                MyUsbFinder = new UsbDeviceFinder(vid, pid);
                MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);

                    wholeUsbDevice = MyUsbDevice as IUsbDevice;
                    if (!ReferenceEquals(wholeUsbDevice, null))
                    {
                        // This is a "whole" USB device. Before it can be used, 
                        // the desired configuration and interface must be selected.
                        // I think those do make some difference...

                        // Select config #1
                        wholeUsbDevice.SetConfiguration(1);

                        // Claim interface #0.
                        wholeUsbDevice.ClaimInterface(0);
                    }

                    writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);

Next I'm trying to send some information to the device. This is where the error will eventually pop up and I'm catching it as an exception in a simple try/catch block:

ErrorCode ec = ErrorCode.None;
if (MyUsbDevice != null)
{
    ec = writer.Write(update, 2000, out bytesWritten);
    if (ec != ErrorCode.None)
    {
        //now try to reconnect to the device, dispose writer first
        writer.Dispose(); // I think this also helps to reestablish the connection and get rid of the error
        if (this.reconnect())
        {
            //reconnected, try to write to the device again
            ec = writer.Write(update, 2000, out bytesWritten);
            if (ec != ErrorCode.None)
            {
                //log the error
            }
        }
    }
}
else //there's no connection to the device, try to reconnect and update again
{
    //now try to reconnect to the device, dispose writer first
    //writer.Dispose();
    if (this.reconnect())
        updateRelayController(); 
}

Up there "update" is a byte array that I'm sending to my device with the appropriate commands and updateRelayController is actually the function that has the code snippet above writing commands to the USB device. Finally, here's my reconnect() function that manages to reestablish connection to the device 99% of the time without having to manually restart the device and plug/unplug usb cables, etc:

public bool reconnect()
{
    //clear the info so far
    if (MyUsbDevice != null)
    {
        writer.Dispose();
        wholeUsbDevice.ReleaseInterface(0);
        wholeUsbDevice.Close();
        MyUsbDevice.Close();
        UsbDevice.Exit();
    }

    //now start over
    MyUsbFinder = new UsbDeviceFinder(vid, pid);
    MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);

    // If the device is open and ready
    if (MyUsbDevice == null)
    {
        //log the error
        return false;
    }
    else
    {
        wholeUsbDevice = MyUsbDevice as IUsbDevice;
        if (!ReferenceEquals(wholeUsbDevice, null))
        {
            // Select config #1
            wholeUsbDevice.SetConfiguration(1);

            // Claim interface #0.
            wholeUsbDevice.ClaimInterface(0);
        }

        writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);

        return true;
    }
}

That's pretty much it so far. The combination of SetConfiguration/ClaimInterface/Dispose reduce the times I see the OverlappedResult error and whenever that happens, judging from my logs, I'm able to recover right away and resend the command to the device. As I said above, this is a workaround to the problem as I'm still getting the error every now and then and I still have no idea why, but at least I'm able to continue working with the device at this point. Would love to find out more on this issue if anyone has more insights. Thanks and I hope this helps!

like image 878
mmvsbg Avatar asked Nov 02 '22 08:11

mmvsbg


1 Answers

NOT an answer! (This is just a workaround to another problem. It fixes the given error while closing the app)

I'm writing this here because it won't be readable as a comment.(for code)

I just commented out the code on dispose as seen below.

    #region IDisposable Members

    /// <summary>
    /// Cancels any pending transfer and frees resources.
    /// </summary>
    public virtual void Dispose()
    {
        if (!IsCancelled) Cancel();

        //I just commented here.
        //int dummy; 
        //if (!mHasWaitBeenCalled) Wait(out dummy);

        if (mPinnedHandle != null) mPinnedHandle.Dispose();
        mPinnedHandle = null;
    }

    #endregion

    ~UsbTransfer() { Dispose(); }

and I couldn't get rid of getting this annoying error, I can send the first message but even I reconnect successfully to device there is no cure :(

EndPoint 0x0x1 is me end endpoint 0x81 is device but after getting this error ???? I don't understand why there isn't a managed lib for usb.

         05 FA 28 81 02 00 08 94 32 Win32Error:GetOverlappedResult Ep 0x81 
        31:
        Win32Error:PipeTransferSubmit Ep 0x01 
        22:
        Win32Error:DeviceIoControl code 00222058 failed: LibUsbDriverIO 
        22:
        Win32Error:PipeTransferSubmit Ep 0x01 
        22:
        Win32Error:DeviceIoControl code 00222058 failed: LibUsbDriverIO 
        22:
        Win32Error:PipeTransferSubmit Ep 0x01 
        22:
        Win32Error:DeviceIoControl code 00222058 failed: LibUsbDriverIO 
        22:
like image 59
Davut Gürbüz Avatar answered Nov 10 '22 01:11

Davut Gürbüz