Subversion Repositories HomeAutomation

Rev

Rev 270 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. //  Serial.cpp - Implementation of the CSerial class
  2. //
  3. //  Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl)
  4. //
  5. // This library is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU Lesser General Public
  7. // License as published by the Free Software Foundation; either
  8. // version 2.1 of the License, or (at your option) any later version.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. // Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public
  16. // License along with this library; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.  
  20. //////////////////////////////////////////////////////////////////////
  21. // Include the standard header files
  22.  
  23. #define STRICT
  24. #include <crtdbg.h>
  25. #include <tchar.h>
  26. #include <windows.h>
  27. #include "stdafx.h"
  28.  
  29.  
  30. //////////////////////////////////////////////////////////////////////
  31. // Include module headerfile
  32.  
  33. #include "Serial.h"
  34.  
  35.  
  36. //////////////////////////////////////////////////////////////////////
  37. // Disable warning C4127: conditional expression is constant, which
  38. // is generated when using the _RPTF and _ASSERTE macros.
  39.  
  40. #pragma warning(disable: 4127)
  41.  
  42.  
  43. //////////////////////////////////////////////////////////////////////
  44. // Enable debug memory manager
  45.  
  46. #ifdef _DEBUG
  47.  
  48. #ifdef THIS_FILE
  49. #undef THIS_FILE
  50. #endif
  51.  
  52. static const char THIS_FILE[] = __FILE__;
  53. #define new DEBUG_NEW
  54.  
  55. #endif
  56.  
  57.  
  58. //////////////////////////////////////////////////////////////////////
  59. // Helper methods
  60.  
  61. inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const
  62. {
  63. #ifdef SERIAL_NO_OVERLAPPED
  64.  
  65.     // Check if an overlapped structure has been specified
  66.     if (lpOverlapped || (dwTimeout != INFINITE))
  67.     {
  68.         // Quit application
  69.         ::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);
  70.         ::DebugBreak();
  71.         ::ExitProcess(0xFFFFFFF);
  72.     }
  73.  
  74. #endif
  75.  
  76. #ifdef SERIAL_NO_CANCELIO
  77.  
  78.     // Check if 0 or INFINITE time-out has been specified, because
  79.     // the communication I/O cannot be cancelled.
  80.     if ((dwTimeout != 0) && (dwTimeout != INFINITE))
  81.     {
  82.         // Quit application
  83.         ::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
  84.         ::DebugBreak();
  85.         ::ExitProcess(0xFFFFFFF);
  86.     }
  87.  
  88. #endif  // SERIAL_NO_CANCELIO
  89.  
  90.     // Avoid warnings
  91.     (void) dwTimeout;
  92.     (void) lpOverlapped;
  93. }
  94.  
  95. inline BOOL CSerial::CancelCommIo (void)
  96. {
  97. #ifdef SERIAL_NO_CANCELIO
  98.     // CancelIo shouldn't have been called at this point
  99.     ::DebugBreak();
  100.     return FALSE;
  101. #else
  102.  
  103.     // Cancel the I/O request
  104.     return ::CancelIo(m_hFile);
  105.  
  106. #endif  // SERIAL_NO_CANCELIO
  107. }
  108.  
  109.  
  110. //////////////////////////////////////////////////////////////////////
  111. // Code
  112.  
  113. CSerial::CSerial ()
  114.     : m_lLastError(ERROR_SUCCESS)
  115.     , m_hFile(0)
  116.     , m_eEvent(EEventNone)
  117.     , m_dwEventMask(0)
  118. #ifndef SERIAL_NO_OVERLAPPED
  119.     , m_hevtOverlapped(0)
  120. #endif
  121. {
  122. }
  123.  
  124. CSerial::~CSerial ()
  125. {
  126.     // If the device is already closed,
  127.     // then we don't need to do anything.
  128.     if (m_hFile)
  129.     {
  130.         // Display a warning
  131.         _RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n");
  132.  
  133.         // Close implicitly
  134.         Close();
  135.     }
  136. }
  137.  
  138. CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice)
  139. {
  140.     // Try to open the device
  141.     HANDLE hFile = ::CreateFile(lpszDevice,
  142.                            GENERIC_READ|GENERIC_WRITE,
  143.                            0,
  144.                            0,
  145.                            OPEN_EXISTING,
  146.                            0,
  147.                            0);
  148.  
  149.     // Check if we could open the device
  150.     if (hFile == INVALID_HANDLE_VALUE)
  151.     {
  152.         // Display error
  153.         switch (::GetLastError())
  154.         {
  155.         case ERROR_FILE_NOT_FOUND:
  156.             // The specified COM-port does not exist
  157.             return EPortNotAvailable;
  158.  
  159.         case ERROR_ACCESS_DENIED:
  160.             // The specified COM-port is in use
  161.             return EPortInUse;
  162.  
  163.         default:
  164.             // Something else is wrong
  165.             return EPortUnknownError;
  166.         }
  167.     }
  168.  
  169.     // Close handle
  170.     ::CloseHandle(hFile);
  171.  
  172.     // Port is available
  173.     return EPortAvailable;
  174. }
  175.  
  176. LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped)
  177. {
  178.     // Reset error state
  179.     m_lLastError = ERROR_SUCCESS;
  180.  
  181.     // Check if the port isn't already opened
  182.     if (m_hFile)
  183.     {
  184.         m_lLastError = ERROR_ALREADY_INITIALIZED;
  185.         _RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n");
  186.         return m_lLastError;
  187.     }
  188.  
  189.     // Open the device
  190.     m_hFile = ::CreateFile(lpszDevice,
  191.                            GENERIC_READ|GENERIC_WRITE,
  192.                            0,
  193.                            0,
  194.                            OPEN_EXISTING,
  195.                            fOverlapped?FILE_FLAG_OVERLAPPED:0,
  196.                            0);
  197.     if (m_hFile == INVALID_HANDLE_VALUE)
  198.     {
  199.         // Reset file handle
  200.         m_hFile = 0;
  201.  
  202.         // Display error
  203.         m_lLastError = ::GetLastError();
  204.         _RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
  205.         return m_lLastError;
  206.     }
  207.  
  208. #ifndef SERIAL_NO_OVERLAPPED
  209.     // We cannot have an event handle yet
  210.     _ASSERTE(m_hevtOverlapped == 0);
  211.  
  212.     // Create the event handle for internal overlapped operations (manual reset)
  213.     if (fOverlapped)
  214.     {
  215.         m_hevtOverlapped = ::CreateEvent(0,true,false,0);
  216.         if (m_hevtOverlapped == 0)
  217.         {
  218.             // Obtain the error information
  219.             m_lLastError = ::GetLastError();
  220.             _RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");
  221.  
  222.             // Close the port
  223.             ::CloseHandle(m_hFile);
  224.             m_hFile = 0;
  225.  
  226.             // Return the error
  227.             return m_lLastError;
  228.         }
  229.     }
  230. #else
  231.    
  232.     // Overlapped flag shouldn't be specified
  233.     _ASSERTE(!fOverlapped);
  234.  
  235. #endif
  236.  
  237.     // Setup the COM-port
  238.     if (dwInQueue || dwOutQueue)
  239.     {
  240.         // Make sure the queue-sizes are reasonable sized. Win9X systems crash
  241.         // if the input queue-size is zero. Both queues need to be at least
  242.         // 16 bytes large.
  243.         _ASSERTE(dwInQueue >= 16);
  244.         _ASSERTE(dwOutQueue >= 16);
  245.  
  246.         if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
  247.         {
  248.             // Display a warning
  249.             long lLastError = ::GetLastError();
  250.             _RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");
  251.  
  252.             // Close the port
  253.             Close();
  254.  
  255.             // Save last error from SetupComm
  256.             m_lLastError = lLastError;
  257.             return m_lLastError;   
  258.         }
  259.     }
  260.  
  261.     // Setup the default communication mask
  262.     SetMask();
  263.  
  264.     // Non-blocking reads is default
  265.     SetupReadTimeouts(EReadTimeoutNonblocking);
  266.  
  267.     // Setup the device for default settings
  268.     COMMCONFIG commConfig = {0};
  269.     DWORD dwSize = sizeof(commConfig);
  270.     commConfig.dwSize = dwSize;
  271.     if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize))
  272.     {
  273.         // Set the default communication configuration
  274.         if (!::SetCommConfig(m_hFile,&commConfig,dwSize))
  275.         {
  276.             // Display a warning
  277.             _RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n");
  278.         }
  279.     }
  280.     else
  281.     {
  282.         // Display a warning
  283.         _RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n");
  284.     }
  285.  
  286.     // Return successful
  287.     return m_lLastError;
  288. }
  289.  
  290. LONG CSerial::Close (void)
  291. {
  292.     // Reset error state
  293.     m_lLastError = ERROR_SUCCESS;
  294.  
  295.     // If the device is already closed,
  296.     // then we don't need to do anything.
  297.     if (m_hFile == 0)
  298.     {
  299.         // Display a warning
  300.         _RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n");
  301.         return m_lLastError;
  302.     }
  303.  
  304. #ifndef SERIAL_NO_OVERLAPPED
  305.     // Free event handle
  306.     if (m_hevtOverlapped)
  307.     {
  308.         ::CloseHandle(m_hevtOverlapped);
  309.         m_hevtOverlapped = 0;
  310.     }
  311. #endif
  312.  
  313.     // Close COM port
  314.     ::CloseHandle(m_hFile);
  315.     m_hFile = 0;
  316.  
  317.     // Return successful
  318.     return m_lLastError;
  319. }
  320.  
  321. LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
  322. {
  323.     // Reset error state
  324.     m_lLastError = ERROR_SUCCESS;
  325.  
  326.     // Check if the device is open
  327.     if (m_hFile == 0)
  328.     {
  329.         // Set the internal error code
  330.         m_lLastError = ERROR_INVALID_HANDLE;
  331.  
  332.         // Issue an error and quit
  333.         _RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n");
  334.         return m_lLastError;
  335.     }
  336.  
  337.     // Obtain the DCB structure for the device
  338.     CDCB dcb;
  339.     if (!::GetCommState(m_hFile,&dcb))
  340.     {
  341.         // Obtain the error code
  342.         m_lLastError = ::   GetLastError();
  343.  
  344.         // Display a warning
  345.         _RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
  346.         return m_lLastError;
  347.     }
  348.  
  349.     // Set the new data
  350.     dcb.BaudRate = DWORD(eBaudrate);
  351.     dcb.ByteSize = BYTE(eDataBits);
  352.     dcb.Parity   = BYTE(eParity);
  353.     dcb.StopBits = BYTE(eStopBits);
  354.  
  355.     // Determine if parity is used
  356.     dcb.fParity  = (eParity != EParNone);
  357.  
  358.     // Set the new DCB structure
  359.     if (!::SetCommState(m_hFile,&dcb))
  360.     {
  361.         // Obtain the error code
  362.         m_lLastError = ::GetLastError();
  363.  
  364.         // Display a warning
  365.         _RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n");
  366.         return m_lLastError;
  367.     }
  368.  
  369.     // Return successful
  370.     return m_lLastError;
  371. }
  372.  
  373. LONG CSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask)
  374. {
  375.     // Reset error state
  376.     m_lLastError = ERROR_SUCCESS;
  377.  
  378.     // Check if the device is open
  379.     if (m_hFile == 0)
  380.     {
  381.         // Set the internal error code
  382.         m_lLastError = ERROR_INVALID_HANDLE;
  383.  
  384.         // Issue an error and quit
  385.         _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n");
  386.         return m_lLastError;
  387.     }
  388.  
  389.     // Obtain the DCB structure for the device
  390.     CDCB dcb;
  391.     if (!::GetCommState(m_hFile,&dcb))
  392.     {
  393.         // Obtain the error code
  394.         m_lLastError = ::GetLastError();
  395.  
  396.         // Display a warning
  397.         _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n");
  398.         return m_lLastError;
  399.     }
  400.  
  401.     // Set the new event character
  402.     dcb.EvtChar = char(bEventChar);
  403.  
  404.     // Adjust the event mask, to make sure the event will be received
  405.     if (fAdjustMask)
  406.     {
  407.         // Enable 'receive event character' event.  Note that this
  408.         // will generate an EEventNone if there is an asynchronous
  409.         // WaitCommEvent pending.
  410.         SetMask(GetEventMask() | EEventRcvEv);
  411.     }
  412.  
  413.     // Set the new DCB structure
  414.     if (!::SetCommState(m_hFile,&dcb))
  415.     {
  416.         // Obtain the error code
  417.         m_lLastError = ::GetLastError();
  418.  
  419.         // Display a warning
  420.         _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n");
  421.         return m_lLastError;
  422.     }
  423.  
  424.     // Return successful
  425.     return m_lLastError;
  426. }
  427.  
  428. LONG CSerial::SetMask (DWORD dwEventMask)
  429. {
  430.     // Reset error state
  431.     m_lLastError = ERROR_SUCCESS;
  432.  
  433.     // Check if the device is open
  434.     if (m_hFile == 0)
  435.     {
  436.         // Set the internal error code
  437.         m_lLastError = ERROR_INVALID_HANDLE;
  438.  
  439.         // Issue an error and quit
  440.         _RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n");
  441.         return m_lLastError;
  442.     }
  443.  
  444.     // Set the new mask. Note that this will generate an EEventNone
  445.     // if there is an asynchronous WaitCommEvent pending.
  446.     if (!::SetCommMask(m_hFile,dwEventMask))
  447.     {
  448.         // Obtain the error code
  449.         m_lLastError = ::GetLastError();
  450.  
  451.         // Display a warning
  452.         _RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n");
  453.         return m_lLastError;
  454.     }
  455.  
  456.     // Save event mask and return successful
  457.     m_dwEventMask = dwEventMask;
  458.     return m_lLastError;
  459. }
  460.  
  461. LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
  462. {
  463.     // Check if time-outs are supported
  464.     CheckRequirements(lpOverlapped,dwTimeout);
  465.  
  466.     // Reset error state
  467.     m_lLastError = ERROR_SUCCESS;
  468.  
  469.     // Check if the device is open
  470.     if (m_hFile == 0)
  471.     {
  472.         // Set the internal error code
  473.         m_lLastError = ERROR_INVALID_HANDLE;
  474.  
  475.         // Issue an error and quit
  476.         _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n");
  477.         return m_lLastError;
  478.     }
  479.  
  480. #ifndef SERIAL_NO_OVERLAPPED
  481.  
  482.     // Check if an overlapped structure has been specified
  483.     if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
  484.     {
  485.         // Set the internal error code
  486.         m_lLastError = ERROR_INVALID_FUNCTION;
  487.  
  488.         // Issue an error and quit
  489.         _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n");
  490.         return m_lLastError;
  491.     }
  492.  
  493.     // Wait for the event to happen
  494.     OVERLAPPED ovInternal;
  495.     if (!lpOverlapped && m_hevtOverlapped)
  496.     {
  497.         // Setup our own overlapped structure
  498.         memset(&ovInternal,0,sizeof(ovInternal));
  499.         ovInternal.hEvent = m_hevtOverlapped;
  500.  
  501.         // Use our internal overlapped structure
  502.         lpOverlapped = &ovInternal;
  503.     }
  504.  
  505.     // Make sure the overlapped structure isn't busy
  506.     _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
  507.  
  508.     // Wait for the COM event
  509.     if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped))
  510.     {
  511.         // Set the internal error code
  512.         long lLastError = ::GetLastError();
  513.  
  514.         // Overlapped operation in progress is not an actual error
  515.         if (lLastError != ERROR_IO_PENDING)
  516.         {
  517.             // Save the error
  518.             m_lLastError = lLastError;
  519.  
  520.             // Issue an error and quit
  521.             _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
  522.             return m_lLastError;
  523.         }
  524.  
  525.         // We need to block if the client didn't specify an overlapped structure
  526.         if (lpOverlapped == &ovInternal)
  527.         {
  528.             // Wait for the overlapped operation to complete
  529.             switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
  530.             {
  531.             case WAIT_OBJECT_0:
  532.                 // The overlapped operation has completed
  533.                 break;
  534.  
  535.             case WAIT_TIMEOUT:
  536.                 // Cancel the I/O operation
  537.                 CancelCommIo();
  538.  
  539.                 // The operation timed out. Set the internal error code and quit
  540.                 m_lLastError = ERROR_TIMEOUT;
  541.                 return m_lLastError;
  542.  
  543.             default:
  544.                 // Set the internal error code
  545.                 m_lLastError = ::GetLastError();
  546.  
  547.                 // Issue an error and quit
  548.                 _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait until COM event has arrived\n");
  549.                 return m_lLastError;
  550.             }
  551.         }
  552.     }
  553.     else
  554.     {
  555.         // The operation completed immediatly. Just to be sure
  556.         // we'll set the overlapped structure's event handle.
  557.         if (lpOverlapped)
  558.             ::SetEvent(lpOverlapped->hEvent);
  559.     }
  560. #else
  561.  
  562.     // Wait for the COM event
  563.     if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),0))
  564.     {
  565.         // Set the internal error code
  566.         m_lLastError = ::GetLastError();
  567.  
  568.         // Issue an error and quit
  569.         _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
  570.         return m_lLastError;
  571.     }
  572.  
  573. #endif
  574.  
  575.     // Return successfully
  576.     return m_lLastError;
  577. }
  578.  
  579.  
  580. LONG CSerial::SetupHandshaking (EHandshake eHandshake)
  581. {
  582.     // Reset error state
  583.     m_lLastError = ERROR_SUCCESS;
  584.  
  585.     // Check if the device is open
  586.     if (m_hFile == 0)
  587.     {
  588.         // Set the internal error code
  589.         m_lLastError = ERROR_INVALID_HANDLE;
  590.  
  591.         // Issue an error and quit
  592.         _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Device is not opened\n");
  593.         return m_lLastError;
  594.     }
  595.  
  596.     // Obtain the DCB structure for the device
  597.     CDCB dcb;
  598.     if (!::GetCommState(m_hFile,&dcb))
  599.     {
  600.         // Obtain the error code
  601.         m_lLastError = ::GetLastError();
  602.  
  603.         // Display a warning
  604.         _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to obtain DCB information\n");
  605.         return m_lLastError;
  606.     }
  607.  
  608.     // Set the handshaking flags
  609.     switch (eHandshake)
  610.     {
  611.     case EHandshakeOff:
  612.         dcb.fOutxCtsFlow = false;                   // Disable CTS monitoring
  613.         dcb.fOutxDsrFlow = false;                   // Disable DSR monitoring
  614.         dcb.fDtrControl = DTR_CONTROL_DISABLE;      // Disable DTR monitoring
  615.         dcb.fOutX = false;                          // Disable XON/XOFF for transmission
  616.         dcb.fInX = false;                           // Disable XON/XOFF for receiving
  617.         dcb.fRtsControl = RTS_CONTROL_DISABLE;      // Disable RTS (Ready To Send)
  618.         break;
  619.  
  620.     case EHandshakeHardware:
  621.         dcb.fOutxCtsFlow = true;                    // Enable CTS monitoring
  622.         dcb.fOutxDsrFlow = true;                    // Enable DSR monitoring
  623.         dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;    // Enable DTR handshaking
  624.         dcb.fOutX = false;                          // Disable XON/XOFF for transmission
  625.         dcb.fInX = false;                           // Disable XON/XOFF for receiving
  626.         dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;    // Enable RTS handshaking
  627.         break;
  628.  
  629.     case EHandshakeSoftware:
  630.         dcb.fOutxCtsFlow = false;                   // Disable CTS (Clear To Send)
  631.         dcb.fOutxDsrFlow = false;                   // Disable DSR (Data Set Ready)
  632.         dcb.fDtrControl = DTR_CONTROL_DISABLE;      // Disable DTR (Data Terminal Ready)
  633.         dcb.fOutX = true;                           // Enable XON/XOFF for transmission
  634.         dcb.fInX = true;                            // Enable XON/XOFF for receiving
  635.         dcb.fRtsControl = RTS_CONTROL_DISABLE;      // Disable RTS (Ready To Send)
  636.         break;
  637.  
  638.     default:
  639.         // This shouldn't be possible
  640.         _ASSERTE(false);
  641.         m_lLastError = E_INVALIDARG;
  642.         return m_lLastError;
  643.     }
  644.  
  645.     // Set the new DCB structure
  646.     if (!::SetCommState(m_hFile,&dcb))
  647.     {
  648.         // Obtain the error code
  649.         m_lLastError = ::GetLastError();
  650.  
  651.         // Display a warning
  652.         _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to set DCB information\n");
  653.         return m_lLastError;
  654.     }
  655.  
  656.     // Return successful
  657.     return m_lLastError;
  658. }
  659.  
  660. LONG CSerial::SetupReadTimeouts (EReadTimeout eReadTimeout)
  661. {
  662.     // Reset error state
  663.     m_lLastError = ERROR_SUCCESS;
  664.  
  665.     // Check if the device is open
  666.     if (m_hFile == 0)
  667.     {
  668.         // Set the internal error code
  669.         m_lLastError = ERROR_INVALID_HANDLE;
  670.  
  671.         // Issue an error and quit
  672.         _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Device is not opened\n");
  673.         return m_lLastError;
  674.     }
  675.  
  676.     // Determine the time-outs
  677.     COMMTIMEOUTS cto;
  678.     if (!::GetCommTimeouts(m_hFile,&cto))
  679.     {
  680.         // Obtain the error code
  681.         m_lLastError = ::GetLastError();
  682.  
  683.         // Display a warning
  684.         _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to obtain timeout information\n");
  685.         return m_lLastError;
  686.     }
  687.  
  688.     // Set the new timeouts
  689.     switch (eReadTimeout)
  690.     {
  691.     case EReadTimeoutBlocking:
  692.         cto.ReadIntervalTimeout = 0;
  693.         cto.ReadTotalTimeoutConstant = 0;
  694.         cto.ReadTotalTimeoutMultiplier = 0;
  695.         break;
  696.     case EReadTimeoutNonblocking:
  697.         cto.ReadIntervalTimeout = MAXDWORD;
  698.         cto.ReadTotalTimeoutConstant = 0;
  699.         cto.ReadTotalTimeoutMultiplier = 0;
  700.         break;
  701.     default:
  702.         // This shouldn't be possible
  703.         _ASSERTE(false);
  704.         m_lLastError = E_INVALIDARG;
  705.         return m_lLastError;
  706.     }
  707.  
  708.     // Set the new DCB structure
  709.     if (!::SetCommTimeouts(m_hFile,&cto))
  710.     {
  711.         // Obtain the error code
  712.         m_lLastError = ::GetLastError();
  713.  
  714.         // Display a warning
  715.         _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n");
  716.         return m_lLastError;
  717.     }
  718.  
  719.     // Return successful
  720.     return m_lLastError;
  721. }
  722.  
  723. CSerial::EBaudrate CSerial::GetBaudrate (void)
  724. {
  725.     // Reset error state
  726.     m_lLastError = ERROR_SUCCESS;
  727.  
  728.     // Check if the device is open
  729.     if (m_hFile == 0)
  730.     {
  731.         // Set the internal error code
  732.         m_lLastError = ERROR_INVALID_HANDLE;
  733.  
  734.         // Issue an error and quit
  735.         _RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Device is not opened\n");
  736.         return EBaudUnknown;
  737.     }
  738.  
  739.     // Obtain the DCB structure for the device
  740.     CDCB dcb;
  741.     if (!::GetCommState(m_hFile,&dcb))
  742.     {
  743.         // Obtain the error code
  744.         m_lLastError = ::GetLastError();
  745.  
  746.         // Display a warning
  747.         _RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Unable to obtain DCB information\n");
  748.         return EBaudUnknown;
  749.     }
  750.  
  751.     // Return the appropriate baudrate
  752.     return EBaudrate(dcb.BaudRate);
  753. }
  754.  
  755. CSerial::EDataBits CSerial::GetDataBits (void)
  756. {
  757.     // Reset error state
  758.     m_lLastError = ERROR_SUCCESS;
  759.  
  760.     // Check if the device is open
  761.     if (m_hFile == 0)
  762.     {
  763.         // Set the internal error code
  764.         m_lLastError = ERROR_INVALID_HANDLE;
  765.  
  766.         // Issue an error and quit
  767.         _RPTF0(_CRT_WARN,"CSerial::GetDataBits - Device is not opened\n");
  768.         return EDataUnknown;
  769.     }
  770.  
  771.     // Obtain the DCB structure for the device
  772.     CDCB dcb;
  773.     if (!::GetCommState(m_hFile,&dcb))
  774.     {
  775.         // Obtain the error code
  776.         m_lLastError = ::GetLastError();
  777.  
  778.         // Display a warning
  779.         _RPTF0(_CRT_WARN,"CSerial::GetDataBits - Unable to obtain DCB information\n");
  780.         return EDataUnknown;
  781.     }
  782.  
  783.     // Return the appropriate bytesize
  784.     return EDataBits(dcb.ByteSize);
  785. }
  786.  
  787. CSerial::EParity CSerial::GetParity (void)
  788. {
  789.     // Reset error state
  790.     m_lLastError = ERROR_SUCCESS;
  791.  
  792.     // Check if the device is open
  793.     if (m_hFile == 0)
  794.     {
  795.         // Set the internal error code
  796.         m_lLastError = ERROR_INVALID_HANDLE;
  797.  
  798.         // Issue an error and quit
  799.         _RPTF0(_CRT_WARN,"CSerial::GetParity - Device is not opened\n");
  800.         return EParUnknown;
  801.     }
  802.  
  803.     // Obtain the DCB structure for the device
  804.     CDCB dcb;
  805.     if (!::GetCommState(m_hFile,&dcb))
  806.     {
  807.         // Obtain the error code
  808.         m_lLastError = ::GetLastError();
  809.  
  810.         // Display a warning
  811.         _RPTF0(_CRT_WARN,"CSerial::GetParity - Unable to obtain DCB information\n");
  812.         return EParUnknown;
  813.     }
  814.  
  815.     // Check if parity is used
  816.     if (!dcb.fParity)
  817.     {
  818.         // No parity
  819.         return EParNone;
  820.     }
  821.  
  822.     // Return the appropriate parity setting
  823.     return EParity(dcb.Parity);
  824. }
  825.  
  826. CSerial::EStopBits CSerial::GetStopBits (void)
  827. {
  828.     // Reset error state
  829.     m_lLastError = ERROR_SUCCESS;
  830.  
  831.     // Check if the device is open
  832.     if (m_hFile == 0)
  833.     {
  834.         // Set the internal error code
  835.         m_lLastError = ERROR_INVALID_HANDLE;
  836.  
  837.         // Issue an error and quit
  838.         _RPTF0(_CRT_WARN,"CSerial::GetStopBits - Device is not opened\n");
  839.         return EStopUnknown;
  840.     }
  841.  
  842.     // Obtain the DCB structure for the device
  843.     CDCB dcb;
  844.     if (!::GetCommState(m_hFile,&dcb))
  845.     {
  846.         // Obtain the error code
  847.         m_lLastError = ::GetLastError();
  848.  
  849.         // Display a warning
  850.         _RPTF0(_CRT_WARN,"CSerial::GetStopBits - Unable to obtain DCB information\n");
  851.         return EStopUnknown;
  852.     }
  853.  
  854.     // Return the appropriate stopbits
  855.     return EStopBits(dcb.StopBits);
  856. }
  857.  
  858. DWORD CSerial::GetEventMask (void)
  859. {
  860.     // Reset error state
  861.     m_lLastError = ERROR_SUCCESS;
  862.  
  863.     // Check if the device is open
  864.     if (m_hFile == 0)
  865.     {
  866.         // Set the internal error code
  867.         m_lLastError = ERROR_INVALID_HANDLE;
  868.  
  869.         // Issue an error and quit
  870.         _RPTF0(_CRT_WARN,"CSerial::GetEventMask - Device is not opened\n");
  871.         return 0;
  872.     }
  873.  
  874.     // Return the event mask
  875.     return m_dwEventMask;
  876. }
  877.  
  878. BYTE CSerial::GetEventChar (void)
  879. {
  880.     // Reset error state
  881.     m_lLastError = ERROR_SUCCESS;
  882.  
  883.     // Check if the device is open
  884.     if (m_hFile == 0)
  885.     {
  886.         // Set the internal error code
  887.         m_lLastError = ERROR_INVALID_HANDLE;
  888.  
  889.         // Issue an error and quit
  890.         _RPTF0(_CRT_WARN,"CSerial::GetEventChar - Device is not opened\n");
  891.         return 0;
  892.     }
  893.  
  894.     // Obtain the DCB structure for the device
  895.     CDCB dcb;
  896.     if (!::GetCommState(m_hFile,&dcb))
  897.     {
  898.         // Obtain the error code
  899.         m_lLastError = ::GetLastError();
  900.  
  901.         // Display a warning
  902.         _RPTF0(_CRT_WARN,"CSerial::GetEventChar - Unable to obtain DCB information\n");
  903.         return 0;
  904.     }
  905.  
  906.     // Set the new event character
  907.     return BYTE(dcb.EvtChar);
  908. }
  909.  
  910. CSerial::EHandshake CSerial::GetHandshaking (void)
  911. {
  912.     // Reset error state
  913.     m_lLastError = ERROR_SUCCESS;
  914.  
  915.     // Check if the device is open
  916.     if (m_hFile == 0)
  917.     {
  918.         // Set the internal error code
  919.         m_lLastError = ERROR_INVALID_HANDLE;
  920.  
  921.         // Issue an error and quit
  922.         _RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Device is not opened\n");
  923.         return EHandshakeUnknown;
  924.     }
  925.  
  926.     // Obtain the DCB structure for the device
  927.     CDCB dcb;
  928.     if (!::GetCommState(m_hFile,&dcb))
  929.     {
  930.         // Obtain the error code
  931.         m_lLastError = ::GetLastError();
  932.  
  933.         // Display a warning
  934.         _RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Unable to obtain DCB information\n");
  935.         return EHandshakeUnknown;
  936.     }
  937.  
  938.     // Check if hardware handshaking is being used
  939.     if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE))
  940.         return EHandshakeHardware;
  941.  
  942.     // Check if software handshaking is being used
  943.     if (dcb.fOutX && dcb.fInX)
  944.         return EHandshakeSoftware;
  945.  
  946.     // No handshaking is being used
  947.     return EHandshakeOff;
  948. }
  949.  
  950. LONG CSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
  951. {
  952.     // Check if time-outs are supported
  953.     CheckRequirements(lpOverlapped,dwTimeout);
  954.  
  955.     // Overlapped operation should specify the pdwWritten variable
  956.     _ASSERTE(!lpOverlapped || pdwWritten);
  957.  
  958.     // Reset error state
  959.     m_lLastError = ERROR_SUCCESS;
  960.  
  961.     // Use our own variable for read count
  962.     DWORD dwWritten;
  963.     if (pdwWritten == 0)
  964.     {
  965.         pdwWritten = &dwWritten;
  966.     }
  967.  
  968.     // Reset the number of bytes written
  969.     *pdwWritten = 0;
  970.  
  971.     // Check if the device is open
  972.     if (m_hFile == 0)
  973.     {
  974.         // Set the internal error code
  975.         m_lLastError = ERROR_INVALID_HANDLE;
  976.  
  977.         // Issue an error and quit
  978.         _RPTF0(_CRT_WARN,"CSerial::Write - Device is not opened\n");
  979.         return m_lLastError;
  980.     }
  981.  
  982. #ifndef SERIAL_NO_OVERLAPPED
  983.  
  984.     // Check if an overlapped structure has been specified
  985.     if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
  986.     {
  987.         // Set the internal error code
  988.         m_lLastError = ERROR_INVALID_FUNCTION;
  989.  
  990.         // Issue an error and quit
  991.         _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped I/O is disabled, specified parameters are illegal.\n");
  992.         return m_lLastError;
  993.     }
  994.  
  995.     // Wait for the event to happen
  996.     OVERLAPPED ovInternal;
  997.     if (!lpOverlapped && m_hevtOverlapped)
  998.     {
  999.         // Setup our own overlapped structure
  1000.         memset(&ovInternal,0,sizeof(ovInternal));
  1001.         ovInternal.hEvent = m_hevtOverlapped;
  1002.  
  1003.         // Use our internal overlapped structure
  1004.         lpOverlapped = &ovInternal;
  1005.     }
  1006.  
  1007.     // Make sure the overlapped structure isn't busy
  1008.     _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
  1009.  
  1010.     // Write the data
  1011.     if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped))
  1012.     {
  1013.         // Set the internal error code
  1014.         long lLastError = ::GetLastError();
  1015.  
  1016.         // Overlapped operation in progress is not an actual error
  1017.         if (lLastError != ERROR_IO_PENDING)
  1018.         {
  1019.             // Save the error
  1020.             m_lLastError = lLastError;
  1021.  
  1022.             // Issue an error and quit
  1023.             _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
  1024.             return m_lLastError;
  1025.         }
  1026.  
  1027.         // We need to block if the client didn't specify an overlapped structure
  1028.         if (lpOverlapped == &ovInternal)
  1029.         {
  1030.             // Wait for the overlapped operation to complete
  1031.             switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
  1032.             {
  1033.             case WAIT_OBJECT_0:
  1034.                 // The overlapped operation has completed
  1035.                 if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE))
  1036.                 {
  1037.                     // Set the internal error code
  1038.                     m_lLastError = ::GetLastError();
  1039.  
  1040.                     _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped completed without result\n");
  1041.                     return m_lLastError;
  1042.                 }
  1043.                 break;
  1044.  
  1045.             case WAIT_TIMEOUT:
  1046.                 // Cancel the I/O operation
  1047.                 CancelCommIo();
  1048.  
  1049.                 // The operation timed out. Set the internal error code and quit
  1050.                 m_lLastError = ERROR_TIMEOUT;
  1051.                 return m_lLastError;
  1052.  
  1053.             default:
  1054.                 // Set the internal error code
  1055.                 m_lLastError = ::GetLastError();
  1056.  
  1057.                 // Issue an error and quit
  1058.                 _RPTF0(_CRT_WARN,"CSerial::Write - Unable to wait until data has been sent\n");
  1059.                 return m_lLastError;
  1060.             }
  1061.         }
  1062.     }
  1063.     else
  1064.     {
  1065.         // The operation completed immediatly. Just to be sure
  1066.         // we'll set the overlapped structure's event handle.
  1067.         if (lpOverlapped)
  1068.             ::SetEvent(lpOverlapped->hEvent);
  1069.     }
  1070.  
  1071. #else
  1072.  
  1073.     // Write the data
  1074.     if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,0))
  1075.     {
  1076.         // Set the internal error code
  1077.         m_lLastError = ::GetLastError();
  1078.  
  1079.         // Issue an error and quit
  1080.         _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
  1081.         return m_lLastError;
  1082.     }
  1083.  
  1084. #endif
  1085.  
  1086.     // Return successfully
  1087.     return m_lLastError;
  1088. }
  1089.  
  1090. LONG CSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
  1091. {
  1092.     // Check if time-outs are supported
  1093.     CheckRequirements(lpOverlapped,dwTimeout);
  1094.  
  1095.     // Determine the length of the string
  1096.     return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout);
  1097. }
  1098.  
  1099. LONG CSerial::Read (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
  1100. {
  1101.     // Check if time-outs are supported
  1102.     CheckRequirements(lpOverlapped,dwTimeout);
  1103.  
  1104.     // Overlapped operation should specify the pdwRead variable
  1105.     _ASSERTE(!lpOverlapped || pdwRead);
  1106.  
  1107.     // Reset error state
  1108.     m_lLastError = ERROR_SUCCESS;
  1109.  
  1110.     // Use our own variable for read count
  1111.     DWORD dwRead;
  1112.     if (pdwRead == 0)
  1113.     {
  1114.         pdwRead = &dwRead;
  1115.     }
  1116.  
  1117.     // Reset the number of bytes read
  1118.     *pdwRead = 0;
  1119.  
  1120.     // Check if the device is open
  1121.     if (m_hFile == 0)
  1122.     {
  1123.         // Set the internal error code
  1124.         m_lLastError = ERROR_INVALID_HANDLE;
  1125.  
  1126.         // Issue an error and quit
  1127.         _RPTF0(_CRT_WARN,"CSerial::Read - Device is not opened\n");
  1128.         return m_lLastError;
  1129.     }
  1130.  
  1131. #ifdef _DEBUG
  1132.     // The debug version fills the entire data structure with
  1133.     // 0xDC bytes, to catch buffer errors as soon as possible.
  1134.     memset(pData,0xDC,iLen);
  1135. #endif
  1136.  
  1137. #ifndef SERIAL_NO_OVERLAPPED
  1138.  
  1139.     // Check if an overlapped structure has been specified
  1140.     if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
  1141.     {
  1142.         // Set the internal error code
  1143.         m_lLastError = ERROR_INVALID_FUNCTION;
  1144.  
  1145.         // Issue an error and quit
  1146.         _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped I/O is disabled, specified parameters are illegal.\n");
  1147.         return m_lLastError;
  1148.     }
  1149.  
  1150.     // Wait for the event to happen
  1151.     OVERLAPPED ovInternal;
  1152.     if (lpOverlapped == 0)
  1153.     {
  1154.         // Setup our own overlapped structure
  1155.         memset(&ovInternal,0,sizeof(ovInternal));
  1156.         ovInternal.hEvent = m_hevtOverlapped;
  1157.  
  1158.         // Use our internal overlapped structure
  1159.         lpOverlapped = &ovInternal;
  1160.     }
  1161.  
  1162.     // Make sure the overlapped structure isn't busy
  1163.     _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
  1164.    
  1165.     // Read the data
  1166.     if (!::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped))
  1167.     {
  1168.         // Set the internal error code
  1169.         long lLastError = ::GetLastError();
  1170.  
  1171.         // Overlapped operation in progress is not an actual error
  1172.         if (lLastError != ERROR_IO_PENDING)
  1173.         {
  1174.             // Save the error
  1175.             m_lLastError = lLastError;
  1176.  
  1177.             // Issue an error and quit
  1178.             _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
  1179.             return m_lLastError;
  1180.         }
  1181.  
  1182.         // We need to block if the client didn't specify an overlapped structure
  1183.         if (lpOverlapped == &ovInternal)
  1184.         {
  1185.             // Wait for the overlapped operation to complete
  1186.             switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
  1187.             {
  1188.             case WAIT_OBJECT_0:
  1189.                 // The overlapped operation has completed
  1190.                 if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE))
  1191.                 {
  1192.                     // Set the internal error code
  1193.                     m_lLastError = ::GetLastError();
  1194.  
  1195.                     _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped completed without result\n");
  1196.                     return m_lLastError;
  1197.                 }
  1198.                 break;
  1199.  
  1200.             case WAIT_TIMEOUT:
  1201.                 // Cancel the I/O operation
  1202.                 CancelCommIo();
  1203.  
  1204.                 // The operation timed out. Set the internal error code and quit
  1205.                 m_lLastError = ERROR_TIMEOUT;
  1206.                 return m_lLastError;
  1207.  
  1208.             default:
  1209.                 // Set the internal error code
  1210.                 m_lLastError = ::GetLastError();
  1211.  
  1212.                 // Issue an error and quit
  1213.                 _RPTF0(_CRT_WARN,"CSerial::Read - Unable to wait until data has been read\n");
  1214.                 return m_lLastError;
  1215.             }
  1216.         }
  1217.     }
  1218.     else
  1219.     {
  1220.         // The operation completed immediatly. Just to be sure
  1221.         // we'll set the overlapped structure's event handle.
  1222.         if (lpOverlapped)
  1223.             ::SetEvent(lpOverlapped->hEvent);
  1224.     }
  1225.  
  1226. #else
  1227.    
  1228.     // Read the data
  1229.     if (!::ReadFile(m_hFile,pData,iLen,pdwRead,0))
  1230.     {
  1231.         // Set the internal error code
  1232.         m_lLastError = ::GetLastError();
  1233.  
  1234.         // Issue an error and quit
  1235.         _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
  1236.         return m_lLastError;
  1237.     }
  1238.  
  1239. #endif
  1240.  
  1241.     // Return successfully
  1242.     return m_lLastError;
  1243. }
  1244.  
  1245. LONG CSerial::Purge()
  1246. {
  1247.     // Reset error state
  1248.     m_lLastError = ERROR_SUCCESS;
  1249.  
  1250.     // Check if the device is open
  1251.     if (m_hFile == 0)
  1252.     {
  1253.         // Set the internal error code
  1254.         m_lLastError = ERROR_INVALID_HANDLE;
  1255.  
  1256.         // Issue an error and quit
  1257.         _RPTF0(_CRT_WARN,"CSerial::Purge - Device is not opened\n");
  1258.         return m_lLastError;
  1259.     }
  1260.  
  1261.     if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR))
  1262.     {
  1263.         // Set the internal error code
  1264.         m_lLastError = ::GetLastError();
  1265.         _RPTF0(_CRT_WARN,"CSerial::Purge - Overlapped completed without result\n");
  1266.     }
  1267.    
  1268.     // Return successfully
  1269.     return m_lLastError;
  1270. }
  1271.  
  1272. LONG CSerial::Break (void)
  1273. {
  1274.     // Reset error state
  1275.     m_lLastError = ERROR_SUCCESS;
  1276.  
  1277.     // Check if the device is open
  1278.     if (m_hFile == 0)
  1279.     {
  1280.         // Set the internal error code
  1281.         m_lLastError = ERROR_INVALID_HANDLE;
  1282.  
  1283.         // Issue an error and quit
  1284.         _RPTF0(_CRT_WARN,"CSerial::Break - Device is not opened\n");
  1285.         return m_lLastError;
  1286.     }
  1287.  
  1288.     // Set the RS-232 port in break mode for a little while
  1289.     ::SetCommBreak(m_hFile);
  1290.     ::Sleep(100);
  1291.     ::ClearCommBreak(m_hFile);
  1292.  
  1293.     // Return successfully
  1294.     return m_lLastError;
  1295. }
  1296.  
  1297. CSerial::EEvent CSerial::GetEventType (void)
  1298. {
  1299. #ifdef _DEBUG
  1300.     // Check if the event is within the mask
  1301.     if ((m_eEvent & m_dwEventMask) == 0)
  1302.         _RPTF2(_CRT_WARN,"CSerial::GetEventType - Event %08Xh not within mask %08Xh.\n", m_eEvent, m_dwEventMask);
  1303. #endif
  1304.  
  1305.     // Obtain the event (mask unwanted events out)
  1306.     EEvent eEvent = EEvent(m_eEvent & m_dwEventMask);
  1307.  
  1308.     // Reset internal event type
  1309.     m_eEvent = EEventNone;
  1310.  
  1311.     // Return the current cause
  1312.     return eEvent;
  1313. }
  1314.  
  1315. CSerial::EError CSerial::GetError (void)
  1316. {
  1317.     // Reset error state
  1318.     m_lLastError = ERROR_SUCCESS;
  1319.  
  1320.     // Check if the device is open
  1321.     if (m_hFile == 0)
  1322.     {
  1323.         // Set the internal error code
  1324.         m_lLastError = ERROR_INVALID_HANDLE;
  1325.  
  1326.         // Issue an error and quit
  1327.         _RPTF0(_CRT_WARN,"CSerial::GetError - Device is not opened\n");
  1328.         return EErrorUnknown;
  1329.     }
  1330.  
  1331.     // Obtain COM status
  1332.     DWORD dwErrors = 0;
  1333.     if (!::ClearCommError(m_hFile,&dwErrors,0))
  1334.     {
  1335.         // Set the internal error code
  1336.         m_lLastError = ::GetLastError();
  1337.  
  1338.         // Issue an error and quit
  1339.         _RPTF0(_CRT_WARN,"CSerial::GetError - Unable to obtain COM status\n");
  1340.         return EErrorUnknown;
  1341.     }
  1342.  
  1343.     // Return the error
  1344.     return EError(dwErrors);
  1345. }
  1346.  
  1347. bool CSerial::GetCTS (void)
  1348. {
  1349.     // Reset error state
  1350.     m_lLastError = ERROR_SUCCESS;
  1351.  
  1352.     // Obtain the modem status
  1353.     DWORD dwModemStat = 0;
  1354.     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
  1355.     {
  1356.         // Obtain the error code
  1357.         m_lLastError = ::GetLastError();
  1358.  
  1359.         // Display a warning
  1360.         _RPTF0(_CRT_WARN,"CSerial::GetCTS - Unable to obtain the modem status\n");
  1361.         return false;
  1362.     }
  1363.  
  1364.     // Determine if CTS is on
  1365.     return (dwModemStat & MS_CTS_ON) != 0;
  1366. }
  1367.  
  1368. bool CSerial::GetDSR (void)
  1369. {
  1370.     // Reset error state
  1371.     m_lLastError = ERROR_SUCCESS;
  1372.  
  1373.     // Obtain the modem status
  1374.     DWORD dwModemStat = 0;
  1375.     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
  1376.     {
  1377.         // Obtain the error code
  1378.         m_lLastError = ::GetLastError();
  1379.  
  1380.         // Display a warning
  1381.         _RPTF0(_CRT_WARN,"CSerial::GetDSR - Unable to obtain the modem status\n");
  1382.         return false;
  1383.     }
  1384.  
  1385.     // Determine if DSR is on
  1386.     return (dwModemStat & MS_DSR_ON) != 0;
  1387. }
  1388.  
  1389. bool CSerial::GetRing (void)
  1390. {
  1391.     // Reset error state
  1392.     m_lLastError = ERROR_SUCCESS;
  1393.  
  1394.     // Obtain the modem status
  1395.     DWORD dwModemStat = 0;
  1396.     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
  1397.     {
  1398.         // Obtain the error code
  1399.         m_lLastError = ::GetLastError();
  1400.  
  1401.         // Display a warning
  1402.         _RPTF0(_CRT_WARN,"CSerial::GetRing - Unable to obtain the modem status");
  1403.         return false;
  1404.     }
  1405.  
  1406.     // Determine if Ring is on
  1407.     return (dwModemStat & MS_RING_ON) != 0;
  1408. }
  1409.  
  1410. bool CSerial::GetRLSD (void)
  1411. {
  1412.     // Reset error state
  1413.     m_lLastError = ERROR_SUCCESS;
  1414.  
  1415.     // Obtain the modem status
  1416.     DWORD dwModemStat = 0;
  1417.     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
  1418.     {
  1419.         // Obtain the error code
  1420.         m_lLastError = ::GetLastError();
  1421.  
  1422.         // Display a warning
  1423.         _RPTF0(_CRT_WARN,"CSerial::GetRLSD - Unable to obtain the modem status");
  1424.         return false;
  1425.     }
  1426.  
  1427.     // Determine if RLSD is on
  1428.     return (dwModemStat & MS_RLSD_ON) != 0;
  1429. }
  1430.