通过前两节,可以正确识别自己的USB-HID设备了,剩下最重要的就是通信了,总结如下;
读取USB-HID设备上传的数据:
由于我们并不知道下位机何时上传数据,因此,我们创建一个辅助线程,来监听USB设备,一旦由数据到来,取走数据,并告诉主程序;
一、首先定义读取异步读USB状态变量
//异步操作
OVERLAPPED m_osRead,m_osWrite;
//初始化
memset(&m_osRead,0,sizeof(OVERLAPPED)); //异步读
memset(&m_osWrite,0,sizeof(OVERLAPPED)); //异步写
二、建立辅助线程
//线程函数
UINT USBReadThreadFunction(LPVOID pParam);
//创建线程
if(usbread_pThread == NULL)
usbread_pThread = AfxBeginThread(USBReadThreadFunction,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
if(usbread_pThread == NULL)
{
CloseHandle(hidHandle);
hidHandle = INVALID_HANDLE_VALUE;
RichEditShow(_T("线程创建失败"));
m_ConnectionFlag=false;
return false;
}
else
{
usbread_pThread->ResumeThread();
}
/*******************************************************************
读报告的线程。由于使用的是异步调用,因而在调用ReadFile
函数时提供一个Overlapped的结构,该结构中含有一个事件的
句柄。平时该事件是处于无信号状态的,因而等待事件的函数
就会被挂起,从而该线程被阻塞。当数据正确返回后,事件被
触发,线程恢复运行。并检查返回的数据量以及报告ID是否正
确,从而设置界面上各开关的状态。由于该函数并不是
CUnidirectionaltesttoolingDlg类(就是该工程中主窗口类)中的成员函数,
所以无法直接调用CUnidirectionaltesttoolingDlg类中的成员函数。
在创建该线程时,通过pParam参数传递了一个this指针,将参数pParam
强制转化为CUnidirectionaltesttoolingDlg类的指针即可
访问CUnidirectionaltesttoolingDlg类中的成员函数。
*********************************************************************/
//创建工作者线程入口函数
UINT USBReadThreadFunction(LPVOID pParam)
{
CUnidirectionaltesttoolingDlg *pDlg = (CUnidirectionaltesttoolingDlg *)pParam;
while(1)
{
if(pDlg->EventObject!=NULL)
{
pDlg->USBReadProcessing(0);
}
else
{
WaitForSingleObject(m_osRead.hEvent,INFINITE);
}
}
return 0;
}
bool CUnidirectionaltesttoolingDlg::USBReadProcessing(int usb)
{
if(hidHandle==INVALID_HANDLE_VALUE)
{
return false;
}
unsigned int read_count=0;
read_count=USBRead();
if(read_count==0)
{
return false;
}
if(usb_judge_time1==1)//PC请求建立连接
{
KillTimer(WM_TIMER1);
usb_judge_time1=0;
usb_judge_write=0;
usb_councet =0;
if((usb_inBuffer[1]==0x98) && (usb_inBuffer[2]==0xAC))
{
RichEditShow(_T("PC建立连接成功"));
usb_judge_write=5;
}
return true;
}
。。。。。。
。。。。。。
}
unsigned int CUnidirectionaltesttoolingDlg::USBRead()
{
if(hidHandle ==INVALID_HANDLE_VALUE)
{
return 0;
}
ResetEvent(m_osRead.hEvent);
unsigned long BytesRead;
m_osRead.Offset = 0;
SetLastError(NO_ERROR);
ReadFile( hidHandle,
(LPVOID)usb_inBuffer,
// inCapabilities.InputReportByteLength,
65,
&BytesRead,
(LPOVERLAPPED)&m_osRead);
DWORD bResult = WaitForSingleObject(m_osRead.hEvent,INFINITE);//0:立即反悔;n:到时间返回;INFINITE:一直等待,知道对象处于通知状态
if(hidHandle ==INVALID_HANDLE_VALUE)//防止期间拔出USB设备
{
return 0;
}
if(bResult == WAIT_TIMEOUT || bResult == WAIT_ABANDONED)
{
CancelIo(&hidHandle);//取消由本线程处理的所有等待的输入输出(I/O)操作。函数不能取消由其他线程处理的I/O操作。
//如果要取消其他线程处理的I/O操作,可以使用CancelIoEx函数。
memset(usb_inBuffer,0,65);
BytesRead = 0;
}
if(bResult == WAIT_OBJECT_0)
{
//如果重叠操作未完成,等待直到操作完成
if(GetLastError() == ERROR_IO_PENDING)
{
BytesRead=GetLastError();
GetOverlappedResult(hidHandle,&m_osRead,&BytesRead,TRUE);
m_osRead.Offset = 0;
}
else
{
memset(usb_inBuffer,0,65);
BytesRead = 0;
}
}
ResetEvent(m_osRead.hEvent);
return (unsigned int)BytesRead;
}注意:在找到USB设备时候,要手动触发下
//手动触发事件,让读报告线程恢复运行。因为在这之前并没有调用
//读数据的函数,也就不会引起事件的产生,所以需要先手动触发一
//次事件,让读报告线程恢复运行。
SetEvent(m_osRead.hEvent);
写USB函数
1、创建辅助函数
UINT USBWriteThreadFunction(LPVOID pParam);
if(usbwrite_pThread == NULL)
usbwrite_pThread = AfxBeginThread(USBWriteThreadFunction,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
if(usbwrite_pThread == NULL)
{
CloseHandle(hidHandle);
hidHandle = INVALID_HANDLE_VALUE;
RichEditShow(_T("线程创建失败"));
m_ConnectionFlag=false;
return false;
}
else
{
usbwrite_pThread->ResumeThread();
}
UINT USBWriteThreadFunction(LPVOID pParam)
{
CUnidirectionaltesttoolingDlg *pDlg = (CUnidirectionaltesttoolingDlg *)pParam;
while(1)
{
if(pDlg->EventObject!=NULL)
{
pDlg->USBWriteProcessing(0);
}
}
return 0;
}
bool CUnidirectionaltesttoolingDlg::USBWriteProcessing(int usb)
{
if(hidHandle==INVALID_HANDLE_VALUE)
{
return false;
}
if(usb_judge_write==1)//PC机建立连接请求
{
usb_judge_write =0;
usb_judge_time1 =1;
usb_outBuffer[1]=0x91;
usb_outBuffer[2]=0xAC;
USBWrite();
SetTimer(WM_TIMER1,Time1,0);
return true;
}
。。。。。。
。。。。。。
}
unsigned int CUnidirectionaltesttoolingDlg::USBWrite()
{
if(hidHandle ==INVALID_HANDLE_VALUE)
{
return 0;
}
ResetEvent(m_osWrite.hEvent);
unsigned long BytesWritten;
usb_outBuffer[0]=0;
m_osWrite.Offset = 0;
SetLastError(NO_ERROR);
WriteFile( hidHandle,
(LPVOID)usb_outBuffer,
// outCapabilities.OutputReportByteLength,
65,
&BytesWritten,
(LPOVERLAPPED)&m_osWrite);
DWORD bResult=WaitForSingleObject(m_osWrite.hEvent,INFINITE);//0:立即反悔;n:到时间返回;INFINITE:一直等待,知道对象处于通知状态
//防止拔出
if(hidHandle ==INVALID_HANDLE_VALUE)
{
return 0;
}
if(bResult == WAIT_TIMEOUT || bResult == WAIT_ABANDONED)
{
CancelIo(&hidHandle);//取消本调线程处理的所有等待的输入输出(I/O)操作。函数不能取消由其他线程处理的I/O操作。
//如果要取消其他线程处理的I/O操作,可以使用CancelIoEx函数。
BytesWritten = 0;
}
if(bResult == WAIT_OBJECT_0)
{
if(GetLastError() == ERROR_IO_PENDING)
{
// BytesWritten=GetLastError();
GetOverlappedResult(hidHandle,&m_osWrite,&BytesWritten,TRUE);
m_osWrite.Offset = 0;
}
else
BytesWritten = 0;
}
ResetEvent(m_osWrite.hEvent);
return (unsigned int)BytesWritten;
}