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


// Function Prototypes
extern void DisplayPIDF501 ( BYTE EcuIdx, BOOL bCC );


/******************************************************************************
**
**  Function:  ClearCodes
**
**  Purpose:   Clear OBD diagnostic information
**
*******************************************************************************/
STATUS ClearCodes ( void )
{
	REQ_MSG        stReqMsg;
	BYTE           EcuIdx;
	STATUS         eRetCode;  // saves the return code from function calls

	unsigned short IMReadinessCount;
	unsigned short IMRPosAckCount;
	unsigned short PositiveAckCount;
	unsigned short RetryCount;


	// Reset the global DTC data
	gbDTCPending = FALSE;
	gbDTCStored  = FALSE;

	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "Clear Codes (SID $14) %s Addressed\n",
	      gbPhysicalAddressing ? "Physically" : "Functionally");

	// Send SID 14 request
	stReqMsg.SID     = 0x14;
	stReqMsg.NumIds  = 3;
	stReqMsg.u.ID[0] = 0xFF; // Emissions-system group MSB
	stReqMsg.u.ID[1] = 0xFF; // Emissions-system group
	stReqMsg.u.ID[2] = 0x33; // Emissions-system group LSB
	if ( (gbPhysicalAddressing == FALSE && (eRetCode = RequestSID ( &stReqMsg, REQ_MSG_ALLOW_NO_RESPONSE )) != FAIL ) ||
	     (gbPhysicalAddressing == TRUE  && (eRetCode = RequestSID_PhysicallyAddressed_All ( &stReqMsg, REQ_MSG_ALLOW_NO_RESPONSE )) != FAIL) )
	{
		eRetCode = PASS;  // mark it as PASS, since ERROR can get here too

		IMReadinessCount = 0;
		IMRPosAckCount   = 0;
		PositiveAckCount = 0;
		RetryCount       = 0;

		if ( gNumOfECUsResp == 0 )
		{
			if ( gbEngineRunning == FALSE )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "No response to SID $14 request\n" );
				eRetCode = FAIL;
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "No response to SID $14 request\n" );
			}
		}
		else
		{
			// all ECUs must respond with the same ackowledgement (positive or negative) with engine running
			for ( EcuIdx = 0;
			      EcuIdx < gUserNumOfECUs;
			      EcuIdx++ )
			{
				if ( (gstResponse[EcuIdx].PIDF501.Data[1] & 0x03) != 0x00 ||
				     (gstResponse[EcuIdx].PIDF501.Data[2] & 0x0F) != 0x00 ||
				     (gstResponse[EcuIdx].PIDF501.Data[3] & 0x0F) != 0x00 ||
				     (gstResponse[EcuIdx].PIDF501.Data[4] & 0x0F) != 0x00 ||
				     (gstResponse[EcuIdx].PIDF501.Data[5] & 0x0F) != 0x00 )
				{
					IMReadinessCount++;
				}

				if ( gstResponse[EcuIdx].ClrDTCSize > 0 &&
				     gstResponse[EcuIdx].ClrDTC[0] == 0x54 )
				{
					if ( gbEngineRunning == TRUE  &&
					     ( (gstResponse[EcuIdx].PIDF501.Data[1] & 0x03) != 0x00 ||
					       (gstResponse[EcuIdx].PIDF501.Data[2] & 0x0F) != 0x00 ||
					       (gstResponse[EcuIdx].PIDF501.Data[3] & 0x0F) != 0x00 ||
					       (gstResponse[EcuIdx].PIDF501.Data[4] & 0x0F) != 0x00 ||
					       (gstResponse[EcuIdx].PIDF501.Data[5] & 0x0F) != 0x00 ) )
					{
						IMRPosAckCount++;
					}
					else
					{
						PositiveAckCount++;
					}
					Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Positive response to SID $14 request\n",
					      GetEcuId ( EcuIdx ) );
				}
				else if ( gbPhysicalAddressing == TRUE &&
				          gstResponse[EcuIdx].ClrDTC[0] == 0x14 &&
				          gstResponse[EcuIdx].ClrDTC[1] == 0x31 )
				{
					PositiveAckCount++;
				}

				if ( gbEngineRunning == TRUE  &&
				     (gstResponse[EcuIdx].PIDF501.Data[1] != 0x00 ||
				      gstResponse[EcuIdx].PIDF501.Data[2] != 0x00 ||
				      gstResponse[EcuIdx].PIDF501.Data[3] != 0x00 ||
				      gstResponse[EcuIdx].PIDF501.Data[4] != 0x00 ||
				      gstResponse[EcuIdx].PIDF501.Data[5] != 0x00) )
				{
					DisplayPIDF501 ( EcuIdx, TRUE );
				}
			}

			// IF the number of responding ECUs is greater than the user entered number
			// OR there are no responding ECUs.
			if ( gNumOfECUsResp > gUserNumOfECUs  ||
			     gNumOfECUsResp == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Incorrect number of responses to SID $14 request\n" );
				eRetCode = FAIL;
			}

			// Check that all ECUs with IM Readiness response the same
			// (all positive or all negative) with engine running
			if ( gbEngineRunning == TRUE &&
			     IMReadinessCount != 0 &&
			     ((PositiveAckCount != 0 ||
			       IMRPosAckCount != 0) &&
			     IMReadinessCount != IMRPosAckCount) )
			{
				// China and Europe allow mixed repsonses
				if ( gstUserInput.eComplianceType != CNOBD &&
				     gstUserInput.eComplianceType != EOBD &&
				     gstUserInput.eComplianceType != EOBD_NO_IUMPR &&
				     gstUserInput.eComplianceType != HD_EOBD )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "Received both positive and negative responses from ECUs containing IM Readiness.\n" );
					eRetCode = FAIL;
				}
			}
			else if ( gbEngineRunning == FALSE &&
			          gNumOfECUsResp != (unsigned long)(PositiveAckCount + IMRPosAckCount) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Not all ECU responses positive.\n" );
				eRetCode = FAIL;
			}
		}  // end else ( gNumOfECUsResp != 0 )
	}  // end if ( RequestSID () )

	// Delay after request to allow time for codes to clear
	Sleep ( 2000 );

	return eRetCode;
}
