it-swarm-ko.tech

.NET에서 USB 장치 작업

.Net (C #)을 사용하여 USB 장치를 어떻게 사용할 수 있습니까?

USB 이벤트 감지 (연결/연결 끊기) 및 장치와의 통신 (읽기/쓰기) 방법.

이 작업을 수행하는 기본 .Net 솔루션이 있습니까?

43
David Thibault

이에 대한 네이티브 솔루션 (예 : 시스템 라이브러리)이 없습니다. 이것이 moobaa 에서 언급 한 것처럼 SharpUSBLib 가 존재하는 이유입니다.

USB 장치에 대한 자체 처리기를 롤링하려면 SerialPort class of System.IO.Ports 를 확인하십시오.

21
Jon Limjap

SharpUSBLib을 사용해 보았는데 컴퓨터를 망쳤습니다 (시스템 복원 필요). 같은 프로젝트의 동료에게도 일어났습니다.

LibUSBDotNet에서 대안을 찾았습니다. http://sourceforge.net/projects/libusbdotnet 아직 많이 사용하지 않았지만 최근에 업데이트 된 것 같습니다 (Sharp와 달리).

편집 : 2017 년 2 월 중순부터 LibUSBDotNet은 약 2 주 전에 업데이트되었습니다. 한편 SharpUSBLib는 2004 년 이후로 업데이트되지 않았습니다.

26
Sofox

다음 코드를 사용하여 USB 장치가 컴퓨터에서 연결 및 분리 된시기를 감지했습니다.

class USBControl : IDisposable
    {
        // used for monitoring plugging and unplugging of USB devices.
        private ManagementEventWatcher watcherAttach;
        private ManagementEventWatcher watcherRemove;

        public USBControl()
        {
            // Add USB plugged event watching
            watcherAttach = new ManagementEventWatcher();
            //var queryAttach = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
            watcherAttach.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
            watcherAttach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
            watcherAttach.Start();

            // Add USB unplugged event watching
            watcherRemove = new ManagementEventWatcher();
            //var queryRemove = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
            watcherRemove.EventArrived += new EventArrivedEventHandler(watcher_EventRemoved);
            watcherRemove.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
            watcherRemove.Start();
        }

        /// <summary>
        /// Used to dispose of the USB device watchers when the USBControl class is disposed of.
        /// </summary>
        public void Dispose()
        {
            watcherAttach.Stop();
            watcherRemove.Stop();
            //Thread.Sleep(1000);
            watcherAttach.Dispose();
            watcherRemove.Dispose();
            //Thread.Sleep(1000);
        }

        void watcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
            Debug.WriteLine("watcher_EventArrived");
        }

        void watcher_EventRemoved(object sender, EventArrivedEventArgs e)
        {
            Debug.WriteLine("watcher_EventRemoved");
        }

        ~USBControl()
        {
            this.Dispose();
        }


    }

응용 프로그램을 닫을 때 Dispose () 메서드를 호출해야합니다. 그렇지 않으면 런타임시 닫을 때 COM 개체 오류가 발생합니다.

12
Syn
11
moobaa

2 년 동안 사용한 라이브러리 인 LibUSBDotNet 을 권장합니다. USB 장치로 작업해야하는 경우 (요청 보내기, 응답 처리)이 라이브러리는 내가 찾은 최고의 솔루션이었습니다.

장점 :

  • 동기화 또는 비동기 모드에서 작동하는 데 필요한 모든 방법이 있습니다.
  • 소스 코드 제공
  • 바로 사용하기에 충분한 샘플.

단점 :

  • 문서가 잘못되었습니다 (오픈 소스 프로젝트의 일반적인 문제). 기본적으로 CHM 도움말 파일에서 메소드에 대한 일반적인 설명을 찾을 수 있습니다. 그러나 나는 여전히 제공된 샘플을 발견하고 소스 코드는 코딩하기에 충분합니다. 때로는 이상한 행동을보고 왜 이런 식으로 구현되었고 힌트조차 얻지 못하는지 알고 싶습니다 ...
  • 더 이상 지원되지 않는 것 같습니다. 마지막 버전은 2010 년 10 월에 발행되었습니다. 때로는 답변을 받기가 어렵습니다.
4
Alex Klaus

USB 장치는 일반적으로 Hid 및 USB의 두 가지 범주로 분류됩니다. USB 장치는 숨김 장치 일 수도 있고 아닐 수도 있습니다. Hid는 일반적으로 직접 USB보다 작업하기가 조금 더 쉽습니다. 플랫폼마다 USB 및 Hid를 처리하기위한 API가 다릅니다.

UWP에 대한 설명서는 다음과 같습니다.

USB : https://docs.Microsoft.com/en-us/windows-hardware/drivers/usbcon/how-to-connect-to-a-usb-device--uwp-app-

숨김 : https://docs.Microsoft.com/en-us/uwp/api/windows.devices.humaninterfacedevice

다음은 Android 설명서입니다. https://developer.xamarin.com/api/namespace/Android.Hardware.Usb/

다음은 원시 Windows API 레벨에서 USB/Hid를 처리하기위한 두 가지 클래스입니다.

https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Hid.Net/Windows/HidAPICalls.cs

public static class HidAPICalls 
{
    #region Constants
    private const int DigcfDeviceinterface = 16;
    private const int DigcfPresent = 2;
    private const uint FileShareRead = 1;
    private const uint FileShareWrite = 2;
    private const uint GenericRead = 2147483648;
    private const uint GenericWrite = 1073741824;
    private const uint OpenExisting = 3;
    private const int HIDP_STATUS_SUCCESS = 0x110000;
    private const int HIDP_STATUS_INVALID_PREPARSED_DATA = -0x3FEF0000;
    #endregion

    #region API Calls

    [DllImport("hid.dll", SetLastError = true)]
    private static extern bool HidD_GetPreparsedData(SafeFileHandle hidDeviceObject, out IntPtr pointerToPreparsedData);

    [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    private static extern bool HidD_GetManufacturerString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);

    [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    private static extern bool HidD_GetProductString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);

    [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    private static extern bool HidD_GetSerialNumberString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);

    [DllImport("hid.dll", SetLastError = true)]
    private static extern int HidP_GetCaps(IntPtr pointerToPreparsedData, out HidCollectionCapabilities hidCollectionCapabilities);

    [DllImport("hid.dll", SetLastError = true)]
    private static extern bool HidD_GetAttributes(SafeFileHandle hidDeviceObject, out HidAttributes attributes);

    [DllImport("hid.dll", SetLastError = true)]
    private static extern bool HidD_FreePreparsedData(ref IntPtr pointerToPreparsedData);

    [DllImport("hid.dll", SetLastError = true)]
    private static extern void HidD_GetHidGuid(ref Guid hidGuid);

    private delegate bool GetString(SafeFileHandle hidDeviceObject, IntPtr pointerToBuffer, uint bufferLength);

    #endregion

    #region Helper Methods

    #region Public Methods
    public static HidAttributes GetHidAttributes(SafeFileHandle safeFileHandle)
    {
        var isSuccess = HidD_GetAttributes(safeFileHandle, out var hidAttributes);
        WindowsDeviceBase.HandleError(isSuccess, "Could not get Hid Attributes");
        return hidAttributes;
    }

    public static HidCollectionCapabilities GetHidCapabilities(SafeFileHandle readSafeFileHandle)
    {
        var isSuccess = HidD_GetPreparsedData(readSafeFileHandle, out var pointerToPreParsedData);
        WindowsDeviceBase.HandleError(isSuccess, "Could not get pre parsed data");

        var result = HidP_GetCaps(pointerToPreParsedData, out var hidCollectionCapabilities);
        if (result != HIDP_STATUS_SUCCESS)
        {
            throw new Exception($"Could not get Hid capabilities. Return code: {result}");
        }

        isSuccess = HidD_FreePreparsedData(ref pointerToPreParsedData);
        WindowsDeviceBase.HandleError(isSuccess, "Could not release handle for getting Hid capabilities");

        return hidCollectionCapabilities;
    }

