3430|2

46

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【GD32L233C-START评测】6. 为HID设备做个简单的上位机 [复制链接]

【GD32L233C-START评测】1.开箱测试点亮彩屏
【GD32L233C-START评测】2.超级玛丽跑起来
【GD32L233C-START评测】3.USB键盘的实现
【GD32L233C-START评测】4.USB鼠标的实现

【GD32L233C-START评测】5.USB自定义HID设备点灯

 

上一篇中实现了自定义HID设备,并且使用《圈圈教你玩USB》中的上位机小工具。圈圈的工具是使用MFC写的,而且是在VC6.0下的。VC6.0已经太老了,现在写上位机C#显然要比MFC要方便的许多。所以就使用C#的Winform写个简单的HID上位机。

上位机的界面如下:

界面比较简单,使用combox显示系统里面所有的HID设备的设备路径。然后中间四个按钮代表开发板上的四个灯。最下面的文本框显示操作过程中的信息的输出。

使用C#写HID上位机其实和C++差不多,也是调用系统中HID.dll export出来的HidD_GetHidGuid之类函数, setupapi.dll export出来的SetupDiEnumDeviceInterfaces之类函数,已经Windows系统中操作文件的kernel32.dll中的createfile这类函数。

首先是枚举系统中所有的HID设备。

public static void GetHidDeviceList(ref List<string> deviceList)
        {
            Guid hUSB = Guid.Empty;
            uint index = 0;

            deviceList.Clear();
            // 取得hid设备全局id
            HidD_GetHidGuid(ref hUSB);
            //取得一个包含所有HID接口信息集合的句柄
            IntPtr hidInfoSet = SetupDiGetClassDevs(ref hUSB, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);
            if (hidInfoSet != IntPtr.Zero)
            {
                SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA();
                interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo);
                //查询集合中每一个接口
                for (index = 0; index < MAX_USB_DEVICES; index++)
                {
                    //得到第index个接口信息
                    if (SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUSB, index, ref interfaceInfo))
                    {
                        int buffsize = 0;
                        // 取得接口详细信息:第一次读取错误,但可以取得信息缓冲区的大小
                        SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, IntPtr.Zero, buffsize, ref buffsize, null);
                        //构建接收缓冲
                        IntPtr pDetail = Marshal.AllocHGlobal(buffsize);
                        SP_DEVICE_INTERFACE_DETAIL_DATA detail = new SP_DEVICE_INTERFACE_DETAIL_DATA();
                        detail.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));
                        Marshal.StructureToPtr(detail, pDetail, false);
                        if (SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null))
                        {
                            deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4)));
                        }
                        Marshal.FreeHGlobal(pDetail);
                    }
                }
            }
            SetupDiDestroyDeviceInfoList(hidInfoSet);
        }

然后就是打开我们在界面上选中的设备:

public HID_RETURN OpenDevice(string deviceString)
        {
            if (deviceOpened == true)
                return HID_RETURN.DEVICE_OPENED;

            IntPtr device = CreateFile(deviceString,
                                        DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE,
                                        0,
                                        0,
                                        CREATIONDISPOSITION.OPEN_EXISTING,
                                        FLAGSANDATTRIBUTES.FILE_FLAG_OVERLAPPED,
                                        0);
            if (device != INVALID_HANDLE_VALUE)
            {
                //HIDD_ATTRIBUTES attributes;
                //HidD_GetAttributes(device, out attributes);
                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;
            }
            else
            {
                return HID_RETURN.DEVICE_NOT_FIND;
            }
        }

然后就是向设备发送数据,对于上层来说也就是向文件中写入数据:

        public HID_RETURN Write(report r)
        {
            if (deviceOpened)
            {
                try
                {
                    byte[] buffer = new byte[outputReportLength];
                    buffer[0] = r.reportID;
                    int maxBufferLength = 0;
                    if (r.reportBuff.Length < outputReportLength - 1)
                        maxBufferLength = r.reportBuff.Length;
                    else
                        maxBufferLength = outputReportLength - 1;

                    for (int i = 0; i < maxBufferLength; i++)
                        buffer[i + 1] = r.reportBuff[i];
                    hidDevice.Write(buffer, 0, OutputReportLength);
                    return HID_RETURN.SUCCESS;
                }
                catch
                {
                    EventArgs ex = new EventArgs();
                    OnDeviceRemoved(ex);//发出设备移除消息
                    CloseDevice();
                    return HID_RETURN.NO_DEVICE_CONECTED;
                }
            }
            return HID_RETURN.WRITE_FAILD;
        }

上述的三个函数基本上就完成了HID设备的遍历,然后对指定设备的打开,最后向设备写入数据。对应到界面上就是点击一个按钮,那么开发板上对应的LED灯就会被点亮。

感兴趣的小伙伴可以git clone代码自己研究,代码在https://github.com/bzhou830/GD32/tree/main/HIDApp中。

 

 

 

此帖出自GD32 MCU论坛

最新回复

上位机的界面虽然简单,功能上还是能用的   详情 回复 发表于 2022-3-23 07:26
点赞 关注(1)
 

回复
举报

6807

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

上位机的界面虽然简单,功能上还是能用的

此帖出自GD32 MCU论坛

点评

哈哈,功能肯定是要能用呀  详情 回复 发表于 2022-3-23 10:24
 
 
 

回复

46

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
Jacktang 发表于 2022-3-23 07:26 上位机的界面虽然简单,功能上还是能用的

哈哈,功能肯定是要能用呀

此帖出自GD32 MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表