Listing 2: A dumb-terminal program that uses CSerialPort

//===================================================================
// File    : Terminal.cpp
// Author  : Eric Woodruff,  Eric@EWoodruff.us
// Updated : Mon 04/07/1997
// Note    : Copyright 1996-97, Eric Woodruff, All rights reserved
// Compiler: Borland C++ 5.xx, Visual C++ 4.xx
//
// Compile with:
//      bcc32 -DBUILD_SPCOMM_NODLL terminal.cpp serialport.cpp
//   or
//      cl -DBUILD_SPCOMM_NODLL terminal.cpp serialport.cpp
//
// A simple terminal program to demonstrate the stock CSerialPort
// class.
//
//===================================================================

#include <windows.h>
#include <ctype.h>
#include <stdio.h>

#include "SerialPort.h"

BOOL InitConsole(void);
void DumbTerminal(const char *pszPortName, const char *pszOptions);
DWORD WINAPI CommReader(void *pvData);

#define MAX_SIZE    1024

HANDLE hStdIn, hStdOut;

void main(int argc, char *argv[])
{
    if(argc < 3)
    {
     printf(" Syntax: Terminal portname parity_data_stop_localecho\n"
            "Example: Terminal COM1 7E1\n"
            "Example: Terminal COM1 N81L  (Add L for local echo)");
     exit(1);
    }

    if(!InitConsole())
        printf("Could not initialize console handles\n");
    else
        DumbTerminal(argv[1], argv[2]);

    exit(0);
}

BOOL InitConsole(void)
{
    // Get handles for standard input and output
    hStdIn = GetStdHandle(STD_INPUT_HANDLE);
    if(hStdIn == INVALID_HANDLE_VALUE)
        return FALSE;

    hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if(hStdOut == INVALID_HANDLE_VALUE)
        return FALSE;

    // Turn off all input mode processing
    SetConsoleMode(hStdIn, 0);

    return TRUE;
}

void DumbTerminal(const char *pszPortName, const char *pszOptions)
{
    INPUT_RECORD irInput;
    BOOL bContinue = TRUE;
    DWORD dwRecords;

    char chChar;

    // Assumed defaults are N81
    BOOL bLocalEcho = FALSE;
    int  nParity = NOPARITY, nDataBits = EIGHTDATABITS,
         nStopBits = ONESTOPBIT;

    // This is just a demo, so there is no real editing
    chChar = toupper(pszOptions[0]);
    if(chChar == 'E')
        nParity = EVENPARITY;
    else
        if(chChar == 'O')
            nParity = ODDPARITY;

    if(pszOptions[1] == '7')
        nDataBits = SEVENDATABITS;

    if(pszOptions[2] == '2')
        nDataBits = TWOSTOPBITS;

    if(toupper(pszOptions[3]) == 'L')
        bLocalEcho = TRUE;

    // Open the port and use the given settings
    CSerialPort COMPort(pszPortName);
    COMPort.SetParityDataStop(nParity, nDataBits, nStopBits);

    // If valid, start the reader thread
    if(!COMPort.IsValid() || !COMPort.StartCommThread(CommReader))
        printf("Error %ld initializing COM port!",
            COMPort.GetLastError());
    else
    {
        printf("Connected on %s using options %s\nESC to quit\n",
            pszPortName, pszOptions);

        // Wait for keyboard input and send each character to the
        // port until ESC is hit.
        do
        {
            // This will block until input is available
            if(ReadConsoleInput(hStdIn, &irInput, 1, &dwRecords))
            {
                if(irInput.EventType == KEY_EVENT &&
                  irInput.Event.KeyEvent.bKeyDown)
                {
                    chChar = irInput.Event.KeyEvent.uChar.AsciiChar;

                    // If ESC, stop. If not zero, write it to port
                    if(chChar == 27)
                        bContinue = FALSE;
                    else
                        if(chChar)
                        {
                            COMPort.WriteCommBlock(&chChar, 1);
                            // For non-modem connections
                            if(bLocalEcho)
                                WriteConsole(hStdOut, &chChar, 1,
                                    &dwRecords, NULL);
                        }
                }
            }

        } while(bContinue);
    }
}

// This is the thread function that handles incoming data.  Unless
// otherwise specified, CSerialPort::StartCommThread() passes a
// pointer the the port object itself.
DWORD WINAPI CommReader(void *pvData)
{
    CSerialPort *COMPort = (CSerialPort *)pvData;
    DWORD dwEventMask, dwBytesWritten;
    int   nSize;
    char  byBuffer[MAX_SIZE];

    // Tell the port to notify us when a read event occurs (EV_RXCHAR
    // is enabled by default).
    if(!COMPort->WaitCommEvent())
        return 1L;      // Error

    // Wait for an empty Comm event that signals the COM port object
    // is shutting down.
    do
    {
        // Since this is a separate thread, we can pass TRUE so
        // that the function doesn't return until an event occurs.
        dwEventMask = COMPort->CheckForCommEvent(TRUE);
        if(dwEventMask & EV_RXCHAR)
        {
            // Read as much as possible and display it on the screen
            nSize = COMPort->ReadCommBlock(byBuffer, MAX_SIZE);
            if(nSize)
                WriteConsole(hStdOut, byBuffer, nSize,
                   &dwBytesWritten, NULL);

            // Set it up to wait for the next event
            COMPort->WaitCommEvent();
        }

    } while(dwEventMask);

    return 0L;
}
//End of File