BioUsb-程序执行流程分析

1void CMainFrame::OnDeviceConnect() 连接设备
//定时器作用:每隔一段读缓存(从设备端点读取数据)
//每隔一段时间(10ms)执行mycallback()回调函数,以实现连续采集。
::timeSetEvent (10,0,mycallback,(DWORD)this,TIME_PERIODIC);  
2、执行mycallback回调函数

void WINAPI mycallback(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { CMainFrame * pMainFrame = (CMainFrame*)AfxGetMainWnd(); if(pMainFrame->hdev != INVALID_HANDLE_VALUE) { if(pMainFrame->dwCurStep == CURSTEP_NOTHING) { if((pMainFrame->pBioScan->Execute_ReadFile( pMainFrame->m_hWnd,//this-> pMainFrame->hdev, 1000, pMainFrame->ReadBuff, REQ_NUM, &(pMainFrame->dwBytesReturned)) == NO_ERROR)) { pMainFrame->dwCurStep = CURSTEP_READ; } } } }

3、执行Execute_ReadFile()函数

DWORD CBioUSBAPI::Execute_ReadFile ( HWND hWnd, HANDLE hDevice, DWORD dwTimeOut, PBYTE pInBuffer, DWORD dwInSize, LPDWORD lpBytesReturned ) { •••••• //置为激发状态(有信号状态) SetEvent(hEvent_Read); ••••••• }

4、待hEvent_Read置为有信号状态后,ThreadExecute_Read(PVOID pContext)waitForSingleObject(```)后执行,开始将设备端点数据读取至计算机中。

DWORD WINAPI ThreadExecute_Read(PVOID pContext) { CBioUSBAPI* pUSBAPI = (CBioUSBAPI *)pContext; HANDLE hEvent_Waiter; hEvent_Waiter = CreateEvent( NULL, TRUE, FALSE, NULL); //创建手动重置事件 while(TRUE) { // Wait for Execute of Read //等待hEvent_Read变为激发态(手动重置对象) WaitForSingleObject(pUSBAPI->hEvent_Read, INFINITE); //手动重置为非激发状态 ResetEvent(pUSBAPI->hEvent_Read); ````````

WaitForSingleObject()函数介绍详见 hj的多线程程序设计P93

引用:事实上,win32中大部分以HANDLE表示的对象都能够作为WaitForSingleObject()的等待目标。视你所拥有的对象不同,操作系统等待的事情也不太一样。形式上来说,系统等待着这一对象“被激发”。

Ps: ThreadExecute_Read是线程函数,在CBioUSBAPI类的构造函数中被CreateThread启动。

 

Api函数

IRP主要功能代码

说明

CreateFile

IRP_MJ_CREATE

打开设备

ReadFile

IRP_MJ_READ

从设备获取数据

WriteFile

IRP_MJ_WRITE

向设备发送数据

CloseHandle

IRP_MJ_CLOSE

关闭设备

DeviceIoControl

IRP_MJ_DEVICE_CONTROL

控制操作

 

 

 

 

 

 

 

usb设备进行通信之前,首先需要得到usb设备的句柄。通过获取设备GUID、获取设备信息集、获取设备路径名可查找到设备并得到所要打开设备的路径名。然后通过API函数CreateFile来打开设备,当成功打开后,CreateFile函数会返回一个其他API函数可用来与设备交换数据的句柄。打开设备之后,应用程序就可以使用ReadFileWriteFile函数和设备进行数据交换了。当读写usb设备结束可以断开设备时候,就可以调用CloseHandle函数关闭设备。

4.1 CreateFile

在以下函数OpenDeviceInterface中被调用

HANDLE CBioUSBAPI::OpenDeviceInterface(PCHAR pDeviceInterfaceSymbolicName) { HANDLE hReturnHandle = CreateFile( pDeviceInterfaceSymbolicName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); return hReturnHandle; } OpenDeviceInterface()在void CMainFrame::OnDeviceConnect()中被调用 void CMainFrame::OnDeviceConnect() { // TODO: Add your command handler code here // TODO: Add your command handler code here if(hdev != INVALID_HANDLE_VALUE) return; int IdIndex = m_wndTransBar.m_DeviceName.GetCurSel(); if(IdIndex >= 0) { m_wndTransBar.m_DeviceName.GetLBText(IdIndex,m_CurrentInterfaceSymbolicName); hdev = pBioScan->OpenDeviceInterface(m_CurrentInterfaceSymbolicName); if(hdev != INVALID_HANDLE_VALUE) { dwCurStep = CURSTEP_NOTHING; m_Link = TRUE; timeKillEvent(mr); mr = ::timeSetEvent (10,0,mycallback,(DWORD)this,TIME_PERIODIC); } else { MessageBox("Get device handle failed!"); } } }

4.2 ReadFile

在以下<FONT style="FONT-SIZE: 10.5pt" face=""">ThreadExecute_Read函数中被调用

DWORD WINAPI ThreadExecute_Read(PVOID pContext) { CBioUSBAPI* pUSBAPI = (CBioUSBAPI *)pContext; OVERLAPPED olRead; BOOLEAN bResult; DWORD TEMP; HANDLE hEvent_Waiter; hEvent_Waiter = CreateEvent( NULL, TRUE, FALSE, NULL); //创建手动重置事件 if( hEvent_Waiter==NULL) { return -1; } memset(&olRead, 0, sizeof(OVERLAPPED)); olRead.Offset = 0; olRead.OffsetHigh = 0; olRead.hEvent = hEvent_Waiter; while(TRUE) { // Wait for Execute of Read //等待hEvent_Read变为激发态(手动重置对象) WaitForSingleObject(pUSBAPI->hEvent_Read, INFINITE); //手动重置为非激发状态 ResetEvent(pUSBAPI->hEvent_Read); if(pUSBAPI->dwCoreStatus == BIOUSB_DESTROY) { break; } if((pUSBAPI->stRead.hDevice == INVALID_HANDLE_VALUE) || (pUSBAPI->stRead.hDevice == NULL)) continue; if(!ReadFile(pUSBAPI->stRead.hDevice, pUSBAPI->stRead.pInBuffer, pUSBAPI->stRead.dwInSize, pUSBAPI->stRead.lpBytesReturned, &olRead)) { TEMP = GetLastError(); if(ERROR_IO_PENDING != GetLastError()) { ::EnterCriticalSection(&M_CS); *(pUSBAPI->stRead.lpBytesReturned) = -1;//0; // InterlockedExchange((long *)pUSBAPI->stRead.lpBytesReturned, -1); ::LeaveCriticalSection(&M_CS); } else { // 等待ReadFile操作结束信号:hEvent_Waiter if(WaitForSingleObject(hEvent_Waiter, pUSBAPI->stRead.dwTimeOut) == WAIT_TIMEOUT) { // 在dwTimeOut时间后,hEvent_Waiter仍无信号,则取消IO操作 CancelIo(pUSBAPI->stRead.hDevice); SetEvent(hEvent_Waiter); } // 获取数据,此时hEvent_Waiter信号已设置 bResult = GetOverlappedResult(pUSBAPI->stRead.hDevice, &olRead, pUSBAPI->stRead.lpBytesReturned, FALSE);// FALSE:立即返回,TRUE:阻塞,等待olRead中的事件 if(!bResult) { *(pUSBAPI->stRead.lpBytesReturned) = -2; } } } SendMessage(pUSBAPI->stRead.hTargetWnd, MSG_READ_COMPLETION, 0, (LPARAM)&pUSBAPI->stRead); ResetEvent(hEvent_Waiter); //复位事件 } memset(&pUSBAPI->stRead, 0, sizeof(STRUCT_IO)); if(hEvent_Waiter != NULL) { CloseHandle(hEvent_Waiter); hEvent_Waiter = NULL; } if(pUSBAPI->hEvent_Read != NULL) { CloseHandle(pUSBAPI->hEvent_Read); pUSBAPI->hEvent_Read = NULL; } return 0; }

ReadFile

The ReadFile function reads data from a file, starting at the position indicated by the file pointer. After the read operation has been completed, the file pointer is adjusted by the number of bytes actually read, unless the file handle is created with the overlapped attribute. If the file handle is created for overlapped input and output (I/O), the application must adjust the position of the file pointer after the read operation.

BOOL ReadFile(
  HANDLE hFile,                // handle of file to read
  LPVOID lpBuffer,             // pointer to buffer that receives data
  DWORD nNumberOfBytesToRead,  // number of bytes to read
  LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read
  LPOVERLAPPED lpOverlapped    // pointer to structure for data
);

 

hFile

Handle to the file to be read. The file handle must have been created with GENERIC_READ access to the file.

lpBuffer

Pointer to the buffer that receives the data read from the file.

程序中:

ReadFile(pUSBAPI->stRead.hDevice,

                                    pUSBAPI->stRead.pInBuffer,

                                    pUSBAPI->stRead.dwInSize,

                                    pUSBAPI->stRead.lpBytesReturned,

                                    &olRead))

pUSBAPI定义:

CBioUSBAPI* pUSBAPI = (CBioUSBAPI *)pContext;

是一个指向CBioUSBAPI类的指针。

 

stRead是类CBioUSBAPI的成员变量,

class CBioUSBAPI 

{···

STRUCT_IO stRead;     //类型为结构体类型(即STRUCT_IO

····

}

 

STRUCT_IO定义:

typedef struct _STRUCT_IO

{

       HWND hTargetWnd;

       HANDLE hDevice;

       DWORD dwIoControlCode;

       PBYTE pInBuffer;

       DWORD dwInSize;

       PBYTE pOutBuffer;

       DWORD dwOutSize;

       LPDWORD lpBytesReturned;

       DWORD   dwTimeOut;

}STRUCT_IO,*PSTRUCT_IO;

 

 

 

SendMessage(pUSBAPI->stRead.hTargetWnd,

                                   MSG_READ_COMPLETION,

                                   0,

                                   (LPARAM)&pUSBAPI->stRead);

作用:读取端点数据后,发消息MSG_READ_COMPLETION通知窗口过程函数。

 

stRead作为SendMessage()函数的第四个参数被传送给消息处理函数。

5、待采集线程函数ThreadExecute_Read(PVOID pContext)通过SendMessage(····)函数发送“读完成”消息后,WindowProc(····)被调用。其作用主要是对采集到保存在缓冲区的数据pUSBAPI->stRead.pInBuffer进行处理。LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class if((!m_Link) && (mr)) { timeKillEvent(mr); mr = NULL; } CString str; // TODO: Add your specialized code here and/or call the base class if((message == MSG_READ_COMPLETION) || (message == MSG_IOCONTROL_COMPLETION)) { PSTRUCT_IO pIO = (PSTRUCT_IO)lParam; if(pIO == NULL) { MessageBox("Return: Write/Read file failed!"); int i = 0; } else { if(dwCurStep == CURSTEP_READ) { DWORD dwTime = 0; DWORD dwCurNum = *(pIO->lpBytesReturned); if(!(dwCurNum & 0x80000000) && dwCurNum)// REQ_NUM) { dwCurNum /= EP_PACKET_SIZE; dwLength += dwCurNum; CScanViewerView *pView = (CScanViewerView *)GetActiveView(); CScanViewerDoc * pDoc = pView->GetDocument(); pDoc->AddFrames(&(pIO->pInBuffer[0]),dwCurNum); dwTime = pIO->pInBuffer[3]; dwTime *= 256; dwTime += pIO->pInBuffer[2]; } CString strInd; strInd.Format("%d",dwLength); m_wndStatusBar.SetPaneText(3,strInd); if(dwTime) { strInd.Format("%d",dwTime); m_wndStatusBar.SetPaneText(5,strInd); } memset(pIO, 0, sizeof(STRUCT_IO)); dwCurStep = CURSTEP_NOTHING; } if(dwCurStep == CURSTEP_IN) { memset(pIO, 0, sizeof(STRUCT_IO)); dwCurStep = CURSTEP_NOTHING; } else if(dwCurStep == CURSTEP_READ_DESC_DEVICE) { } else if(dwCurStep == CURSTEP_READ_DESC_STRING_1) { } else if(dwCurStep == CURSTEP_READ_DESC_STRING_2) { } else if(dwCurStep == CURSTEP_READ_DESC_STRING_3) { } else { dwCurStep = CURSTEP_NOTHING; } } } return CFrameWnd::WindowProc(message, wParam, lParam); }

虚函数WindowProc()定义在类CMainFrame中:

class CMainFrame : public CFrameWnd { // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMainFrame) public: virtual BOOL PreCreateWindow(CREATESTRUCT& cs); virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo); protected: virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); //}}AFX_VIRTUAL // Implementation public: virtual ~CMainFrame(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif public: HANDLE hdev; CBioUSBAPI * pBioScan; void EnumDeviceInterfaces(); void CloseDevice(); DWORD dwCurStep; long lSysTick; protected: // control bar embedded members CStatusBar m_wndStatusBar; CTrueColorToolBar m_wndToolBar; CTransDlgBar m_wndTransBar; CReBar m_wndReBar; private: MMRESULT mr; public: DWORD dwBytesReturned; TCHAR m_CurrentInterfaceSymbolicName[MAX_PATH]; DWORD dwReadLength; BYTE ReadBuff[REQ_NUM]; HANDLE hEvent_ReadNext; protected: // control bar embedded members BOOLEAN m_Online; public: BOOLEAN m_Link; BOOLEAN m_FileOpen; DWORD dwLength; }; pDoc->AddFrames(&(pIO->pInBuffer[0]),dwCurNum)将调用如下函数: void CScanViewerDoc::AddFrames(PBYTE pData,int wNums) { SetModifiedFlag(TRUE); SetPathName("Bioscan.scv*"); for( int i = 0;i<wNums;i++) { CDataFrame * pDataFrame = new CDataFrame(); pDataFrame->AddData(pData + i * EP_PACKET_SIZE); m_ObArray.Add(pDataFrame); } } pDataFrame->AddData(pData + i * EP_PACKET_SIZE);调用 void CDataFrame::AddData(PBYTE pData)函数 void CDataFrame::AddData(PBYTE pData) { // char bDotOrder[16] = {16,32,30,46,28,44,26,42,24,40,22,38,20,36,18,34}; if(!pData) return; int i; for (i=0;i<EP_PACKET_SIZE;i++) { m_bData[i] = pData[i]; } }

 

你可能感兴趣的:(BioUsb-程序执行流程分析)