16,471
社区成员
发帖
与我相关
我的任务
分享
UINT CSerialPort::CommThread(LPVOID pParam)
{
CSerialPort *port = (CSerialPort*)pParam;
port->m_bThreadAlive = TRUE;
DWORD BytesTransfered = 0;
DWORD MultipleEvent = 0;
DWORD dwError = 0;
COMSTAT comstat;
memset(&comstat, 0 , sizeof(COMSTAT));
BOOL bResult = TRUE;
DWORD couts = 0;
// 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 (;;)
{
ResetEvent(port->m_overlapped.hEvent);
//成功返回非0值,否则返回0
//如果异步操作不能马上完成,那么该函数会返回一个FALSE,同时GetLastError函数可以截获错误码ERROR_IO_PENDING(#define ERROR_IO_PENDING 997),表示操作转到后台运行。在WaitCommEvent函数返回之前,系统将OVERLAPPED结构中的hEven句柄设置为无信号状态;当WaitCommEvent函数所等待的任何一个Event发生后,系统将OVERLAPPED结构中的hEven句柄设置为有信号状态,同时将所发生事件赋给lpEvtMask。
DWORD ComEvent = 0;
couts++;
bResult = WaitCommEvent(port->m_hComm, &ComEvent, &port->m_overlapped);
//调用失败
if (!bResult)
{
dwError = GetLastError();
switch (dwError)
{
case ERROR_IO_PENDING:
{
GetOverlappedResult(port->m_hComm,&port->m_overlapped,&ComEvent,true);
break;
}
case 87:
{
break;
}
default:
{
port->ProcessErrorMessage(_T("WaitCommEvent()"));
break;
}
}
}
else
{
bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
if (comstat.cbInQue == 0)
continue;
}
DWORD ThreadID = GetCurrentThreadId();//获取当前线程ID
TRACE("%s:Com Thread %04x 运行第 %d 次~!\n",_GetTime(),ThreadID,couts);
MultipleEvent = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
TRACE("%s:WaitForMultipleObjects 返回值为:%d~!\n",_GetTime(),MultipleEvent);
switch (MultipleEvent)
{
//结束线程
case 0:
{
port->m_bThreadAlive = FALSE;
::PostMessage(port->m_pOwner->m_hWnd,MY_COMM_KILLPORTTHREAD,(WPARAM)0,(LPARAM)0);
TRACE("%s:Com Thread %04x is ended by Event\n",_GetTime(),ThreadID);
AfxEndThread(100);
break;
}
case 1:
{
DWORD CommEvent = 0;
GetCommMask(port->m_hComm, &CommEvent);
if (CommEvent & EV_RXCHAR)
{
// Receive character event from port.
TRACE("%s:接收数据处理,GetCommMask:%d,GetWaitCommEvent: %d ~!\n",
_GetTime(),
CommEvent,
ComEvent);
LONG Thread_Prio = GetThreadPriority(port->m_Thread->m_hThread);
if (Thread_Prio != THREAD_PRIORITY_ERROR_RETURN)
{
SetThreadPriority(port->m_Thread->m_hThread,THREAD_PRIORITY_HIGHEST);
}
port->ReceiveChar(port);
SetThreadPriority(port->m_Thread->m_hThread,Thread_Prio);
}
else
{
TRACE("%s:异常结束,GetCommMask:%d,GetWaitCommEvent: %d ~!\n",
_GetTime(),
CommEvent,
ComEvent);
}
break;
}
case 2:
{
CWinThread* m_WriteThread;
if (!(m_WriteThread = AfxBeginThread(WriteCharThread, port)))
{
TRACE("%s:WriteCharThread 启动失败,原因:%s ~!\n",
_GetTime(),
_GetErrorCodeCause(GetLastError()));
break;
}
ResetEvent(port->m_hWriteEvent);
TRACE("%s:WriteThread %04x started\n",_GetTime(),m_WriteThread->m_nThreadID);
break;
}
}
}
return 111;
}
BOOL CSerialPort::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message)
UINT portnr, // portnumber (1..4)
UINT baud, // baudrate
TCHAR parity, // parity
UINT databits, // databits
UINT stopbits, // stopbits
DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc
UINT writebuffersize) // size to the writebuffer
{
//assert(portnr > 0 && portnr < 5);
assert(pPortOwner != NULL);
// if the thread is alive: Kill
//KillPortThread();
if (m_bThreadAlive)
{
do
{
if (SetEvent(m_hShutdownEvent))
{
TRACE("%s:ShutdownEvent ComThread by InitPort!\n",_GetTime());
}
}
while (m_bThreadAlive);
TRACE("%s:Thread ended int InitPort!\n",_GetTime());
}
// create events
if (m_overlapped.hEvent != NULL)
ResetEvent(m_overlapped.hEvent);
m_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hWriteEvent != NULL)
ResetEvent(m_hWriteEvent);
m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hShutdownEvent != NULL)
ResetEvent(m_hShutdownEvent);
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// initialize the event objects
m_hEventArray[0] = m_hShutdownEvent; // 串口关闭事件,自己控制触发
m_hEventArray[1] = m_overlapped.hEvent; // 串口接收到数据事件,由串口驱动触发
m_hEventArray[2] = m_hWriteEvent; // 串口写数据事件,自己控制触发
// initialize critical section
InitializeCriticalSection(&m_csCommunicationSync);//临界区初始化
// set buffersize for writing and save the owner
//m_pOwner = dynamic_cast<CMainFrame*>(pPortOwner);
m_pOwner = pPortOwner;
m_nPortNr = portnr;
m_nWriteBufferSize = writebuffersize;
m_dwCommEvents = dwCommEvents;
BOOL bResult = FALSE;
TCHAR* szPort = new TCHAR[50];
TCHAR* szBaud = new TCHAR[50];
// now it critical!
EnterCriticalSection(&m_csCommunicationSync);
// if the port is already opened: close it
if (m_hComm != NULL)
{
CloseHandle(m_hComm);
m_hComm = NULL;
}
// prepare port strings
wsprintf(szPort, _T("COM%d"), portnr);
//sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
wsprintf(szBaud, _T("baud=%d parity=%c data=%d stop=%d"), baud, parity, databits, stopbits);
// get a handle to the port
m_hComm = CreateFile(szPort, // communication port string (COMX) //modify by leo
GENERIC_READ|GENERIC_WRITE, // read/write types
0, // comm devices must be opened with exclusive access
NULL, // no security attributes
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,// Async I/O
0); // template must be 0 for comm devices
if (m_hComm == INVALID_HANDLE_VALUE)
{
//DWORD nErrer = GetLastError();
TRACE("%s:CreateFile Com%d Error ,%s~\n",_GetTime(),m_nPortNr,_GetErrorCodeCause(GetLastError()));
// port not found
delete [] szPort;
delete [] szBaud;
return FALSE;
}
// set the timeout values
m_CommTimeouts.ReadIntervalTimeout = -1;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
m_CommTimeouts.WriteTotalTimeoutMultiplier = 0;
m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
SetupComm(m_hComm,4096,2048);
// configure
if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
{
//if (SetCommMask(m_hComm, dwCommEvents))EV_RXCHAR
if (SetCommMask(m_hComm, EV_RXCHAR))
{
if (GetCommState(m_hComm, &m_dcb))
{
m_dcb.EofChar = 89;
m_dcb.ErrorChar = 88;
m_dcb.EvtChar = 89;
//m_dcb.EvtChar = 30;
m_dcb.XonChar = 89;
m_dcb.XoffChar =89;
m_dcb.fRtsControl = RTS_CONTROL_DISABLE;
m_dcb.fDtrControl = DTR_CONTROL_DISABLE;
m_dcb.fDsrSensitivity = FALSE;
m_dcb.XonLim = 2048;
m_dcb.XoffLim = 512;
if (BuildCommDCB(szBaud, &m_dcb))
{
if (SetCommState(m_hComm, &m_dcb))
; // normal operation... continue
else
ProcessErrorMessage(_T("SetCommState()"));
}
else
ProcessErrorMessage(_T("BuildCommDCB()"));
}
else
ProcessErrorMessage(_T("GetCommState()"));
}
else
ProcessErrorMessage(_T("SetCommMask()"));
}
else
ProcessErrorMessage(_T("SetCommTimeouts()"));
delete [] szPort;
delete [] szBaud;
// flush the port
//PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
// release critical section
LeaveCriticalSection(&m_csCommunicationSync);
TRACE("%s:Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", _GetTime(),portnr);
return TRUE;
}