/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-3
**  FileName: VerifyMILData.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: VerifyMILData
**
**  Purpose:   Verify OBD MIL / DTC status
**
*******************************************************************************/
STATUS VerifyMILData ( void )
{
	REQ_MSG  stReqMsg;
	PID     *pPid;
	BYTE     EcuIdx;
	STATUS   eRetCode = PASS;

	BYTE     NumOfECUsWithDTCs;
	BYTE     NumOfECUsWithMILAndDTCs;


	// Request SID 1 PID 1 data
	stReqMsg.SID    = 0x01;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = 0x01;
	if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) != PASS )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $01 PID $01 request failed\n" );
		eRetCode = FAIL;
	}

	// Record MIL status to log
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( IsIDSupported ( EcuIdx, PIDREQUEST, 0x01 ) == TRUE )
		{
			pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

			// If PID 1 supported, there should be data
			if ( (pPid->Data[0] & 0x80) == 0x80 )
			{
				// if test 9.4, MIL must not be illuminated
				if ( geTestPhase == eTestNoFault3DriveCycle &&
				     gTestSubsection == 4 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  MIL Illuminated\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
				else
				{
					Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  MIL Illuminated\n",
					      GetEcuId ( EcuIdx ) );
				}
			}
			else
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  MIL NOT Illuminated\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  SID $01 PID $01 not supported\n",
			      GetEcuId ( EcuIdx ) );
		}
	}

	// Check if a DTC is supposed to be present
	if ( gbDTCStored == FALSE )
	{
		// Verify MIL/DTC status for every ECU that responded
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			// check for PID 1 support
			if ( IsIDSupported ( EcuIdx, PIDREQUEST, 0x01 ) == TRUE )
			{
				pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

				// PID 1 supported, check for data
				if ( gstResponse[EcuIdx].PidSize == 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Insufficient data returned for SID $01 request\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}

				// if MIL bit is set or DTC_CNT is not 0
				if ( pPid->Data[0] != 0x00 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  MIL/DTC status bit(s) set\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
		}
	}
	else
	{
		// Verify that SID 1 reports a DTC stored
		for ( EcuIdx = 0, NumOfECUsWithDTCs = 0, NumOfECUsWithMILAndDTCs = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			// If PID 1 supported, there should be data
			if ( IsIDSupported ( EcuIdx, PIDREQUEST, 0x01 ) == TRUE &&
			     gstResponse[EcuIdx].PidSize == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Insufficient data returned for SID $01 request\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

			// Count ECUs with at least one DTC
			if ( (pPid->Data[0] & 0x7F) != 0x00 )
			{
				NumOfECUsWithDTCs++;

				// Count ECUs with at least one DTC and MIL is lit
				if ( (pPid->Data[0] & 0x80) != 0x00 )
				{
					NumOfECUsWithMILAndDTCs++;
				}
			}
		}

		// Check if any ECU reported a DTC
		if ( NumOfECUsWithDTCs == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "SID $01 indicates no ECU has DTC stored\n" );
			eRetCode = FAIL;
		}

		if ( gbDTCHistorical == TRUE )
		{
			// If the DTC is historical, make sure MIL is off
			if ( NumOfECUsWithMILAndDTCs > 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "SID $01 indicates MIL light ON after 3 driving cycles with fault repaired\n" );
				eRetCode = FAIL;
			}
		}
		else
		{
			// If the DTC is not historical, make sure MIL is on
			if ( NumOfECUsWithMILAndDTCs == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "SID $01 indicates MIL light OFF before 3 driving cycles with fault repaired\n" );
				eRetCode = FAIL;
			}
		}
	}

	// Test case 5.4.1, verify that at least 1 ECU responded but
	// not more then the total specified by the user.
	if ( gbEngineRunning == FALSE )
	{
		if ( ( gNumOfECUsResp == 0 ) || ( gNumOfECUsResp > gUserNumOfECUs ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Number of SID $01 responses in error (%d responses, 1 to %d expected\n",
			      gNumOfECUsResp,
			      gUserNumOfECUs );
			eRetCode = FAIL;
		}
	}

	return eRetCode;
}
