📄 comm.cpp
字号:
#include "StdAfx.h"
#include <stdio.h>
#include "COMM.h"
/**********************************************************************
Function: ReadThread
Description:建立读串口线程,接收到字符时通知窗口或线程,线程结束
Input: pParam -> CommDevice 类对象
***********************************************************************/
UINT ReadThread(LPVOID pParam)
{
DWORD dwEventMask;
BOOL Reading;
HANDLEInfo *pc = (HANDLEInfo *)pParam;
PurgeComm(pc->CommInfo,PURGE_RXCLEAR);
if (!SetCommMask(pc->CommInfo, EV_RXCHAR)) return(FALSE);
Reading = TRUE;
while(pc->ThreadRun)
{
dwEventMask = 0;
if(WaitCommEvent(pc->CommInfo, &dwEventMask, NULL))
{
if ((dwEventMask & EV_RXCHAR) == EV_RXCHAR)
{
Reading = FALSE; //接收到字符
pc->ThreadRun = FALSE;
}
else
SetCommMask(pc->CommInfo, EV_RXCHAR); //未接收到字符,置中断
}
}
SetCommMask(pc->CommInfo,0);
if(!Reading)
::PostMessage((HWND)pc->HwndInfo,WM_RECVCHAR,NULL,NULL);
return(TRUE);
}
/**********************************************************************
Function: TimeOutThread
Description:时间超时监控线程,将超时通知串口事件读
Input: pParam -> CommDevice 类对象
***********************************************************************/
UINT TimeOutThread(LPVOID pParam)
{
DWORD endtime;
HANDLEInfo* tmp = (HANDLEInfo *)pParam;
endtime=GetTickCount()+(tmp->TimeOut);
while (tmp->ThreadRun)
{
if(GetTickCount()>endtime)
{
tmp->ThreadRun=FALSE;
SetCommMask( tmp->CommInfo, 0);
break;
}
}
return(TRUE);
}
/**********************************************************************
Function: CCommDevice
Description:类析构
***********************************************************************/
CCommDevice::CCommDevice()
{
memset(ComPort,0,sizeof(ComPort));
hCom = NULL;
fConnected = FALSE;
CRead_Thread = NULL;
CTimeOut = NULL;
//zrz mody TraceFlag = FALSE;
TraceFlag = TRUE;
memset(Trace_File,0,sizeof(Trace_File));
TraceMode = 0;
HandleInfo.HwndInfo = NULL;
HandleInfo.CommHwnd = NULL;
HandleInfo.CommInfo = NULL;
HandleInfo.TimeOut = 0;
HandleInfo.ThreadRun = FALSE;
}
/**********************************************************************
Function: ~CCommDevice
Description:类解析,关闭串口
***********************************************************************/
CCommDevice::~CCommDevice()
{
Close();
}
/**********************************************************************
Function: Open
Description:打开串口
Input: szPort-->串口设备逻辑名
return: Fail-->false;Success-->true
***********************************************************************/
BOOL CCommDevice::Open(char *szPort)
{
DCB dcb;
char szErrorMsg[20];
Close();
ComPort[0]=0;
fConnected = FALSE;
sprintf(szErrorMsg, "不能打开%s口", szPort);
/*
if ((HANDLE)-1 == (hCom =
CreateFile( szPort, GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL )))
{
//MessageBox(NULL, szErrorMsg, NULL, MB_OK|MB_ICONINFORMATION);
return(FALSE);
}
*/
if( (hCom=CreateFile(szPort,GENERIC_READ|
GENERIC_WRITE,0,
NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE )
{
MessageBox(NULL, szErrorMsg, NULL, MB_OK|MB_ICONINFORMATION);
return(FALSE);
}
HandleInfo.ThreadRun = FALSE;
CRead_Thread = NULL;
CTimeOut = NULL;
SetCommMask( hCom, 0 );
SetupComm( hCom, 4096, 4096 );
PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts( hCom, &CommTimeOuts);
dcb.DCBlength = sizeof( DCB );
GetCommState( hCom, &dcb );
dcb.BaudRate = CBR_9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fOutxDsrFlow = FALSE; // true or false
dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR_CONTROL_HANDSHAKE
dcb.fOutxCtsFlow = FALSE; // true or false
dcb.fRtsControl = RTS_CONTROL_ENABLE; // RTS_CONTROL_HANDSHAKE
dcb.fInX = dcb.fOutX = FALSE;
dcb.XonChar = 0x11; //ASCII_XON ;
dcb.XoffChar = 0x13; //ASCII_XOFF ;
dcb.XonLim = 100;
dcb.XoffLim = 100;
// other various settings
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
if(SetCommState( hCom, &dcb ))
{
EscapeCommFunction( hCom, SETDTR );
fConnected = TRUE;
strcpy(ComPort,szPort);
HandleInfo.CommInfo=hCom;
}
else
{
CloseHandle( hCom );
fConnected = FALSE;
//MessageBox(NULL, szErrorMsg, NULL, MB_OK | MB_ICONINFORMATION);
}
return(fConnected);
}
/**********************************************************************
Function: Open
Description:带设置参数打开串口
Input: szPort-->串口设备逻辑名
dcb -> 串口设置
return: Fail-->false;Success-->true
***********************************************************************/
BOOL CCommDevice::Open(char *szPort,DCB *pdcb)
{
DCB dcb;
char szErrorMsg[20];
Close();
ComPort[0]=0;
fConnected = FALSE;
sprintf(szErrorMsg, "不能打开%s口", szPort);
/*
if ((HANDLE)-1 == (hCom =
CreateFile( szPort, GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL )))
{
//MessageBox(NULL, szErrorMsg, NULL, MB_OK | MB_ICONINFORMATION);
return(FALSE);
}*/
if( (hCom=CreateFile(szPort,GENERIC_READ|
GENERIC_WRITE,0,
NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE )
{
MessageBox(NULL, szErrorMsg, NULL, MB_OK|MB_ICONINFORMATION);
return(FALSE);
}
HandleInfo.ThreadRun = FALSE;
CRead_Thread = NULL;
CTimeOut = NULL;
SetCommMask( hCom, 0 );
SetupComm( hCom, 4096, 4096 );
PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts( hCom, &CommTimeOuts );
dcb.DCBlength = sizeof( DCB );
GetCommState( hCom, &dcb );
dcb.BaudRate = pdcb->BaudRate;
dcb.ByteSize = pdcb->ByteSize;
dcb.Parity = pdcb->Parity;
dcb.StopBits = pdcb->StopBits;
dcb.fOutxDsrFlow = pdcb->fOutxDsrFlow; // true or false
if( dcb.fOutxDsrFlow )
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; // DTR_CONTROL_HANDSHAKE
else
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fOutxCtsFlow = pdcb->fOutxCtsFlow; // truem or false
if( dcb.fOutxCtsFlow )
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; // RTS_CONTROL_HANDSHAKE
else
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fInX = dcb.fOutX = pdcb->fInX;
dcb.XonChar = pdcb->XonChar; //ASCII_XON
dcb.XoffChar = pdcb->XoffChar; //ASCII_XOFF
dcb.XonLim = pdcb->XonLim;
dcb.XoffLim = pdcb->XoffLim;
// other various settings
dcb.fBinary = pdcb->fBinary;
dcb.fParity = pdcb->fParity;
if(SetCommState( hCom, &dcb ))
{
EscapeCommFunction( hCom, SETDTR );
fConnected = TRUE;
strcpy(ComPort,szPort);
HandleInfo.CommInfo=hCom;
}
else
{
CloseHandle( hCom );
fConnected = FALSE;
//MessageBox(NULL, szErrorMsg, NULL, MB_OK | MB_ICONINFORMATION);
}
return(fConnected);
}
/**********************************************************************
Function: SetCommHwnd
Description:配置串口相关窗口句柄
***********************************************************************/
void CCommDevice::SetCommHwnd(HWND HwndParam)
{
HandleInfo.CommHwnd=HwndParam;
}
/**********************************************************************
Function: GetCommHwnd
Description:获取串口相关窗口句柄
***********************************************************************/
HWND CCommDevice::GetCommHwnd(void)
{
return(HandleInfo.CommHwnd);
}
/**********************************************************************
Function: SetReadTimeOut
Description:串口读超时设置,为异步读服务
Input: dwTimeOuts-->串口读总超时
***********************************************************************/
void CCommDevice::SetReadTimeOut(DWORD dwTimeOuts)
{
if(dwTimeOuts == 0)
{
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
}
else
{
CommTimeOuts.ReadIntervalTimeout = 0;
CommTimeOuts.ReadTotalTimeoutMultiplier = 10;
CommTimeOuts.ReadTotalTimeoutConstant = dwTimeOuts;
}
SetCommTimeouts( hCom, &CommTimeOuts );
}
/**********************************************************************
Function: Read
Description:串口异步读(非阻塞方式从串口读固定长度字符,但不阻塞其他线程
和消息,允许重叠超作),时间由SetReadTimeOut指定。
Input: lpszBlock-->串口数据缓冲指针;
nMaxLength-->串口需读数据个数;
return: 串口实际读入数据个数
***********************************************************************/
int CCommDevice::Read(char *lpszBlock, DWORD nMaxLength)
{
COMSTAT ComStat;
DWORD dwErrorFlags,dwLength,endtime;
OVERLAPPED os_read;
MSG MyMesg;
if(!fConnected) return(0);
os_read.Offset = 0;
os_read.OffsetHigh = 0;
os_read.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ); // no name
if(os_read.hEvent == NULL) return(0);
ClearCommError( hCom, &dwErrorFlags, &ComStat);
dwLength = 0;
if(!ReadFile(hCom, lpszBlock, nMaxLength, &dwLength, &os_read))
{
dwLength=0;
if(GetLastError() == ERROR_IO_PENDING)
{
if(GetCommHwnd()!=NULL)
{
endtime=GetTickCount()+CommTimeOuts.ReadTotalTimeoutMultiplier*nMaxLength+CommTimeOuts.ReadTotalTimeoutConstant;
while(!GetOverlappedResult(hCom, &os_read, &dwLength, FALSE))
{
if(PeekMessage(&MyMesg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&MyMesg);
DispatchMessage(&MyMesg);
}
if(GetTickCount()>(endtime+100))
{
dwLength = 0;
break;
}
Sleep(20);
}
}
else
{
while(!GetOverlappedResult( hCom, &os_read, &dwLength, TRUE))
{
if(GetLastError() == ERROR_IO_INCOMPLETE)
{
os_read.Offset += dwLength;
continue;
}
else
{
dwLength = 0;
break;
}
}
}
}
else dwLength = 0;
ResetEvent(os_read.hEvent);
}
ClearCommError( hCom, &dwErrorFlags, &ComStat);
CloseHandle(os_read.hEvent);
lpszBlock[dwLength] = 0;
if(TraceFlag) CommTrace(Trace_File,lpszBlock,dwLength,TraceMode,1);
return(dwLength);
}
/**********************************************************************
Function: Write
Description:串口异步写
Input: lpszBlock-->串口数据缓冲指针;nMaxLength-->串口需写数据个数
return: Fail-->false;Success-->true
***********************************************************************/
BOOL CCommDevice::Write(char *lpszBlock, DWORD dwBytesToWrite)
{
DWORD dwBytesWritten;
DWORD dwErrorFlags;
DWORD dwBytesSent;
COMSTAT ComStat;
OVERLAPPED os_write;
dwBytesSent=0;
if(!fConnected) return(FALSE);
if(!dwBytesToWrite) return(TRUE);
if(TraceFlag) CommTrace(Trace_File,lpszBlock,dwBytesToWrite,TraceMode,0);
SetCommMask(hCom,0);
PurgeComm(hCom,PURGE_TXCLEAR | PURGE_RXCLEAR);
os_write.Offset=0;
os_write.OffsetHigh=0;
os_write.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ); // no name
if (os_write.hEvent == NULL) return(FALSE);
if(!WriteFile( hCom, lpszBlock, dwBytesToWrite, &dwBytesWritten, &os_write ))
{
if(GetLastError() == ERROR_IO_PENDING)
{
while(!GetOverlappedResult( hCom, &os_write, &dwBytesWritten, TRUE ))
{
if(GetLastError() == ERROR_IO_INCOMPLETE)
{
dwBytesSent += dwBytesWritten;
continue;
}
else
{
ClearCommError( hCom, &dwErrorFlags, &ComStat ) ;
break;
}
}
ResetEvent(os_write.hEvent);
CloseHandle(os_write.hEvent);
dwBytesSent += dwBytesWritten;
if( dwBytesSent == dwBytesToWrite ) return(TRUE);
else return(FALSE);
}
else
{
ClearCommError(hCom, &dwErrorFlags, &ComStat);
ResetEvent(os_write.hEvent);
CloseHandle(os_write.hEvent);
return(FALSE);
}
}
CloseHandle(os_write.hEvent);
return(TRUE);
}
/**********************************************************************
Function: ReadBlock
Description:串口同步读(阻塞方式读串口,直到串口缓冲区中没有数据--->
靠字符间间隔超时确定没有数据)
Input: pReadBuf-->串口数据缓冲指针
str_room-->串口数据缓冲空间大小;
ByteTime-->字节间隔最大时间(1--10000,default--300)
return: 从串口实际读入的字节个数
***********************************************************************/
int CCommDevice::ReadBlock(char *pReadBuf,unsigned int str_room,DWORD ByteTime)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -