📄 serialcomm.cpp
字号:
#include "stdafx.h"
CSerialComm::CSerialComm(LPCTSTR xComName,CommPortSettings xPortSettings)
{
mPortName = xComName;
mPortSettings = xPortSettings;
mPortStatus.dwrError = 0;
mPortStatus.dwwError = 0;
mPortStatus.dwOpen = 0;//没有打开
mPortStatus.dwrecvbytesLimit = 1;
mdwStoredFlags = EV_ERR | EV_RXCHAR;
mdwCommEvent = 0;
ZeroMemory(mrecvBuf,InOutBufferSize);//初始化接收缓冲区
mrecvBytesNum = 0;
ZeroMemory(&mosRead,sizeof(OVERLAPPED));//用于重叠读/写
ZeroMemory(&mosWrite,sizeof(OVERLAPPED));
ZeroMemory(&mosStatus,sizeof(OVERLAPPED));
mPortStatus.hReadEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //手工初始无信号
mosRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //手工初始无信号
mosStatus.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //手工初始无信号
mosWrite.hEvent = CreateEvent(NULL,TRUE,TRUE,NULL); //手工初始有信号
mhCom=CreateFile(mPortName.c_str(),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);
if(mhCom == INVALID_HANDLE_VALUE)//打开端口错误
{
mPortStatus.dwwError = GetLastError( );
mPortStatus.dwrError = mPortStatus.dwwError;
}
else //打开端口正确
{
mPortStatus.dwOpen = 1;//表示串口已打开
SetupComm(mhCom,InOutBufferSize,InOutBufferSize);//设置缓冲区大小
mcommTimeOuts.ReadIntervalTimeout = MAXDWORD;
mcommTimeOuts.ReadTotalTimeoutConstant = 1200;//If no character arrives within the time specified by ReadTotalTimeoutConstant, ReadFile times out.
mcommTimeOuts.ReadTotalTimeoutMultiplier = MAXDWORD;
mcommTimeOuts.WriteTotalTimeoutConstant = 1000;
mcommTimeOuts.WriteTotalTimeoutMultiplier = 50;
SetCommTimeouts(mhCom,&mcommTimeOuts);//设置超时
FillMemory(&mDCB,sizeof(DCB),0);
GetCommState(mhCom,&mDCB);
mDCB.BaudRate = mPortSettings.BaudRate;
mDCB.ByteSize = mPortSettings.ByteSize;
mDCB.Parity = mPortSettings.Parity;
mDCB.StopBits = mPortSettings.StopBits;
SetCommState(mhCom,&mDCB);//设置串口通信参数
SetCommMask(mhCom,mdwStoredFlags);//设置事件屏蔽
}
//---------------------------------创建读线程
if(mPortStatus.dwwError == 0)
{
mbReadFlag = TRUE;//线程运行标志
mhReadThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadThread,(LPVOID)this,CREATE_SUSPENDED,&mdwReadThreadId);
ResumeThread(mhReadThread);
}
//---------------------------------Initialize the critical section one time only.
InitializeCriticalSection(&CriticalSection);
}
DWORD CSerialComm::ReadComm(BYTE* xBuffer,DWORD xLength) //从缓冲区中读入指定数量的字符
{
DWORD tmLength = 0;
EnterCriticalSection(&CriticalSection);
//----------------------------------
tmLength = min(xLength,mrecvBytesNum);
if(tmLength > 0)
{
CopyMemory(xBuffer,mrecvBuf,tmLength);
}
//----------------------------------
LeaveCriticalSection(&CriticalSection);
return tmLength;
}
BOOL CSerialComm::WriteComm(BYTE* xBuffer,DWORD xLength) //把指定数量的字符(字节)从串口中输出
{
BOOL tmRes = TRUE;
BOOL tmfState = TRUE;
DWORD tmLength = 0;
COMSTAT tmComStat;
DWORD tmErrorFlags;
mPortStatus.dwwError = 0;
//--------------------------------
tmfState = GetOverlappedResult(mhCom,&mosWrite,&tmLength,FALSE); //等待上一次操作的完成
if(!tmfState)
{
mPortStatus.dwwError = GetLastError();
if(mPortStatus.dwwError == ERROR_IO_INCOMPLETE) //上次写操作还没有完成
{
tmRes = FALSE;//不能进行该次写操作
}
return tmRes;
}
//---------------------------------
ResetEvent(mosWrite.hEvent);//重置为无信号
ClearCommError(mhCom,&tmErrorFlags,&tmComStat);//clears the device's error flag to enable next input and output (I/O) operations.
tmfState = WriteFile(mhCom,xBuffer,xLength,&tmLength,&mosWrite);
if(!tmfState) //写操作没有完成
{
mPortStatus.dwwError = GetLastError();
if( mPortStatus.dwwError == ERROR_IO_PENDING) //写操作正在进行(write is pending)
{
tmRes = TRUE;
}
else
{
tmRes = FALSE;//写操作失败
}
}
else
{
tmRes = TRUE;//write operation completed immediately
}
//---------------------------------
return tmRes;
}
CSerialComm::~CSerialComm()
{
//---------------------------------退出线程
SetCommMask(mhCom,0);//不再等待任何事件
mbReadFlag = FALSE;
WaitForSingleObject(mhReadThread,INFINITE);//等待线程结束
CloseHandle(mhReadThread);
//---------------------------------
if(mPortStatus.dwOpen == 1)
{
CloseHandle(mosRead.hEvent);
CloseHandle(mosWrite.hEvent);
CloseHandle(mosStatus.hEvent);
CloseHandle(mPortStatus.hReadEvent);
CloseHandle(mhCom);
}
//---------------------------------
DeleteCriticalSection(&CriticalSection);//Release resources used by the critical section object.
}
//==============================================================================================读过程
DWORD WINAPI ReadThread(LPVOID xpParam)
{
DWORD tmdwRes = 0;
DWORD tmdwRead;
DWORD tmError = 0;
BOOL tmbWaitingOnStatus = FALSE;
COMSTAT tmComStat;
CSerialComm* mpCSerialComm = (CSerialComm*)xpParam;
mpCSerialComm->mPortStatus.dwrError = 0;
while(mpCSerialComm->mbReadFlag) //读数据循环
{
if(!tmbWaitingOnStatus)
{
if(!WaitCommEvent(mpCSerialComm->mhCom,&(mpCSerialComm->mdwCommEvent),&(mpCSerialComm->mosStatus))) //重叠等待
{
tmError = GetLastError();
if(tmError == ERROR_IO_PENDING)//the operation is executing in the background
{
tmbWaitingOnStatus = TRUE;
}
else //error in WaitCommEvent,clear
{
mpCSerialComm->mPortStatus.dwrError = tmError;
ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
if(tmComStat.cbInQue > 0) //清理输入缓冲
{
PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);
}
::Sleep(1000);
}
}
else //WaitCommEvent returned immediately
{
tmbWaitingOnStatus = FALSE;
ReportStatusEvent(mpCSerialComm);
}
}
//------------------------------check on overlapped operation
if(tmbWaitingOnStatus)
{
tmdwRes = WaitForSingleObject(mpCSerialComm->mosStatus.hEvent,STATUS_CHECK_TIMEOUT);
switch(tmdwRes)
{
case WAIT_OBJECT_0://mosStatus.hEvent is signaled.
{
if(!GetOverlappedResult(mpCSerialComm->mhCom,&(mpCSerialComm->mosStatus),&tmdwRead,FALSE))
{
tmError = GetLastError();// For a WaitCommEvent operation, tmdwRead value is undefined.
if(tmError != ERROR_IO_INCOMPLETE) //WaitCommEvent operation failed
{
mpCSerialComm->mPortStatus.dwrError = tmError;
ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
if(tmComStat.cbInQue > 0) //清理输入缓冲
{
PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);
}
Sleep(1000);
tmbWaitingOnStatus = FALSE;//应该进行下一个WaitCommEvent
}
}
else //a new WaitCommEvent can be issued
{
tmbWaitingOnStatus = FALSE;
ReportStatusEvent(mpCSerialComm);
}
}
break;
case WAIT_TIMEOUT:
{
ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);//清理输入缓冲(完整数据传输必须在一定的时间内到达)
Sleep(1000);
tmbWaitingOnStatus = FALSE;//应该进行下一个WaitCommEvent
}
break;
default://Error in WaitForSingleObject;a problem with the mosStatus.hEvent
{
ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
if(tmComStat.cbInQue > 0) //清理输入缓冲
{
PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);
}
mpCSerialComm->mPortStatus.dwrError = GetLastError();
Sleep(1000);
tmbWaitingOnStatus = FALSE;//应该进行下一个WaitCommEvent
}
}
}
}
//---------------------------------
return tmdwRes;
}
void ReportStatusEvent(LPVOID xpParam) //辅助过程
{
DWORD tmError = 0;
COMSTAT tmComStat;
CSerialComm* mpCSerialComm = (CSerialComm*)xpParam;
if(!ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat))
{
mpCSerialComm->mPortStatus.dwrError = GetLastError();
}
else
{
if((mpCSerialComm->mdwCommEvent) & EV_RXCHAR)
{
if(tmComStat.cbInQue >= (mpCSerialComm->mPortStatus.dwrecvbytesLimit))
{
EnterCriticalSection(&(mpCSerialComm->CriticalSection));
ReadFile(mpCSerialComm->mhCom,mpCSerialComm->mrecvBuf,InOutBufferSize,&(mpCSerialComm->mrecvBytesNum),&(mpCSerialComm->mosRead));
SetEvent(mpCSerialComm->mPortStatus.hReadEvent);//置为有信号状态,在外部将其置为无信号状态
LeaveCriticalSection(&(mpCSerialComm->CriticalSection));
}
}
else
{
mpCSerialComm->mPortStatus.dwrError = EV_ERR;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -