/// <summary> /// Wait for the transfer to complete, timeout, or get cancelled. /// </summary> /// <param name="transferredCount">The number of bytes transferred on <see cref="ErrorCode.Success"/>.</param> /// <param name="cancel">Not used for libusb-1.0. Transfers are always cancelled on timeout or error.</param> /// <returns><see cref="ErrorCode.Success"/> if the transfer completes successfully, otherwise one of the other <see cref="ErrorCode"/> codes.</returns> public override ErrorCode Wait(out int transferredCount, bool cancel) { transferredCount = 0; int ret = 0; MonoUsbError monoError; ErrorCode ec; int iWait = WaitHandle.WaitAny(new WaitHandle[] { mTransferCompleteEvent, mTransferCancelEvent }, Timeout.Infinite, UsbConstants.EXIT_CONTEXT); switch (iWait) { case 0: // TransferCompleteEvent if (mTransfer.Status == MonoUsbTansferStatus.TransferCompleted) { transferredCount = mTransfer.ActualLength; return(ErrorCode.Success); } string s; monoError = MonoUsbApi.MonoLibUsbErrorFromTransferStatus(mTransfer.Status); ec = MonoUsbApi.ErrorCodeFromLibUsbError((int)monoError, out s); UsbError.Error(ErrorCode.MonoApiError, (int)monoError, "Wait:" + s, EndpointBase); return(ec); case 1: // TransferCancelEvent ret = (int)mTransfer.Cancel(); bool bTransferComplete = mTransferCompleteEvent.WaitOne(100, UsbConstants.EXIT_CONTEXT); mTransferCompleteEvent.Set(); if (ret != 0 || !bTransferComplete) { ec = ret == 0 ? ErrorCode.CancelIoFailed : ErrorCode.MonoApiError; UsbError.Error(ec, ret, String.Format("Wait:Unable to cancel transfer or the transfer did not return after it was cancelled. Cancelled:{0} TransferCompleted:{1}", (MonoUsbError)ret, bTransferComplete), EndpointBase); return(ec); } return(ErrorCode.IoCancelled); default: // Critical failure timeout mTransfer.Cancel(); ec = ((EndpointBase.mEpNum & (byte)UsbCtrlFlags.Direction_In) > 0) ? ErrorCode.ReadFailed : ErrorCode.WriteFailed; mTransferCompleteEvent.Set(); UsbError.Error(ec, ret, String.Format("Wait:Critical timeout failure! The transfer callback function was not called within the allotted time."), EndpointBase); return(ec); } }
private static int libusb_control_transfer(MonoUsbDeviceHandle deviceHandle, MonoUsbControlSetupHandle controlSetupHandle, int timeout) { MonoUsbTransfer transfer = MonoUsbTransfer.Alloc(0); ManualResetEvent completeEvent = new ManualResetEvent(false); GCHandle gcCompleteEvent = GCHandle.Alloc(completeEvent); transfer.FillControl(deviceHandle, controlSetupHandle, controlTransferDelegate, GCHandle.ToIntPtr(gcCompleteEvent), timeout); int r = (int)transfer.Submit(); if (r < 0) { transfer.Free(); gcCompleteEvent.Free(); return(r); } while (!completeEvent.WaitOne(0, false)) { r = MonoUsbApi.HandleEvents(sessionHandle); if (r < 0) { if (r == (int)MonoUsbError.ErrorInterrupted) { continue; } transfer.Cancel(); while (!completeEvent.WaitOne(0, false)) { if (MonoUsbApi.HandleEvents(sessionHandle) < 0) { break; } } transfer.Free(); gcCompleteEvent.Free(); return(r); } } if (transfer.Status == MonoUsbTansferStatus.TransferCompleted) { r = transfer.ActualLength; } else { r = (int)MonoUsbApi.MonoLibUsbErrorFromTransferStatus(transfer.Status); } transfer.Free(); gcCompleteEvent.Free(); return(r); }
/// <summary> /// Perform a USB control transfer for multi-threaded applications using the <see cref="MonoUsbEventHandler"/> class. /// </summary> /// <remarks> /// <para>The direction of the transfer is inferred from the bmRequestType field of the setup packet.</para> /// <para>The wValue, wIndex and wLength fields values should be given in host-endian byte order.</para> /// <note type="tip" title="Libusb-1.0 API:"><seelibusb10 group="syncio"/></note> /// </remarks> /// <param name="deviceHandle">A handle for the device to communicate with.</param> /// <param name="requestType">The request type field for the setup packet.</param> /// <param name="request">The request field for the setup packet.</param> /// <param name="value">The value field for the setup packet</param> /// <param name="index">The index field for the setup packet.</param> /// <param name="pData">A suitably-sized data buffer for either input or output (depending on direction bits within bmRequestType).</param> /// <param name="dataLength">The length field for the setup packet. The data buffer should be at least this size.</param> /// <param name="timeout">timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0.</param> /// <returns> /// <list type="bullet"> /// <item>on success, the number of bytes actually transferred</item> /// <item><see cref="MonoUsbError.ErrorTimeout"/> if the transfer timed out</item> /// <item><see cref="MonoUsbError.ErrorPipe"/> if the control request was not supported by the device.</item> /// <item><see cref="MonoUsbError.ErrorNoDevice"/> if the device has been disconnected</item> /// <item>another <see cref="MonoUsbError"/> code on other failures</item> /// </list> /// </returns> public static int ControlTransferAsync([In] MonoUsbDeviceHandle deviceHandle, byte requestType, byte request, short value, short index, IntPtr pData, short dataLength, int timeout) { MonoUsbControlSetupHandle setupHandle = new MonoUsbControlSetupHandle(requestType, request, value, index, pData, dataLength); MonoUsbTransfer transfer = new MonoUsbTransfer(0); ManualResetEvent completeEvent = new ManualResetEvent(false); GCHandle gcCompleteEvent = GCHandle.Alloc(completeEvent); transfer.FillControl(deviceHandle, setupHandle, DefaultAsyncDelegate, GCHandle.ToIntPtr(gcCompleteEvent), timeout); int r = (int)transfer.Submit(); if (r < 0) { transfer.Free(); gcCompleteEvent.Free(); return(r); } IntPtr pSessionHandle; MonoUsbSessionHandle sessionHandle = MonoUsbEventHandler.SessionHandle; if (sessionHandle == null) { pSessionHandle = IntPtr.Zero; } else { pSessionHandle = sessionHandle.DangerousGetHandle(); } if (MonoUsbEventHandler.IsStopped) { while (!completeEvent.WaitOne(0)) { r = HandleEvents(pSessionHandle); if (r < 0) { if (r == (int)MonoUsbError.ErrorInterrupted) { continue; } transfer.Cancel(); while (!completeEvent.WaitOne(0)) { if (HandleEvents(pSessionHandle) < 0) { break; } } transfer.Free(); gcCompleteEvent.Free(); return(r); } } } else { completeEvent.WaitOne(Timeout.Infinite); } if (transfer.Status == MonoUsbTansferStatus.TransferCompleted) { r = transfer.ActualLength; if (r > 0) { byte[] ctrlDataBytes = setupHandle.ControlSetup.GetData(r); Marshal.Copy(ctrlDataBytes, 0, pData, Math.Min(ctrlDataBytes.Length, dataLength)); } } else { r = (int)MonoLibUsbErrorFromTransferStatus(transfer.Status); } transfer.Free(); gcCompleteEvent.Free(); return(r); }
// This function originated from do_sync_bulk_transfer() // in sync.c of the Libusb-1.0 source code. private static MonoUsbError doBulkAsyncTransfer(MonoUsbDeviceHandle dev_handle, byte endpoint, byte[] buffer, int length, out int transferred, int timeout) { transferred = 0; MonoUsbTransfer transfer = new MonoUsbTransfer(0); if (transfer.IsInvalid) { return(MonoUsbError.ErrorNoMem); } MonoUsbTransferDelegate monoUsbTransferCallbackDelegate = bulkTransferCB; int[] userCompleted = new int[] { 0 }; GCHandle gcUserCompleted = GCHandle.Alloc(userCompleted, GCHandleType.Pinned); MonoUsbError e; GCHandle gcBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); transfer.FillBulk( dev_handle, endpoint, gcBuffer.AddrOfPinnedObject(), length, monoUsbTransferCallbackDelegate, gcUserCompleted.AddrOfPinnedObject(), timeout); e = transfer.Submit(); if ((int)e < 0) { transfer.Free(); gcUserCompleted.Free(); return(e); } int r; Console.WriteLine("Transfer Submitted.."); while (userCompleted[0] == 0) { e = (MonoUsbError)(r = Usb.HandleEvents(sessionHandle)); if (r < 0) { if (e == MonoUsbError.ErrorInterrupted) { continue; } transfer.Cancel(); while (userCompleted[0] == 0) { if (Usb.HandleEvents(sessionHandle) < 0) { break; } } transfer.Free(); gcUserCompleted.Free(); return(e); } } transferred = transfer.ActualLength; e = MonoUsbApi.MonoLibUsbErrorFromTransferStatus(transfer.Status); transfer.Free(); gcUserCompleted.Free(); return(e); }