//
//  The CommThread Function.
//
UINT CSerialPort::CommThread(LPVOID pParam)
{
	// Cast the void pointer passed to the thread back to
	// a pointer of CSerialPort class
	CSerialPort *port = (CSerialPort*)pParam;
	
	// Set the status variable in the dialog class to
	// TRUE to indicate the thread is running.
	port->m_bThreadAlive = TRUE;	
		
	// Misc. variables
	DWORD BytesTransfered = 0; 
	DWORD Event = 0;
	DWORD CommEvent = 0;
	DWORD dwError = 0;
	static COMSTAT comstat;
	BOOL  bResult = TRUE;
		
	// Clear comm buffers at startup
	if (port->m_hComm)		// check if the port is opened
		PurgeComm(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 continue
					break;
				}
			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 port
				WriteChar(port);
				break;
			}

		} // end switch

	} // close forever loop

	return 0;
}
예제 #2
0
//
//  The CommThread Function.
///线程函数
///监视线程的大致流程:
///检查串口-->进入循环{WaitCommEvent(不阻塞询问)询问事件-->如果有事件来到-->到相应处理(关闭\读\写)}
//
DWORD WINAPI CSerialPort::CommThread(LPVOID pParam)
{
    // Cast the void pointer passed to the thread back to
    // a pointer of CSerialPort class
    CSerialPort *port = (CSerialPort*)pParam;

    // Set the status variable in the dialog class to
    // TRUE to indicate the thread is running.
    ///TRUE表示线程正在运行
    port->m_bThreadAlive = TRUE;

    // Misc. variables
    DWORD BytesTransfered = 0;
    DWORD Event = 0;
    DWORD CommEvent = 0;
    DWORD dwError = 0;
    COMSTAT comstat;
    BOOL  bResult = TRUE;

    // Clear comm buffers at startup
    ///开始时清除串口缓冲
    if (port->m_hComm)		// check if the port is opened
        PurgeComm(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!

        /*
        WaitCommEvent函数第3个参数1pOverlapped可以是一个OVERLAPPED结构的变量指针
        ,也可以是NULL,当用NULL时,表示该函数是同步的,否则表示该函数是异步的。
        调用WaitCommEvent时,如果异步操作不能立即完成,会立即返回FALSE,系统在
        WaitCommEvent返回前将OVERLAPPED结构成员hEvent设为无信号状态,等到产生通信
        事件时,系统将其置有信号
        */

        bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);///表示该函数是异步的

        if (!bResult)
        {
            // If WaitCommEvent() returns FALSE, process the last error to determin
            // the reason..
            ///如果WaitCommEvent返回Error为FALSE,则查询错误信息
            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 continue
                break;
            }
            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	///WaitCommEvent()能正确返回
        {
            // 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.
        ///等待3个事件:关断/读/写,有一个事件发生就返回
        Event = WaitForMultipleObjects(3, ///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.
            ///关断事件,关闭串口
            CloseHandle(port->m_hComm);
            port->m_hComm=NULL;
            port->m_bThreadAlive = FALSE;

            // Kill this thread.  break is not needed, but makes me feel better.
            //AfxEndThread(100);
            ::ExitThread(100);

            break;
        }
        case 1:	// read event 将定义的各种消息发送出去
        {
            GetCommMask(port->m_hComm, &CommEvent);
            if (CommEvent & EV_RXCHAR) //接收到字符,并置于输入缓冲区中
                ReceiveChar(port);

            if (CommEvent & EV_CTS) //CTS信号状态发生变化
                ::SendMessage(port->m_pOwner, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
            if (CommEvent & EV_RXFLAG) //接收到事件字符,并置于输入缓冲区中
                ::SendMessage(port->m_pOwner, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
            if (CommEvent & EV_BREAK)  //输入中发生中断
                ::SendMessage(port->m_pOwner, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
            if (CommEvent & EV_ERR) //发生线路状态错误,线路状态错误包括CE_FRAME,CE_OVERRUN和CE_RXPARITY
                ::SendMessage(port->m_pOwner, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
            if (CommEvent & EV_RING) //检测到振铃指示
                ::SendMessage(port->m_pOwner, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

            break;
        }
        case 2: // write event 发送数据
        {
            // Write character event from port
            WriteChar(port);
            break;
        }
        default:
        {
            AfxMessageBox("接收有问题!");
            break;
        }

        } // end switch

    } // close forever loop

    return 0;
}
예제 #3
0
uint8_t NormalUart::ReceiveByte()
{
	uint32_t error;
	return ReceiveChar(&mH, &error);
}