⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ceserialcomm.cpp

📁 PDA串口通讯程序,实现收发功能并根据协议解析等功能
💻 CPP
字号:
/*************************************************************************
 CeSerialComm.cpp: implementation of the CCeSerialComm class.
 作    者:	Raymond
 创建时间:	2006.04.19
 作    用:	封装串口API
*************************************************************************/
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RddDbg.h"
#include "CeSerialComm.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCeSerialComm::CCeSerialComm()
{
	m_hComm = NULL;
	m_strPort = _T("COM1");
	m_strError = _T("");
	m_uRate = 9600;
}

CCeSerialComm::~CCeSerialComm()
{

}

BOOL CCeSerialComm::InitComm(LPCTSTR lpszPort, UINT uRate, UINT uTimeOut)
{
	if(IsCommOpened()) return TRUE;

	if(!OpenComm(lpszPort)) return FALSE;

	DCB commParam;
	// 得到打开串口的当前属性参数,修改后再重新设置串口。
	// 设置串口的超时特性为立即返回。
	if (!GetCommState(m_hComm,&commParam))
	{
		return FALSE;
	}
	
	commParam.fOutxCtsFlow = FALSE;
	commParam.fOutxDsrFlow = FALSE;
	commParam.fRtsControl = DTR_CONTROL_DISABLE;
	commParam.fDtrControl = DTR_CONTROL_DISABLE;
	commParam.BaudRate = uRate;     // set the baud rate
	commParam.ByteSize = 8;             // data size, xmit, and rcv
	commParam.Parity = NOPARITY;        // no parity bit
	commParam.StopBits = ONESTOPBIT;    // one stop bit
	
	if (!SetCommState(m_hComm, &commParam))
	{
		AfxMessageBox(_T("设置串口属性参数失败!"));		
		return FALSE;
	}
	
	
    //设置串口读写时间
	COMMTIMEOUTS CommTimeOuts;
	GetCommTimeouts (m_hComm, &CommTimeOuts);
	CommTimeOuts.ReadIntervalTimeout = MAXDWORD;  
	CommTimeOuts.ReadTotalTimeoutMultiplier = 0;  
	CommTimeOuts.ReadTotalTimeoutConstant = 0;    
	CommTimeOuts.WriteTotalTimeoutMultiplier = 10;  
	CommTimeOuts.WriteTotalTimeoutConstant = 1000;  
	
	if(!SetCommTimeouts( m_hComm, &CommTimeOuts ))
	{
		TRACE( _T("SetCommTimeouts 返回错误") );
		return FALSE;
	}
	
	//指定端口监测的事件集
	SetCommMask (m_hComm, EV_RXCHAR|EV_TXEMPTY);
	
	//分配设备缓冲区
	SetupComm(m_hComm, 2048, 2048);
	
	//初始化缓冲区中的信息
	PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);

	return TRUE;
}

BOOL CCeSerialComm::OpenComm(LPCTSTR lpszPort)
{
	TCHAR szPort[15];	
	
	//设置串口名
	wsprintf(szPort, L"%s:", lpszPort);
	m_hComm = CreateFile(szPort, GENERIC_READ|GENERIC_WRITE, 0, NULL,
		                 OPEN_EXISTING, 0, NULL);

	if(m_hComm == INVALID_HANDLE_VALUE)
	{
		m_strError = GetLastErrorDisc();
		AfxMessageBox(m_strError);
		return FALSE;
	}
	
	return TRUE;
}

BOOL CCeSerialComm::CloseComm()
{
	if(m_hComm != NULL && m_hComm != INVALID_HANDLE_VALUE) return FALSE;
	return CloseHandle(m_hComm);
}

BOOL CCeSerialComm::ClearCommBreaks()
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;

	return ClearCommBreak(m_hComm);
}

BOOL CCeSerialComm::ClearCommErrors(LPDWORD lpErrors, LPCOMSTAT lpStat)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return ClearCommError(m_hComm, lpErrors, lpStat);
}

BOOL CCeSerialComm::GetCommMasks(LPDWORD lpEvtMask)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return GetCommMask(m_hComm, lpEvtMask);
}

BOOL CCeSerialComm::GetCommStates(LPDCB lpDCB)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return GetCommState(m_hComm, lpDCB);
}

BOOL CCeSerialComm::GetCommTimeOut(LPCOMMTIMEOUTS lpCommTimeouts)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return GetCommTimeouts(m_hComm, lpCommTimeouts);
}

BOOL CCeSerialComm::SetCommTimeOut(LPCOMMTIMEOUTS lpCommTimeouts)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return SetCommTimeouts(m_hComm, lpCommTimeouts);
}

BOOL CCeSerialComm::PurgeCeComm(DWORD dwFlags)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return PurgeComm(m_hComm, dwFlags);
}

BOOL CCeSerialComm::SetCommMasks(DWORD dwEvtMsk)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return SetCommMask(m_hComm, dwEvtMsk);
}

BOOL CCeSerialComm::SetCommStates(LPDCB lpDCB)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return SetCommState(m_hComm, lpDCB);	
}

BOOL CCeSerialComm::IsCommOpened()
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;

	return TRUE;
}

