Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Serial.cpp - Implementation of the CSerial class
- //
- // Copyright (C) 1999-2003 Ramon de Klein ([email protected])
- //
- // This library is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Lesser General Public
- // License as published by the Free Software Foundation; either
- // version 2.1 of the License, or (at your option) any later version.
- //
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public
- // License along with this library; if not, write to the Free Software
- // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- //////////////////////////////////////////////////////////////////////
- // Include the standard header files
- #define STRICT
- #include <crtdbg.h>
- #include <tchar.h>
- #include <windows.h>
- //////////////////////////////////////////////////////////////////////
- // Include module headerfile
- #include "Serial.h"
- //////////////////////////////////////////////////////////////////////
- // Disable warning C4127: conditional expression is constant, which
- // is generated when using the _RPTF and _ASSERTE macros.
- #pragma warning(disable: 4127)
- //////////////////////////////////////////////////////////////////////
- // Enable debug memory manager
- #ifdef _DEBUG
- #ifdef THIS_FILE
- #undef THIS_FILE
- #endif
- static const char THIS_FILE[] = __FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Helper methods
- inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const
- {
- #ifdef SERIAL_NO_OVERLAPPED
- // Check if an overlapped structure has been specified
- if (lpOverlapped || (dwTimeout != INFINITE))
- {
- // Quit application
- ::MessageBox(0,_T("Overlapped I/O and time-outs are not supported, when overlapped I/O is disabled."),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
- ::DebugBreak();
- ::ExitProcess(0xFFFFFFF);
- }
- #endif
- #ifdef SERIAL_NO_CANCELIO
- // Check if 0 or INFINITE time-out has been specified, because
- // the communication I/O cannot be cancelled.
- if ((dwTimeout != 0) && (dwTimeout != INFINITE))
- {
- // Quit application
- ::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
- ::DebugBreak();
- ::ExitProcess(0xFFFFFFF);
- }
- #endif // SERIAL_NO_CANCELIO
- // Avoid warnings
- (void) dwTimeout;
- (void) lpOverlapped;
- }
- inline BOOL CSerial::CancelCommIo (void)
- {
- #ifdef SERIAL_NO_CANCELIO
- // CancelIo shouldn't have been called at this point
- ::DebugBreak();
- return FALSE;
- #else
- // Cancel the I/O request
- return ::CancelIo(m_hFile);
- #endif // SERIAL_NO_CANCELIO
- }
- //////////////////////////////////////////////////////////////////////
- // Code
- CSerial::CSerial ()
- : m_lLastError(ERROR_SUCCESS)
- , m_hFile(0)
- , m_eEvent(EEventNone)
- , m_dwEventMask(0)
- #ifndef SERIAL_NO_OVERLAPPED
- , m_hevtOverlapped(0)
- #endif
- {
- }
- CSerial::~CSerial ()
- {
- // If the device is already closed,
- // then we don't need to do anything.
- if (m_hFile)
- {
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n");
- // Close implicitly
- Close();
- }
- }
- CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice)
- {
- // Try to open the device
- HANDLE hFile = ::CreateFile(lpszDevice,
- GENERIC_READ|GENERIC_WRITE,
- 0,
- 0,
- OPEN_EXISTING,
- 0,
- 0);
- // Check if we could open the device
- if (hFile == INVALID_HANDLE_VALUE)
- {
- // Display error
- switch (::GetLastError())
- {
- case ERROR_FILE_NOT_FOUND:
- // The specified COM-port does not exist
- return EPortNotAvailable;
- case ERROR_ACCESS_DENIED:
- // The specified COM-port is in use
- return EPortInUse;
- default:
- // Something else is wrong
- return EPortUnknownError;
- }
- }
- // Close handle
- ::CloseHandle(hFile);
- // Port is available
- return EPortAvailable;
- }
- LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped)
- {
- // 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,"CSerial::Open - Port already opened\n");
- return m_lLastError;
- }
- // Open the device
- m_hFile = ::CreateFile(lpszDevice,
- GENERIC_READ|GENERIC_WRITE,
- 0,
- 0,
- OPEN_EXISTING,
- fOverlapped?FILE_FLAG_OVERLAPPED:0,
- 0);
- if (m_hFile == INVALID_HANDLE_VALUE)
- {
- // Reset file handle
- m_hFile = 0;
- // Display error
- m_lLastError = ::GetLastError();
- _RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
- return m_lLastError;
- }
- #ifndef SERIAL_NO_OVERLAPPED
- // We cannot have an event handle yet
- _ASSERTE(m_hevtOverlapped == 0);
- // Create the event handle for internal overlapped operations (manual reset)
- if (fOverlapped)
- {
- m_hevtOverlapped = ::CreateEvent(0,true,false,0);
- if (m_hevtOverlapped == 0)
- {
- // Obtain the error information
- m_lLastError = ::GetLastError();
- _RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");
- // Close the port
- ::CloseHandle(m_hFile);
- m_hFile = 0;
- // Return the error
- return m_lLastError;
- }
- }
- #else
- // Overlapped flag shouldn't be specified
- _ASSERTE(!fOverlapped);
- #endif
- // Setup the COM-port
- if (dwInQueue || dwOutQueue)
- {
- // Make sure the queue-sizes are reasonable sized. Win9X systems crash
- // if the input queue-size is zero. Both queues need to be at least
- // 16 bytes large.
- _ASSERTE(dwInQueue >= 16);
- _ASSERTE(dwOutQueue >= 16);
- if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
- {
- // Display a warning
- long lLastError = ::GetLastError();
- _RPTF0(_CRT_WARN,"CSerial::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();
- // Non-blocking reads is default
- SetupReadTimeouts(EReadTimeoutNonblocking);
- // Setup the device for default settings
- COMMCONFIG commConfig = {0};
- DWORD dwSize = sizeof(commConfig);
- commConfig.dwSize = dwSize;
- if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize))
- {
- // Set the default communication configuration
- if (!::SetCommConfig(m_hFile,&commConfig,dwSize))
- {
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n");
- }
- }
- else
- {
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n");
- }
- // Return successful
- return m_lLastError;
- }
- LONG CSerial::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,"CSerial::Close - Method called when device is not open\n");
- return m_lLastError;
- }
- #ifndef SERIAL_NO_OVERLAPPED
- // Free event handle
- if (m_hevtOverlapped)
- {
- ::CloseHandle(m_hevtOverlapped);
- m_hevtOverlapped = 0;
- }
- #endif
- // Close COM port
- ::CloseHandle(m_hFile);
- m_hFile = 0;
- // Return successful
- return m_lLastError;
- }
- LONG CSerial::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,"CSerial::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,"CSerial::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,"CSerial::Setup - Unable to set DCB information\n");
- return m_lLastError;
- }
- // Return successful
- return m_lLastError;
- }
- LONG CSerial::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,"CSerial::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,"CSerial::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,"CSerial::SetEventChar - Unable to set DCB information\n");
- return m_lLastError;
- }
- // Return successful
- return m_lLastError;
- }
- LONG CSerial::SetMask (DWORD dwEventMask)
- {
- // 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,"CSerial::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,dwEventMask))
- {
- // Obtain the error code
- m_lLastError = ::GetLastError();
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n");
- return m_lLastError;
- }
- // Save event mask and return successful
- m_dwEventMask = dwEventMask;
- return m_lLastError;
- }
- LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
- {
- // Check if time-outs are supported
- CheckRequirements(lpOverlapped,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,"CSerial::WaitEvent - Device is not opened\n");
- return m_lLastError;
- }
- #ifndef SERIAL_NO_OVERLAPPED
- // Check if an overlapped structure has been specified
- if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
- {
- // Set the internal error code
- m_lLastError = ERROR_INVALID_FUNCTION;
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n");
- return m_lLastError;
- }
- // Wait for the event to happen
- OVERLAPPED ovInternal;
- if (!lpOverlapped && m_hevtOverlapped)
- {
- // 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(!m_hevtOverlapped || 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,"CSerial::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
- CancelCommIo();
- // 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,"CSerial::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.
- if (lpOverlapped)
- ::SetEvent(lpOverlapped->hEvent);
- }
- #else
- // Wait for the COM event
- if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),0))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
- return m_lLastError;
- }
- #endif
- // Return successfully
- return m_lLastError;
- }
- LONG CSerial::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,"CSerial::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,"CSerial::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,"CSerial::SetupHandshaking - Unable to set DCB information\n");
- return m_lLastError;
- }
- // Return successful
- return m_lLastError;
- }
- LONG CSerial::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,"CSerial::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,"CSerial::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
- _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n");
- return m_lLastError;
- }
- // Return successful
- return m_lLastError;
- }
- CSerial::EBaudrate CSerial::GetBaudrate (void)
- {
- // 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,"CSerial::GetBaudrate - Device is not opened\n");
- return EBaudUnknown;
- }
- // 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,"CSerial::GetBaudrate - Unable to obtain DCB information\n");
- return EBaudUnknown;
- }
- // Return the appropriate baudrate
- return EBaudrate(dcb.BaudRate);
- }
- CSerial::EDataBits CSerial::GetDataBits (void)
- {
- // 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,"CSerial::GetDataBits - Device is not opened\n");
- return EDataUnknown;
- }
- // 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,"CSerial::GetDataBits - Unable to obtain DCB information\n");
- return EDataUnknown;
- }
- // Return the appropriate bytesize
- return EDataBits(dcb.ByteSize);
- }
- CSerial::EParity CSerial::GetParity (void)
- {
- // 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,"CSerial::GetParity - Device is not opened\n");
- return EParUnknown;
- }
- // 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,"CSerial::GetParity - Unable to obtain DCB information\n");
- return EParUnknown;
- }
- // Check if parity is used
- if (!dcb.fParity)
- {
- // No parity
- return EParNone;
- }
- // Return the appropriate parity setting
- return EParity(dcb.Parity);
- }
- CSerial::EStopBits CSerial::GetStopBits (void)
- {
- // 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,"CSerial::GetStopBits - Device is not opened\n");
- return EStopUnknown;
- }
- // 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,"CSerial::GetStopBits - Unable to obtain DCB information\n");
- return EStopUnknown;
- }
- // Return the appropriate stopbits
- return EStopBits(dcb.StopBits);
- }
- DWORD CSerial::GetEventMask (void)
- {
- // 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,"CSerial::GetEventMask - Device is not opened\n");
- return 0;
- }
- // Return the event mask
- return m_dwEventMask;
- }
- BYTE CSerial::GetEventChar (void)
- {
- // 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,"CSerial::GetEventChar - Device is not opened\n");
- return 0;
- }
- // 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,"CSerial::GetEventChar - Unable to obtain DCB information\n");
- return 0;
- }
- // Set the new event character
- return BYTE(dcb.EvtChar);
- }
- CSerial::EHandshake CSerial::GetHandshaking (void)
- {
- // 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,"CSerial::GetHandshaking - Device is not opened\n");
- return EHandshakeUnknown;
- }
- // 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,"CSerial::GetHandshaking - Unable to obtain DCB information\n");
- return EHandshakeUnknown;
- }
- // Check if hardware handshaking is being used
- if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE))
- return EHandshakeHardware;
- // Check if software handshaking is being used
- if (dcb.fOutX && dcb.fInX)
- return EHandshakeSoftware;
- // No handshaking is being used
- return EHandshakeOff;
- }
- LONG CSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
- {
- // Check if time-outs are supported
- CheckRequirements(lpOverlapped,dwTimeout);
- // Overlapped operation should specify the pdwWritten variable
- _ASSERTE(!lpOverlapped || pdwWritten);
- // Reset error state
- m_lLastError = ERROR_SUCCESS;
- // Use our own variable for read count
- DWORD dwWritten;
- if (pdwWritten == 0)
- {
- pdwWritten = &dwWritten;
- }
- // Reset the number of bytes written
- *pdwWritten = 0;
- // 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,"CSerial::Write - Device is not opened\n");
- return m_lLastError;
- }
- #ifndef SERIAL_NO_OVERLAPPED
- // Check if an overlapped structure has been specified
- if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
- {
- // Set the internal error code
- m_lLastError = ERROR_INVALID_FUNCTION;
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped I/O is disabled, specified parameters are illegal.\n");
- return m_lLastError;
- }
- // Wait for the event to happen
- OVERLAPPED ovInternal;
- if (!lpOverlapped && m_hevtOverlapped)
- {
- // 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(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
- // Write the data
- if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,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,"CSerial::Write - Unable to write the data\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
- if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped completed without result\n");
- return m_lLastError;
- }
- break;
- case WAIT_TIMEOUT:
- // Cancel the I/O operation
- CancelCommIo();
- // 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,"CSerial::Write - Unable to wait until data has been sent\n");
- return m_lLastError;
- }
- }
- }
- else
- {
- // The operation completed immediatly. Just to be sure
- // we'll set the overlapped structure's event handle.
- if (lpOverlapped)
- ::SetEvent(lpOverlapped->hEvent);
- }
- #else
- // Write the data
- if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,0))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
- return m_lLastError;
- }
- #endif
- // Return successfully
- return m_lLastError;
- }
- LONG CSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
- {
- // Check if time-outs are supported
- CheckRequirements(lpOverlapped,dwTimeout);
- // Determine the length of the string
- return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout);
- }
- LONG CSerial::Read (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
- {
- // Check if time-outs are supported
- CheckRequirements(lpOverlapped,dwTimeout);
- // Overlapped operation should specify the pdwRead variable
- _ASSERTE(!lpOverlapped || pdwRead);
- // Reset error state
- m_lLastError = ERROR_SUCCESS;
- // Use our own variable for read count
- DWORD dwRead;
- if (pdwRead == 0)
- {
- pdwRead = &dwRead;
- }
- // Reset the number of bytes read
- *pdwRead = 0;
- // 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,"CSerial::Read - Device is not opened\n");
- return m_lLastError;
- }
- #ifdef _DEBUG
- // The debug version fills the entire data structure with
- // 0xDC bytes, to catch buffer errors as soon as possible.
- memset(pData,0xDC,iLen);
- #endif
- #ifndef SERIAL_NO_OVERLAPPED
- // Check if an overlapped structure has been specified
- if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
- {
- // Set the internal error code
- m_lLastError = ERROR_INVALID_FUNCTION;
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped I/O is disabled, specified parameters are illegal.\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(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
- // Read the data
- if (!::ReadFile(m_hFile,pData,iLen,pdwRead,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,"CSerial::Read - Unable to read the data\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
- if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped completed without result\n");
- return m_lLastError;
- }
- break;
- case WAIT_TIMEOUT:
- // Cancel the I/O operation
- CancelCommIo();
- // 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,"CSerial::Read - Unable to wait until data has been read\n");
- return m_lLastError;
- }
- }
- }
- else
- {
- // The operation completed immediatly. Just to be sure
- // we'll set the overlapped structure's event handle.
- if (lpOverlapped)
- ::SetEvent(lpOverlapped->hEvent);
- }
- #else
- // Read the data
- if (!::ReadFile(m_hFile,pData,iLen,pdwRead,0))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
- return m_lLastError;
- }
- #endif
- // Return successfully
- return m_lLastError;
- }
- LONG CSerial::Purge()
- {
- // 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,"CSerial::Purge - Device is not opened\n");
- return m_lLastError;
- }
- if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- _RPTF0(_CRT_WARN,"CSerial::Purge - Overlapped completed without result\n");
- }
- // Return successfully
- return m_lLastError;
- }
- LONG CSerial::Break (void)
- {
- // 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,"CSerial::Break - Device is not opened\n");
- return m_lLastError;
- }
- // Set the RS-232 port in break mode for a little while
- ::SetCommBreak(m_hFile);
- ::Sleep(100);
- ::ClearCommBreak(m_hFile);
- // Return successfully
- return m_lLastError;
- }
- CSerial::EEvent CSerial::GetEventType (void)
- {
- #ifdef _DEBUG
- // Check if the event is within the mask
- if ((m_eEvent & m_dwEventMask) == 0)
- _RPTF2(_CRT_WARN,"CSerial::GetEventType - Event %08Xh not within mask %08Xh.\n", m_eEvent, m_dwEventMask);
- #endif
- // Obtain the event (mask unwanted events out)
- EEvent eEvent = EEvent(m_eEvent & m_dwEventMask);
- // Reset internal event type
- m_eEvent = EEventNone;
- // Return the current cause
- return eEvent;
- }
- CSerial::EError CSerial::GetError (void)
- {
- // 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,"CSerial::GetError - Device is not opened\n");
- return EErrorUnknown;
- }
- // Obtain COM status
- DWORD dwErrors = 0;
- if (!::ClearCommError(m_hFile,&dwErrors,0))
- {
- // Set the internal error code
- m_lLastError = ::GetLastError();
- // Issue an error and quit
- _RPTF0(_CRT_WARN,"CSerial::GetError - Unable to obtain COM status\n");
- return EErrorUnknown;
- }
- // Return the error
- return EError(dwErrors);
- }
- bool CSerial::GetCTS (void)
- {
- // Reset error state
- m_lLastError = ERROR_SUCCESS;
- // Obtain the modem status
- DWORD dwModemStat = 0;
- if (!::GetCommModemStatus(m_hFile,&dwModemStat))
- {
- // Obtain the error code
- m_lLastError = ::GetLastError();
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::GetCTS - Unable to obtain the modem status\n");
- return false;
- }
- // Determine if CTS is on
- return (dwModemStat & MS_CTS_ON) != 0;
- }
- bool CSerial::GetDSR (void)
- {
- // Reset error state
- m_lLastError = ERROR_SUCCESS;
- // Obtain the modem status
- DWORD dwModemStat = 0;
- if (!::GetCommModemStatus(m_hFile,&dwModemStat))
- {
- // Obtain the error code
- m_lLastError = ::GetLastError();
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::GetDSR - Unable to obtain the modem status\n");
- return false;
- }
- // Determine if DSR is on
- return (dwModemStat & MS_DSR_ON) != 0;
- }
- bool CSerial::GetRing (void)
- {
- // Reset error state
- m_lLastError = ERROR_SUCCESS;
- // Obtain the modem status
- DWORD dwModemStat = 0;
- if (!::GetCommModemStatus(m_hFile,&dwModemStat))
- {
- // Obtain the error code
- m_lLastError = ::GetLastError();
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::GetRing - Unable to obtain the modem status");
- return false;
- }
- // Determine if Ring is on
- return (dwModemStat & MS_RING_ON) != 0;
- }
- bool CSerial::GetRLSD (void)
- {
- // Reset error state
- m_lLastError = ERROR_SUCCESS;
- // Obtain the modem status
- DWORD dwModemStat = 0;
- if (!::GetCommModemStatus(m_hFile,&dwModemStat))
- {
- // Obtain the error code
- m_lLastError = ::GetLastError();
- // Display a warning
- _RPTF0(_CRT_WARN,"CSerial::GetRLSD - Unable to obtain the modem status");
- return false;
- }
- // Determine if RLSD is on
- return (dwModemStat & MS_RLSD_ON) != 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement