使用HID协议与USB设备通信

目录

警告

背景

使用代码


警告

USB嗅探器由于其用户模式方法访问硬件,无法读取RID0HID数据包,这是由于Windows保护级别可防止键盘记录器/间谍软件。

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

背景

WDK示例可以写这篇文章:

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

使用代码

主要代码:

void    CheckHIDRead()
{
    HIDReadInfo.Device = new HID_DEVICE[DeviceDiscovery.FindDeviceNumber()];

    DeviceDiscovery.FindKnownHIDDevices(ref HIDReadInfo.Device);

    for (var Index = 0; Index < HIDReadInfo.Device.Length; Index++)
    {
        if (HIDReadInfo.VendorID != 0)
        {
            var Count = 0;

            if (HIDReadInfo.Device[Index].Attributes.VendorID == HIDReadInfo.VendorID)
            {
                Count++;
            }
            if (HIDReadInfo.Device[Index].Attributes.ProductID == HIDReadInfo.ProductID)
            {
                Count++;
            }

            if (Count == 2)
            {
                HIDReadInfo.iDevice = Index;
                HIDReadInfo.Active  = true;

                return;
            }
        }
    }
}
void    CheckHIDWrite()
{
    HIDWriteInfo.Device = new HID_DEVICE[DeviceDiscovery.FindDeviceNumber()];

    DeviceDiscovery.FindKnownHIDDevices(ref HIDWriteInfo.Device);

    for (var Index = 0; Index < HIDWriteInfo.Device.Length; Index++)
    {
        if (HIDWriteInfo.VendorID != 0)
        {
            var Count = 0;

            if (HIDWriteInfo.Device[Index].Attributes.VendorID == HIDWriteInfo.VendorID)
            {
                Count++;
            }
            if (HIDWriteInfo.Device[Index].Attributes.ProductID == HIDWriteInfo.ProductID)
            {
                Count++;
            }
            if (HIDWriteInfo.Device[Index].Caps.UsagePage == HIDWriteInfo.UsagePage)
            {
                Count++;
            }
            if (HIDWriteInfo.Device[Index].Caps.Usage == HIDWriteInfo.Usage)
            {
                Count++;
            }

            if (Count == 4)
            {
                HIDWriteInfo.iDevice = Index;
                HIDWriteInfo.Active  = true;

                return;
            }
        }
    }
}

HIDReadUpdate()HIDWriteUpdate()用于检查我们是否按读取发送按钮,以及输入的数据(VID-PID-Usa...)是否与连接的USB设备相对应。

此函数返回USB设备的数量,以便对其进行扫描。

Int32   FindDeviceNumber()
{
    var hidGuid        = new Guid();
    var deviceInfoData = new SP_DEVICE_INTERFACE_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));

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

    return (Index);
}

此函数返回HIDRead()HIDWrite()所需的每个USB设备的数据结构。

static public void FindKnownHIDDevices(ref HID_DEVICE[] HID_Devices)
{
    var hidGuid                 = new Guid();
    var deviceInfoData          = new SP_DEVICE_INTERFACE_DATA();
    var functionClassDeviceData = new SP_DEVICE_INTERFACE_DETAIL_DATA();

    Hid.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));

    for (var iHIDD = 0; iHIDD < HID_Devices.Length; iHIDD++)
    {
        SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, IntPtr.Zero, ref hidGuid, iHIDD, ref deviceInfoData);

        //
        // Allocate a function class device data structure to receive the
        // goods about this particular device.
        //
        var RequiredLength = 0;
        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 HID_Devices, iHIDD);
    }
}

此函数扩展FindKnownHIDDevices()

static void OpenHIDDevice(String DevicePath, ref HID_DEVICE[] HID_Device, Int32 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 relivant information in the given
    // HID_DEVICE structure.
    //
    HID_Device[iHIDD].DevicePath = DevicePath;

    //
    // The hid.dll api's 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(HID_Device[iHIDD].Handle);
    HID_Device[iHIDD].Handle     = CreateFile(HID_Device[iHIDD].DevicePath,
                                              FileAccess.ReadWrite, FileShare.ReadWrite,
                                              0, FileMode.Open, FileOptions.None,
                                              IntPtr.Zero);
    HID_Device[iHIDD].Caps       = new HIDP_CAPS();
    HID_Device[iHIDD].Attributes = new HIDD_ATTRIBUTES();

    //
    // If the device was not opened as overlapped, then fill in the rest of the
    // HID_Device 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.
    //
    Hid.HidD_FreePreparsedData(ref HID_Device[iHIDD].Ppd);
    HID_Device[iHIDD].Ppd = IntPtr.Zero;

    Hid.HidD_GetPreparsedData(HID_Device[iHIDD].Handle, ref HID_Device[iHIDD].Ppd);
    Hid.HidD_GetAttributes   (HID_Device[iHIDD].Handle, ref HID_Device[iHIDD].Attributes);
    Hid.HidP_GetCaps         (HID_Device[iHIDD].Ppd   , ref HID_Device[iHIDD].Caps);

    var Buffer = Marshal.AllocHGlobal(126);
    {
        Hid.HidD_GetManufacturerString(HID_Device[iHIDD].Handle, Buffer, 126);
        HID_Device[iHIDD].Manufacturer = Marshal.PtrToStringAuto(Buffer);

        Hid.HidD_GetProductString(HID_Device[iHIDD].Handle, Buffer, 126);
        HID_Device[iHIDD].Product = Marshal.PtrToStringAuto(Buffer);

        Hid.HidD_GetSerialNumberString(HID_Device[iHIDD].Handle, Buffer, 126);
        HID_Device[iHIDD].SerialNumber = Marshal.PtrToStructure<Int32>(Buffer);
    }
    Marshal.FreeHGlobal(Buffer);
}

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

static async public void BeginAsyncRead(object? state)
{
    //
    // Read what the USB device has sent to the PC and store the result inside HID_Report[]
    //
    if (HIDReadInfo.Active == true)
    {
        var Device       = HIDReadInfo.Device[HIDReadInfo.iDevice];
        var ReportBuffer = new Byte[Device.Caps.InputReportByteLength];

        if (ReportBuffer.Length > 0)
        {
            await Task.Run(() =>
            {
                var NumberOfBytesRead = 0U;
                Kernel32.ReadFile(Device.Handle, ReportBuffer, Device.Caps.InputReportByteLength, ref NumberOfBytesRead, IntPtr.Zero);
            });

            HIDReadInfo.ReportData = new List<Byte>(ReportBuffer);
        }
    }
}

static public void BeginSyncSend(object? state)
{
    //
    // Sent to the USB device what is stored inside WriteData[]
    //
    if (HIDWriteInfo.Done is false && HIDWriteInfo.Active is true)
    {
        var Device = HIDWriteInfo.Device[HIDWriteInfo.iDevice];
        var ReportBuffer = new Byte[Device.Caps.OutputReportByteLength];

        if (ReportBuffer.Length > 0)
        {
            //
            // Add ReportID to the first byte of HID_ReportContent
            //
            ReportBuffer[0] = HIDWriteInfo.ReportID;

            //
            // Copy ReportData into HID_ReportContent starting from index 1
            //
            Array.Copy(HIDWriteInfo.ReportData, 0, ReportBuffer, 1, ReportBuffer.Length - 1);

            var varA = 0U;
            Kernel32.WriteFile(Device.Handle, ReportBuffer, Device.Caps.OutputReportByteLength, ref varA, IntPtr.Zero);
        }

        HIDWriteInfo.Done = true;
    }
}

为此,您需要在之前设置以下数据:

  • VendorID
  • ProductID
  • UsagePage
  • Usage
  • ReportID

但请注意,您需要为所有这些参数设置正确的值,如果是false,您将无法发送HID数据包。

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

  • VendorID
  • ProductID

此外,如果USB设备无法发送数据,则无法读取,如果USB设备无法读取数据(在其HID报告描述符中定义),则无法写入。

设备由其定义VendorID:ProductID,但缩小为由UsagePageUsageReportID定义的多个函数。

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

要设置这些变量,您需要读取目标USB设备的HID描述符,可以使用USB嗅探器将其检索为 GitHub - djpnewton/busdog: busdog is a filter driver for MS Windows (XP and above) to sniff USB traffic.http://www.usblyzer.com/usb-analysis-features.htm

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

要学习阅读HID描述符,请使用此工具:Human Interface Devices (HID) Specifications and Tools | USB-IF

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

https://www.codeproject.com/Articles/1244702/Communication-with-USB-Devices-using-HID-Protocol

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USB HID指的是USB Human Interface Device(人机接口设备协议。它是一种在USB接口上实现人机交互的协议标准。USB HID设备是指符合USB HID协议设备,可以通过USB接口与计算机进行通信USB HID协议定义了HID设备与主机之间的通信方式和数据格式。HID设备可以是各种输入设备,如键盘、鼠标、游戏手柄等,也可以是一些输出设备,如LED灯、触摸屏等。通过USB HID协议,这些设备可以与计算机进行双向通信。 在USB HID协议中,设备是通过在发送的数据包中定义的报告描述符(Report Descriptor)来描述自己的功能和属性的。报告描述符包含了设备的输入、输出、特征等数据报告的定义,以及每个报告的数据格式和长度。主机可以通过读取设备的报告描述符来了解设备的功能和属性,从而进行相应的数据交互。 USB HID设备在与主机通信时,会按照一定的规则和格式进行数据的传输。数据的传输通过数据报进行,每个数据报包含有一个或多个报告的数据。数据报的格式包含一个报告ID和对应的报告数据。报告ID用于标识不同的报告,主机可以通过报告ID来识别并处理不同的报告。 USB HID协议的实现为人机交互提供了便捷的方式。它广泛应用于各种输入设备和输出设备,为用户提供了更加灵活和丰富的计算机交互体验。同时,USB HID协议也为设备的开发者提供了统一的标准和接口,简化了设备的开发和兼容性的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值