www.pudn.com > AtModem.rar > 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 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 
  dcb.StopBits = ONESTOPBIT;  // one stop bit 
  dcb.fAbortOnError=FALSE; 
 
  //dcb.EofChar=1; 
	//dcb.fRtsControl=DTR_CONTROL_DISABLE; 
  if(m_bSemiduplex) 
	dcb.fRtsControl=RTS_CONTROL_TOGGLE;//半双工 
  else dcb.fRtsControl=RTS_CONTROL_ENABLE;//用来控制modem 
 
  SetupComm(m_hFileHandle,2048,2048);//setup comm buffer size 
 
  /*  COMMTIMEOUTS  TimeOuts; 
	//Setup timeout 
	TimeOuts.ReadIntervalTimeout=MAXDWORD;  
	TimeOuts.ReadTotalTimeoutMultiplier=0;  
	TimeOuts.ReadTotalTimeoutConstant=0;  
	TimeOuts.WriteTotalTimeoutMultiplier=100;  
	TimeOuts.WriteTotalTimeoutConstant=1000; 
	SetCommTimeouts(m_hFileHandle, &TimeOuts); 
*/ 
 
  Purge(PURGE_ALL); 
  fSuccess = SetCommState(m_hFileHandle, &dcb); 
 
 
  if (!fSuccess)  
  { 
      // Handle the error. 
      TRACE(_TEXT("SetCommState failed with error %d.\n"), GetLastError()); 
      return FALSE; 
  } 
//  EscapeCommFunction(m_hFileHandle,CLRRTS);//半双工 
  return TRUE; 
} 
 
/*************************2001.10.31 ycat ********************************************* 
FUNCTION: BOOL CYsComm::SetEvent(DWORD dwEvent) 
 
PURPOSE: 设置要等待的串口事件 
 
PARAMETERS: 
		dwEvent:要等待的事件 
 
		EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |\ 
		EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY  
 
RETURN VALUE:  
		TRUE表示操做成功,FALSE表示操作失败 
 
COMMENTS: 目前只支持一种状态,说明见下一WaitEvent() 
*********************************************************************************/ 
BOOL CYsComm::SetEvent(DWORD dwEvent) 
{ 
	return SetCommMask(m_hFileHandle,dwEvent); 
} 
/*************************2001.10.31 ycat ********************************************* 
FUNCTION: int CYsComm::WaitEvent(DWORD* pwdEvent,DWORD dwTimeOut) 
 
PURPOSE: 等待收到某个串口事件 
 
PARAMETERS: 
		pwdEvent:所等到的事件 
		dwTimeOut:超时设置 
 
RETURN VALUE:  
    -1: 除timeout外其它错误 
	 1:等待成功 
	-2: 表示timeout 
 
COMMENTS:  
		Note   The Microsoft Win32 SDK Knowledge Base documents  
	a problem with Windows 95 and the EV_RING flag. 
	The above code never returns in Windows 95 because 
	the EV_RING event is not detected by the system; 
	Windows NT properly reports the EV_RING event. 
	Please see the Win32 SDK Knowledge Base for more  
	information on this bug. 
 
		There are two interesting side effects of SetCommMask 
	and WaitCommEvent. First, if the communications port  
	is open for nonoverlapped operation, WaitCommEvent  
	will be blocked until an event occurs.  
 
		If another thread calls SetCommMask to set a new event mask, 
	that thread will be blocked on the call to SetCommMask.  
	The reason is that the original call to WaitCommEvent  
	in the first thread is still executing.  
 
		The call to SetCommMask blocks the thread until 
	the WaitCommEvent function returns in the first  
	thread. This side effect is universal for ports 
	open for nonoverlapped I/O. If a thread is blocked 
	on any communications function and another thread 
	calls a communications function, the second thread 
	is blocked until the communications function returns  
	in the first thread.  
 
		The second interesting note about 
	these functions is their use on a port open for overlapped  
	operation. If SetCommMask sets a new event mask, 
	any pending WaitCommEvent will complete successfully, 
	and the event mask produced by the operation is NULL. 
 
	如果用重叠IO,则SetCommMask使正在等待的WaitCommEvent马上返回, 
	而且返回的事件为NULL 
 
	出错时返回负数,但DWORD为无符号数,会不会出问题? 
	目前只支持等待一个事件 
**********************************************************************/ 
int CYsComm::WaitEvent(DWORD* pwdEvent,DWORD dwTimeOut) 
{ 
	  if(m_hFileHandle==NULL) return -1; 
	  DWORD nRet; 
	  DWORD dwRes; 
	  DWORD dwOvRes; 
	  int i; 
	   
//	  if(!SetCommMask(m_hFileHandle,EV_RXCHAR)) 
//		  return -1;//清除以前事件 
	 // WaitCommEvent(m_hFileHandle,pwdEvent,NULL); 
 
      // Issue a status event check if one hasn't been issued already. 
      if (WaitCommEvent(m_hFileHandle,pwdEvent,&m_overlappedEvent)) 
	  { 
            // WaitCommEvent returned immediately. 
            // Deal with status event as appropriate. 
            DoStateEvent(*pwdEvent);  
			nRet=1; 
			goto Exit; 
      } 
 
	  i=GetLastError(); 
	  // error in WaitCommEvent; abort 
      if (i!= ERROR_IO_PENDING) 
	  { 
		  nRet=-1; 
		  TRACE(_TEXT("GetlastError %d\n"),i); 
		  goto Exit; 
	  } 
      // Check on overlapped operation. 
      // Wait a little while for an event to occur. 
      dwRes = WaitForSingleObject(m_overlappedEvent.hEvent, dwTimeOut); 
      switch(dwRes) 
       { 
        // Event occurred. 
	       case WAIT_OBJECT_0:  
                if (GetOverlappedResult(m_hFileHandle,&m_overlappedEvent,&dwOvRes,FALSE)) 
				{ 
                    // Status event is stored in the event flag 
                    // specified in the original WaitCommEvent call. 
                    // Deal with the status event as appropriate. 
                    DoStateEvent(*pwdEvent); 
					nRet=1; 
					goto Exit; 
				} 
				else  
				{ 
                    // An error occurred in the overlapped operation; 
                    // call GetLastError to find out what it was 
                    // and abort if it is fatal. 
					TRACE(_TEXT("An error occurred in the overlapped operation\nGetLastError is %d\n "), 
						GetLastError()); 
					nRet=-1; 
					goto Exit; 
				} 
                break; 
             case WAIT_TIMEOUT: 
				nRet=-2; 
				goto Exit; 
                break;                        
             default: 
				nRet=-1; 
				goto Exit; 
         } 
Exit: 
	return nRet; 
} 
/* 
对串口事件进行处理,还要修改 
返回值无意义 
*/ 
BOOL CYsComm::DoStateEvent(DWORD dwEvtMask) 
{ 
	if(dwEvtMask==NULL) return TRUE; 
//dwEvtMask可能会为NULL 
		if (dwEvtMask & EV_BREAK) //检测到转入的中止 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_BREAK,m_nPort); 
		} 
		if (dwEvtMask & EV_CTS) //CTS (清除发送)信号改变状态 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_CTS,m_nPort); 
		} 
		if (dwEvtMask & EV_DSR) //DSR (数据设置就绪) 信号改变状态 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_DSR,m_nPort); 
		} 
		if (dwEvtMask & EV_ERR) //发生线路状态错误 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_ERR,m_nPort); 
		} 
		if (dwEvtMask & EV_RING)//检测到振铃 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_RING,m_nPort); 
		} 
		if (dwEvtMask & EV_RLSD)//RLSD(接收线路信号检测)信号改变状态 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_RLSD,m_nPort); 
		} 
		if (dwEvtMask & EV_RXCHAR)//收到一个字符,并放入输入缓冲区 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_RXCHAR,m_nPort); 
		} 
		if (dwEvtMask & EV_RXFLAG) //收到事件字符(DCB结构的EvtChar成员),并放入输入缓冲区 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_RXFLAG,m_nPort); 
		} 
		if (dwEvtMask & EV_TXEMPTY)//输出缓冲区最后一个字符发送出去 
		{ 
			if(m_hWnd)PostMessage(m_hWnd,WM_YSCOMM_MESSAGE,WM_EV_TXEMPTY,m_nPort); 
		} 
	return TRUE; 
} 
 
//一个例子,供参考 
/*************************2001.10.30 ycat ********************************************* 
FUNCTION: UINT CATModem::ReadCommThread(LPVOID pParam) 
 
PURPOSE: 线程函数,把串口读入缓冲区的字符,写到自己维护的缓冲区中,并判断断线 
 
PARAMETERS: 
		pParam:指向CATModem类 
 
RETURN VALUE: 
 
COMMENTS: 断线的处理,也许还要改进 
**********************************************************************/ 
 
 
/*************************2001.11.06 ycat ********************************************* 
FUNCTION: int CYsComm::ReadComm( 
						PBYTE pByteRead, 
						DWORD dwCount, 
						DWORD* dwHaveReaded, 
						DWORD nTimeOut) 
 
PURPOSE: 在dwReadTimeOut里读到dwCount个字符,既使超时, 
		 在缓冲区里也有在超时之前读出来的数据 
 
PARAMETERS: 
		pByteRead:			存放返回数据的字符串缓冲区 
		dwCount:			希望要读到的字符个数 
		dwHaveReaded:		已经读到的数据 
		dwReadTimeOut:		超时的时间 
 
RETURN VALUE: 
	   -1: 除-2,-3之外的其它错误 
		1:表示写com口成功 
		-2:表示超时 
		-3: 表示读操作被停止 
 
 
COMMENTS: 
        不能支持多线程 
 
		即使没有读够dwCount个数,缓冲区里的字符仍然有效 
 
		注意和ReadIn()的区别 
**********************************************************************/ 
/*int CYsComm::ReadComm(PBYTE pByteRead,DWORD dwCount, 
			DWORD* dwHaveReaded,DWORD nTimeOut) 
{ 
	int nRet; 
	DWORD dwTimeAfter; 
	DWORD dwTimeUsed; 
	DWORD dwTimeBefore; 
 
	for(DWORD i=0;inTimeOut) 
		{ 
			if(idwInterTimeOut) 
		{ 
			if(i