    public static string GetManufacturer(SafeFileHandle safeFileHandle)
    {
        return GetHidString(safeFileHandle, HidD_GetManufacturerString);
    }

    public static string GetProduct(SafeFileHandle safeFileHandle)
    {
        return GetHidString(safeFileHandle, HidD_GetProductString);
    }

    public static string GetSerialNumber(SafeFileHandle safeFileHandle)
    {
        return GetHidString(safeFileHandle, HidD_GetSerialNumberString);
    }
    #endregion

    #region Private Static Methods
    private static string GetHidString(SafeFileHandle safeFileHandle, GetString getString)
    {
        var pointerToBuffer = Marshal.AllocHGlobal(126);
        var isSuccess = getString(safeFileHandle, pointerToBuffer, 126);
        Marshal.FreeHGlobal(pointerToBuffer);
        WindowsDeviceBase.HandleError(isSuccess, "Could not get Hid string");
        return Marshal.PtrToStringUni(pointerToBuffer);     
    }
    #endregion

    #endregion

}

https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net/Windows/WinUsbApiCalls.cs

public static partial class WinUsbApiCalls
{
    #region Constants
    public const int EnglishLanguageID = 1033;
    public const uint DEVICE_SPEED = 1;
    public const byte USB_ENDPOINT_DIRECTION_MASK = 0X80;
    public const int WritePipeId = 0x80;

    /// <summary>
    /// Not sure where this constant is defined...
    /// </summary>
    public const int DEFAULT_DESCRIPTOR_TYPE = 0x01;
    public const int USB_STRING_DESCRIPTOR_TYPE = 0x03;
    #endregion

    #region API Calls
    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, byte[] Buffer, uint BufferLength, ref uint LengthTransferred, IntPtr Overlapped);

    [DllImport("winusb.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool WinUsb_GetAssociatedInterface(SafeFileHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeFileHandle AssociatedInterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, out USB_DEVICE_DESCRIPTOR deviceDesc, uint BufferLength, out uint LengthTransfered);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, UInt16 LanguageID, byte[] Buffer, UInt32 BufferLength, out UInt32 LengthTransfered);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_Free(SafeFileHandle InterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeFileHandle InterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_QueryDeviceInformation(IntPtr InterfaceHandle, uint InformationType, ref uint BufferLength, ref byte Buffer);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_QueryInterfaceSettings(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, out USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_QueryPipe(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, byte PipeIndex, out WINUSB_PIPE_INFORMATION PipeInformation);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_ReadPipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_SetPipePolicy(IntPtr InterfaceHandle, byte PipeID, uint PolicyType, uint ValueLength, ref uint Value);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_WritePipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
    #endregion

    #region Public Methods
    public static string GetDescriptor(SafeFileHandle defaultInterfaceHandle, byte index, string errorMessage)
    {
        var buffer = new byte[256];
        var isSuccess = WinUsb_GetDescriptor(defaultInterfaceHandle, USB_STRING_DESCRIPTOR_TYPE, index, EnglishLanguageID, buffer, (uint)buffer.Length, out var transfered);
        WindowsDeviceBase.HandleError(isSuccess, errorMessage);
        var descriptor = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));
        return descriptor.Substring(0, descriptor.Length - 1);
    }
    #endregion
}

이러한 솔루션을 사용하면 일정한 간격으로 장치를 폴링하거나 API의 기본 장치 청취 클래스 중 하나를 사용해야합니다. 그러나이 라이브러리는 모든 플랫폼에서 Hid 및 USB에 계층을 배치하여 연결 및 연결 끊기를 쉽게 감지 할 수 있습니다. https://github.com/MelbourneDeveloper/Device.Net/wiki/Device-Listener =. 이것이 당신이 그것을 사용하는 방법입니다 :

