// Serial.h - Definition 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
|
|
|
#ifndef __SERIAL_H
|
#define __SERIAL_H
|
|
|
//////////////////////////////////////////////////////////////////////
|
// The SERIAL_DEFAULT_OVERLAPPED defines if the default open mode uses
|
// overlapped I/O. When overlapped I/O is available (normal Win32
|
// platforms) it uses overlapped I/O. Windows CE doesn't allow the use
|
// of overlapped I/O, so it is disabled there by default.
|
|
#ifndef SERIAL_DEFAULT_OVERLAPPED
|
#ifndef SERIAL_NO_OVERLAPPED
|
#define SERIAL_DEFAULT_OVERLAPPED true
|
#else
|
#define SERIAL_DEFAULT_OVERLAPPED false
|
#endif
|
#endif
|
|
|
//////////////////////////////////////////////////////////////////////
|
//
|
// CSerial - Win32 wrapper for serial communications
|
//
|
// Serial communication often causes a lot of problems. This class
|
// tries to supply an easy to use interface to deal with serial
|
// devices.
|
//
|
// The class is actually pretty ease to use. You only need to open
|
// the COM-port, where you need to specify the basic serial
|
// communication parameters. You can also choose to setup handshaking
|
// and read timeout behaviour.
|
//
|
// The following serial classes are available:
|
//
|
// CSerial - Serial communication support.
|
// CSerialEx - Serial communication with listener thread for events
|
// CSerialSync - Serial communication with synchronized event handler
|
// CSerialWnd - Asynchronous serial support, which uses the Win32
|
// message queue for event notification.
|
// CSerialMFC - Preferred class to use in MFC-based GUI windows.
|
//
|
//
|
// Pros:
|
// -----
|
// - Easy to use (hides a lot of nasty Win32 stuff)
|
// - Fully ANSI and Unicode aware
|
//
|
// Cons:
|
// -----
|
// - Little less flexibility then native Win32 API, however you can
|
// use this API at the same time for features which are missing
|
// from this class.
|
// - Incompatible with Windows 95 or Windows NT v3.51 (or earlier),
|
// because CancelIo isn't support on these platforms. Define the
|
// SERIAL_NO_CANCELIO macro for support of these platforms as
|
// well. When this macro is defined, then only time-out values of
|
// 0 or INFINITE are valid.
|
//
|
//
|
// Copyright (C) 1999-2003 Ramon de Klein
|
// (Ramon.de.Klein@ict.nl)
|
|
#define FC_DTRDSR 0x01
|
#define FC_RTSCTS 0x02
|
#define FC_XONXOFF 0x04
|
#define ASCII_BEL 0x07
|
#define ASCII_BS 0x08
|
#define ASCII_LF 0x0A
|
#define ASCII_CR 0x0D
|
#define ASCII_XON 0x11
|
#define ASCII_XOFF 0x13
|
|
class AFX_EXT_CLASS CSerial
|
{
|
// Class enumerations
|
public:
|
// Communication event
|
typedef enum
|
{
|
EEventUnknown = -1, // Unknown event
|
EEventNone = 0, // Event trigged without cause
|
EEventBreak = EV_BREAK, // A break was detected on input
|
EEventCTS = EV_CTS, // The CTS signal changed state
|
EEventDSR = EV_DSR, // The DSR signal changed state
|
EEventError = EV_ERR, // A line-status error occurred
|
EEventRing = EV_RING, // A ring indicator was detected
|
EEventRLSD = EV_RLSD, // The RLSD signal changed state
|
EEventRecv = EV_RXCHAR, // Data is received on input
|
EEventRcvEv = EV_RXFLAG, // Event character was received on input
|
EEventSend = EV_TXEMPTY, // Last character on output was sent
|
EEventPrinterError = EV_PERR, // Printer error occured
|
EEventRx80Full = EV_RX80FULL, // Receive buffer is 80 percent full
|
EEventProviderEvt1 = EV_EVENT1, // Provider specific event 1
|
EEventProviderEvt2 = EV_EVENT2, // Provider specific event 2
|
}
|
EEvent;
|
|
// Baudrate
|
typedef enum
|
{
|
EBaudUnknown = -1, // Unknown
|
EBaud110 = CBR_110, // 110 bits/sec
|
EBaud300 = CBR_300, // 300 bits/sec
|
EBaud600 = CBR_600, // 600 bits/sec
|
EBaud1200 = CBR_1200, // 1200 bits/sec
|
EBaud2400 = CBR_2400, // 2400 bits/sec
|
EBaud4800 = CBR_4800, // 4800 bits/sec
|
EBaud9600 = CBR_9600, // 9600 bits/sec
|
EBaud14400 = CBR_14400, // 14400 bits/sec
|
EBaud19200 = CBR_19200, // 19200 bits/sec (default)
|
EBaud38400 = CBR_38400, // 38400 bits/sec
|
EBaud56000 = CBR_56000, // 56000 bits/sec
|
EBaud57600 = CBR_57600, // 57600 bits/sec
|
EBaud115200 = CBR_115200, // 115200 bits/sec
|
EBaud128000 = CBR_128000, // 128000 bits/sec
|
EBaud256000 = CBR_256000, // 256000 bits/sec
|
}
|
EBaudrate;
|
|
// Data bits (5-8)
|
typedef enum
|
{
|
EDataUnknown = -1, // Unknown
|
EData5 = 5, // 5 bits per byte
|
EData6 = 6, // 6 bits per byte
|
EData7 = 7, // 7 bits per byte
|
EData8 = 8 // 8 bits per byte (default)
|
}
|
EDataBits;
|
|
// Parity scheme
|
typedef enum
|
{
|
EParUnknown = -1, // Unknown
|
EParNone = NOPARITY, // No parity (default)
|
EParOdd = ODDPARITY, // Odd parity
|
EParEven = EVENPARITY, // Even parity
|
EParMark = MARKPARITY, // Mark parity
|
EParSpace = SPACEPARITY // Space parity
|
}
|
EParity;
|
|
// Stop bits
|
typedef enum
|
{
|
EStopUnknown = -1, // Unknown
|
EStop1 = ONESTOPBIT, // 1 stopbit (default)
|
EStop1_5 = ONE5STOPBITS,// 1.5 stopbit
|
EStop2 = TWOSTOPBITS // 2 stopbits
|
}
|
EStopBits;
|
|
// Handshaking
|
typedef enum
|
{
|
EHandshakeUnknown = -1, // Unknown
|
EHandshakeOff = 0, // No handshaking
|
EHandshakeHardware = 1, // Hardware handshaking (RTS/CTS)
|
EHandshakeSoftware = 2 // Software handshaking (XON/XOFF)
|
}
|
EHandshake;
|
|
// Timeout settings
|
typedef enum
|
{
|
EReadTimeoutUnknown = -1, // Unknown
|
EReadTimeoutNonblocking = 0, // Always return immediately
|
EReadTimeoutBlocking = 1 // Block until everything is retrieved
|
}
|
EReadTimeout;
|
|
// Communication errors
|
typedef enum
|
{
|
EErrorUnknown = 0, // Unknown
|
EErrorBreak = CE_BREAK, // Break condition detected
|
EErrorFrame = CE_FRAME, // Framing error
|
EErrorIOE = CE_IOE, // I/O device error
|
EErrorMode = CE_MODE, // Unsupported mode
|
EErrorOverrun = CE_OVERRUN, // Character buffer overrun, next byte is lost
|
EErrorRxOver = CE_RXOVER, // Input buffer overflow, byte lost
|
EErrorParity = CE_RXPARITY,// Input parity error
|
EErrorTxFull = CE_TXFULL // Output buffer full
|
}
|
EError;
|
|
// Port availability
|
typedef enum
|
{
|
EPortUnknownError = -1, // Unknown error occurred
|
EPortAvailable = 0, // Port is available
|
EPortNotAvailable = 1, // Port is not present
|
EPortInUse = 2 // Port is in use
|
|
}
|
EPort;
|
|
// Construction
|
public:
|
CSerial();
|
virtual ~CSerial();
|
|
// Operations
|
public:
|
// Check if particular COM-port is available (static method).
|
static EPort CheckPort (LPCTSTR lpszDevice);
|
|
// Open the serial communications for a particular COM port. You
|
// need to use the full devicename (i.e. "COM1") to open the port.
|
// It's possible to specify the size of the input/output queues.
|
virtual LONG Open (LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0, bool fOverlapped = SERIAL_DEFAULT_OVERLAPPED);
|
|
// Close the serial port.
|
virtual LONG Close (void);
|
|
// Setup the communication settings such as baudrate, databits,
|
// parity and stopbits. The default settings are applied when the
|
// device has been opened. Call this function if these settings do
|
// not apply for your application. If you prefer to use integers
|
// instead of the enumerated types then just cast the integer to
|
// the required type. So the following two initializations are
|
// equivalent:
|
//
|
// Setup(EBaud9600,EData8,EParNone,EStop1)
|
//
|
// or
|
//
|
// Setup(EBaudrate(9600),EDataBits(8),EParity(NOPARITY),EStopBits(ONESTOPBIT))
|
//
|
// In the latter case, the types are not validated. So make sure
|
// that you specify the appropriate values.
|
virtual LONG Setup (EBaudrate eBaudrate = EBaud9600,
|
EDataBits eDataBits = EData8,
|
EParity eParity = EParNone,
|
EStopBits eStopBits = EStop1);
|
|
// Set/clear the event character. When this byte is being received
|
// on the serial port then the EEventRcvEv event is signalled,
|
// when the mask has been set appropriately. If the fAdjustMask flag
|
// has been set, then the event mask is automatically adjusted.
|
virtual LONG SetEventChar (BYTE bEventChar, bool fAdjustMask = true);
|
|
// Set the event mask, which indicates what events should be
|
// monitored. The WaitEvent method can only monitor events that
|
// have been enabled. The default setting only monitors the
|
// error events and data events. An application may choose to
|
// monitor CTS. DSR, RLSD, etc as well.
|
virtual LONG SetMask (DWORD dwMask = EEventBreak|EEventError|EEventRecv);
|
|
// The WaitEvent method waits for one of the events that are
|
// enabled (see SetMask).
|
virtual LONG WaitEvent (LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
|
|
// Setup the handshaking protocol. There are three forms of
|
// handshaking:
|
//
|
// 1) No handshaking, so data is always send even if the receiver
|
// cannot handle the data anymore. This can lead to data loss,
|
// when the sender is able to transmit data faster then the
|
// receiver can handle.
|
// 2) Hardware handshaking, where the RTS/CTS lines are used to
|
// indicate if data can be sent. This mode requires that both
|
// ports and the cable support hardware handshaking. Hardware
|
// handshaking is the most reliable and efficient form of
|
// handshaking available, but is hardware dependant.
|
// 3) Software handshaking, where the XON/XOFF characters are used
|
// to throttle the data. A major drawback of this method is that
|
// these characters cannot be used for data anymore.
|
virtual LONG SetupHandshaking (EHandshake eHandshake);
|
|
// Read operations can be blocking or non-blocking. You can use
|
// this method to setup wether to use blocking or non-blocking
|
// reads. Non-blocking reads is the default, which is required
|
// for most applications.
|
//
|
// 1) Blocking reads, which will cause the 'Read' method to block
|
// until the requested number of bytes have been read. This is
|
// useful if you know how many data you will receive.
|
// 2) Non-blocking reads, which will read as many bytes into your
|
// buffer and returns almost immediately. This is often the
|
// preferred setting.
|
virtual LONG SetupReadTimeouts (EReadTimeout eReadTimeout);
|
|
// Obtain communication settings
|
virtual EBaudrate GetBaudrate (void);
|
virtual EDataBits GetDataBits (void);
|
virtual EParity GetParity (void);
|
virtual EStopBits GetStopBits (void);
|
virtual EHandshake GetHandshaking (void);
|
virtual DWORD GetEventMask (void);
|
virtual BYTE GetEventChar (void);
|
|
// Write data to the serial port. Note that we are only able to
|
// send ANSI strings, because it probably doesn't make sense to
|
// transmit Unicode strings to an application.
|
virtual LONG Write (const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
|
virtual LONG Write (LPCSTR pString, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
|
virtual LONG WriteByte (unsigned char*pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
|
|
// Read data from the serial port. Refer to the description of
|
// the 'SetupReadTimeouts' for an explanation about (non) blocking
|
// reads and how to use this.
|
virtual LONG Read (void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
|
|
// Send a break
|
LONG Break (void);
|
|
// Determine what caused the event to trigger
|
EEvent GetEventType (void);
|
|
// Obtain the error
|
EError GetError (void);
|
|
// Obtain the COMM and event handle
|
HANDLE GetCommHandle (void) { return m_hFile; }
|
|
// Check if com-port is opened
|
bool IsOpen (void) const { return (m_hFile != 0); }
|
|
// Obtain last error status
|
LONG GetLastError (void) const { return m_lLastError; }
|
|
// Obtain CTS/DSR/RING/RLSD settings
|
bool GetCTS (void);
|
bool GetDSR (void);
|
bool GetRing (void);
|
bool GetRLSD (void);
|
|
// Purge all buffers
|
LONG Purge (void);
|
|
protected:
|
// Internal helper class which wraps DCB structure
|
class CDCB : public DCB
|
{
|
public:
|
CDCB() { DCBlength = sizeof(DCB); }
|
};
|
|
// Attributes
|
protected:
|
LONG m_lLastError; // Last serial error
|
HANDLE m_hFile; // File handle
|
EEvent m_eEvent; // Event type
|
DWORD m_dwEventMask; // Event mask
|
|
#ifndef SERIAL_NO_OVERLAPPED
|
HANDLE m_hevtOverlapped; // Event handle for internal overlapped operations
|
#endif
|
|
protected:
|
// Check the requirements
|
void CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const;
|
|
// CancelIo wrapper (for Win95 compatibility)
|
BOOL CancelCommIo (void);
|
};
|
|
#endif // __SERIAL_H
|