USB HID类的编写

   使用CH372 USB芯片进行USB数据通信时,CH372默认有2种模式,一种是内置固件模式,另外一种是外置固件模式。当设置CH372为外置固件模式时,上位机界面可以脱离调用该USB芯片公司提供的dll,使用微软提供的DDK文件提供的函数实现。

    该类库有两个文件,分别是CHIDUSB.cpp和CHIDUSB.h。

CHIDUSB.h

 

 
  
1 /* **************************************************
2 *作 者:温子祺
3 *联系方式:wenziqi@hotmail.com
4 *说 明:CHIDUSB.h
5 不要忘记引用以下的代码
6 #include "dbt.h"
7
8 extern "C" {
9 #include "hidsdi.h"
10 #include "setupapi.h"
11 }
12 #pragma comment(lib,"hid")
13 #pragma comment(lib,"setupapi")
14 ************************************************** */
15 #ifndef __CHIDUSB_H__
16   #define __CHIDUSB_H__
17
18 #include " dbt.h "
19
20   extern " C " {
21 #include " hidsdi.h "
22 #include " setupapi.h "
23 }
24
25   #pragma comment(lib,"hid")
26   #pragma comment(lib,"setupapi")
27
28
29
30   class CHIDUSB
31 {
32   public :
33 CHIDUSB();
34 virtual ~ CHIDUSB();
35
36 BOOL Close( void );
37 BOOL Open (CWnd * pPortOwner,
38 DWORD VID,
39 DWORD PID,
40 UINT unUSBRecvBufSize,
41 UINT unRecvMsg,
42 UINT unConnectMsg
43 );
44
45 UINT Send(UCHAR * pSendBytes,UINT unSendLen);
46 UINT Recv(UCHAR * pRecvBytes);
47 void GetDevicePath(CString & str);
48
49 protected :
50
51 BOOL Ready( void ) const ; // USB是否已经打开
52 BOOL CreateThreadAndEvent( void ); // 创建线程和事件
53 static
54 DWORD RecvThread(LPVOID lpArg); // 接收线程
55
56 void RegisterHIDDevice(CWnd * pPortOwner,GUID HidGuid);
57
58 private :
59
60 CWnd * m_pOwner;
61
62 BOOL m_bInit;
63
64 HIDP_CAPS m_Capabilities;
65
66 OVERLAPPED m_ovUSBRead;
67 OVERLAPPED m_ovUSBWrite;
68
69 HANDLE m_hUSBWrite;
70 HANDLE m_hUSBRead;
71 HANDLE m_hRecvExitEvent;
72
73 UCHAR * m_szUSBRecvBuf;
74 UINT m_unUSBRecvBufSize;
75 UINT m_unRecvLength;
76
77 UINT m_unRecvMsg;
78 UINT m_unConnectMsg;
79 CString m_strDevicePath;
80
81 };
82
83
84
85 #endif

 

CHIDUSB.cpp

 

 

 

 
  
