?? comport.cpp
字號:
#include "stdafx.h"
#include <crtdbg.h>
#include <tchar.h>
//////////////////////////////////////////////////////////////////////
// Include module headerfile
#include "ComPort.h"
//////////////////////////////////////////////////////////////////////
// Disable warning C4127: conditional expression is constant, which
// is generated when using the _RPTF and _ASSERTE macros.
#pragma warning(disable: 4127)
//////////////////////////////////////////////////////////////////////
// Code
CComPort::CComPort ()
{
// Reset data
m_lLastError = ERROR_SUCCESS;
m_hFile = 0;
m_eEvent = EEventNone;
m_hevtOverlapped = 0;
}
CComPort::~CComPort ()
{
// If the device is already closed,
// then we don't need to do anything.
if (m_hFile)
{
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::~CComPort - Serial port not closed\n");
// Close implicitly
Close();
}
}
LONG CComPort::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the port isn't already opened
if (m_hFile)
{
m_lLastError = ERROR_ALREADY_INITIALIZED;
_RPTF0(_CRT_WARN,"CComPort::Open - Port already opened\n");
return m_lLastError;
}
// Open the device
m_hFile = ::CreateFile(lpszDevice,
GENERIC_READ|GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (m_hFile == INVALID_HANDLE_VALUE)
{
// Reset file handle
m_hFile = 0;
// Display error
m_lLastError = ::GetLastError();
_RPTF0(_CRT_WARN, "CComPort::Open - Unable to open port\n");
return m_lLastError;
}
// We cannot have an event handle yet
_ASSERTE(m_hevtOverlapped == 0);
// Create the event handle for internal overlapped operations (manual reset)
m_hevtOverlapped = ::CreateEvent(0,true,false,0);
if (m_hevtOverlapped == 0)
{
// Obtain the error information
m_lLastError = ::GetLastError();
_RPTF0(_CRT_WARN,"CComPort::Open - Unable to create event\n");
// Close the port
::CloseHandle(m_hFile);
m_hFile = 0;
// Return the error
return m_lLastError;
}
// Setup the COM-port
if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
{
// Display a warning
long lLastError = ::GetLastError();
_RPTF0(_CRT_WARN,"CComPort::Open - Unable to setup the COM-port\n");
// Close the port
Close();
// Save last error from SetupComm
m_lLastError = lLastError;
return m_lLastError;
}
// Setup the default communication mask
SetMask();
// Setup the device for default settings
Setup();
// Non-blocking reads is default
SetupReadTimeouts(EReadTimeoutNonblocking);
// Default is no handshaking
SetupHandshaking(EHandshakeOff);
// Return successful
return m_lLastError;
}
LONG CComPort::Close (void)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// If the device is already closed,
// then we don't need to do anything.
if (m_hFile == 0)
{
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::Close - Method called when device is not open\n");
return m_lLastError;
}
// Free event handle
::CloseHandle(m_hevtOverlapped);
m_hevtOverlapped = 0;
// Close COM port
::CloseHandle(m_hFile);
m_hFile = 0;
// Return successful
return m_lLastError;
}
LONG CComPort::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::Setup - Device is not opened\n");
return m_lLastError;
}
// Obtain the DCB structure for the device
CDCB dcb;
if (!::GetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::Setup - Unable to obtain DCB information\n");
return m_lLastError;
}
// Set the new data
dcb.BaudRate = DWORD(eBaudrate);
dcb.ByteSize = BYTE(eDataBits);
dcb.Parity = BYTE(eParity);
dcb.StopBits = BYTE(eStopBits);
// Determine if parity is used
dcb.fParity = (eParity != EParNone);
// Set the new DCB structure
if (!::SetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::Setup - Unable to set DCB information\n");
return m_lLastError;
}
// Return successful
return m_lLastError;
}
LONG CComPort::SetEventChar (BYTE bEventChar, bool fAdjustMask)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::SetEventChar - Device is not opened\n");
return m_lLastError;
}
// Obtain the DCB structure for the device
CDCB dcb;
if (!::GetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::SetEventChar - Unable to obtain DCB information\n");
return m_lLastError;
}
// Set the new event character
dcb.EvtChar = char(bEventChar);
// Adjust the event mask, to make sure the event will be received
if (fAdjustMask)
{
// Enable 'receive event character' event. Note that this
// will generate an EEventNone if there is an asynchronous
// WaitCommEvent pending.
SetMask(GetEventMask() | EEventRcvEv);
}
// Set the new DCB structure
if (!::SetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::SetEventChar - Unable to set DCB information\n");
return m_lLastError;
}
// Return successful
return m_lLastError;
}
LONG CComPort::SetMask (DWORD dwMask)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::SetMask - Device is not opened\n");
return m_lLastError;
}
// Set the new mask. Note that this will generate an EEventNone
// if there is an asynchronous WaitCommEvent pending.
if (!::SetCommMask(m_hFile,dwMask))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::SetMask - Unable to set event mask\n");
return m_lLastError;
}
// Return successful
return m_lLastError;
}
LONG CComPort::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::WaitEvent - Device is not opened\n");
return m_lLastError;
}
// Wait for the event to happen
OVERLAPPED ovInternal;
if (lpOverlapped == 0)
{
// Setup our own overlapped structure
memset(&ovInternal,0,sizeof(ovInternal));
ovInternal.hEvent = m_hevtOverlapped;
// Use our internal overlapped structure
lpOverlapped = &ovInternal;
}
// Make sure the overlapped structure isn't busy
_ASSERTE(HasOverlappedIoCompleted(lpOverlapped));
// Wait for the COM event
if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped))
{
// Set the internal error code
long lLastError = ::GetLastError();
// Overlapped operation in progress is not an actual error
if (lLastError != ERROR_IO_PENDING)
{
// Save the error
m_lLastError = lLastError;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::WaitEvent - Unable to wait for COM event\n");
return m_lLastError;
}
// We need to block if the client didn't specify an overlapped structure
if (lpOverlapped == &ovInternal)
{
// Wait for the overlapped operation to complete
switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
{
case WAIT_OBJECT_0:
// The overlapped operation has completed
break;
case WAIT_TIMEOUT:
// Cancel the I/O operation
::CancelIo(m_hFile);
// The operation timed out. Set the internal error code and quit
m_lLastError = ERROR_TIMEOUT;
return m_lLastError;
default:
// Set the internal error code
m_lLastError = ::GetLastError();
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::WaitEvent - Unable to wait until COM event has arrived\n");
return m_lLastError;
}
}
}
else
{
// The operation completed immediatly. Just to be sure
// we'll set the overlapped structure's event handle.
::SetEvent(lpOverlapped->hEvent);
}
// Return successfully
return m_lLastError;
}
LONG CComPort::SetupHandshaking (EHandshake eHandshake)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::SetupHandshaking - Device is not opened\n");
return m_lLastError;
}
// Obtain the DCB structure for the device
CDCB dcb;
if (!::GetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::SetupHandshaking - Unable to obtain DCB information\n");
return m_lLastError;
}
// Set the handshaking flags
switch (eHandshake)
{
case EHandshakeOff:
dcb.fOutxCtsFlow = false; // Disable CTS monitoring
dcb.fOutxDsrFlow = false; // Disable DSR monitoring
dcb.fDtrControl = DTR_CONTROL_DISABLE; // Disable DTR monitoring
dcb.fOutX = false; // Disable XON/XOFF for transmission
dcb.fInX = false; // Disable XON/XOFF for receiving
dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send)
break;
case EHandshakeHardware:
dcb.fOutxCtsFlow = true; // Enable CTS monitoring
dcb.fOutxDsrFlow = true; // Enable DSR monitoring
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; // Enable DTR handshaking
dcb.fOutX = false; // Disable XON/XOFF for transmission
dcb.fInX = false; // Disable XON/XOFF for receiving
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTS handshaking
break;
case EHandshakeSoftware:
dcb.fOutxCtsFlow = false; // Disable CTS (Clear To Send)
dcb.fOutxDsrFlow = false; // Disable DSR (Data Set Ready)
dcb.fDtrControl = DTR_CONTROL_DISABLE; // Disable DTR (Data Terminal Ready)
dcb.fOutX = true; // Enable XON/XOFF for transmission
dcb.fInX = true; // Enable XON/XOFF for receiving
dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send)
break;
default:
// This shouldn't be possible
_ASSERTE(false);
m_lLastError = E_INVALIDARG;
return m_lLastError;
}
// Set the new DCB structure
if (!::SetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::SetupHandshaking - Unable to set DCB information\n");
return m_lLastError;
}
// Return successful
return m_lLastError;
}
LONG CComPort::SetupReadTimeouts (EReadTimeout eReadTimeout)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CComPort::SetupReadTimeouts - Device is not opened\n");
return m_lLastError;
}
// Determine the time-outs
COMMTIMEOUTS cto;
if (!::GetCommTimeouts(m_hFile,&cto))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CComPort::SetupReadTimeouts - Unable to obtain timeout information\n");
return m_lLastError;
}
// Set the new timeouts
switch (eReadTimeout)
{
case EReadTimeoutBlocking:
cto.ReadIntervalTimeout = 0;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier = 0;
break;
case EReadTimeoutNonblocking:
cto.ReadIntervalTimeout = MAXDWORD;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier = 0;
break;
default:
// This shouldn't be possible
_ASSERTE(false);
m_lLastError = E_INVALIDARG;
return m_lLastError;
}
// Set the new DCB structure
if (!::SetCommTimeouts(m_hFile,&cto))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -