Mercurial > hg > ucis.core
diff USBLib/Communication/LibUsbDotNet.cs @ 21:dcfec2be27c9
Added USBLib
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 01:04:59 +0200 |
parents | |
children | 5b14fed54a89 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsbDotNet.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,528 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; +using System.Text; +using System.IO; +using LibUsbDotNet.Main; +using LibUsbDotNet.Info; +using LibUsbDotNet.Descriptors; +using UCIS.USBLib.Communication; +using LibUsb0Registry = UCIS.USBLib.Communication.LibUsb.LibUsb0Registry; +using LibUsb1Registry = UCIS.USBLib.Communication.LibUsb1.LibUsb1Registry; +using nIUsbDevice = UCIS.USBLib.Communication.IUsbDevice; +using nIUsbInterface = UCIS.USBLib.Communication.IUsbInterface; +using WinUsbRegistry = UCIS.USBLib.Communication.WinUsb.WinUsbRegistry; + +namespace LibUsbDotNet { + public class UsbDevice : IUsbDevice { + public nIUsbInterface Device { get; private set; } + public UsbDevice(nIUsbInterface dev) { + Device = dev; + } + public bool GetDescriptor(byte descriptorType, byte index, short langId, Byte[] buffer, int bufferLength, out int transferLength) { + try { + transferLength = Device.GetDescriptor(descriptorType, index, langId, buffer, 0, bufferLength); + return true; + } catch { + transferLength = 0; + return false; + } + } + public bool ControlTransfer(ref UsbSetupPacket setupPacket, Byte[] buffer, int bufferLength, out int lengthTransferred) { + if ((setupPacket.RequestType & 128) != 0) { + lengthTransferred = Device.ControlRead((UsbControlRequestType)setupPacket.RequestType, setupPacket.Request, setupPacket.Value, setupPacket.Index, buffer, 0, bufferLength); + } else { + lengthTransferred = Device.ControlWrite((UsbControlRequestType)setupPacket.RequestType, setupPacket.Request, setupPacket.Value, setupPacket.Index, buffer, 0, bufferLength); + } + return true; + } + public DriverModeType DriverMode { get { return DriverModeType.Unknown; } } + public enum DriverModeType { + Unknown, + LibUsb, + WinUsb, + MonoLibUsb, + LibUsbWinBack + } + public UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID, EndpointType endpointType) { + return new UsbEndpointWriter(Device, (Byte)writeEndpointID, endpointType); + } + public UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int buffersize, EndpointType endpointType) { + UsbEndpointReader reader = new UsbEndpointReader(Device, (Byte)readEndpointID, endpointType); + reader.ReadBufferSize = buffersize; + return reader; + } + public void Close() { + Device.Dispose(); + } + public UsbDeviceInfo Info { get { return new UsbDeviceInfo(this); } } + public static IList<UsbRegistry> AllDevices { + get { + List<UsbRegistry> list = new List<UsbRegistry>(); + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + foreach (IUsbDeviceRegistry reg in WinUsbRegistry.DeviceList) list.Add(new UsbRegistry(reg)); + foreach (IUsbDeviceRegistry reg in LibUsb0Registry.DeviceList) list.Add(new UsbRegistry(reg)); + } else { + foreach (IUsbDeviceRegistry reg in LibUsb1Registry.DeviceList) list.Add(new UsbRegistry(reg)); + } + return list; + } + } + private SafeHandle Handle { get { return null; } } + public bool SetConfiguration(byte config) { + nIUsbDevice dev = Device as nIUsbDevice; + if (dev == null) return false; + try { + dev.Configuration = config; + return true; + } catch { + return false; + } + } + public bool ClaimInterface(int interfaceID) { + nIUsbDevice dev = Device as nIUsbDevice; + if (dev == null) return false; + try { + dev.ClaimInterface(interfaceID); + return true; + } catch { + return false; + } + } + public bool ReleaseInterface(int interfaceID) { + nIUsbDevice dev = Device as nIUsbDevice; + if (dev == null) return false; + try { + dev.ReleaseInterface(interfaceID); + return true; + } catch { + return false; + } + } + public IList<UsbConfigInfo> Configs { + get { + List<UsbConfigInfo> rtnConfigs = new List<UsbConfigInfo>(); + byte[] cfgBuffer = new byte[UsbConstants.MAX_CONFIG_SIZE]; + int iConfigs = Info.Descriptor.ConfigurationCount; + for (int iConfig = 0; iConfig < iConfigs; iConfig++) { + int iBytesTransmitted; + if (!GetDescriptor((byte)UsbDescriptorType.Configuration, 0, 0, cfgBuffer, cfgBuffer.Length, out iBytesTransmitted)) + throw new Exception("Could not read configuration descriptor"); + if (iBytesTransmitted < UsbConfigDescriptor.Size || cfgBuffer[1] != (byte)UsbDescriptorType.Configuration) + throw new Exception("GetDeviceConfigs: USB config descriptor is invalid."); + UsbConfigDescriptor configDescriptor = new UsbConfigDescriptor(); + Helper.BytesToObject(cfgBuffer, 0, Math.Min(UsbConfigDescriptor.Size, cfgBuffer[0]), configDescriptor); + if (configDescriptor.TotalLength != iBytesTransmitted) throw new Exception("GetDeviceConfigs: USB config descriptor length doesn't match the length received."); + List<byte[]> rawDescriptorList = new List<byte[]>(); + int iRawLengthPosition = configDescriptor.Length; + while (iRawLengthPosition < configDescriptor.TotalLength) { + byte[] rawDescriptor = new byte[cfgBuffer[iRawLengthPosition]]; + if (iRawLengthPosition + rawDescriptor.Length > iBytesTransmitted) throw new Exception("Descriptor length is out of range."); + Array.Copy(cfgBuffer, iRawLengthPosition, rawDescriptor, 0, rawDescriptor.Length); + rawDescriptorList.Add(rawDescriptor); + iRawLengthPosition += rawDescriptor.Length; + } + rtnConfigs.Add(new UsbConfigInfo(this, configDescriptor, ref rawDescriptorList)); + } + return rtnConfigs; + } + } + } + public interface IUsbDevice { + bool SetConfiguration(byte config); + bool ClaimInterface(int interfaceID); + bool ReleaseInterface(int interfaceID); + } + public class UsbEndpointWriter : IDisposable { + public nIUsbInterface Device { get; private set; } + public Byte EndpointID { get; private set; } + public EndpointType EndpointType { get; private set; } + public Byte EpNum { get { return EndpointID; } } + public UsbEndpointWriter(nIUsbInterface dev, byte epid, EndpointType eptype) { + Device = dev; + EndpointID = epid; + EndpointType = eptype; + } + public ErrorCode Write(byte[] buffer, int offset, int count, int timeout, out int transferLength) { + switch (EndpointType) { + case EndpointType.Bulk: transferLength = Device.BulkWrite(EndpointID, buffer, offset, count); break; + case EndpointType.Interrupt: transferLength = Device.InterruptWrite(EndpointID, buffer, offset, count); break; + default: transferLength = 0; return ErrorCode.Error; + } + return ErrorCode.Ok; + } + public void Dispose() { } + } + public class UsbEndpointReader : IDisposable { + public nIUsbInterface Device { get; private set; } + public Byte EndpointID { get; private set; } + public EndpointType EndpointType { get; private set; } + public Byte EpNum { get { return EndpointID; } } + public int ReadBufferSize { get; set; } + + public UsbEndpointReader(nIUsbInterface dev, byte epid, EndpointType eptype) { + Device = dev; + EndpointID = epid; + EndpointType = eptype; + ReadBufferSize = 4096; + } + public ErrorCode Read(byte[] buffer, int offset, int count, int timeout, out int transferLength) { + switch (EndpointType) { + case EndpointType.Bulk: transferLength = Device.BulkRead(EndpointID, buffer, offset, count); break; + case EndpointType.Interrupt: transferLength = Device.InterruptRead(EndpointID, buffer, offset, count); break; + default: transferLength = 0; return ErrorCode.Error; + } + return ErrorCode.Ok; + } + public void Dispose() { DataReceivedEnabled = false; } + + private bool mDataReceivedEnabled; + private Thread mReadThread; + + public virtual bool DataReceivedEnabled { + get { return mDataReceivedEnabled; } + set { + if (value != mDataReceivedEnabled) { + if (mDataReceivedEnabled) { + mReadThread.Abort(); + } else { + mDataReceivedEnabled = true; + mReadThread = new Thread(ReadDataProcess); + mReadThread.Start(); + } + } + } + } + + private void ReadDataProcess(object state) { + byte[] buffer = new byte[ReadBufferSize]; + try { + while (mDataReceivedEnabled) { + int transferLength; + Read(buffer, 0, buffer.Length, -1, out transferLength); + EventHandler<EndpointDataEventArgs> eh = DataReceived; + if (!ReferenceEquals(eh, null)) eh(this, new EndpointDataEventArgs(buffer, transferLength)); + } + } catch (Exception ex) { + if (ReadError != null) ReadError(this, new ErrorEventArgs(ex)); + } finally { + mDataReceivedEnabled = false; + } + } + + public event EventHandler<EndpointDataEventArgs> DataReceived; + public event ErrorEventHandler ReadError; + } +} +namespace LibUsbDotNet.Main { + public static class UsbConstants { + public const int MAX_CONFIG_SIZE = 4096; + public const int MAX_DEVICES = 128; + public const int MAX_ENDPOINTS = 32; + public const byte ENDPOINT_DIR_MASK = 0x80; + public const byte ENDPOINT_NUMBER_MASK = 0xf; + } + public static class Helper { + public static void BytesToObject(byte[] sourceBytes, int iStartIndex, int iLength, object destObject) { + GCHandle gch = GCHandle.Alloc(destObject, GCHandleType.Pinned); + IntPtr ptrDestObject = gch.AddrOfPinnedObject(); + Marshal.Copy(sourceBytes, iStartIndex, ptrDestObject, iLength); + gch.Free(); + } + public static string ToString(string sep0, string[] names, string sep1, object[] values, string sep2) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < names.Length; i++) sb.Append(sep0 + names[i] + sep1 + values[i] + sep2); + return sb.ToString(); + } + } + public class EndpointDataEventArgs : EventArgs { + internal EndpointDataEventArgs(byte[] bytes, int size) { + Buffer = bytes; + Count = size; + } + public byte[] Buffer { get; private set; } + public int Count { get; private set; } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbSetupPacket { + public byte RequestType; + public byte Request; + public short Value; + public short Index; + public short Length; + public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) { + RequestType = requestType; + Request = request; + Value = value; + Index = index; + Length = length; + } + } + public enum UsbEndpointDirection : byte { + EndpointIn = 0x80, + EndpointOut = 0x00, + } + public enum UsbRequestType : byte { + TypeClass = (0x01 << 5), + TypeReserved = (0x03 << 5), + TypeStandard = (0x00 << 5), + TypeVendor = (0x02 << 5), + } + public enum WriteEndpointID : byte { + Ep01 = 0x01, + Ep02 = 0x02, + Ep03 = 0x03, + Ep04 = 0x04, + Ep05 = 0x05, + Ep06 = 0x06, + Ep07 = 0x07, + Ep08 = 0x08, + Ep09 = 0x09, + Ep10 = 0x0A, + Ep11 = 0x0B, + Ep12 = 0x0C, + Ep13 = 0x0D, + Ep14 = 0x0E, + Ep15 = 0x0F, + } + public enum ReadEndpointID : byte { + Ep01 = 0x81, + Ep02 = 0x82, + Ep03 = 0x83, + Ep04 = 0x84, + Ep05 = 0x85, + Ep06 = 0x86, + Ep07 = 0x87, + Ep08 = 0x88, + Ep09 = 0x89, + Ep10 = 0x8A, + Ep11 = 0x8B, + Ep12 = 0x8C, + Ep13 = 0x8D, + Ep14 = 0x8E, + Ep15 = 0x8F, + } + public enum UsbRequestRecipient : byte { + RecipDevice = 0x00, + RecipInterface = 0x01, + RecipEndpoint = 0x02, + RecipOther = 0x03, + } + public enum EndpointType : byte { + Control, + Isochronous, + Bulk, + Interrupt + } + public enum ErrorCode { + Ok = 0, + Error = 1, + } + public class UsbRegistry { + public IUsbDeviceRegistry Registry { get; private set; } + public UsbRegistry(IUsbDeviceRegistry reg) { + Registry = reg; + } + public int Vid { get { return Registry.Vid; } } + public int Pid { get { return Registry.Pid; } } + public int Rev { get { return 0; } } + public Boolean IsAlive { get { return true; } } + public Boolean Open(out UsbDevice hand) { + hand = new UsbDevice(Registry.Open()); + return true; + } + public IDictionary<String, Object> DeviceProperties { get { return Registry.DeviceProperties; } } + public String FullName { get { return Registry.FullName; } } + public String Name { get { return Registry.Name; } } + public String SymbolicName { get { return Registry.SymbolicName; } } + } +} +namespace LibUsbDotNet.Info { + public class UsbDeviceInfo { + private readonly UsbDeviceDescriptor mDeviceDescriptor; + internal UsbDevice mUsbDevice; + internal UsbDeviceInfo(UsbDevice usbDevice) { + mUsbDevice = usbDevice; + mDeviceDescriptor = new UsbDeviceDescriptor(); + Byte[] bytes = new Byte[UsbDeviceDescriptor.Size]; + int ret; + usbDevice.GetDescriptor((byte)UsbDescriptorType.Device, 0, 0, bytes, UsbDeviceDescriptor.Size, out ret); + Object asobj = mDeviceDescriptor; + Helper.BytesToObject(bytes, 0, ret, asobj); + mDeviceDescriptor = (UsbDeviceDescriptor)asobj; + } + public UsbDeviceDescriptor Descriptor { get { return mDeviceDescriptor; } } + public String ManufacturerString { + get { + if (Descriptor.ManufacturerStringIndex == 0) return null; + return mUsbDevice.Device.GetString(0, Descriptor.ManufacturerStringIndex); + } + } + public String ProductString { + get { + if (Descriptor.ProductStringIndex == 0) return null; + return mUsbDevice.Device.GetString(0, Descriptor.ProductStringIndex); + } + } + public String SerialString { + get { + if (Descriptor.SerialStringIndex == 0) return null; + return mUsbDevice.Device.GetString(0, Descriptor.SerialStringIndex); + } + } + } + public class UsbConfigInfo { + private readonly List<UsbInterfaceInfo> mInterfaceList = new List<UsbInterfaceInfo>(); + internal readonly UsbConfigDescriptor mUsbConfigDescriptor; + internal UsbDevice mUsbDevice; + internal UsbConfigInfo(UsbDevice usbDevice, UsbConfigDescriptor descriptor, ref List<byte[]> rawDescriptors) { + mUsbDevice = usbDevice; + mUsbConfigDescriptor = descriptor; + UsbInterfaceInfo currentInterface = null; + for (int iRawDescriptor = 0; iRawDescriptor < rawDescriptors.Count; iRawDescriptor++) { + byte[] bytesRawDescriptor = rawDescriptors[iRawDescriptor]; + switch (bytesRawDescriptor[1]) { + case (byte)UsbDescriptorType.Interface: + currentInterface = new UsbInterfaceInfo(usbDevice, bytesRawDescriptor); + mInterfaceList.Add(currentInterface); + break; + case (byte)UsbDescriptorType.Endpoint: + if (currentInterface == null) throw new Exception("Recieved and endpoint descriptor before receiving an interface descriptor."); + currentInterface.mEndpointInfo.Add(new UsbEndpointInfo(bytesRawDescriptor)); + break; + } + } + } + public UsbConfigDescriptor Descriptor { get { return mUsbConfigDescriptor; } } + public ReadOnlyCollection<UsbInterfaceInfo> InterfaceInfoList { get { return mInterfaceList.AsReadOnly(); } } + } + public class UsbInterfaceInfo { + internal readonly UsbInterfaceDescriptor mUsbInterfaceDescriptor; + internal UsbDevice mUsbDevice; + internal List<UsbEndpointInfo> mEndpointInfo = new List<UsbEndpointInfo>(); + internal UsbInterfaceInfo(UsbDevice usbDevice, byte[] descriptor) { + mUsbDevice = usbDevice; + mUsbInterfaceDescriptor = new UsbInterfaceDescriptor(); + Helper.BytesToObject(descriptor, 0, Math.Min(UsbInterfaceDescriptor.Size, descriptor[0]), mUsbInterfaceDescriptor); + } + public UsbInterfaceDescriptor Descriptor { get { return mUsbInterfaceDescriptor; } } + public ReadOnlyCollection<UsbEndpointInfo> EndpointInfoList { get { return mEndpointInfo.AsReadOnly(); } } + } + public class UsbEndpointInfo { + internal UsbEndpointDescriptor mUsbEndpointDescriptor; + internal UsbEndpointInfo(byte[] descriptor) { + mUsbEndpointDescriptor = new UsbEndpointDescriptor(); + Helper.BytesToObject(descriptor, 0, Math.Min(UsbEndpointDescriptor.Size, descriptor[0]), mUsbEndpointDescriptor); + } + public UsbEndpointDescriptor Descriptor { + get { return mUsbEndpointDescriptor; } + } + } +} +namespace LibUsbDotNet.Descriptors { + public enum DescriptorType : byte { + Device = 1, + Configuration = 2, + String = 3, + Interface = 4, + Endpoint = 5, + DeviceQualifier = 6, + OtherSpeedConfiguration = 7, + InterfacePower = 8, + OTG = 9, + Debug = 10, + InterfaceAssociation = 11, + Hid = 0x21, + HidReport = 0x22, + Physical = 0x23, + Hub = 0x29 + } + public enum ClassCodeType : byte { + PerInterface = 0, + Audio = 1, + Comm = 2, + Hid = 3, + Printer = 7, + Ptp = 6, + MassStorage = 8, + Hub = 9, + Data = 10, + VendorSpec = 0xff + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public abstract class UsbDescriptor { + public static readonly int Size = Marshal.SizeOf(typeof(UsbDescriptor)); + public byte Length; + public DescriptorType DescriptorType; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbDeviceDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbDeviceDescriptor)); + public short BcdUsb; + public ClassCodeType Class; + public byte SubClass; + public byte Protocol; + public byte MaxPacketSize0; + public short VendorID; + public short ProductID; + public short BcdDevice; + public byte ManufacturerStringIndex; + public byte ProductStringIndex; + public byte SerialStringIndex; + public byte ConfigurationCount; + internal UsbDeviceDescriptor() { } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbConfigDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbConfigDescriptor)); + public readonly short TotalLength; + public readonly byte InterfaceCount; + public readonly byte ConfigID; + public readonly byte StringIndex; + public readonly byte Attributes; + public readonly byte MaxPower; + internal UsbConfigDescriptor() { } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbInterfaceDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbInterfaceDescriptor)); + public readonly byte InterfaceID; + public readonly byte AlternateID; + public readonly byte EndpointCount; + public readonly ClassCodeType Class; + public readonly byte SubClass; + public readonly byte Protocol; + public readonly byte StringIndex; + internal UsbInterfaceDescriptor() { } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbEndpointDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbEndpointDescriptor)); + public readonly byte EndpointID; + public readonly byte Attributes; + public readonly short MaxPacketSize; + public readonly byte Interval; + public readonly byte Refresh; + public readonly byte SynchAddress; + internal UsbEndpointDescriptor() { } + } +} +namespace MonoLibUsb { + public static class MonoUsbApi { + internal const CallingConvention CC = 0; + internal const string LIBUSB_DLL = "libusb-1.0.dll"; + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_detach_kernel_driver")] + public static extern int DetachKernelDriver([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + public static int ControlTransfer(MonoUsbDeviceHandle deviceHandle, byte requestType, byte request, short value, short index, object data, short dataLength, int timeout) { + throw new NotImplementedException(); + } + public static int BulkTransfer(MonoUsbDeviceHandle deviceHandle, byte endpoint, object data, int length, out int actualLength, int timeout) { + throw new NotImplementedException(); + } + } + public abstract class MonoUsbDeviceHandle : SafeHandle { + public MonoUsbDeviceHandle(Boolean bOwnsHandle) : base(IntPtr.Zero, bOwnsHandle) { } + } +}