/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-5
**  FileName: VerifyPermanentDTCData.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 <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


// Variable Prototypes
extern unsigned char DTCTypeCharacter[];

BYTE           gPermDTCSupEcuCnt = 0;
unsigned long  gPermDTCSupEcuIdArray[MAX_ECUS];


/*******************************************************************************
**
**  Function:  VerifyPermanentDTCData
**
**  Purpose:   Verify Permanent DTC support
**
*******************************************************************************/
STATUS VerifyPermanentDTCData ( BYTE State )
{
	REQ_MSG        stReqMsg;
	BYTE           EcuIdx;
	STATUS         eRetCode = PASS;

	unsigned long  NumOfDTCs;
	unsigned long  DataIdx;
	DTCASTR  *pDTC;
	unsigned long  InitialFailureCount = 0;
	BYTE           EcuIdIdx;

	InitialFailureCount = GetFailureCount ( );

	// Count number of ECUs responding to SID $19 $55
	stReqMsg.SID     = 0x19;
	stReqMsg.NumIds  = 2;
	stReqMsg.u.ID[0] = 0x55;  // subfunction (LEV) reportWWHOBDDTCWithPermanentStatus
	stReqMsg.u.ID[1] = 0x33;  // Emissions-system group

	if ( gbPhysicalAddressing == FALSE )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Request Permanent Codes (SID $19 LEV $55 group $33) Functionally Addressed\n" );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Request Permanent Codes (SID $19 LEV $55 group $33) Physically Addressed\n" );
	}

	if ( (gbPhysicalAddressing == FALSE && (eRetCode = RequestSID ( &stReqMsg, REQ_MSG_NORMAL|REQ_MSG_IGNORE_NO_RESPONSE )) == FAIL ) ||
	     (gbPhysicalAddressing == TRUE  && (eRetCode = RequestSID_PhysicallyAddressed_All ( &stReqMsg, REQ_MSG_NORMAL|REQ_MSG_IGNORE_NO_RESPONSE )) == FAIL ))
	{
		// An ECU supports Permanent DTCs
		for ( EcuIdx = 0, EcuIdIdx = 0, gPermDTCSupEcuCnt = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( gstResponse[EcuIdx].bPermDTCSupported )
			{
				gPermDTCSupEcuCnt++;
				gPermDTCSupEcuIdArray[EcuIdIdx++] = GetEcuId ( EcuIdx );
			}
		}

		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $19 LEV $55 request failed\n" );
		eRetCode = FAIL;
	}


	for ( EcuIdx = 0, EcuIdIdx = 0, gPermDTCSupEcuCnt = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( gstResponse[EcuIdx].bPermDTCSupported )
		{
			gPermDTCSupEcuCnt++;
			gPermDTCSupEcuIdArray[EcuIdIdx++] = GetEcuId ( EcuIdx );
		}
	}


	// If a Permanent DTC is not supposed to be present (Test 5.4, 9.5, 9.18)
	if ( State == DTC_STATE_NO_FAULT ||
		 State == DTC_STATE_REPAIR_3DC_FAULT ||
		 State == DTC_STATE_ERASE_PERM_FAULT )
	{
		// Verify that no Permanent DTCs reported
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			// check the Permanent DTCs count
			if ( gstResponse[EcuIdx].PermDTC[0] != 0x00 ||
			     gstResponse[EcuIdx].PermDTC[1] != 0x00 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  SID $19 LEV $55 indicates Permanent DTC\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
			else
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  SID $19 LEV $55 indicates no Permanent DTC\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}

	// If a Permanent DTC is supposed to be present (Test 8.5, 9.9, 9.13, 9.15)
	else
	{
		// Verify that Permanent DTCs are reported
		NumOfDTCs = 0;
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			// Print out all the DTCs
			for ( DataIdx = 0;
			      DataIdx < gstResponse[EcuIdx].PermDTCSize;
			      DataIdx += 4 )
			{
				pDTC = (DTCASTR *) &gstResponse[EcuIdx].PermDTC[DataIdx];
				if ( pDTC->Dtc.HighByte != 0 ||
				     pDTC->Dtc.MidByte  != 0 ||
				     pDTC->Dtc.LowByte  != 0 )
				{
					Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Permanent DTC $%c%02X%02X (Failure Type = $%02X  Status = $%02X) detected\n",
					      GetEcuId ( EcuIdx ),
					       DTCTypeCharacter[(pDTC->Dtc.HighByte & 0xC0) >> 6],  // 1st character (P, C, B, U)
					       pDTC->Dtc.HighByte & 0x3F,                           // 2nd (0,1,2,3) and 3rd (0-F) characters
					       pDTC->Dtc.MidByte,                                   // 4th and 5th characters (0-F)
					       pDTC->Dtc.LowByte,                                   // Failure Type Byte
					       pDTC->Status );                                      // Status of DTC

					NumOfDTCs++;
				}
			}
		}

		// If no stored DTCs found, then fail
		if ( NumOfDTCs == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "No ECU indicates Permanent DTC\n" );
			eRetCode = FAIL;
		}
	}

//	for ( EcuIdx = 0;
//	      EcuIdx < gNumOfECUs;
//	      EcuIdx++ )
//	{
//		if ( (gstResponse[EcuIdx].bConfDTCSupported == TRUE ||
//		      gstResponse[EcuIdx].bPendDTCSupported == TRUE) &&
//		     gstResponse[EcuIdx].bPermDTCSupported == FALSE )
//		{
//			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
//			      "ECU %X  Supports SID $19 LEV 42 Status Mask $04 and $08 but not SID $19 LEV $55
//			      GetEcuId ( EcuIdx ) );
//			eRetCode = FAIL;;
//		}
//	}

	if ( InitialFailureCount != GetFailureCount ( ) )
	{
		// There could have been early/late responses that weren't treated as FAIL
		eRetCode = FAIL;
	}

	return eRetCode;
}
