/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-5
**  FileName: Test9_7to17_PermanentCodes.c
**  Author:   EnGenius
**  Date:     2/25/2022
**  Email:    <support@autosinnovate.org>
**
**  Purpose:  SAE J1699-5 Vehicle OBD II Compliance Test Cases Source Code.
**            This source code is intended to run the tests described in
**            the SAE J1699-5 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:  03/13/2023  Initial Version
**
********************************************************************************
*******************************************************************************/

#include <stdio.h>    // C Library input and output declarations
#include <stdlib.h>   // C Library general function declarations
#include <string.h>   // C Library character array 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
extern STATUS VerifyIPD ( void );
extern STATUS LogINF12 ( void );
extern STATUS RunDynamicTest10 ( unsigned long EngineStartTimestampMsecs );
extern void   DisplayDynamicTest10Results ( void );
extern void   AllocateMemoryForRunDynamicTest10 ( void );
extern void   FreeMemoryForRunDynamicTest10 ( void );


/*******************************************************************************
**
**  Function:  Test9_7to17_PermanentCodes
**
**  Purpose:   Run Tests 9.7-17 to read permanent codes
**
*******************************************************************************/
STATUS Test9_7to17_PermanentCodes ( void )
{
	STATUS        eRetCode;

	unsigned long EngineStartTimestampMsecs;
	BOOL          bSubTestFailed = FALSE;


//*******************************************************************************
//  Test 9.7 - Induce Circuit Fault to Set Pending DTC
//*******************************************************************************
	gTestSubsection = 7;
	gbTestSubsectionFailed = FALSE;

	// Prompt user to induce fault and set pending DTC
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Induce Circuit Fault to Set Pending DTC)" );

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key off and induce a failure that will generate a MIL light.\n"
	      "The selected fault must illuminate the MIL within a maximum of\n"
	      "two (for OBD-II) or three (for EOBD/IOBD/OBDBr) driving cycles.\n\n"
	      
	      "NOTE: You may first start the engine and then induce a failure\n"
	      "in order to avoid starting issues.");

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

	      "Let idle for one 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." );

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition OFF (engine OFF) for 30 seconds or longer, as appropriate\n"
          "for the ECU, and keep failure present.");

	if ( gstUserInput.eComplianceType != US_OBDII &&
	     gstUserInput.eComplianceType != HD_OBD   &&
	     gstUserInput.eComplianceType != CNOBD )
	{
		printf ( "\n\n\n" );
		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Start engine or activate propulsion system for Hybrid/PHEV.\n\n"

		      "Let idle for one minute or whatever time it takes to set\n"
		      "a confirmed DTC. The MIL may or may not illuminate on this driving cycle.\n\n"

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

		printf ( "\n\n\n" );
		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Turn ignition OFF (engine OFF) for 30 seconds or longer, as appropriate\n"
		      "for the ECU, and keep failure present." );
	}

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

	      "Let idle for one minute or whatever time it takes to set\n"
	      "a confirmed DTC and illuminate the MIL.\n\n"

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

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition OFF (engine OFF) for 30 seconds or longer, as appropriate\n"
	      "for the ECU, and keepfailure present.\n"
	      "(This completes the driving cycle and allows permanent code to be set)." );

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition on. DO NOT crank engine." );

	// Engine should now be not running
	gbEngineRunning = FALSE;

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


//*******************************************************************************
//  Test 9.8 - Verify Stored DTCs, Engine Off
//*******************************************************************************
	// A Permanent DTC should now be set
	gbDTCPermanent = TRUE;

	gTestSubsection = 8;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Stored DTCs (SID $19 LEV $42 StatusMask $08), Engine Off)" );

	if ( VerifyConfirmedDTCData ( DTC_STATE_SET_PERM_FAULT ) != 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.9 - Verify stored DTC data, engine off
//*******************************************************************************
	gTestSubsection = 9;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Permanent DTCs (SID $19 LEV $55), Engine Off)" );

	if ( VerifyPermanentDTCData ( DTC_STATE_SET_PERM_FAULT ) != 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.10 - induce fault to be able to retrieve Permanent DTC
//*******************************************************************************
	gTestSubsection = 10;
	gbTestSubsectionFailed = FALSE;

	// Prompt user to induce fault to be able to retrieve Permanent DTC
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Repair Circuit Fault)" );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition OFF (engine OFF) for 30 seconds or longer, as appropriate\n"
	      "for the ECU." );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Connect sensor." );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition on.  DO NOT crank engine." );

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


