// 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
//
// ========================================================================
#pragma once

// 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
 */

#ifdef  BUILD_COMMDLL
#define     COMMDLL_DLLCLASS    __declspec(dllexport)
#else
#define     COMMDLL_DLLCLASS    __declspec(dllimport)
#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).
// ========================================================================

#include <vector>
#include <string>

#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       0x0D
#define ASCII_ACK       0x0E
#define ASCII_XON       0x11
#define ASCII_XOFF      0x13
#define ASCII_NAK       0x15
#define ASCII_CAN       0x18
#define ASCII_SEPARATOR 0x09

#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 COMMDLL_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 SetBaudRate(long lBaudRate = 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(LPCSTR 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);

//  Get Com port name and return number of com port in the system
    static int GetAllComPort(std::vector<std::string> &vecComPortName);
};

// 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;
}

