/// <summary> /// Helper function to populate the required <see cref="MonoUsbTransfer"/> properties for a control transfer. /// </summary> /// <remarks> /// <note type="tip"> /// <para>Isochronous transfers are not supported on windows.</para> /// </note> /// <note title="Libusb-1.0 API Note:" type="cpp"> /// <see cref="FillControl"/> is similar to /// <a href="http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga3a8513ed87229fe2c9771ef0bf17206e">libusb_fill_control_transfer()</a>. /// </note> /// </remarks> /// <param name="devHandle">handle of the device that will handle the transfer</param> /// <param name="controlSetupHandle">the setup packet/control data to transfer.</param> /// <param name="callback">callback function to be invoked on transfer completion</param> /// <param name="userData">user data to pass to callback function</param> /// <param name="timeout">timeout for the transfer in milliseconds</param> public void FillControl(MonoUsbDeviceHandle devHandle, MonoUsbControlSetupHandle controlSetupHandle, Delegate callback, IntPtr userData, int timeout) { PtrDeviceHandle = devHandle.DangerousGetHandle(); Endpoint = 0; PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(callback); PtrUserData = userData; Timeout = timeout; Type = EndpointType.Control; Flags = MonoUsbTransferFlags.None; IntPtr pSetupPacket = controlSetupHandle.DangerousGetHandle(); PtrBuffer = pSetupPacket; MonoUsbControlSetup w = new MonoUsbControlSetup(pSetupPacket); Length = MonoUsbControlSetup.SETUP_PACKET_SIZE + w.Length; }
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, false)) { r = HandleEvents(pSessionHandle); if (r < 0) { if (r == (int)MonoUsbError.ErrorInterrupted) continue; transfer.Cancel(); while (!completeEvent.WaitOne(0, false)) if (HandleEvents(pSessionHandle) < 0) break; transfer.Free(); gcCompleteEvent.Free(); return r; } } } else { completeEvent.WaitOne(Timeout.Infinite, UsbConstants.EXIT_CONTEXT); } 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; }
private static void Main(string[] args) { // Assign the control transfer delegate to the callback function. controlTransferDelegate = ControlTransferCB; // Initialize the context. sessionHandle = new MonoUsbSessionHandle(); if (sessionHandle.IsInvalid) throw new Exception(String.Format("Failed intializing libusb context.\n{0}:{1}", MonoUsbSessionHandle.LastErrorCode, MonoUsbSessionHandle.LastErrorString)); MonoUsbProfileList profileList = new MonoUsbProfileList(); MonoUsbDeviceHandle myDeviceHandle = null; try { // The list is initially empty. // Each time refresh is called the list contents are updated. profileList.Refresh(sessionHandle); // Use the GetList() method to get a generic List of MonoUsbProfiles // Find the first profile that matches in MyVidPidPredicate. MonoUsbProfile myProfile = profileList.GetList().Find(MyVidPidPredicate); if (myProfile == null) { Console.WriteLine("Device not connected."); return; } // Open the device handle to perform I/O myDeviceHandle = myProfile.OpenDeviceHandle(); if (myDeviceHandle.IsInvalid) throw new Exception(String.Format("Failed opening device handle.\n{0}:{1}", MonoUsbDeviceHandle.LastErrorCode, MonoUsbDeviceHandle.LastErrorString)); int ret; MonoUsbError e; // Set Configuration e = (MonoUsbError) (ret = MonoUsbApi.SetConfiguration(myDeviceHandle, 1)); if (ret < 0) throw new Exception(String.Format("Failed SetConfiguration.\n{0}:{1}", e, MonoUsbApi.StrError(e))); // Claim Interface e = (MonoUsbError) (ret = MonoUsbApi.ClaimInterface(myDeviceHandle, 0)); if (ret < 0) throw new Exception(String.Format("Failed ClaimInterface.\n{0}:{1}", e, MonoUsbApi.StrError(e))); // Create a vendor specific control setup, allocate 1 byte for return control data. byte requestType = (byte)(UsbCtrlFlags.Direction_In | UsbCtrlFlags.Recipient_Device | UsbCtrlFlags.RequestType_Vendor); byte request = 0x0F; MonoUsbControlSetupHandle controlSetupHandle = new MonoUsbControlSetupHandle(requestType, request, 0, 0, 1); // Transfer the control setup packet ret = libusb_control_transfer(myDeviceHandle, controlSetupHandle, 1000); if (ret > 0) { Console.WriteLine("\nSuccess!\n"); byte[] ctrlDataBytes = controlSetupHandle.ControlSetup.GetData(ret); string ctrlDataString = Helper.HexString(ctrlDataBytes, String.Empty, "h "); Console.WriteLine("Return Length: {0}", ret); Console.WriteLine("DATA (hex) : [ {0} ]\n", ctrlDataString.Trim()); } MonoUsbApi.ReleaseInterface(myDeviceHandle, 0); } finally { profileList.Close(); if (myDeviceHandle != null) myDeviceHandle.Close(); sessionHandle.Close(); } }