?? serial.cpp
字號(hào):
// Serial.cpp - Implementation of the CSerial class
//
// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//////////////////////////////////////////////////////////////////////
// Include the standard header files
#define STRICT
#include <crtdbg.h>
#include <tchar.h>
#include <windows.h>
#include <stdafx.h>
//////////////////////////////////////////////////////////////////////
// Include module headerfile
#include "Serial.h"
//////////////////////////////////////////////////////////////////////
// Disable warning C4127: conditional expression is constant, which
// is generated when using the _RPTF and _ASSERTE macros.
#pragma warning(disable: 4127)
//////////////////////////////////////////////////////////////////////
// Enable debug memory manager
#ifdef _DEBUG
#ifdef THIS_FILE
#undef THIS_FILE
#endif
static const char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Helper methods
inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const
{
#ifdef SERIAL_NO_OVERLAPPED
// Check if an overlapped structure has been specified
if (lpOverlapped || (dwTimeout != INFINITE))
{
// Quit application
::MessageBox(0,_T("Overlapped I/O and time-outs are not supported, when overlapped I/O is disabled."),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
::DebugBreak();
::ExitProcess(0xFFFFFFF);
}
#endif
#ifdef SERIAL_NO_CANCELIO
// Check if 0 or INFINITE time-out has been specified, because
// the communication I/O cannot be cancelled.
if ((dwTimeout != 0) && (dwTimeout != INFINITE))
{
// Quit application
::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
::DebugBreak();
::ExitProcess(0xFFFFFFF);
}
#endif // SERIAL_NO_CANCELIO
// Avoid warnings
(void) dwTimeout;
(void) lpOverlapped;
}
inline BOOL CSerial::CancelCommIo (void)
{
#ifdef SERIAL_NO_CANCELIO
// CancelIo shouldn't have been called at this point
::DebugBreak();
return FALSE;
#else
// Cancel the I/O request
return ::CancelIo(m_hFile);
#endif // SERIAL_NO_CANCELIO
}
//////////////////////////////////////////////////////////////////////
// Code
CSerial::CSerial ()
: m_lLastError(ERROR_SUCCESS)
, m_hFile(0)
, m_eEvent(EEventNone)
, m_dwEventMask(0)
#ifndef SERIAL_NO_OVERLAPPED
, m_hevtOverlapped(0)
#endif
{
}
CSerial::~CSerial ()
{
// If the device is already closed,
// then we don't need to do anything.
if (m_hFile)
{
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n");
// Close implicitly
Close();
}
}
CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice)
{
// Try to open the device
HANDLE hFile = ::CreateFile(lpszDevice,
GENERIC_READ|GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);
// Check if we could open the device
if (hFile == INVALID_HANDLE_VALUE)
{
// Display error
switch (::GetLastError())
{
case ERROR_FILE_NOT_FOUND:
// The specified COM-port does not exist
return EPortNotAvailable;
case ERROR_ACCESS_DENIED:
// The specified COM-port is in use
return EPortInUse;
default:
// Something else is wrong
return EPortUnknownError;
}
}
// Close handle
::CloseHandle(hFile);
// Port is available
return EPortAvailable;
}
LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the port isn't already opened
if (m_hFile)
{
m_lLastError = ERROR_ALREADY_INITIALIZED;
_RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n");
return m_lLastError;
}
// Open the device
m_hFile = ::CreateFile(lpszDevice,
GENERIC_READ|GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
fOverlapped?FILE_FLAG_OVERLAPPED:0,
0);
if (m_hFile == INVALID_HANDLE_VALUE)
{
// Reset file handle
m_hFile = 0;
// Display error
m_lLastError = ::GetLastError();
_RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
return m_lLastError;
}
#ifndef SERIAL_NO_OVERLAPPED
// We cannot have an event handle yet
_ASSERTE(m_hevtOverlapped == 0);
// Create the event handle for internal overlapped operations (manual reset)
if (fOverlapped)
{
m_hevtOverlapped = ::CreateEvent(0,true,false,0);
if (m_hevtOverlapped == 0)
{
// Obtain the error information
m_lLastError = ::GetLastError();
_RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");
// Close the port
::CloseHandle(m_hFile);
m_hFile = 0;
// Return the error
return m_lLastError;
}
}
#else
// Overlapped flag shouldn't be specified
_ASSERTE(!fOverlapped);
#endif
// Setup the COM-port
if (dwInQueue || dwOutQueue)
{
// Make sure the queue-sizes are reasonable sized. Win9X systems crash
// if the input queue-size is zero. Both queues need to be at least
// 16 bytes large.
_ASSERTE(dwInQueue >= 16);
_ASSERTE(dwOutQueue >= 16);
if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
{
// Display a warning
long lLastError = ::GetLastError();
_RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");
// Close the port
Close();
// Save last error from SetupComm
m_lLastError = lLastError;
return m_lLastError;
}
}
// Setup the default communication mask
SetMask();
// Non-blocking reads is default
SetupReadTimeouts(EReadTimeoutNonblocking);
// Setup the device for default settings
COMMCONFIG commConfig = {0};
DWORD dwSize = sizeof(commConfig);
commConfig.dwSize = dwSize;
if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize))
{
// Set the default communication configuration
if (!::SetCommConfig(m_hFile,&commConfig,dwSize))
{
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n");
}
}
else
{
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n");
}
// Return successful
return m_lLastError;
}
LONG CSerial::Close (void)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// If the device is already closed,
// then we don't need to do anything.
if (m_hFile == 0)
{
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n");
return m_lLastError;
}
#ifndef SERIAL_NO_OVERLAPPED
// Free event handle
if (m_hevtOverlapped)
{
::CloseHandle(m_hevtOverlapped);
m_hevtOverlapped = 0;
}
#endif
// Close COM port
::CloseHandle(m_hFile);
m_hFile = 0;
// Return successful
return m_lLastError;
}
LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n");
return m_lLastError;
}
// Obtain the DCB structure for the device
CDCB dcb;
if (!::GetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = :: GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
return m_lLastError;
}
// Set the new data
dcb.BaudRate = DWORD(eBaudrate);
dcb.ByteSize = BYTE(eDataBits);
dcb.Parity = BYTE(eParity);
dcb.StopBits = BYTE(eStopBits);
// Determine if parity is used
dcb.fParity = (eParity != EParNone);
// Set the new DCB structure
if (!::SetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n");
return m_lLastError;
}
// Return successful
return m_lLastError;
}
LONG CSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n");
return m_lLastError;
}
// Obtain the DCB structure for the device
CDCB dcb;
if (!::GetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n");
return m_lLastError;
}
// Set the new event character
dcb.EvtChar = char(bEventChar);
// Adjust the event mask, to make sure the event will be received
if (fAdjustMask)
{
// Enable 'receive event character' event. Note that this
// will generate an EEventNone if there is an asynchronous
// WaitCommEvent pending.
SetMask(GetEventMask() | EEventRcvEv);
}
// Set the new DCB structure
if (!::SetCommState(m_hFile,&dcb))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n");
return m_lLastError;
}
// Return successful
return m_lLastError;
}
LONG CSerial::SetMask (DWORD dwEventMask)
{
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n");
return m_lLastError;
}
// Set the new mask. Note that this will generate an EEventNone
// if there is an asynchronous WaitCommEvent pending.
if (!::SetCommMask(m_hFile,dwEventMask))
{
// Obtain the error code
m_lLastError = ::GetLastError();
// Display a warning
_RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n");
return m_lLastError;
}
// Save event mask and return successful
m_dwEventMask = dwEventMask;
return m_lLastError;
}
LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
{
// Check if time-outs are supported
CheckRequirements(lpOverlapped,dwTimeout);
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n");
return m_lLastError;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -