【USB】C#使用HID通信

最近做了一个USB通信SDK, 通过HID跟单片机通信,之前研究了一下Libusb, Cyusb, 要么死的太早,要么封装的不好,最后绕来绕去发现还是HID好用,反编译了一个SimpleHid, 别说,用起来还是很酸爽的~~~

1.设备识别

首先你要指定VID和PID, 这2个不知道的可以不用往下看了,就是一个人的名字和性别
设别识别很容易,直接获取设备列表,对比一下vid,pid就搞定了,不多墨迹了

直接Linq一下了

          // 获取所有目标设备信息集合
            List<HIDInfoSet> acceptableDevices = HIDManager.GetInfoSets()
                .Where(set => this.m_OpenOptions.IsVidAndPidAcceptable(set.Vid, set.Pid))
                .ToList();

2.插拔识别

这里有3中方法
方法1.使用winform pnpinvoke 监听消息句柄,判断插拔, 对上位机来说这种方式很常见了,但是有限制,下面说。

方法2.使用cpp dll, 方法1的限制在于有些native软件不能使用winform,比如Unity I2cpp 打包就不行,所以需要自己用C++封装dll,然后使用委托回调函数触发,这个也不难,可以看看我之前的文章
https://blog.csdn.net/gzylongxingtianxia/article/details/136683845

方法3. 简单粗暴,直接开一个监控线程

    private void ThreadProcDeviceDiscovery()
        {
            while (!this.bKillUsbDiscoverThread)
            {
                this.DoDeviceDiscovery();
                Thread.Sleep(200);
            }

            this.KillDiscoveryThread();
        }

监听插拔


        /// <summary>
        /// The do device discovery.
        /// </summary>
        private void DoDeviceDiscovery()
        {
            if (this.m_HidDevices == null)
            {
                return;
            }

            // 获取当前已连接的设备的序列号列表
            List<string> connectedSerialNumbers = new List<string>();
            lock (this.m_HidDevices)
            {
                foreach (UsbHidDevice device in this.m_HidDevices)
                {
                    connectedSerialNumbers.Add(device.hidInfoSet.SerialNumberString);
                }
            }

            // 获取所有目标设备信息集合
            List<HIDInfoSet> acceptableDevices = HIDManager.GetInfoSets()
                .Where(set => this.m_OpenOptions.IsVidAndPidAcceptable(set.Vid, set.Pid))
                .ToList();

            // 获取新发现的设备信息集合
            List<HIDInfoSet> newDevices = acceptableDevices
                .Where(set => !connectedSerialNumbers.Contains(set.SerialNumberString))
                .ToList();

            // 获取已断开的设备列表
            List<UsbHidDevice> disconnectedDevices = this.m_HidDevices
                ?.Where(device => !acceptableDevices.Any(set => set.SerialNumberString == device.hidInfoSet.SerialNumberString))
                .ToList();

            if (disconnectedDevices == null)
            {
                return;
            }

            // 断开已断开的设备并移除
            foreach (UsbHidDevice device in disconnectedDevices)
            {
                lock (this.m_HidDevices)
                {
                    this.m_HidDevices.Remove(device);
                    EventDispatcher.TriggerEvent(EventEnum.DEVICE_DETACHED, device);
                }
            }

            // 实例化新发现的设备并添加到已连接列表中
            foreach (HIDInfoSet set in newDevices)
            {
                UsbHidDevice device = new UsbHidDevice(this, set);
                
                lock (this.m_HidDevices)
                {
                    this.curHidDevice = device;
                    this.m_HidDevices.Add(device);
                }

                EventDispatcher.TriggerEvent(EventEnum.DEVICE_ATTACHED, this.curHidDevice);
            }
        }

3.HID通信

1.创建通信句柄要开启读写

static class DESIREDACCESS
{
    public const uint GENERIC_READ = 0x80000000;
    public const uint GENERIC_WRITE = 0x40000000;
    public const uint GENERIC_EXECUTE = 0x20000000;
    public const uint GENERIC_ALL = 0x10000000;
}

this.handle = NativeMethods.CreateFile(devicePath, DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE, 3, IntPtr.Zero, 3, 0x40000000, IntPtr.Zero);

NativeMethods.CreateFile第二个参数要开启读写

2.HidCaps


        [StructLayout(LayoutKind.Sequential, Pack=1)]
        public struct HidCaps
        {
            public short Usage;
            public short UsagePage;
            public short InputReportByteLength;
            public short OutputReportByteLength;
            public short FeatureReportByteLength;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=0x11)]
            public short[] Reserved;
            public short NumberLinkCollectionNodes;
            public short NumberInputButtonCaps;
            public short NumberInputValueCaps;
            public short NumberInputDataIndices;
            public short NumberOutputButtonCaps;
            public short NumberOutputValueCaps;
            public short NumberOutputDataIndices;
            public short NumberFeatureButtonCaps;
            public short NumberFeatureValueCaps;
            public short NumberFeatureDataIndices;
        }

InputReportByteLength 和 OutputReportByteLength 这2个长度很重要,一般是65个字节,ReportId + Data

3. 构建报文数据
Report Id 单个包来说都是 0 ,如果一次发多个包,就要递增,我这里是一个包的情况
总长度 0x41 = 65 , ReportId + Data ,数据占64个字节
长度一定不能错,否则会包HID参数异常
下面是一个参考方法

       public void MakeBytes(EMessage cmd, byte value)
        {
        	this.reportId = 0;
            this.value = (int)value;
            this.length = 1;
            this.cmd = (int)cmd;

            var i = 0;
            this.sendData = new byte[0x41];
            this.sendData[i] = this.reportId;
            this.sendData[i++] = 0x05;
            this.sendData[i++] = 0XAA;
            this.sendData[i++] = 0XAA;
            this.sendData[i++] = (byte)cmd;
            this.sendData[i++] = 1;
            this.sendData[i++] = value;

            for (; i < 0x41; i++)
            {
                this.sendData[i] = 0;
            }
        }

4. 读写
当设备连接成功后,会建立一个字节流

 this.fileStream = new FileStream(new SafeFileHandle(this.handle, false), FileAccess.ReadWrite, this.hidCaps.InputReportByteLength, true);

通过这个字节流读写数据

 public byte[] ReadRawInputReport()
 {
     byte reportID = 0;
     byte[] buffer = this.CreateRawInputReport(reportID);
     try
     {
         this.fileStream.Read(buffer, 0, buffer.Length);
     }
     catch (Exception e)
     {
         return buffer;
     }

     return buffer;
 }

public void WriteRawOutputReport(byte[] data)
 {
     try
     {
         this.fileStream.Write(data, 0, data.Length);
         this.fileStream.Flush();
     }
     catch (Exception e)
     {
         throw new HIDDeviceException();
     }
 }

Ojbkey了,剩下的开多少个线程,如何处理发送接收就自己发挥吧,也比较简单,下班了,周末愉快,老铁们~~!!

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
赋所有源代码,开发工具vs2010 framework3.5 baidu搜索c# HidUsb都是大同小异案例,而且拿下来基本不能用。大都是围绕public static extern int CreateFile(省略众多参数..);发现没有,copy下来测试基本都是用不了的。 原因很简单:windows不允许你用程序随便就去访问硬件设备。所以在此把之前做过的基于C#开发读写HidUsb设备的项目整理成一个简单的小案例,分享给大家,开发环境VS2010。 该案例重点在public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile); 看着貌似也是用到CreateFile这个函数,其实并不然,注意到没有"SafeFileHandle",这就是重点! 这样windows是允许程序访问外接hidusb设备的。 当然具体如何运用这个函数现在已经不是您应该 关心的了,因为我已经为您把它封装成一个类,您只要调用相应的方法就OK. 例: //第一步:获取HidUsb设备信息 List slist = new List(); UsbHidDevice usbhid = new UsbHidDevice(); usbhid.GetDeviceList(ref slist); //HidUsb设备信息包含在List数据集中 注:当获取到HidUsb设备信息为:\\?\hid#vid_0e2c&pid;_0112#6&1b44c403;&0&0000;#{4d1e55b2-f16f-11cf-88cb-001111000030}, 注意该字符串里的“vid_0e2c”和“pid_0112”部分,那么: vid为0e2c, pid为:0112 //第二步:创建一个HidUsb设备访问实例 UsbHidDevice Device = new UsbHidDevice(vid, pid); //第三步:连接HidUsb设备 Boolean connBool = Device.Connect(); //第四步:实现数据接收事件 Device.DataReceived += new UsbHidDevice.DataReceivedDelegate(Device_DataReceived); //当HidUsb设备返回信息时触发此事件 void Device_DataReceived(byte[] data) { //处理接收到的数据逻辑 } //第五步:向Hid设备发送数据"0xa0 00 0x12 0x9 0x22" string txt = "0xa0 00 0x12 0x9 0x22"; //把数据转换为字节数组 byte[] data = ConvertHelper.StringToByte(txt2); byte bt = 0; CommandMessage cmdMsg = new CommandMessage(bt, data); Boolean sbool = Device.SendMessage(cmdMsg); //发送数据 //第六步:释放所有资源 Device.Dispose();

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值