HID_USB通信

經過這一段時間的摸索,自己寫了HID_USB模塊,

#ifndef __HIDUSB__H__20140620
#define __HIDUSB__H__20140620

#include "../include/IHidUsb.h"
#include "../include/UsbProcol.h"

extern "C"
{
#include "hidsdi.h"
#include "hid.h"
}

class CHidUsb : public IHidUsb
{
public:
	virtual HANDLE OpenDevice(DWORD dwVentorId, DWORD dwProductId, IUsbResponse *lpRes, VOID *lpContext, DWORD dwTimeOut = 5);
	virtual BOOL WriteDevice(HANDLE hUsbDevice, const CHAR *lpszBuf, INT nSize, BOOL bNeedRead = TRUE);
	virtual VOID CloseDevice(HANDLE hUsbDevice);
	virtual BOOL ReOpen(HANDLE hUsbDevice);
	virtual VOID Release();

	typedef struct tagDEVICE_CONFIG
	{
		DWORD dwVentorId;
		DWORD dwProductId;
		DWORD dwTimeOut;

	}DEVICE_CONFIG;

private:
	CHidUsb();
	virtual ~CHidUsb();

private:
	HANDLE OpenHidDevice(DWORD dwVentorId, DWORD dwProductId);
	BOOL TranslateData(const CHAR *lpszBuf, INT nSize);

public:
	static CHidUsb *CreateInstance();
	static DWORD WINAPI ThreadProc(LPVOID lpParameter);

private:
	HANDLE m_hUsbDevice;
	HANDLE m_hThread;
	DEVICE_CONFIG m_DeviceCfg;
	IUsbResponse *m_lpResponse;
	VOID *m_lpContext;
	BOOL m_bStop;
	BOOL m_bClose; 

	HANDLE m_hWriteEvent;
	HANDLE m_hReadEvent;
	HANDLE m_hWaitEvent;

	static CHidUsb *m_lpInstance;
};

#endif

.cpp


#include "HidUsb.h"
#include <string.h>
#include <assert.h>

#pragma comment(lib, "../Bin/hid.lib")
#pragma comment(lib, "setupapi.lib ")
CHidUsb *CHidUsb::m_lpInstance = NULL;

#define  HID_PACKAGE_SIZE	64

HANDLE CHidUsb::OpenDevice(DWORD dwVentorId, DWORD dwProductId, IUsbResponse *lpRes, VOID *lpContext, DWORD dwTimeOut)
{
	do
	{
		m_hUsbDevice = OpenHidDevice(dwVentorId, dwProductId);
		if (INVALID_HANDLE_VALUE == m_hUsbDevice)
		{
			break;
		}

	memset(&m_DeviceCfg, 0, sizeof(m_DeviceCfg));
	m_DeviceCfg.dwVentorId = dwVentorId;
	m_DeviceCfg.dwProductId = dwProductId;
	m_DeviceCfg.dwTimeOut = dwTimeOut;

	m_lpResponse = lpRes;
	m_lpContext = lpContext;
	m_bStop = FALSE;
	m_hReadEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
	m_hWriteEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
	m_hWaitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);

	SetEvent(m_hWaitEvent);
	// 創建接受線程
	m_hThread = ::CreateThread(0, 0, ThreadProc, this, 0, 0);
	assert(m_hThread != INVALID_HANDLE_VALUE);

	} while (0);

	return m_hUsbDevice;
}

BOOL CHidUsb::WriteDevice(HANDLE hUsbDevice, const CHAR *lpszBuf, INT nSize, BOOL bNeedRead)
{
	DWORD dwSizeWritten;
	OVERLAPPED OverLapped;
	DWORD dwErrCode;
	INT nWriteSize;
	INT nNeedWriteSize;
	CHAR szHidBuf[HID_PACKAGE_SIZE + 1];
	BOOL bRet;

	nNeedWriteSize = nSize;
	nWriteSize = 0;

	// 只能已HID包的格式發送
	memset(&OverLapped, 0, sizeof(OverLapped));
	OverLapped.hEvent = m_hWriteEvent;
	bRet = FALSE;

	while (1)
	{
		if (nSize <= 0)
		{
			bRet = TRUE;
			break;
		}

		nNeedWriteSize = HID_PACKAGE_SIZE;
		if (nNeedWriteSize > nSize)
		{
			nNeedWriteSize = nSize;
		}
		nSize -= nNeedWriteSize;

		memset(szHidBuf, 0xff, HID_PACKAGE_SIZE + 1);
		szHidBuf[0] = 0;
		memcpy(szHidBuf + 1, lpszBuf, nNeedWriteSize);
		lpszBuf += nNeedWriteSize;

		if (!::WriteFile(m_hUsbDevice, szHidBuf, HID_PACKAGE_SIZE + 1, &dwSizeWritten, &OverLapped))
		{
			dwErrCode = GetLastError();
			if (dwErrCode == ERROR_IO_PENDING)	// 延時等待
			{
				DWORD dwTimeOut;
				DWORD dwResult;

				dwTimeOut = 2 * 1000;			// 等待2s, 因爲WriteFile函數是主動發送,所以這裏人爲定義了超時
				dwResult = WaitForSingleObject(OverLapped.hEvent, dwTimeOut);
				if (dwResult == WAIT_TIMEOUT)	// 寫超時
				{
					// 關掉連接
					CloseDevice(m_hUsbDevice);
					m_hUsbDevice = INVALID_HANDLE_VALUE;
					bRet = FALSE;
					break;
				}
				else if (dwResult == WAIT_OBJECT_0)
				{
					GetOverlappedResult(m_hUsbDevice, &OverLapped, &dwSizeWritten, FALSE);
					assert(dwSizeWritten == HID_PACKAGE_SIZE + 1);
					continue;
				}
				else
				{
					assert(0);
				}
			}

			break;
		}

		assert(dwSizeWritten == HID_PACKAGE_SIZE + 1);
		nWriteSize += dwSizeWritten;

	}

	return bRet;
}

VOID CHidUsb::CloseDevice(HANDLE hUsbDevice)
{

	// 斷開設備方法,爲了同步, 可能會影響到速度
	m_bClose = TRUE;
}

VOID CHidUsb::Release()
{
	CloseDevice(m_hUsbDevice);

	assert(m_hWaitEvent != INVALID_HANDLE_VALUE);
	assert(m_hWriteEvent != INVALID_HANDLE_VALUE);
	assert(m_hReadEvent != INVALID_HANDLE_VALUE);
	assert(m_hThread != INVALID_HANDLE_VALUE);

	m_bStop = TRUE;
	SetEvent(m_hWaitEvent);
	WaitForSingleObject(m_hThread, INFINITE);
	CloseHandle(m_hWriteEvent);
	CloseHandle(m_hWaitEvent);
	CloseHandle(m_hReadEvent);
	
	m_hUsbDevice = INVALID_HANDLE_VALUE;
	m_hThread = INVALID_HANDLE_VALUE;
	m_hWriteEvent = INVALID_HANDLE_VALUE;
	m_hWaitEvent = INVALID_HANDLE_VALUE;
	m_hReadEvent = INVALID_HANDLE_VALUE;
}

CHidUsb::CHidUsb()
{
	m_hUsbDevice = INVALID_HANDLE_VALUE;
	m_hThread = INVALID_HANDLE_VALUE;
	m_hWriteEvent = INVALID_HANDLE_VALUE;
	m_hWaitEvent = INVALID_HANDLE_VALUE;
	m_hReadEvent = INVALID_HANDLE_VALUE;
	memset(&m_DeviceCfg, 0, sizeof(m_DeviceCfg));
	m_lpResponse = NULL;
	m_lpContext = NULL;
	m_bStop  = TRUE;
	m_bClose = FALSE;
}

CHidUsb::~CHidUsb()
{

}

CHidUsb *CHidUsb::CreateInstance()
{
	if (m_lpInstance == NULL)
	{
		m_lpInstance = new CHidUsb;
	}

	return m_lpInstance;
}