1 /* **************************************************
2 *作 者:温子祺
3 *联系方式:wenziqi@hotmail.com
4 *说 明:CHIDUSB.cpp
5 ************************************************** */
6 #include " StdAfx.h "
7 #include " CHIDUSB.h "
8 #include < assert.h > // 使用断言
9
10 CHIDUSB::CHIDUSB()
11 {
12 m_pOwner = NULL;
13 m_hUSBWrite = NULL;
14 m_hUSBWrite = NULL;
15 m_hUSBRead = NULL;
16 m_hRecvExitEvent = NULL;
17 m_unRecvLength = 0 ;
18 m_bInit = FALSE;
19 m_szUSBRecvBuf = NULL;
20 }
21
22 CHIDUSB:: ~ CHIDUSB()
23 {
24 m_pOwner = NULL;
25 m_hUSBWrite = NULL;
26 m_hUSBWrite = NULL;
27 m_hUSBRead = NULL;
28 m_hRecvExitEvent = NULL;
29 m_szUSBRecvBuf = NULL;
30 }
31
32 BOOL CHIDUSB::Close( void )
33 {
34 m_bInit = FALSE;
35
36 if (m_hUSBRead)
37 {
38 CloseHandle(m_hUSBRead);
39 m_hUSBRead = NULL;
40 }
41
42 if (m_hUSBWrite)
43 {
44 CloseHandle(m_hUSBWrite);
45 m_hUSBWrite = NULL;
46 }
47
48 if (m_ovUSBRead.hEvent)
49 {
50 CloseHandle(m_ovUSBRead.hEvent);
51 m_ovUSBRead.hEvent = NULL;
52 }
53
54 if (m_ovUSBWrite.hEvent)
55 {
56 CloseHandle(m_ovUSBWrite.hEvent);
57 m_ovUSBWrite.hEvent = NULL;
58 }
59
60 if (m_hRecvExitEvent)
61 {
62 SetEvent(m_hRecvExitEvent); // 退出线程
63 CloseHandle(m_hRecvExitEvent);
64 m_hRecvExitEvent = NULL;
65 }
66
67 if (m_pOwner)
68 {
69 m_pOwner = NULL;
70 }
71
72 if (m_szUSBRecvBuf)
73 {
74 delete []m_szUSBRecvBuf;
75 m_szUSBRecvBuf = NULL;
76 }
77
78
79 return TRUE;
80 }
81
82 BOOL CHIDUSB::Ready( void ) const
83 {
84
85 return m_bInit;
86 }
87
88 BOOL CHIDUSB::CreateThreadAndEvent( void )
89 {
90 m_ovUSBRead.Offset = 0 ;
91 m_ovUSBRead.OffsetHigh = 0 ;
92 m_ovUSBRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
93
94 if (NULL == m_ovUSBRead.hEvent)
95 {
96 return FALSE;
97 }
98 else
99 {
100 ResetEvent(m_ovUSBRead.hEvent);
101 }
102
103
104 m_ovUSBWrite.Offset = 0 ;
105 m_ovUSBWrite.OffsetHigh = 0 ;
106 m_ovUSBWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
107
108 if (NULL == m_ovUSBWrite.hEvent)
109 {
110
111 return FALSE;
112 }
113 else
114 {
115 ResetEvent(m_ovUSBWrite.hEvent);
116 }
117
118
119 m_hRecvExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* 创建接收线程退出事件 */
120
121 if (NULL == m_hRecvExitEvent)
122 {
123 return FALSE;
124 }
125
126 ResetEvent(m_hRecvExitEvent); // 设置线程没有退出
127
128 HANDLE hThread = NULL;
129 DWORD dwThreadID = 0 ;
130
131 // 创建接收线程
132 hThread = CreateThread( 0 ,
133 0 ,
134 (LPTHREAD_START_ROUTINE)RecvThread,
135 this ,
136 0 ,
137 & dwThreadID);
138
139 if (NULL == hThread)
140 {
141 return FALSE;
142 }
143
144 CloseHandle(hThread);
145 hThread = NULL;
146
147 return TRUE;
148 }
149
150 BOOL CHIDUSB::Open(CWnd * pPortOwner,
151 DWORD VID,
152 DWORD PID,
153 UINT unUSBRecvBufSize,
154 UINT unRecvMsg,
155 UINT unConnectMsg)
156 {
157 assert(NULL != pPortOwner);
158
159 m_pOwner = pPortOwner;
160
161 if (Ready())
162 {
163 Close();
164 }
165
166 if ( ! m_szUSBRecvBuf)
167 {
168 m_szUSBRecvBuf = new UCHAR[unUSBRecvBufSize];
169 m_unUSBRecvBufSize = unUSBRecvBufSize;
170 }
171
172
173 ULONG Required;
174 // 定义strUsbPath 设备路径
175 // CString strUsbPath;
176 // 定义一个GUID的结构体HidGuid来保存HID设备的接口类GUID。
177 GUID HidGuid;
178 // 定义一个DEVINFO的句柄hDevInfoSet来保存获取到的设备信息集合句柄。
179 HDEVINFO hDevInfoSet;
180 // 定义MemberIndex,表示当前搜索到第几个设备,0表示第一个设备。
181 DWORD MemberIndex;
182 // DevInfoData,用来保存设备的驱动接口信息
183 SP_DEVICE_INTERFACE_DATA DevInfoData;
184 // 定义一个BOOL变量,保存函数调用是否返回成功
185 BOOL Result;
186 // 定义一个RequiredSize的变量,用来接收需要保存详细信息的缓冲长度。
187 DWORD RequiredSize;
188 // 定义一个指向设备详细信息的结构体指针。
189 PSP_DEVICE_INTERFACE_DETAIL_DATA pDevDetailData;
190 // 定义一个用来保存打开设备的句柄。
191 HANDLE DevHandle;
192 // 定义一个HIDD_ATTRIBUTES的结构体变量,保存设备的属性。
193 HIDD_ATTRIBUTES DevAttributes;
194
195 // Request to receive messages when a device is attached or removed.
196 // Also see WM_DEVICECHANGE in BEGIN_MESSAGE_MAP(CUsbhidiocDlg, CDialog).
197 DEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface;
198
199 // 对DevInfoData结构体的cbSize初始化为结构体大小
200 DevInfoData.cbSize = sizeof (DevInfoData);
201 // 对DevAttributes结构体的Size初始化为结构体大小
202 DevAttributes.Size = sizeof (DevAttributes);
203 // 根据HidGuid来获取设备信息集合。其中Flags参数设置为
204 // DIGCF_DEVICEINTERFACE|DIGCF_PRESENT,前者表示使用的GUID为
205 // 接口类GUID,后者表示只列举正在使用的设备,因为我们这里只
206 // 查找已经连接上的设备。返回的句柄保存在hDevinfo中。注意设备
207 // 信息集合在使用完毕后,要使用函数SetupDiDestroyDeviceInfoList
208 // 销毁,不然会造成内存泄漏。
209
210 // 调用HidD_GetHidGuid函数获取HID设备的GUID,并保存在HidGuid中。
211 HidD_GetHidGuid( & HidGuid);
212
213 hDevInfoSet = SetupDiGetClassDevs( & HidGuid,
214 NULL,
215 NULL,
216 DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
217 // 然后对设备集合中每个设备进行列举,检查是否是我们要找的设备
218 // 当找到我们指定的设备,或者设备已经查找完毕时,就退出查找。
219 // 首先指向第一个设备,即将MemberIndex置为0。
220 MemberIndex = 0 ;
221
222
223 while ( 1 )
224 {
225 // 调用SetupDiEnumDeviceInterfaces在设备信息集合中获取编号为
226 // MemberIndex的设备信息。
227 Result = SetupDiEnumDeviceInterfaces(hDevInfoSet,
228 0 ,
229 & HidGuid,
230 MemberIndex,
231 & DevInfoData);
232
233 // 如果获取信息失败,则说明设备已经查找完毕,退出循环。
234 if (Result == FALSE) break ;
235
236 // 将MemberIndex指向下一个设备
237 MemberIndex ++ ;
238
239 // 如果获取信息成功,则继续获取该设备的详细信息。在获取设备
240 // 详细信息时,需要先知道保存详细信息需要多大的缓冲区,这通过
241 // 第一次调用函数SetupDiGetDeviceInterfaceDetail来获取。这时
242 // 提供缓冲区和长度都为NULL的参数,并提供一个用来保存需要多大
243 // 缓冲区的变量RequiredSize。
244 Result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
245 & DevInfoData,
246 NULL,
247 0 ,
248 & RequiredSize,
249 NULL);
250
251 // 然后,分配一个大小为RequiredSize缓冲区,用来保存设备详细信息。
252 pDevDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(RequiredSize);
253
254 if (pDevDetailData == NULL) // 如果内存不足,则直接返回。
255 {
256 TRACE( " 内存不足! " );
257 SetupDiDestroyDeviceInfoList(hDevInfoSet);
258 return FALSE;
259 }
260
261 // 并设置pDevDetailData的cbSize为结构体的大小(注意只是结构体大小,
262 // 不包括后面缓冲区)。
263 pDevDetailData -> cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
264
265 // 然后再次调用SetupDiGetDeviceInterfaceDetail函数来获取设备的
266 // 详细信息。这次调用设置使用的缓冲区以及缓冲区大小。
267 Result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
268 & DevInfoData,
269 pDevDetailData,
270 RequiredSize,
271 & Required,
272 NULL);
273
274 // 将设备路径复制出来,然后销毁刚刚申请的内存。
275 m_strDevicePath = pDevDetailData -> DevicePath;
276 free(pDevDetailData);
277
278 // 如果调用失败,则查找下一个设备。
279 if (Result == FALSE) continue ;
280
281 // 如果调用成功,则使用不带读写访问的CreateFile函数
282 // 来获取设备的属性,包括VID、PID、版本号等。
283 // 对于一些独占设备(例如USB键盘),使用读访问方式是无法打开的,
284 // 而使用不带读写访问的格式才可以打开这些设备,从而获取设备的属性。
285 DevHandle = CreateFile(m_strDevicePath,
286 0 ,
287 FILE_SHARE_READ | FILE_SHARE_WRITE,
288 (LPSECURITY_ATTRIBUTES)NULL,
289 OPEN_EXISTING,
290 0 ,
291 NULL);
292
293 // 如果打开成功,则获取设备属性。
294 if (DevHandle != INVALID_HANDLE_VALUE)
295 {
296 // 获取设备的属性并保存在DevAttributes结构体中
297 Result = HidD_GetAttributes(DevHandle,
298 & DevAttributes);
299
300 // 获取失败,查找下一个
301 if (Result == FALSE)
302 {
303 // 关闭刚刚打开的设备
304 CloseHandle(DevHandle);
305 DevHandle = NULL;
306 continue ;
307 }
308 // 如果获取成功,则将属性中的VID、PID以及设备版本号与我们需要的
309 // 进行比较,如果都一致的话,则说明它就是我们要找的设备。
310 if (DevAttributes.VendorID == VID) // 如果VID相等
311 if (DevAttributes.ProductID == PID) // 并且PID相等
312 // if(DevAttributes.VersionNumber==StUsbID.m_dwPVN) // 并且设备版本号相等
313 {
314 DevBroadcastDeviceInterface.dbcc_size = sizeof (DevBroadcastDeviceInterface);
315 DevBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
316 DevBroadcastDeviceInterface.dbcc_classguid = HidGuid;
317 // 获取设备属性结构体
318
319 PHIDP_PREPARSED_DATA PreparsedData;
320
321 HidD_GetPreparsedData(DevHandle,
322 & PreparsedData
323 );
324
325 HidP_GetCaps (PreparsedData,
326 & m_Capabilities
327 );
328 // 释放资源
329 HidD_FreePreparsedData(PreparsedData);
330
331 // 那么就是我们要找的设备,分别使用读写方式打开之,并保存其句柄
332 // 并且选择为异步访问方式。
333 // 读方式打开设备
334
335 m_hUSBRead = CreateFile(m_strDevicePath,
336 GENERIC_READ,
337 FILE_SHARE_READ | FILE_SHARE_WRITE,
338 (LPSECURITY_ATTRIBUTES)NULL,
339 OPEN_EXISTING,
340 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
341 NULL);
342
343 if (INVALID_HANDLE_VALUE == m_hUSBRead)
344 {
345 TRACE( " 读访问打开HidUsb设备失败......! " );
346 }
347 else
348 {
349 TRACE( " 读访问打开HidUsb设备成功......! " );
350
351 }
352
353 // 写方式打开设备
354 m_hUSBWrite = CreateFile(m_strDevicePath,
355 GENERIC_WRITE,
356 FILE_SHARE_READ | FILE_SHARE_WRITE,
357 (LPSECURITY_ATTRIBUTES)NULL,
358 OPEN_EXISTING,
359 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
360 NULL);
361
362 if (INVALID_HANDLE_VALUE == m_hUSBWrite)
363 {
364 TRACE( " 写访问打开HidUsb设备失败......! " );
365 }
366 else
367 {
368 TRACE( " 写访问打开HidUsb设备成功......! " );
369
370 }
371
372 if (m_hUSBRead == INVALID_HANDLE_VALUE
373 && m_hUSBWrite == INVALID_HANDLE_VALUE)
374 {
375 return FALSE;
376 }
377
378 if ( ! CreateThreadAndEvent())
379 {
380 return FALSE;
381 }
382
383 m_bInit = TRUE;
384
385 m_unRecvMsg = unRecvMsg;
386 m_unConnectMsg = unConnectMsg;
387
388 RegisterHIDDevice(pPortOwner,HidGuid);
389
390 return TRUE;
391 }
392 }
393 // 如果打开失败,则查找下一个设备
394 else continue ;
395 }
396
397
398 // 调用SetupDiDestroyDeviceInfoList函数销毁设备信息集合
399 SetupDiDestroyDeviceInfoList(hDevInfoSet);
400
401 return FALSE;
402
403 }
404 UINT CHIDUSB::Send(UCHAR * pSendBytes,UINT unSendLen)
405 {
406 if (NULL == pSendBytes || 0 == unSendLen)
407 {
408 return 0 ;
409 }
410
411 if (m_hUSBWrite == INVALID_HANDLE_VALUE \
412 || m_hUSBWrite == NULL)
413 {
414 return 0 ;
415 }
416
417 UCHAR szSendBuf[ 65 ] = { 0 };
418 DWORD dwSendBytes = 0 ;
419 INT rt = 0 ;
420
421 // HID发送报告第一个字节必须为0
422 // 所以发送总长度为0x41=65
423
424 memcpy( & szSendBuf[ 1 ],pSendBytes, 64 );
425
426 rt = WriteFile(m_hUSBWrite,
427 szSendBuf,
428 m_Capabilities.OutputReportByteLength,
429 NULL,
430 & m_ovUSBWrite);
431
432 WaitForSingleObject(m_ovUSBWrite.hEvent, 3000 );
433 ResetEvent (m_ovUSBWrite.hEvent);
434
435 GetOverlappedResult(m_hUSBWrite, & m_ovUSBWrite, & dwSendBytes,TRUE);
436
437 return (UINT)(dwSendBytes - 1 );
438 }
439
440 UINT CHIDUSB::Recv(UCHAR * pRecvBytes)
441 {
442 if (NULL == pRecvBytes || 0 == m_unRecvLength)
443 {
444 return 0 ;
445 }
446
447 if (m_hUSBRead == INVALID_HANDLE_VALUE \
448 || m_hUSBRead == NULL)
449 {
450 return 0 ;
451 }
452
453 UINT unRecvLength = m_unRecvLength;
454
455 m_unRecvLength = 0 ;
456
457 memcpy(pRecvBytes,m_szUSBRecvBuf, 64 );
458
459 return unRecvLength;
460 }
461
462 DWORD CHIDUSB::RecvThread(LPVOID lpArg)
463 {
464 assert(NULL != lpArg);
465
466 CHIDUSB * pArg = (CHIDUSB * )lpArg;
467
468 assert(NULL != pArg);
469
470 UCHAR szRecvBuf[ 65 ] = { 0 };
471 DWORD dwRecvBytes = 0 ;
472
473 while ( 1 )
474 {
475 if (WaitForSingleObject(pArg -> m_hRecvExitEvent, 0 ) == WAIT_OBJECT_0)
476 {
477 break ; // 线程退出
478 }
479
480 if (pArg -> Ready())
481 {
482 memset(pArg -> m_szUSBRecvBuf, 0 , sizeof (pArg -> m_szUSBRecvBuf));
483 memset(szRecvBuf, 0 , sizeof (szRecvBuf));
484
485 ReadFile(pArg -> m_hUSBRead,
486 szRecvBuf,
487 pArg -> m_Capabilities.InputReportByteLength,
488 NULL,
489 & pArg -> m_ovUSBRead
490 );
491
492 WaitForSingleObject(pArg -> m_ovUSBRead.hEvent,INFINITE);
493 ResetEvent(pArg -> m_ovUSBRead.hEvent);
494 // 通过GetOverlappedResult函数来获取实际读取到的字节数。
495 GetOverlappedResult(pArg -> m_hUSBRead, & pArg -> m_ovUSBRead, & dwRecvBytes,TRUE);
496
497 if (dwRecvBytes)
498 {
499 memcpy(pArg -> m_szUSBRecvBuf, & szRecvBuf[ 1 ], 64 );
500 pArg -> m_unRecvLength = (UINT)(dwRecvBytes - 1 ); // 默认返回65个字节,所以要减1
501 dwRecvBytes = 0 ;
502 // 完成这个消息才进行下个操作,因而不需要加上同步事件。
503 // 如果使用PostMessage()就需要加上同步事件
504 ::SendMessage((pArg -> m_pOwner) -> m_hWnd,
505 pArg -> m_unRecvMsg,
506 0 ,
507 0 );
508
509 }
510
511 }
512 Sleep( 1 );
513 }
514
515 Sleep( 10 );
516
517 return 0 ;
518 }
519
520 void CHIDUSB::GetDevicePath(CString & str)
521 {
522 str = m_strDevicePath;
523 }
524
525 void CHIDUSB::RegisterHIDDevice(CWnd * pPortOwner,GUID HidGuid)
526 {
527 DEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface;
528 HDEVNOTIFY DeviceNotificationHandle;
529
530 DevBroadcastDeviceInterface.dbcc_size = sizeof (DevBroadcastDeviceInterface);
531 DevBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
532 DevBroadcastDeviceInterface.dbcc_classguid = HidGuid;
533
534 DeviceNotificationHandle =
535 RegisterDeviceNotification(pPortOwner -> m_hWnd, & DevBroadcastDeviceInterface, DEVICE_NOTIFY_WINDOW_HANDLE);
536 }
537
538

 

转载于:https://www.cnblogs.com/wenziqi/archive/2010/07/01/1769213.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值