yuanchaost

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

class _SERIAL_PORT_DATA
{
public:
 //Constructors /Destructors
 _SERIAL_PORT_DATA();
 ~_SERIAL_PORT_DATA();

 HINSTANCE m_hKernel32;
 typedef BOOL (WINAPI CANCELIO)(HANDLE);
 typedef CANCELIO* LPCANCELIO;
 LPCANCELIO m_lpfnCancelIo;
};

_SERIAL_PORT_DATA::_SERIAL_PORT_DATA()
{
 m_hKernel32 = LoadLibrary(L"KERNEL32.DLL");
 //VERIFY(m_hKernel32 != NULL);
 m_lpfnCancelIo = (LPCANCELIO) GetProcAddress(m_hKernel32, "CancelIo");
}

_SERIAL_PORT_DATA::~_SERIAL_PORT_DATA()
{
 FreeLibrary(m_hKernel32);
 m_hKernel32 = NULL;
}

/The local variable which handle the function pointers

_SERIAL_PORT_DATA _SerialPortData;

 


////////// Exception handling code

void AfxThrowSerialException(DWORD dwError /* = 0 */)
{

 if (dwError == 0)
  dwError = ::GetLastError();

 CSerialException* pException = new CSerialException(dwError);

 TRACE(_T("Warning: throwing CSerialException for error %d\n"), dwError);
 THROW(pException);


 //throw(Exception(get_last_error_string()));
}

BOOL CSerialException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
{
 ASSERT(pstrError != NULL && AfxIsValidString(pstrError, nMaxError));

 if (pnHelpContext != NULL)
  *pnHelpContext = 0;

 LPTSTR lpBuffer;
 BOOL bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  NULL,  m_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  (LPTSTR) &lpBuffer, 0, NULL);

 if (bRet == FALSE)
  *pstrError = '\0';
 else
 {
  lstrcpyn(pstrError, lpBuffer, nMaxError);
  bRet = TRUE;

  LocalFree(lpBuffer);
 }

 return bRet;
}

CString CSerialException::GetErrorMessage()
{
 CString rVal;
 LPTSTR pstrError = rVal.GetBuffer(4096);
 GetErrorMessage(pstrError, 4096, NULL);
 rVal.ReleaseBuffer();
 return rVal;
}

CSerialException::CSerialException(DWORD dwError)
{
 m_dwError = dwError;
}

CSerialException::~CSerialException()
{
}

IMPLEMENT_DYNAMIC(CSerialException, CException)

#ifdef _DEBUG
 void CSerialException::Dump(CDumpContext& dc) const
{
 CObject::Dump(dc);

 dc << "m_dwError = " << m_dwError;
}
#endif

 

 

////////// The actual serial port code

CSerialPort::CSerialPort()
{
 m_hComm = INVALID_HANDLE_VALUE;
 m_bOverlapped = FALSE;
 m_hEvent = NULL;
}

CSerialPort::~CSerialPort()
{
 Close();
}

//IMPLEMENT_DYNAMIC(CSerialPort, CObject)

