#include "stdafx.h"
#include "ConstDef.h"
#include "CSerial.h"
#include "stdio.h"
/**************************************************************************************************
** 函数名称: CSerial::CSerial()
** 功能描述: 构造函数
** 输 入 : 无
** 全局变量: m_ahEvents-事件数组
m_lBaud-全局波特率
m_nPort-全局串口号
m_hCom-全局串口句柄
** 输 出 : 无
** 调用模块: 无
***************************************************************************************************/
CSerial::CSerial()
{
m_lBaud=38400;
m_nPort=1;
m_hCom=NULL;
m_ahEvents[EVENT_READ ]= CreateEvent(NULL, TRUE, FALSE, "CommReadEvent");
m_ahEvents[EVENT_WRITE]= CreateEvent(NULL, TRUE, FALSE, "CommWriteEvent");
}
/**************************************************************************************************
** 函数名称: CSerial::~CSerial()
** 功能描述: 析构函数
** 输 入 : 无
** 全局变量: m_ahEvents-事件数组
** 输 出 : 无
** 调用模块: Close()-关闭串口
***************************************************************************************************/
CSerial::~CSerial()
{
Close();
for (int i=0;i<MAX_EVENTS_NUM;i++)
{
if (m_ahEvents[i])
{
CloseHandle(m_ahEvents[i]);
}
}
if (m_osR.hEvent)
{
CloseHandle(m_osR.hEvent);
}
if (m_osW.hEvent)
{
CloseHandle(m_osW.hEvent);
}
}
/**************************************************************************************************
** 函数名称: CSerial::Reset()
** 功能描述: 重置串口参数
** 输 入 : port-串口号
** baud-波特率
** 全局变量: m_nPort-全局串口号
** m_lBaud-全局波特率
** 输 出 : TRUE-设置正确
** 调用模块: 无
***************************************************************************************************/
int CSerial::Reset(int port,long baud/* =38400 */)
{
m_nPort=port;
m_lBaud=baud;
return TRUE;
}
/**************************************************************************************************
** 函数名称: CSerial::Open()
** 功能描述: 打开串口
** 输 入 : 无
** 全局变量: PacketSend:发送数据包
** 输 出 : ERROR_COM_INVALID-无效的串口句柄
** ERROR_COM_SET_EVENT-设置串口事件失败
** COM_OPEN_OK-打开串口成功
** 调用模块: Ready()-检测是否已经打开串口(正确取得句柄值)
***************************************************************************************************/
int CSerial::Open()
{
if (Ready())
{
Close();
}
char *tmp=new char[16];
COMMTIMEOUTS timeout;
sprintf(tmp,"COM%d",m_nPort);
m_hCom=CreateFile( tmp,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
if (m_hCom==INVALID_HANDLE_VALUE)
{
return ERROR_COM_INVALID;
}
//设置超时
GetCommTimeouts(m_hCom,&timeout);
timeout.ReadIntervalTimeout=1000;
timeout.ReadTotalTimeoutMultiplier=1000;
timeout.WriteTotalTimeoutConstant=1000;
SetCommTimeouts(m_hCom,&timeout);
//设置串口参数
DCB dcb;
GetCommState(m_hCom,&dcb);
dcb.fBinary=TRUE; // 二进制方式
dcb.BaudRate=m_lBaud; // 波特率
dcb.ByteSize=8; // 每个字符有8位
dcb.Parity=NOPARITY; // 无校验
dcb.StopBits=ONESTOPBIT;// 一个停止位
dcb.EvtChar='q'; // 这个一定要,否则大于127的数值会接收不了啊
dcb.fRtsControl=RTS_CONTROL_DISABLE;
SetCommState(m_hCom,&dcb);
//设置监视的串口通信事件
if (!SetCommMask(m_hCom, EV_RXCHAR))
{
return ERROR_COM_SET_EVENT;
}
return COM_OPEN_OK ; //返回打开串口成功
}
/**************************************************************************************************
** 函数名称: CSerial::Ready()
** 功能描述: 返回串口句柄值
** 输 入 : 无
** 全局变量: m_hCom-全局串口句柄
** 输 出 : m_hCom-句柄值
** 调用模块: 无
***************************************************************************************************/
int CSerial::Ready()
{
return (m_hCom>0);
}
/**************************************************************************************************
** 函数名称: CSerial::Close()
** 功能描述: 返回串口句柄值
** 输 入 : 无
** 全局变量: m_hCom-全局串口句柄
** 输 出 : ERROR_COM_INVALID-无效的串口句柄值
** COM_CLOSE_OK-串口关闭成功
** 调用模块: Ready()-返回设备是否已经正确打开
***************************************************************************************************/
int CSerial::Close()
{
if (!Ready())
{
return ERROR_COM_INVALID;
}
else
{
if (CloseHandle(m_hCom))
{
m_hCom=NULL;
return COM_CLOSE_OK;
}
else
{
return ERROR_COM_INVALID;
}
}
}
/**************************************************************************************************
** 函数名称: CSerial::SendData(char *pbuf,int nlen)
** 功能描述: 发送数据到串口
** 输 入 : pbuf-要发送的数据
** nlen-要发送数据的长度
** 全局变量: m_hCom-全局串口句柄
** 输 出 : ERROR_COM_CLOSED-串口关闭失败
** ERROR_BUF_FAULT-发送数据的缓冲区不正确
** ERROR_WRITE_TIMEOUT-发送数据超时
** ERROR_WRITE_FAIL-发送数据失败
** dwWriteBytes-返回已经发送的字节数
** 调用模块: Ready()-返回设备是否已经正确打开
***************************************************************************************************/
int CSerial::SendData(char *pbuf,int nlen)
{
if (!Ready())
{
return ERROR_COM_CLOSED;
}
if ((pbuf == NULL) || (nlen<=0))
{
return ERROR_BUF_FAULT;
}
//清空输入输出缓冲区
PurgeComm(m_hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
//清除串口错误事件
DWORD dwError=0;
COMSTAT comstat;
ClearCommError(m_hCom,&dwError,&comstat);
//重叠结构
memset(&m_osW,0,sizeof(m_osW));
ResetEvent(m_ahEvents[EVENT_WRITE]);
m_osW.hEvent=m_ahEvents[EVENT_WRITE];
DWORD dwWriteBytes;
if (!WriteFile(m_hCom,pbuf,nlen,&dwWriteBytes,&m_osW))
{
if(GetLastError()==ERROR_IO_PENDING)
{
if (WaitForSingleObject(m_osW.hEvent,1500)!=WAIT_OBJECT_0)
{
return ERROR_WRITE_TIMEOUT;
}
else if (!GetOverlappedResult(m_hCom,&m_osW,&dwWriteBytes,FALSE))
{
return ERROR_WRITE_FAIL;
}
}
}
return (int)dwWriteBytes;
}
/**************************************************************************************************
** 函数名称: CSerial::RecvData(unsigned char *pbuf,int nlen)
** 功能描述: 从串口读取数据
** 输 入 : pbuf-要保存接收的数据缓冲区
** nlen-要接收数据的长度
** 全局变量: m_hCom-全局串口句柄
** 输 出 : ERROR_COM_CLOSED-串口关闭失败
** ERROR_BUF_FAULT-接收数据的缓冲区不正确
** ERROR_READ_TIMEOUT-读取数据超时
** ERROR_READ_FAIL-读取数据失败
** dwReadBytes-返回已经读取的字节数
** 调用模块: Ready()-返回设备是否已经正确打开
***************************************************************************************************/
int CSerial::RecvData(unsigned char *pbuf,int nlen)
{
if (!Ready())
{
return ERROR_COM_CLOSED;
}
if ((pbuf == NULL) || (nlen<=0))
{
return ERROR_BUF_FAULT;
}
//重叠结构
memset(&m_osR,0,sizeof(m_osR));
ResetEvent(m_ahEvents[EVENT_READ]);
m_osR.hEvent=m_ahEvents[EVENT_READ];
DWORD dwReadedBytes=0;
if (!ReadFile(m_hCom,pbuf,nlen,&dwReadedBytes,&m_osR))
{
if (GetLastError()==ERROR_IO_PENDING)
{
if (WaitForSingleObject(m_osR.hEvent,3000)!=WAIT_OBJECT_0)
{
return ERROR_READ_TIMEOUT;
}
else if (!(GetOverlappedResult(m_hCom,&m_osR,&dwReadedBytes,FALSE)))
{
return ERROR_READ_FAIL;
}
}
}
//清空输入输出缓冲区
PurgeComm(m_hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
//清除串口错误事件
DWORD dwError=0;
COMSTAT comstat;
ClearCommError(m_hCom,&dwError,&comstat);
return (int)dwReadedBytes;
}