/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-3
**  FileName: VehicleReport.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 <string.h>   // C Library character array declarations
#include <windows.h>  // Windows API declarations
#include "j2534.h"    // j1699 project j2534 declarations
#include "j1699.h"    // j1699 project general declarations


// Function Prototypes
STATUS ReadCALIDs  ( void );
STATUS ReadCVNs    ( void );

extern STATUS ReadVIN     ( void );
extern STATUS PrintCALIDs ( void );
extern STATUS VerifyCALIDData ( BYTE          EcuIdx,
                                unsigned long Inf3NumItems );
extern STATUS PrintCVNs   ( void );
extern STATUS VerifyCVNData ( BYTE          EcuIdx,
                              unsigned long Inf5NumItems );
extern STATUS VerifyPid1C ( PID          *pPid,
                            unsigned long SidIdx,
                            BYTE          EcuIdx );
extern void   LogVersionInformation ( SCREENOUTPUT bDisplay,
                                      LOGOUTPUT    bLog );
extern STATUS AppendLogFile  ( void );


/*******************************************************************************
**
**  Function:  VehicleReport
**
**  Purpose:
**
*******************************************************************************/
STATUS VehicleReport ( void )
{
	REQ_MSG  stReqMsg;
	PID     *pPid;
	BYTE     EcuIdx;


	// Create the log file
	gLogFileHandle = NULL;
	sprintf_s ( gLogFileNameString, MAX_LOGFILENAME, "Vehicle Report.log" );

	// Open the log file
	if ( fopen_s ( &gLogFileHandle, gLogFileNameString, "w+" ) != 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTOFF, NO_PROMPT,
		      "Cannot open log file %s\n",
		      gLogFileNameString );
		StopTest ( FAIL, geTestPhase );
		exit (FAIL);
	}

	// Application version, build date, OS, etc
	LogVersionInformation ( SCREENOUTPUTON, LOGOUTPUTON );

	// Copy temp log file to actual log file
	if ( AppendLogFile ( ) != PASS )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTOFF, NO_PROMPT,
		      "Unable to copy temp log file to %s\n",
		      gLogFileNameString );
		StopTest ( FAIL, geTestPhase );
		exit (FAIL);
	}

	// Echo user responses to the log file
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%d\n",
	      gDisplayStrings[DSPSTR_PRMPT_MODEL_YEAR],
	      gModelYear );

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%d\n",
	      gDisplayStrings[DSPSTR_PRMPT_OBD_ECU],
	      gUserNumOfECUs );

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%d\n",
	      gDisplayStrings[DSPSTR_PRMPT_RPGM_ECU],
	      gUserNumOfECUsReprgm );

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%s\n",
	      gDisplayStrings[DSPSTR_PRMPT_ENG_TYPE],
	      gEngineTypeStrings[gstUserInput.eEngineType] );

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%s\n",
	      gDisplayStrings[DSPSTR_PRMPT_PWRTRN_TYPE],
	      gPwrTrnTypeStrings[gstUserInput.ePwrTrnType] );

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%s\n",
	      gDisplayStrings[DSPSTR_PRMPT_VEH_TYPE],
	      gVehicleTypeStrings[gstUserInput.eVehicleType] );

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "%s%s\n\n",
	      gDisplayStrings[DSPSTR_STMT_COMPLIANCE_TYPE],
	      gComplianceTestTypeStrings[gstUserInput.eComplianceType] );


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


	// Determine Protocol
	gTestSubsection = 1;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Determine Protocol" );
	if ( DetermineOBDProtocol ( ) != PASS )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Protocol determination unsuccessful.\n" );
		return FAIL;
	}
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );


	// get VIN
	gTestSubsection = 2;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read VIN" );
	ReadVIN ( );
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );

	// get CALID
	gTestSubsection = 3;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read CALIDs" );
	PrintCALIDs ( );
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );

	// get CVNs
	gTestSubsection = 4;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read CVNs " );
	PrintCVNs ( );
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );

	// get Pending DTCs
	gTestSubsection = 5;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read Pending DTCs" );
	VerifyPendingDTCData ( );
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );

	// get Stored DTCs
	gTestSubsection = 6;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read Stored DTCs" );
	VerifyStoredDTCData ( );
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );

	// get Permanent DTCs
	gTestSubsection = 7;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read Permanent DTCs" );
	VerifyPermanentCodeSupport ( );
	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n\n" );

	// get SID 1 PID 1C
	gTestSubsection = 8;
	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Vehicle Report: Read SID $01  PID $1C" );
	stReqMsg.SID    = 0x01;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = 0x1C;
	if ( RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE|REQ_MSG_IGNORE_NO_RESPONSE ) == PASS )
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( gstResponse[EcuIdx].PidSize > 0 )
			{
				pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

				if ( pPid->ID == 0x1C )
				{
					Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "SID $01 PID $1C = %d\n",
					      pPid->Data[0] );

					VerifyPid1C ( pPid, 0, EcuIdx );
					break;  // leave ECU for loop
				}
			}
		}
	}


	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key OFF.\n" );


	Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "\n\n**** END OF VECHICLE REPORT ****\n" );


	// End of report, disconnect
	DisconnectOBDProtocol ( );
	gbProtocolDetermined = FALSE;

	// save Vehicle Report.log
	fclose ( gLogFileHandle );

	// reset temp file to beginning
	fseek ( gTempLogFileHandle, 0, SEEK_SET );

	return PASS;
}

/*******************************************************************************
**
**  Function:  ReadCALIDs
**
**  Purpose:   Print CALIDs to the log file
**
*******************************************************************************/
STATUS ReadCALIDs ( void )
{
	BYTE           EcuIdx;
	REQ_MSG        stReqMsg;
	STATUS         RetCode = PASS;

	unsigned long  Inf3NumItems[MAX_ECUS] = {0};


	stReqMsg.SID    = 0x09;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = INF_TYPE_CALID;
	if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "INF $04 (CALID) request\n" );
		return FAIL;
	}

	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( VerifyCALIDData ( EcuIdx, Inf3NumItems[EcuIdx] ) == FAIL )
		{
			RetCode = FAIL;
		}
	}

	return RetCode;
}


/*******************************************************************************
**
**  Function:  ReadCVNs
**
**  Purpose:   print CVNs to the log file
**
*******************************************************************************/
STATUS ReadCVNs ( void )
{
	BYTE           EcuIdx;
	REQ_MSG        stReqMsg;
	STATUS         RetCode = PASS;

	unsigned long  Inf5NumItems[MAX_ECUS] = {0};


	stReqMsg.SID    = 0x09;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = INF_TYPE_CVN;
	if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "INF $06 (CVN) request\n" );
		return FAIL;
	}

	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( VerifyCVNData ( EcuIdx, Inf5NumItems[EcuIdx] ) == FAIL )
		{
			RetCode = FAIL;
		}
	}

	return RetCode;
}