//*******************************************************************************
//  Test 9.11 - Clear DTCs, engine off
//*******************************************************************************
	gTestSubsection = 11;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Clear DTCs (SID $14), Engine Off)" );

	if ( ClearCodes ( ) != 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.12 - Verify MIL status, engine off
//*******************************************************************************
	gTestSubsection = 12;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify MIL Status, Engine Off)" );

	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.13 - Verify stored DTC data, engine off
//*******************************************************************************
	gTestSubsection = 13;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Permanent DTCs (SID $19 LEV $55), Engine Off)" );

	if ( VerifyPermanentDTCData ( DTC_STATE_REPAIR_PERM_FAULT ) != 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.14 - repair circuit fault and complete one drive cycle
//*******************************************************************************
	gTestSubsection = 14;
	gbTestSubsectionFailed = FALSE;

	// Prompt user to repair circuit fault and complete one drive cycle
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Complete One Driving Cycle With Fault Repaired)" );

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

	      "Let idle for one minute or whatever time it takes\n"
	      "to run monitor and detect that there is no malfunction\n"
	      "(Monitor may have already run with engine off).\n\n"

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

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition OFF (engine OFF) for 30 seconds or longer, as appropriate\n"
	      "for the ECU.\n"
	      "(This completes one driving cycle with no fault)." );

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

	      "REMAIN AT IDLE until directed to start drive cycle" );

	EngineStartTimestampMsecs = GetTickCount ( );

	printf ( "\n\n\n" );
	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Continue to idle until the ECU detects that there is no malfunction.\n"
	      "(This starts the second driving cycle; however, second driving cycle\n"
	      "will not be complete 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." );

	// Engine should now be running
	gbEngineRunning = TRUE;

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


//*******************************************************************************
//  Test 9.15 - Verify stored DTC data, engine off
//*******************************************************************************
	// A Permanent DTC should now be set
	gbDTCPermanent = TRUE;

	gTestSubsection = 15;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Permanent DTCs (SID $19 LEV $55), Engine Running)" );

	if ( VerifyPermanentDTCData ( DTC_STATE_REPAIR_1DC_PERM_FAULT ) != 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.16 - Complete Permanent Code Drive Cycle
//*******************************************************************************
	gTestSubsection = 16;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Complete Permanent Code Drive Cycle)" );

	// Initialize Array
	AllocateMemoryForRunDynamicTest10 ( );

	// Request INF support data
	if ( RequestIDSupportData ( INFREQUEST, TRUE ) != PASS )
	{
		if ( Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT,
		           "Problems verifying PID $F8xx supported data." ) == 'N' )
		{
			FreeMemoryForRunDynamicTest10 ( );
			return FAIL;
		}
	}

	if ( VerifyIPD ( ) != PASS || gbTestSubsectionFailed == TRUE )
	{
		if ( Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT,
		           "Unable to capture Initial OBDCOND and IGNCNT." ) == 'N' )
		{
			Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );

			// free memory for IPT Arrays
			FreeMemoryForRunDynamicTest10 ( );

			return FAIL;
		}

		bSubTestFailed = TRUE;
		gbTestSubsectionFailed = FALSE;
	}

	if ( gbPlugIn )
	{
		if ( LogINF12 (  ) != PASS )
		{
			bSubTestFailed = TRUE;
		}
	}

	// stop tester-present message
	StopPeriodicMsg ( TRUE );
	Sleep ( gRequestDelayTimeMsecs );

	gbSuspendScreenOutput = TRUE;
	eRetCode = RunDynamicTest10 ( EngineStartTimestampMsecs );
	gbSuspendScreenOutput = FALSE;

	DisplayDynamicTest10Results ( );

	// free memory for IPT Arrays
	FreeMemoryForRunDynamicTest10 ( );

	// re-start tester-present message
	StartPeriodicMsg ( );

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

	if ( eRetCode == FAIL || gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Errors detected during dynamic test.  View Logfile for more details.\n" );

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

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Stop the vehicle in a safe location and turn the ignition off." );

	// Engine should now be not running
	gbEngineRunning = FALSE;


//*******************************************************************************
//  Test 9.17 - Start Engine
//*******************************************************************************
	gTestSubsection = 17;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	// Prompt user to induce fault to be able to retrieve Permanent DTC
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Key On)" );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn ignition on and Start engine or activate propulsion system for Hybrid/PHEV." );

	// Engine should now be running
	gbEngineRunning = TRUE;

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

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

	return PASS;
}
