zoukankan      html  css  js  c++  java
  • serialport

    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);

  • 相关阅读:
    基础知识记录
    不同数据库'查询第几行到第几行记录'脚本的区别
    visual studio自动生成的私有内部字段变量以_为前缀
    ASP.NET Core 集成Prometheus+grafana
    netcore命令行运行程序
    RabbitMQ使用建议
    解决Pg新增数据主键冲突
    .Net Core调用第三方WebService
    .Net Core调用oracle存储过程
    call,apply,bind使用区别
  • 原文地址:https://www.cnblogs.com/yuanchao/p/13385658.html
Copyright © 2011-2022 走看看