BOOL CCeSerialComm::ReadNoEvent(BYTE *pByMsg, DWORD dwLen, LPDWORD lpdwReadLen, DWORD dwTimeOut/* =0 */)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	
	if(dwTimeOut != 0)
	{
		COMMTIMEOUTS CommTimeouts;
		if(!GetCommTimeOut(&CommTimeouts)) return FALSE;
		
		CommTimeouts.ReadTotalTimeoutMultiplier = 10;
		CommTimeouts.ReadTotalTimeoutConstant = dwTimeOut;
		if(!SetCommTimeOut(&CommTimeouts)) return FALSE;
	}
	
	if(!ReadFile(m_hComm, pByMsg, dwLen, lpdwReadLen, NULL))
	{
		CloseComm();
		return FALSE;
	}
	if(*lpdwReadLen != dwLen) return FALSE;
	return TRUE;
}

BOOL CCeSerialComm::ReadComm(BYTE *pByMsg, DWORD dwNumberOfBytesToRead, LPDWORD lpNumOfByRead, DWORD dwTimeOut)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;

	if(dwTimeOut != 0)
	{
		COMMTIMEOUTS CommTimeouts;
		if(!GetCommTimeOut(&CommTimeouts)) return FALSE;
		
		CommTimeouts.ReadTotalTimeoutMultiplier = 10;
		CommTimeouts.ReadTotalTimeoutConstant = dwTimeOut;
		if(!SetCommTimeOut(&CommTimeouts)) return FALSE;
	}

	if(!ReadFile(m_hComm, pByMsg, dwNumberOfBytesToRead, lpNumOfByRead, NULL))
	{
		CloseComm();
		return FALSE;
	}
	return TRUE;
}

BOOL CCeSerialComm::WriteComm(BYTE *pByMsg, DWORD dwNumOfByToWrite, LPDWORD lpNumOfByWritten, DWORD dwTimeOut)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;

	if(dwTimeOut != 0)
	{
		COMMTIMEOUTS CommTimeouts;
		if(!GetCommTimeOut(&CommTimeouts)) return FALSE;
		
		CommTimeouts.WriteTotalTimeoutMultiplier = 10;
		CommTimeouts.WriteTotalTimeoutConstant = dwTimeOut;
		if(!SetCommTimeOut(&CommTimeouts)) return FALSE;
	}

	if(!WriteFile(m_hComm, pByMsg, dwNumOfByToWrite, lpNumOfByWritten, NULL))
	{
		CloseComm();
		return FALSE;
	}

	return TRUE;
}

BOOL CCeSerialComm::WaitCommEvents(LPDWORD lpEvtMask)
{
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	return WaitCommEvent(m_hComm, lpEvtMask, NULL);	
}

int CCeSerialComm::ReadAframe(BYTE *pByMsg, LPDWORD lpdwReadLen, DWORD dwTimeOut /* = 0 */)
{
	*lpdwReadLen = 0;
	DWORD dwIndex = 0;
	DWORD dwReadLen;

	if(!Read(pByMsg+dwIndex, 1, &dwReadLen, dwTimeOut)) return 0; //读出错
	if(pByMsg[0] != 0xeb && pByMsg[0] != 0xd7) return -1; //报文头第一个字节出错
	dwIndex += 1; //读出一个字节
	*lpdwReadLen = dwIndex;
	
	if(!Read(pByMsg+dwIndex, 1, &dwReadLen, dwTimeOut)) return 0; //读出错
	if(!(pByMsg[0]==0xeb && pByMsg[1]==0x90) && !(pByMsg[0]==0xd7 && pByMsg[1]==0x09)) return -1; //报文头出错
	dwIndex += 1; //读出一个字节
	*lpdwReadLen = dwIndex;
	
	if(!Read(pByMsg+dwIndex, 2, &dwReadLen, dwTimeOut)) return 0; //读出错
	int iMsgLen = pByMsg[2] + pByMsg[3]*0x100;
	if(iMsgLen > MAX_MSG_LEN) return -1; //长度出错
	dwIndex += 2; //读出2个字节
	*lpdwReadLen = dwIndex;
	
	if(!Read(pByMsg+dwIndex, iMsgLen-4, &dwReadLen, dwTimeOut)) return 0; //读出错

	dwIndex += iMsgLen-4; //读出iMsgLen-4个字节
	*lpdwReadLen = dwIndex;
	
	return 1; //读完
	
}

BOOL CCeSerialComm::Recv(BYTE *pByMsg, DWORD &dwLen, DWORD dwTimeOut)
{
	dwLen = 0;
	DWORD dwCommStatus;
	
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	//清空串口
	if(!PurgeCeComm(PURGE_RXCLEAR | PURGE_TXCLEAR )) return FALSE;
	
	if(!SetCommMasks(EV_RXCHAR)) return FALSE;
	
	if(!WaitCommEvents(&dwCommStatus)) return FALSE;
	
	if(!SetCommMasks(EV_RXCHAR)) return FALSE;
	
	if(dwCommStatus & EV_RXCHAR)
	{
		DWORD dwReadLen;
		DWORD dwIndex = 0;
		
		do 
		{
			
			if(!ReadComm(pByMsg+dwIndex, 1, &dwReadLen, dwTimeOut))
			{
				m_strError = GetLastErrorDisc();
				return FALSE;
			}
			
			if(dwReadLen == 1)
			{
				dwIndex++;
				dwLen ++;
			}
			else
			{
				return FALSE;
			}

		} while(dwReadLen == 1);
		
		return TRUE;
	}

	return FALSE;
}

/*****************************************************************************************
	设计意图:从串口中读取指定长度的数据。如果串口中原来有数据,则直接读出来,读到够长度就
			  返回,如果不够,则等待直到读到所需为止。如果串口中没有数据,则等待
*****************************************************************************************/
BOOL CCeSerialComm::Read(BYTE *pByMsg, DWORD dwLen, LPDWORD lpdwReadLen, DWORD dwTimeOut)
{
	*lpdwReadLen = 0;
	
	if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) return FALSE;
	COMSTAT comStat;
	DWORD dwErrors;
	DWORD dwCommStatus;
	BOOL bIsHasData = TRUE; //原本就有数据

	if(!ClearCommErrors(&dwErrors, &comStat)) return FALSE;
	DWORD dwInLen = comStat.cbInQue;
	if(dwInLen < 1) //没有数据
	{
		//清空串口
		if(!PurgeCeComm(PURGE_RXCLEAR | PURGE_TXCLEAR )) return FALSE;
		
		if(!SetCommMasks(EV_RXCHAR)) return FALSE;

		if(!WaitCommEvents(&dwCommStatus)) return FALSE;

		bIsHasData = FALSE;
	}
	
	DWORD dwIndex = 0;
	DWORD dwReadLen;

	//有数据来,或者原本就有数据
	if((dwCommStatus & EV_RXCHAR) || bIsHasData)
	{
		do 
		{
			if(!ReadComm(pByMsg+dwIndex, 1, &dwReadLen, dwTimeOut))
			{
				*lpdwReadLen = dwReadLen;
				m_strError = GetLastErrorDisc();
				return FALSE;
			}
			if(dwReadLen == 1) 
			{
				dwIndex++;
			}
			
			if(dwIndex == dwLen) //已经读完所需
			{
				*lpdwReadLen = dwLen;
				return TRUE;
			}

		} while(dwIndex < dwInLen);
	}
	
	//清空串口
	if(!PurgeCeComm(PURGE_RXCLEAR | PURGE_TXCLEAR )) return FALSE;
	//长度不够
	if(!SetCommMasks(EV_RXCHAR)) return FALSE;
	
	//读到所需为止
	while(dwIndex < dwLen)
	{
		if(!WaitCommEvents(&dwCommStatus)) return FALSE;

		if(!SetCommMasks(EV_RXCHAR)) return FALSE;
		
		if(dwCommStatus & EV_RXCHAR)
		{
			do 
			{
				if(!ReadComm(pByMsg+dwIndex, 1, &dwReadLen, dwTimeOut))
				{
					m_strError = GetLastErrorDisc();
					*lpdwReadLen = dwReadLen;
					return FALSE;
				}

				if(dwReadLen == 1) dwIndex++;
				
				if(dwIndex == dwLen) //已经够所需了
				{
					*lpdwReadLen = dwLen;
					return TRUE;
				}
			
			} while(dwReadLen == 1);
		}
		
	}
	
	return FALSE;
}

BOOL CCeSerialComm::Write(BYTE *pByMsg, DWORD dwLen, LPDWORD lpdwWriteLen, DWORD dwTimeOut)
{
	UINT uIndex = 0;
	*lpdwWriteLen = 0;
	
	while(uIndex < dwLen)
	{
		DWORD dwWrittenLen;

		if(!WriteComm(pByMsg+uIndex, 1, &dwWrittenLen))
		{
			m_strError = GetLastErrorDisc();
			return FALSE;
		}
		if(dwWrittenLen == 1)
		{
			uIndex++;
			(*lpdwWriteLen)++;
		}
		else 
		{
			return FALSE;
		}
	}

	return TRUE;
}

CString CCeSerialComm::GetLastErrorDisc()
{
	int iErCode = GetLastError();

	HLOCAL hLocal = NULL;
	BOOL fOk = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
			    NULL, iErCode, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED),
				(PTSTR) &hLocal, 0, NULL);
	
	//如果没有则从网络模块查找.
	if(!fOk) 
	{
		HMODULE hDLL = LoadLibraryEx(TEXT("netmsg.dll"), NULL, 
				      DONT_RESOLVE_DLL_REFERENCES);
		if(hDLL != NULL)
		{
			FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,
				hDLL, iErCode, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED),
				(PTSTR)&hLocal, 0, NULL);
			FreeLibrary(hDLL);
		}
	}

	if(hLocal != NULL)
	{
		CString strMsg;
		strMsg.Format(_T("%s"), (PTSTR)LocalLock(hLocal));
		m_strError = strMsg;
		LocalFree(hLocal);
		return strMsg;
	}

	return _T("Unknow Error");
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -