MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Core/MOOSGenLib/NTSerial.cpp
Go to the documentation of this file.
00001 
00002 //
00003 //   MOOS - Mission Oriented Operating Suite 
00004 //  
00005 //   A suit of Applications and Libraries for Mobile Robotics Research 
00006 //   Copyright (C) 2001-2005 Massachusetts Institute of Technology and 
00007 //   Oxford University. 
00008 //    
00009 //   This software was written by Paul Newman at MIT 2001-2002 and Oxford 
00010 //   University 2003-2005. email: pnewman@robots.ox.ac.uk. 
00011 //      
00012 //   This file is part of a  MOOS Core Component. 
00013 //        
00014 //   This program is free software; you can redistribute it and/or 
00015 //   modify it under the terms of the GNU General Public License as 
00016 //   published by the Free Software Foundation; either version 2 of the 
00017 //   License, or (at your option) any later version. 
00018 //          
00019 //   This program is distributed in the hope that it will be useful, 
00020 //   but WITHOUT ANY WARRANTY; without even the implied warranty of 
00021 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
00022 //   General Public License for more details. 
00023 //            
00024 //   You should have received a copy of the GNU General Public License 
00025 //   along with this program; if not, write to the Free Software 
00026 //   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
00027 //   02111-1307, USA. 
00028 //
00030 #ifdef _WIN32
00031     #pragma warning(disable : 4786)
00032 #endif
00033 
00034 
00035 //    Serial.cpp - Implementation of the CNTSerial class
00036 //
00037 //    Copyright (C) 1999-2001 Ramon de Klein (R.de.Klein@iaf.nl)
00038 //
00039 // This program is free software; you can redistribute it and/ormodify
00040 // it under the terms of the GNU General Public License as published by
00041 // the Free Software Foundation; either version 2 of the License, or
00042 // (at your option) any later version.
00043 //
00044 // This program is distributed in the hope that it will be useful,
00045 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00046 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00047 // GNU General Public License for more details.
00048 //
00049 // You should have received a copy of the GNU General Public License
00050 // along with this program; if not, write to the Free Software
00051 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00052 
00053 
00055 // Include the precompiled header
00056 
00057 #define STRICT
00058 #include <crtdbg.h>
00059 #include <tchar.h>
00060 #include <windows.h>
00061 
00062 
00064 // Include module headerfile
00065 
00066 #include "NTSerial.h"
00067 
00068 
00070 // Disable warning C4127: conditional expression is constant, which
00071 // is generated when using the _RPTF and _ASSERTE macros.
00072 
00073 #pragma warning(disable: 4127)
00074 
00075 
00077 // Enable debug memory manager
00078 
00079 #ifdef _DEBUG
00080 static const char THIS_FILE[] = __FILE__;
00081 #define new DEBUG_NEW
00082 #endif
00083 
00084 
00086 // Code
00087 
00088 CNTSerial::CNTSerial ()
00089 {
00090     // Reset data
00091     m_lLastError     = ERROR_SUCCESS;
00092     m_hFile          = 0;
00093     m_eEvent         = EEventNone;
00094     m_hevtOverlapped = 0;
00095 }
00096 
00097 CNTSerial::~CNTSerial ()
00098 {
00099     // If the device is already closed,
00100     // then we don't need to do anything.
00101     if (m_hFile)
00102     {
00103         // Display a warning
00104         _RPTF0(_CRT_WARN,"CNTSerial::~CNTSerial - Serial port not closed\n");
00105 
00106         // Close implicitly
00107         ClosePort();
00108     }
00109 }
00110 
00111 CNTSerial::EPort CNTSerial::CheckPort (LPCTSTR lpszDevice)
00112 {
00113     // Try to open the device
00114     HANDLE hFile = ::CreateFile(lpszDevice, 
00115                            GENERIC_READ|GENERIC_WRITE, 
00116                            0, 
00117                            0, 
00118                            OPEN_EXISTING, 
00119                            FILE_FLAG_OVERLAPPED, 
00120                            0);
00121 
00122     // Check if we could open the device
00123     if (hFile == INVALID_HANDLE_VALUE)
00124     {
00125         // Display error
00126         switch (::GetLastError())
00127         {
00128         case ERROR_FILE_NOT_FOUND:
00129             // The specified COM-port does not exist
00130             return EPortNotAvailable;
00131 
00132         case ERROR_ACCESS_DENIED:
00133             // The specified COM-port is in use
00134             return EPortInUse;
00135 
00136         default:
00137             // Something else is wrong
00138             return EPortUnknownError;
00139         }
00140     }
00141 
00142     // Close handle
00143     ::CloseHandle(hFile);
00144 
00145     // Port is available
00146     return EPortAvailable;
00147 }
00148 
00149 LONG CNTSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue)
00150 {
00151     // Reset error state
00152     m_lLastError = ERROR_SUCCESS;
00153 
00154     // Check if the port isn't already opened
00155     if (m_hFile)
00156     {
00157         m_lLastError = ERROR_ALREADY_INITIALIZED;
00158         _RPTF0(_CRT_WARN,"CNTSerial::Open - Port already opened\n");
00159         return m_lLastError;
00160     }
00161 
00162     // Open the device
00163     m_hFile = ::CreateFile(lpszDevice,
00164                            GENERIC_READ|GENERIC_WRITE,
00165                            0,
00166                            0,
00167                            OPEN_EXISTING,
00168                            FILE_FLAG_OVERLAPPED,
00169                            0);
00170     if (m_hFile == INVALID_HANDLE_VALUE)
00171     {
00172         // Reset file handle
00173         m_hFile = 0;
00174 
00175         // Display error
00176         m_lLastError = ::GetLastError();
00177         _RPTF0(_CRT_WARN, "CNTSerial::Open - Unable to open port\n");
00178         return m_lLastError;
00179     }
00180 
00181     // We cannot have an event handle yet
00182     _ASSERTE(m_hevtOverlapped == 0);
00183 
00184     // Create the event handle for internal overlapped operations (manual reset)
00185     m_hevtOverlapped = ::CreateEvent(0,true,false,0);
00186     if (m_hevtOverlapped == 0)
00187     {
00188         // Obtain the error information
00189         m_lLastError = ::GetLastError();
00190         _RPTF0(_CRT_WARN,"CNTSerial::Open - Unable to create event\n");
00191 
00192         // Close the port
00193         ::CloseHandle(m_hFile);
00194         m_hFile = 0;
00195 
00196         // Return the error
00197         return m_lLastError;
00198     }
00199 
00200     // Setup the COM-port
00201     if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
00202     {
00203         // Display a warning
00204         long lLastError = ::GetLastError();
00205         _RPTF0(_CRT_WARN,"CNTSerial::Open - Unable to setup the COM-port\n");
00206 
00207         // Close the port
00208         ClosePort();
00209 
00210         // Save last error from SetupComm
00211         m_lLastError = lLastError;
00212         return m_lLastError;
00213     }
00214 
00215     // Setup the default communication mask
00216     SetMask();
00217 
00218     // Setup the device for default settings
00219     Setup();
00220 
00221     // Non-blocking reads is default
00222     SetupReadTimeouts(EReadTimeoutNonblocking);
00223 
00224     // Default is no handshaking
00225     SetupHandshaking(EHandshakeOff);
00226 
00227     // Return successful
00228     return m_lLastError;
00229 }
00230 
00231 LONG CNTSerial::ClosePort (void)
00232 {
00233     // Reset error state
00234     m_lLastError = ERROR_SUCCESS;
00235 
00236     // If the device is already closed,
00237     // then we don't need to do anything.
00238     if (m_hFile == 0)
00239     {
00240         // Display a warning
00241         _RPTF0(_CRT_WARN,"CNTSerial::Close - Method called when device is not open\n");
00242         return m_lLastError;
00243     }
00244 
00245     // Free event handle
00246     ::CloseHandle(m_hevtOverlapped);
00247     m_hevtOverlapped = 0;
00248 
00249     // Close COM port
00250     ::CloseHandle(m_hFile);
00251     m_hFile = 0;
00252 
00253     // Return successful
00254     return m_lLastError;
00255 }
00256 
00257 LONG CNTSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
00258 {
00259     // Reset error state
00260     m_lLastError = ERROR_SUCCESS;
00261 
00262     // Check if the device is open
00263     if (m_hFile == 0)
00264     {
00265         // Set the internal error code
00266         m_lLastError = ERROR_INVALID_HANDLE;
00267 
00268         // Issue an error and quit
00269         _RPTF0(_CRT_WARN,"CNTSerial::Setup - Device is not opened\n");
00270         return m_lLastError;
00271     }
00272 
00273     // Obtain the DCB structure for the device
00274     CDCB dcb;
00275     if (!::GetCommState(m_hFile,&dcb))
00276     {
00277         // Obtain the error code
00278         m_lLastError = ::GetLastError();
00279 
00280         // Display a warning
00281         _RPTF0(_CRT_WARN,"CNTSerial::Setup - Unable to obtain DCB information\n");
00282         return m_lLastError;
00283     }
00284 
00285     // Set the new data
00286     dcb.BaudRate = DWORD(eBaudrate);
00287     dcb.ByteSize = BYTE(eDataBits);
00288     dcb.Parity   = BYTE(eParity);
00289     dcb.StopBits = BYTE(eStopBits);
00290 
00291     // Determine if parity is used
00292     dcb.fParity  = (eParity != EParNone);
00293 
00294     // Set the new DCB structure
00295     if (!::SetCommState(m_hFile,&dcb))
00296     {
00297         // Obtain the error code
00298         m_lLastError = ::GetLastError();
00299 
00300         // Display a warning
00301         _RPTF0(_CRT_WARN,"CNTSerial::Setup - Unable to set DCB information\n");
00302         return m_lLastError;
00303     }
00304 
00305     // Return successful
00306     return m_lLastError;
00307 }
00308 
00309 LONG CNTSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask)
00310 {
00311     // Reset error state
00312     m_lLastError = ERROR_SUCCESS;
00313 
00314     // Check if the device is open
00315     if (m_hFile == 0)
00316     {
00317         // Set the internal error code
00318         m_lLastError = ERROR_INVALID_HANDLE;
00319 
00320         // Issue an error and quit
00321         _RPTF0(_CRT_WARN,"CNTSerial::SetEventChar - Device is not opened\n");
00322         return m_lLastError;
00323     }
00324 
00325     // Obtain the DCB structure for the device
00326     CDCB dcb;
00327     if (!::GetCommState(m_hFile,&dcb))
00328     {
00329         // Obtain the error code
00330         m_lLastError = ::GetLastError();
00331 
00332         // Display a warning
00333         _RPTF0(_CRT_WARN,"CNTSerial::SetEventChar - Unable to obtain DCB information\n");
00334         return m_lLastError;
00335     }
00336 
00337     // Set the new event character
00338     dcb.EvtChar = char(bEventChar);
00339 
00340     // Adjust the event mask, to make sure the event will be received
00341     if (fAdjustMask)
00342     {
00343         // Enable 'receive event character' event.  Note that this
00344         // will generate an EEventNone if there is an asynchronous
00345         // WaitCommEvent pending.
00346         SetMask(GetEventMask() | EEventRcvEv);
00347     }
00348 
00349     // Set the new DCB structure
00350     if (!::SetCommState(m_hFile,&dcb))
00351     {
00352         // Obtain the error code
00353         m_lLastError = ::GetLastError();
00354 
00355         // Display a warning
00356         _RPTF0(_CRT_WARN,"CNTSerial::SetEventChar - Unable to set DCB information\n");
00357         return m_lLastError;
00358     }
00359 
00360     // Return successful
00361     return m_lLastError;
00362 }
00363 
00364 LONG CNTSerial::SetMask (DWORD dwMask)
00365 {
00366     // Reset error state
00367     m_lLastError = ERROR_SUCCESS;
00368 
00369     // Check if the device is open
00370     if (m_hFile == 0)
00371     {
00372         // Set the internal error code
00373         m_lLastError = ERROR_INVALID_HANDLE;
00374 
00375         // Issue an error and quit
00376         _RPTF0(_CRT_WARN,"CNTSerial::SetMask - Device is not opened\n");
00377         return m_lLastError;
00378     }
00379 
00380     // Set the new mask. Note that this will generate an EEventNone
00381     // if there is an asynchronous WaitCommEvent pending.
00382     if (!::SetCommMask(m_hFile,dwMask))
00383     {
00384         // Obtain the error code
00385         m_lLastError = ::GetLastError();
00386 
00387         // Display a warning
00388         _RPTF0(_CRT_WARN,"CNTSerial::SetMask - Unable to set event mask\n");
00389         return m_lLastError;
00390     }
00391 
00392     // Return successful
00393     return m_lLastError;
00394 }
00395 
00396 LONG CNTSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
00397 {
00398     // Reset error state
00399     m_lLastError = ERROR_SUCCESS;
00400 
00401     // Check if the device is open
00402     if (m_hFile == 0)
00403     {
00404         // Set the internal error code
00405         m_lLastError = ERROR_INVALID_HANDLE;
00406 
00407         // Issue an error and quit
00408         _RPTF0(_CRT_WARN,"CNTSerial::WaitEvent - Device is not opened\n");
00409         return m_lLastError;
00410     }
00411 
00412     // Wait for the event to happen
00413     OVERLAPPED ovInternal;
00414     if (lpOverlapped == 0)
00415     {
00416         // Setup our own overlapped structure
00417         memset(&ovInternal,0,sizeof(ovInternal));
00418         ovInternal.hEvent = m_hevtOverlapped;
00419 
00420         // Use our internal overlapped structure
00421         lpOverlapped = &ovInternal;
00422     }
00423 
00424     // Make sure the overlapped structure isn't busy
00425     _ASSERTE(HasOverlappedIoCompleted(lpOverlapped));
00426 
00427     // Wait for the COM event
00428     if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped))
00429     {
00430         // Set the internal error code
00431         long lLastError = ::GetLastError();
00432 
00433         // Overlapped operation in progress is not an actual error
00434         if (lLastError != ERROR_IO_PENDING)
00435         {
00436             // Save the error
00437             m_lLastError = lLastError;
00438 
00439             // Issue an error and quit
00440             _RPTF0(_CRT_WARN,"CNTSerial::WaitEvent - Unable to wait for COM event\n");
00441             return m_lLastError;
00442         }
00443 
00444         // We need to block if the client didn't specify an overlapped structure
00445         if (lpOverlapped == &ovInternal)
00446         {
00447             // Wait for the overlapped operation to complete
00448             switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
00449             {
00450             case WAIT_OBJECT_0:
00451                 // The overlapped operation has completed
00452                 break;
00453 
00454             case WAIT_TIMEOUT:
00455                 // Cancel the I/O operation
00456                 ::CancelIo(m_hFile);
00457 
00458                 // The operation timed out. Set the internal error code and quit
00459                 m_lLastError = ERROR_TIMEOUT;
00460                 return m_lLastError;
00461 
00462             default:
00463                 // Set the internal error code
00464                 m_lLastError = ::GetLastError();
00465 
00466                 // Issue an error and quit
00467                 _RPTF0(_CRT_WARN,"CNTSerial::WaitEvent - Unable to wait until COM event has arrived\n");
00468                 return m_lLastError;
00469             }
00470         }
00471     }
00472     else
00473     {
00474         // The operation completed immediatly. Just to be sure
00475         // we'll set the overlapped structure's event handle.
00476         ::SetEvent(lpOverlapped->hEvent);
00477     }
00478 
00479     // Return successfully
00480     return m_lLastError;
00481 }
00482 
00483 
00484 LONG CNTSerial::SetupHandshaking (EHandshake eHandshake)
00485 {
00486     // Reset error state
00487     m_lLastError = ERROR_SUCCESS;
00488 
00489     // Check if the device is open
00490     if (m_hFile == 0)
00491     {
00492         // Set the internal error code
00493         m_lLastError = ERROR_INVALID_HANDLE;
00494 
00495         // Issue an error and quit
00496         _RPTF0(_CRT_WARN,"CNTSerial::SetupHandshaking - Device is not opened\n");
00497         return m_lLastError;
00498     }
00499 
00500     // Obtain the DCB structure for the device
00501     CDCB dcb;
00502     if (!::GetCommState(m_hFile,&dcb))
00503     {
00504         // Obtain the error code
00505         m_lLastError = ::GetLastError();
00506 
00507         // Display a warning
00508         _RPTF0(_CRT_WARN,"CNTSerial::SetupHandshaking - Unable to obtain DCB information\n");
00509         return m_lLastError;
00510     }
00511 
00512     // Set the handshaking flags
00513     switch (eHandshake)
00514     {
00515     case EHandshakeOff:
00516         dcb.fOutxCtsFlow = false;                    // Disable CTS monitoring
00517         dcb.fOutxDsrFlow = false;                    // Disable DSR monitoring
00518         dcb.fDtrControl = DTR_CONTROL_DISABLE;        // Disable DTR monitoring
00519         dcb.fOutX = false;                            // Disable XON/XOFF for transmission
00520         dcb.fInX = false;                            // Disable XON/XOFF for receiving
00521         dcb.fRtsControl = RTS_CONTROL_DISABLE;        // Disable RTS (Ready To Send)
00522         break;
00523 
00524     case EHandshakeHardware:
00525         dcb.fOutxCtsFlow = true;                    // Enable CTS monitoring
00526         dcb.fOutxDsrFlow = true;                    // Enable DSR monitoring
00527         dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;    // Enable DTR handshaking
00528         dcb.fOutX = false;                            // Disable XON/XOFF for transmission
00529         dcb.fInX = false;                            // Disable XON/XOFF for receiving
00530         dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;    // Enable RTS handshaking
00531         break;
00532 
00533     case EHandshakeSoftware:
00534         dcb.fOutxCtsFlow = false;                    // Disable CTS (Clear To Send)
00535         dcb.fOutxDsrFlow = false;                    // Disable DSR (Data Set Ready)
00536         dcb.fDtrControl = DTR_CONTROL_DISABLE;        // Disable DTR (Data Terminal Ready)
00537         dcb.fOutX = true;                            // Enable XON/XOFF for transmission
00538         dcb.fInX = true;                            // Enable XON/XOFF for receiving
00539         dcb.fRtsControl = RTS_CONTROL_DISABLE;        // Disable RTS (Ready To Send)
00540         break;
00541 
00542     default:
00543         // This shouldn't be possible
00544         _ASSERTE(false);
00545         m_lLastError = E_INVALIDARG;
00546         return m_lLastError;
00547     }
00548 
00549     // Set the new DCB structure
00550     if (!::SetCommState(m_hFile,&dcb))
00551     {
00552         // Obtain the error code
00553         m_lLastError = ::GetLastError();
00554 
00555         // Display a warning
00556         _RPTF0(_CRT_WARN,"CNTSerial::SetupHandshaking - Unable to set DCB information\n");
00557         return m_lLastError;
00558     }
00559 
00560     // Return successful
00561     return m_lLastError;
00562 }
00563 
00564 LONG CNTSerial::SetupReadTimeouts (EReadTimeout eReadTimeout)
00565 {
00566     // Reset error state
00567     m_lLastError = ERROR_SUCCESS;
00568 
00569     // Check if the device is open
00570     if (m_hFile == 0)
00571     {
00572         // Set the internal error code
00573         m_lLastError = ERROR_INVALID_HANDLE;
00574 
00575         // Issue an error and quit
00576         _RPTF0(_CRT_WARN,"CNTSerial::SetupReadTimeouts - Device is not opened\n");
00577         return m_lLastError;
00578     }
00579 
00580     // Determine the time-outs
00581     COMMTIMEOUTS cto;
00582     if (!::GetCommTimeouts(m_hFile,&cto))
00583     {
00584         // Obtain the error code
00585         m_lLastError = ::GetLastError();
00586 
00587         // Display a warning
00588         _RPTF0(_CRT_WARN,"CNTSerial::SetupReadTimeouts - Unable to obtain timeout information\n");
00589         return m_lLastError;
00590     }
00591 
00592     // Set the new timeouts
00593     switch (eReadTimeout)
00594     {
00595     case EReadTimeoutBlocking:
00596         cto.ReadIntervalTimeout = 0;
00597         cto.ReadTotalTimeoutConstant = 0;
00598         cto.ReadTotalTimeoutMultiplier = 0;
00599         break;
00600     case EReadTimeoutNonblocking:
00601         cto.ReadIntervalTimeout = MAXDWORD;
00602         cto.ReadTotalTimeoutConstant = 0;
00603         cto.ReadTotalTimeoutMultiplier = 0;
00604         break;
00605     default:
00606         // This shouldn't be possible
00607         _ASSERTE(false);
00608         m_lLastError = E_INVALIDARG;
00609         return m_lLastError;
00610     }
00611 
00612     // Set the new DCB structure
00613     if (!::SetCommTimeouts(m_hFile,&cto))
00614     {
00615         // Obtain the error code
00616         m_lLastError = ::GetLastError();
00617 
00618         // Display a warning
00619         _RPTF0(_CRT_WARN,"CNTSerial::SetupReadTimeouts - Unable to set timeout information\n");
00620         return m_lLastError;
00621     }
00622 
00623     // Return successful
00624     return m_lLastError;
00625 }
00626 
00627 CNTSerial::EBaudrate CNTSerial::GetBaudrate (void)
00628 {
00629     // Reset error state
00630     m_lLastError = ERROR_SUCCESS;
00631 
00632     // Check if the device is open
00633     if (m_hFile == 0)
00634     {
00635         // Set the internal error code
00636         m_lLastError = ERROR_INVALID_HANDLE;
00637 
00638         // Issue an error and quit
00639         _RPTF0(_CRT_WARN,"CNTSerial::GetBaudrate - Device is not opened\n");
00640         return EBaudUnknown;
00641     }
00642 
00643     // Obtain the DCB structure for the device
00644     CDCB dcb;
00645     if (!::GetCommState(m_hFile,&dcb))
00646     {
00647         // Obtain the error code
00648         m_lLastError = ::GetLastError();
00649 
00650         // Display a warning
00651         _RPTF0(_CRT_WARN,"CNTSerial::GetBaudrate - Unable to obtain DCB information\n");
00652         return EBaudUnknown;
00653     }
00654 
00655     // Return the appropriate baudrate
00656     return EBaudrate(dcb.BaudRate);
00657 }
00658 
00659 CNTSerial::EDataBits CNTSerial::GetDataBits (void)
00660 {
00661     // Reset error state
00662     m_lLastError = ERROR_SUCCESS;
00663 
00664     // Check if the device is open
00665     if (m_hFile == 0)
00666     {
00667         // Set the internal error code
00668         m_lLastError = ERROR_INVALID_HANDLE;
00669 
00670         // Issue an error and quit
00671         _RPTF0(_CRT_WARN,"CNTSerial::GetDataBits - Device is not opened\n");
00672         return EDataUnknown;
00673     }
00674 
00675     // Obtain the DCB structure for the device
00676     CDCB dcb;
00677     if (!::GetCommState(m_hFile,&dcb))
00678     {
00679         // Obtain the error code
00680         m_lLastError = ::GetLastError();
00681 
00682         // Display a warning
00683         _RPTF0(_CRT_WARN,"CNTSerial::GetDataBits - Unable to obtain DCB information\n");
00684         return EDataUnknown;
00685     }
00686 
00687     // Return the appropriate bytesize
00688     return EDataBits(dcb.ByteSize);
00689 }
00690 
00691 CNTSerial::EParity CNTSerial::GetParity (void)
00692 {
00693     // Reset error state
00694     m_lLastError = ERROR_SUCCESS;
00695 
00696     // Check if the device is open
00697     if (m_hFile == 0)
00698     {
00699         // Set the internal error code
00700         m_lLastError = ERROR_INVALID_HANDLE;
00701 
00702         // Issue an error and quit
00703         _RPTF0(_CRT_WARN,"CNTSerial::GetParity - Device is not opened\n");
00704         return EParUnknown;
00705     }
00706 
00707     // Obtain the DCB structure for the device
00708     CDCB dcb;
00709     if (!::GetCommState(m_hFile,&dcb))
00710     {
00711         // Obtain the error code
00712         m_lLastError = ::GetLastError();
00713 
00714         // Display a warning
00715         _RPTF0(_CRT_WARN,"CNTSerial::GetParity - Unable to obtain DCB information\n");
00716         return EParUnknown;
00717     }
00718 
00719     // Check if parity is used
00720     if (!dcb.fParity)
00721     {
00722         // No parity
00723         return EParNone;
00724     }
00725 
00726     // Return the appropriate parity setting
00727     return EParity(dcb.Parity);
00728 }
00729 
00730 CNTSerial::EStopBits CNTSerial::GetStopBits (void)
00731 {
00732     // Reset error state
00733     m_lLastError = ERROR_SUCCESS;
00734 
00735     // Check if the device is open
00736     if (m_hFile == 0)
00737     {
00738         // Set the internal error code
00739         m_lLastError = ERROR_INVALID_HANDLE;
00740 
00741         // Issue an error and quit
00742         _RPTF0(_CRT_WARN,"CNTSerial::GetStopBits - Device is not opened\n");
00743         return EStopUnknown;
00744     }
00745 
00746     // Obtain the DCB structure for the device
00747     CDCB dcb;
00748     if (!::GetCommState(m_hFile,&dcb))
00749     {
00750         // Obtain the error code
00751         m_lLastError = ::GetLastError();
00752 
00753         // Display a warning
00754         _RPTF0(_CRT_WARN,"CNTSerial::GetStopBits - Unable to obtain DCB information\n");
00755         return EStopUnknown;
00756     }
00757 
00758     // Return the appropriate stopbits
00759     return EStopBits(dcb.StopBits);
00760 }
00761 
00762 DWORD CNTSerial::GetEventMask (void)
00763 {
00764     // Reset error state
00765     m_lLastError = ERROR_SUCCESS;
00766 
00767     // Check if the device is open
00768     if (m_hFile == 0)
00769     {
00770         // Set the internal error code
00771         m_lLastError = ERROR_INVALID_HANDLE;
00772 
00773         // Issue an error and quit
00774         _RPTF0(_CRT_WARN,"CNTSerial::GetEventMask - Device is not opened\n");
00775         return 0;
00776     }
00777 
00778     // Obtain the COM mask
00779     DWORD dwMask = 0;
00780     if (!::GetCommMask(m_hFile, &dwMask))
00781     {
00782         // Set the internal error code
00783         m_lLastError = ::GetLastError();
00784 
00785         // Issue an error and quit
00786         _RPTF0(_CRT_WARN,"CNTSerial::GetEventMask - Unable to get the event mask\n");
00787         return 0;
00788     }
00789 
00790     // Return the event mask
00791     return dwMask;
00792 }
00793 
00794 BYTE CNTSerial::GetEventChar (void)
00795 {
00796     // Reset error state
00797     m_lLastError = ERROR_SUCCESS;
00798 
00799     // Check if the device is open
00800     if (m_hFile == 0)
00801     {
00802         // Set the internal error code
00803         m_lLastError = ERROR_INVALID_HANDLE;
00804 
00805         // Issue an error and quit
00806         _RPTF0(_CRT_WARN,"CNTSerial::GetEventChar - Device is not opened\n");
00807         return 0;
00808     }
00809 
00810     // Obtain the DCB structure for the device
00811     CDCB dcb;
00812     if (!::GetCommState(m_hFile,&dcb))
00813     {
00814         // Obtain the error code
00815         m_lLastError = ::GetLastError();
00816 
00817         // Display a warning
00818         _RPTF0(_CRT_WARN,"CNTSerial::GetEventChar - Unable to obtain DCB information\n");
00819         return 0;
00820     }
00821 
00822     // Set the new event character
00823     return BYTE(dcb.EvtChar);
00824 }
00825 
00826 CNTSerial::EHandshake CNTSerial::GetHandshaking (void)
00827 {
00828     // Reset error state
00829     m_lLastError = ERROR_SUCCESS;
00830 
00831     // Check if the device is open
00832     if (m_hFile == 0)
00833     {
00834         // Set the internal error code
00835         m_lLastError = ERROR_INVALID_HANDLE;
00836 
00837         // Issue an error and quit
00838         _RPTF0(_CRT_WARN,"CNTSerial::GetHandshaking - Device is not opened\n");
00839         return EHandshakeUnknown;
00840     }
00841 
00842     // Obtain the DCB structure for the device
00843     CDCB dcb;
00844     if (!::GetCommState(m_hFile,&dcb))
00845     {
00846         // Obtain the error code
00847         m_lLastError = ::GetLastError();
00848 
00849         // Display a warning
00850         _RPTF0(_CRT_WARN,"CNTSerial::GetHandshaking - Unable to obtain DCB information\n");
00851         return EHandshakeUnknown;
00852     }
00853 
00854     // Check if hardware handshaking is being used
00855     if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE))
00856         return EHandshakeHardware;
00857 
00858     // Check if software handshaking is being used
00859     if (dcb.fOutX && dcb.fInX)
00860         return EHandshakeSoftware;
00861 
00862     // No handshaking is being used
00863     return EHandshakeOff;
00864 }
00865 
00866 LONG CNTSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
00867 {
00868     // Overlapped operation should specify the pdwWritten variable
00869     _ASSERTE(!lpOverlapped || pdwWritten);
00870 
00871     // Reset error state
00872     m_lLastError = ERROR_SUCCESS;
00873 
00874     // Use our own variable for read count
00875     DWORD dwWritten;
00876     if (pdwWritten == 0)
00877     {
00878         pdwWritten = &dwWritten;
00879     }
00880 
00881     // Reset the number of bytes written
00882     *pdwWritten = 0;
00883 
00884     // Check if the device is open
00885     if (m_hFile == 0)
00886     {
00887         // Set the internal error code
00888         m_lLastError = ERROR_INVALID_HANDLE;
00889 
00890         // Issue an error and quit
00891         _RPTF0(_CRT_WARN,"CNTSerial::Write - Device is not opened\n");
00892         return m_lLastError;
00893     }
00894 
00895     // Wait for the event to happen
00896     OVERLAPPED ovInternal;
00897     if (lpOverlapped == 0)
00898     {
00899         // Setup our own overlapped structure
00900         memset(&ovInternal,0,sizeof(ovInternal));
00901         ovInternal.hEvent = m_hevtOverlapped;
00902 
00903         // Use our internal overlapped structure
00904         lpOverlapped = &ovInternal;
00905     }
00906 
00907     // Make sure the overlapped structure isn't busy
00908     _ASSERTE(HasOverlappedIoCompleted(lpOverlapped));
00909 
00910     // Write the data
00911     if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped))
00912     {
00913         // Set the internal error code
00914         long lLastError = ::GetLastError();
00915 
00916         // Overlapped operation in progress is not an actual error
00917         if (lLastError != ERROR_IO_PENDING)
00918         {
00919             // Save the error
00920             m_lLastError = lLastError;
00921 
00922             // Issue an error and quit
00923             _RPTF0(_CRT_WARN,"CNTSerial::Write - Unable to write the data\n");
00924             return m_lLastError;
00925         }
00926 
00927         // We need to block if the client didn't specify an overlapped structure
00928         if (lpOverlapped == &ovInternal)
00929         {
00930             // Wait for the overlapped operation to complete
00931             switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
00932             {
00933             case WAIT_OBJECT_0:
00934                 // The overlapped operation has completed
00935                 if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE))
00936                 {
00937                     // Set the internal error code
00938                     m_lLastError = ::GetLastError();
00939 
00940                     _RPTF0(_CRT_WARN,"CNTSerial::Write - Overlapped completed without result\n");
00941                     return m_lLastError;
00942                 }
00943                 break;
00944 
00945             case WAIT_TIMEOUT:
00946                 // Cancel the I/O operation
00947                 ::CancelIo(m_hFile);
00948 
00949                 // The operation timed out. Set the internal error code and quit
00950                 m_lLastError = ERROR_TIMEOUT;
00951                 return m_lLastError;
00952 
00953             default:
00954                 // Set the internal error code
00955                 m_lLastError = ::GetLastError();
00956 
00957                 // Issue an error and quit
00958                 _RPTF0(_CRT_WARN,"CNTSerial::Write - Unable to wait until data has been sent\n");
00959                 return m_lLastError;
00960             }
00961         }
00962     }
00963     else
00964     {
00965         // The operation completed immediatly. Just to be sure
00966         // we'll set the overlapped structure's event handle.
00967         ::SetEvent(lpOverlapped->hEvent);
00968     }
00969 
00970     // Return successfully
00971     return m_lLastError;
00972 }
00973 
00974 LONG CNTSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
00975 {
00976     // Determine the length of the string
00977     return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout);
00978 }
00979 
00980 LONG CNTSerial::NTRead (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
00981 {
00982     // Overlapped operation should specify the pdwRead variable
00983     _ASSERTE(!lpOverlapped || pdwRead);
00984 
00985     // Reset error state
00986     m_lLastError = ERROR_SUCCESS;
00987 
00988     // Use our own variable for read count
00989     DWORD dwRead;
00990     if (pdwRead == 0)
00991     {
00992         pdwRead = &dwRead;
00993     }
00994 
00995     // Reset the number of bytes read
00996     *pdwRead = 0;
00997 
00998     // Check if the device is open
00999     if (m_hFile == 0)
01000     {
01001         // Set the internal error code
01002         m_lLastError = ERROR_INVALID_HANDLE;
01003 
01004         // Issue an error and quit
01005         _RPTF0(_CRT_WARN,"CNTSerial::Read - Device is not opened\n");
01006         return m_lLastError;
01007     }
01008 
01009     // Wait for the event to happen
01010     OVERLAPPED ovInternal;
01011     if (lpOverlapped == 0)
01012     {
01013         // Setup our own overlapped structure
01014         memset(&ovInternal,0,sizeof(ovInternal));
01015         ovInternal.hEvent = m_hevtOverlapped;
01016 
01017         // Use our internal overlapped structure
01018         lpOverlapped = &ovInternal;
01019     }
01020 
01021     // Make sure the overlapped structure isn't busy
01022     _ASSERTE(HasOverlappedIoCompleted(lpOverlapped));
01023 
01024 #ifdef _DEBUG
01025     // The debug version fills the entire data structure with
01026     // 0xDC bytes, to catch buffer errors as soon as possible.
01027     memset(pData,0xDC,iLen);
01028 #endif
01029     
01030     // Read the data
01031     if (!::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped))
01032     {
01033         // Set the internal error code
01034         long lLastError = ::GetLastError();
01035 
01036         // Overlapped operation in progress is not an actual error
01037         if (lLastError != ERROR_IO_PENDING)
01038         {
01039             // Save the error
01040             m_lLastError = lLastError;
01041 
01042             // Issue an error and quit
01043             _RPTF0(_CRT_WARN,"CNTSerial::Read - Unable to read the data\n");
01044             return m_lLastError;
01045         }
01046 
01047         // We need to block if the client didn't specify an overlapped structure
01048         if (lpOverlapped == &ovInternal)
01049         {
01050             // Wait for the overlapped operation to complete
01051             switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
01052             {
01053             case WAIT_OBJECT_0:
01054                 // The overlapped operation has completed
01055                 if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE))
01056                 {
01057                     // Set the internal error code
01058                     m_lLastError = ::GetLastError();
01059 
01060                     _RPTF0(_CRT_WARN,"CNTSerial::Read - Overlapped completed without result\n");
01061                     return m_lLastError;
01062                 }
01063                 break;
01064 
01065             case WAIT_TIMEOUT:
01066                 // Cancel the I/O operation
01067                 ::CancelIo(m_hFile);
01068 
01069                 // The operation timed out. Set the internal error code and quit
01070                 m_lLastError = ERROR_TIMEOUT;
01071                 return m_lLastError;
01072 
01073             default:
01074                 // Set the internal error code
01075                 m_lLastError = ::GetLastError();
01076 
01077                 // Issue an error and quit
01078                 _RPTF0(_CRT_WARN,"CNTSerial::Read - Unable to wait until data has been read\n");
01079                 return m_lLastError;
01080             }
01081         }
01082     }
01083     else
01084     {
01085         // The operation completed immediatly. Just to be sure
01086         // we'll set the overlapped structure's event handle.
01087         ::SetEvent(lpOverlapped->hEvent);
01088     }
01089 
01090     // Return successfully
01091     return m_lLastError;
01092 }
01093 
01094 int CNTSerial::Flush()
01095 {
01096     // Check if the device is open
01097     if (m_hFile == 0)
01098     {
01099         // Set the internal error code
01100         m_lLastError = ERROR_INVALID_HANDLE;
01101 
01102         // Issue an error and quit
01103         _RPTF0(_CRT_WARN,"CNTSerial::Read - Device is not opened\n");
01104         return m_lLastError;
01105     }
01106 
01107     if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR))
01108     {
01109         // Set the internal error code
01110         m_lLastError = ::GetLastError();
01111         _RPTF0(_CRT_WARN,"CNTSerial::Read - Overlapped completed without result\n");
01112     }
01113     
01114     // Return successfully
01115     return m_lLastError;
01116 }
01117 
01118 CNTSerial::EEvent CNTSerial::GetEventType (void)
01119 {
01120     // Obtain the event
01121     EEvent eEvent = m_eEvent;
01122 
01123     // Reset internal event type
01124     m_eEvent = EEventNone;
01125 
01126     // Return the current cause
01127     return eEvent;
01128 }
01129 
01130 CNTSerial::EError CNTSerial::GetError (void)
01131 {
01132     // Reset error state
01133     m_lLastError = ERROR_SUCCESS;
01134 
01135     // Check if the device is open
01136     if (m_hFile == 0)
01137     {
01138         // Set the internal error code
01139         m_lLastError = ERROR_INVALID_HANDLE;
01140 
01141         // Issue an error and quit
01142         _RPTF0(_CRT_WARN,"CNTSerial::GetError - Device is not opened\n");
01143         return EErrorUnknown;
01144     }
01145 
01146     // Obtain COM status
01147     DWORD dwErrors = 0;
01148     if (!::ClearCommError(m_hFile,&dwErrors,0))
01149     {
01150         // Set the internal error code
01151         m_lLastError = ::GetLastError();
01152 
01153         // Issue an error and quit
01154         _RPTF0(_CRT_WARN,"CNTSerial::GetError - Unable to obtain COM status\n");
01155         return EErrorUnknown;
01156     }
01157 
01158     // Return the error
01159     return EError(dwErrors);
01160 }
01161 
01162 bool CNTSerial::GetCTS (void)
01163 {
01164     // Reset error state
01165     m_lLastError = ERROR_SUCCESS;
01166 
01167     // Obtain the modem status
01168     DWORD dwModemStat = 0;
01169     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
01170     {
01171         // Obtain the error code
01172         m_lLastError = ::GetLastError();
01173 
01174         // Display a warning
01175         _RPTF0(_CRT_WARN,"CNTSerial::GetCTS - Unable to obtain the modem status\n");
01176         return false;
01177     }
01178 
01179     // Determine if CTS is on
01180     return (dwModemStat & MS_CTS_ON) != 0;
01181 }
01182 
01183 bool CNTSerial::GetDSR (void)
01184 {
01185     // Reset error state
01186     m_lLastError = ERROR_SUCCESS;
01187 
01188     // Obtain the modem status
01189     DWORD dwModemStat = 0;
01190     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
01191     {
01192         // Obtain the error code
01193         m_lLastError = ::GetLastError();
01194 
01195         // Display a warning
01196         _RPTF0(_CRT_WARN,"CNTSerial::GetDSR - Unable to obtain the modem status\n");
01197         return false;
01198     }
01199 
01200     // Determine if DSR is on
01201     return (dwModemStat & MS_DSR_ON) != 0;
01202 }
01203 
01204 bool CNTSerial::GetRing (void)
01205 {
01206     // Reset error state
01207     m_lLastError = ERROR_SUCCESS;
01208 
01209     // Obtain the modem status
01210     DWORD dwModemStat = 0;
01211     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
01212     {
01213         // Obtain the error code
01214         m_lLastError = ::GetLastError();
01215 
01216         // Display a warning
01217         _RPTF0(_CRT_WARN,"CNTSerial::GetRing - Unable to obtain the modem status");
01218         return false;
01219     }
01220 
01221     // Determine if Ring is on
01222     return (dwModemStat & MS_RING_ON) != 0;
01223 }
01224 
01225 bool CNTSerial::GetRLSD (void)
01226 {
01227     // Reset error state
01228     m_lLastError = ERROR_SUCCESS;
01229 
01230     // Obtain the modem status
01231     DWORD dwModemStat = 0;
01232     if (!::GetCommModemStatus(m_hFile,&dwModemStat))
01233     {
01234         // Obtain the error code
01235         m_lLastError = ::GetLastError();
01236 
01237         // Display a warning
01238         _RPTF0(_CRT_WARN,"CNTSerial::GetRLSD - Unable to obtain the modem status");
01239         return false;
01240     }
01241 
01242     // Determine if RLSD is on
01243     return (dwModemStat & MS_RLSD_ON) != 0;
01244 }
01245 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines