// Serial.cpp - Implementation of the CSerial class // // Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) // // 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 #include #include ////////////////////////////////////////////////////////////////////// // 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 { //{{{ // [ADD] // for controlling RTS InitializeCriticalSection(&m_CritSect); m_dwRefCount = 0; //}}} } 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(); } //{{{ // [ADD] // for controlling RTS DeleteCriticalSection(&m_CritSect); //}}} } 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 _RPTF1(_CRT_WARN,"CSerial::Open - [%s] The specified COM-port does not exist\n", lpszDevice); return EPortNotAvailable; case ERROR_ACCESS_DENIED: // The specified COM-port is in use _RPTF1(_CRT_WARN,"CSerial::Open - [%s] The specified COM-port is in use\n", lpszDevice); return EPortInUse; default: // Something else is wrong _RPTF1(_CRT_WARN,"CSerial::Open - [%s] Something else is wrong\n", lpszDevice); return EPortUnknownError; } } _RPTF1(_CRT_WARN,"CSerial::Open - [%s] The specified COM-port is available\n", lpszDevice); // 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; //{{{ // [ADD] // for controlling RTS m_dwRefCount = 0; //}}} // 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); _RPTF1(_CRT_WARN, "CSerial::Open - [%s] is opened\n", lpszDevice); // 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; } _RPTF0(_CRT_WARN, "CSerial::Open - create event for operlapped\n"); } #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)) { #ifdef _DEBUG DCB & dcb = commConfig.dcb; #endif _RPTF0(_CRT_WARN,"CSerial::Open - ======== Comm Config =======\n"); _RPTF1(_CRT_WARN,"CSerial::Open - dwSize %x\n", commConfig.dwSize); _RPTF1(_CRT_WARN,"CSerial::Open - wVersion %x\n", commConfig.wVersion); _RPTF1(_CRT_WARN,"CSerial::Open - dwProviderSubType %x\n", commConfig.dwProviderSubType); _RPTF1(_CRT_WARN,"CSerial::Open - dwProviderOffset %x\n", commConfig.dwProviderOffset); _RPTF1(_CRT_WARN,"CSerial::Open - dwProviderSize %x\n", commConfig.dwProviderSize); _RPTF0(_CRT_WARN,"CSerial::Open - ========== DCB ===========\n"); _RPTF1(_CRT_WARN,"CSerial::Open - DCBlength %x\n", dcb.DCBlength); _RPTF1(_CRT_WARN,"CSerial::Open - BaudRate %x\n", dcb.BaudRate); _RPTF1(_CRT_WARN,"CSerial::Open - fBinary %x\n", dcb.fBinary); _RPTF1(_CRT_WARN,"CSerial::Open - fParity %x\n", dcb.fParity); _RPTF1(_CRT_WARN,"CSerial::Open - fOutxCtsFlow %x\n", dcb.fOutxCtsFlow); _RPTF1(_CRT_WARN,"CSerial::Open - fOutxDsrFlow %x\n", dcb.fOutxDsrFlow); _RPTF1(_CRT_WARN,"CSerial::Open - fDtrControl %x\n", dcb.fDtrControl); _RPTF1(_CRT_WARN,"CSerial::Open - fDsrSensitivity %x\n", dcb.fDsrSensitivity); _RPTF1(_CRT_WARN,"CSerial::Open - fTXContinueOnXoff %x\n", dcb.fTXContinueOnXoff); _RPTF1(_CRT_WARN,"CSerial::Open - fOutX %x\n", dcb.fOutX); _RPTF1(_CRT_WARN,"CSerial::Open - fInX %x\n", dcb.fInX); _RPTF1(_CRT_WARN,"CSerial::Open - fErrorChar %x\n", dcb.fErrorChar); _RPTF1(_CRT_WARN,"CSerial::Open - fNull %x\n", dcb.fNull); _RPTF1(_CRT_WARN,"CSerial::Open - fRtsControl %x\n", dcb.fRtsControl); _RPTF1(_CRT_WARN,"CSerial::Open - fAbortOnError %x\n", dcb.fAbortOnError); _RPTF1(_CRT_WARN,"CSerial::Open - fDummy2 %x\n", dcb.fDummy2); _RPTF1(_CRT_WARN,"CSerial::Open - wReserved %x\n", dcb.wReserved); _RPTF1(_CRT_WARN,"CSerial::Open - XonLim %x\n", dcb.XonLim); _RPTF1(_CRT_WARN,"CSerial::Open - XoffLim %x\n", dcb.XoffLim); _RPTF1(_CRT_WARN,"CSerial::Open - ByteSize %x\n", dcb.ByteSize); _RPTF1(_CRT_WARN,"CSerial::Open - Parity %x\n", dcb.Parity); _RPTF1(_CRT_WARN,"CSerial::Open - StopBits %x\n", dcb.StopBits); _RPTF1(_CRT_WARN,"CSerial::Open - XonChar %x\n", dcb.XonChar); _RPTF1(_CRT_WARN,"CSerial::Open - XoffChar %x\n", dcb.XoffChar); _RPTF1(_CRT_WARN,"CSerial::Open - ErrorChar %x\n", dcb.ErrorChar); _RPTF1(_CRT_WARN,"CSerial::Open - EofChar %x\n", dcb.EofChar); _RPTF1(_CRT_WARN,"CSerial::Open - EvtChar %x\n", dcb.EvtChar); _RPTF1(_CRT_WARN,"CSerial::Open - wReserved1 %x\n", dcb.wReserved1); _RPTF0(_CRT_WARN,"CSerial::Open - ==========================\n"); // 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; //{{{ // [ADD] // for controlling RTS m_dwRefCount = 0; //}}} // 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); //{{{ // [ADD] store the baudrate for controlling RST m_baudRate = DWORD(eBaudrate); //}}} //{{{ // [ADD] // flow control : Handshaking off dcb.fRtsControl = RTS_CONTROL_DISABLE; //dcb.fRtsControl = RTS_CONTROL_TOGGLE; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.XonLim = 0x800; dcb.XoffLim = 0x200; //}}} // 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; } #if 0 _RPTF0(_CRT_WARN,"CSerial::Setup - ========== DCB ===========\n"); _RPTF1(_CRT_WARN,"CSerial::Setup - DCBlength %x\n", dcb.DCBlength); _RPTF1(_CRT_WARN,"CSerial::Setup - BaudRate %x\n", dcb.BaudRate); _RPTF1(_CRT_WARN,"CSerial::Setup - fBinary %x\n", dcb.fBinary); _RPTF1(_CRT_WARN,"CSerial::Setup - fParity %x\n", dcb.fParity); _RPTF1(_CRT_WARN,"CSerial::Setup - fOutxCtsFlow %x\n", dcb.fOutxCtsFlow); _RPTF1(_CRT_WARN,"CSerial::Setup - fOutxDsrFlow %x\n", dcb.fOutxDsrFlow); _RPTF1(_CRT_WARN,"CSerial::Setup - fDtrControl %x\n", dcb.fDtrControl); _RPTF1(_CRT_WARN,"CSerial::Setup - fDsrSensitivity %x\n", dcb.fDsrSensitivity); _RPTF1(_CRT_WARN,"CSerial::Setup - fTXContinueOnXoff %x\n", dcb.fTXContinueOnXoff); _RPTF1(_CRT_WARN,"CSerial::Setup - fOutX %x\n", dcb.fOutX); _RPTF1(_CRT_WARN,"CSerial::Setup - fInX %x\n", dcb.fInX); _RPTF1(_CRT_WARN,"CSerial::Setup - fErrorChar %x\n", dcb.fErrorChar); _RPTF1(_CRT_WARN,"CSerial::Setup - fNull %x\n", dcb.fNull); _RPTF1(_CRT_WARN,"CSerial::Setup - fRtsControl %x\n", dcb.fRtsControl); _RPTF1(_CRT_WARN,"CSerial::Setup - fAbortOnError %x\n", dcb.fAbortOnError); _RPTF1(_CRT_WARN,"CSerial::Setup - fDummy2 %x\n", dcb.fDummy2); _RPTF1(_CRT_WARN,"CSerial::Setup - wReserved %x\n", dcb.wReserved); _RPTF1(_CRT_WARN,"CSerial::Setup - XonLim %x\n", dcb.XonLim); _RPTF1(_CRT_WARN,"CSerial::Setup - XoffLim %x\n", dcb.XoffLim); _RPTF1(_CRT_WARN,"CSerial::Setup - ByteSize %x\n", dcb.ByteSize); _RPTF1(_CRT_WARN,"CSerial::Setup - Parity %x\n", dcb.Parity); _RPTF1(_CRT_WARN,"CSerial::Setup - StopBits %x\n", dcb.StopBits); _RPTF1(_CRT_WARN,"CSerial::Setup - XonChar %x\n", dcb.XonChar); _RPTF1(_CRT_WARN,"CSerial::Setup - XoffChar %x\n", dcb.XoffChar); _RPTF1(_CRT_WARN,"CSerial::Setup - ErrorChar %x\n", dcb.ErrorChar); _RPTF1(_CRT_WARN,"CSerial::Setup - EofChar %x\n", dcb.EofChar); _RPTF1(_CRT_WARN,"CSerial::Setup - EvtChar %x\n", dcb.EvtChar); _RPTF1(_CRT_WARN,"CSerial::Setup - wReserved1 %x\n", dcb.wReserved1); _RPTF0(_CRT_WARN,"CSerial::Setup - ==========================\n"); #endif //{{{ // [ADD] set RTS // _RPTF0(_CRT_WARN,"CSerial::Setup - EscapeCommFunction CLRRTS\n"); EscapeCommFunction(m_hFile, CLRRTS ); //}}} // 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; } _RPTF0(_CRT_WARN,"CSerial::SetMask - "); #if 1 // metalbrain - to avoid warning (C4390) if(dwEventMask & EEventBreak){ _RPT0(_CRT_WARN,"EEventBreak "); } if(dwEventMask & EEventCTS){ _RPT0(_CRT_WARN,"EEventCTS "); } if(dwEventMask & EEventDSR){ _RPT0(_CRT_WARN,"EEventDSR "); } if(dwEventMask & EEventError){ _RPT0(_CRT_WARN,"EEventError "); } if(dwEventMask & EEventRing){ _RPT0(_CRT_WARN,"EEventRing "); } if(dwEventMask & EEventRLSD){ _RPT0(_CRT_WARN,"EEventRLSD "); } if(dwEventMask & EEventRecv){ _RPT0(_CRT_WARN,"EEventRecv "); } if(dwEventMask & EEventRcvEv){ _RPT0(_CRT_WARN,"EEventRcvEv "); } if(dwEventMask & EEventSend){ _RPT0(_CRT_WARN,"EEventSend "); } if(dwEventMask & EEventPrinterError){ _RPT0(_CRT_WARN,"EEventPrinterError "); } if(dwEventMask & EEventRx80Full){ _RPT0(_CRT_WARN,"EEventRx80Full "); } if(dwEventMask & EEventProviderEvt1){ _RPT0(_CRT_WARN,"EEventProviderEvt1 "); } if(dwEventMask & EEventProviderEvt2){ _RPT0(_CRT_WARN,"EEventProviderEvt2 "); } #else if(dwEventMask & EEventBreak) _RPT0(_CRT_WARN,"EEventBreak "); if(dwEventMask & EEventCTS) _RPT0(_CRT_WARN,"EEventCTS "); if(dwEventMask & EEventDSR) _RPT0(_CRT_WARN,"EEventDSR "); if(dwEventMask & EEventError) _RPT0(_CRT_WARN,"EEventError "); if(dwEventMask & EEventRing) _RPT0(_CRT_WARN,"EEventRing "); if(dwEventMask & EEventRLSD) _RPT0(_CRT_WARN,"EEventRLSD "); if(dwEventMask & EEventRecv) _RPT0(_CRT_WARN,"EEventRecv "); if(dwEventMask & EEventRcvEv) _RPT0(_CRT_WARN,"EEventRcvEv "); if(dwEventMask & EEventSend) _RPT0(_CRT_WARN,"EEventSend "); if(dwEventMask & EEventPrinterError) _RPT0(_CRT_WARN,"EEventPrinterError "); if(dwEventMask & EEventRx80Full) _RPT0(_CRT_WARN,"EEventRx80Full "); if(dwEventMask & EEventProviderEvt1) _RPT0(_CRT_WARN,"EEventProviderEvt1 "); if(dwEventMask & EEventProviderEvt2) _RPT0(_CRT_WARN,"EEventProviderEvt2 "); #endif _RPT0(_CRT_WARN,"\n"); // 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 _RPTF1(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event %d\n", lLastError); return m_lLastError; } else { //_RPTF0(_CRT_WARN,"CSerial::WaitEvent - ERROR_IO_PENDING\n"); } // 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 _RPTF0(_CRT_WARN,"CSerial::WaitEvent - The overlapped operation has completed\n"); break; case WAIT_TIMEOUT: _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Cancel the I/O operation\n"); // 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. _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Success\n"); 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; } #if 0 _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - ========== DCB ===========\n"); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - DCBlength %x\n", dcb.DCBlength); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - BaudRate %x\n", dcb.BaudRate); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fBinary %x\n", dcb.fBinary); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fParity %x\n", dcb.fParity); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fOutxCtsFlow %x\n", dcb.fOutxCtsFlow); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fOutxDsrFlow %x\n", dcb.fOutxDsrFlow); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fDtrControl %x\n", dcb.fDtrControl); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fDsrSensitivity %x\n", dcb.fDsrSensitivity); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fTXContinueOnXoff %x\n", dcb.fTXContinueOnXoff); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fOutX %x\n", dcb.fOutX); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fInX %x\n", dcb.fInX); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fErrorChar %x\n", dcb.fErrorChar); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fNull %x\n", dcb.fNull); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fRtsControl %x\n", dcb.fRtsControl); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fAbortOnError %x\n", dcb.fAbortOnError); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - fDummy2 %x\n", dcb.fDummy2); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - wReserved %x\n", dcb.wReserved); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - XonLim %x\n", dcb.XonLim); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - XoffLim %x\n", dcb.XoffLim); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - ByteSize %x\n", dcb.ByteSize); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - Parity %x\n", dcb.Parity); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - StopBits %x\n", dcb.StopBits); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - XonChar %x\n", dcb.XonChar); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - XoffChar %x\n", dcb.XoffChar); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - ErrorChar %x\n", dcb.ErrorChar); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - EofChar %x\n", dcb.EofChar); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - EvtChar %x\n", dcb.EvtChar); _RPTF1(_CRT_WARN,"CSerial::SetupHandshaking - wReserved1 %x\n", dcb.wReserved1); _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - ==========================\n"); #endif // 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; } cto.WriteTotalTimeoutConstant = 0; cto.WriteTotalTimeoutMultiplier = 0; // 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; } _RPTF1(_CRT_WARN,"CSerial::SetupReadTimeouts - ReadIntervalTimeout %d\n", cto.ReadIntervalTimeout); _RPTF1(_CRT_WARN,"CSerial::SetupReadTimeouts - ReadTotalTimeoutConstant %d\n", cto.ReadTotalTimeoutConstant); _RPTF1(_CRT_WARN,"CSerial::SetupReadTimeouts - ReadTotalTimeoutMultiplier %d\n", cto.ReadTotalTimeoutMultiplier); _RPTF1(_CRT_WARN,"CSerial::SetupReadTimeouts - WriteTotalTimeoutConstant %d\n", cto.WriteTotalTimeoutConstant); _RPTF1(_CRT_WARN,"CSerial::SetupReadTimeouts - WriteTotalTimeoutMultiplier %d\n", cto.WriteTotalTimeoutMultiplier); // 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)); //{{{ // [ADD] EnterCriticalSection(&m_CritSect); if(m_dwRefCount == 0) { _RPTF0(_CRT_WARN,"CSerial::Write - EscapeCommFunction SETRTS\n"); EscapeCommFunction(m_hFile, SETRTS); } m_dwRefCount++; LeaveCriticalSection(&m_CritSect); //}}} // 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; } else { //_RPTF0(_CRT_WARN,"CSerial::Write - ERROR_IO_PENDING\n"); } // 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; } #if 1 // metalbrain if (iLen != *pdwWritten){ _RPTF2(_CRT_WARN,"CSerial::Write - Bytes Sent: %d; Message Length: %d\n", *pdwWritten, iLen); } #else if (iLen != *pdwWritten) _RPTF2(_CRT_WARN,"CSerial::Write - Bytes Sent: %d; Message Length: %d\n", *pdwWritten, iLen); #endif break; case WAIT_TIMEOUT: _RPTF0(_CRT_WARN,"CSerial::Write - Cancel the I/O operation\n"); // 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; } void DELAY(ULONG microsec) { LARGE_INTEGER Freq, Start, End; double Elapse; End.QuadPart = 0; QueryPerformanceFrequency(&Freq); QueryPerformanceCounter(&Start); do { for(int i = 0; i < 1000; i++) QueryPerformanceCounter(&End); Elapse = (double)((End.QuadPart - Start.QuadPart) * 1000000 / Freq.QuadPart); } while(Elapse < microsec); _RPTF2(_CRT_WARN, "DELAY - Elapse %f delay %d\n", Elapse, microsec); }