經過這一段時間的摸索,自己寫了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;
}
保存起來,用來以後記錄。