📄 yscomm.cpp
字号:
// YsAT.cpp: implementation of the CYsComm class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "YsComm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CYsComm::CYsComm()
{
//ifdef _BALANCE
m_bSemiduplex=FALSE;
//#else
// m_bSemiduplex=TRUE;//半双工
//#endif
m_hFileHandle = NULL;
//m_overlappedWrite={0, 0, 0, 0, NULL};
memset(&m_overlappedWrite,0,sizeof(OVERLAPPED));
//m_overlappedRead = {0, 0, 0, 0, NULL};
memset(&m_overlappedRead,0,sizeof(OVERLAPPED));
memset(&m_overlappedEvent,0,sizeof(OVERLAPPED));
// Needed for overlapped I/O.
m_overlappedWrite.hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
if (m_overlappedWrite.hEvent == NULL)
{
TRACE(_TEXT("Unable to CreateEvent:\n "));
}
// Lets put an event in the Read overlapped structure.
m_overlappedRead.hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
if (m_overlappedRead.hEvent == NULL)
{
TRACE(_TEXT("Unable to CreateEvent: \n"));
}
m_overlappedEvent.hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
if (m_overlappedEvent.hEvent == NULL)
{
TRACE(_TEXT("Unable to CreateEvent: \n"));
}
m_hStopReadEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if (m_hStopReadEvent== NULL)
{
TRACE(_TEXT("Unable to CreateEvent: \n"));
}
m_hStopWriteEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if (m_hStopWriteEvent== NULL)
{
TRACE(_TEXT("Unable to CreateEvent: \n"));
}
m_nPort=0;
m_hWnd=NULL;
}
CYsComm::~CYsComm()
{
StopComm();
CloseHandle(m_overlappedRead.hEvent);
CloseHandle(m_overlappedWrite.hEvent);
CloseHandle(m_overlappedEvent.hEvent);
CloseHandle(m_hStopWriteEvent);
CloseHandle(m_hStopReadEvent);
}
/*************************2001.10.31 ycat *********************************************
FUNCTION: BOOL CYsComm::Create(UINT port,HWND hWnd)
PURPOSE: 创建串口文件句柄
PARAMETERS:
port:串口的串口号
hWnd:用来接收消息的窗口句柄
RETURN VALUE:
如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
**********************************************************************/
BOOL CYsComm::Create(UINT port,BOOL bSemiduplex,HWND hWnd)
{
m_bSemiduplex=bSemiduplex;
CString sBuff;
DWORD dwError = 0;
if(m_hFileHandle!=NULL)
{
StopComm();
}
sBuff.Format(_TEXT("COM%d"),port);
m_hFileHandle = CreateFile(sBuff,
GENERIC_READ|GENERIC_WRITE,
0,//exclusive access
NULL,
OPEN_EXISTING, //必须
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
NULL);
if(m_hFileHandle == INVALID_HANDLE_VALUE)
{
dwError = GetLastError();
TRACE(_TEXT("Open COM%d Error code %d,Please check if the port is usable.\n"),port,dwError);
return FALSE;
}
m_hWnd=hWnd;
m_nPort=port;
return TRUE;
}
/*************************2001.10.31 ycat *********************************************
FUNCTION: void CYsComm::StopComm()
PURPOSE: 关闭串口句柄
PARAMETERS:
RETURN VALUE:
COMMENTS:
**********************************************************************/
void CYsComm::StopComm()
{
// No need to continue if we're not communicating.
if (m_hFileHandle == NULL)
return;
//Purge(PURGE_ALL);
TRACE(_TEXT("Stopping the Comm\n"));
// Now close the comm port handle.
CloseHandle(m_hFileHandle);
m_hFileHandle = NULL;
}
/*************************2001.10.31 ycat *********************************************
/*************************2001.11.06 ycat *********************************************
FUNCTION: int CYsComm::ReadIn(LPTSTR lpszInputBuffer,
DWORD dwCount,
DWORD dwReadTimeOut)
PURPOSE: 在dwReadTimeOut里读到dwCount个字符,否则出错
PARAMETERS:
lpszInputBuffer: 存放返回数据的字符串缓冲区
dwCount: 希望要读到的字符个数
dwReadTimeOut: 超时的时间
RETURN VALUE:
-1: 除-2,-3之外的其它错误
1:表示写com口成功
-2: 表示timeout
-3: 表示读操作被停止
COMMENTS:
不能支持多线程
如果读出的数和dwCount不一样,那么将返回超时
读出来的数没有意义
注意和ReadComm()的区别
**********************************************************************/
int CYsComm::ReadIn(PBYTE lpszInputBuffer,
DWORD dwCountoByte,
DWORD dwReadTimeOut)
{
if ( m_hFileHandle == NULL)
{
TRACE(_TEXT("m_hFileHandle error.\n"));
return -1;
}
int nRet;
DWORD dwLastError;
DWORD dwHandleSignaled;
HANDLE HandlesToWaitFor[2];
int iWait=2;
// HandlesToWaitFor[0] = g_hCloseEvent;//为了支持多线程
//OVERLAPPED o={0};
//o.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
HandlesToWaitFor[0] = m_overlappedRead.hEvent;
HandlesToWaitFor[1] = m_hStopReadEvent;
//HandlesToWaitFor[0] = o.hEvent;
DWORD dwHaveReaded=0;
// unsigned char
// WCHAR
if (ReadFile((HANDLE)m_hFileHandle,
(LPVOID)lpszInputBuffer,
(DWORD)dwCountoByte,
(LPDWORD)&dwHaveReaded,
(LPOVERLAPPED)&m_overlappedRead))
{ // This would only happen if there was data waiting to be read.
// TRACE(_TEXT("there waw data waiting to be read.\n");
nRet=1;
goto Exit;
}
// ReadFile failed. Expected because of overlapped I/O.
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if (GetLastError()!= ERROR_IO_PENDING)
{
TRACE(_TEXT("Error to reading to CommFile %x\n"),dwLastError);
nRet=-1;
goto Exit;
}
// This is the expected ERROR_IO_PENDING case.
// Wait for either overlapped I/O completion,
// or for the CloseEvent to get signaled.
dwHandleSignaled =
WaitForMultipleObjects(iWait,HandlesToWaitFor,
FALSE,dwReadTimeOut);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0 : // Wait finished.
{
// Time to get the results of the WriteFile
break;
}
case WAIT_OBJECT_0+1 : // Wait finished.
{
TRACE(_TEXT("stop read event set\n"));
nRet=-3;
goto Exit;
}
case WAIT_TIMEOUT :
{
// TRACE(_TEXT("read time out\n"));
nRet=-2;
goto Exit;
}
case WAIT_FAILED: // Wait failed. Shouldn't happen.
{
TRACE(_TEXT("read WAIT_FAILED: \n "));
nRet=-1;
goto Exit;
}
default: // This case should never occur.
{
TRACE(_TEXT("Unexpected Wait return value '%x'"),dwHandleSignaled);
nRet=-1;
goto Exit;
}
}
if (GetOverlappedResult(m_hFileHandle,
&m_overlappedRead,&dwHaveReaded, FALSE))
{
nRet=1;
goto Exit;
}
else
{
//cause by Purge(PURGE_RXABORT)
TRACE(_TEXT("read operation error \n "));
nRet=-1;
}
Exit:
/* if(nRet==1)
{
for(UINT i=0;i<dwHaveReaded;i++)
TRACE("@@@ %x @@@\n",lpszInputBuffer[i],lpszInputBuffer[i]);
}*/
if(nRet!=1) Purge(PURGE_RXABORT);//取消读操作
return nRet;
}
/*************************2001.10.31 ycat *********************************************
FUNCTION: int CYsComm::BOOL CYsComm::Purge(DWORD nType)
PURPOSE: 清除串口
PARAMETERS:
nType的值及说明,可组合起来用
PURGE_TXABORT Terminates all outstanding overlapped write
operations and returns immediately,
even if the write operations have not been completed.
PURGE_RXABORT Terminates all outstanding overlapped
read operations and returns immediately,
even if the read operations have not been completed.
PURGE_TXCLEAR Clears the output buffer (if the device driver has one).
PURGE_RXCLEAR Clears the input buffer (if the device driver has one).
RETURN VALUE: 如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
**********************************************************************/
BOOL CYsComm::Purge(DWORD nType)
{
if(!m_hFileHandle)
{
// SetLastError(_TEXT("comm file handle isn't available"));
return FALSE;
}
if(nType&PURGE_RXABORT)
PulseEvent(m_hStopReadEvent);
if(nType&PURGE_TXABORT)
PulseEvent(m_hStopWriteEvent);
int i=PurgeComm(m_hFileHandle,nType);
if(!i)
{
// SetLastError(_TEXT("Purge com fail"));
return FALSE;
}
// ResetError();
// TRACE(_TEXT("Purge Comm\n");
return i;
}
/*查询缓冲区内的字符数
nType=TYPE_READ 表示查读缓冲区
nType=TYPE_WRITE表示写缓冲区*/
BOOL CYsComm::GetBufferCount(int nType,LPDWORD lpNumberInBuffer)
{
DWORD Errors;
COMSTAT State;
if(!ClearCommError(m_hFileHandle,&Errors,&State))
return FALSE;
if(nType==TYPE_READ) *lpNumberInBuffer=State.cbInQue;
else *lpNumberInBuffer=State.cbOutQue;
return TRUE;
}
/*************************2001.10.31 ycat *********************************************
FUNCTION: int CYsComm::WriteComm(LPCTSTR lpszStringToWrite,
DWORD dwCount)
PURPOSE: 向串口发送数据
PARAMETERS:
lpszStringToWrite:要写的字符串
dwCount:字符串的长度
RETURN VALUE:
-1:除timeout外其它错误
1:表示写com口成功
-2:表示timeout
-3:表示stop write event set
COMMENTS:
Change the WaitForSingleObject call to include a real
time-out value. This causes more problems because
if the program issues another operation
while an older operation is still pending,
new OVERLAPPED structures and overlapped
events need to be allocated.
This type of recordkeeping is difficult,
particularly when compared to using a “job queue”
design for the operations.
不支持多线程
**********************************************************************/
int CYsComm::WriteComm(PBYTE lpszStringToWrite,
DWORD dwCount)
{
if ( m_hFileHandle == NULL)
{
TRACE(_TEXT("m_hFileHandle error_W.\n"));
return -1;
}
int nRet;
DWORD dwLastError;
DWORD dwHaveWritten = 0;
DWORD dwStartWrite = 0; // Start at the beginning.
DWORD dwNumToWrite = dwCount;
DWORD dwHandleSignaled;
HANDLE HandlesToWaitFor[2];
int iWait=2;
HandlesToWaitFor[0] = m_overlappedWrite.hEvent;
HandlesToWaitFor[1] = m_hStopWriteEvent;
// EscapeCommFunction(m_hFileHandle,SETRTS);//半双工
// Keep looping until all characters have been written.
do
{
// Start the overlapped I/O.
if (!WriteFile((HANDLE)m_hFileHandle,
(LPCVOID)&(lpszStringToWrite[dwStartWrite]),
(DWORD)dwCount,
(LPDWORD)&dwHaveWritten,
(LPOVERLAPPED)&m_overlappedWrite))
{
// WriteFile failed. Expected; lets handle it.
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if(GetLastError()!= ERROR_IO_PENDING)
{
TRACE(_TEXT("Error to writing to CommFile %x\n"),dwLastError);
nRet=-1;
goto Exit;
}
// Wait for either overlapped I/O completion,
// or for the CloseEvent to get signaled.
dwHandleSignaled =
WaitForMultipleObjects(2, HandlesToWaitFor,
FALSE,5000);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0 : // Wait finished.
{
// Time to get the results of the WriteFile
break;
}
case WAIT_TIMEOUT :
{
TRACE(_TEXT("write time out\n"));
nRet=-2;
goto Exit;
}
case WAIT_FAILED: // Wait failed. Shouldn't happen.
{
TRACE(_TEXT("Write WAIT_FAILED: \n "));
nRet=-1;
goto Exit;
}
case WAIT_OBJECT_0+1:
{
//stop event set
TRACE(_TEXT("stop event set"));
nRet=-3;
goto Exit;
}
default: // This case should never occur.
{
TRACE(_TEXT("Unexpected Wait return value '%x'"),dwHandleSignaled);
nRet=-1;
goto Exit;
}
}
//判断是否已经结束
if (!GetOverlappedResult(m_hFileHandle,
&m_overlappedWrite,
&dwHaveWritten,
TRUE))
{
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port.
if (dwLastError == ERROR_INVALID_HANDLE)
{
TRACE(_TEXT("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port.\n"));
nRet=-1;
goto Exit;
}
// No idea what could cause another error.
TRACE(_TEXT("Error writing to CommFile while waiting %x \n"),dwLastError);
nRet=-1;
goto Exit;
}
}
// Some data was written. Make sure it all got written.
//TRACE(_TEXT("Write bytes %ld\n",dwHaveWritten);
dwCount -= dwHaveWritten;
dwStartWrite += dwHaveWritten;
}while(dwCount > 0); // Write the whole thing!
// Wrote the whole string.
// *pdwCountWritten = dwNumToWrite;
nRet=1;
Exit:
// EscapeCommFunction(m_hFileHandle,CLRRTS);//半双工
if(nRet!=1) Purge(PURGE_TXABORT|PURGE_TXCLEAR);//取消写操作
return nRet;
}
/*
很简单的设置串口的程序,无参数接口,还需修改
*/
BOOL CYsComm::SetComm(int iBaud)
{
m_iBaud=iBaud;
DCB dcb;
BOOL fSuccess;
fSuccess = GetCommState(m_hFileHandle, &dcb);
if (!fSuccess)
{
// Handle the error.
TRACE(_TEXT("GetCommState failed with error %d.\n"), GetLastError());
return FALSE;
}
//BuildCommDCB("2400,n,8,1", &dcb)) //another way to set DCB
dcb.fBinary=TRUE;
dcb.BaudRate = iBaud; // set the baud rate
dcb.ByteSize = 8; // data size, xmit, and rcv
dcb.Parity = 0;//EVENPARITY;// Even parity bit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -