【C#】HID API

该博客介绍了如何在Windows环境下使用C#进行HID(Human Interface Device)通信。内容包括通过PID和VID自动连接设备,无需额外驱动,并提供了一个3层结构的HID接口实现,支持异步收发数据。示例代码包括Hid.cs和HIDInterface.cs两个文件,数据包大小固定为64bytes,首个字节表示后续数据长度。
摘要由CSDN通过智能技术生成

范例下载地址:https://download.csdn.net/download/u010875635/10689911

Windows使用HID通信相对比较简单,HID都是通过PID、VID信息来查找连接的,相比于串口,几乎无变化,连接无需人工选择,十分方便,也不需要驱动。

下面上实例,PID为0x003f,VID为0x04D8,支持发送接收数据显示到UI,使用C#来编写,调用的是windows api(create file、read file、write file)。

本实例将HID接口分成3层,支持自动连接、断开状态通知,异步收发数据,单个数据包大小为64bytes(因为从设备的数据包设定为64bytes,保持一致)。

接口分为两层,第一层将create file、read file、write file封装,第二层再封装自动连接、异步收发。

Hid.cs -> HIDInterface.cs -> 应用

注意,这里所有数据都是64bytes,但是有用数据并非这么多,所以设定为第一个数据为后面数据实际长度,若需要修改定义,请在HIDInterface.cs的Send与HidDataReceived函数中修改处理方法即可。

 

Hid.cs

 

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Windows;

namespace HID_SIMPLE.HID
{
    public class report : EventArgs
    {
        public readonly byte reportID;
        public readonly byte[] reportBuff;
        public report(byte id, byte[] arrayBuff)
        {
            reportID = id;
            reportBuff = arrayBuff;
        }
    }
    public class Hid : object
    {
        private IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        private const int MAX_USB_DEVICES = 64;
        private bool deviceOpened = false;
        private FileStream hidDevice = null;
        private IntPtr hHubDevice;
        
        int outputReportLength;//输出报告长度,包刮一个字节的报告ID
        public int OutputReportLength { get { return outputReportLength; } }
        int inputReportLength;//输入报告长度,包刮一个字节的报告ID   
        public int InputReportLength { get { return inputReportLength; } }

        /// <summary>
        /// 打开指定信息的设备
        /// </summary>
        /// <param name="vID">设备的vID</param>
        /// <param name="pID">设备的pID</param>
        /// <param name="serial">设备的serial</param>
        /// <returns></returns>
        public HID_RETURN OpenDevice(UInt16 vID, UInt16 pID, string serial)
        {
            if (deviceOpened == false)
            {
                //获取连接的HID列表
                List<string> deviceList = new List<string>();
                GetHidDeviceList(ref deviceList);
                if (deviceList.Count == 0)
                    return HID_RETURN.NO_DEVICE_CONECTED;
                for (int i = 0; i < deviceList.Count; i++)
                {
                    IntPtr device = CreateFile(deviceList[i],
                                                DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE,
                                                0,
                                                0,
                                                CREATIONDISPOSITION.OPEN_EXISTING,
                                                FLAGSANDATTRIBUTES.FILE_FLAG_OVERLAPPED,
                                                0);
                    if (device != INVALID_HANDLE_VALUE)
                    {
                        HIDD_ATTRIBUTES attributes;
                        IntPtr serialBuff = Marshal.AllocHGlobal(512);
                        HidD_GetAttributes(device, out attributes);
                        HidD_GetSerialNumberString(device, serialBuff, 512);
                        string deviceStr = Marshal.PtrToStringAuto(serialBuff);
                        Marshal.FreeHGlobal(serialBuff);
                        if (attributes.VendorID == vID && attributes.ProductID == pID && deviceStr.Contains(serial))
                        {
                            IntPtr preparseData;
                            HIDP_CAPS caps;
                            HidD_GetPreparsedData(device, out preparseData);
                            HidP_GetCaps(preparseData, out caps);
                            HidD_FreePreparsedData(preparseData);
                            outputReportLength = caps.OutputReportByteLength;
                            inputReportLength = caps.InputReportByteLength;

                            hidDevice = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite, inputReportLength, true);
                            deviceOpened = true;
                            BeginAsyncRead();

                            hHubDevice = device;
                            return HID_RETURN.SUCCESS;
                        }
                    }
                }
                return HID_RETURN.DEVICE_NOT_FIND;
            }
            else
                return HID_RETURN.DEVICE_OPENED;
        }

        /// <summary>
        /// 关闭打开的设备
        /// </summary>
        public void CloseDevice()
        {
            if (deviceOpened == true)
            {
                deviceOpened = false;
                hidDevice.Close();
            }
        }

        /// <summary>
        /// 开始一次异步读
        /// </summary>
        private void BeginAsyncRead()
        {
            byte[] inputBuff = new byte[InputReportLength];
            hidDevice.BeginRead(inputBuff, 0, InputReportLength, new AsyncCallback(ReadCompleted), inputBuff);
        }

        /// <summary>
        /// 异步读取结束,发出有数据到达事件
        /// </summary>
        /// <param name="iResult">这里是输入报告的数组</param>
        private void ReadCompleted(IAsyncResult iResult)
        {
            byte[] readBuff = (byte[])(iResult.AsyncState);
            try
            {
                hidDevice.EndRead(iResult);//读取结束,如果读取错误就会产生一个异常
                byte[] reportData = new byte[readBuff.Length - 1];
                for (int i = 1; i < readBuff.Length; i++)
                    reportData[i - 1] = readBuff[i];
                report e = new report(readBuff[0], reportData);
                OnDataReceived(e); //发出数据到达消息
                if (!deviceOpened) return;
                BeginAsyncRead();//启动下一次读操作
            }
            catch //读写错误,设备已经被移除
            {
                //MyConsole.WriteLine("设备无法连接,请重新插入设备");
                EventArgs ex = new EventArgs();
                OnDeviceRemoved(ex);//发出设备移除消息
                CloseDevice();

            }
        }

        public delegate void DelegateDataReceived(object sender, report e);
        //public event EventHandler<ConnectEventArg> StatusConnected;
       
        public DelegateDataReceived DataReceived;

        /// <summary>
        /// 事件:数据到达,处理此事件以接收输入数据
        /// </summary>
        
        protected virtual void OnDataReceived(report e)
        {
            if (DataReceived != null) DataReceived(this, e);
        }

        /// <summary>
        /// 事件:设备断开
        /// </summary>

        public delegate void DelegateStatusConnected(object sender, EventArgs e);
        public DelegateStatusConnected DeviceRemoved;
        protected virtual void OnDeviceRemoved(EventArgs e)
        {
            if (DeviceRemoved != null) DeviceRemoved(this,
好的,以下是一个基于C#HID蓝牙链接例程: ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using InTheHand.Net; using InTheHand.Net.Bluetooth; using InTheHand.Net.Sockets; namespace BluetoothHID { class Program { static void Main(string[] args) { // 蓝牙设备的MAC地址 BluetoothAddress address = BluetoothAddress.Parse("00:11:22:33:44:55"); // 创建一个蓝牙客户端 BluetoothClient client = new BluetoothClient(); // 连接设备 BluetoothDeviceInfo device = client.DiscoverDevices().FirstOrDefault(d => d.DeviceAddress == address); if (device == null) { Console.WriteLine("设备未找到!"); return; } BluetoothEndPoint endpoint = new BluetoothEndPoint(device.DeviceAddress, BluetoothService.HumanInterfaceDeviceService); client.Connect(endpoint); // 获取数据流 System.IO.Stream stream = client.GetStream(); // 发送数据 byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 }; stream.Write(data, 0, data.Length); // 接收数据 byte[] buffer = new byte[1024]; int count = stream.Read(buffer, 0, buffer.Length); Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, count)); // 关闭连接 client.Close(); } } } ``` 以上代码演示了如何连接到一个HID蓝牙设备,并发送数据。具体实现可能会因设备不同而有所差异,但这个示例可以作为一个基础。需要注意的是,这个代码使用了第三方库 `InTheHand.Net`,该库提供了.NET下操作蓝牙设备的相关API
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值