DWORD CHidUsb::ThreadProc(LPVOID lpParameter)
{
	CHidUsb *lpInstance = (CHidUsb *)lpParameter;
	HANDLE hDevice;
	OVERLAPPED OverLapped;
	CHAR szBuf[HID_PACKAGE_SIZE + 1];
	DWORD dwSizeReaded;
	DWORD dwResult;
	DWORD dwTimeOut;
	IUsbResponse *lpRes;
	VOID *lpContext;
	DWORD dwErrCode;
	DWORD dwTimeTickPre; // 上一次的時間計數, 這裏用來計算超時

	lpRes = lpInstance->m_lpResponse;
	lpContext = lpInstance->m_lpContext;
	memset(&OverLapped, 0, sizeof(OverLapped));
	OverLapped.hEvent = lpInstance->m_hReadEvent;
	dwTimeOut = lpInstance->m_DeviceCfg.dwTimeOut;

	dwTimeTickPre = 0;
	while (1)
	{
		WaitForSingleObject(lpInstance->m_hWaitEvent, INFINITE);
		if (lpInstance->m_bStop)
		{
			break;
		}
		hDevice = lpInstance->m_hUsbDevice;
		lpInstance->m_bClose = FALSE;

		// 開始讀數據,這裏只是簡單讀HID驅動的緩衝區
		while (1)
		{
			if (lpInstance->m_bClose) // Jimmy added it, 關掉設備
			{
				lpRes->OnError(IHidUsb::ERR_HANDLE);
				break;
			}
			if (::ReadFile(hDevice, szBuf, HID_PACKAGE_SIZE + 1, &dwSizeReaded, &OverLapped)) // 成功讀取到HID設備的數據
			{
				dwTimeTickPre = 0;
				assert(szBuf[0] == 0 && dwSizeReaded == HID_PACKAGE_SIZE + 1);
				lpRes->OnReadDevice(hDevice, &szBuf[0], HID_PACKAGE_SIZE, lpContext);
			}
			else
			{
				dwErrCode = GetLastError();
				if (dwErrCode == ERROR_IO_PENDING)	// 重疊端口即將阻塞
				{
					DWORD dwTimeWait;
					
					// 等待2 * 1000ms
					dwTimeWait = 2 * 1000;
					dwResult = WaitForSingleObject(OverLapped.hEvent, dwTimeWait);
					if (dwResult == WAIT_TIMEOUT)
					{
						// 接受超時
						if (GetTickCount() - dwTimeTickPre > dwTimeOut)
						{
							dwTimeTickPre = 0;
							if (!lpRes->OnTimeOut(lpContext)) // 連接斷開
							{
								break;
							}
						}
						
						continue;
					}
					else if (dwResult == WAIT_OBJECT_0)	// USB的數據可讀
					{
						dwTimeTickPre = 0;
						GetOverlappedResult(hDevice, &OverLapped, &dwSizeReaded, FALSE);
						assert(szBuf[0] == 0 && dwSizeReaded == HID_PACKAGE_SIZE + 1);
						lpRes->OnReadDevice(hDevice, &szBuf[0], HID_PACKAGE_SIZE, lpContext);
						
					}
					else	// 這個錯誤是不允許出現的
					{
						assert(0);
					}
				}
				else
				{
					lpRes->OnError(IHidUsb::ERR_HANDLE);
					break;
				}
			}

			::CloseHandle(hDevice);
			hDevice = INVALID_HANDLE_VALUE;
		}
	}

	return 1;
}

HANDLE CHidUsb::OpenHidDevice(DWORD dwVentorId, DWORD dwProductId)
{
	GUID								HidGuid;
	HDEVINFO							DevInfo;
	HIDD_ATTRIBUTES						DevAttributes;
	SP_DEVICE_INTERFACE_DATA			DevData;
	PSP_DEVICE_INTERFACE_DETAIL_DATA	DevDetail;
	PHIDP_PREPARSED_DATA				PreparsedData;
	HIDP_CAPS							Capabilities;
	ULONG								ulLength;
	INT									nIndex;
	USHORT								usFIFOLen;
	
 
	BOOL	bOk;
	HANDLE	hDevHandle = INVALID_HANDLE_VALUE;
	INT		nDevCount= 0;

	/* Get GUID for all System HIDs */
	HidD_GetHidGuid(&HidGuid);

	/* Get Device Information for all present devices */
	DevInfo = SetupDiGetClassDevs(&HidGuid,	NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
	DevData.cbSize = sizeof(DevData);
	DevDetail = NULL;

	nIndex = -1;
	/* Scan all Devices */
	 do 
	 {
		 nIndex ++;

		/* Device Interface Element of a Device Information set */
		 bOk = SetupDiEnumDeviceInterfaces(DevInfo, 0, &HidGuid, nIndex, &DevData);
		if (!bOk)
		{
			break;
		}

		/* Get Device Interface Details - Get Length */
		bOk = SetupDiGetDeviceInterfaceDetail(DevInfo, &DevData, NULL, 0, &ulLength, NULL);
  
		/* Allocate memory for Device Detailed Data */
		DevDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(ulLength);

		/* Set cbSize in the DevDetail structure */
		DevDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

		/* Get Device Interface Details */
		bOk = SetupDiGetDeviceInterfaceDetail(DevInfo, &DevData, DevDetail, ulLength, NULL, NULL);
		if (!bOk) 
		{
			free(DevDetail);
			DevDetail = NULL;
			continue;
		}
  
	  /* Create File for Device Read/Write */
		hDevHandle = CreateFile(DevDetail->DevicePath, 
								GENERIC_WRITE | GENERIC_READ, 
								FILE_SHARE_WRITE, 
								NULL,
								OPEN_EXISTING, 
								FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 
								NULL);

	  if (hDevHandle == INVALID_HANDLE_VALUE)
	  {
		  free(DevDetail);
		  DevDetail = NULL;
		  continue;
	  }
	  
	  DevAttributes.Size = sizeof(DevAttributes);
	  bOk = HidD_GetAttributes(hDevHandle,&DevAttributes);
	  if(!bOk) 
	  {
		  free(DevDetail);
		  CloseHandle(hDevHandle);
		  DevDetail = NULL;

		  continue;
	  }
	  if(DevAttributes.VendorID != dwVentorId || DevAttributes.ProductID != dwProductId)
	  {
		  free(DevDetail);
		  CloseHandle(hDevHandle);
		  hDevHandle = INVALID_HANDLE_VALUE;
		  DevDetail = NULL;
		  
		  continue;
	  }

	  /* Get Preparsed Data */
	  bOk = HidD_GetPreparsedData(hDevHandle, &PreparsedData);
	  if (!bOk) 
	  {
	   free(DevDetail);
	   CloseHandle(hDevHandle);
	   DevDetail = NULL;
	   continue;
	  }

	  /* Get Device's Capabilities */
	  HidP_GetCaps(PreparsedData, &Capabilities);
	  usFIFOLen = Capabilities.InputReportByteLength;
	  free(DevDetail);

	  break;

	 } while (nDevCount < 20);

	 SetupDiDestroyDeviceInfoList (DevInfo);

	return hDevHandle;
}

BOOL CHidUsb::TranslateData(const CHAR *lpszBuf, INT nSize)
{
	CHAR szTranslateBuf[1024];
	INT nTranslateIndex;
	const CHAR *lpszPos;

	nTranslateIndex = 0;
	lpszPos = lpszBuf;
	while (1)
	{
		if (nSize <= 0)
		{
			break;
		}

		lpszPos += 1; // ReportID
		memcpy(&szTranslateBuf[nTranslateIndex], lpszPos, HID_PACKAGE_SIZE);
		nTranslateIndex += HID_PACKAGE_SIZE;
		lpszPos += HID_PACKAGE_SIZE;
		nSize -= (HID_PACKAGE_SIZE + 1);

	}

	return m_lpResponse->OnReadDevice(m_hUsbDevice, szTranslateBuf, nTranslateIndex, m_lpContext);
}


BOOL CHidUsb::ReOpen(HANDLE hUsbDevice)
{
	// 重新打開設備前,一定要關掉設備
	CloseDevice(m_hUsbDevice);

	m_bClose = FALSE;
	m_hUsbDevice = OpenHidDevice(m_DeviceCfg.dwVentorId, m_DeviceCfg.dwProductId);
	if (m_hUsbDevice != INVALID_HANDLE_VALUE)
	{
		SetEvent(m_hWaitEvent);
	}

	return m_hUsbDevice != INVALID_HANDLE_VALUE;
}

保存起來,用來以後記錄。


發佈了38 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章