// SerialPort.h: interface for the CSerialPort class.
//
//
#if !defined(AFX_SERIALPORT_H__BCE7D852_C6B1_4AEE_925C_1485DBF44011__INCLUDED_)
#define AFX_SERIALPORT_H__BCE7D852_C6B1_4AEE_925C_1485DBF44011__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <afxmt.h>
typedef struct
{
DWORD dwPortNum; /* 端口号 */
DWORD dwBaudRate; /* 波特率 */
BOOL bParity; /* 奇偶校验类型 */
DWORD dwNumberOfDataBit; /* 数据位数目 */
DWORD dwNumberOfStopBit; /* 停止位数目 */
BOOL bFluxControlType; /* 流控方式 */
}SerialPortInfo;
class CSerialPort
{
public:
CEvent m_EventComPort;
CEvent m_EventPurge;
CCriticalSection m_SectionLock;
public:
CSerialPort();
//初始化串口
BOOL Init(SerialPortInfo* stPortInfo);
//取得串口当前配置
void GetState(DCB& dcb);
//配置串口
void SetState(DCB& dcb);
//打开串口
BOOL OpenPort(SerialPortInfo* stPortInfo);
//关闭串口
BOOL ClosePort();
BOOL Purge();
//下发数据
BOOL Write(BYTE* pInBuf,DWORD dwBufLen,DWORD* pdwStatus);
//接收数据
BOOL Read(BYTE* pOutBuf,DWORD dwBufLen,DWORD *pdwRealLen,DWORD* pdwStatus);
DWORD GetAvailableDataLen();
BOOL BeginListenCommEvent();
BOOL WaiteForAEvent();
//获取最近一个错误码
BOOL GetPortStatus()
{
return m_bPortStatus;
}
//设置串口状态
void SetPortStatus(BOOL bPortStatus)
{
m_bPortStatus = bPortStatus;
}
//获取串口状态
DWORD GetLastErrorCode()
{
return m_dwLastErrorCode;
}
virtual ~CSerialPort();
private:
HANDLE m_hPortHandle;
DWORD m_dwLastErrorCode;
BOOL m_bPortStatus;
};
#endif // !defined(AFX_SERIALPORT_H__BCE7D852_C6B1_4AEE_925C_1485DBF44011__INCLUDED_)
// SerialPort.cpp: implementation of the CSerialPort class.
//
//
#include "stdafx.h"
#include "PortAccess.h"
#include "SerialPort.h"
#include "GloableDefine.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CSerialPort::CSerialPort()
{
m_dwLastErrorCode = ERROR_CODE_NO_ERROR;
m_bPortStatus = FALSE;
m_hPortHandle = NULL;
}
CSerialPort::~CSerialPort()
{
if (m_hPortHandle)
{
CloseHandle(m_hPortHandle);
}
}
BOOL CSerialPort:: Init(SerialPortInfo* stPortInfo)
{
BOOL bRet = TRUE;
CString strPortName = "";
strPortName.Format("\\\\.\\COM%d", stPortInfo->dwPortNum);
try
{
m_hPortHandle = CreateFile( strPortName,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == m_hPortHandle)
{
m_dwLastErrorCode = ERROR_CODE_INIT_PORT_FAILD;
bRet = FALSE;
}
SetCommMask(m_hPortHandle, EV_RXCHAR);
DCB dcb;
GetState(dcb);
dcb.BaudRate = stPortInfo->dwBaudRate;
dcb.Parity = NOPARITY;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.fDsrSensitivity = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
SetState(dcb);
}
catch (DWORD dwError)
{
m_dwLastErrorCode = dwError;
bRet = FALSE;
}
if (bRet)
{
SetPortStatus(TRUE);
}
return bRet;
}
void CSerialPort::GetState(DCB& dcb)
{
if(GetCommState(m_hPortHandle, &dcb) == 0) //function failed
{
throw COMERR_GETSTATE;
}
}
void CSerialPort::SetState(DCB& dcb)
{
if(SetCommState(m_hPortHandle, &dcb) == 0) //function failed
{
throw COMERR_SETSTATE;
}
}
BOOL CSerialPort::Purge()
{
if(m_hPortHandle != INVALID_HANDLE_VALUE)
{
m_EventPurge.SetEvent();
m_SectionLock.Lock();
PurgeComm(m_hPortHandle, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
m_SectionLock.Unlock();
}
return TRUE;
}
BOOL CSerialPort::Read(BYTE* pOutBuf,DWORD dwBufLen,DWORD *pdwRealLen,DWORD* pdwStatus)
{
OVERLAPPED OverLap;
DWORD dwNoUse;
BOOL bRet;
memset(&OverLap, 0, sizeof(OverLap));
for(;;)
{
m_SectionLock.Lock(); //
if(GetAvailableDataLen() >= dwBufLen)
{
break;
}
BeginListenCommEvent();
for(;;)
{
try
{
m_SectionLock.Unlock();
break;
}
catch(...)
{
m_dwLastErrorCode = ERROR_CODE_UNKNOW;
}
}
if(WaiteForAEvent() == FALSE)
{
if(pdwRealLen)
{
*pdwRealLen = 0;
}
return TRUE;
}
}
//!!注,上面的等待理论上是有漏洞的,如果操作系统的串口缓冲区长度不到dwBufferLen,
//则这个等待将永远不会返回。
//m_SectionLock.Lock();
bRet = ReadFile(m_hPortHandle, pOutBuf, dwBufLen, &dwNoUse, &OverLap);
if(FALSE == bRet)
{
//如果发生错误
if(::GetLastError() != ERROR_IO_PENDING)
{
m_SectionLock.Unlock();
return FALSE;
}
else
{
//如果读操作正在进行
if(GetOverlappedResult(m_hPortHandle, &OverLap, &dwNoUse, TRUE) == FALSE)
{
m_SectionLock.Unlock();
return FALSE;
}
}
}
m_SectionLock.Unlock();
if(pdwRealLen)
{
*pdwRealLen = dwBufLen;
}
return TRUE;
}
BOOL CSerialPort::Write(BYTE* pInBuf,DWORD dwBufLen,DWORD* pdwStatus)
{
OVERLAPPED OverLap;
DWORD dwWriteLen, dwNoUse;
memset(&OverLap, 0, sizeof(OverLap));
m_SectionLock.Lock();
BOOL bRet = WriteFile(m_hPortHandle, pInBuf, dwBufLen, &dwWriteLen, &OverLap);
if(FALSE == bRet)
{
if(::GetLastError() != ERROR_IO_PENDING)
{
m_SectionLock.Unlock();
return FALSE;
}
if(GetOverlappedResult(m_hPortHandle, &OverLap, &dwNoUse, TRUE) == FALSE)
{
m_SectionLock.Unlock();
return FALSE;
}
}
m_SectionLock.Unlock();
return TRUE;
}
BOOL CSerialPort::OpenPort(SerialPortInfo* stPortInfo)
{
return Init(stPortInfo);
}
BOOL CSerialPort::ClosePort()
{
if(m_hPortHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hPortHandle);
m_hPortHandle = INVALID_HANDLE_VALUE;
SetPortStatus(FALSE);
}
return TRUE;
}
DWORD CSerialPort::GetAvailableDataLen()
{
COMSTAT ComState;
DWORD dwError;
BOOL bRet = ClearCommError(m_hPortHandle, &dwError, &ComState);
if(FALSE == bRet)
{
return DWORD(0);
}
return ComState.cbInQue;
}
BOOL CSerialPort::BeginListenCommEvent()
{
DWORD dwEvent;
OVERLAPPED OverLap;
memset(&OverLap, 0, sizeof(OverLap));
OverLap.hEvent = m_EventComPort.m_hObject;
BOOL bRet = WaitCommEvent(m_hPortHandle, &dwEvent, &OverLap);
if(FALSE == bRet)
{
if(::GetLastError() != ERROR_IO_PENDING)
{
return FALSE;
}
}
return TRUE;
}
BOOL CSerialPort::WaiteForAEvent()
{
DWORD dwRet;
HANDLE hEvent[] = {HANDLE(m_EventComPort), HANDLE(m_EventPurge)};
for(;;)
{
dwRet = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE);
if(dwRet - WAIT_OBJECT_0 == 1)
{
return FALSE;
}
else if(dwRet - WAIT_OBJECT_0 == 0)
{
return TRUE;
}
}
}