www.pudn.com > GPSComEVC3.0.rar > Serial.cpp


// Serial.cpp: implementation of the CSerial class. 
 
// 
 
////////////////////////////////////////////////////////////////////// 
 
  
 
#include "stdafx.h" 
#include "Serial.h" 
#include "GpsNavDoc.h"  
#include "MainFrm.h" 
 
 
#include  
 
 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
 
  
TCHAR* GetUnicodeString(const char *s); 
 
////////////////////////////////////////////////////////////////////// 
 
// Construction/Destruction 
 
////////////////////////////////////////////////////////////////////// 
  
 
CSerial::CSerial() 
{ 
	m_strReceived=""; 
	m_index=0; 
}  
 
CSerial::~CSerial() 
{ 
       if(hPort != INVALID_HANDLE_VALUE) 
              ClosePort(hPort); 
}  
 
BOOL CSerial::OpenPort(CWnd* pPortOwner,UINT  portnr,UINT  baud,char  parity,UINT  databits,UINT  stopbits,DWORD dwCommEvents,UINT  buffersize) 
{ 
	   if(!(portnr > 0 && portnr < 5&&pPortOwner != NULL)) 
		   return FALSE; 
       DWORD dwError,dwThreadID; 
	   CString str=""; 
	   TCHAR *szPort = new TCHAR[50]; 
       if(hPort!= NULL) 
       { 
			CloseHandle(hPort); 
			hPort = NULL; 
       } 
	   str.Format( _T("COM%d:"), portnr); 
	   lstrcpy(szPort,(LPCTSTR)str); 
 
       //打开串口 
       hPort = CreateFile (szPort,  
						GENERIC_READ | GENERIC_WRITE, 
						0,  
						NULL,  
						OPEN_EXISTING, 
						0,  
						NULL); 
       //如果打开端口出错, 返回FALSE 
       if ( hPort == INVALID_HANDLE_VALUE ) 
       { 
              //不能打开端口 
              CString strError; 
              strError.Format(_T("Unable to open com%d, Error No.=%d"),portnr, GetLastError()); 
              MessageBox (NULL, strError,      TEXT("Error!"), MB_OK); 
			  delete [] szPort; 
			  //delete [] szBaud; 
              return FALSE; 
       } 
       //指定端口监测的事件集 
       SetCommMask (hPort, dwCommEvents); 
       //分配设备缓冲区 
       SetupComm(hPort,buffersize,buffersize); 
       //初始化缓冲区中的信息 
       PurgeComm(hPort,PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);  
 
       //配置串行端口 
       if(!InitDCB(baud)) 
              return FALSE;  
 
       //设置端口超时值 
       if(!InitCommTimeouts()) 
              return FALSE; 
  
       //设置端口上指定信号的状态 
       // SETDTR: 发送DTR (data-terminal-ready)信号 
       // SETRTS: 发送RTS (request-to-send)信号 
 
       EscapeCommFunction (hPort, SETDTR); 
       EscapeCommFunction (hPort, SETRTS); 
 
        //创建一个从串口读取数据的线程 
       if (hReadThread = CreateThread (NULL, 0, ReadPortThread, this, 0,&dwThreadID)) 
       { 
 
       } 
       else 
       { 
              //不能创建线程 
              MessageBox (NULL, TEXT("Unable to create the read thread"),TEXT("Error!"), MB_OK); 
              dwError = GetLastError (); 
              return FALSE; 
       } 
       m_bConnected=TRUE; 
	   m_pOwner=pPortOwner; 
       return TRUE; 
} 
 
  
 
DWORD CSerial::WritePort(TCHAR *buf,DWORD dwCharToWrite) 
{ 
       BOOL fWriteState; 
       DWORD dwBytesWritten;  
       //写入数据 
       fWriteState=WriteFile(hPort,buf,dwCharToWrite*sizeof(TCHAR),&dwBytesWritten,NULL); 
       if(!fWriteState) 
       { 
              //不能写数据 
              MessageBox(NULL,TEXT("Can't Write String to Comm"),TEXT("Error!"),MB_OK); 
              dwBytesWritten=0; 
       } 
       return dwBytesWritten; 
}  
 
BOOL CSerial::ClosePort(HANDLE hCommPort) 
{ 
       if (hCommPort != INVALID_HANDLE_VALUE) 
       { 
              //设置连接属性为FALSE 
              m_bConnected=FALSE; 
              //结束线程中WaitCommEvent的等待 
              SetCommMask(hPort,0); 
              //阻塞至线程停止 
 
              if(hReadThread) 
              { 
                     TerminateThread(hReadThread,0); 
                     CloseHandle(hReadThread); 
              } 
 
              //清除端口上指定信号的状态 
              EscapeCommFunction(hPort,CLRDTR); 
              EscapeCommFunction(hPort,CLRRTS); 
              //清除驱动程序内部的发送和接收队列 
 
              PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR); 
              //关闭串口 
              CloseHandle (hCommPort); 
              hCommPort = INVALID_HANDLE_VALUE; 
              return TRUE; 
       } 
       else 
       { 
              return TRUE; 
       } 
}  
 
BOOL CSerial::InitDCB(UINT  baud) 
{ 
       DCB PortDCB; 
       DWORD dwError;  
 
       PortDCB.DCBlength = sizeof (DCB);  
 
       //得到端口的默认设置信息 
       GetCommState (hPort, &PortDCB);  
 
       //改变DCB结构设置 
       PortDCB.BaudRate = baud;               //波特率 
       PortDCB.fBinary = TRUE;                //Win32不支持非二进制串行传输模式,必须为TRUE 
       PortDCB.fParity = TRUE;                 //启用奇偶校验 
       PortDCB.fOutxCtsFlow = TRUE;            //串行端口的输出由CTS线控制 
       PortDCB.fOutxDsrFlow = FALSE;           //关闭串行端口的DSR流控制 
       PortDCB.fDtrControl = DTR_CONTROL_ENABLE;   //启用DTR线 
       PortDCB.fDsrSensitivity = FALSE;        //如果设为TRUE将忽略任何输入的字节,除非DSR线被启用 
       //PortDCB.fTXContinueOnXoff = TRUE;       //当为TRUE时,如果接收缓冲区已满且驱动程序已传送XOFF字符,将使驱动程序停止传输字符 
 
       PortDCB.fTXContinueOnXoff = FALSE; 
       PortDCB.fOutX = FALSE;                  //设为TRUE指定XON/XOFF控制被用于控制串行输出  
       PortDCB.fInX = FALSE;                   //设为TRUE指定XON/XOFF控制被用于控制串行输入  
       PortDCB.fErrorChar = FALSE;             //WINCE串行驱动程序的默认执行将忽略这个字段  
       PortDCB.fNull = FALSE;                  //设为TRUE将使串行驱动程序忽略收到的空字节  
       PortDCB.fRtsControl = RTS_CONTROL_ENABLE;   //启用RTS线  
       PortDCB.fAbortOnError = FALSE;          //WINCE串行驱动程序的默认执行将忽略这个字段 
       PortDCB.ByteSize = 8;                   //每字节的位数  
       PortDCB.Parity = NOPARITY;              //无奇偶校验  
       PortDCB.StopBits = ONESTOPBIT;          //每字节一位停止位   
 
       //根据DCB结构配置端口  
       if (!SetCommState (hPort, &PortDCB)) 
       { 
              //不能配置串行端口 
              MessageBox (NULL, TEXT("Unable to configure the serial port"),TEXT("Error!"), MB_OK); 
              dwError = GetLastError (); 
              return FALSE; 
       } 
       return TRUE; 
} 
  
 
BOOL CSerial::InitCommTimeouts() 
{ 
       COMMTIMEOUTS CommTimeouts; 
       DWORD dwError; 
  
       //得到超时参数 
       GetCommTimeouts (hPort, &CommTimeouts);  
 
       //改变COMMTIMEOUTS结构设置 
       CommTimeouts.ReadIntervalTimeout =MAXDWORD;//1000; 
       CommTimeouts.ReadTotalTimeoutMultiplier = 0;//1000; 
       CommTimeouts.ReadTotalTimeoutConstant = 0;//1000; 
       CommTimeouts.WriteTotalTimeoutMultiplier = 0; 
       CommTimeouts.WriteTotalTimeoutConstant = 5000;//5000; 
  
 
       //设置端口超时值  
       if (!SetCommTimeouts (hPort, &CommTimeouts)) 
       { 
              //不能设置超时值 
              MessageBox (NULL, TEXT("Unable to set the time-out parameters"), TEXT("Error"), MB_OK); 
              dwError = GetLastError (); 
              return FALSE; 
       } 
       return TRUE; 
} 
 
DWORD WINAPI ReadPortThread(LPVOID pParam) 
{ 
							  
	POSITION po=AfxGetApp()->GetFirstDocTemplatePosition(); 
	CDocTemplate *pDocTem=AfxGetApp()->GetNextDocTemplate(po); 
	po=pDocTem->GetFirstDocPosition(); 
	CGpsNavDoc *pDoc=(CGpsNavDoc *)pDocTem->GetNextDoc(po); 
 
	CSerial *port = (CSerial*)pParam; 
 
    BOOL fReadState; 
    DWORD dwCommModemStatus; 
 
    DWORD dwLength,dwreadedLength; 
	dwreadedLength=0; 
    COMSTAT ComStat; 
    DWORD dwErrorFlags; 
	unsigned char RXBuff; 
    /*char* buf=new char[256];*/ 
	int nTemp=0; 
	BOOL bResult; 
	int i=0; 
	unsigned long r_len = 0; 
	OVERLAPPED _ro; // 重叠I/O 
	 
	_ro.Offset = 0; 
	_ro.OffsetHigh = 0; 
 
	// create events 
	DWORD CommEvent = 0; 
	_ro.hEvent = NULL; 
	if (_ro.hEvent != NULL) 
		ResetEvent(_ro.hEvent); 
	_ro.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
	CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd(); 
	PurgeComm(port->hPort, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); 
    while (port->hPort != INVALID_HANDLE_VALUE)  
    { 
           //等待串口的事件发生 
			//PurgeComm(port->hPort,PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);  
 
			//PurgeComm(port->hPort,PURGE_RXCLEAR); 
			// 指定监视的端口事件 
			//SetCommMask (port->hPort, EV_RXCHAR | EV_CTS /*| EV_DSR | EV_RLSD | EV_RING */); 
 
           bResult =WaitCommEvent (port->hPort, &dwCommModemStatus, &_ro);//(NULL); 
		   if(!bResult) 
			   continue; 
 
		   ClearCommError(port->hPort,&dwErrorFlags,&ComStat); 
		   if (ComStat.cbInQue == 0) 
			   continue;			 
		    
			//SetCommMask (port->hPort, EV_RXCHAR | EV_CTS /*| EV_DSR | EV_RING */);//// 
			if ((dwCommModemStatus & EV_RXCHAR) == EV_RXCHAR)  
			{//有数据信号 
				pDoc->UpdateAllViews(NULL); 
 
                  ClearCommError(port->hPort,&dwErrorFlags,&ComStat); 
                  //cbInQue返回在串行驱动程序输入队列中的字符数 
                  dwLength=ComStat.cbInQue; 
                  if(dwLength>0) 
				  {	 
					  //从串口读取数据 
                      fReadState=ReadFile(port->hPort, 
											/*buf,*/&RXBuff, 
											/*dwLength,*/1, 
											&dwreadedLength, 
											&_ro); 
											//NULL); 
                      if(!fReadState) 
                      { 
                             //不能从串口读取数据 
                             MessageBox(NULL,TEXT("Error in read from serial port"),TEXT("Read Error"),MB_OK); 
                      } 
                      else 
                      { 
							char ch=(char)RXBuff; 
 
							if (ch == 10 && port->m_strReceived[port->m_index-1] == 13) 
							{ 
 								port->m_strReceived+=ch; 
								port->m_index++; 
								i=port->m_strReceived.Find(_T("$GPGGA")); 
								if(i==-1) 
								{ 
									return 0; 
								} 
								port->m_strReceived=port->m_strReceived.Mid(i);	 
								pMain->m_strReceived=port->m_strReceived; 
								::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM)0, (LPARAM) port->m_nPortNr); 
								port->m_index=0; 
								port->m_strReceived=""; 
							} 
							else if (port->m_index<1000) 
							{ 
								port->m_strReceived+= ch; 
								port->m_index++; 
							} 
							else 
							{ 
								port->m_index=0; 
							} 
                      } 
                      //delete[] buf; 
                  } 
           } 
           GetCommModemStatus (port->hPort, &dwCommModemStatus); 
		   nTemp=1;///////// 
    } 
	CloseHandle(_ro.hEvent); 
	pMain->m_wndStatusBar.SetPaneText(0,_T("Thread End...."),TRUE); 
    return 0; 
} 
 
 
// Restart the comm thread 
// 
BOOL CSerial::RestartMonitoring() 
{ 
	ResumeThread(hPort); 
	return TRUE; 
} 
// 
// Suspend the comm thread 
// 
BOOL CSerial::StopMonitoring() 
{ 
	SuspendThread(hPort);  
	return TRUE;	 
}