MOOS 0.2375
|
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