【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了,剩下的开多少个线程,如何处理发送接收就自己发挥吧,也比较简单,下班了,周末愉快,老铁们~~!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/780959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序的日语词汇学习设计与实现(论文+源码)_kaic

日语词汇学习小程序 摘 要 日语词汇学习小程序是高校人才培养计划的重要组成部分&#xff0c;是实现人才培养目标、培养学生科研能力与创新思维、检验学生综合素质与实践能力的重要手段与综合性实践教学环节。本学生所在学院多采用半手工管理日语词汇学习小程序的方式&#x…

如何用Python脚本自动发送邮件?

目录 1. 基础知识 1.1. SSH&#xff08;Secure Shell&#xff09;协议 1.2. SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;协议 1.3. SSH协议与SMTP协议之间的关系 2. QQ邮箱设置 2.1. 开启SMTP服务 2.2. 编写脚本 3. 测试成功 1. 基础知识 邮件的发送过…

从TCP/IP协议到socket编程详解

​ 我的所有学习笔记&#xff1a;https://github.com/Dusongg/StudyNotes⭐⭐⭐ ​ 文章目录 1 网络基础知识1.1 查看网络信息1.2 认识端口号1.3 UDP1.4 TCP1.4.1 确认应答机制1.4.2 TCP三次握手/四次挥手为什么是三次握手为什么是四次挥手listen 的第二个参数 backlog—— 全…

01_安装VMwareWorkstation虚拟机

环境&#xff1a;Win10 19045 软件版本&#xff1a;VMware-workstation-17.5.1 一、下载链接 Download VMware Workstation Pro 二、安装&#xff08;无脑下一步&#xff09; 安装位置自选&#xff0c;最好非系统盘。 增强型键盘驱动自选。 更新自选。 快捷方式自选。 三、…

fastllm在CPU上推理ChatGLM2-6b,就来看这篇文章,速度很快

介绍: GitHub - ztxz16/fastllm: 纯c++的全平台llm加速库,支持python调用,chatglm-6B级模型单卡可达10000+token / s,支持glm, llama, moss基座,手机端流畅运行纯c++的全平台llm加速库,支持python调用,chatglm-6B级模型单卡可达10000+token / s,支持glm, llama, moss基…

Linux系统----------探索mysql数据库MHA高可用

目录 一、MHA概述 1.1 什么是 MHA 1.2MHA 的组成 1.2.1MHA Node&#xff08;数据节点&#xff09; 1.2.2MHA Manager&#xff08;管理节点&#xff09; 1.3MHA 的特点 1.4MHA工作原理 1.5数据同步的方式 1.5.1同步复制 1.5.2异步复制 1.5.3半同步复制 二、搭建 MySQ…

分布式算法 - ZAB算法

ZAB算法是用于实现分布式系统中的原子广播的核心算法&#xff0c;它被广泛应用于ZooKeeper分布式协调服务中。 ZAB算法由两个主要阶段组成&#xff1a;崩溃恢复阶段和消息广播阶段。 在崩溃恢复阶段&#xff0c;当一个ZooKeeper节点启动或者领导者节点崩溃重启时&#xff0c;…

蓝桥杯2016年第十三届省赛真题-凑算式

一、题目 凑算式 B DEF A --- ------- 10 C GHI 这个算式中A~I代表1~9的数字&#xff0c;不同的字母代表不同的数字。&#xff08;比赛时&#xff0c;题目有改动&#xff09; 比如&#xff1a; 68/39…

[高考] 数学题的一般解题思路

最近家里来了一位高中生&#xff0c;每天晩上辅导一下。虽然我不赞成现在的教育方式&#xff0c;但也脱不了随大流的现实。现根据这两周的教学经验总结一二&#xff0c;以便后续用的上&#xff01; 之前也经常听到有些学生说自己数学一点都不会。我觉的只要智力可以&#xff0…

docker:can’t create unix socket /var/run/docker.sock: is a directory

docker:can’t create unix socket /var/run/docker.sock: is a directory 原因&#xff1a;docker.sock不能创建 解决方式&#xff1a; rm -rf /var/run/docker.sock 然后重新启动docker Docker是一种相对使用较简单的容器&#xff0c;我们可以通过以下几种方式获取信息&…

C++入门练习题目解析(第二讲)

1.设计一个表示点的类point&#xff0c;内含私有成员变量x&#xff0c;y表示点的坐标。再设计一个独立函数double distance(point m,point n); 来计算两点距离。 #include<iostream> #include<math.h> using namespace std; class point { private:int x, y; publ…

小赢科技公布2023年业绩:业绩稳健增长,服务“触角”有效延伸

近日&#xff0c;金融科技公司小赢科技&#xff08;NYSE:XYF&#xff09;发布了2023年第四季度及全年未经审计的财务业绩。 财报显示&#xff0c;小赢科技2023年全年总净营收约为48.15亿元&#xff0c;同比增长35.1%&#xff1b;净利润约为11.87亿元&#xff0c;同比增长46.2%…

平价的挂耳式耳机有哪些?五大高口碑品牌,深度测评严选!

随着技术的发展&#xff0c;市面上的一些高端开放式耳机已经在音质上有了显著的提升&#xff0c;甚至可以媲美一些入耳式耳机。与传统入耳式耳机相比&#xff0c;开放式耳机不会对耳道造成压迫&#xff0c;这减少了耳朵的疲劳感&#xff0c;使得长时间聆听音乐变得更加舒适。由…

FastAPI+React全栈开发08 安装MongoDB

Chapter02 Setting Up the Document Store with MongoDB 08 Installing MongoDB and friends FastAPIReact全栈开发08 安装MongoDB The MongoDB ecosystem is composed of different pieces of software, and I remember that when I was starting to play with it, there w…

《AIGC重塑金融:AI大模型驱动的金融变革与实践》

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-oBSlqt4Vga1he7DL {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

亚信安全联合人保财险推出数字安全保障险方案,双重保障企业数字化转型

数字化发展&#xff0c;新兴技术的应用与落地带来网络攻击的进一步演进升级&#xff0c;同时全球产业链供应链融合协同的不断加深&#xff0c;更让网络威胁的影响范围与危害程度不断加剧。 企业单纯依靠自身安全能力建设&#xff0c;能否跟上网络威胁的进化速度&#xff1f;能否…

《算法笔记》系列----质数的判断(埃氏筛法)

目录 一、朴素算法 二、埃氏筛法 1、与朴素算法对比 2、算法介绍 3、例题即代码实现 一、朴素算法 从素数的定义中可以知道&#xff0c;一个整数n要被判断为素数&#xff0c;需要判断n是否能被2.3.n- 1中的一个整除。只2&#xff0c;3..n- 1都不能整除n&#xff0c;n才能…

基于el-table实现行内增删改

实现效果&#xff1a; 核心代码&#xff1a; <el-table :data"items"style"width: 100%;margin-top: 16px"border:key"randomKey"><el-table-column label"计划名称"property"name"><template slot-scope&q…

【LAMMPS学习】五、LAMMPS命令(9-12) (Bond\Angle\Dihedral\Improper)势

5. 命令 本部分描述了 LAMMPS 输入脚本的格式以及其中的命令如何用于定义 LAMMPS 模拟。主要包括以下内容。 5.1. LAMMPS 输入脚本 5.2.输入脚本的解析规则 5.3.输入脚本结构 5.4. 按类别划分的命令 5.5.通用命令 5.6.Fix命令 5.7.compute命令 5.8.Pair_style 势 5.…

SpringMVC源码分析(六)--参数名称解析器

默认情况下编译时&#xff0c;不会带上方法参数名称&#xff0c;例如通过javac ./ParamNameResolverTest.java编译如下类 public class ParamNameResolverTest {public void test(String name, int age) {} } 编译的结果如下&#xff1a; public class ParamNameResolverTes…