一、USB HID 设备枚举操作
本文需求是通过USB HID的pid,vid,pvn(bcdDevice:用于标识USB当前产品的固件版本号)去寻找HID设备,然后进行数据传输操作。我也忘记当时数据是不是正常的了,反正下位机是有问题的后面改回来,客户上位机通信是ok,只是这个程序后续未验证了,但实现方式是这样的,区别也就是下面writefile的数据第一个字节的问题,给自己留个bug也行
在Win下面通过SetupDi系列函数进行枚举USB设备
BOOL Enum(USHORT m_Pid, USHORT m_Vid, USHORT m_Pvn, char* str, int* len)
DWORD DeviceNum = 0;
GUID hidGuid;
::HidD_GetHidGuid((LPGUID)&hidGuid);
HDEVINFO hDevInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
if (hDevInfoList != NULL)
{
SP_DEVICE_INTERFACE_DATA deviceInfoData;
ZeroMemory(&deviceInfoData, sizeof(deviceInfoData));
deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
SetLastError(NO_ERROR);
while (1)
{
int ret = GetLastError();
if (ret == ERROR_NO_MORE_ITEMS)
{
break;
}
ZeroMemory(&deviceInfoData, sizeof(deviceInfoData));
deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiEnumDeviceInterfaces(hDevInfoList, 0, &hidGuid, DeviceNum, &deviceInfoData))
{
PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
ULONG predictedLength, requiredLength;
predictedLength = requiredLength = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfoList,
&deviceInfoData,
NULL,
0,
&requiredLength,
NULL);
predictedLength = requiredLength;
functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(predictedLength);
functionClassDeviceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SP_DEVINFO_DATA did = { sizeof(SP_DEVINFO_DATA) };
if (SetupDiGetDeviceInterfaceDetail(hDevInfoList,
&deviceInfoData,
functionClassDeviceData,
predictedLength,
&requiredLength,
&did))
{
TCHAR fname[256];
if (!SetupDiGetDeviceRegistryProperty(hDevInfoList, &did, SPDRP_FRIENDLYNAME, NULL, (PBYTE)fname, sizeof(fname), NULL))
{
if (!SetupDiGetDeviceRegistryProperty(hDevInfoList, &did, SPDRP_DEVICEDESC, NULL, (PBYTE)fname, sizeof(fname), NULL))
{
strncpy_s(fname, 256, (char*)functionClassDeviceData->DevicePath, 256);
}
}
HANDLE UdiskDevice = CreateFile(functionClassDeviceData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
HIDD_ATTRIBUTES Attributes;
ZeroMemory(&Attributes, sizeof(Attributes));
Attributes.Size = sizeof(HIDD_ATTRIBUTES);
if (!HidD_GetAttributes(UdiskDevice, &Attributes))
{
CloseHandle(UdiskDevice);
DeviceNum++;
continue;
}
if (Attributes.ProductID == m_Pid && Attributes.VendorID == m_Vid
&& Attributes.VersionNumber == m_Pvn)
{
CString m_linkname = functionClassDeviceData->DevicePath;
memcpy(str, m_linkname.GetBuffer(), m_linkname.GetLength());
*len = m_linkname.GetLength();
free(functionClassDeviceData);
SetupDiDestroyDeviceInfoList(hDevInfoList);
return TRUE;
}
free(functionClassDeviceData);
CloseHandle(UdiskDevice);
UdiskDevice = INVALID_HANDLE_VALUE;
}
DeviceNum++;
}
}
}
SetupDiDestroyDeviceInfoList(hDevInfoList);
return FALSE;
}
二、USB HID写操作
void CCoreUSBHIDCommToolDlg::OnBnClickedBtnSend()
{
CString Cstr;
int Len;
UINT16 OutLength = 0;
UINT8 OutData[4096] = { 0 };
UINT8 InputData[1024] = { 0 };
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
CString DevicePath = m_USBPath;
UpdateData(TRUE);
Cstr = m_SendInfo;
Cstr.Remove(' ');
Len = Cstr.GetLength();
memcpy(InputData, Cstr.GetBuffer(), Len);
if ((Len == 0) || (Len % 2 != 0))
{
AfxMessageBox("Input Data Error!");
return;
}
if (AsciiToHex(InputData, Len, OutData, &OutLength) == FALSE)
{
AfxMessageBox("Input Data Error!");
return;
}
unsigned long NumberOfBytesWriten = 0;
if (hWriteCom == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Comm Fail...");
return;
}
OVERLAPPED Overlapped;
Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
Overlapped.Offset = 0;
Overlapped.OffsetHigh = 0;
SetLastError(NO_ERROR);
int WriteTimeout = 100;
int status = 1;
BOOL bRet = WriteFile(hWriteCom, OutData, WriteLen, &NumberOfBytesWriten, &Overlapped);
if (bRet)
{
status = 0;
}
if (status != 0)
{
DWORD CommLastErrCode = GetLastError();
CloseHandle(hWriteCom);
hWriteCom = INVALID_HANDLE_VALUE;
CString strDate;
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("Cannot Write Data..." + strDate + "\r\n");
return;
}
AfxBeginThread(UsbRunReadInfo, this);
}
三、USB HID读操作
UINT CCoreUSBHIDCommToolDlg::UsbRunReadInfo(void* pParam)
{
CCoreUSBHIDCommToolDlg* pData = (CCoreUSBHIDCommToolDlg*)pParam;
CString DevicePath = pData->m_USBPath;
BOOL result1;
unsigned long numBytesReturned;
int Imglen = 0;
CString str = NULL;
clock_t start, end, final = 0;
pData->SetDlgItemText(IDC_EDIT_Recv, "");
if (pData->hReadCom == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Comm Fail...");
return 1;
}
CFile cf;
FILE* fp;
if (!(fp = fopen("", "wb")))
{
return 0;
}
if (!cf.Open(_T(""), CFile::modeCreate | CFile::modeWrite))
{
AfxMessageBox(_T(""));
return 0;
}
OVERLAPPED Overlapped;
DWORD Flag;
Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
Overlapped.Offset = 0;
Overlapped.OffsetHigh = 0;
int status = 1;
int cusumlen = 0;
int OffsetAddr = 0;
byte inbuffer[4096] = { 0 };
clock_t dwStart = clock();
clock_t dwEnd;
UINT8* Startptr = RecvBuffer;
while (ReadFile(pData->hReadCom, Startptr, pData->ReadLen, &numBytesReturned, &Overlapped))
{
memcpy(&RecvBufferNoID[OffsetAddr], &Startptr[1], (numBytesReturned - 1));
*Startptr = *(Startptr + (numBytesReturned - 1));
OffsetAddr += (numBytesReturned - 1);
cusumlen += numBytesReturned;
if (OffsetAddr >= sumlen)
{
break;
}
dwEnd = clock();
if (dwEnd - dwStart > 5000)
{
break;
}
}
dwEnd = clock();
if (OffsetAddr != sumlen)
{
CString strDate;
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)pData->GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("Read Data Timeout..." + strDate + "\r\n");
CloseHandle(pData->hReadCom);
pData->hReadCom = INVALID_HANDLE_VALUE;
fclose(fp);
cf.Close();
return 0;
}
int length = 0;
int i = 0;
for (i = 0; i < sumlen; i++)
{
CString Tmp;
Tmp.Format("%02X", RecvBufferNoID[i]);
str += Tmp;
if ((i - 1) % 53 == 0 && i != 0)
{
str += "\r\n";
}
}
if ((i - 1) % 53 != 0)
{
str += "\r\n";
}
fwrite(RecvBufferNoID, sizeof(unsigned char), sumlen, fp);
fclose(fp);
CString ss;
ss.Format("时间为%d ms", dwEnd - dwStart);
str += ss;
((CEdit*)(pData->GetDlgItem(IDC_EDIT_Recv)))->SetWindowText(str);
((CEdit*)(pData->GetDlgItem(IDC_EDIT_Recv)))->SetSel(str.GetLength(), str.GetLength());
((CEdit*)(pData->GetDlgItem(IDC_EDIT_Recv)))->ReplaceSel("\r\n");
int len = str.GetLength();
cf.Write(str.GetBuffer(len), len);
cf.Close();
FILE* fpbmp;
fpbmp = fopen("", "wb");
if (fpbmp == NULL)
{
fclose(fpbmp);
return FALSE;
}
*((int*)&bmpDummy[18]) = width;
*((int*)&bmpDummy[22]) = High;
fwrite(bmpDummy, 1078, sizeof(char), fpbmp);
fwrite(RecvBufferNoID, width * High, sizeof(unsigned char), fpbmp);
fclose(fpbmp);
return 0;
}
四、当时封装的其他函数
BOOL AsciiToHex(UINT8* _pInData, UINT16 _nInLength, UINT8* _pOutData, UINT16* _nOutLength)
{
UINT16 i, j, nLen;
UINT8 TmpData;
for (i = 0; i < _nInLength; i++)
{
if ((_pInData[i] >= '0') && (_pInData[i] <= '9'))
TmpData = _pInData[i] - '0';
else if ((_pInData[i] >= 'A') && (_pInData[i] <= 'F'))
TmpData = _pInData[i] - 0x37;
else if ((_pInData[i] >= 'a') && (_pInData[i] <= 'f'))
TmpData = _pInData[i] - 0x57;
else
return FALSE;
_pInData[i] = TmpData;
}
for (nLen = 0, j = 0; j < i; j += 2)
_pOutData[nLen++] = (_pInData[j] << 4) | _pInData[j + 1];
*_nOutLength = nLen;
return TRUE;
}
void CCoreUSBHIDCommToolDlg::OnBnClickedBtnOpen()
{
CString str, Tstr, strDate;
USHORT m_Pid, m_Vid, m_Pvn;
GetDlgItemText(IDC_EDIT_PID, str);
if (str.IsEmpty())
{
AfxMessageBox("PID 输入为空!!!");
return;
}
m_Pid = strtoull(str, NULL, 16);
GetDlgItemText(IDC_EDIT_VID, str);
if (str.IsEmpty())
{
AfxMessageBox("VID 输入为空!!!");
return;
}
m_Vid = strtoull(str, NULL, 16);
GetDlgItemText(IDC_EDIT_PVN, str);
if (str.IsEmpty())
{
AfxMessageBox("PVN 输入为空!!!");
return;
}
m_Pvn = strtoull(str, NULL, 16);
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("正在打开设备,请等待" + strDate + "\r\n");
char charstr[128] = { 0 };
int len = 0;
BOOL ret = Enum(m_Pid, m_Vid, m_Pvn, charstr, &len);
if (ret == FALSE)
{
GetLocalTime(&st);
memset(m_USBPath, 0, sizeof(char) * 128);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("打开设备失败未识别到设备" + strDate + "\r\n");
return;
}
memcpy(m_USBPath, charstr, len);
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
hWriteCom = CreateFile(
m_USBPath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING, 0,
NULL);
if (hWriteCom == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Comm Fail...");
return ;
}
if (!HidD_GetPreparsedData(hWriteCom, &PreparsedData))
{
CloseHandle(hWriteCom);
CString strDate;
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("Cannot get the Preparsed Data..." + strDate + "\r\n");
return ;
}
if (!HidP_GetCaps(PreparsedData, &Capabilities))
{
CloseHandle(hWriteCom);
CString strDate;
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("Cannot get the Cap Data..." + strDate + "\r\n");
return ;
}
WriteLen = Capabilities.OutputReportByteLength;
hReadCom = CreateFile(
m_USBPath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING, 0,
NULL);
if (hReadCom == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Comm Fail...");
CloseHandle(hWriteCom);
hWriteCom = INVALID_HANDLE_VALUE;
return;
}
if (!HidD_GetPreparsedData(hReadCom, &PreparsedData))
{
CloseHandle(hWriteCom);
CloseHandle(hReadCom);
hWriteCom = INVALID_HANDLE_VALUE;
hReadCom = INVALID_HANDLE_VALUE;
CString strDate;
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("Cannot get the Preparsed Data..." + strDate + "\r\n");
return;
}
if (!HidP_GetCaps(PreparsedData, &Capabilities))
{
CloseHandle(hWriteCom);
CloseHandle(hReadCom);
hWriteCom = INVALID_HANDLE_VALUE;
hReadCom = INVALID_HANDLE_VALUE;
CString strDate;
SYSTEMTIME st;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("Cannot get the Cap Data..." + strDate + "\r\n");
return;
}
ReadLen = Capabilities.OutputReportByteLength;
GetLocalTime(&st);
strDate.Format("%02d-%02d-%02d", st.wHour, st.wMinute, st.wSecond);
((CEdit*)GetDlgItem(IDC_EDIT_Recv))->ReplaceSel("打开设备成功"+ strDate + "\r\n");
SaveCfg();
((CButton*)GetDlgItem(IDC_BTN_Close))->EnableWindow(TRUE);
((CButton*)GetDlgItem(IDC_BTN_Open))->EnableWindow(FALSE);
((CButton*)GetDlgItem(IDC_BTN_Send))->EnableWindow(TRUE);
}``