/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-3
**  FileName: TestWithPendingDtc.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 <conio.h>    // MS-DOS console input and output declarations
#include <windows.h>  // Windows API declarations
#include "j2534.h"    // j1699 project j2534 declarations
#include "j1699.h"    // j1699 project general declarations


// Funcrion Prototypes
void   SaveDTCList ( unsigned int SID );


/*******************************************************************************
**
**  Function:  Test6_PendingDtc
**
**  Purpose:   Run test 6 with a pending code induced by a fault
**
*******************************************************************************/
STATUS Test6_PendingDtc ( void )
{
	BOOL  bSubTestFailed = FALSE;
	BOOL  bLoopDone      = FALSE;


//*******************************************************************************
//  Test 6.1 - Induce Fault
//*******************************************************************************
	gTestSubsection = 1;
	gbTestSubsectionFailed = FALSE;

	// Prompt user to induce fault and start engine
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Induce Fault)" );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key off and disconnect a sensor (e.g. ECT, TP, IAT, MAF, etc.)\n"
	      "that will generate a MIL light with the engine idling for one ECU.\n"
	      "The selected fault must illuminate the MIL using %s driving cycles\n"
	      "(not one like GM Type A) to allow for proper testing of Mode 7 and\n"
	      "freeze frame.\n"
	      "NOTE: You may first start the engine and then disconnect a sensor, in order to avoid starting issues.\n",
	      gstUserInput.NumDCToSetMIL == 2 ? "two" : "three" );

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

	      "Let idle.\n\n"

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

	gbEngineRunning = TRUE;

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


//*******************************************************************************
//  Test 6.2 - Determine the OBD protocol to use, Engine Running
//*******************************************************************************
	// Determine the OBD protocol to use
	gTestSubsection = 2;
	gbTestSubsectionFailed = 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 6.3 - Verify Pending DTCs, Engine Running
//*******************************************************************************
	gTestSubsection = 3;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

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

	// flush the STDIN stream of any user input before loop
	ClearKeyboardBuffer ( );

	// Wait for pending DTC
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTOFF, NO_PROMPT,
	      "Waiting for pending DTC...(press any key to stop test)\n" );
	while ( !_kbhit ( ) )
	{
		if ( IsDTCPending ( (REQ_MSG_NORMAL|REQ_MSG_ALLOW_NO_RESPONSE) ) == PASS )
		{
			bLoopDone = TRUE;
			break;  // leave while (not keyboard hit) loop
		}
		Sleep ( 500 );
	}

	if ( bLoopDone == FALSE )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "User abort\n" );
	}

	printf ( "\007\n" );  // Beep

	// Flush the STDIN stream of any user input above
	ClearKeyboardBuffer ( );

	// Set flag to indicate a pending DTC should be present
	gbDTCPending = TRUE;

	// Verify there is a pending DTC
	if ( IsDTCPending ( (REQ_MSG_NORMAL|REQ_MSG_ALLOW_NO_RESPONSE) ) != FAIL )
	{
		// Get DTC list from SID $07
		SaveDTCList ( 7 );

		// Check if a DTC is stored as well (i.e. GM Type A)
		if ( IsDTCStored ( (REQ_MSG_NORMAL|REQ_MSG_ALLOW_NO_RESPONSE) ) == PASS )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Type A DTC detected, pending without a stored code functionality not tested\n" );
			gbDTCStored = TRUE;
		}
	}
	else
	{
		bSubTestFailed = TRUE;
	}

	// Verify pending DTC data
	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 6.4 - Verify stored DTC data
//*******************************************************************************
	// Verify stored DTC data
	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 6.5 - Verify freeze frame support and data
//*******************************************************************************
	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 6.6 - Continue to Induce Circuit Fault (EOBD/IOBD/OBDBr only)
//*******************************************************************************
	if ( gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
	     gstUserInput.eComplianceType == EOBD_NO_IUMPR ||
	     gstUserInput.eComplianceType == HD_EOBD ||
	     gstUserInput.eComplianceType == IOBD_NO_IUMPR ||
	     gstUserInput.eComplianceType == HD_IOBD_NO_IUMPR ||
	     gstUserInput.eComplianceType == OBDBr_NO_IUMPR )
	{
		gTestSubsection = 6;
		gbTestSubsectionFailed = FALSE;
		bSubTestFailed = FALSE;

		Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "(Continue to induce fault - EOBD/IOBD/OBDBr only)" );

		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Turn key OFF for 30 seconds or longer, as appropriate for the ECU,\n"
		      "and keep sensor disconnected.\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 to set a pending DTC.\n\n"

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

		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, "" );
		}
	}

	return PASS;
}