/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-3
**  FileName: VerifyVehicleState.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 <conio.h>    // MS-DOS console input and output declarations
#include <windows.h>  // Windows API declarations
#include "j2534.h"    // j1699 project j2534 declarations
#include "j1699.h"    // j1699 project general declarations


// Function Prototypes
STATUS      LogRPM    ( unsigned short *pRPM );
void        AbortTest ( void );

extern void LogStats  ( void );
extern void StopTest  ( STATUS ExitCode,
                        TEST_PHASE egeTestPhase );


/*******************************************************************************
**
**  Function:  VerifyVehicleState
**
**  Purpose:   CHeck desired vehicle state against actual vehicle state.
**
*******************************************************************************/
STATUS VerifyVehicleState ( BOOL bEngineRunning,
                            BOOL bHybrid )
{
	STATUS         eRetCode = PASS;

	unsigned short RPM;


	if ( LogRPM ( &RPM ) == PASS )
	{
		Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
		      "VerifyVehicleState - Expected State: %s, RPM: %u, Hybrid: %s\n",
		      (bEngineRunning == TRUE) ? "Running" : "Off",
		      RPM,
		      (bHybrid == TRUE) ? "Yes" : "No" );

		if ( bEngineRunning == FALSE && RPM > 0 )
		{
			// Engine is running, but it should be off
			if ( Log ( USER_ERROR, SCREENOUTPUTON, LOGOUTPUTON, QUIT_CONTINUE_PROMPT,
			           "Engine is running, when it should be off.\n" ) == 'Q' )
			{
				eRetCode = ABORT;
			}
		}
		else if ( bEngineRunning == TRUE && RPM < 300 )
		{
			// Engine is off, but it should be running
			if ( bHybrid == TRUE )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Engine is off, but it should be running.\n" );
			}
			else
			{
				if ( Log ( USER_ERROR, SCREENOUTPUTON, LOGOUTPUTON, QUIT_CONTINUE_PROMPT,
				           "Engine is off, when it should be running.\n" ) == 'Q' )
				{
					eRetCode = ABORT;
				}
			}
		}
	}
	else
	{
		if ( Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, QUIT_CONTINUE_PROMPT,
		           "Cannot determine engine state.\n" ) == 'Q' )
		{
			eRetCode = ABORT;
		}
		else
		{
			eRetCode = FAIL;
		}
	}


	if ( eRetCode == ABORT )
	{
		AbortTest ( );  // this function never returns
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  LogRPM
**
**  Purpose:   Read current vehicle engine speed.
**
*******************************************************************************/
STATUS LogRPM ( unsigned short *pRPM )
{
	REQ_MSG         stReqMsg;
	PID            *pPid;
	BYTE            EcuIdx;
	STATUS          eRetCode = FAIL;

	unsigned short  RPM = 0;


	// request RPM - SID 1 PID $0C
	stReqMsg.SID    = 0x01;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = 0x0C;
	if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "No response to SID $01 PID $0C (RPM) request.\n" );
		eRetCode = FAIL;
	}

	else
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( gstResponse[EcuIdx].PidSize > 0 )
			{
				pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

				if ( pPid->ID == 0x0C )
				{
					RPM = pPid->Data[0];
					RPM = (RPM << 8) | (pPid->Data[1]);

					// convert from 1 cnt = 1/4 RPM to 1 cnt = 1 RPM
					RPM >>= 2;

					Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  PID $0C  RPM = %d\n",
					      GetEcuId ( EcuIdx ),
					      RPM );
					eRetCode = PASS;
				}
			}
		}
	}

	*pRPM = RPM;
	return eRetCode;
}


/*******************************************************************************
**
**  AbortTest
**
*******************************************************************************/
void AbortTest ( void )
{
	// terminate the test
	Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "User Aborted :: terminating application\n\n" );

	gbTestAborted = TRUE;
	LogStats ( );
	StopTest ( ABORT, geTestPhase );

	exit (ABORT);
}
