//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Copyright  1997  Microsoft Corporation.  All Rights Reserved.

Module Name:

     tsttmout.cpp  

Abstract:
Functions:
Notes:
--*/
/*++
 
 
Module Name:
 
    TstTmOut.cpp
 
Abstract:
 
    These test test the Read and Write Timeouts.
 
Author:
 
    Uknown (unknown)
 
Notes:
 
--*/
#define __THIS_FILE__ TEXT("TstTmOut.cpp")

#include "PSerial.h"
#include "TstModem.h"
#include "TstModem.h"

/*++
 
TestReadTimeout:
 
    Tests the duration of read time outs in serveral configurations.
    
Arguments:
 
    TUX standard arguments.
 
Return Value:
 
    TPR_HANDLED: for TPM_QUERY_THREAD_COUNT
    TPR_EXECUTE: for TPM_EXECUTE
    TPR_NOT_HANDLED: for all other messages.
 
Author:
 
    Uknown (unknown)
 
Notes:
 
    
 
--*/
TESTPROCAPI TestReadTimeouts( UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    
    if( uMsg == TPM_QUERY_THREAD_COUNT )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = 0;
        return SPR_HANDLED;
    }
    else if (uMsg != TPM_EXECUTE)
    {
        return TPR_NOT_HANDLED;
    } // end if else if

    BOOL            bRtn            = FALSE;
    DWORD           dwResult        = TPR_PASS;
    CommPort *      hCommPort       = NULL;
    DWORD           dwBytes         = 0;
    DWORD           nStartTick      = 0;
    DWORD           nEndTick        = 0;
    DWORD           nTotalTicks     = 0;
    DWORD           nDeltaTicks     = 0;
    DWORD           nExpectedTicks  = 0;
    INT             iIdx;
    COMMTIMEOUTS    cto;
    BOOL            fSending        = FALSE;
    const int       nBuffSize       = 100;
    BYTE            aBuffer[nBuffSize];
    const int       nTimeoutTests   = 1;
    
    struct TESTREADTIMEOUTS {
    DWORD   ReadMultiplier;
    DWORD   ReadConstant;
    } aTestReadTimeouts[nTimeoutTests] = {
    {  0, 5000  } };
    
    /* --------------------------------------------------------------------
    Open the comm port for this test.
    -------------------------------------------------------------------- */
    
    INT i = 0;
    hCommPort = CreateCommObject(g_bCommDriver);
    FUNCTION_ERROR( hCommPort == NULL, return FALSE );
    hCommPort -> CreateFile( g_lpszCommPort, 
                             GENERIC_READ | GENERIC_WRITE, 0, NULL,
                             OPEN_EXISTING, 0, NULL );

    // If client could not connect it could be because primary has not done
    // CreateFile yet, let's time out and try a bunch of times
    while(!hCommPort->IsValid()&& i < MAX_BT_CONN_ATTEMPTS)
    {
         Sleep(BT_CONN_ATTEMPT_TIMEOUT);

         hCommPort -> CreateFile( g_lpszCommPort, 
                                  GENERIC_READ | GENERIC_WRITE, 0, NULL,
                                  OPEN_EXISTING, 0, NULL );
         i++;
    }
   
    FUNCTION_ERROR( !hCommPort->IsValid(), return TPR_ABORT );        


    if( !g_fSetCommProp )
    {
    g_pKato->Log( LOG_WARNING, 
              TEXT("WARNING: in %s @ line %d: g_CommProp NOT negotiated using local value."),
              __THIS_FILE__, __LINE__ );
    bRtn =  GetCommProperties( hCommPort, &g_CommProp );
    COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup );
    
    } // end if( !g_fSetCommProp )

    bRtn = SetupDefaultPort( hCommPort );
    DEFAULT_ERROR( FALSE == bRtn, goto TRTCleanup);
    
    /* --------------------------------------------------------------------
    Sync the begining of the test.
    -------------------------------------------------------------------- */
    bRtn = BeginTestSync( hCommPort, lpFTE->dwUniqueID );
    DEFAULT_ERROR( FALSE == bRtn, dwResult = TPR_ABORT; goto TRTCleanup);

    /* --------------------------------------------------------------------
    Test the immediate return read.
    -------------------------------------------------------------------- */
    cto.ReadIntervalTimeout         = MAXDWORD; 
    cto.ReadTotalTimeoutMultiplier  = 0; 
    cto.ReadTotalTimeoutConstant    = 0; 
    cto.WriteTotalTimeoutMultiplier = 0; 
    cto.WriteTotalTimeoutConstant   = 0; 
    bRtn = SetCommTimeouts( hCommPort, &cto );
    COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);
   
    nStartTick = GetTickCount();
    bRtn = ReadFile( hCommPort, aBuffer, nBuffSize, &dwBytes, NULL );
    nEndTick = GetTickCount();
    COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);

    nTotalTicks = nEndTick - nStartTick;

    g_pKato->Log( LOG_DETAIL, TEXT("In %s @ line %d: Took %d ms to pole for %d bytes."),
         __THIS_FILE__, __LINE__, nTotalTicks, dwBytes );

    /* --------------------------------------------------------------------
    Test inter-char interval timing.
    -------------------------------------------------------------------- */
    if( PCF_INTTIMEOUTS & g_CommProp.dwProvCapabilities )
    {
    cto.ReadIntervalTimeout         = 100;
    cto.ReadTotalTimeoutConstant    = 10000;
    bRtn = SetCommTimeouts( hCommPort, &cto );
    COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);

    g_pKato->Log( LOG_DETAIL, 
              TEXT("In %s @ line %d:  Testing interdigit timeout of %d ms"),
              __THIS_FILE__, __LINE__, cto.ReadIntervalTimeout );
    
    fSending = g_fPrimary;
    for( iIdx = 1; iIdx <= 2; iIdx++ )
    {
        if( fSending )
        {
            // 8-sep-97 - On a slow CE machine, it may take some time for it to get into
            // ReadFile, so wait 2 seconds before sending the first byte
            g_pKato->Log( LOG_DETAIL, TEXT("In %s @ line %d: Sender Waiting 2000ms before sending."), __THIS_FILE__, __LINE__ );
            Sleep( 2000 );
            fSending = FALSE;


        aBuffer[0] = 'X';
        CMDLINENUM( bRtn = WriteFile( hCommPort, aBuffer, 1, &dwBytes, NULL) );
        DEFAULT_ERROR( 1 != dwBytes, goto TRTCleanup);
        COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);
        
        Sleep( 3 * cto.ReadIntervalTimeout );
        
        aBuffer[0] = 'y';
        CMDLINENUM( bRtn = WriteFile( hCommPort, aBuffer, 1, &dwBytes, NULL ) );
        DEFAULT_ERROR( 1 != dwBytes, goto TRTCleanup);
        COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);

        } // end if( fSending )            

        else
        {
        fSending = TRUE;
                g_pKato->Log( LOG_DETAIL, TEXT("In %s @ line %d: Receiver Starting Timeout Test."),
                    __THIS_FILE__, __LINE__ );
        nStartTick = GetTickCount();
        bRtn = ReadFile( hCommPort, aBuffer, 2, &dwBytes, NULL );
        COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);
                nEndTick = GetTickCount();

            CMDLINENUM( nTotalTicks = nEndTick - nStartTick );

            if( 2 == dwBytes ) 
            {
                g_pKato->Log( LOG_FAIL, 
                      TEXT("FAIL in %s @ line %d: Read didn't time out.  ")
                      TEXT("Read 2, \"%c%c\", bytes in %d ms."),
                      __THIS_FILE__, __LINE__, aBuffer[0], aBuffer[1],
                      nEndTick - nStartTick );
                dwResult = TPR_FAIL;

            } // end if( 2 == dwBytes )

            else if( 0 == dwBytes )
            {
                LOGLINENUM();
                g_pKato->Log( LOG_FAIL, 
                      TEXT("FAIL in %s @ line %d: Didn't receive first character, timed out in %d ms"),
                      __THIS_FILE__, __LINE__, nTotalTicks );
                dwResult = TPR_FAIL;

            } // end if( 2 == dwBytes ) else if( nTotalTicks > SLEEPTIME )

            else
            {
                g_pKato->Log( LOG_DETAIL, 
                      TEXT("In %s @ line %d: Read timed out in %d ms"),
                      __THIS_FILE__, __LINE__, nTotalTicks );

            } // end if( 2 == dwBytes ) else if( nTotalTicks > SLEEPTIME ) else
        
        } //  if( fSending ) else

    } // end for( iIdx = 1; iIdx <= 2; iIdx++ )

    }  // end if( PCF_INTTIMEOUTS & g_CommProp.dwProvCapabilities )

    else 
    {
    g_pKato->Log( LOG_WARNING, 
              TEXT("FAIL in %s @ line %d: Enviroment doesn't support interval timeouts"),
              __THIS_FILE__, __LINE__ );
              
    } // end if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities ) else

    /* --------------------------------------------------------------------
    Test total timeouts
    -------------------------------------------------------------------- */
    COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);
    
    if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities )
    {
    cto.ReadIntervalTimeout         = 0; 

    for( iIdx = 0; iIdx < nTimeoutTests; iIdx++ )
    {
            g_pKato->Log( LOG_DETAIL, TEXT("In %s @ line %d: Pass %d Testing Total Timeouts."), __THIS_FILE__, __LINE__, iIdx );

        // Set comm timeouts
        cto.ReadTotalTimeoutMultiplier  = aTestReadTimeouts[iIdx].ReadMultiplier; 
        cto.ReadTotalTimeoutConstant    = aTestReadTimeouts[iIdx].ReadConstant; 
        bRtn = SetCommTimeouts( hCommPort, &cto );
        COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup);

        g_pKato->Log( LOG_DETAIL, 
              TEXT("In %s @ line %d: Read timeout of ")
              TEXT("%d bytes * %dms + %dms"),
              __THIS_FILE__, __LINE__, nBuffSize, 
              aTestReadTimeouts[iIdx].ReadMultiplier, 
              aTestReadTimeouts[iIdx].ReadConstant );
              
        // Perform the read
        nStartTick = GetTickCount();
        bRtn = ReadFile( hCommPort, aBuffer, nBuffSize, &dwBytes, NULL );
        nEndTick = GetTickCount();
        COMM_ERROR( hCommPort, FALSE == bRtn, goto TRTCleanup );

        g_pKato->Log( LOG_DETAIL, 
              TEXT("In %s @ line %d: ReadFile Return value(%ld) return Bytes(%ld) "),
              __THIS_FILE__, __LINE__, 
              bRtn,dwBytes);
        // Calculate results
        nExpectedTicks = aTestReadTimeouts[iIdx].ReadMultiplier * nBuffSize +
                 aTestReadTimeouts[iIdx].ReadConstant;
        nDeltaTicks = nExpectedTicks / 10;                             
        nTotalTicks = nEndTick - nStartTick;
        
        /* ------------------------------------------------------------
        Check Results.
        ------------------------------------------------------------ */
        if( (nTotalTicks < (nExpectedTicks - nDeltaTicks)) ||
        (nTotalTicks > (nExpectedTicks + nDeltaTicks))   )
        {
        g_pKato->Log( LOG_FAIL, 
                  TEXT("FAIL in %s @ line %d: Read Timeout, ")
                  TEXT("Took %dms to timeout expected %dms +/- %d ms"),
                  __THIS_FILE__, __LINE__, nTotalTicks, 
                  nExpectedTicks, nDeltaTicks );
        dwResult = TPR_FAIL;

        } // if Timeout out of range.

        else
        {
        g_pKato->Log( LOG_DETAIL, 
                  TEXT("In %s @ line %d: Read Timed out in %dms,  ")
                  TEXT("Valid range %dms +/- %d ms"),
                  __THIS_FILE__, __LINE__, nTotalTicks, 
                  nExpectedTicks, nDeltaTicks );
                  
        }  // if ( Timeout out of range ) else


    }  // end for( iIdx = 1; iIdx <= nTimeoutTests; iIdx++ )

    } // end if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities )

    else 
    {
    g_pKato->Log( LOG_WARNING, 
              TEXT("WARNING in %s @ line %d: Enviroment doesn't support total timeouts"),
              __THIS_FILE__ );
              
    } // end if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities ) else
  
    TRTCleanup:

    if( FALSE == bRtn ) dwResult = TPR_FAIL;

    /* --------------------------------------------------------------------
    Sync the end of a test of the test.
    -------------------------------------------------------------------- */
    dwResult = EndTestSync( hCommPort, lpFTE->dwUniqueID, dwResult );

    delete hCommPort ;
    

    return dwResult;
    
} // end TestReadTimeouts( ... ) 


/*++
 
TestWriteTimeout:
 
    Tests the duration of write time outs in serveral configurations.
    
Arguments:
 
    TUX standard arguments.
 
Return Value:
 
    TPR_HANDLED: for TPM_QUERY_THREAD_COUNT
    TPR_EXECUTE: for TPM_EXECUTE
    TPR_NOT_HANDLED: for all other messages.
 
Author:
 
    Uknown (unknown)
 
Notes:
 
    
 
--*/
TESTPROCAPI TestWriteTimeouts( UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    
    if( uMsg == TPM_QUERY_THREAD_COUNT )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = 0;
        return SPR_HANDLED;
    }
    else if (uMsg != TPM_EXECUTE)
    {
        return TPR_NOT_HANDLED;
    } // end if else if

    BOOL            bRtn            = FALSE;
    DWORD           dwResult        = TPR_PASS;
    CommPort *      hCommPort       = NULL;
    DWORD           dwBytes         = 0;
    DWORD           nStartTick      = 0;
    DWORD           nEndTick        = 0;
    DWORD           nTotalTicks     = 0;
    DWORD           nDeltaTicks     = 0;
    DWORD           nExpectedTicks  = 0;
    INT             iIdx;
    COMMTIMEOUTS    cto;
    DCB             LocalDcb;
    const int       nBuffSize       = 100;
    BYTE            aBuffer[nBuffSize];
    const int       nTimeoutTests   = 3;
    struct TESTWRITETIMEOUTS {
    DWORD   WriteMultiplier;
    DWORD   WriteConstant;
    } aTestWriteTimeouts[nTimeoutTests] = {
    { 50,   0   },
    { 40, 1000  },  
    {  0, 5000  } };
    
    /* --------------------------------------------------------------------
    Open the comm port for this test.
    -------------------------------------------------------------------- */
    hCommPort = CreateCommObject(g_bCommDriver);
    FUNCTION_ERROR( hCommPort == NULL, return FALSE );
    hCommPort -> CreateFile( g_lpszCommPort, 
                        GENERIC_READ | GENERIC_WRITE, 0, NULL,
                        OPEN_EXISTING, 0, NULL );
    FUNCTION_ERROR( !hCommPort->IsValid(), return TPR_ABORT );        

    __try {

    if( !g_fSetCommProp )
    {
    g_pKato->Log( LOG_WARNING, 
              TEXT("WARNING: in %s @ line %d: g_CommProp NOT negotiated using local value."),
              __THIS_FILE__, __LINE__ );
    bRtn =  GetCommProperties( hCommPort, &g_CommProp );
    COMM_ERROR( hCommPort, FALSE == bRtn, __leave );
    
    } // end if( !g_fSetCommProp )

    bRtn = SetupDefaultPort( hCommPort );
    DEFAULT_ERROR( FALSE == bRtn, __leave );
    
    /* --------------------------------------------------------------------
    Sync the begining of the test.
    -------------------------------------------------------------------- */
    bRtn = BeginTestSync( hCommPort, lpFTE->dwUniqueID );
    DEFAULT_ERROR( FALSE == bRtn, dwResult = TPR_ABORT; __leave );

    /* --------------------------------------------------------------------
    Test total timeouts
    -------------------------------------------------------------------- */
    GetCommTimeouts( hCommPort, &cto );

    /* -------------------------------------------------------------------
    Set Comm Properties for CTS-RTS.
    ------------------------------------------------------------------- */
    bRtn = GetCommState( hCommPort, &LocalDcb );
    COMM_ERROR( hCommPort, FALSE == bRtn, __leave );

    LocalDcb.fOutxCtsFlow = TRUE;

    bRtn = SetCommState( hCommPort, &LocalDcb );
    COMM_ERROR( hCommPort, FALSE == bRtn, __leave );

    bRtn = EscapeCommFunction( hCommPort, CLRRTS );
    COMM_ERROR( hCommPort, FALSE == bRtn, __leave );

    Sleep( 2000 );
    
    if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities )
    {
    
    for( iIdx = 0; iIdx < nTimeoutTests; iIdx++ )
    {
        // Set comm timeouts
        cto.WriteTotalTimeoutMultiplier  = 
            aTestWriteTimeouts[iIdx].WriteMultiplier; 
        cto.WriteTotalTimeoutConstant    = 
            aTestWriteTimeouts[iIdx].WriteConstant; 
        bRtn = SetCommTimeouts( hCommPort, &cto );
        COMM_ERROR( hCommPort, FALSE == bRtn, __leave );

        g_pKato->Log( LOG_DETAIL, 
              TEXT("In %s @ line %d: Write timeout of ")
              TEXT("%d bytes * %dms + %dms"),
              __THIS_FILE__, __LINE__, nBuffSize, 
              aTestWriteTimeouts[iIdx].WriteMultiplier, 
              aTestWriteTimeouts[iIdx].WriteConstant );
              
        // Perform the Write
        nStartTick = GetTickCount();
        bRtn = WriteFile( hCommPort, aBuffer, nBuffSize, &dwBytes, NULL );
        nEndTick = GetTickCount();
        COMM_ERROR( hCommPort, FALSE == bRtn, __leave );

        // Calculate results
        nExpectedTicks = aTestWriteTimeouts[iIdx].WriteMultiplier * nBuffSize +
                 aTestWriteTimeouts[iIdx].WriteConstant;
        nDeltaTicks = nExpectedTicks / 10;                             
        nTotalTicks = nEndTick - nStartTick;
        
        /* ------------------------------------------------------------
        Check Results.
        ------------------------------------------------------------ */
        if( nBuffSize == dwBytes )
        {
        g_pKato->Log( LOG_FAIL, 
                  TEXT("FAIL in %s @ line %d: Write Succeeded CTS ignored!  ")
                  TEXT("Took %dms to write %d bytes of %d bytes"),
                  __THIS_FILE__, __LINE__, nTotalTicks, 
                  dwBytes, nBuffSize );
        dwResult = TPR_FAIL;

        }
        
        else if( (nTotalTicks < (nExpectedTicks - nDeltaTicks)) ||
             (nTotalTicks > (nExpectedTicks + nDeltaTicks))   )
        {
        g_pKato->Log( LOG_FAIL, 
                  TEXT("FAIL in %s @ line %d: Write Timeout %d bytes of %d bytes, ")
                  TEXT("Took %dms to timeout expected %dms +/- %d ms"),
                  __THIS_FILE__, __LINE__, dwBytes, nBuffSize,
                  nTotalTicks, nExpectedTicks, nDeltaTicks );
        dwResult = TPR_FAIL;

        } // if ( Timeout out of range ) else

        else
        {
        g_pKato->Log( LOG_DETAIL, 
                  TEXT("In %s @ line %d: Write Timed out in %dms,  ")
                  TEXT("Valid range %dms +/- %d ms"),
                  __THIS_FILE__, __LINE__, nTotalTicks, 
                  nExpectedTicks, nDeltaTicks );
                  
        } // if ( Timeout out of range ) else

    }  // end for( iIdx = 1; iIdx <= nTimeoutTests; iIdx++ )

    } // end if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities )

    else 
    {
    g_pKato->Log( LOG_WARNING, 
              TEXT("FAIL in %s @ line %d: Enviroment doesn't support total timeouts"),
              __THIS_FILE__ );
              
    } // end if( PCF_TOTALTIMEOUTS & g_CommProp.dwProvCapabilities ) else

    bRtn = PurgeComm( hCommPort, 
              PURGE_TXABORT | PURGE_RXABORT | 
              PURGE_RXCLEAR | PURGE_TXCLEAR );
    COMM_ERROR( hCommPort, FALSE == bRtn, __leave );
   
    } __finally {

    if( FALSE == bRtn ) dwResult = TPR_FAIL;

    /* --------------------------------------------------------------------
    Sync the end of a test of the test.
    -------------------------------------------------------------------- */
    dwResult = EndTestSync( hCommPort, lpFTE->dwUniqueID, dwResult );

    delete hCommPort ;

    } 
    return dwResult;
    
} // end TestWriteTimeouts( ... ) 