void CSerialPort::Open(int nPort, DWORD dwBaud, Parity parity, BYTE DataBits, StopBits stopbits, FlowControl fc, BOOL bOverlapped)
{
 //Validate our parameters
 ASSERT(nPort>0 && nPort<=255);

 Close(); //In case we are already open

 //Call CreateFile to open up the comms port
 char sPort[20];
 sprintf(sPort, "\\\\.\\COM%d", nPort);
 DWORD dwCreateProperty;
 if(bOverlapped)
 {
  dwCreateProperty=FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
 }
 else
 {
  dwCreateProperty=FILE_ATTRIBUTE_NORMAL;
 }
 // bOverlapped ? FILE_FLAG_OVERLAPPED : 0
 m_hComm = CreateFileA(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,dwCreateProperty, NULL);
 if (m_hComm == INVALID_HANDLE_VALUE)
 {
  //TRACE(_T("Failed to open up the comms port\n"));
  AfxThrowSerialException();
 }

this->m_CurPortNum = nPort;
 //Create the event we need for later synchronisation use
 /*
 if(bOverlapped)
 {
 m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 if (m_hEvent == NULL)
 {
 Close();
 TRACE(_T("Failed in call to CreateEvent in Open\n"));
 AfxThrowSerialException();
 }
 }
 */

 m_bOverlapped = bOverlapped;

 //Get the current state prior to changing it
 DCB dcb;
 dcb.DCBlength = sizeof(DCB);
 GetState(dcb);

 //Setup the baud rate
 dcb.BaudRate = dwBaud;

 //Setup the Parity
 switch (parity)
 {
 case EvenParity:  dcb.Parity = EVENPARITY;  break;
 case MarkParity:  dcb.Parity = MARKPARITY;  break;
 case NoParity:    dcb.Parity = NOPARITY;    break;
 case OddParity:   dcb.Parity = ODDPARITY;   break;
 case SpaceParity: dcb.Parity = SPACEPARITY; break;
 default:          ASSERT(FALSE);            break;
 }

//Setup the data bits
 dcb.ByteSize = DataBits;

 //Setup the stop bits
 switch (stopbits)
 {
 case OneStopBit:           dcb.StopBits = ONESTOPBIT;   break;
 case OnePointFiveStopBits: dcb.StopBits = ONE5STOPBITS; break;
 case TwoStopBits:          dcb.StopBits = TWOSTOPBITS;  break;
 default:                   ASSERT(FALSE);               break;
 }

 //Setup the flow control
 dcb.fDsrSensitivity = FALSE;
 switch (fc)
 {
 case NoFlowControl:
  {
   dcb.fOutxCtsFlow = FALSE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fOutX = FALSE;
   dcb.fInX = FALSE;
   break;
  }
 case CtsRtsFlowControl:
  {
   dcb.fOutxCtsFlow = TRUE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
   dcb.fOutX = FALSE;
   dcb.fInX = FALSE;
   break;
  }
 case CtsDtrFlowControl:
  {
   dcb.fOutxCtsFlow = TRUE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
   dcb.fOutX = FALSE;
   dcb.fInX = FALSE;
   break;
  }

case DsrRtsFlowControl:
  {
   dcb.fOutxCtsFlow = FALSE;
   dcb.fOutxDsrFlow = TRUE;
   dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
   dcb.fOutX = FALSE;
   dcb.fInX = FALSE;
   break;
  }
 case DsrDtrFlowControl:
  {
   dcb.fOutxCtsFlow = FALSE;
   dcb.fOutxDsrFlow = TRUE;
   dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
   dcb.fOutX = FALSE;
   dcb.fInX = FALSE;
   break;
  }
 case XonXoffFlowControl:
  {
   dcb.fOutxCtsFlow = FALSE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fOutX = TRUE;
   dcb.fInX = TRUE;
   dcb.XonChar = 0x11;
   dcb.XoffChar = 0x13;
   dcb.XoffLim = 100;
   dcb.XonLim = 100;
   break;
  }

default:
  {
   ASSERT(FALSE);
   break;
  }
 }

 //Now that we have all the settings in place, make the changes
 SetState(dcb);
}

void CSerialPort::Close()
{
 if (IsOpen())
 {
  //Close down the comms port
  BOOL bSuccess = CloseHandle(m_hComm);
  m_hComm = INVALID_HANDLE_VALUE;
  if (!bSuccess)
  {
   //TRACE(_T("Failed to close up the comms port, GetLastError:%d\n"), GetLastError());
   AfxThrowSerialException();
  }
  m_bOverlapped = FALSE;

 

 //Free up the event object we are using
  if(m_hEvent)
  {
   CloseHandle(m_hEvent);
   m_hEvent = NULL;
  }

 }
}

void CSerialPort::Attach(HANDLE hComm, BOOL bOverlapped)
{
 Close();
 m_hComm = hComm; 
 m_bOverlapped = bOverlapped;

 //Create the event we need for later synchronisation use
 m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 if (m_hEvent == NULL)
 {
  Close();
  //TRACE(_T("Failed in call to CreateEvent in Attach\n"));
  AfxThrowSerialException();
 }
}

 

HANDLE CSerialPort::Detach()
{
 HANDLE hrVal = m_hComm;
 m_hComm = INVALID_HANDLE_VALUE;
 CloseHandle(m_hEvent);
 m_hEvent = NULL;
 return hrVal;
}