internal class TrezorExample : IDisposable
{
    #region Fields
    //Define the types of devices to search for. This particular device can be connected to via USB, or Hid
    private readonly List<FilterDeviceDefinition> _DeviceDefinitions = new List<FilterDeviceDefinition>
    {
        new FilterDeviceDefinition{ DeviceType= DeviceType.Hid, VendorId= 0x534C, ProductId=0x0001, Label="Trezor One Firmware 1.6.x", UsagePage=65280 },
        new FilterDeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x534C, ProductId=0x0001, Label="Trezor One Firmware 1.6.x (Android Only)" },
        new FilterDeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C1, Label="Trezor One Firmware 1.7.x" },
        new FilterDeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C0, Label="Model T" }
    };
    #endregion

    #region Events
    public event EventHandler TrezorInitialized;
    public event EventHandler TrezorDisconnected;
    #endregion

    #region Public Properties
    public IDevice TrezorDevice { get; private set; }
    public DeviceListener DeviceListener { get; private set; }
    #endregion

    #region Event Handlers
    private void DevicePoller_DeviceInitialized(object sender, DeviceEventArgs e)
    {
        TrezorDevice = e.Device;
        TrezorInitialized?.Invoke(this, new EventArgs());
    }

    private void DevicePoller_DeviceDisconnected(object sender, DeviceEventArgs e)
    {
        TrezorDevice = null;
        TrezorDisconnected?.Invoke(this, new EventArgs());
    }
    #endregion

    #region Public Methods
    public void StartListening()
    {
        TrezorDevice?.Dispose();
        DeviceListener = new DeviceListener(_DeviceDefinitions, 3000);
        DeviceListener.DeviceDisconnected += DevicePoller_DeviceDisconnected;
        DeviceListener.DeviceInitialized += DevicePoller_DeviceInitialized;
    }

    public async Task InitializeTrezorAsync()
    {
        //Get the first available device and connect to it
        var devices = await DeviceManager.Current.GetDevices(_DeviceDefinitions);
        TrezorDevice = devices.FirstOrDefault();
        await TrezorDevice.InitializeAsync();
    }

    public async Task<byte[]> WriteAndReadFromDeviceAsync()
    {
        //Create a buffer with 3 bytes (initialize)
        var writeBuffer = new byte[64];
        writeBuffer[0] = 0x3f;
        writeBuffer[1] = 0x23;
        writeBuffer[2] = 0x23;

        //Write the data to the device
        return await TrezorDevice.WriteAndReadAsync(writeBuffer);
    }

    public void Dispose()
    {
        TrezorDevice?.Dispose();
    }
    #endregion
}
2

SharpUSBLib 라이브러리 및 HID 드라이버를 C #과 함께 사용하는 방법에 대한 자습서가 있습니다.

http://www.developerfusion.com/article/84338/making-usb-c-friendly/

2
James Crowley

PC에 National Instruments 소프트웨어가있는 경우 "NI-VISA Driver Wizard" =.

USB 드라이버를 만드는 단계 : http://www.ni.com/tutorial/4478/en/

드라이버를 생성하면 모든 USB 장치에 바이트를 쓰고 읽을 수 있습니다.

장치 관리자에서 Windows에 드라이버가 표시되는지 확인하십시오.

enter image description here

C # 코드 :

    using NationalInstruments.VisaNS;

    #region UsbRaw
    /// <summary>
    /// Class to communicate with USB Devices using the UsbRaw Class of National Instruments
    /// </summary>
    public class UsbRaw
    {
        private NationalInstruments.VisaNS.UsbRaw usbRaw;
        private List<byte> DataReceived = new List<byte>();

        /// <summary>
        /// Initialize the USB Device to interact with
        /// </summary>
        /// <param name="ResourseName">In this format: "USB0::0x1448::0x8CA0::NI-VISA-30004::RAW".  Use the NI-VISA Driver Wizard from Start»All Programs»National Instruments»VISA»Driver Wizard to create the USB Driver for the device you need to talk to.</param>
        public UsbRaw(string ResourseName)
        {
            usbRaw = new NationalInstruments.VisaNS.UsbRaw(ResourseName, AccessModes.NoLock, 10000, false);
            usbRaw.UsbInterrupt += new UsbRawInterruptEventHandler(OnUSBInterrupt);
            usbRaw.EnableEvent(UsbRawEventType.UsbInterrupt, EventMechanism.Handler);
        }

        /// <summary>
        /// Clears a USB Device from any previous commands
        /// </summary>
        public void Clear()
        {
            usbRaw.Clear();
        }

        /// <summary>
        /// Writes Bytes to the USB Device
        /// </summary>
        /// <param name="EndPoint">USB Bulk Out Pipe attribute to send the data to.  For example: If you see on the Bus Hound sniffer tool that data is coming out from something like 28.4 (Device column), this means that the USB is using Endpoint 4 (Number after the dot)</param>
        /// <param name="BytesToSend">Data to send to the USB device</param>
        public void Write(short EndPoint, byte[] BytesToSend)
        {
            usbRaw.BulkOutPipe = EndPoint;
            usbRaw.Write(BytesToSend);       // Write to USB
        }

        /// <summary>
        /// Reads bytes from a USB Device
        /// </summary>
        /// <returns>Bytes Read</returns>
        public byte[] Read()
        {
            usbRaw.ReadByteArray();     // This fires the UsbRawInterruptEventHandler                

            byte[] rxBytes = DataReceived.ToArray();      // Collects the data received

            return rxBytes;
        }

        /// <summary>
        /// This is used to get the data received by the USB device
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnUSBInterrupt(object sender, UsbRawInterruptEventArgs e)
        {
            try
            {
                DataReceived.Clear();     // Clear previous data received
                DataReceived.AddRange(e.DataBuffer);                    
            }
            catch (Exception exp)
            {
                string errorMsg = "Error: " + exp.Message;
                DataReceived.AddRange(ASCIIEncoding.ASCII.GetBytes(errorMsg));
            }
        }

        /// <summary>
        /// Use this function to clean up the UsbRaw class
        /// </summary>
        public void Dispose()
        {
            usbRaw.DisableEvent(UsbRawEventType.UsbInterrupt, EventMechanism.Handler);

            if (usbRaw != null)
            {
                usbRaw.Dispose();
            }              
        }

    }
    #endregion UsbRaw

용법:

UsbRaw usbRaw = new UsbRaw("USB0::0x1448::0x8CA0::NI-VISA-30004::RAW");

byte[] sendData = new byte[] { 0x53, 0x4c, 0x56 };
usbRaw.Write(4, sendData);      // Write bytes to the USB Device
byte[] readData = usbRaw.Read();   // Read bytes from the USB Device

usbRaw.Dispose();

이것이 누군가를 돕기를 바랍니다.

1
Pabinator

# .NET도 지원하는 사용자 모드에서 USB 드라이버를 작성하기위한 일반적인 툴킷 WinDriver 가 있습니다

1
Ilya

나는 운 좋게 이러한 제안 중 몇 가지를 시도했습니다. Java 및 hid4Java 라이브러리를 사용하여 작업 솔루션을 작성했습니다. 콘솔 응용 프로그램으로 Process.Start()을 사용하여 C #에서 셸을 사용할 수 있습니다. 응답, 읽기 및 매개 변수 전달 기본 HID I/O를 제공하지만 연결/연결 끊기 이벤트는 제공하지 않으므로 데몬/서비스로 실행하고 명명 된 파이프 또는 다른 서버/클라이언트 전송을 사용하려면이 속성을 다시 작성해야합니다. 현재로서는 hi4Java 라이브러리가 "정상 작동"한 이후로 작업을 완료하는 것으로 충분합니다.

0
Mike Lowery

이 기사 를 사용하여 Teensy 에 대한 인터페이스를 얻었습니다.

0
Brad Bruce

대부분의 USB 칩셋에는 드라이버가 제공됩니다. Silicon Labs 하나 있습니다.

0
Nick