Search code examples
c#windowsusblibusb

LibUsbDotNet UsbDevice.ControlTransfer hangs


I have a C# .Net Winforms application, which uses LibUsbDotNet to program firmware into an USB-device (Atmel AVR32) using "DFU_DNLOAD" transfers, which is a special kind of control-transfers. This all works, BUT: A specific kind of transfer, which causes the device to erase its internal flash, fails to send an ACK within the correct timing.

When this happens, my LibUsbDotNet connection becomes irreparably broken, which causes everything to fail.

My code does the following:

int TransferToDevice(byte request, short value, byte[] data)
{
  var setup = new UsbSetupPacket(
                (byte)(UsbCtrlFlags.Direction_Out | UsbCtrlFlags.RequestType_Class | UsbCtrlFlags.Recipient_Interface),
                request,
                value,
                0,
                (short)data.Length);

  int n;
  IntPtr unmanagedPointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(data.Length);
  System.Runtime.InteropServices.Marshal.Copy(data, 0, unmanagedPointer, data.Length);
  // UsbDevice obtained else-where
  if (!UsbDevice.ControlTransfer(ref setup, unmanagedPointer, data.Length, out n))
  {
    n = 0;
  }
  System.Runtime.InteropServices.Marshal.FreeHGlobal(unmanagedPointer);
  return n;
}

// In order to do a "DFU_DNLOAD", the method above is used as follows:
TransferToDevice(DFU_DNLOAD, Transactions++, data); // "data" is the payload
// where DFU_DNLOAD is:
private const byte DFU_DNLOAD    = 1;
// Transactions is 
short Transaction = 0;

The above code works (the device correctly receives the "DFU_DNLOAD" message), but the missing ACK is the problem. Once the error occurs, every attempt to communicate with the device (even if I try to re-initialize everything) fails, untill the device is disconnected and re-inserted...

I would like to be able to reset or re-initialize the USB-connection somehow, when this error occurs. Currently I am only able to re-establish communications with the device by exiting my application and re-starting it manually.


Solution

  • Just guessing, but in case if data is array of short, than size of the buffer should be adjusted

    int numberOfValues = data.Length;
    int size = Marshal.SizeOf(typeof(short)); 
    
    IntPtr unmanagedPointer = Marshal.AllocHGlobal(numberOfValues*size);
    
    if (unmanagedPointer == IntPtr.Zero)
        throw new OutOfMemoryException("Unable allocate memory");