串口与线程,事件的功能
自学BCB也有一段时间了,前段时间领导让我接手一个工程源码,看到串口通信这一块,对线程和事件的操作流程不太明白
希望大侠能帮我分析下其工作流程。感谢
程序中的注解是我个人理解,也不知道是不是正确。
多线程 串口 事件
//---------------------------------------------------------------------------
//串口线程的入口函数
DWORD WINAPI CommProc(LPVOID pParam)//关于此函数的定义有一定的要求。除函数名外,不能随便修改
{
OVERLAPPED os;
DWORD dwMask,dwTrans;
COMSTAT ComStat;
DWORD dwErrorFlags;
COMMCLASS * comm =(COMMCLASS *)pParam;//传入的参数强制转换成类的对象指针
memset(&os, 0, sizeof(OVERLAPPED));
os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (os.hEvent == NULL)
{
comm->strError="Can't Create event object !";
return (UNIT)-1;
}
SetEvent(comm->m_hPostMsgEvent);//m_hPostMsgEvent事件在打开串口连接的时候创建,用于同步线程操作
while(comm->m_bConnected)//串口未关闭,则进入循环
{
ClearCommError(comm->m_hCom, &dwErrorFlags, &ComStat);
if(ComStat.cbInQue)
{
if(comm->frmMsg != NULL)
::PostMessage(comm->frmMsg-Handle, WM_COMMNOTIFY, 1, 0);
tmpLen = comm->ReadComm(&comm->m_bufRec[comm->m_bufRecLen], min(ComStat.cbInQue, MAXZDLEN-comm->m_bufRecLen-1));
if(tmpLen == 0)
{
continue;
}
comm->m_bufRecLen += tmpLen;
comm->m_bufRec[comm->m_bufRecLen] = NULL;
WaitForSingleObject(comm->m_hPostMsgEvent,INFINITE);
if(comm->frmMsg != NULL)
{
ResetEvent(comm->m_hPostMsgEvent);
::PostMessage(comm_frmMsg->Handle, WM_COMMNOTIFY, 2, (long)comm->m_hPostMsgEvent);
}
else
setEvent(comm->mPostMsgEvent);
continue;
}
dwMask = 0;
if(!WaitCommEvent(comm->m_hCom, &dwMask, &os))
{
if(GetLastError() == ERROR_IO_PENDING)
GetOverlappendResult(comm->m_hCom, &os, &dwTrans, TRUE);
else
{
CloseHandel(os.hEvent);
return (UNIT)-1;
}
}
if((dwMask & EV_DSR) || (dwMask & EV_CTS) || (dwMask & EV_RING) || (dwMask & EV_RLSD))
{
DWORD statttt =0;
if(GetCommModemStatus(comm_m_hCom, &statttt,))
{
if(comm->frmMsg !=NULL)
{
WaitForSingleObject(comm->m_hPostMsgEvent, INFINITE);
ResetEvent(comm->m_hPostMsgEvent);
::PostMessage(comm->frmMsg->Handle, WM_COMMNOTIFY, CM_RECSTS, statttt);
}
else
SetEvent(comm->m_hPostMsgEvent);
}
}
}
CloseHandle(os.hEvent);
return 0;
}
char COMMCLASS::OpenConnection(bool bCrtThread/* = true*/)
{
m_iLastError = 0;
DWORD errNo;
//创建一个消息响应事件
if(m_hPostMsgEvent == NULL)
if ((m_hPostMsgEvent = CreateEvent(NULL,TRUE,TRUE,NULL)) ==NULL)
{
m_iLastError = 2;
return 2;
}
//异步读事件
if(m_osRead.hEvent == NULL)
if((m_osRead.hEvent =CreateEvent(NULL,TRUE,FALSE,NULL))==NULL)
{
m_iLastError = 3;
return 3;
}
//异步写事件
if(m_osWrite.hEvent == NULL)
if((m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL))==NULL)
{
m_iLastError = 4;
return 4;
}
COMMTIMEOUTS TimeOuts; //在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。
if(m_bConnected)
{
DWORD dwExitCode;
//线程正在运行
if ( m_pThread != NULL &&
GetExitCodeThread( m_pThread, &dwExitCode) &&
dwExitCode == STILL_ACTIVE)
return 1;
m_bConnected =FALSE;
SetEvent(m_hPostMsgEvent);
SetCommMask(m_hCom,0);
CloseHandle(m_pThread);
m_pThread= NULL;
CloseHandle(m_hCom);
}
//打开串口
m_hCom = CreateFile(m_sPort.c_str() ,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,NULL);
if(m_hCom==INVALID_HANDLE_VALUE)
{
errNo = GetLastError();
if(errNo == 2)
m_iLastError = 11;//COMM口可能不存在
else if(errNo == 5)
m_iLastError = 12;//COMM口可能已被其它程序占用!
else
{
m_iLastError = 13;//COMM口打开失败
m_iErrNo = errNo;
}
return m_iLastError;
}
//初始化一个指定的通信设备的通信参数
SetupComm( m_hCom,MAXJSLEN,MAXZDLEN);
//SetCommMask(m_hCom,EV_RXCHAR);//|EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_RING|EV_RLSD|EV_RXFLAG); //EV_TXEMPTY
SetCommMask(m_hCom,EV_RXCHAR|EV_CTS|EV_DSR|EV_ERR|EV_RING|EV_RLSD);//EV_ERR:CE_FRAME,CE_OVERRUN,CE_RXPARITY
//清空缓冲区
PurgeComm( m_hCom, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
//set RTS,DTR
EscapeCommFunction(m_hCom,SETRTS|SETDTR);
//设置超时
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=0;
TimeOuts.ReadTotalTimeoutConstant= 0;
TimeOuts.WriteTotalTimeoutMultiplier =5;
TimeOuts.WriteTotalTimeoutConstant = 2000;
SetCommTimeouts(m_hCom,&TimeOuts);
//配置串口参数
if(ConfigConnection())
{
m_bConnected = TRUE;
//创建一个挂起线程
m_pThread = CreateThread(NULL,0, CommProc,this,CREATE_SUSPENDED ,&threadID );
if(m_pThread==NULL)
{
CloseHandle(m_hCom);
m_hCom = INVALID_HANDLE_VALUE;
m_iLastError = 6;//创建线程失败
return 6;
}
m_bConnected = TRUE;
if(m_pThread != NULL)
ResumeThread(m_pThread); //执行线程
}
else
{
CloseHandle(m_hCom);
m_iLastError = 7; //COMM口参数设置失败
return 7;
}
ResetEvent(m_hPostMsgEvent);
DWORD statttt = 0;
//串口状态
if(GetCommModemStatus(m_hCom,&statttt))
{
if(frmMsg != NULL)
::PostMessage(frmMsg->Handle ,WM_COMMNOTIFY,1, statttt);
else
SetEvent(m_hPostMsgEvent);
}
return 1;
}