/*******************************************************************************
********************************************************************************
**  SAE J1699-5 Vehicle OBD II Compliance Test Cases Source Code
**
**   Copyright (C) 2022
**
**  ****************************************************************************
**
**  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.
**
********************************************************************************
*******************************************************************************/

#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, Stop/Start: %s\n",
		      (bEngineRunning == TRUE) ? "Running" : "Off",
		      RPM,
		      (bHybrid == TRUE) ? "Yes" : "No",
		      (gstUserInput.ePwrTrnType == SS) ? "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." ) == '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 ( gstUserInput.ePwrTrnType == SS )
			{
				char UserResponse[4];
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Engine is off, but it should be running.\n" );
				Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, CUSTOM_PROMPT,
				      "Is vehicle in Auto Stop?\n(Enter Yes or Quit)" );
				fgets ( UserResponse, sizeof ( UserResponse ), stdin );
				if ( UserResponse[0] == 'Q' )
				{
					eRetCode = ABORT;
				}
			}
			else
			{
				if ( Log ( USER_ERROR, SCREENOUTPUTON, LOGOUTPUTON, QUIT_CONTINUE_PROMPT,
				           "Engine is off, when it should be running." ) == 'Q' )
				{
					eRetCode = ABORT;
				}
			}
		}
	}
	else
	{
		if ( Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, QUIT_CONTINUE_PROMPT,
		           "Cannot determine engine state." ) == '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 - PID $F40C
	stReqMsg.SID      = 0x22;
	stReqMsg.NumIds   = 1;
	stReqMsg.u.DID[0] = 0xF40C;
	if ( RequestSID ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "No response to PID $F40C (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->PIDLSB == 0x0C )
				{
					RPM = (pPid->Data[0] << 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 $F40C  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 );
}
