首页 » 技术分享 » 串口类CSerialPort(2010-03-05)

串口类CSerialPort(2010-03-05)

 

<Header File>

#ifndef __SERIALPORTTOOL_H__
#define __SERIALPORTTOOL_H__

#define WM_COMM_BREAK_DETECTED WM_USER+1
#define WM_COMM_CTS_DETECTED WM_USER+2
#define WM_COMM_DSR_DETECTED WM_USER+3
#define WM_COMM_ERR_DETECTED WM_USER+4
#define WM_COMM_RING_DETECTED WM_USER+5
#define WM_COMM_RLSD_DETECTED WM_USER+6
#define WM_COMM_RXCHAR WM_USER+7
#define WM_COMM_RXFLAG_DETECTED WM_USER+8
#define WM_COMM_TXEMPTY_DETECTED WM_USER+9

class CSerialPort
{
public:
 CSerialPort();
 virtual ~CSerialPort();
 BOOL InitPort(CWnd* pPortOwner,UINT portnr=1,UINT baud=57600,char parity='N',
  UINT databits=8,UINT stopbits=1,DWORD dwCommEvents=EV_RXCHAR|EV_CTS,
  UINT nBufferSize=2048);
 BOOL StartMonitoring();
 BOOL RestartMonitoring();
 BOOL StopMonitoring();
 DWORD GetWriteBufferSize();
 DWORD GetCommEvents();
 DCB   GetDCB();
 void WriteToPort(unsigned char* string);
 void WriteToPort(unsigned char* string,int n);
 void WriteToPort(LPCTSTR string);
 void WriteToPort(LPCTSTR string,int n);
 UINT m_nWriteSize;
 
protected:
 void ProcessErrorMessage(char* ErrorText);
 static UINT CommThread(LPVOID pParam);
 static void ReceiveChar(CSerialPort* port,COMSTAT comstat);
 static void WriteChar(CSerialPort* port);
 //thread
 CWinThread* m_Thread;
 //synchronisation objects
 CRITICAL_SECTION m_csCommunicationSync;
 BOOL m_bThreadAlive;
 //handles
 HANDLE m_hShutdownEvent;
 HANDLE m_hComm;
 HANDLE m_hWriteEvent;
 HANDLE m_hEventArray[3];
 //structures
 OVERLAPPED m_ov;
 COMMTIMEOUTS m_CommTimeOuts;
 DCB m_dcb;
 //owner window
 CWnd* m_pOwner;
 //misc
 UINT m_nPortNr;
 unsigned char* m_szWriteBuffer;
 DWORD m_dwCommEvents;
 DWORD m_nWriteBufferSize;
};
#endif __SERIALPORTTOOL_H__

</Header File>

 

<Source File>

#include "stdafx.h"
#include "SerialPortTool.h"
#include <assert.h>
//Constructor
CSerialPort::CSerialPort()
{
m_hComm=NULL;
m_Thread = NULL;
m_ov.Offset=0;
m_ov.OffsetHigh=0;
m_ov.hEvent=NULL;
m_hWriteEvent=NULL;
m_hShutdownEvent=NULL;
m_szWriteBuffer=NULL;
m_bThreadAlive=FALSE;
m_nWriteSize =0;
 //handles
m_hShutdownEvent=NULL;
m_hComm=NULL;
m_hWriteEvent=NULL;
m_nPortNr=0;
m_szWriteBuffer=NULL;
//m_dwCommEvents=0xffffffff;
//m_nWriteBufferSize=0xffffffff;
}
CSerialPort::~CSerialPort()
{
 do
 {
 SetEvent(m_hShutdownEvent);
 }while(m_bThreadAlive);
 if(m_hComm!=NULL)
 {
  CloseHandle(m_hComm);
  m_hComm=NULL;
 }
 if(m_hShutdownEvent!=NULL)
  CloseHandle(m_hShutdownEvent);
 if(m_ov.hEvent=!NULL)
  CloseHandle(m_ov.hEvent);
 if(m_hWriteEvent!=NULL)
  CloseHandle(m_hWriteEvent);
 TRACE("Thread ended/n");
 delete [] m_szWriteBuffer;
}
BOOL CSerialPort::InitPort(CWnd* pPortOwner,
         UINT portnr,
         UINT baud,
         char parity,
         UINT databits,
         UINT stopbits,
         DWORD dwCommEvents,
         UINT writebuffersize)
{
// assert(portnr>0 && portnr<5);
// assert(pPortOwner!=NULL);
 //if the thread is alive :kill
 if(m_bThreadAlive)
 {
  do
  {
   SetEvent(m_hShutdownEvent);
  }while(m_bThreadAlive);
  //TRACE("Thread ended/n");
 }
 //create events
 if(m_ov.hEvent!=NULL)
  ResetEvent(m_ov.hEvent);
 else
  m_ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 if(m_hWriteEvent!=NULL)
  ResetEvent(m_hWriteEvent);
 else
  m_hWriteEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 if(m_hShutdownEvent!=NULL)
  ResetEvent(m_hShutdownEvent);
 else
  m_hShutdownEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 m_hEventArray[0]=m_hShutdownEvent;
 m_hEventArray[1]=m_ov.hEvent;
 m_hEventArray[2]=m_hWriteEvent;
 //initialize critical section
 InitializeCriticalSection(&m_csCommunicationSync);
 //set buffersize for writing and save the owner
 m_pOwner=pPortOwner;
 if(m_szWriteBuffer!=NULL)
  delete [] m_szWriteBuffer;
 m_szWriteBuffer=new unsigned char[writebuffersize];
 m_nPortNr=portnr;
 m_nWriteBufferSize=writebuffersize;
 m_dwCommEvents=dwCommEvents;
 BOOL bResult=FALSE;
 char *szPort=new char[50];
 char *szBaud=new char[50];
 //now it critical!
 EnterCriticalSection(&m_csCommunicationSync);
 //if the port is already opened:close it
 if(m_hComm!=NULL)
 {
 CloseHandle(m_hComm);
 m_hComm=NULL;
 }
 //prepare port strings
 sprintf(szPort,"COM%d",portnr);
 sprintf(szBaud,"baud=%d parity=%c data=%d stop=%d",baud,parity,databits,stopbits);
 //get handle to the port
 m_hComm=CreateFile(szPort,
     GENERIC_READ|GENERIC_WRITE,
     0,
     NULL,
     OPEN_EXISTING,
     FILE_FLAG_OVERLAPPED,
     0);
 if(m_hComm==INVALID_HANDLE_VALUE)
 {
 delete [] szPort;
 delete [] szBaud;
 return FALSE;
 }
 //set the timeout values
 m_CommTimeOuts.ReadIntervalTimeout=1000;
 m_CommTimeOuts.ReadTotalTimeoutConstant=1000;
 m_CommTimeOuts.ReadTotalTimeoutMultiplier=1000;
 m_CommTimeOuts.WriteTotalTimeoutConstant=1000;
 m_CommTimeOuts.WriteTotalTimeoutMultiplier=1000;
 //configure
 /* SetCommTimeouts(m_hComm,&m_CommTimeOuts);
 SetCommMask(m_hComm,dwCommEvents);
 GetCommState(m_hComm,&m_dcb);
 m_dcb.fRtsControl=RTS_CONTROL_ENABLE;
 BuildCommDCB(szBaud,&m_dcb);
 SetCommState(m_hComm,&m_dcb);
*/
 if(SetCommTimeouts(m_hComm,&m_CommTimeOuts))
 {
  if(SetCommMask(m_hComm,dwCommEvents))
  {
   if(GetCommState(m_hComm,&m_dcb))
   {
    m_dcb.fRtsControl=RTS_CONTROL_ENABLE;//set RTS bit high
    if(BuildCommDCB(szBaud,&m_dcb))
    {
     if(SetCommState(m_hComm,&m_dcb))
      ;
     else
      ProcessErrorMessage("SetCommState()");
    }
    else
     ProcessErrorMessage("BuildCommDCB()");
   }
   else
    ProcessErrorMessage("GetCommState()");
  }
  else
   ProcessErrorMessage("SetCommMask()");
 }
 else
  ProcessErrorMessage("SetCommTimeouts()");
 delete [] szPort;
 delete [] szBaud;
 //flush the port
 PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
 //release critical section
 LeaveCriticalSection(&m_csCommunicationSync);
 TRACE("Initialisation for communicationport %d completed./nUse Startmonitor to communicate./n",portnr);
  return TRUE;
}
UINT CSerialPort::CommThread(LPVOID pParam)
{
 CSerialPort *port=(CSerialPort*)pParam;
 port->m_bThreadAlive=TRUE;
 DWORD BytesTransfered=0;
 DWORD Event=0;
 DWORD CommEvent=0;
 DWORD dwError=0;
 COMSTAT comstat;
 BOOL bResult=TRUE;
 if(port->m_hComm)
  PurgeComm(port->m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
 //begin forever loop.
 for(;;)
 {
 bResult=WaitCommEvent(port->m_hComm,&Event,&port->m_ov);
 if(!bResult)
  {
   switch(dwError=GetLastError())
   {
   case ERROR_IO_PENDING:
    {
    break;
    }
   case 87:
    {
    break;
    }
   default:
    {
    port->ProcessErrorMessage("WaitCommEvent()");
    break;
    }
   }
  }
 else
  {
  bResult=ClearCommError(port->m_hComm,&dwError,&comstat);
  if(comstat.cbInQue==0)
   continue;
  }
 Event=WaitForMultipleObjects(3,port->m_hEventArray,FALSE,INFINITE);
 switch(Event)
 {
 case 0:
  {
  port->m_bThreadAlive=FALSE;
  AfxEndThread(100);
  break;
  }
 case 1:
  {
  GetCommMask(port->m_hComm,&CommEvent);
  /*if(CommEvent&EV_CTS)
   ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_CTS_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);
  if(CommEvent&EV_RXFLAG)
   ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RXFLAG_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);
  if(CommEvent&EV_BREAK)
   ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_BREAK_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);
  if(CommEvent&EV_ERR)
   ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_ERR_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);
  if(CommEvent&EV_RING)
   ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RING_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);
  */
  if(CommEvent&EV_RXFLAG)
   ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RXFLAG_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);
  if(CommEvent&EV_RXCHAR)
   ReceiveChar(port,comstat);
  break;
  }
 case 2:
  {
  WriteChar(port);
  break;
  }
 }
}
return 0;
}
BOOL CSerialPort::StartMonitoring()
{
if(!(m_Thread=AfxBeginThread(CommThread,this)))
 return FALSE;
 m_Thread->SetThreadPriority(THREAD_PRIORITY_TIME_CRITICAL);
//TRACE("Thread started/n");
return TRUE;
}
BOOL CSerialPort::RestartMonitoring()
{
TRACE("Thread resumed/n");
m_Thread->ResumeThread();
return TRUE;
}
BOOL CSerialPort::StopMonitoring()
{
TRACE("Thread suspended/n");
m_Thread->SuspendThread();
return TRUE;
}
void CSerialPort::ProcessErrorMessage(char* ErrorText)
{
char *temp=new char[200];
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
     NULL,
     GetLastError(),
     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
     (LPTSTR)& lpMsgBuf,
     0,
     NULL
     );
sprintf(temp,"WARNING:%s Failed with the following error:/n%s/nPort:%d/n",
  (char*)ErrorText,lpMsgBuf,m_nPortNr);
MessageBox(NULL,temp,"Application Error",MB_ICONSTOP);
LocalFree(lpMsgBuf);
if(temp)
 delete [] temp;
return;
}
void CSerialPort::WriteChar(CSerialPort* port)
{
BOOL bWrite =TRUE;
BOOL bResult=TRUE;
DWORD BytesSent=0;
ResetEvent(port->m_hWriteEvent);
EnterCriticalSection(&port->m_csCommunicationSync);
if(bWrite)
{
 port->m_ov.Offset=0;
 port->m_ov.OffsetHigh=0;
 PurgeComm(port->m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
 bResult=WriteFile(port->m_hComm,
  port->m_szWriteBuffer,
 // strlen((char*)port->m_szWriteBuffer),
  port->m_nWriteSize,
  &BytesSent,
  &port->m_ov);
 if(!bResult)
 {
  DWORD dwError=GetLastError();
  switch(dwError)
  {
  case ERROR_IO_PENDING:
   {
    BytesSent=0;
    bWrite=FALSE;
    break;
   }
  default:
   {
    port->ProcessErrorMessage("WriteFile()");
   }
  }
 
 }
 else
 {
  LeaveCriticalSection(&port->m_csCommunicationSync);
 }
}
if(!bWrite)
{
 bWrite=TRUE;
 bResult=GetOverlappedResult(port->m_hComm,
  &port->m_ov,
  &BytesSent,
  TRUE);
 if(!bResult)
 {
  port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");
 }
}
//if(BytesSent!=strlen((char*)port->m_szWriteBuffer))
if(BytesSent!=port->m_nWriteSize)
{
 TRACE("WARNING:WriteFile() error..Bytes Sent:%d; Message Length: %d/n",BytesSent,strlen((char*)port->m_szWriteBuffer));
}
return;
}

void CSerialPort::ReceiveChar(CSerialPort* port,COMSTAT comstat)
{
 BOOL bRead=TRUE;
 BOOL bResult=TRUE;
 DWORD dwError=0;
 DWORD BytesRead=0;
 unsigned char RXBuff;
 for(;;)
 {
  EnterCriticalSection(&port->m_csCommunicationSync);
  bResult=ClearCommError(port->m_hComm,&dwError,&comstat);
  LeaveCriticalSection(&port->m_csCommunicationSync); 
   if(comstat.cbInQue==0)
  {
   break;
  }
  EnterCriticalSection(&port->m_csCommunicationSync);
  if(bRead)
  {
   bResult=ReadFile(port->m_hComm,
    &RXBuff,
    1,
    &BytesRead,
    &port->m_ov);
   if(!bResult)
   {
    switch(dwError=GetLastError())
    {
    case ERROR_IO_PENDING:
     {
      bRead=FALSE;
      break;
     }
    default:
     {
      port->ProcessErrorMessage("ReadFile()");
      break;
     }
    }
   }
   else
   {
    bRead=TRUE;
   }
  }
  if(!bRead)
  {
   bRead=TRUE;
   bResult=GetOverlappedResult(port->m_hComm,
    &port->m_ov,
    &BytesRead,
    TRUE);
  /* if(!bResult)
   {
    port->ProcessErrorMessage("GetOverlappedResult() in ReadFile()");
   }*/
  }
  LeaveCriticalSection(&port->m_csCommunicationSync);

  ::SendMessage((port->m_pOwner)->m_hWnd,WM_COMM_RXCHAR,(WPARAM)RXBuff,(LPARAM)port->m_nPortNr);

 }
 return;
}
void CSerialPort::WriteToPort(unsigned char* string)
{
 assert(m_hComm!=0);
 memset(m_szWriteBuffer,0,sizeof(m_szWriteBuffer));
 memcpy(m_szWriteBuffer,string,1);
 m_nWriteSize=1;
 SetEvent(m_hWriteEvent);
 return;
}
void CSerialPort::WriteToPort(unsigned char* string,int n)
{
 assert(m_hComm!=0);
 memset(m_szWriteBuffer,0,sizeof(m_szWriteBuffer));
 memcpy(m_szWriteBuffer,string,n);
 m_nWriteSize=n;
 SetEvent(m_hWriteEvent);
 return;
}

void CSerialPort::WriteToPort(LPCTSTR string)
{
 assert(m_hComm!=0);
 memset(m_szWriteBuffer,0,sizeof(m_szWriteBuffer));
 memcpy(m_szWriteBuffer,string,1);
 m_nWriteSize=1;
 SetEvent(m_hWriteEvent);
 return;
}
void CSerialPort::WriteToPort(LPCTSTR string,int n)
{
 assert(m_hComm!=0);
 memset(m_szWriteBuffer,0,sizeof(m_szWriteBuffer));
 memcpy(m_szWriteBuffer,string,n);
 m_nWriteSize=n;
 SetEvent(m_hWriteEvent);
 return;
}
DCB CSerialPort::GetDCB()
{
 return m_dcb;
}
DWORD CSerialPort::GetCommEvents()
{
 return m_dwCommEvents;
}
DWORD CSerialPort::GetWriteBufferSize()
{
 return m_nWriteBufferSize;
}

</Source File>

正所谓:多情不义易自闭,路边的野花别乱采;飘然牡丹花下死,化作春泥更护花!实在是字字猪鸡(珠玑)啊!

另附狼酒CCTB,我最喜欢的冷笑话一则,说:计划生育部长下乡普查,问老农:你知道近亲为什么不能结婚吗?老农憨厚地笑答:呵呵……太熟了,不好意思下手。

警:这里有人就要问了,什么是CCTB?既然你诚心诚意的请教我,那我就大发慈悲的告诉你:C(姓)C(名)T(特别)B(变态)

转载自原文链接, 如需删除请联系管理员。

原文链接:串口类CSerialPort(2010-03-05),转载请注明来源!

0