DWORD CSerialPort::Read(void* lpBuf, DWORD dwCount)
{
 ASSERT(IsOpen());
 ASSERT(!m_bOverlapped);

 DWORD Errors;
 COMSTAT comstat;
 BOOL ok;
 ok = ::ClearCommError(this->m_hComm,&Errors,&comstat);
 if(!ok)
 {
  return 0;
 }
 if(comstat.cbInQue==0)
 {
  return 0;
 }

DWORD dwBytesRead = 0;
 if (!ReadFile(m_hComm, lpBuf, comstat.cbInQue, &dwBytesRead, NULL))
 {
  //TRACE(_T("Failed in call to ReadFile\n"));
  AfxThrowSerialException();
 }

 return dwBytesRead;
}

BOOL CSerialPort::Read(void* lpBuf, DWORD dwCount, OVERLAPPED& overlapped, DWORD* pBytesRead)
{
 ASSERT(IsOpen());
 ASSERT(m_bOverlapped);

DWORD dwBytesRead = 0;
 //DWORD Errors;
 //  COMSTAT comstat;
 /*
 BOOL ok;
 ok = ::ClearCommError(this->m_hComm,&Errors,&comstat);
 if(!ok)
 {
 return false;
 }
 if(comstat.cbInQue==0)
 {
 return false;
 }
 */
 BOOL bSuccess = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
 if (!bSuccess)
 {
  if (GetLastError() != ERROR_IO_PENDING)
  {
   //TRACE(_T("Failed in call to ReadFile\n"));
   AfxThrowSerialException();
  }
 }
 else
 {
  if (pBytesRead)
   *pBytesRead = dwBytesRead;
 }
 return bSuccess;
}

 

DWORD CSerialPort::Write(const void* lpBuf, DWORD dwCount)
{

 ASSERT(IsOpen());
 ASSERT(!m_bOverlapped);

 DWORD dwBytesWritten = 0;
 if (!WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, NULL))
 {
  //TRACE(_T("Failed in call to WriteFile\n"));
  AfxThrowSerialException();
 }

 return dwBytesWritten;
}

BOOL CSerialPort::Write(const void* lpBuf, DWORD dwCount, OVERLAPPED& overlapped, DWORD* pBytesWritten)
{
 ASSERT(IsOpen());

 ASSERT(m_bOverlapped);

 DWORD dwBytesWritten = 0;
 BOOL bSuccess = WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, &overlapped);
 if (!bSuccess)
 {
  if (GetLastError() != ERROR_IO_PENDING)
  {
   //TRACE(_T("Failed in call to WriteFile\n"));
   AfxThrowSerialException();
  }
 }
 else
 {
  if (pBytesWritten)
   *pBytesWritten = dwBytesWritten;
 }

 return bSuccess;
}

 

bool CSerialPort::GetOverlappedResult(OVERLAPPED& overlapped, DWORD& dwBytesTransferred, BOOL bWait)
{
 ASSERT(IsOpen());
 ASSERT(m_bOverlapped);

 BOOL bSuccess = ::GetOverlappedResult(m_hComm, &overlapped, &dwBytesTransferred, bWait);
 if (!bSuccess)
 {
  if (GetLastError() != ERROR_IO_PENDING)
  {
   //TRACE(_T("Failed in call to GetOverlappedResult\n"));
   AfxThrowSerialException();
  }
 }

 return bSuccess == TRUE;
}

void WINAPI CSerialPort::_OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped)
{
 //Validate our parameters
 ASSERT(lpOverlapped);


 //Convert back to the C++ world
 CSerialPort* pSerialPort = (CSerialPort*) lpOverlapped->hEvent;
 ASSERT(pSerialPort);
 //ASSERT(pSerialPort->IsKindOf(RUNTIME_CLASS(CSerialPort)));

 //Call the C++ function
 pSerialPort->OnCompletion(dwErrorCode, dwCount, lpOverlapped);
}

void CSerialPort::OnCompletion(DWORD /*dwErrorCode*/, DWORD /*dwCount*/, LPOVERLAPPED lpOverlapped)
{
 //Jus

 

void CSerialPort::CancelIo()
{
 ASSERT(IsOpen());

 if (_SerialPortData.m_lpfnCancelIo == NULL)
 {
  //TRACE(_T("CancelIo function is not supported on this OS. You need to be running at least NT 4 or Win 98 to use this function\n"));
  AfxThrowSerialException(ERROR_CALL_NOT_IMPLEMENTED); 
 }

 if (!::_SerialPortData.m_lpfnCancelIo(m_hComm))
 {
  //TRACE(_T("Failed in call to CancelIO\n"));
  AfxThrowSerialException();
 }
}

DWORD CSerialPort::BytesWaiting()
{
 ASSERT(IsOpen());

 //Check to see how many characters are unread
 COMSTAT stat;
 GetStatus(stat);
 return stat.cbInQue;
}

 

BOOL CSerialPort::DataWaiting(DWORD dwTimeout)
{
 ASSERT(IsOpen());
 ASSERT(m_hEvent);
 //Setup to wait for incoming data
 DWORD dwOldMask;
 GetMask(dwOldMask);
 SetMask(EV_RXCHAR);

 //Setup the overlapped structure
 OVERLAPPED o;
 o.hEvent = m_hEvent;

 //Assume the worst;
 BOOL bSuccess = FALSE;

 DWORD dwEvent;
 bSuccess = WaitEvent(dwEvent, o);
 if (!bSuccess)
 {
  if (WaitForSingleObject(o.hEvent, dwTimeout) == WAIT_OBJECT_0)
  {
   DWORD dwBytesTransferred;
   GetOverlappedResult(o, dwBytesTransferred, FALSE);
   bSuccess = TRUE;
  }
 }

 //Reset the event mask
 SetMask(dwOldMask);

 return bSuccess;
}

void CSerialPort::WriteEx(const void* lpBuf, DWORD dwCount)
{
 ASSERT(IsOpen());

 OVERLAPPED* pOverlapped = new OVERLAPPED;
 ZeroMemory(pOverlapped, sizeof(OVERLAPPED));
 pOverlapped->hEvent = (HANDLE) this;
 if (!WriteFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion))
 {
  delete pOverlapped;
  //TRACE(_T("Failed in call to WriteFileEx\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::ReadEx(void* lpBuf, DWORD dwCount)
{
 ASSERT(IsOpen());

 OVERLAPPED* pOverlapped = new OVERLAPPED;
 ZeroMemory(pOverlapped, sizeof(OVERLAPPED));
 pOverlapped->hEvent = (HANDLE) this;
 if (!ReadFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion))
 {
  delete pOverlapped;
  //TRACE(_T("Failed in call to ReadFileEx\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::TransmitChar(char cChar)
{
 ASSERT(IsOpen());

 if (!TransmitCommChar(m_hComm, cChar))
 {
  //TRACE(_T("Failed in call to TransmitCommChar\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::GetConfig(COMMCONFIG& config)
{
 ASSERT(IsOpen());

 DWORD dwSize = sizeof(COMMCONFIG);
 if (!GetCommConfig(m_hComm, &config, &dwSize))
 {
  //TRACE(_T("Failed in call to GetCommConfig\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::SetConfig(COMMCONFIG& config)
{
 ASSERT(IsOpen());

 DWORD dwSize = sizeof(COMMCONFIG);
 if (!SetCommConfig(m_hComm, &config, dwSize))
 {
  //TRACE(_T("Failed in call to SetCommConfig\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::SetBreak()
{
 ASSERT(IsOpen());

 if (!SetCommBreak(m_hComm))
 {
  //TRACE(_T("Failed in call to SetCommBreak\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::ClearBreak()
{
 ASSERT(IsOpen());

 if (!ClearCommBreak(m_hComm))
 {
  //TRACE(_T("Failed in call to SetCommBreak\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::ClearError(DWORD& dwErrors)
{
 ASSERT(IsOpen());

 if (!ClearCommError(m_hComm, &dwErrors, NULL))
 {
  //TRACE(_T("Failed in call to ClearCommError\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::GetDefaultConfig(int nPort, COMMCONFIG& config)
{
 //Validate our parameters
 ASSERT(nPort>0 && nPort<=255);

 //Create the device name as a string
 char sPort[20];
 sprintf(sPort, "COM%d", nPort);

 DWORD dwSize = sizeof(COMMCONFIG);
 if (!GetDefaultCommConfigA(sPort, &config, &dwSize))
 {
  //TRACE(_T("Failed in call to GetDefaultCommConfig\n"));
  AfxThrowSerialException();
 }
}

void CSerialPort::SetDefaultConfig(int nPort, COMMCONFIG& config)
{
 //Validate our parameters
 ASSERT(nPort>0 && nPort<=255);

 //Create the device name as a string
 char sPort[20];
 sprintf(sPort, "COM%d", nPort);

 

posted on 2020-07-27 15:28  yuanchaost  阅读(514)  评论(0编辑  收藏  举报