📄 comcontrol.cpp
字号:
// ComControl.cpp
#include "StdAfx.h"
#include "ComControl.h"
#include "DlgComSet.h"
UINT ComThreadProc(LPVOID para)
{
CComControl* pCom = (CComControl*)para;
DWORD dwEventMask;
OVERLAPPED eov;
memset( &eov, 0, sizeof( OVERLAPPED ) ) ;
eov.hEvent = CreateEvent( NULL, // no security attributes
FALSE, // auto reset event
FALSE, // not signaled
NULL // no name
);
HANDLE hWaits[2];
DWORD dwWait;
hWaits[0] = eov.hEvent;
hWaits[1] = pCom->m_hExit;
while(true)
{
dwEventMask = 0;
WaitCommEvent(pCom->m_hCom, &dwEventMask, &eov);
dwWait = WaitForMultipleObjects(2, hWaits, false, INFINITE);
if(dwWait == WAIT_OBJECT_0+1)
break;
//EnterCriticalSection(&pCom->m_csWmThreshold);
pCom->ResetBytes();
if(dwEventMask & EV_ERR) // 线路错误CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
{
SendMessage( pCom->m_hOwner, WM_COM, COM_ERR ,0 );
}
if(dwEventMask & EV_TXEMPTY) // 输出缓冲区空
{
SendMessage( pCom->m_hOwner, WM_COM, COM_EMPTY ,0 );
}
if( dwEventMask & EV_RXCHAR &&
// pCom->m_bCanInterrupt && //确认上一条消息已处理完
// pCom->m_nThresHold &&
pCom->m_cbInQue >= pCom->m_nThresHold // 输入缓冲区接收到一字符
)
{
pCom->m_bCanInterrupt = false;
SendMessage( pCom->m_hOwner, WM_COM,COM_THRESHOLD,0);
}
//LeaveCriticalSection(&pCom->m_csWmThreshold);
}
CloseHandle(eov.hEvent);
return true;
}
CComControl::CComControl(HWND hOwner)
{
m_hOwner = hOwner;
InitCom();
}
void CComControl::InitCom()
{
InitializeCriticalSection(&m_csWmThreshold);
memset( &m_ovRead, 0, sizeof( OVERLAPPED ) ) ;
memset( &m_ovWrite, 0, sizeof( OVERLAPPED ) ) ;
m_ovRead.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req;TRUE=人工重置;FASE=自动重置
FALSE, // initial event reset;TRUE=已通知状态;FALSE=未通知状态
NULL // no name
);
m_ovWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); // See above
m_nThresHold = 0;
m_bCanInterrupt = false;
m_hExit = CreateEvent(NULL, false, false, NULL);
m_szPortName = "COM1";
m_lBaudRate = 9600;
m_nParity = NOPARITY;
m_hCom = INVALID_HANDLE_VALUE;
m_cbInQue = 0;
m_cbOutQue = 0;
m_pThread = AfxBeginThread(ComThreadProc, (LPVOID)this,THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
}
CComControl::~CComControl()
{
m_pThread->ResumeThread();
SetEvent(m_hExit);
WaitForSingleObject(m_pThread->m_hThread, INFINITE);
m_pThread = NULL; //this ensure pCom->ClosePort work correct
ClosePort();
CloseHandle(m_ovRead.hEvent);
CloseHandle(m_ovWrite.hEvent);
CloseHandle(m_hExit);
DeleteCriticalSection(&m_csWmThreshold);
}
bool __fastcall CComControl::IsWindowsNT()
{
OSVERSIONINFO osv;
osv.dwOSVersionInfoSize = sizeof(osv);
GetVersionEx(&osv);
return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
void CComControl::ResetBytes()
{
DWORD dwErrWord;
COMSTAT comstat;
ClearCommError(m_hCom, &dwErrWord, &comstat);
m_cbInQue = comstat.cbInQue;
m_cbOutQue = comstat.cbOutQue;
}
bool CComControl::OpenPort()
{
if(m_hCom != INVALID_HANDLE_VALUE) {
ClosePort();
}
m_hCom = CreateFile( "\\\\.\\" + m_szPortName, // pointer to name of the file
GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
0, // share mode
NULL, // lpsa;pointer to security attributes
OPEN_EXISTING, // how to create
FILE_FLAG_OVERLAPPED, // file attributes //fdwAttrsAndFlags
NULL // handle to file with attributes to copy
);
if(m_hCom == INVALID_HANDLE_VALUE) {
return false;
}
DCB dcb;
memset(&dcb, 0, sizeof(dcb));
dcb.DCBlength = sizeof(dcb); // 以字节数指定当前的波特率
dcb.fBinary = true; // 必须是true
dcb.BaudRate = m_lBaudRate; // 当前的波特率
dcb.Parity = m_nParity; // 奇偶校验方法,NOPARITY / ODDPARITY / EVENPARITY / MARKPARITY
if(m_nParity != NOPARITY)
{
dcb.fParity = true; // 指定奇偶校验是否是允许的
}
dcb.ByteSize = 8; // 指定端口当前使用的数据位数
dcb.StopBits = ONESTOPBIT; // 指定端口当前使用的停止位数 ONESTOPBIT / ONE5STOPBITS / TWOSTOPBITS
dcb.fDtrControl = DTR_CONTROL_DISABLE; // DTR_CONTROL_DISABLE置DTR为OFF,DTR_CONTROL_ENABLE置DTR为ON,DTR_CONTROL_HANDSHAKE允许DTR"握手"
dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS置OFF
dcb.fAbortOnError = true; // 有错误发生时中止读、写操作
dcb.fDsrSensitivity = false; // 若为TRUE,则DSR为OFF时接收的字节被忽略
dcb.wReserved1 = 0; // 没有使用,必须为零
COMMTIMEOUTS timeouts; // 定义超时时间
timeouts.ReadIntervalTimeout = 10*9600 / m_lBaudRate + 100;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 10*9600 / m_lBaudRate;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier= 2*9600 / m_lBaudRate;
//////////////////// 张尚文CommTest的超时时间处理结果。///////////////////
// CommTimeOuts.ReadIntervalTimeout = 10*CBR_9600/FBaudRate + 100 ; //
// CommTimeOuts.ReadTotalTimeoutMultiplier = 10*CBR_9600/FBaudRate; //
// CommTimeOuts.ReadTotalTimeoutConstant = 0 ; //
// // CBR_9600 is approximately 1byte/ms. For our purposes, allow //
// // double the expected time per character for a fudge factor. //
// CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/FBaudRate; //
// CommTimeOuts.WriteTotalTimeoutConstant = 0 ; //
//////////////////////////////////////////////////////////////////////////
if( !SetCommState(m_hCom, &dcb) ||
!SetupComm(m_hCom, 2048, 2048) ||
!SetCommTimeouts(m_hCom, &timeouts) ||
!SetCommMask(m_hCom, EV_RXCHAR|EV_TXEMPTY|EV_ERR) ||
!PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR )
)
{
ClosePort();
return false;
}
m_pThread->ResumeThread();
return true;
}
void CComControl::ClosePort()
{
if(m_hCom != INVALID_HANDLE_VALUE)
{
if(m_pThread)
m_pThread->SuspendThread();
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
CloseHandle(m_hCom);
m_hCom = INVALID_HANDLE_VALUE;
}
}
void CComControl::SetParam()
{
CDlgComSet DlgComSet;
DlgComSet.m_szPort = m_szPortName;
CString br;
br.Format("%d", m_lBaudRate);
DlgComSet.m_szBaud = br;
CString jy;
switch(m_nParity)
{
case ODDPARITY:
jy = "奇校验";
break;
case EVENPARITY:
jy = "偶校验";
break;
default:
jy = "无校验";
break;
}
DlgComSet.m_szParity = jy;
if(DlgComSet.DoModal() == IDOK)
{
m_szPortName = DlgComSet.m_szPort;
m_lBaudRate = atol(DlgComSet.m_szBaud);
jy = DlgComSet.m_szParity;
if(jy == "奇校验")
m_nParity = ODDPARITY;
else if(jy == "偶校验")
m_nParity = EVENPARITY;
else
m_nParity = NOPARITY;
/* if(m_hCom != INVALID_HANDLE_VALUE)//设置串口后直接打开串口
{
ClosePort();
Sleep(10); // I don't know reason,if don't do this,OpenPort may fail
OpenPort();
}
*/ }
}
void CComControl::SetParam(const char* szPortName, long lBaudRate, int nParity)
{
m_szPortName = szPortName;
m_lBaudRate = lBaudRate;
m_nParity = nParity;
if(m_hCom != INVALID_HANDLE_VALUE)
{
ClosePort();
Sleep(10);
OpenPort();
}
}
void CComControl::SetThreshold(DWORD nThreshold)
{
//EnterCriticalSection(&m_csWmThreshold);
m_nThresHold = nThreshold;
if(!PortOpened())
return;
m_bCanInterrupt = true;
ResetBytes();
if(m_nThresHold && m_cbInQue >= m_nThresHold && m_bCanInterrupt)
{
m_bCanInterrupt = false;
PostMessage( m_hOwner, WM_COM, COM_THRESHOLD ,0 );
}
//LeaveCriticalSection(&m_csWmThreshold);
}
bool CComControl::Send(BYTE* pBuff, DWORD dwBytesSend)
{
if(!PortOpened()) return false;
BOOL wRes;
DWORD dwBytesW;
wRes = WriteFile( m_hCom,
pBuff,
dwBytesSend,
&dwBytesW,
&m_ovWrite
);
if(!wRes) //there are some data not send
{
if(GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_ovWrite.hEvent, 20*1000); //this block the calling thread
wRes = GetOverlappedResult( m_hCom, // handle to comm device
&m_ovWrite, // pointer to overlapped structure
&dwBytesW, // pointer to actual bytes count
false // wait flag
);
if(!wRes || dwBytesW != dwBytesSend)
{
ClearInOut();
return false;
}
}
else // an error occured
{
ClearInOut();
return false;
}
}
return true;
}
bool CComControl::Receive(BYTE* pBuff, DWORD dwBytesRead)
{
DWORD dwBytesReaded = 0;
return Receive(pBuff, dwBytesRead, dwBytesReaded);
}
bool CComControl::Receive(BYTE* pBuff, DWORD dwBytesRead, DWORD& dwBytesReaded)
{
dwBytesReaded = 0;
if(!PortOpened()) return false;
BOOL rRes=true;
if(m_hCom == INVALID_HANDLE_VALUE) return false;
//EnterCriticalSection(&m_csWmThreshold);
if( !ReadFile( m_hCom, // handle of file to read
pBuff, // address of buffer that receives data
dwBytesRead, // number of bytes to read
&dwBytesReaded, // address of number of bytes read
&m_ovRead // address of structure for data
)
)
{
if (GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_ovRead.hEvent, INFINITE); //this block the calling thread,if err or timeout it return
rRes = GetOverlappedResult(m_hCom, &m_ovRead, &dwBytesReaded, false);
if(!rRes || dwBytesReaded != dwBytesRead)
{ // an error occurred, i think it most was timeout also it return when line error
rRes = false;
}
else
{ // some other error occurred
rRes = true;
}
}
}
ResetBytes();
//LeaveCriticalSection(&m_csWmThreshold);
if(rRes)
return true;
else
return false;
}
void CComControl::ClearInOut()
{
if(m_hCom == INVALID_HANDLE_VALUE)
return;
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_TXCLEAR);
ResetBytes();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -