hid usb通信_如何使用HID协议与其USB设备通信

hid usb通信

(You need Visual Studio.)

(您需要Visual Studio。)

警告 (Warning)

This USB sniffer, because of its user mode method access to hardware, cannot read HID packets with RID at 0, it's due to Windows protection level to prevent keyloggers/spying software.

此USB嗅探器由于其用户模式方法可访问硬件,因此无法读取RID为0的HID数据包,这是由于Windows的保护级别所致,以防止键盘记录器/间谍软件。

Example of use:

使用示例:

DEVICE_VID  = 1A2C;
DEVICE_PID  = 0001;
USAGE_PAGE  = FF00;
USAGE       = 0000;
REPORT_ID   = FF;

Do not add 0x, else the application will crash (I haven't added 0x prefix support)

不要添加0x,否则应用程序将崩溃(我还没有添加0x前缀支持)

hid usb通信_如何使用HID协议与其USB设备通信_第1张图片

hid usb通信_如何使用HID协议与其USB设备通信_第2张图片

Unfortunately, the write function can only send 1 byte (+ Report ID byte), it's because I was too lazy to add a fully functional text parse function ^^.

不幸的是, write函数只能发送1个字节(+报告ID字节),这是因为我懒得添加一个功能齐全的文本解析函数^^。

But it's working, the most important thing, you can verify it via any USB sniffer (use your own values for that).

但这是有效的,最重要的是,您可以通过任何USB嗅探器对其进行验证(为此使用您自己的值)。

介绍 (Introduction)

This article shows you how to using the USB/HID protocol under Windows to be able to send/receive USB packets from any USB devices connected to the PC.

本文向您展示如何在Windows下使用USB / HID协议,以便能够从连接到PC的任何USB设备发送/接收USB数据包。

And without using DLL, just an application is needed.

而且,无需使用DLL,仅需要一个应用程序即可。

背景 (Background)

This article was possible with this WDK sample:

使用此WDK示例可以实现本文:

Basically, it's just a rewrite of this sample, but in a simple form.

基本上,这只是对该示例的重写,但是形式很简单。

使用代码 (Using the Code)

Declaration of variables, WinAPI functions and using: https://pastebin.com/MSRAYJ5b

变量声明,WinAPI函数和使用: https : //pastebin.com/MSRAYJ5b

All that you need is those functions:

您所需要做的就是这些功能:

HidD_GetHidGuid
SetupDiGetClassDevs
SetupDiEnumDeviceInterfaces
SetupDiGetDeviceInterfaceDetail
SetupDiGetDeviceInterfaceDetail
CreateFile
HidD_GetPreparsedData
HidD_GetAttributes
HidP_GetCaps
WriteFile

Assembled, it will look like this, the core of your program:

组装后,程序的核心将如下所示:

This function also detects if the device you target is disconnected to avoid unnecessary call of WinAPI functions.

此功能还检测目标设备是否断开连接,以避免不必要的WinAPI函数调用。

void HID()
{
    HID_DEVICE[] pDevice = new HID_DEVICE[1];

    while (true)
    {
        if (nbrDevices != FindNumberDevices())
        {
            nbrDevices = FindNumberDevices();
            pDevice    = new HID_DEVICE[nbrDevices];
            FindKnownHidDevices(ref pDevice);

            var i = 0;
            while (i < nbrDevices)
            {
                var count = 0;

                if (pDevice[i].Attributes.VendorID  == DEVICE_VID)
                    count++;
                if (pDevice[i].Attributes.ProductID == DEVICE_PID)
                    count++;
                if (pDevice[i].Caps.UsagePage       == USAGE_PAGE)
                    count++;
                if (pDevice[i].Caps.Usage           == USAGE)
                    count++;

                if (count == 4)
                {
                    iHIDD = i;
                    isConnected = true;

                    break;
                }
                else
                    isConnected = false;

                i++;
            }
        }

        if (isConnected)
        {
            //Read(pDevice[iHIDD]);
            //Write(pDevice[iHIDD]);
        }
    }
}


As the function says, it returns the number of devices, not really their number, but the number of functions devices that are defined by the VID/PID, Usage Page, Usage and Report ID.

就像函数所说的那样,它返回设备的数目,而不是设备的数目,而是由VID / PID,使用页面,使用情况和报告ID定义的设备的数目。

int FindNumberDevices()
{
    Guid                     hidGuid        = new Guid();
    SP_DEVICE_INTERFACE_DATA deviceInfoData = new SP_DEVICE_INTERFACE_DATA();
    int index = 0;

    HidD_GetHidGuid(ref hidGuid);

    //
    // Open a handle to the plug and play dev node.
    //
    SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
    hardwareDeviceInfo    = SetupDiGetClassDevs
    (ref hidGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    deviceInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));

    index = 0;
    while (SetupDiEnumDeviceInterfaces
          (hardwareDeviceInfo, IntPtr.Zero, ref hidGuid, index, ref deviceInfoData))
    {
        index++;
    }

    return (index);
}


This function returns all the data structures for each USB device needed for ReadFile() and WriteFile().

此函数返回ReadFile()WriteFile()所需的每个USB设备的所有数据结构。

int FindKnownHidDevices(ref HID_DEVICE[] HidDevices)
{
    int                             iHIDD;
    int                             RequiredLength;

    Guid                            hidGuid            = new Guid();
    SP_DEVICE_INTERFACE_DATA        deviceInfoData     = new SP_DEVICE_INTERFACE_DATA();
    SP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData =
                                             new SP_DEVICE_INTERFACE_DETAIL_DATA();

    HidD_GetHidGuid(ref hidGuid);

    //
    // Open a handle to the plug and play dev node.
    //
    SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
    hardwareDeviceInfo    = SetupDiGetClassDevs
    (ref hidGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    deviceInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));

    iHIDD = 0;
    while (SetupDiEnumDeviceInterfaces
    (hardwareDeviceInfo, IntPtr.Zero, ref hidGuid, iHIDD, ref deviceInfoData))
    {
        RequiredLength = 0;

        //
        // allocate a function class device data structure to receive the
        // goods about this particular device.
        //
        SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo,
        ref deviceInfoData, IntPtr.Zero, 0, ref RequiredLength, IntPtr.Zero);

        if (IntPtr.Size == 8)
            functionClassDeviceData.cbSize = 8;
        else if (IntPtr.Size == 4)
            functionClassDeviceData.cbSize = 5;

        //
        // Retrieve the information from Plug and Play.
        //
        SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo, ref deviceInfoData,
        ref functionClassDeviceData, RequiredLength, ref RequiredLength, IntPtr.Zero);

        //
        // Open device with just generic query abilities to begin with
        //
        OpenHidDevice(functionClassDeviceData.DevicePath, ref HidDevices, iHIDD);

        iHIDD++;
    }

    return iHIDD;
}


This function depends on FindKnownHidDevices().

此函数取决于FindKnownHidDevices()

void OpenHidDevice(string DevicePath, ref HID_DEVICE[] HidDevice, int iHIDD)
{
    /*++
    RoutineDescription:
    Given the HardwareDeviceInfo, representing a handle to the plug and
    play information, and deviceInfoData, representing a specific hid device,
    open that device and fill in all the relevant information in the given
    HID_DEVICE structure.
    --*/

    HidDevice[iHIDD].DevicePath = DevicePath;

    //
    //  The hid.dll APIs do not pass the overlapped structure into deviceiocontrol
    //  so to use them we must have a non overlapped device.  If the request is for
    //  an overlapped device, we will close the device below and get a handle to an
    //  overlapped device
    //
    CloseHandle(HidDevice[iHIDD].HidDevice);
    HidDevice[iHIDD].HidDevice  = CreateFile(HidDevice[iHIDD].DevicePath,
    GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ |
    FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, IntPtr.Zero);
    HidDevice[iHIDD].Caps       = new HIDP_CAPS();
    HidDevice[iHIDD].Attributes = new HIDD_ATTRIBUTES();

    //
    //  If the device was not opened as overlapped, then fill in the rest of the
    //  HidDevice structure.  However, if opened as overlapped, this handle cannot
    //  be used in the calls to the HidD_ exported functions since each of these
    //  functions does synchronous I/O.
    //
    HidD_FreePreparsedData(ref HidDevice[iHIDD].Ppd);
    HidDevice[iHIDD].Ppd = IntPtr.Zero;
    HidD_GetPreparsedData(HidDevice[iHIDD].HidDevice, ref HidDevice[iHIDD].Ppd);
    HidD_GetAttributes(HidDevice[iHIDD].HidDevice, ref HidDevice[iHIDD].Attributes);
    HidP_GetCaps(HidDevice[iHIDD].Ppd, ref HidDevice[iHIDD].Caps);

    //MessageBox.Show(GetLastError().ToString());

    //
    // At this point, the client has a choice. It may choose to look at the
    // Usage and Page of the top level collection found in the HIDP_CAPS
    // structure. In this way --------*it could just use the usages it knows about.
    // If either HidP_GetUsages or HidP_GetUsageValue return an error, then
    // that particular usage does not exist in the report.
    // This is most likely the preferred method as the application can only
    // use usages of which it already knows.
    // In this case, the app need not even call GetButtonCaps or GetValueCaps.
    //
    // In this example, however, we will call FillDeviceInfo to look for all
    //    of the usages in the device.
    //
    //FillDeviceInfo(ref HidDevice);
}


Then come the two important functions that will make you able to read or write USB packets between a USB device and the PC.

然后是两个重要的功能,这些功能使您能够在USB设备和PC之间读取或写入USB数据包。

void Write(HID_DEVICE HidDevice) // Read the Report[] and
                                 // send it to the USB device targeted
                                 // by HidDevice.HidDevice
{
    byte[] Report = new byte[HidDevice.Caps.OutputReportByteLength];
    uint   tmp = 0;

    Report[0] = REPORT_ID;

    WriteFile(HidDevice.HidDevice, Report,
              HidDevice.Caps.OutputReportByteLength, ref tmp, IntPtr.Zero);
}

void Read(HID_DEVICE HidDevice) // Read what the USB device has sent
                                // to the PC and store the result into Report[]
{
    byte[] Report = new byte[HidDevice.Caps.InputReportByteLength];
    uint   tmp = 0;

    Report[0] = REPORT_ID;

    ReadFile(HidDevice.HidDevice, Report,
             HidDevice.Caps.InputReportByteLength, ref tmp, IntPtr.Zero);
}


To be able to do that, you need to set variables below before calling Write() or Read():

为此,您需要在调用Write()Read()之前在下面设置变量:

  • DEVICE_VID

    DEVICE_VID

  • DEVICE_PID

    DEVICE_PID

  • USAGE_PAGE

    USAGE_PAGE

  • USAGE

    USAGE

  • REPORT_ID

    REPORT_ID

But be careful, you need to set the correct values for all those parameters, if one is false, you will not be able to write HID packets.

但请注意,您需要为所有这些参数设置正确的值,如果其中一个为false ,则将无法写入HID数据包。

To read HID packets, you only need:

要读取HID数据包,您只需要:

  • DEVICE_VID

    DEVICE_VID

  • DEVICE_PID

    DEVICE_PID

Also, you cannot read if the device cannot send data and you cannot write if the device cannot read data.

此外,如果设备无法发送数据,则无法读取;如果设备无法读取数据,则无法写入。

A device is defined by its DEVICE_VID/DEVICE_PID but shrunk into several functions defined by its USAGE_PAGE, USAGE and REPORT_ID.

设备由其DEVICE_VID / DEVICE_PID定义,但缩减为由其USAGE_PAGEUSAGEREPORT_ID定义的多个功能。

As an example, the first function of a mouse is to send data, so you can read data from PC and the second function is to receive data, so you can send data from PC.

例如,鼠标的第一个功能是发送数据,因此您可以从PC读取数据,第二个功能是接收数据,因此您可以从PC发送数据。

But also a function can read and send data, but it depends on the HID descriptor.

而且一个函数可以读取和发送数据,但是它取决于HID描述符。

And to set those variables, you need to read the HID Descriptor of the USB devices that you target, it can be retrieved with a USB sniffer as https://github.com/djpnewton/busdog.

要设置这些变量,您需要读取目标USB设备的HID描述符,可以使用USB嗅探器将其检索为https://github.com/djpnewton/busdog 。

The HID Descriptor usually begins with 0x05, 0x01.

HID描述符通常以0x05、0x01开头。

And to learn to read HID Descriptor, use this tool: http://www.usb.org/developers/hidpage#HID Descriptor Tool

要学习阅读HID描述符,请使用以下工具: http : //www.usb.org/developers/hidpage#HID描述符工具

Because this code is just a rewrite of an old C code from the 90s, it works on all Windows Versions.

因为此代码只是对90年代旧C代码的重写,所以它适用于所有Windows版本。

翻译自: https://www.codeproject.com/Articles/1244702/How-to-Communicate-with-its-USB-Devices-using-HID

hid usb通信

你可能感兴趣的:(python,linux,java,c++,go)