📄 serialobject.cpp
字号:
// SerialObject.cpp: implementation of the CSerialPort class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SerialObject.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSerialPort::CSerialPort():
m_hOwnerWnd(NULL),
m_nPortNr(1),
m_lpszWriteBuffer(NULL),
m_dwWriteBufferSize(0),
m_dwCommEvent(0),
m_bThreadAlive(FALSE),
m_pThread(NULL),
//m_csCommunicationSync;
m_hComm(INVALID_HANDLE_VALUE),
m_hShutdownEvent(NULL),
m_hWriteEvent(NULL),
//m_hEventArray[3];
//m_ov;
//m_CommTimeouts;
//m_strRec;
m_nToSend(0)
{
memset(&m_ov, sizeof(OVERLAPPED), '\0');
memset(&m_dcb, sizeof(DCB), 0);
m_ov.hEvent = NULL;
m_ov.Offset = 0;
m_ov.OffsetHigh = 0;
}
CSerialPort::~CSerialPort()
{
if (m_pThread != NULL)
{
TerminateMonitoring();
}
if (m_lpszWriteBuffer != NULL)
{
delete[] m_lpszWriteBuffer;
}
if (m_hComm != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hComm);
::DeleteCriticalSection(&m_csCommunicationSync);
}
if (m_hShutdownEvent != NULL)
{
::CloseHandle(m_hShutdownEvent);
}
if (m_hWriteEvent != NULL)
{
::CloseHandle(m_hWriteEvent);
}
if (m_ov.hEvent != NULL)
{
::CloseHandle(m_ov.hEvent);
}
}
BOOL CSerialPort::InitPort(HWND hOverWnd, UINT portnr/* = 1*/, UINT baud/* = 9600*/,
char parity/* = 'N'*/, UINT databits/* = 8*/, UINT stopbits/* = 1*/,
DWORD dwCommEvent/* = EV_RXCHAR | EV_CTS*/, UINT nWriteBufferSize/* = 512*/)
{
ASSERT(hOverWnd != NULL);
ASSERT(portnr > 0 && portnr < 5);
//如果有本端口已经有监控线程了,先终止它
if (m_pThread != NULL)
{
TerminateMonitoring();
}
//创建或复位
if (m_ov.hEvent != NULL)
{
ResetEvent(m_ov.hEvent);
}
else
{
m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
//创建或复位
if (m_hWriteEvent != NULL)
{
ResetEvent(m_ov.hEvent);
}
else
{
m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
//创建或复位
if (m_hShutdownEvent != NULL)
{
ResetEvent(m_ov.hEvent);
}
else
{
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
//用于WaitForMultipleObject
m_hEventArray[0] = m_hShutdownEvent; //shutdown 在最WaitForMultipleObject的前面
m_hEventArray[1] = m_ov.hEvent;
m_hEventArray[2] = m_hWriteEvent;
//初始化临界对象, 在析构时用DeleteCriticalSection释放
InitializeCriticalSection(&m_csCommunicationSync);
m_hOwnerWnd = hOverWnd;
m_nPortNr = portnr;
m_dwCommEvent = dwCommEvent;
//初始化写缓冲区
if (m_lpszWriteBuffer != NULL)
{
delete[] m_lpszWriteBuffer;
}
m_lpszWriteBuffer = new BYTE[nWriteBufferSize];
m_dwWriteBufferSize = nWriteBufferSize;
//打开串口
EnterCriticalSection(&m_csCommunicationSync);
if (m_hComm != NULL)
{
::CloseHandle(m_hComm);
m_hComm = NULL;
}
CString strCom;
strCom.Format("COM%d", portnr);
m_hComm = ::CreateFile(strCom, //lpFileName
GENERIC_READ | GENERIC_WRITE, //dwDesiredAccess
0, //dwShareMode, 因为不能共享,必须为0
NULL, //lpSecurityAttributes, 为NULL时分配缺省的安全属性
OPEN_EXISTING, //dwCreationDisposition, 这里为直接打开已经存在的端口
FILE_FLAG_OVERLAPPED, //dwFlagsAndAttributes, 对于口串口硬件,唯一意义是,设置异步访问与否
NULL //hTemplateFile, 串口没有模板文件,必须设为NULL
);
if (m_hComm == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
TRACE("打开串行端口失败:%ld\n", dwError);
return FALSE;
}
//
m_CommTimeouts.ReadIntervalTimeout = 1000L;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000L;
m_CommTimeouts.ReadTotalTimeoutConstant = 1000L;
m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000L;
m_CommTimeouts.WriteTotalTimeoutConstant = 1000L;
//设置端口
if (!::SetCommTimeouts(m_hComm, &m_CommTimeouts))
{
::PurgeComm(m_hComm,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
LeaveCriticalSection(&m_csCommunicationSync);
ProcessErrorMessage("");
return FALSE;
}
if (!::SetCommMask(m_hComm, dwCommEvent))
{
::PurgeComm(m_hComm,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
LeaveCriticalSection(&m_csCommunicationSync);
ProcessErrorMessage("");
return FALSE;
}
if (!::GetCommState(m_hComm, &m_dcb))
{
::PurgeComm(m_hComm,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
LeaveCriticalSection(&m_csCommunicationSync);
ProcessErrorMessage("");
return FALSE;
}
//m_dcb.fRtsControl = RTS_CONTROL_ENABLE;
char szBaud[50];
sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
if (!::BuildCommDCB(szBaud, &m_dcb))
{
::PurgeComm(m_hComm,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
LeaveCriticalSection(&m_csCommunicationSync);
ProcessErrorMessage("");
return FALSE;
}
LeaveCriticalSection(&m_csCommunicationSync);
return TRUE;
}
void CSerialPort::ProcessErrorMessage(LPCTSTR ErrorText) const
{
AfxMessageBox(ErrorText);
}
UINT CSerialPort::CommThread(LPVOID pParam)
{
CSerialPort *port = (CSerialPort *)pParam;
port->m_bThreadAlive = TRUE;
//保证端口是可用的
ASSERT(port->m_hComm != INVALID_HANDLE_VALUE);
DWORD bytesTransfered = 0;
DWORD dwEvtMask = 0;
DWORD dwEventIndex = 0;
DWORD dwError = 0;
COMSTAT comstat;
BOOL bResult = TRUE;
//清除
PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |
PURGE_RXABORT | PURGE_TXABORT);
while(1)
{
//
bResult = ::WaitCommEvent(port->m_hComm, &dwEvtMask, &port->m_ov);
if (!bResult)
{
dwError = GetLastError();
switch(dwError)
{
case ERROR_IO_PENDING:
break;
case 87:
break;
default:
{
port->ProcessErrorMessage("");
TRACE("---------\n");
::ClearCommError(port->m_hComm, &dwError, &comstat);
break;
}
}
}
else
{
bResult = ::ClearCommError(port->m_hComm, &dwError, &comstat);
if (comstat.cbInQue == 0)
{
continue;
}
}
//
dwEventIndex = ::WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
switch(dwEventIndex)
{
case 0: //m_hShutdownEvent
{
port->m_bThreadAlive = FALSE;
AfxEndThread(100);
break;
}
break;
case 1://串口事件
{
GetCommMask(port->m_hComm, &dwEvtMask);
if (dwEvtMask & EV_CTS)
::SendMessage(port->m_hOwnerWnd, WM_COM_CTS_DETECTED,
(WPARAM)0, (LPARAM)port->m_nPortNr);
if (dwEvtMask & EV_RXFLAG)
::SendMessage(port->m_hOwnerWnd, WM_COM_RXFLAG_DETECTED,
(WPARAM)0, (LPARAM)port->m_nPortNr);
if (dwEvtMask & EV_BREAK)
::SendMessage(port->m_hOwnerWnd, WM_COM_BREAK_DETECTED,
(WPARAM)0, (LPARAM)port->m_nPortNr);
if (dwEvtMask & EV_ERR)
::SendMessage(port->m_hOwnerWnd, WM_COM_ERR_DETECTED,
(WPARAM)0, (LPARAM)port->m_nPortNr);
if (dwEvtMask & EV_RING)
::SendMessage(port->m_hOwnerWnd, WM_COM_RING_DETECTED,
(WPARAM)0, (LPARAM)port->m_nPortNr);
if (dwEvtMask & EV_RXCHAR)
{
ReceiveChar(port, comstat);
}
}
break;
case 2://写
{
WriteChar(port);
}
break;
default:
break;
}
}//end while(1)
return 0L;
}
void CSerialPort::ReceiveChar(CSerialPort *port, COMSTAT comstat)
{
BOOL bRead = TRUE;
BOOL bResult = TRUE;
DWORD dwError = 0;
DWORD bytesRead = 0;
unsigned char RXBuffer = 0;
int nCounter = 0;
while(1) //此处用while, 等测试后 去掉
{
nCounter++;
EnterCriticalSection(&port->m_csCommunicationSync);
bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
LeaveCriticalSection(&port->m_csCommunicationSync);
//while的出口
if (comstat.cbInQue == 0)
{
break;
}
EnterCriticalSection(&port->m_csCommunicationSync);
bResult = ::ReadFile(port->m_hComm,
&RXBuffer,
1,
&bytesRead,
&port->m_ov);
if (!bResult)
{
dwError = GetLastError();
switch(dwError)
{
case ERROR_IO_PENDING:
{
bRead = FALSE;
break;
}
break;
default:
{
bRead = TRUE; //出错了,不用在等待读取了
port->ProcessErrorMessage("");
}
break;
}
}
else
{
bRead = TRUE;
}
//在这里等待,直到读取
if (!bRead)
{
bRead = TRUE;
bResult = GetOverlappedResult(port->m_hComm,
&port->m_ov,
&bytesRead,
TRUE);
if (!bResult)
{
port->ProcessErrorMessage("");
}
}//end if (!bRead)
LeaveCriticalSection(&port->m_csCommunicationSync);
::SendMessage(port->m_hOwnerWnd, WM_COM_RXCHAR_DETECTED,
(WPARAM)RXBuffer, (LPARAM)port->m_nPortNr);
}//end while(1)
}
void CSerialPort::WriteChar(CSerialPort *port)
{
BOOL bWrite = TRUE;
BOOL bResult = TRUE;
DWORD bytesSend = 0;
ResetEvent(port->m_hWriteEvent);
EnterCriticalSection(&port->m_csCommunicationSync);
port->m_ov.Offset = 0;
port->m_ov.OffsetHigh = 0;
PurgeComm(port->m_hComm,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
bResult = WriteFile(port->m_hComm,
port->m_lpszWriteBuffer,
port->m_nToSend,
&bytesSend,
&port->m_ov);
if (!bResult)
{
DWORD dwError = GetLastError();
switch(dwError)
{
case ERROR_IO_PENDING:
{
bytesSend =0;
bWrite = FALSE;
}
break;
default:
{
bytesSend = 0;
bWrite = TRUE; //已经出错,不用等待"写操作"完成了
//port->ProcessErrorMessage("");
TRACE("==================\n");
}
break;
}
}
else
{
LeaveCriticalSection(&port->m_csCommunicationSync);
}
//等待写操作,直到完成
if (!bWrite)
{
bWrite = TRUE;
bResult = GetOverlappedResult(port->m_hComm,
&port->m_ov,
&bytesSend,
TRUE);
LeaveCriticalSection(&port->m_csCommunicationSync);
if (!bResult)
{
port->ProcessErrorMessage("");
}
}
}
void CSerialPort::WriteToPort(const BYTE *lpszWriteBuffer, int nLength)
{
ASSERT(m_lpszWriteBuffer != NULL);
ASSERT(nLength > 0);
if (m_hComm == INVALID_HANDLE_VALUE)
{
AfxMessageBox("");
return;
}
memset(m_lpszWriteBuffer, 0, m_dwWriteBufferSize);
memcpy(m_lpszWriteBuffer, lpszWriteBuffer, nLength);
m_nToSend = nLength;
SetEvent(m_hWriteEvent);
}
void CSerialPort::WriteToPort(CString &strWrite)
{
int nLength = strWrite.GetLength();
memset(m_lpszWriteBuffer, 0, m_dwWriteBufferSize);
memcpy(m_lpszWriteBuffer, strWrite.GetBuffer(nLength), nLength);
m_nToSend = nLength;
SetEvent(m_hWriteEvent);
}
inline DCB CSerialPort::GetDCB() const
{
return m_dcb;
}
inline DWORD CSerialPort::GetWriteBufferSize() const
{
return m_dwWriteBufferSize;
}
inline DWORD CSerialPort::GetCommEvent() const
{
return m_dwCommEvent;
}
BOOL CSerialPort::StartMonitoring()
{
if (m_pThread != NULL)
{
AfxMessageBox("已经起动了监视线程!");
return FALSE;
}
m_pThread = AfxBeginThread(CommThread, this);
if (m_pThread == NULL)
{
TRACE0("创建线程失败!\n");
return FALSE;
}
//m_pThread->m_bAutoDelete = FALSE;
TRACE1("%d\n", m_pThread->m_bAutoDelete);
return TRUE;
}
BOOL CSerialPort::SuspendMonitoring()
{
if (m_bThreadAlive && (m_pThread != NULL))
{
m_pThread->SuspendThread();
m_bThreadAlive = FALSE;
}
return TRUE;
}
BOOL CSerialPort::ResumeMonitoring()
{
if (!m_bThreadAlive && (m_pThread != NULL))
{
m_pThread->ResumeThread();
m_bThreadAlive = TRUE;
return TRUE;
}
return FALSE;
}
BOOL CSerialPort::TerminateMonitoring()
{
if (m_pThread != NULL)
{
if (!m_bThreadAlive)
{
m_pThread->ResumeThread();
m_bThreadAlive = TRUE;
}
do
{
SetEvent(m_hShutdownEvent);
} while(m_bThreadAlive);
// m_pThread = NULL;
m_bThreadAlive = FALSE;
return TRUE;
}
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -