#define COMM_API _declspec(dllexport)
#include "CommLib.h"
cnComm::cnComm(BOOL bAutoReceive, bool fAutoBeginThread, DWORD dwIOMode)
: _dwIOMode(dwIOMode), _fAutoBeginThread(fAutoBeginThread)
{
Init();
m_bAutoReceive = bAutoReceive;
IsCommflag = false;
}
cnComm::~cnComm()
{
Close();
Destroy();
}
void cnComm::Init()
{
memset(_szCommStr, 0, 20);
memset(&_DCB, 0, sizeof(_DCB));
_DCB.DCBlength = sizeof(_DCB);
_hCommHandle = INVALID_HANDLE_VALUE;
memset(&_ReadOverlapped, 0, sizeof(_ReadOverlapped));
memset(&_WriteOverlapped, 0, sizeof(_WriteOverlapped));
_ReadOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
assert(_ReadOverlapped.hEvent != NULL);
_WriteOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
assert(_WriteOverlapped.hEvent != NULL);
_hNotifyWnd = NULL;
_dwNotifyNum = 0;
_dwMaskEvent = DEFAULT_COM_MASK_EVENT;
_hThreadHandle = NULL;
memset(&_WaitOverlapped, 0, sizeof(_WaitOverlapped));
_WaitOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
assert(_WaitOverlapped.hEvent != NULL);
::InitializeCriticalSection(&_Mutex);
}
//析构
void cnComm::Destroy()
{
if(_ReadOverlapped.hEvent != NULL)
CloseHandle(_ReadOverlapped.hEvent);
if(_WriteOverlapped.hEvent != NULL)
CloseHandle(_WriteOverlapped.hEvent);
if(_WaitOverlapped.hEvent != NULL)
CloseHandle(_WaitOverlapped.hEvent);
::DeleteCriticalSection(&_Mutex);
}
//关闭串口 同时也关闭关联线程
void cnComm::Close()
{
if(IsOpen())
{
PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);
EndThread();
::CloseHandle(_hCommHandle);
_hCommHandle = INVALID_HANDLE_VALUE;
}
}
//判断串口是或打开
bool cnComm::IsOpen()
{
return _hCommHandle != INVALID_HANDLE_VALUE;
}
//终止线程
bool cnComm::EndThread(DWORD dwWaitTime)
{
if(IsThreadRunning())
{
_fRunFlag = false;
::SetCommMask(_hCommHandle, 0);
::SetEvent(_WaitOverlapped.hEvent);
if(::WaitForSingleObject(_hThreadHandle, dwWaitTime) != WAIT_OBJECT_0)
if(!::TerminateThread(_hThreadHandle, 0))
return false;
::CloseHandle(_hThreadHandle);
::ResetEvent(_WaitOverlapped.hEvent);
_hThreadHandle = NULL;
return true;
}
return false;
}
//辅助线程控制 建监视线程
bool cnComm::BeginThread()
{
if(!IsThreadRunning())
{
_fRunFlag = true;
_hThreadHandle = NULL;
#ifdef _MT
unsigned int id;
_hThreadHandle = (HANDLE)_beginthreadex(NULL, 0, CommThreadProc, this, 0, &id);
#else
DWORD id;
_hThreadHandle = ::CreateThread(NULL, 0, CommThreadProc, this, 0, &id);
#endif
return (_hThreadHandle != NULL);
}
return false;
}
//线程是否运行
bool cnComm::IsThreadRunning()
{
return _hThreadHandle != NULL;
}
//打开串口 缺省 9600, 8, n, 1
bool cnComm::Open(DWORD dwPort)
{
//是否自动接收数据
if(m_bAutoReceive)
{
SetWnd(GetForegroundWindow());
}
return Open(dwPort, 9600);
}
//打开串口 缺省 baud_rate, n, 8, 1
bool cnComm::Open(DWORD dwPort, DWORD dwBaudRate)
{
if(dwPort < 1 || dwPort > 1024)
return false;
BindCommPort(dwPort);
if(!OpenCommPort())
return false;
if(!SetupPort())
return false;
//是否自动接收数据
if(m_bAutoReceive)
SetWnd(GetForegroundWindow());
return SetState(dwBaudRate);
}
//打开串口, 使用类似"9600, n, 8, 1"的设置字符串设置串口
bool cnComm::Open(DWORD dwPort, char *szSetStr)
{
if(dwPort < 1 || dwPort > 1024)
return false;
BindCommPort(dwPort);
if(!OpenCommPort())
return false;
if(!SetupPort())
return false;
//是否自动接收数据
if(m_bAutoReceive)
SetWnd(GetForegroundWindow());
return SetState(szSetStr);
}
//绑定串口
void cnComm::BindCommPort(DWORD dwPort)
{
assert(dwPort >= 1 && dwPort <= 1024);
char p[5];
_dwPort = dwPort;
//通过函数CreateFile打开串口, 其第一个参数就是串口的逻辑端口名, 是用”COMX”表示的, 其中X是1~N的整数,
//当X大于10时, 有时会出现无法打开的问题, 把逻辑端口名改成"\\\\.\\COM
//strcpy_s(_szCommStr, "\\\\.\\COM");
strcpy_s(_szCommStr, "COM");
_ltoa_s(_dwPort, p, 10);
strcat_s(_szCommStr, p);
}
//打开串口
bool cnComm::OpenCommPort()
{
if(IsOpen())
Close();
_hCommHandle = ::CreateFile(
_szCommStr, //将要打开的串口逻辑名,如“com1”
GENERIC_READ | GENERIC_WRITE, //指定串口访问的类型,可以是读取、写入或二者并列
0, //指定共享属性,由于串口不能共享,该参数必须置为0
NULL, //引用安全性属性结构,缺省值为NULL
OPEN_EXISTING, //创建标志,对串口操作该参数必须置为OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL | _dwIOMode, //属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;
NULL //对串口而言该参数必须置为NULL
);
if(_fAutoBeginThread)
{
if(IsOpen() && BeginThread())
return true;
else
{
Close(); //创建线程失败
return false;
}
}
return IsOpen();
}
//设置串口
bool cnComm::SetupPort()
{
if(!IsOpen())
return false;
//输入缓冲区和输出缓冲区的大小都是4096
if(!::SetupComm(_hCommHandle, 4096, 4096))
return false;
//得到延时的超时结构
if(!::GetCommTimeouts(_hCommHandle, &_CO))
return false;
_CO.ReadIntervalTimeout = 0; //设定读间隔超时
_CO.ReadTotalTimeoutMultiplier = 1; //设定读时间系数
_CO.ReadTotalTimeoutConstant = 1000; //设定读时间常量
_CO.WriteTotalTimeoutMultiplier = 1; //设定写时间系数
_CO.WriteTotalTimeoutConstant = 1000; //设定写时间常量
if(!::SetCommTimeouts(_hCommHandle, &_CO)) //是否设置超时
return false;
//用PurgeComm()函数清空缓冲区
//PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。
//PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。
//PURGE_TXCLEAR 清除输出缓冲区
//PURGE_RXCLEAR 清除输入缓冲区
if(!::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ))
return false;
return true;
}
//设置串口参数 DCB
bool cnComm::SetState(DCB *pdcb)
{
return IsOpen() ? ::SetCommState(_hCommHandle, pdcb == NULL ? &_DCB : pdcb) == TRUE : false;
}
//设置串口参数:波特率,停止位,等 支持设置字符串 "9600, 8, n, 1"
bool cnComm::SetState(char *szSetStr)
{
if(IsOpen())
{
if(::GetCommState(_hCommHandle, &_DCB) != TRUE)
return false;
if(::BuildCommDCB(szSetStr, &_DCB) != TRUE)
return false;
return ::SetCommState(_hCommHandle, &_DCB) == TRUE;
}
return false;
}
//设置串口参数:波特率,停止位,等
bool cnComm::SetState(DWORD dwBaudRate, DWORD dwByteSize, DWORD dwParity, DWORD dwStopBits)
{
if(IsOpen())
{
if(::GetCommState(_hCommHandle, &_DCB) != TRUE)
return false;
_DCB.BaudRate = dwBaudRate;
_DCB.ByteSize = (unsigned char)dwByteSize;
_DCB.Parity = (unsigned char)dwParity;
_DCB.StopBits = (unsigned char)dwStopBits;
return ::SetCommState(_hCommHandle, &_DCB) == TRUE;
}
return false;
}
//关联消息的窗口句柄
void cnComm::SetWnd(HWND hWnd)
{
assert(::IsWindow(hWnd));
_hNotifyWnd = hWnd;
}
DWORD cnComm::ThreadFunc()
{
if(!::SetCommMask(_hCommHandle, _dwMaskEvent))
{
char szBuffer[256];
_snprintf_s(szBuffer, 255, "%s(%d) : COM%d Call WINAPI SetCommMask(%x, %x) Fail, thread work invalid! GetLastError() = %d;",
__FILE__, __LINE__, _dwPort, _hCommHandle, _dwMaskEvent, GetLastError());
MessageBox(NULL, szBuffer, "Class cnComm", MB_OK);
return 1;
}
COMSTAT Stat;
DWORD dwError;
for(DWORD dwLength, dwMask = 0; _fRunFlag && IsOpen(); dwMask = 0)
{
if(!::WaitCommEvent(_hCommHandle, &dwMask, &_WaitOverlapped))
{
if(::GetLastError() == ERROR_IO_PENDING)// asynchronous
::GetOverlappedResult(_hCommHandle, &_WaitOverlapped, &dwLength, TRUE);
else
continue;
}
if(dwMask == 0)
continue;
switch(dwMask)
{
//EV_RXCHAR:接收到一个字符,并放入缓存区
case EV_RXCHAR :
::ClearComm