/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-3
**  FileName: TestWithNoFaultAfter3DriveCycles.c
**  Author:   EnGenius
**  Date:     2/25/2022
**  Email:    <support@autosinnovate.org>
**
**  Purpose:  SAE J1699-3 Vehicle OBD II Compliance Test Cases Source Code.
**            This source code is intended to run the tests described in
**            the SAE J1699-3 document in an automated manner, when compiled
**            and used with an SAE J2534-compatible pass-thru device.
**
**            File j1699.c contains information on building and running this test.
**
**  Description:
**
**  Modifications:  12/07/2022  Initial Version
**
********************************************************************************
*******************************************************************************/

#include <stdio.h>    // C Library input and output declarations
#include <stdlib.h>   // C Library general function declarations
#include <time.h>     // C Library time and date declarations
#include <windows.h>  // Windows API declarations
#include "j2534.h"    // j1699 project j2534 declarations
#include "j1699.h"    // j1699 project general declarations


// Function Prototypes
STATUS VerifyINFChange ( void );


// Variables
extern BYTE          gSid0ASupEcuCnt;           // count of ECUs supporting SID $0A
extern unsigned int  gSid0ASupEcuIdArray[MAX_ECUS];


/*******************************************************************************
**
**  Function:  Test9_NoFaultsAfter3DriveCycles
**
**  Purpose:   Run test 9 with no faults after 3 drive cycles
**
*******************************************************************************/
STATUS Test9_NoFaultsAfter3DriveCycles ( void )
{
	BYTE    EcuIdx;
	STATUS  eRetCode;

	BOOL    bSubTestFailed = FALSE;


//*******************************************************************************
//  Test 9.1 - Complete Two or More Additional Drive Cycles
//*******************************************************************************
	gTestSubsection = 1;
	gbTestSubsectionFailed = FALSE;

	// Prompt user to complete the second and perform the third drive cycle
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Complete Two or More Additional Drive Cycles)" );

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key OFF for 30 seconds or longer, as appropriate for the ECU\n"
	      "(This completes two driving cycles)." );

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Start engine or activate propulsion system for Hybrid/PHEV.\n\n"

	      "Let idle for 1 minute or whatever time it takes\n"
	      "to run the monitor and detect that there is no malfunction.\n"
	      "(This starts third driving cycle; however, third driving cycle will not be\n"
	      "completed until key is turned off).\n\n"

	      "Note: Some powertrain control systems have engine controls that can start and\n"
	      "stop the engine without regard to ignition position.\n" );

	do
	{
		printf ( "\n\n\n" );
		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Turn key OFF for 30 seconds or longer, as appropriate for the ECU\n"
		      "(This completes the current driving cycles with no fault)." );

		printf ( "\n\n\n" );
		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Start engine or activate propulsion system for Hybrid/PHEV.\n\n"

		      "Let idle for 1 minute or whatever time it takes\n"
		      "to run the monitor and detect that there is no malfunction.\n"
		      "(This starts another driving cycle; however, the driving cycle will not be\n"
		      "completed until key is turned off).\n\n"

		      "Note: Some powertrain control systems have engine controls that can start and\n"
		      "stop the engine without regard to ignition position.\n" );
		printf ( "\n\n\n" );
	}
	while ( Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
	             "The MIL should now be OFF.  If it is, the test will continue to\n"
	             "Test 9.2.\n"
	             "If the MIL is still ON, additional driving cycles may be performed\n"
	             "until MIL is off.\n\n"

	             "Is MIL OFF?" ) != 'Y' );

	gbEngineRunning = TRUE;

	Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );


//*******************************************************************************
//  Test 9.2 - Determine the OBD protocol to use
//*******************************************************************************
	// Set flag to indicate DTC should be historical
	gbDTCHistorical = TRUE;

	// Set flag to indicate no Permanent DTC
	gbDTCPermanent = FALSE;

	gTestSubsection = 2;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Determine Protocol, Engine Running)" );

	if ( DetermineOBDProtocol ( ) != PASS )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Protocol determination unsuccessful.\n" );
		Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
		return FAIL;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 9.3 - Verify pending DTC data, Engine Running
//*******************************************************************************
	gTestSubsection = 3;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Pending DTCs (Service $07), Engine Running)" );

	if ( VerifyPendingDTCData ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 9.4 - Verify stored DTC data, Engine Running
//*******************************************************************************
	gTestSubsection = 4;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Stored DTCs (Service $03), Engine Running)" );

	if ( VerifyStoredDTCData ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	// Verify MIL and DTC status is cleared
	if ( VerifyMILData ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 9.5 - Verify freeze frame support and data, Engine Running
//*******************************************************************************
	gTestSubsection = 5;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Freeze Frame Data (Service $02), Engine Running)" );

	if ( VerifyFFSupportAndData ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	// Link active test to verify communication remained active for ALL protocols
	if ( VerifyECUCommunication ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 9.6 - Verify Permanent Codes, Engine Running
//*******************************************************************************
	gTestSubsection = 6;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Permanent DTCs (Service $0A), Engine Running)" );

	if ( VerifyPermanentCodeSupport ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 9.7 - Verify Permanent Codes Drive Cycle
//*******************************************************************************
	gTestSubsection = 7;
	gbTestSubsectionFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Complete Static Test or Continue to Permanent Code Drive Cycle)" );

	if ( gSid0ASupEcuCnt != 0 )
	{
		for ( EcuIdx = 0;
		      EcuIdx < gSid0ASupEcuCnt;
		      EcuIdx++ )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Service $0A is supported by:  ECU %X\n",
			      gSid0ASupEcuIdArray[EcuIdx]  );
		}

		if ( Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		           "Do you wish to run the CARB drive cycle portion for Permanent DTCs (Tests 9.8-9.22)?" ) == 'Y' )
		{
			Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );

			//***************************************************************************
			//  Test 9.8-21 - Verify Permanent Codes
			//***************************************************************************
			// Verify Permanent Codes
			if ( (eRetCode = Test9_8to21_PermanentCodes ( )) != PASS )
			{
				bSubTestFailed = TRUE;
			}

			//***************************************************************************
			//  Test 9.22 - Verify Permanent Code support
			//***************************************************************************
			gTestSubsection = 22;
			gbTestSubsectionFailed = FALSE;
			bSubTestFailed = FALSE;

			Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "(Verify Permanent DTCs (Service $0A), Engine Running)" );

			if ( VerifyPermanentCodeSupport ( ) != PASS )
			{
				bSubTestFailed = TRUE;
			}

			if ( VerifyINFChange ( ) != PASS )
			{
				bSubTestFailed = TRUE;
			}

			if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
			{
				bSubTestFailed = TRUE;
			}

			if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
			{
				if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
				{
					return FAIL;
				}
			}
			else
			{
				Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
			}
		}

		else
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Service $0A was supported but the operator chose not to run\n"
			      "the Permanent Code Drive Cycle test.\n\n" );

			Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
		}
	}
	// Service $0A not supported
	// IF US, warn if SID $0A not supported
	else if ( gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Service $0A was not supported by any ECU, therefore\n"
		      "the Permanent Code Drive Cycle was not tested.\n\n" );

		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}
	// IF not US, just note that SID $0A not supported and Permanent Code Drive Cycle not tested
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Service $0A was not supported by any ECU, therefore\n"
		      "the Permanent Code Drive Cycle was not tested.\n\n" );

		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 9.23 - Clear codes
//*******************************************************************************
	gTestSubsection = 23;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Clear DTCs (Service $04) with Engine Off)" );

	// Clear Codes Engine OFF
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key OFF for 30 seconds or longer, as appropriate for the ECU.\n" );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key ON with engine OFF. Do not crank engine.\n" );

	gbEngineRunning = FALSE;

	if ( DetermineOBDProtocol ( ) != PASS )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Protocol determination unsuccessful.\n" );
		Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Turn key OFF" );
		return FAIL;
	}

	if ( ClearCodes ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyINFChange ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
			      "Turn key OFF" );
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}

	return PASS;
}
