?? comm_mon.cpp
字號:
// comm_mon.cpp
#include "stdafx.h"
#include "comm_mon.h"
#include "commspy.h"
GCommMonitor::GCommMonitor()
{
m_hConn = NULL;
m_hMPP = NULL;
m_pConn = NULL;
m_pMPP = NULL;
}
GCommMonitor::~GCommMonitor()
{
if(m_pConn && m_pConn->bConnected)
{
TRACE(_T("Warning: terminating COMM connection in GCommMonitor::~GCommMonitor()\n"));
Disconnect();
}
if(m_hConn)
{
::GlobalUnlock(m_hConn);
::GlobalFree(m_hConn);
}
if(m_hMPP)
{
::GlobalUnlock(m_hMPP);
::GlobalFree(m_hMPP);
}
}
BOOL GCommMonitor::IsConnected() const
{
return (m_pConn && m_pConn->bConnected);
}
BOOL GCommMonitor::Connect(LPTTYSTRUCT lpTTY)
{
if(m_pConn && m_pConn->bConnected)
return TRUE;
// only allocate this guy once
if(!m_hConn)
{
m_hConn = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(CONNECTION));
m_pConn = (LPCONNECTION)::GlobalLock(m_hConn);
ZeroMemory(m_pConn, sizeof(CONNECTION));
}
// create I/O event used for overlapped reads/writes
if((m_pConn->osRead.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
return FALSE;
if((m_pConn->osWrite.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
return FALSE;
// open communcations file
CString strPort;
if(lpTTY->byCommPort > 3)
{
strPort = "\\\\.\\TELNET";
}
else
{
strPort.Format(_T("COM%d"), lpTTY->byCommPort + 1);
}
m_pConn->hCommDev = ::CreateFile(strPort, GENERIC_READ|GENERIC_WRITE, 0,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
NULL);
if(m_pConn->hCommDev == INVALID_HANDLE_VALUE)
return FALSE;
BOOL bPurge = FALSE;
// get any early notifications
if(::SetCommMask(m_pConn->hCommDev, EV_RXCHAR))
{
// setup device buffers
if(::SetupComm(m_pConn->hCommDev, 4096, 4096))
{
// purge any information in the buffer
if(::PurgeComm(m_pConn->hCommDev, PURGE_TXABORT|PURGE_RXABORT|
PURGE_TXCLEAR|PURGE_RXCLEAR))
{
bPurge = TRUE;
}
}
}
if(!bPurge)
{
::CloseHandle(m_pConn->hCommDev);
return FALSE;
}
// set up for overlapped I/O
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
if(!::SetCommTimeouts(m_pConn->hCommDev, &CommTimeOuts))
{
::CloseHandle(m_pConn->hCommDev);
return FALSE;
}
// set up the connect
DCB dcb;
ZERO_MEMORY(dcb);
dcb.DCBlength = sizeof(DCB);
if(!::GetCommState(m_pConn->hCommDev, &dcb))
{
::CloseHandle(m_pConn->hCommDev);
return FALSE;
}
dcb.BaudRate = lpTTY->dwBaudRate;
dcb.ByteSize = lpTTY->byByteSize;
dcb.Parity = lpTTY->byParity;
dcb.StopBits = lpTTY->byStopBits;
// setup hardware flow control
BOOL bSet = (BYTE)((lpTTY->byFlowCtrl & FC_DTRDSR) != 0);
dcb.fOutxDsrFlow = bSet;
if(bSet)
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
else
dcb.fDtrControl = DTR_CONTROL_ENABLE;
bSet = (BYTE)((lpTTY->byFlowCtrl & FC_RTSCTS) != 0);
dcb.fOutxCtsFlow = bSet;
if(bSet)
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
else
dcb.fRtsControl = RTS_CONTROL_ENABLE;
// setup software flow control
bSet = (BYTE)((lpTTY->byFlowCtrl & FC_XONXOFF) != 0);
dcb.fInX = dcb.fOutX = bSet;
dcb.XonChar = ASCII_XON;
dcb.XoffChar = ASCII_XOFF;
dcb.XonLim = 100;
dcb.XoffLim = 100;
// other various settings
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
if(!::SetCommState(m_pConn->hCommDev, &dcb))
{
::CloseHandle(m_pConn->hCommDev);
return FALSE;
}
m_pConn->bConnected = TRUE;
return m_pConn->bConnected;
}
BOOL GCommMonitor::Disconnect()
{
if(!m_pConn)
return TRUE;
// set connected flag to false
m_pConn->bConnected = FALSE;
// disable event notification and wait for thread to halt
SetCommMask(m_pConn->hCommDev, 0);
// block until thread has been halted
//while(m_pConn->dwThreadID != 0)
//{
// Sleep(10);
//}
// drop DTR
EscapeCommFunction(m_pConn->hCommDev, CLRDTR);
// purge any outstanding reads/writes and close device handle
PurgeComm(m_pConn->hCommDev, PURGE_TXABORT|PURGE_RXABORT|
PURGE_TXCLEAR|PURGE_RXCLEAR);
::CloseHandle(m_pConn->hCommDev);
::CloseHandle(m_pConn->osRead.hEvent);
::CloseHandle(m_pConn->osWrite.hEvent);
return TRUE;
}
BOOL GCommMonitor::Monitor(LPMONITORPROC lpMonitorProc, LPARAM lParam)
{
BOOL bMonitor = FALSE;
// create monitoring thread
if(m_pConn->bConnected)
{
if(lpMonitorProc)
{
if(!m_hMPP)
{
m_hMPP = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(MONITORPROCPARAMS));
m_pMPP = (LPMONITORPROCPARAMS)::GlobalLock(m_hMPP);
}
m_pMPP->lpConn = m_pConn;
m_pMPP->lpCallback = lpMonitorProc;
m_pMPP->lpCallbackParam = lParam;
// create a secondary thread to watch for an event
DWORD dwThreadID;
if(::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CommMonitorProc,
(LPVOID)m_pMPP, 0, &dwThreadID))
{
m_pConn->dwThreadID = dwThreadID;
::EscapeCommFunction(m_pConn->hCommDev, SETDTR);
bMonitor = TRUE;
}
}
else
{
ASSERT(FALSE); // not currently implemented
}
}
return bMonitor;
}
DWORD CALLBACK GCommMonitor::CommMonitorProc(LPVOID lpThreadParameter)
{
HGLOBAL hParams = (HGLOBAL)lpThreadParameter;
LPMONITORPROCPARAMS pParams = (LPMONITORPROCPARAMS)::GlobalLock(hParams);
if(!pParams)
return 0;
HGLOBAL hBuf = ::GlobalAlloc(GMEM_MOVEABLE, MAX_RXBLOCK + 1);
if(!hBuf)
{
::GlobalUnlock(hParams);
return 0;
}
LPBYTE lpBuffer = (LPBYTE)::GlobalLock(hBuf);
if(!lpBuffer)
{
::GlobalUnlock(hParams);
::GlobalFree(hBuf);
return 0;
}
// create I/O event used for overlapped read
OVERLAPPED os;
::ZeroMemory(&os, sizeof(os));
os.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
if(os.hEvent == NULL || !SetCommMask(pParams->lpConn->hCommDev, EV_RXCHAR))
{
ReportLastError();
return 0;
}
while(pParams->lpConn->bConnected)
{
DWORD dwEvtMask = 0;
int nLength = 0;
OVERLAPPED ol;
::ZeroMemory(&ol, sizeof(ol));
ol.hEvent = os.hEvent;
WaitCommEvent(pParams->lpConn->hCommDev, &dwEvtMask, &ol);
if((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
{
do
{
if((nLength = CommReadBlock(pParams->lpConn, lpBuffer, MAX_RXBLOCK)) != 0)
{
if(pParams->lpCallback)
pParams->lpCallback(hBuf, nLength, pParams->lpCallbackParam);
}
} while(nLength > 0);
}
}
::GlobalUnlock(hBuf);
::GlobalFree(hBuf);
// get rid of event handles
::CloseHandle(os.hEvent);
// clear information in structure (indicates the thread has terminated)
pParams->lpConn->dwThreadID = NULL;
::GlobalUnlock(hParams);
return 1;
}
BOOL CALLBACK GCommMonitor::CommReadBlock(LPCONNECTION lpConn, LPBYTE lpszBlock,
int nLen)
{
// only try to read number of bytes in queue
DWORD dwErrorFlags;
COMSTAT ComStat;
::ClearCommError(lpConn->hCommDev, &dwErrorFlags, &ComStat);
DWORD dwLength = min((DWORD)nLen, ComStat.cbInQue);
if(dwLength > 0)
{
BOOL bReadStat = ReadFile(lpConn->hCommDev, lpszBlock, dwLength,
&dwLength, &lpConn->osRead);
if(!bReadStat)
{
if(GetLastError() == ERROR_IO_PENDING)
{
OutputDebugString("\n\rIO Pending");
// we have to wait for read to complete. This function will timeout
// according to the CommTimeOuts.ReadTotalTimeoutConstant variable
// Every time it times out, check for port errors
while(!GetOverlappedResult(lpConn->hCommDev, &lpConn->osRead,
&dwLength, TRUE))
{
DWORD dwError = GetLastError();
if(dwError == ERROR_IO_INCOMPLETE)
{
// normal result if not finished
continue;
}
else
{
// CAN DISPLAY ERROR MESSAGE HERE
// an error occured, try to recover
::ClearCommError(lpConn->hCommDev, &dwErrorFlags, &ComStat);
if(dwErrorFlags > 0)
{
// CAN DISPLAY ERROR MESSAGE HERE
}
break;
}
}
}
else
{
// some other error occured
dwLength = 0;
ClearCommError(lpConn->hCommDev, &dwErrorFlags, &ComStat);
if(dwErrorFlags > 0)
{
// CAN DISPLAY ERROR MESSAGE HERE
}
}
}
}
return dwLength;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -