首页 > 编程语言 >【USB】C#使用HID通信

【USB】C#使用HID通信

时间:2024-09-02 15:49:32浏览次数:12  
标签:sendData set USB C# short HID device HidDevices public

https://blog.csdn.net/gzylongxingtianxia/article/details/137151349

 

最近做了一个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();
1
2
3
4
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();
}
1
2
3
4
5
6
7
8
9
10
监听插拔


/// <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);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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);
1
2
3
4
5
6
7
8
9
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
4. 读写
当设备连接成功后,会建立一个字节流

this.fileStream = new FileStream(new SafeFileHandle(this.handle, false), FileAccess.ReadWrite, this.hidCaps.InputReportByteLength, true);
1
通过这个字节流读写数据

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();
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Ojbkey了,剩下的开多少个线程,如何处理发送接收就自己发挥吧,也比较简单,下班了,周末愉快,老铁们~~!!
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/gzylongxingtianxia/article/details/137151349

标签:sendData,set,USB,C#,short,HID,device,HidDevices,public
From: https://www.cnblogs.com/chinasoft/p/18392818

相关文章

  • conda环境下安装pysctransform
    要在Conda环境中安装一个程序的软件包,可以按照以下步骤进行操作。这里的步骤包括克隆GitHub仓库,安装所需的Python包,并最终安装pySCTransform。1.创建并激活一个新的Conda环境首先,创建并激活一个新的Conda环境以避免影响到其他项目:condacreate--namepysc_envpyt......
  • Nginx:location、proxy_pass中的斜杠/
    学习自:nginxlocation/区别详解_nginx_脚本之家nginx的location与proxy_pass指令超详细讲解及其有无斜杠(/)结尾的区别_nginxlocation斜杠-CSDN博客nginx的location、root、alias指令用法和区别–蓝队云Nginx系列-5root和alias和index和try_files_nginxrootindex-CSD......
  • ECharts实现雷达图详解
    ECharts是一款由百度开源的数据可视化工具,它提供了丰富的图表类型,如折线图、柱状图、饼图、散点图、雷达图、地图、K线图、热力图、仪表盘等,以及丰富的交互功能。ECharts组件的核心功能实现原理主要包括以下几个方面:数据驱动:ECharts采用数据驱动的设计理念,图表的生成和更新......
  • AP2813宽输入电压5-80V 双路降压恒流LED芯片_外围简单内置功率管驱动IC
    产品描述AP2813是一款双路降压恒流驱动器,高效率、外围简单、内置功率管,适用于5-80V输入的高精度降压LED恒流驱动芯片。内置功率管输出最大功率可达12W,最大电流1.2A。AP2813一路直亮,另外一路通过MODE1切换全亮,爆闪。AP2813工作频率固定在150KHZ左右,同时内置抖频......
  • 软件供应链风险评估:实现安全 SDLC有哪些步骤
    软件供应链包含多个环节,如开发人员、基础设施组件、GitHub存储库等。而企业的软件供应链是否安全,取决于其最薄弱的环节。随着构建的软件复杂性以及对第三方组件的依赖增加,软件供应链中的潜在风险也在逐渐增大。一旦其中包含漏洞或缺陷就可能带来重大风险。软件供应链风险的类型......
  • OpenCV(图像NaN处理)
    目录1.目的2.示例1.目的将src矩阵中的某些区域(由mask指定的非零区域)设置为NaN。SetToNan函数实现了这一功能。2.示例#include<iostream>#include<opencv2/opencv.hpp>usingnamespacestd;usingnamespacecv;voidSetToNan(cv::Mat&src,constcv::Mat......
  • 【新品8折】正点原子ZYNQ7035/7045/7100开发板发布、ZYNQ 7000系列、双核ARM、PCIe2.0
    【新品发布】正点原子FPGA新品ZYNQ7035/7045/7100开发板,ZYNQ7000系列、双核ARM、PCIe2.0、SFPX2!正点原子Z100ZYNQ开发板,搭载XilinxZynq7000系列芯片,核心板支持XilinxZynq-7035、Zynq-7045和Zynq-7100三种型号。开发板由核心板+底板组成,外设资源丰富,板载2路千兆以太网接口(PS+P......
  • Leetcode——1.合并有序数组
    给你两个按非递减顺序排列的整数数组nums1_和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你合并nums2_到nums1中,使合并后的数组同样按非递减顺序排列。注意:最终,合并后数组不应由函数返回,而是存储在数组nums1中。为了应对这种情况,nums1的初......
  • 【方法分享】准大学生如何自学C语言?
    准大学生如何自学C语言文章目录准大学生如何自学C语言一、找寻一个优质教学视频二、使用优质编译器三、安排一个电子笔记需不需要一个ipad来辅助学习?四、除工具以外的学习方法1.专心致志,不要让其他东西分心2.多练习,多练习,多练习3.复习!结语虽说现在已经接近我们最长的且无忧无虑的......
  • .NET 8.0 前后分离快速开发框架--YuebonCore
    合集-.NET开源项目(9) 1.推荐一款界面优雅、功能强大的.NET+Vue权限管理系统08-052..NET开源权限认证项目MiniAuth上线08-063..NET与LayUI实现高效敏捷开发框架08-084..NET8+Blazor多租户、模块化、DDD框架、开箱即用08-095.推荐一个优秀的.NETMAUI组件......