// USBFunc.cpp: implementation of the CUSBFunc class.
//
//
#include "stdafx.h"
#include "USBFunc.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define MAX_TRANS_LEN 64
CUSBFunc::CUSBFunc()
{
m_hDev = INVALID_HANDLE_VALUE;
m_hThread = INVALID_HANDLE_VALUE;
memset(&m_ReadOl, 0, sizeof(m_ReadOl));
m_ReadOl.hEvent = ::CreateEvent(NULL, true, false, NULL);
ASSERT(m_ReadOl.hEvent != NULL);
memset(&m_WriteOl, 0, sizeof(m_WriteOl));
m_WriteOl.hEvent = ::CreateEvent(NULL, true, false, NULL);
ASSERT(m_WriteOl.hEvent != NULL);
m_bOpen = FALSE;
}
CUSBFunc::~CUSBFunc()
{
Close();
}
void CUSBFunc::InitDev(HWND hWnd)
{
// 查找本系统中HID类的GUID标识
HidD_GetHidGuid(&m_guidHID);
// 注册设备的GUID,以便响应系统热拔插消息
// 设备的GUID, 不同的设备有不同的GUID,根据实际情况设定
DEV_BROADCAST_DEVICEINTERFACE DevInt;
memset(&DevInt,0,sizeof(DEV_BROADCAST_DEVICEINTERFACE));
DevInt.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
DevInt.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
DevInt.dbcc_classguid = m_guidHID;
HDEVNOTIFY hDevNotify = RegisterDeviceNotification(hWnd,&DevInt,DEVICE_NOTIFY_WINDOW_HANDLE);
m_hParentWnd = hWnd;
}
BOOL CUSBFunc::IsOpen()
{
return m_bOpen;
}
void CUSBFunc::Close()
{
if(m_ReadOl.hEvent != NULL)
{
CloseHandle(m_ReadOl.hEvent);
m_ReadOl.hEvent = NULL;
}
if(m_WriteOl.hEvent != NULL)
{
CloseHandle(m_WriteOl.hEvent);
m_WriteOl.hEvent = NULL;
}
if (m_hDev != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hDev);
m_hDev = INVALID_HANDLE_VALUE;
}
if (m_hThread != INVALID_HANDLE_VALUE)
{
::TerminateThread(m_hThread, 0);
CloseHandle(m_hThread);
m_hThread = INVALID_HANDLE_VALUE;
}
m_bOpen = FALSE;
}
BOOL CUSBFunc::Open()
{
HDEVINFO hDevInfo = SetupDiGetClassDevs(&m_guidHID,NULL,0,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );
if(hDevInfo == INVALID_HANDLE_VALUE)
{
return FALSE;
}
// 准备查找符合HID规范的USB设备
int iIndex = 0;
SP_DEVICE_INTERFACE_DATA InterfaceData;
InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
while (1)
{
if (!SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&m_guidHID,iIndex,
&InterfaceData))
{
// 设备已经查找完毕,退出循环
SetupDiDestroyDeviceInfoList(hDevInfo);
return FALSE;
}
iIndex++;
// 查找USB设备接口
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
DWORD strSzie=0;
SetupDiGetDeviceInterfaceDetail(hDevInfo,&InterfaceData,NULL,0,&strSzie,NULL);
// 读取设备路径名
DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(strSzie);
DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SP_DEVINFO_DATA infodata;
infodata.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiGetDeviceInterfaceDetail(hDevInfo,&InterfaceData,
DetailData,strSzie,&strSzie,NULL))
{
// 查找下一个设备
free(DetailData);
continue;
}
// 开放与设备的通信
m_hDev = CreateFile(
DetailData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
//FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
free(DetailData);
if (m_hDev != INVALID_HANDLE_VALUE)
{
// 查询设备属性
HIDD_ATTRIBUTES Attrib;
Attrib.Size = sizeof(HIDD_ATTRIBUTES);
if (!HidD_GetAttributes(m_hDev,&Attrib))
{
CloseHandle(m_hDev);
continue;
}
// 核对设备(c8051f320),过滤鼠标、键盘、游戏手柄
if (Attrib.VendorID == 0x10C4 && Attrib.ProductID == 0x8468)
{
UCHAR uBuf[256] = {0};
PHIDP_PREPARSED_DATA PreparsedData;
if (!HidD_GetPreparsedData (m_hDev, &PreparsedData))
{
CloseHandle(m_hDev);
continue;
}
HIDP_CAPS Capabilities;
NTSTATUS ntStatus;
ntStatus = HidP_GetCaps(PreparsedData, &Capabilities);
if (HIDP_STATUS_SUCCESS == ntStatus)
{
DWORD DeviceUsage = (Capabilities.UsagePage * 256) + Capabilities.Usage;
}
HidD_FreePreparsedData(PreparsedData);
if (!HidD_GetProductString(m_hDev,uBuf,256))
{
CloseHandle(m_hDev);
continue;
}
if (!HidD_GetManufacturerString(m_hDev,uBuf,MAX_TRANS_LEN))
{
CloseHandle(m_hDev);
continue;
}
//create thread begin to accept
m_hThread = ::CreateThread(NULL, NULL,
AccpetThread, this,NULL, &m_dwThreadID);
m_bOpen = TRUE;
break;
}
CloseHandle(m_hDev);
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return TRUE;
}
DWORD CUSBFunc::Read(UCHAR* pBuf,DWORD dwWait)
{
if (m_hDev == INVALID_HANDLE_VALUE)
{
return 0;
}
DWORD dwRealLen = 0;
if(!ReadFile(m_hDev,pBuf,MAX_TRANS_LEN, &dwRealLen, &m_ReadOl))
{
if(GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_ReadOl.hEvent,dwWait); // 结束异步I/O
if(!::GetOverlappedResult(m_hDev, &m_ReadOl, &dwRealLen, FALSE))
{
if(::GetLastError() != ERROR_IO_INCOMPLETE)
dwRealLen = 0;
}
}
else
{
dwRealLen = 0;
}
}
#ifdef DEBUG_VERSION
CString sLog,sTmp;
sLog = "read: ";
for (DWORD i = 0; i < 64; i++)
{
sTmp.Format("%02X-",pBuf[i]);
sLog += sTmp;
}
TRACE(sLog+"\n");
#endif
//ResetEvent(m_ReadOl.hEvent);
//::PostMessage(m_hParentWnd,WM_COM_RECEIVE,(WPARAM)(LPCSTR)pBuf,MAX_TRANS_LEN);
return dwRealLen;
}
DWORD CUSBFunc::Write(UCHAR* pBuf,DWORD dwLen)
{
if (m_hDev == INVALID_HANDLE_VALUE)
{
return -1;
}
//USB1.1全速中断模式只支持每毫秒64
if (dwLen > 63)
{
return -2;
}
DWORD dwRealLen = 0;
UCHAR uBuf[MAX_TRANS_LEN] = {0};
uBuf[0] = (UCHAR)0x02;
memcpy(uBuf+1,pBuf,dwLen);
if(!WriteFile(m_hDev,uBuf,MAX_TRANS_LEN, &dwRealLen, &m_WriteOl))
{
//TRACE("ERROR CODE = %d",GetLastError());
if(GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_WriteOl.hEvent, 3000); // 结束异步I/O
if(!::GetOverlappedResult(m_hDev, &m_WriteOl, &dwRealLen, FALSE))
{
if(::GetLastError() != ERROR_IO_INCOMPLETE)
{
dwRealLen = 0;
}
}
}
else
{
dwRealLen = 0;
}
}
#ifdef DEBUG_VERSION
CString sLog,sTmp;
sLog = "send: ";
for (DWORD i = 0; i < 64; i++)
{
sTmp.Format("%02X-",uBuf[i]);
sLog += sTmp;
}
TRACE(sLog+"\n");
#endif
/*
// 把发送的数据发给主窗口,调试时用
if ( dwRealLen == MAX_TRANS_LEN)
{
SetEvent(m_eAccept);
#ifdef DEBUG_VERSION
::SendMessage(m_hParentWnd,WM_COM_SEND,(WPARAM)(LPCSTR)pBuf,MAX_TRANS_LEN);
#endif
}
//ResetEvent(m_WriteOl.hEvent);
//::PostMessage(m_hParentWnd,WM_COM_SEND,(WPARAM)(LPCSTR)pBuf,MAX_TRANS_LEN);
*/ return dwRealLen;
}
DWORD WINAPI CUSBFunc::AccpetThread(PVOID pParam)
{
CUSBFunc *pFunc = (CUSBFunc *)pParam;
UCHAR uBuf[MAX_TRANS_LEN] = {0};
DWORD dwLen;
while (1)
{
if(WaitForSingleObject(pFunc->m_eAccept, INFINITE) == WAIT_OBJECT_0)
{
dwLen = pFunc->Read(uBuf,MAX_TRANS_LEN);
if (dwLen == MAX_TRANS_LEN)
{
// 把收到的数据发给主窗口
::SendMessage(pFunc->m_hParentWnd,WM_COM_RECEIVE,(WPARAM)(LPCSTR)uBuf,MAX_TRANS_LEN);
// ResetEvent(pFunc->m_eAccept);
}
}
}
return 0;
}