//
// Test the quick return timeouts
//
// Assume that we are using a loopback connector.
//
// Assume that it isn't running on a stressed machine.
//

#include "windows.h"
#include "stdio.h"

#define FAILURE printf("FAIL: %d\n",__LINE__);exit(1)

int __cdecl main(int argc, char *argv[]) {
    CHAR *myPort = "COM1";
    DCB myDcb;
    DWORD junk;
    COMMTIMEOUTS myTimeOuts;
    DWORD numberActuallyRead;
    DWORD numberActuallyWritten;
    UCHAR readBuff[1000];
    HANDLE comHandle;
    DWORD startingTicks;
    OVERLAPPED readOl;
    OVERLAPPED writeOl;
    UCHAR writeBuff[5] = {0,1,2,3,4};

    if (argc > 1) {

        myPort = argv[1];

    }

    if ((comHandle = CreateFile(
                     myPort,
                     GENERIC_READ | GENERIC_WRITE,
                     0,
                     NULL,
                     CREATE_ALWAYS,
                     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
                     NULL
                     )) == ((HANDLE)-1)) {

        FAILURE;

    }

    if (!(readOl.hEvent = CreateEvent(
                             NULL,
                             TRUE,
                             FALSE,
                             NULL
                             ))) {

        FAILURE;

    }

    if (!GetCommState(
             comHandle,
             &myDcb
             )) {

        FAILURE;

    }

    myDcb.BaudRate = 19200;
    myDcb.ByteSize = 8;
    myDcb.StopBits = ONESTOPBIT;
    myDcb.Parity = NOPARITY;
    myDcb.fOutxCtsFlow = FALSE;
    myDcb.fOutxDsrFlow = FALSE;
    myDcb.fDsrSensitivity = FALSE;
    myDcb.fOutX = FALSE;
    myDcb.fInX = FALSE;
    myDcb.fRtsControl = RTS_CONTROL_ENABLE;
    myDcb.fDtrControl = DTR_CONTROL_ENABLE;
    if (!SetCommState(
            comHandle,
            &myDcb
            )) {

        FAILURE;

    }

    //
    // Make sure that the IO doesn't time out.
    //

    myTimeOuts.ReadIntervalTimeout = 0;
    myTimeOuts.ReadTotalTimeoutMultiplier = 0;
    myTimeOuts.ReadTotalTimeoutConstant = 0;
    myTimeOuts.WriteTotalTimeoutMultiplier = 0;
    myTimeOuts.WriteTotalTimeoutConstant = 0;

    if (!SetCommTimeouts(
             comHandle,
             &myTimeOuts
             )) {

        FAILURE;

    }

    //
    // Start off a read.  It shouldn't complete
    //

    if (!ReadFile(
             comHandle,
             &readBuff[0],
             1000,
             &numberActuallyRead,
             &readOl
             )) {

        if (GetLastError() != ERROR_IO_PENDING) {

            FAILURE;

        }

        if (GetOverlappedResult(
                 comHandle,
                 &readOl,
                 &numberActuallyRead,
                 FALSE
                 )) {

            FAILURE;

        }

    } else {

        FAILURE;

    }

    //
    // The read should still be there.  Now do a purge comm.  We
    // should then do a sleep for 2 seconds to give the read time
    // to complete.  Then we should first make sure that the
    // read has completed (via a get overlapped).  Then we should
    // do a SetupComm (with a "large" value so that we will actually
    // allocate a new typeahead buffer).  If there is still a "dangling"
    // read, then we should never return from SetupComm.
    //

    if (!PurgeComm(
             comHandle,
             PURGE_TXABORT | PURGE_RXABORT
             )) {

        FAILURE;

    }

    if (WaitForSingleObject(
             readOl.hEvent,
             2000
             ) != WAIT_OBJECT_0) {

        FAILURE;

    }

    if (!SetupComm(
             comHandle,
             20000,
             20000
             )) {

        FAILURE;

    }

    return 1;

}