深入浅出Win32多线程程序设计之综合实例-4

来源:互联网 发布:南京逍遥游网络怎么样 编辑:程序博客网 时间:2024/05/01 16:01
3.3.3核心函数:串口线程控制函数串口线程处理函数是整个类中最核心的部分,它主要完成两类工作:(1)利用WaitCommEvent函数对串口上发生的事件进行获取并根据事件的不同类型进行相应的处理;(2)利用WaitForMultipleObjects函数对串口相关的用户控制事件进行等待并做相应处理。 UINT CSerialPort::CommThread(LPVOID pParam){// Cast the void pointer passed to the thread back to// a pointer of CSerialPort classCSerialPort *port = (CSerialPort*)pParam;// Set the status variable in the dialog class to// TRUE to indicate the thread is running.port->m_bThreadAlive = TRUE;// Misc. variablesDWORD BytesTransfered = 0;DWORD Event = 0;DWORD CommEvent = 0;DWORD dwError = 0;COMSTAT comstat;BOOL bResult = TRUE;// Clear comm buffers at startupif (port->m_hComm)// check if the port is openedPurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);// begin forever loop. This loop will run as long as the thread is alive.for (;;){// Make a call to WaitCommEvent(). This call will return immediatly// because our port was created as an async port (FILE_FLAG_OVERLAPPED// and an m_OverlappedStructerlapped structure specified). This call will cause the// m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to// be placed in a non-signeled state if there are no bytes available to be read,// or to a signeled state if there are bytes available. If this event handle// is set to the non-signeled state, it will be set to signeled when a// character arrives at the port.// we do this for each port!bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);if (!bResult){// If WaitCommEvent() returns FALSE, process the last error to determin// the reason..switch (dwError = GetLastError()){case ERROR_IO_PENDING:{// This is a normal return value if there are no bytes// to read at the port.// Do nothing and continuebreak;}case 87:{// Under Windows NT, this value is returned for some reason.// I have not investigated why, but it is also a valid reply// Also do nothing and continue.break;}default:{// All other error codes indicate a serious error has// occured. Process this error.port->ProcessErrorMessage("WaitCommEvent()");break;}}}else{// If WaitCommEvent() returns TRUE, check to be sure there are// actually bytes in the buffer to read.//// If you are reading more than one byte at a time from the buffer// (which this program does not do) you will have the situation occur// where the first byte to arrive will cause the WaitForMultipleObjects()// function to stop waiting. The WaitForMultipleObjects() function// resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state// as it returns.//// If in the time between the reset of this event and the call to// ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again// to the signeled state. When the call to ReadFile() occurs, it will// read all of the bytes from the buffer, and the program will// loop back around to WaitCommEvent().//// At this point you will be in the situation where m_OverlappedStruct.hEvent is set,// but there are no bytes available to read. If you proceed and call// ReadFile(), it will return immediatly due to the async port setup, but// GetOverlappedResults() will not return until the next character arrives.//// It is not desirable for the GetOverlappedResults() function to be in// this state. The thread shutdown event (event 0) and the WriteFile()// event (Event2) will not work if the thread is blocked by GetOverlappedResults().//// The solution to this is to check the buffer with a call to ClearCommError().// This call will reset the event handle, and if there are no bytes to read// we can loop back through WaitCommEvent() again, then proceed.// If there are really bytes to read, do nothing and proceed.bResult = ClearCommError(port->m_hComm, &dwError, &comstat);if (comstat.cbInQue == 0)continue;} // end if bResult// Main wait function. This function will normally block the thread// until one of nine events occur that require action.Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);switch (Event){case 0:{// Shutdown event. This is event zero so it will be// the higest priority and be serviced first.port->m_bThreadAlive = FALSE;// Kill this thread. break is not needed, but makes me feel better.AfxEndThread(100);break;}case 1:// read event{GetCommMask(port->m_hComm, &CommEvent);if (CommEvent &EV_CTS)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);if (CommEvent &EV_RXFLAG)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED,(WPARAM)0, (LPARAM)port->m_nPortNr);if (CommEvent &EV_BREAK)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED,(WPARAM)0, (LPARAM)port->m_nPortNr);if (CommEvent &EV_ERR)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);if (CommEvent &EV_RING)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED,(WPARAM)0, (LPARAM)port->m_nPortNr);if (CommEvent &EV_RXCHAR)// Receive character event from port.ReceiveChar(port, comstat);break;}case 2:// write event{// Write character event from portWriteChar(port);break;}} // end switch} // close forever loopreturn 0;} 下列三个函数用于对串口线程进行启动、挂起和恢复: //// start comm watching//BOOL CSerialPort::StartMonitoring(){if (!(m_Thread = AfxBeginThread(CommThread, this)))return FALSE;TRACE("Thread started/n");return TRUE;}//// Restart the comm thread//BOOL CSerialPort::RestartMonitoring(){TRACE("Thread resumed/n");m_Thread->ResumeThread();return TRUE;}//// Suspend the comm thread//BOOL CSerialPort::StopMonitoring(){TRACE("Thread suspended/n");m_Thread->SuspendThread();return TRUE;} 3.3.4读写串口下面一组函数是用户对串口进行读写操作的接口://// Write a character.//void CSerialPort::WriteChar(CSerialPort *port){BOOL bWrite = TRUE;BOOL bResult = TRUE;DWORD BytesSent = 0;ResetEvent(port->m_hWriteEvent);// Gain ownership of the critical sectionEnterCriticalSection(&port->m_csCommunicationSync);if (bWrite){// Initailize variablesport->m_ov.Offset = 0;port->m_ov.OffsetHigh = 0;// Clear bufferPurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);bResult = WriteFile(port->m_hComm, // Handle to COMM Portport->m_szWriteBuffer, // Pointer to message buffer in calling finctionstrlen((char*)port->m_szWriteBuffer), // Length of message to send&BytesSent, // Where to store the number of bytes sent&port->m_ov); // Overlapped structure// deal with any error codesif (!bResult){DWORD dwError = GetLastError();switch (dwError){case ERROR_IO_PENDING:{// continue to GetOverlappedResults()BytesSent = 0;bWrite = FALSE;break;}default:{// all other error codesport->ProcessErrorMessage("WriteFile()");}}}else{LeaveCriticalSection(&port->m_csCommunicationSync);}} // end if(bWrite)if (!bWrite){bWrite = TRUE;bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port&port->m_ov, // Overlapped structure&BytesSent, // Stores number of bytes sentTRUE); // Wait flagLeaveCriticalSection(&port->m_csCommunicationSync);// deal with the error codeif (!bResult){port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");}} // end if (!bWrite)// Verify that the data size send equals what we tried to sendif (BytesSent != strlen((char*)port->m_szWriteBuffer)){TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d/n",BytesSent, strlen((char*)port->m_szWriteBuffer));}}//// Character received. Inform the owner//void CSerialPort::ReceiveChar(CSerialPort *port, COMSTAT comstat){BOOL bRead = TRUE;BOOL bResult = TRUE;DWORD dwError = 0;DWORD BytesRead = 0;unsigned char RXBuff;for (;;){// Gain ownership of the comm port critical section.// This process guarantees no other part of this program// is using the port object.EnterCriticalSection(&port->m_csCommunicationSync);// ClearCommError() will update the COMSTAT structure and// clear any other errors.bResult = ClearCommError(port->m_hComm, &dwError, &comstat);LeaveCriticalSection(&port->m_csCommunicationSync);// start forever loop. I use this type of loop because I// do not know at runtime how many loops this will have to// run. My solution is to start a forever loop and to// break out of it when I have processed all of the// data available. Be careful with this approach and// be sure your loop will exit.// My reasons for this are not as clear in this sample// as it is in my production code, but I have found this// solutiion to be the most efficient way to do this.if (comstat.cbInQue == 0){// break out when all bytes have been readbreak;}EnterCriticalSection(&port->m_csCommunicationSync);if (bRead){bResult = ReadFile(port->m_hComm, // Handle to COMM port&RXBuff, // RX Buffer Pointer1, // Read one byte&BytesRead, // Stores number of bytes read&port->m_ov); // pointer to the m_ov structure// deal with the error codeif (!bResult){switch (dwError = GetLastError()){case ERROR_IO_PENDING:{// asynchronous i/o is still in progress// Proceed on to GetOverlappedResults();bRead = FALSE;break;}default:{// Another error has occured. Process this error.port->ProcessErrorMessage("ReadFile()");break;}}}else{// ReadFile() returned complete. It is not necessary to call GetOverlappedResults()bRead = TRUE;}} // close if (bRead)if (!bRead){bRead = TRUE;bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port&port->m_ov, // Overlapped structure&BytesRead, // Stores number of bytes readTRUE); // Wait flag// deal with the error codeif (!bResult){port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");}} // close if (!bRead)LeaveCriticalSection(&port->m_csCommunicationSync);// notify parent that a byte was received::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM)RXBuff,(LPARAM)port->m_nPortNr);} // end forever loop}//// Write a string to the port//void CSerialPort::WriteToPort(char *string){assert(m_hComm != 0);memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));strcpy(m_szWriteBuffer, string);// set event for writeSetEvent(m_hWriteEvent);}//// Return the output buffer size//DWORD CSerialPort::GetWriteBufferSize(){return m_nWriteBufferSize;}
原创粉丝点击