// Listing 1
//
//========================================================================
// File    : SerialPort.h
// Author  : Eric Woodruff,  CIS ID: 72134,1150
// Updated : Mon 04/07/97 21:28:39
// Note    : Copyright 1996-97, Eric Woodruff, All rights reserved
// Compiler: Borland C++ 5.xx, Visual C++ 4.xx
//
// Class declaration for CSerialPort.  This class is a wrapper for the
// Win32 serial communication API functions.
//
// This class can be compiled for a DLL.  Use the appropriate #define:
//  BUILD_SPCOMM_DLL defined   - Build DLL
//  BUILD_SPCOMM_NODLL defined - Not a DLL
//  Neither defined            - Assumed to be #include for app DLL import
//
//========================================================================

#if !defined(__SERIALPORT_H)
#define __SERIALPORT_H

// If you will never build this for use in a DLL, you can comment out
// this #if block.
//#if defined(BUILD_SPCOMM_DLL)
//    #define _DLLCLASS __declspec(dllexport)
//#elif !defined(BUILD_SPCOMM_NODLL)
//    #define _DLLCLASS __declspec(dllimport)
//#else
    #define _DLLCLASS
//#endif

//========================================================================
// Serial I/O definitions
// The standard serial I/O definitions can be found in WINBASE.H (i.e.
// CBR_xxxx, PCF_xxx, EV_xxx, CE_xxx, etc).
//========================================================================

#define SEVENDATABITS   7       // No equivalents in WINBASE.H
#define EIGHTDATABITS   8
#define PCF_NOFLOWCTL   0

#define ASCII_NUL       0x00    // Some common control codes
#define ASCII_SOH       0x01
#define ASCII_STX       0x02
#define ASCII_ETX       0x03
#define ASCII_EOT       0x04
#define ASCII_ENQ       0x05
#define ASCII_ACK       0x06
#define ASCII_XON       0x11
#define ASCII_XOFF      0x13
#define ASCII_NAK       0x15
#define ASCII_CAN       0x18

#define SP_INBUFSIZE    4096    // Default to 4K input and output buffer
#define SP_OUTBUFSIZE   4096

#define SP_WRITETIMEOUT 1000    // Default to a 1 second write timeout

//========================================================================
// Serial port class definition
//========================================================================
class _DLLCLASS CSerialPort
{
protected:
    HANDLE hPortId;         // Handle for port I/O
    HANDLE hThread;         // Event watch thread handle
    DWORD  dwThreadId;      // Event watch thread ID
    DWORD  dwLastError;     // Last error code from GetLastError()
    DWORD  dwCommErrors;    // Last comm error flags from ClearCommError()

    // Overlapped I/O structures for read and write
    OVERLAPPED olRead, olWrite;

    DWORD      dwEventMask;     // Event mask for WaitCommEvent()

    // Overlapped I/O structure for WaitCommEvent()
    OVERLAPPED olWait;

public:
    CSerialPort(const char *szPortName);
    ~CSerialPort();

    //====================================================================
    // Initialization/configuration functions
    //====================================================================
    BOOL SetBaudRate(int nBaudRate = CBR_19200);

    BOOL SetParityDataStop(int nParity = NOPARITY,
        int nDataBits = EIGHTDATABITS, int nStopBits = ONESTOPBIT);

    BOOL SetFlowControl(int nFlowCtrl = PCF_DTRDSR | PCF_RTSCTS,
        int nXOnLimit = 100, int nXOffLimit = 100,
        char chXOnChar = ASCII_XON, char chXOffChar = ASCII_XOFF);

    BOOL SetBufferSizes(int nInBufSize = SP_INBUFSIZE,
        int nOutBufSize = SP_OUTBUFSIZE);

    BOOL SetReadTimeouts(int nInterval = MAXDWORD, int nMultiplier = 0,
        int nConstant = 0);

    BOOL SetWriteTimeouts(int nMultiplier = 0,
        int nConstant = SP_WRITETIMEOUT);

    //====================================================================
    // Thread functions
    //====================================================================
    BOOL StartCommThread(LPTHREAD_START_ROUTINE CommProc,
        void *pvData = NULL);
    DWORD StopCommThread(void);

    //====================================================================
    // Inline functions
    //====================================================================

    // Return TRUE if port is open and no error occurred on the
    // last operation, FALSE if not.
    inline BOOL IsValid(void);

    // Return last error that occurred
    inline DWORD GetLastError(void);

    // Return the last set of error flags retrieved by ClearCommError
    inline DWORD GetCommErrors(void);

    //====================================================================
    // Virtual member functions
    //====================================================================

    // Can be overridden to alter the data being read/written.
    // Plain read and write by default
    virtual int ReadCommBlock(LPSTR lpBytes, int nBytesToRead,
        BOOL bExactSize = FALSE);
    virtual int WriteCommBlock(LPSTR lpBytes, int nBytesToWrite);

    // Can be overridden to provide custom handling of the data read
    // by the comm thread.  Does nothing by default.
    virtual int ProcessData(char *byData, int nLength);

    // Can be overridden to provide custom polled I/O
    virtual BOOL  WaitCommEvent(void);
    virtual DWORD CheckForCommEvent(BOOL bWait = FALSE);

    //====================================================================
    // Win32 API wrapper functions
    //
    // The following are not implemented in the class as they require
    // no access to the port handle or other internal data:
    //
    // BuildCommDCB
    // BuildCommDCBAndTimeouts
    // CommConfigDialog
    //
    //====================================================================
    BOOL ClearCommBreak(void);
    BOOL ClearCommError(LPCOMSTAT lpStat, LPDWORD lpdwErrors = NULL);
    BOOL EscapeCommFunction(DWORD dwFunc);
    BOOL GetCommConfig(LPCOMMCONFIG lpCC, LPDWORD lpdwSize);
    BOOL GetCommMask(LPDWORD lpEvtMask);
    BOOL GetCommModemStatus(LPDWORD lpModemStat);
    BOOL GetCommProperties(LPCOMMPROP lpCommProp);
    BOOL PurgeComm(DWORD fdwAction);
    BOOL SetCommBreak(void);
    BOOL SetCommConfig(LPCOMMCONFIG lpCC, DWORD dwSize);
    BOOL SetCommMask(DWORD fdwEvtMask);
    BOOL TransmitCommChar(char chTransmit);

    // DeviceIoControl() call to enable/disable insertion of line status
    // and modem status values in the normal data stream
    BOOL LSRMST_INSERT(BYTE chEscapeChar);

    //====================================================================
    // Win32 API wrappers for those who prefer the direct approach to port
    // configuration.
    //====================================================================
    BOOL GetCommState(LPDCB lpDCB);
    BOOL GetCommTimeouts(LPCOMMTIMEOUTS lpCommTimeouts);
    BOOL SetCommState(LPDCB lpDCB);
    BOOL SetCommTimeouts(LPCOMMTIMEOUTS lpCommTimeouts);
    BOOL SetupComm(DWORD cbInQueue, DWORD cbOutQueue);
};

// Inline function bodies
inline BOOL CSerialPort::IsValid(void)
    {  return (!(hPortId == INVALID_HANDLE_VALUE || dwLastError));  }

inline DWORD CSerialPort::GetLastError(void)
    {  return dwLastError; }

inline DWORD CSerialPort::GetCommErrors(void)
    {  return dwCommErrors;  }

#endif
