/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-5
**  FileName: VerifyINFSupportAndData.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 declarations
#include <string.h>   // C Library character array declarations
#include <time.h>     // C Library time and date declarations
#include <math.h>     // C Library math declarations
#include <windows.h>  // Windows API declarations
#include "j2534.h"    // j1699 project j2534 declarations
#include "j1699.h"    // j1699 project general declarations


#define  MAX_NAME_LENGTH  10


/* Function Prototypes */
extern void SaveIPD    ( BYTE EcuIdx );
extern void LogIPD     ( BYTE EcuIdx );

STATUS VerifyVINData   ( BYTE EcuIdx );
STATUS VerifyCALIDData ( BYTE EcuIdx );
STATUS VerifyCVNData   ( BYTE EcuIdx );
STATUS VerifyECUNameData ( BYTE EcuIdx );
STATUS VerifyINF08Data ( BYTE  EcuIdx );
STATUS VerifyINF0BData ( BYTE  EcuIdx );
STATUS VerifyINF0D_0FData ( BYTE  EcuIdx );
STATUS VerifyINF10Data ( BYTE EcuIdx );
STATUS VerifyINF11Data ( BYTE EcuIdx);
STATUS VerifyINF12Data ( BYTE EcuIdx );
STATUS VerifyINF13Data ( BYTE EcuIdx );
STATUS VerifyINF14Data ( BYTE EcuIdx );
STATUS VerifyINF16Data ( BYTE EcuIdx );
STATUS VerifyINF17Data ( BYTE EcuIdx );
STATUS VerifyINF18Data ( BYTE EcuIdx );
STATUS VerifyINF19Data ( BYTE EcuIdx );
STATUS VerifyINF1AData ( BYTE EcuIdx );
STATUS VerifyINF1BData ( BYTE EcuIdx );
STATUS VerifyINF1CData ( BYTE EcuIdx );
STATUS VerifyINF1DData ( BYTE EcuIdx );
STATUS VerifyINF1EData ( BYTE EcuIdx );
STATUS VerifyINF1FData ( BYTE EcuIdx );
STATUS VerifyINF21Data ( BYTE EcuIdx );
STATUS VerifyINF22Data ( BYTE EcuIdx );
STATUS VerifyINF23Data ( BYTE EcuIdx );
STATUS VerifyINF24Data ( BYTE EcuIdx );
STATUS VerifyINF25_29Data ( BYTE EcuIdx );
STATUS VerifyINF2AData ( BYTE EcuIdx );
STATUS VerifyINF41_43_45Data ( BYTE EcuIdx );
STATUS VerifyINF42_44_46Data ( BYTE EcuIdx );
STATUS VerifyINF47Data ( BYTE EcuIdx );
STATUS VerifyINF48Data ( BYTE EcuIdx );
STATUS VerifyINF49Data ( BYTE EcuIdx );
STATUS VerifyINF50Data ( BYTE EcuIdx );
STATUS VerifyINF51Data ( BYTE EcuIdx );
STATUS VerifyINF52Data ( BYTE EcuIdx );
STATUS VerifyINF53Data ( BYTE EcuIdx );
STATUS VerifyINF54_5BData ( BYTE EcuIdx );
STATUS VerifyINF61_62_67_68_6D_6EData ( BYTE EcuIdx );
STATUS VerifyINF63_69_6F_73Data ( BYTE EcuIdx );
STATUS VerifyINF64_6A_70_74Data ( BYTE EcuIdx );
STATUS VerifyINF65_6B_71_75Data ( BYTE EcuIdx );
STATUS VerifyINF66_6C_72_76Data ( BYTE EcuIdx );
STATUS VerifyINF77Data ( BYTE EcuIdx );
STATUS VerifyINF78Data ( BYTE EcuIdx );
STATUS VerifyINF79Data ( BYTE EcuIdx );
STATUS VerifyINF82Data ( BYTE EcuIdx );
STATUS VerifyINF83Data ( BYTE EcuIdx );
STATUS VerifyINF84Data ( BYTE EcuIdx );
STATUS VerifyINF85_8D__96_97Data ( BYTE EcuIdx );
STATUS VerifyINF8E_90Data ( BYTE EcuIdx );
STATUS VerifyINF91_93Data ( BYTE EcuIdx );
STATUS VerifyINF94Data ( BYTE EcuIdx );
STATUS VerifyINF95Data ( BYTE EcuIdx );
STATUS VerifyINF98_99Data ( BYTE EcuIdx );
STATUS VerifyINF9AData ( BYTE EcuIdx );
STATUS VerifyINF9BData ( BYTE EcuIdx );
STATUS VerifyINF9C_A1Data ( BYTE EcuIdx );
STATUS VerifyINFA2Data ( BYTE EcuIdx );
STATUS VerifyINFA3Data ( BYTE EcuIdx );
STATUS VerifyINFA4Data ( BYTE EcuIdx );
STATUS VerifyINFA5Data ( BYTE EcuIdx );
STATUS VerifyINFA6Data ( BYTE EcuIdx );
STATUS VerifyINFA7Data ( BYTE EcuIdx );
STATUS VerifyINFA8Data ( BYTE EcuIdx );
STATUS VerifyINFA9_AEData ( BYTE EcuIdx );
STATUS VerifyINFAF_B3Data ( BYTE EcuIdx );
STATUS VerifyINFB4Data ( BYTE EcuIdx );


extern const char szINF8[][10];
extern const char szINFB[][10];

typedef struct
{
	unsigned long INF16_IGNCNTR_R;
	unsigned long INF16_IGNCNTR_L;

	unsigned long INF16_FEOCNTR_R;
	unsigned long INF16_FEOCNTR_L;

	unsigned long INF16_ERT_R;
	unsigned long INF16_ERT_L;

	unsigned long INF16_IERT_L;

	double         INF17_DT_R;
	double         INF17_DT_L;

	double         INF17_FC_R;
	double         INF17_FC_L;

	double         INF18_EOE_R;
	double         INF18_EOE_L;

	unsigned long INF19_PSA_R;
	unsigned long INF19_PSA_L;

	unsigned long INF19_IPSA_L;

	unsigned long INF19_CPSA_R;
	unsigned long INF19_CPSA_L;

	unsigned long INF41_ERT_A;
	double        INF41_DT_A;
	double        INF41_EOE_A;
	double        INF41_VFC_A;

	double        INF42_EFC_A;
	unsigned long INF42_IERT_A;
	double        INF42_IEFC_A;
	unsigned long INF42_UERT_A;
	unsigned long INF42_PKE_A;
	unsigned long INF42_PTOERT_A;
	double        INF42_PTOFC_A;

	double        INF43_DT_S;
	double        INF43_EOE_S;
	double        INF43_VFC_S;

	double        INF44_EFC_S;

	unsigned long INF47_PSA_A;
	unsigned long INF47_PSA_S;
	unsigned long INF47_PSA_L;
	unsigned long INF47_IPSA_A;
	unsigned long INF47_IPSA_S;
	unsigned long INF47_IPSA_L;
	unsigned long INF47_UPSA_A;
	unsigned long INF47_UPSA_S;
	unsigned long INF47_UPSA_L;

	double        INF61_NOxEOB_A[17];

	double        INF62_NOxTPB_A[17];

	double        INF63_EOEB_A[17];

	double        INF64_DTB_A[17];

	unsigned long INF65_ERTB_A[17];

	double        INF66_FCB_A[17];
} INFCOMP;
INFCOMP  Test_5_16_INF[MAX_ECUS];


const char szINF8[][10]  = { "OBDCOND",
                             "IGNCNTR",
                             "CATCOMP1",
                             "CATCOND1",
                             "CATCOMP2",
                             "CATCOND2",
                             "O2SCOMP1",
                             "O2SCOND1",
                             "O2SCOMP2",
                             "O2SCOND2",
                             "EGRCOMP",
                             "EGRCOND",
                             "AIRCOMP",
                             "AIRCOND",
                             "EVAPCOMP",
                             "EVAPCOND",
                             "SO2SCOMP1",
                             "SO2SCOND1",
                             "SO2SCOMP2",
                             "SO2SCOND2",
                             "AFRICOMP1",
                             "AFRICOND1",
                             "AFRICOMP2",
                             "AFRICOND2",
                             "PFCOMP1",
                             "PFCOND1",
                             "PFCOMP2",
                             "PFCOND2" };

const char szINFB[][10]  = { "OBDCOND",
                             "IGNCNTR",
                             "HCCATCOMP",
                             "HCCATCOND",
                             "NCATCOMP",
                             "NCATCOND",
                             "NADSCOMP",
                             "NADSCOND",
                             "PMCOMP",
                             "PMCOND",
                             "EGSCOMP",
                             "EGSCOND",
                             "EGRCOMP",
                             "EGRCOND",
                             "BPCOMP",
                             "BPCOND",
                             "FUELCOMP",
                             "FUELCOND" };


/*******************************************************************************
**
**  Function:  VerifyINFSupportAndData
**
**  Purpose:   Verify INF vehicle info support and data
**
*******************************************************************************/
STATUS VerifyINFSupportAndData ( void )
{
	REQ_MSG        stReqMsg;
	INF           *pINF;
	STATUS         eRetCode;

	BYTE           EcuIdx;      // ECU Index
	BYTE           EcuLoopIdx;  // nested ECU Index
	unsigned short IdIdx;       // INF ID index

	unsigned long  INF2NumResponses = 0;      // number of INF $02 responses
	BOOL           bINF4Responded[MAX_ECUS];  // per ECU INF $4 response indicator
	BYTE           INF6NumResponses = 0;      // number of INF $06 responses
	BOOL           bINFAResponded[MAX_ECUS];  // per ECU INF $A response indicator
	BYTE           INFDNumResponses = 0;      // number of INF $0D responses
	BYTE           INF13NumResponses = 0;     // number of INF $13 responses

	#define  MAX_INF_ID 0xAE
	unsigned short  INFSupportCountList[] =
	{ 0xF802, 0xF804, 0xF806, 0xF80A, 0xF80D, 0xF810, 0xF812, 0xF813, 0xF814,
	  0xF816, 0xF817, 0xF818, 0xF819, 0xF81A, 0xF81B, 0xF81C, 0xF81D, 0xF81E, 0xF81F,
	  0xF821, 0xF822, 0xF823, 0xF824, 0xF825, 0xF826, 0xF827, 0xF828, 0xF829, 0xF82A,
	  // F82B-F83F SAE Reserved
	  0xF841, 0xF842, 0xF843, 0xF844, 0xF845, 0xF846, 0xF847, 0xF848, 0xF849, 0xF850,
	  0xF851, 0xF852, 0xF853, 0xF854, 0xF855, 0xF856, 0xF857, 0xF858, 0xF859, 0xF85A,
	  0xF85B,
	  // F85C-F85F SAE Reserved
	  0xF861, 0xF862, 0xF863, 0xF864, 0xF865, 0xF866, 0xF867, 0xF868, 0xF869, 0xF86A,
	  0xF86B, 0xF86C, 0xF86D, 0xF86E, 0xF86F, 0xF870, 0xF871, 0xF872, 0xF873, 0xF874,
	  0xF875, 0xF876, 0xF877, 0xF878, 0xF879,
	  0xF882, 0xF883, 0xF884, 0xF885, 0xF886, 0xF887, 0xF888, 0xF889, 0xF88A, 0xF88B,
	  0xF88C, 0xF88D, 0xF88E, 0xF88F, 0xF890,
	  0xF896, 0xF897, 0xF898, 0xF899, 0xF89A, 0xF89B, 0xF89C, 0xF89D, 0xF89E, 0xF89F,
	  0xF8A1,         0xF8A8, 0xF8A9, 0xF8AA, 0xF8AB, 0xF8AC, 0xF8AD, 0xF8AE
	};
	BYTE  INFSupportCount[MAX_INF_ID + 1];

	BOOL  bINF2Supported[MAX_ECUS];   // per ECU support INF $2 indicator
	BOOL  bINF13Supported[MAX_ECUS];  // per ECU support INF $13 indicator
	BOOL  bF501Support = FALSE;

	BOOL  bTestFailed = FALSE;

	unsigned long InitialFailureCount = 0;


	InitialFailureCount = GetFailureCount ( );

	memset ( &INFSupportCount[0],
	         0,
	         sizeof ( INFSupportCount ) );

	// Request INF support data
	if ( RequestIDSupportData ( INFREQUEST, TRUE ) != PASS )
	{
		if ( Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT,
		           "Problems verifying PID $F8xx supported data." ) == 'N' )
		{
			return FAIL;
		}
	}


	if ( gbPhysicalAddressing == FALSE )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Request PID (SID $22 DID $F8xx) Functionally Addressed\n" );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Request PID (SID $22 DID $F8xx) Physically Addressed\n" );
	}


	// only do required support check for functional addressing
	if ( gbPhysicalAddressing == FALSE )
	{
		// Determine number of ECUs supporting required INFs
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( bF501Support == FALSE &&
			     ((gstResponse[EcuIdx].PIDF501.Data[2] & 0x08) == 0x08 ||  // SCR Monitor supported
			      (gstResponse[EcuIdx].PIDF501.Data[3] & 0x08) == 0x08) )  // PM Monitor suppported
			{
				bF501Support = TRUE;
			}

			// initialize the array values for this EcuIdx before use
			bINF4Responded[EcuIdx] = FALSE;
			bINFAResponded[EcuIdx] = FALSE;
			bINF2Supported[EcuIdx] = FALSE;
			bINF13Supported[EcuIdx] = FALSE;


			for ( IdIdx = 0;
			      IdIdx < (sizeof ( INFSupportCountList )/2);
			      IdIdx++ )
			{
				if ( IsIDSupported ( EcuIdx, INFREQUEST, INFSupportCountList[IdIdx] ) == TRUE )
				{
					INFSupportCount[INFSupportCountList[IdIdx]-0xF800]++;

					// VIN
					if ( INFSupportCountList[IdIdx] == 0xF802 )
					{
						bINF2Supported[EcuIdx] = TRUE;
					}

					// EG/EFN
					else if ( INFSupportCountList[IdIdx] == 0xF813 )
					{
						bINF13Supported[EcuIdx] = TRUE;
					}

					// if deprecated or reserved INF is supported, this is a failure
					else if ( INFSupportCountList[IdIdx] == 0xF801 ||
					          INFSupportCountList[IdIdx] == 0xF803 ||
					          INFSupportCountList[IdIdx] == 0xF805 ||
					          INFSupportCountList[IdIdx] == 0xF807 ||
					          INFSupportCountList[IdIdx] == 0xF809 ||
					          INFSupportCountList[IdIdx] == 0xF80C ||
					          INFSupportCountList[IdIdx] == 0xF80E ||
					          INFSupportCountList[IdIdx] == 0xF815 ||
					          INFSupportCountList[IdIdx] == 0xF84A ||
					          INFSupportCountList[IdIdx] == 0xF84B ||
					          INFSupportCountList[IdIdx] == 0xF84C ||
					          INFSupportCountList[IdIdx] == 0xF84D ||
					          INFSupportCountList[IdIdx] == 0xF84E ||
					          INFSupportCountList[IdIdx] == 0xF84F )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  Supports INF $%04X (Must not be supported)\n",
						      GetEcuId ( EcuIdx ),
						      INFSupportCountList[IdIdx] );
						bTestFailed = TRUE;
					}
				} // end if INF supported

				// if INF not supported
				else
				{
					// ECUNAME
					if ( INFSupportCountList[IdIdx] == 0xF80A )
					{
						if ( gstUserInput.eComplianceType == US_OBDII ||
						     gstUserInput.eComplianceType == HD_OBD )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $F80A (ECUNAME)  not supported! (Required for all ECUs)\n",
							      GetEcuId ( EcuIdx ) );
							bTestFailed = TRUE;
						}
					}
					// PROT_ID
					else if ( INFSupportCountList[IdIdx] == 0xF810 )
					{
						if ( gstUserInput.eComplianceType == US_OBDII ||
						     gstUserInput.eComplianceType == HD_OBD )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $F810 (PROT_ID)  not supported! (Required for all ECUs)\n",
							      GetEcuId ( EcuIdx ) );
							bTestFailed = TRUE;
						}
					}
				} // end if INF notsupported
			} // end for ( IdIdx
		} // end for ( EcuIdx


		//Check support of required INFs
		// Verify that one and only one ECU supports INF $02 (VIN) for US OBD II and HD EOBD
		if ( INFSupportCount[0x02] == 0 )
		{
			if ( gstUserInput.eComplianceType == US_OBDII ||
			     gstUserInput.eComplianceType == HD_OBD   ||
			     gstUserInput.eComplianceType == HD_EOBD )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F802 (VIN) not supported by any ECUs\n" );
				bTestFailed = TRUE;
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F802 (VIN) not supported by any ECUs\n" );
			}
		}
		else if ( INFSupportCount[0x02] > 1 )
		{
			for ( EcuIdx = 0;
			      EcuIdx < gNumOfECUs;
			      EcuIdx++ )
			{
				if ( bINF2Supported[EcuIdx] == TRUE )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F802 (VIN) supported by multiple ECUs\n",
					      GetEcuId ( EcuIdx ) );
				}
			}
			bTestFailed = TRUE;
		}

		// Verify that INF $04 (CALID) is supported by the expected number of ECUs (from user prompt)
		if ( INFSupportCount[0x04] != gUserNumOfECUs )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F804 (CALID) not supported by expected number of ECUs ( %d support, %d expected)!\n",
			      INFSupportCount[0x04],
			      gUserNumOfECUs );
			bTestFailed = TRUE;
		}

		// Verify that INF $06 (CVN) is supported by at least the number of reprogrammable ECUs (from user prompt)
		if ( INFSupportCount[0x06] < gUserNumOfECUs &&
		     ( gstUserInput.eComplianceType == US_OBDII ||
		       gstUserInput.eComplianceType == HD_OBD   ||
		       gstUserInput.eComplianceType == CNOBD) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F806 (CVN) supported by less than the expected number of ECUs ( %d support, %d expected)!\n",
			      INFSupportCount[0x06],
			      gUserNumOfECUs );
			bTestFailed = TRUE;
		}


		// Verify that INF $0A is supported by all ECUs
		if ( INFSupportCount[0x0A] != gUserNumOfECUs &&
		     (gstUserInput.eComplianceType == US_OBDII ||
		      gstUserInput.eComplianceType == HD_OBD   ||
		      gstUserInput.eComplianceType == CNOBD) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F80A (ECU_NAME) is not supported by all ECUs! (Required for all vehicles)\n" );
			bTestFailed = TRUE;
		}

		// Verify that INF $0D is supported for Heavy Duty vehicles
		if ( (INFSupportCount[0x0D] == 0 || INFSupportCount[0x0D] > 1) &&
		     gstUserInput.eComplianceType == HD_OBD )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F80D (ESN) is not supported by one and only one ECU! (Required for Heavy Duty vehicles)\n" );
			bTestFailed = TRUE;
		}

		// Verify that INF $10 is supported for every ECU
		if ( INFSupportCount[0x10] != gUserNumOfECUs )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F810 (PROT_ID) is not supported by all ECU! (Required for all vehicles)\n" );
			bTestFailed = TRUE;
		}

		// Verify that INF $12 is supported for PHEV OBDII vehicles
		if ( INFSupportCount[0x12] == 0 &&
		     gstUserInput.ePwrTrnType == PHEV &&
		     (gstUserInput.eComplianceType == US_OBDII ||
		      gstUserInput.eComplianceType == CNOBD) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F812 (FEOCNTR) is not supported by any ECU! (Required for PHEV vehicles)\n" );
			bTestFailed = TRUE;
		}

		// Verify that INF $14 is supported for gasoline OBDII vehicles
		if ( INFSupportCount[0x14] == 0 &&
		     gstUserInput.eFuelType == GASOLINE &&
		     gstUserInput.eComplianceType == US_OBDII )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F814 (EVAP_DIST) is not supported by any ECU! (Required for vehicles that meet the LEV III / Tier 3 EVAP requirements)\n" );
		}


		// Verify that Light  and Medium Duty OBDII vehicles support required INFs
		if ( (gstUserInput.eVehicleType == LD || 
		      gstUserInput.eVehicleType == MD) &&
		     gstUserInput.eComplianceType == US_OBDII )
		{
			// Verify that INF $13 is supported
			if ( INFSupportCount[0x13] == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F813 (TG/EFN) is not supported by any ECU! (Required for Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
			else if ( INFSupportCount[0x13] > 1  )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F813 (TG/EFN) supported by more than one ECU!\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $16 is supported
			if ( INFSupportCount[0x16] == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F816 (ERT/IERT) is not supported by any ECU! (Required for Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $17 is supported
			if ( INFSupportCount[0x17] == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F817 (DT/FC) is not supported by any ECU! (Required for Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $18 is supported
			if ( INFSupportCount[0x18] == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F818 (PKE/EOE) is not supported by any ECU! (Required for Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $19 is supported
			if ( INFSupportCount[0x19] == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F819 (PSA) is not supported by any ECU! (Required for Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $1A is supported for PHEV
			if ( INFSupportCount[0x1A] == 0 &&
			     gstUserInput.ePwrTrnType == PHEV )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F81A (PHEVDD) is not supported by any ECU! (Required for Light Duty PHEV vehicles)\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $1B is supported
			if ( INFSupportCount[0x1B] == 0 &&
			     gstUserInput.ePwrTrnType == PHEV )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F81B (CDFC/CIFC) is not supported by any ECU! (Required for Light Duty PHEV vehicles)\n" );
				bTestFailed = TRUE;
			}

			// Verify that INF $1C is supported for PHEV
			if ( INFSupportCount[0x1C] == 0 &&
			     gstUserInput.ePwrTrnType == PHEV )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F81C (CDEOGE/CDERGE/GE) is not supported by any ECU! (Required for Light Duty PHEV vehicles)\n" );
				bTestFailed = TRUE;
			}
		}


		// Verify that INFs $F841-F85B are supported for MY 2022 and later Heavy Duty vehicles
		for ( IdIdx = 0x41;
		      IdIdx <= 0x5B;
		      IdIdx++ )
		{
			// INFs $4A thru $4F should not be supported by any vehicle
			if ( IdIdx >= 0x4A && IdIdx <= 0x4F )
			{
				if ( INFSupportCount[IdIdx] != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is supported by an ECU! (Reserved infotype)\n",
					      IdIdx );
					bTestFailed = TRUE;
				}
			}

			// Should only be supported by Heavy Duty vehicles
			else if ( gstUserInput.eVehicleType != HD &&
			          gstUserInput.eComplianceType == US_OBDII &&
			          INFSupportCount[IdIdx] != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F8%02X is supported by an ECU! (Should only be supported by Heavy Duty vehicles)\n",
				      IdIdx );
				bTestFailed = TRUE;
			}

			// MY 2024 and later Heavy Duty US vehicles should support
			else if ( gstUserInput.eVehicleType == HD &&
			          gstUserInput.eComplianceType == HD_OBD &&
			          gModelYear >= 2022 &&
			          INFSupportCount[IdIdx] == 0 )
			{
				// INFs $47, $48, $49, $50 should be supported by PHEV
				if ( IdIdx == 0x47 ||
				     IdIdx == 0x48 ||
				     IdIdx == 0x49 ||
				     IdIdx == 0x50 )
				{
					if ( gstUserInput.ePwrTrnType == PHEV )
					{
						if ( gModelYear == 2022 || gModelYear == 2023 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $F8%02X is not supported by any ECU! (May be supported from MY 2022, but required for MY 2024 and later Heavy Duty PHEV vehicles)\n",
							      IdIdx );
						}
						else
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $F8%02X is not supported by any ECU! (Required for MY 2024 and later Heavy Duty PHEV vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}
				}

				// INF $51 should be supported by S/S
				else if ( IdIdx == 0x51 )
				{
					if ( gstUserInput.ePwrTrnType == SS )
					{
						if ( gModelYear == 2022 || gModelYear == 2023 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $F8%02X is not supported by any ECU! ((May be supported from MY 2022, but required for MY 2024 and later Heavy Duty S/S vehicles)\n",
							      IdIdx );
						}
						else
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $F8%02X is not supported by any ECU! (Required for MY 2024 and later Heavy Duty S/S vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}
				}
				// INFs $52-$5B, warn for non-support
				else if ( IdIdx >= 0x52 && IdIdx <= 0x5B )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! ((May be supported from MY 2022, but required for MY 2024 and later Heavy Duty vehicles)\n",
					      IdIdx );
				}

				else if ( gbHybrid == FALSE )
				{
					if ( gModelYear == 2022 || gModelYear == 2023 )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $F8%02X is not supported by any ECU! ((May be supported from MY 2022, but required for MY 2024 and later Heavy Duty vehicles)\n",
						      IdIdx );
					}
					else
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $F8%02X is not supported by any ECU! (Required for MY 2024 and later Heavy Duty vehicles)\n",
						      IdIdx );
						bTestFailed = TRUE;
					}
				}
			}
		}


		// Verify that INFs $61-76 are supported for MY 2022 and later Heavy and Medium Duty Diesel vehicles
		for ( IdIdx = 0x61;
		      IdIdx <= 0x76;
		      IdIdx++ )
		{
			if ( gbHybrid == FALSE &&
			     gstUserInput.eFuelType == DIESEL &&
			     (((gstUserInput.eVehicleType == MD ||
			        gstUserInput.eVehicleType == MDDC) &&
			       gstUserInput.eComplianceType == US_OBDII) ||
			      gstUserInput.eComplianceType == HD_OBD) &&
			     gModelYear >= 2022 &&
			     INFSupportCount[IdIdx] == 0 )
			{
				if ( gModelYear == 2022 || gModelYear == 2023 )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! (May be supported from MY 2022, but required for MY 2024 and later Heavy Duty and Medium Duty Diesel vehicles)\n",
					      IdIdx );
				}
				else
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! (Required for MY 2024 and later Heavy Duty and Medium Duty Diesel vehicles)\n",
					      IdIdx );
					bTestFailed = TRUE;
				}
			}
			else if ( (gbHybrid == TRUE ||
			           gstUserInput.eFuelType == GASOLINE ||
			           gstUserInput.eVehicleType == LD) &&
			          gstUserInput.eComplianceType == US_OBDII &&
			          INFSupportCount[IdIdx] != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F8%02X is supported by an ECU! (Should only be supported by Heavy Duty or Medium Duty Diesel vehicles)\n",
				      IdIdx );
			}
		}



		// Verify that INF $77 is supported for MY 2024 and later Heavuy Duty and Medium Duty vehicles
		if ( INFSupportCount[0x77] == 0 )
		{
			if ( gbHybrid == FALSE &&
			     ((gstUserInput.eVehicleType == MDDC &&
			       gstUserInput.eComplianceType == US_OBDII) ||
			      gstUserInput.eComplianceType == HD_OBD) &&
			     bF501Support == TRUE &&
			     gModelYear >= 2024 &&
			     INFSupportCount[IdIdx] == 0 )
			{
				if ( gstUserInput.eComplianceType == US_OBDII == TRUE )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F877 is not supported by any ECU! (Required for MY 2024 and later Heavy Duty and Medium Duty Diesel vehicles)\n" );
					bTestFailed = TRUE;
				}
			}
		}

		// Verify that INF $78 is supported for MY 2024 and later Heavy and Medium Duty Diesel vehicles
		if ( INFSupportCount[0x78] == 0 )
		{
			if ( gbHybrid == FALSE &&
			     gstUserInput.eFuelType == DIESEL &&
			     ((gstUserInput.eVehicleType == MDDC &&
			       gstUserInput.eComplianceType == US_OBDII) ||
			      gstUserInput.eComplianceType == HD_OBD) &&
			     gModelYear >= 2024 &&
			     INFSupportCount[IdIdx] == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $F8%02X is not supported by any ECU! (Required for MY 2024 and later Heavy Duty and Medium Duty Diesel vehicles)\n",
				      IdIdx );
				bTestFailed = TRUE;
			}
		}

		// Verify that INF $83 and $84 are supported for MY 2026 and later diesel vehicles
		for ( IdIdx = 0x83;
		      IdIdx <= 0x84;
		      IdIdx++ )
		{
			if ( INFSupportCount[IdIdx] == 0 &&
			     gstUserInput.eFuelType == DIESEL )
			{
				if ( gModelYear == 2026 || gModelYear == 2027 )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! (May be supported from MY 2026, but required for MY 2028 and later Diesel vehicles)\n",
					      IdIdx );
				}
				else if ( gModelYear >= 2028 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! (Required for MY 2028 and later Diesel vehicles)\n",
					      IdIdx );
				}
			}
		}

		// Verify that INF $85-AE are supported for ZEVs & ACC II-Credit Earning PHEVs
		if ( gstUserInput.eComplianceType == US_ZEV )
		{
			for ( IdIdx = 0x85;
			      IdIdx <= 0xAE;
			      IdIdx++ )
			{
				if ( ((IdIdx >= 0x85 && IdIdx <= 0x89) ||
				       IdIdx == 0x8B ||
				      ((IdIdx == 0x8C || IdIdx == 0x8D) &&
				        gstUserInput.ePowerType != PHEVG && gstUserInput.ePowerType != PHEVD) ||
				      (IdIdx >= 0x8E && IdIdx <= 0x90) ||
				      (IdIdx >= 0x96 && IdIdx <= 0x9A) ||
				      (IdIdx >= 0xA9 && IdIdx <= 0xAE)) &&
				     INFSupportCount[IdIdx] == 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! (Required for ZEVs & ACC II-Credit Earning PHEVs)\n",
					      IdIdx );
				}
				else if ( IdIdx >= 0x9B &&
				          gstUserInput.ePowerType == FUELCELL &&
				         INFSupportCount[IdIdx] == 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "INF $F8%02X is not supported by any ECU! (Required for FCEVs)\n",
					      IdIdx );
				}
			}
		}
	}  // end if ( gbPhysicalAddressing == FALSE )


	// For each INF group
	// Verify that all SID 9 INF data is valid
	// Request user supplied expected OBD ECU responses
	for ( IdIdx = 0xF801;
	      IdIdx < 0xF900;
	      IdIdx++ )
	{
		// skip INF-support INFs
		// and unsupported INFs
		if ( IdIdx == 0xF820 || IdIdx == 0xF840 ||
		     IdIdx == 0xF860 || IdIdx == 0xF880 ||
		     IdIdx == 0xF8A0 || IdIdx == 0xF8C0 ||
		     IdIdx == 0xF8E0 ||
		     IsIDSupported ( ALLECUS, INFREQUEST, IdIdx ) == FALSE )
		{
			continue;  // just go to the next itteration of the INF for loop
		}

		stReqMsg.SID      = 0x22;
		stReqMsg.NumIds   = 1;
		stReqMsg.u.DID[0] = IdIdx;
		eRetCode = PASS;
		if ( gbPhysicalAddressing == FALSE && RequestSID ( &stReqMsg, REQ_MSG_NORMAL ) != PASS )
		{
			eRetCode = FAIL;
		}
		else if ( gbPhysicalAddressing == TRUE )
		{
			gbAllECUResetCompleted = FALSE;
			for ( EcuIdx = 0;
			      EcuIdx < gNumOfECUs;
			      EcuIdx++ )
			{
				if ( IsIDSupported ( EcuIdx, INFREQUEST, IdIdx) )
				{
					if ( RequestSID_PhysicallyAddressed_Single ( &stReqMsg, REQ_MSG_NORMAL, gstResponse[EcuIdx].ReqId ) != PASS )
					{
						eRetCode = FAIL;
					}
				}
			}
		}

		if ( eRetCode != PASS )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $%04X request\n",
			      IdIdx );

			if ( IdIdx != INF_TYPE_CALID ) // IF not CALID, Don't check
			{
				continue;  // just go to the next itteration of the INF for loop
			}
		}


		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			// If INF is not supported, skip to next ECU
			if ( IsIDSupported ( EcuIdx, INFREQUEST, IdIdx ) == FALSE )
			{
				continue;  // just go to the next itteration of the ECU for loop
			}

			// INF's 1, 3, 5 & 7 should not be supported by any ECU
			if ( IdIdx ==  0xF801 || IdIdx ==  0xF803 ||
			     IdIdx ==  0xF805 || IdIdx ==  0xF807 ||
			     IdIdx ==  0xF809 || IdIdx ==  0xF80C ||
			     IdIdx ==  0xF80E )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%04X is supported (Should not be supported by UDS vehicles)\n",
				      GetEcuId ( EcuIdx ),
				      IdIdx );
				continue;  // just go to the next itteration of the ECU for loop
			}


			// Check the data to see if it is valid
			pINF = (INF *)&gstResponse[EcuIdx].INF[0];

			// if there is no data, skip checking it
			if ( gstResponse[EcuIdx].INFSize == 0 )
			{
				bTestFailed = TRUE;
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  No INF $%04X data\n",
				      GetEcuId ( EcuIdx ),
				      IdIdx );
				continue;  // just go to the next itteration of the ECU for loop
			}

			// Check various INF values for validity
			switch ( IdIdx )
			{
				case INF_TYPE_VIN:
				{
					// Isolated VIN verification logic
					if ( VerifyVINData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}

					// Check for INF $2 (VIN) support from multiple controllers
					if ( ++INF2NumResponses != 0x01 &&
					     (gstUserInput.eComplianceType == US_OBDII ||
					      gstUserInput.eComplianceType == HD_OBD) )
					{
						bTestFailed = TRUE;
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $F802 (VIN) response from multiple controllers!\n" );
					}
					else if ( INF2NumResponses != 0x01 &&
					          (gstUserInput.eComplianceType == EOBD ||
					           gstUserInput.eComplianceType == EOBD_NO_IUMPR ||
					           gstUserInput.eComplianceType == IOBD_NO_IUMPR ||
					           gstUserInput.eComplianceType == OBDBr_NO_IUMPR ||
					           gstUserInput.eComplianceType == CNOBD) )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $F802 (VIN) response from multiple controllers!\n" );
					}

				}
				break;

				case INF_TYPE_CALID:
				{
					bINF4Responded[EcuIdx] = TRUE;

					if ( VerifyCALIDData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_CVN:
				{
					INF6NumResponses++;

					if ( VerifyCVNData ( EcuIdx ) == FAIL )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_IPT_GAS:
				{
					if ( VerifyINF08Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_ECUNAME:
				{
					bINFAResponded[EcuIdx] = TRUE;

					if ( VerifyECUNameData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}

					// Check for duplicate ECU Names
					for ( EcuLoopIdx = 0;
					      EcuLoopIdx < EcuIdx;
					      EcuLoopIdx++ )
					{
						if ( gstResponse[EcuIdx].INFSize != 0 &&
						     gstResponse[EcuLoopIdx].INFSize != 0 &&
						     _memicmp ( &gstResponse[EcuIdx].INF[0],
						                &gstResponse[EcuLoopIdx].INF[0],
						                gstResponse[EcuLoopIdx].INFSize ) == 0 )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X and ECU %X  INF $F80A, Duplicate ECU names\n",
							      GetEcuId ( EcuIdx ),
							      GetEcuId ( EcuLoopIdx ) );
						}
					}
				}
				break;

				case INF_TYPE_IPT_DIESEL:
				{
					if ( VerifyINF0BData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_ESN:     // INFOTYPE $0D Engine Serial Number
				case INF_TYPE_EROTAN:  // INFOTYPE $0F Exhaust Regulation or Type Approval
				{
					if ( VerifyINF0D_0FData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_PROTID:  // INFOTYPE $10 Protocol Identification
				{
					if ( VerifyINF10Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_GTR:  // INFOTYPE $11 Protocol Identification
				{
					if ( VerifyINF11Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_FEOCNTR:  // INFOTYPE $12 Fueled Engine Operation Ignition Cycle Counter
				{
					if ( VerifyINF12Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_TG_EFN:  // INFOTYPE $13 Test Grooup/Engine Family Number
				{
					if ( VerifyINF13Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_EVAP_DIST:  // INFOTYPE $14 Distance Traveled Since Evap Monitoring Decision
				{
					if ( VerifyINF14Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_ER_IT:   // INFOTYPE $16 Engine Run/Idle Time
				{
					if ( VerifyINF16Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_DT_FC:   // INFOTYPE $17 Distance/Fuel Used
				{
					if ( VerifyINF17Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_PKE_EOE:  // INFOTYPE $18 PKE/EOE
				{
					if ( VerifyINF18Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_PSA:     // INFOTYPE $19 PSA
				{
					if ( VerifyINF19Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_PHEVDD:  // INFOTYPE $1A PHEV Distance Data
				{
					if ( VerifyINF1AData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_PHEVFD:  // INFOTYPE $1B PHEV Fuel Data
				{
					if ( VerifyINF1BData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_PHEVGD:  // INFOTYPE $1C PHEV Grid Data
				{
					if ( VerifyINF1CData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_AAF1OCCVD:  // INFOTYPE $1D Active Aerodynamic Features 1 Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF1DData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_AAF2OCCVD:  // INFOTYPE $1E Active Aerodynamic Features 2 Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF1EData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_AAF3OCCVD:  // INFOTYPE $1F Active Aerodynamic Features 3 Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF1FData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_DSOMOCCVD:  // INFOTYPE $21 Driver Selectable Operating Modes Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF21Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_RTSSCOCCVD:  // INFOTYPE $22 Run Time for Stop-Start and Coasting Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF22Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_DCTOCCVD:   // INFOTYPE $23 Driver Coaching Technology Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF23Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_APTWUFOCCVD:  // INFOTYPE $24 Active Powertrain Warm Up Features Off Cycle Credit Vehicle Data
				{
					if ( VerifyINF24Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_OCCT1VD:  // INFOTYPE $25 Off Cycle Credit Technology 1 Vehicle Data
				case INF_TYPE_OCCT2VD:  // INFOTYPE $26 Off Cycle Credit Technology 2 Vehicle Data
				case INF_TYPE_OCCT3VD:  // INFOTYPE $27 Off Cycle Credit Technology 3 Vehicle Data
				case INF_TYPE_OCCT4VD:  // INFOTYPE $28 Off Cycle Credit Technology 4 Vehicle Data
				case INF_TYPE_OCCT5VD:  // INFOTYPE $29 Off Cycle Credit Technology 5 Vehicle Data
				{
					if ( VerifyINF25_29Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_EDSMD:  // INFOTYPE $2A Eco Driver-Selectable Mode Data
				{
					if ( VerifyINF2AData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGA100HD1:  // INFOTYPE $41 HD GHG Active 100 Hour Data #1
				case INF_TYPE_HDGHGS100HD1:  // INFOTYPE $43 HD GHG Stored 100 Hour Data #1
				case INF_TYPE_HDGHGLD1:      // INFOTYPE $45 HD GHG Lifetime Data #1
				{
					if ( VerifyINF41_43_45Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGA100HD2:  // INFOTYPE $42 HD GHG Active 100 Hour Data #2
				case INF_TYPE_HDGHGS100HD2:  // INFOTYPE $44 HD GHG Stored 100 Hour Data #2
				case INF_TYPE_HDGHGLD2:      // INFOTYPE $46 HD GHG Lifetime Data #2
				{
					if ( VerifyINF42_44_46Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGPSAD:     // INFOTYPE $47 HD GHG PSA Data
				{
					if ( VerifyINF47Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGPHEVVD:   // INFOTYPE $48 HD GHG Plug-in Hybrid Vehicle Distance Data
				{
					if ( VerifyINF48Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGPHEVFD:   // INFOTYPE $49 HD GHG Plug-in Hybrid Vehicle Fuel Data
				{
					if ( VerifyINF49Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGPHEVGD:   // INFOTYPE $50 HD GHG Plug-in Hybrid Vehicle Grid Data
				{
					if ( VerifyINF50Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGATSS:     // INFOTYPE $51 HD GHG Active Technology: Stop-Start
				{
					if ( VerifyINF51Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGATAES:    // INFOTYPE $52 HD GHG Active Technology: Automatic Engine Shutdown
				{
					if ( VerifyINF52Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGATWHR:    // INFOTYPE $53 HD GHG Active Technology: Waste Heat Recovery
				{
					if ( VerifyINF53Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_HDGHGAT1AT2:   // INFOTYPE $54 HD GHG Active Technology #1 and Active Technology #2
				case INF_TYPE_HDGHGAT3AT4:   // INFOTYPE $55 HD GHG Active Technology #3 and Active Technology #4
				case INF_TYPE_HDGHGAT5AT6:   // INFOTYPE $56 HD GHG Active Technology #5 and Active Technology #6
				case INF_TYPE_HDGHGAT7AT8:   // INFOTYPE $57 HD GHG Active Technology #7 and Active Technology #8
				case INF_TYPE_HDGHGAT9AT10:  // INFOTYPE $58 HD GHG Active Technology #9 and Active Technology #10
				case INF_TYPE_HDGHGAT11AT12: // INFOTYPE $59 HD GHG Active Technology #11 and Active Technology #12
				case INF_TYPE_HDGHGAT13AT14: // INFOTYPE $5A HD GHG Active Technology #13 and Active Technology #14
				case INF_TYPE_HDGHGAT15AT16: // INFOTYPE $5B HD GHG Active Technology #15 and Active Technology #16
				{
					if ( VerifyINF54_5BData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_NOx100HMEOA:   // INFOTYPE $61 NOx Binning: 100 Hour NOx Mass - Engine Out Bins (Active)
				case INF_TYPE_NOx100HMTA:    // INFOTYPE $62 NOx Binning: 100 Hour NOx Mass - Tailpipe Bins (Active)
				case INF_TYPE_NOx100HMEOS:   // INFOTYPE $67 NOx Binning: 100 Hour NOx Mass - Engine Out Bins (Stored)
				case INF_TYPE_NOx100HMTS:    // INFOTYPE $68 NOx Binning: 100 Hour NOx Mass - Tailpipe Bins (Stored)
				case INF_TYPE_NOxVMEOL:      // INFOTYPE $6D NOx Binning Valid NOx: NOx Mass - Engine Out Bins (Lifetime)
				case INF_TYPE_NOxVMTL:       // INFOTYPE $6E NOx Binning Valid NOx: NOx Mass - Tailpipe Bins (Lifetime)
				{
					if ( VerifyINF61_62_67_68_6D_6EData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_NOx100HEOEA:   // INFOTYPE $63 NOx Binning: 100 Hour Engine Output Energy Bins (Active)
				case INF_TYPE_NOx100HEOES:   // INFOTYPE $69 NOx Binning: 100 Hour Engine Output Energy Bins (Stored)
				case INF_TYPE_NOxVEOEL:      // INFOTYPE $6F NOx Binning Valid NOx: Engine Output Energy Bins (Lifetime)
				case INF_TYPE_NOxEAEOEL:     // INFOTYPE $73 NOx Binning Engine Activity: Engine Output Energy Bins (Lifetime)
				{
					if ( VerifyINF63_69_6F_73Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_NOx100HDTA:    // INFOTYPE $64 NOx Binning: 100 Hour Distance traveled Bins (Active)
				case INF_TYPE_NOx100HDTS:    // INFOTYPE $6A NOx Binning: 100 Hour Distance traveled Bins (Stored)
				case INF_TYPE_NOxVDTL:       // INFOTYPE $70 NOx Binning Valid NOx: Distance traveled Bins (Lifetime)
				case INF_TYPE_NOxEADTL:      // INFOTYPE $74 NOx Binning Engine Activity: Distance Traveled Bins (Lifetime)
				{
					if ( VerifyINF64_6A_70_74Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_NOx100HERTA:   // INFOTYPE $65 NOx Binning: 100 Hour Engine Run Time Bins (Active)
				case INF_TYPE_NOx100HERTS:   // INFOTYPE $6B NOx Binning: 100 Hour Engine Run Time Bins (Stored)
				case INF_TYPE_NOxVERTL:      // INFOTYPE $71 NOx Binning Valid NOx: Engine Run Time Bins (Lifetime)
				case INF_TYPE_NOxEAERTL:     // INFOTYPE $75 NOx Binning Engine Activity: Engine Run Time Bins (Lifetime)
				{
					if ( VerifyINF65_6B_71_75Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_NOx100HVFCA:   // INFOTYPE $66 NOx Binning: 100 Hour Vehicle Fuel Consumption Bins (Active)
				case INF_TYPE_NOx100HVFCS:   // INFOTYPE $6C NOx Binning: 100 Hour Vehicle Fuel Consumption Bins (Stored)
				case INF_TYPE_NOxVVFCL:      // INFOTYPE $72 NOx Binning Valid NOx: Vehicle Fuel Consumption Bins (Lifetime)
				case INF_TYPE_NOxEAVFCL:     // INFOTYPE $76 NOx Binning Engine Activity: Vehicle Fuel Consumption Bins (Lifetime)
				{
					if ( VerifyINF66_6C_72_76Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_NOxPMRVD:      // INFOTYPE $77 NOX/PM Regeneration Vehicle Data
				{
					if ( VerifyINF77Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_ER:            // INFOTYPE $78 Engine Ratings
				{
					if ( VerifyINF78Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_MAD:           // INFOTYPE $79 Monitor Activity Denominator
				{
					if ( VerifyINF79Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_IPD_UDS:       // INFOTYPE $82 In-Use Performance Data for OBDonUDS
				{
					if ( VerifyINF82Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_DCSERS:        // INFOTYPE $83 In-Use Performance Data for OBDonUDS
				{
					if ( VerifyINF83Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case INF_TYPE_DCSERS_EWMA:   // INFOTYPE $84 In-Use Performance Data for OBDonUDS
				{
					if ( VerifyINF84Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF885:  // INFOTYPE $85-8D, $96,97
				case 0xF886:
				case 0xF887:
				case 0xF888:
				case 0xF889:
				case 0xF88A:
				case 0xF88B:
				case 0xF88C:
				case 0xF88D:
				case 0xF896:
				case 0xF897:
				{
					if ( VerifyINF85_8D__96_97Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF88E:  // INFOTYPE $8E-90
				case 0xF88F:
				case 0xF890:
				{
					if ( VerifyINF8E_90Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF891:  // INFOTYPE $91-93
				case 0xF892:
				case 0xF893:
				{
					if ( VerifyINF91_93Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF894:  // INFOTYPE $94
				{
					if ( VerifyINF94Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF895:  // INFOTYPE $95
				{
					if ( VerifyINF95Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF898:  // INFOTYPE $98-99
				case 0xF899:
				{
					if ( VerifyINF98_99Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF89A:  // INFOTYPE $9A
				{
					if ( VerifyINF9AData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF89B:  // INFOTYPE $9B
				{
					if ( VerifyINF9BData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF89C:  // INFOTYPE $9C-A1
				case 0xF89D:
				case 0xF89E:
				case 0xF89F:
				case 0xF8A1:
				{
					if ( VerifyINF9C_A1Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A2:  // INFOTYPE $A2
				{
					if ( VerifyINFA2Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A3:  // INFOTYPE $A3
				{
					if ( VerifyINFA3Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A4:  // INFOTYPE $A4
				{
					if ( VerifyINFA4Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A5:  // INFOTYPE $A5
				{
					if ( VerifyINFA5Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A6:  // INFOTYPE $A6
				{
					if ( VerifyINFA6Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A7:  // INFOTYPE $A7
				{
					if ( VerifyINFA7Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A8:  // INFOTYPE $A8
				{
					if ( VerifyINFA8Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8A9:  // INFOTYPE $A9-AE
				case 0xF8AA:
				case 0xF8AB:
				case 0xF8AC:
				case 0xF8AD:
				case 0xF8AE:
				{
					if ( VerifyINFA9_AEData ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8AF:  // INFOTYPE $AF-B3
				case 0xF8B0:
				case 0xF8B1:
				case 0xF8B2:
				case 0xF8B3:
				{
					if ( VerifyINFAF_B3Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				case 0xF8B4:  // INFOTYPE $B4
				{
					if ( VerifyINFB4Data ( EcuIdx ) != PASS )
					{
						bTestFailed = TRUE;
					}
				}
				break;

				default:
				{
					// Non-OBD INF type
				}
				break;
			} // end switch ( index )


			// Verify that every ECU responded to INF $04 request
			if ( IdIdx == 0xF804 &&
			     bINF4Responded[EcuIdx] == FALSE )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Did not report INF $F804 (CALID)\n",
				      GetEcuId ( EcuIdx ) );
				bTestFailed = TRUE;
			}

			// Verify that INF $A is supported
			if ( IdIdx == 0xF80A &&
			     bINFAResponded[EcuIdx] == FALSE &&
			     (gstUserInput.eComplianceType == US_OBDII ||
			      gstUserInput.eComplianceType == HD_OBD   ||
			      gstUserInput.eComplianceType == CNOBD) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Did not report INF $F80A (ECUNAME) (Required for all vehicles)\n",
				       GetEcuId ( EcuIdx ) );
				bTestFailed = TRUE;
			}

		} // end for ( EcuIdx )

	} // end for ( IdIdx )


	// Verify that INF $2 is supported by the correct number of ECUs
	if ( INF2NumResponses == 0 )
	{
		if ( gstUserInput.eComplianceType == US_OBDII ||
		     gstUserInput.eComplianceType == HD_OBD )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F802 (VIN) must be reported by one ECU\n" );
			bTestFailed = TRUE;
		}
		else
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $F802 (VIN) not reported by any ECUs\n" );
		}
	}

	// Verify that INF $6 is supported by the correct number of ECUs
	if ( INF6NumResponses > gUserNumOfECUs &&
	     (gstUserInput.eComplianceType == US_OBDII ||
	      gstUserInput.eComplianceType == HD_OBD   ||
	      gstUserInput.eComplianceType == CNOBD) )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "INF $F806 (CVN) not reported by expected number of ECUs\n" );
	}


	// Check Group INF support
	if ( RequestGroupPIDSupportData ( INFREQUEST ) == FAIL )
	{
		bTestFailed = TRUE;
	}


	// If there where any errors in the responses, fail
	if ( bTestFailed == TRUE || InitialFailureCount != GetFailureCount ( ) )
	{
		// There could have been early/late responses that weren't treated as FAIL
		return FAIL;
	}
	else
	{
		return PASS;
	}

}


/*******************************************************************************
**
**  Function:  VerifyVINData
**
**  Purpose:   Verify the VIN data.
**             In the event the format fails defined criteria
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyVINData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	BYTE    VinIndex;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the data Size
	// must contain 17 bytes of data
	if ( DataSize != 17 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F802 Invalid Data Size = %d (should be 17)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
	}

	// Check the data to see if it is valid
	if ( pINF->INFLSB == (INF_TYPE_VIN & 0x00FF) )
	{
		// Copy the VIN into the global array
		memcpy ( gVINString, &pINF[0].Data[0], 17 );
	}


	// Print VIN string to log file
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F802  VIN = %s\n",
	      GetEcuId ( EcuIdx ),
	      gVINString );

	// Check all VIN characters for validity
	for ( VinIndex = 0;
	      VinIndex < 17;
	      VinIndex++ )
	{
		if ( gVINString[VinIndex] <  '0' || gVINString[VinIndex] >  'Z' ||
		     gVINString[VinIndex] == 'I' || gVINString[VinIndex] == 'O' ||
		     gVINString[VinIndex] == 'Q' || gVINString[VinIndex] == ':' ||
		     gVINString[VinIndex] == ';' || gVINString[VinIndex] == '<' ||
		     gVINString[VinIndex] == '>' || gVINString[VinIndex] == '=' ||
		     gVINString[VinIndex] == '?' || gVINString[VinIndex] == '@' )
		{
			break;  // leave VIN index for loop
		}
	}

	if ( VinIndex != 17 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  Invalid VIN information\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}


	// Check that VIN model year character matches user input model year
	if ( ( (gVINString[9] == '1' && gVINModelYear != 2001 && gVINModelYear != 2031) ||
	       (gVINString[9] == '2' && gVINModelYear != 2002 && gVINModelYear != 2032) ||
	       (gVINString[9] == '3' && gVINModelYear != 2003 && gVINModelYear != 2033) ||
	       (gVINString[9] == '4' && gVINModelYear != 2004 && gVINModelYear != 2034) ||
	       (gVINString[9] == '5' && gVINModelYear != 2005 && gVINModelYear != 2035) ||
	       (gVINString[9] == '6' && gVINModelYear != 2006 && gVINModelYear != 2036) ||
	       (gVINString[9] == '7' && gVINModelYear != 2007 && gVINModelYear != 2037) ||
	       (gVINString[9] == '8' && gVINModelYear != 2008 && gVINModelYear != 2038) ||
	       (gVINString[9] == '9' && gVINModelYear != 2009 && gVINModelYear != 2039) ||
	       (gVINString[9] == 'A' && gVINModelYear != 2010) ||
	       (gVINString[9] == 'B' && gVINModelYear != 1981 && gVINModelYear != 2011) ||
	       (gVINString[9] == 'C' && gVINModelYear != 1982 && gVINModelYear != 2012) ||
	       (gVINString[9] == 'D' && gVINModelYear != 1983 && gVINModelYear != 2013) ||
	       (gVINString[9] == 'E' && gVINModelYear != 1984 && gVINModelYear != 2014) ||
	       (gVINString[9] == 'F' && gVINModelYear != 1985 && gVINModelYear != 2015) ||
	       (gVINString[9] == 'G' && gVINModelYear != 1986 && gVINModelYear != 2016) ||
	       (gVINString[9] == 'H' && gVINModelYear != 1987 && gVINModelYear != 2017) ||
	       (gVINString[9] == 'J' && gVINModelYear != 1988 && gVINModelYear != 2018) ||
	       (gVINString[9] == 'K' && gVINModelYear != 1989 && gVINModelYear != 2019) ||
	       (gVINString[9] == 'L' && gVINModelYear != 1990 && gVINModelYear != 2020) ||
	       (gVINString[9] == 'M' && gVINModelYear != 1991 && gVINModelYear != 2021) ||
	       (gVINString[9] == 'N' && gVINModelYear != 1992 && gVINModelYear != 2022) ||
	       (gVINString[9] == 'P' && gVINModelYear != 1993 && gVINModelYear != 2023) ||
	       (gVINString[9] == 'R' && gVINModelYear != 1994 && gVINModelYear != 2024) ||
	       (gVINString[9] == 'S' && gVINModelYear != 1995 && gVINModelYear != 2025) ||
	       (gVINString[9] == 'T' && gVINModelYear != 1996 && gVINModelYear != 2026) ||
	       (gVINString[9] == 'V' && gVINModelYear != 1997 && gVINModelYear != 2027) ||
	       (gVINString[9] == 'W' && gVINModelYear != 1998 && gVINModelYear != 2028) ||
	       (gVINString[9] == 'X' && gVINModelYear != 1999 && gVINModelYear != 2029) ||
	       (gVINString[9] == 'Y' && gVINModelYear != 2000 && gVINModelYear != 2030) ) &&
	       (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  VIN year character (%c) does not match user entry (%d)\n",
		      GetEcuId ( EcuIdx ),
		      gVINString[9],
		      gVINModelYear );
		eRetCode = FAIL;
	}

	else if ( gVINString[9] == '0' || gVINString[9] == 'I' ||
	          gVINString[9] == 'O' || gVINString[9] == 'Q' ||
	          gVINString[9] == 'U' || gVINString[9] == 'Z' )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  Invalid VIN year character (%c) not currently defined)\n",
		      GetEcuId ( EcuIdx ),
		      gVINString[9] );
		eRetCode = FAIL;
	}

	else if ( gVINModelYear < 1981 || gVINModelYear > 2039 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  Model Year %d does not currently have a VIN character defined)\n",
		      GetEcuId ( EcuIdx ),
		      gVINModelYear );
		eRetCode = FAIL;
	}

	if ( eRetCode != FAIL )
	{
		gstResponse[EcuIdx].bVINValid = TRUE;

		strncpy_s ( gstResponse[EcuIdx].VINString, VIN_BUFFER_SIZE, gVINString, VIN_BUFFER_SIZE );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyCALIDData
**
**  Purpose:   Verify the CALID data.
**             In the event the format fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyCALIDData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned short  CalidCnt;
	unsigned short  ItemIndex;
	unsigned short  ByteIdx;
	char            Buffer[CALID_BUFFER_SIZE];
	unsigned int    CalidStringSize;
	BOOL            bCalidEnd = FALSE;


	pINF = (INF*) &gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// Calculate the number of CALIDs (each CALID is 16 bytes)
	CalidCnt = DataSize / 16;
	if ( DataSize % 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F804 Invalid Data Size = %d (should be evenly divisible by 16)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	CalidStringSize = CalidCnt * CALID_BUFFER_SIZE;
	// allocate memory for copying end-of-test stats
	if ( gstResponse[EcuIdx].pCALIDString != NULL &&
	     gstResponse[EcuIdx].CALIDCount != CalidCnt )
	{
		if ( (gstResponse[EcuIdx].pCALIDString = realloc ( gstResponse[EcuIdx].pCALIDString, CalidStringSize)) == NULL )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Unable to allocate memory for ECU %X CALID storage\n",
			      GetEcuId ( EcuIdx ) );
			return FAIL;
		}
	}
	else
	{
		if ( (gstResponse[EcuIdx].pCALIDString = (char *) malloc ( CalidStringSize )) == NULL )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Unable to allocate memory for ECU %X CALID storage\n",
			      GetEcuId ( EcuIdx ) );
			return FAIL;
		}
	}

	memset ( gstResponse[EcuIdx].pCALIDString,
	         0x00,
	         CalidStringSize );
	gstResponse[EcuIdx].CALIDCount = CalidCnt;

	for ( ItemIndex = 0;
	      ItemIndex < CalidCnt;
	      ItemIndex++ )
	{
		bCalidEnd = FALSE;
		memcpy ( Buffer,
		         &(pINF->Data[ItemIndex * 16]),
		         16 );

		Buffer[16] = 0;
		// if there is only one CALID, don't number it
		if ( CalidCnt == 1 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F804  CALID   = %s\n",
			      GetEcuId ( EcuIdx ),
			      Buffer );
		}
		// else, there are more than one CALID, number them
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F804  CALID%02d = %s\n",
			      GetEcuId ( EcuIdx ),
			      ItemIndex+1,
			      Buffer );
		}

		for ( ByteIdx = 0;
		      ByteIdx < 16;
		      ByteIdx++ )
		{
			if ( bCalidEnd == FALSE )
			{
				if ( Buffer[ByteIdx] < 0x20 || Buffer[ByteIdx] > 0x7E )
				{
					if ( Buffer[ByteIdx] != 0x00 )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  CALID contains one or more invalid characters\n",
						      GetEcuId ( EcuIdx ) );
						eRetCode = FAIL;
						Buffer[ByteIdx] = 0;
						break;  // leave CALID byte index for loop
					}
					else if ( ByteIdx == 0 )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  CALID can not start with pad byte\n",
						      GetEcuId ( EcuIdx ) );
						eRetCode = FAIL;
						break;  // leave CALID byte index for loop
					}
					else
					{
						bCalidEnd = TRUE;
					}
				}
			}
			else
			{
				if ( Buffer[ByteIdx] != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  CALID not zero padded on right\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
					Buffer[ByteIdx] = 0;
					break;  // leave CALID byte index for loop
				}
			}
		} // end for (ByteIdx...

		//  add the current CALID to this ECU's CALID list
		strcpy_s ( &gstResponse[EcuIdx].pCALIDString[ItemIndex * CALID_BUFFER_SIZE],
		           CALID_BUFFER_SIZE,
		           Buffer );
	}  // end for (ItemIndex...


	// response size should be 1
	if ( CalidCnt != 1 && 
	     gstUserInput.eEnergyType != ZEV )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F804 CALID count = %d (should be 1 for MY 2009 and later, unless EO approved)\n",
		      GetEcuId ( EcuIdx ),
		      CalidCnt );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyCVNData
**
**  Purpose:   Verify the CVN data.
**             In the event the format fails defined criteria
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyCVNData ( BYTE EcuIdx )
{
	INF  *pINF;
	BYTE  DataSize;

	unsigned short  CvnCnt;
	unsigned short  ItemIndex;
	unsigned short  ByteIdx;
	char            Buffer[CVN_BUFFER_SIZE];
	unsigned int    CvnStringSize;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// Calculate The number of CVNs (each CVN is 4 bytes)
	CvnCnt = DataSize / 4;
	if ( DataSize % 4 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F806 Invalid Data Size = %d (should be evenly divisible by 4)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	// allocate memory for copying end-of-test stats
	CvnStringSize = CvnCnt * CVN_BUFFER_SIZE;
	if ( gstResponse[EcuIdx].pCVNString != NULL &&
	     gstResponse[EcuIdx].CVNCount != CvnCnt )
	{
		if ( (gstResponse[EcuIdx].pCVNString = realloc ( gstResponse[EcuIdx].pCVNString, CvnStringSize )) == NULL )
		{
			if (gstUserInput.eEnergyType != ZEV)
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Unable to allocate memory for ECU %X CVN storage\n",
				      GetEcuId ( EcuIdx ) );
				return FAIL;
			}
			else
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Unable to allocate memory for ECU %X CVN storage\n",
				      GetEcuId ( EcuIdx ) );
				return ERRORS;
			}
		}
	}
	else
	{
		if ( (gstResponse[EcuIdx].pCVNString = (char *) malloc ( CvnStringSize )) == NULL )
		{
			if (gstUserInput.eEnergyType != ZEV)
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Unable to allocate memory for ECU %X CVN storage\n",
				      GetEcuId ( EcuIdx ) );
				return FAIL;
			}
			else
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Unable to allocate memory for ECU %X CVN storage\n",
				      GetEcuId ( EcuIdx ) );
				return ERRORS;
			}
		}
	}
	memset ( gstResponse[EcuIdx].pCVNString,
	         0x00,
	         CvnStringSize );
	gstResponse[EcuIdx].CVNCount = CvnCnt;

	for ( ItemIndex = 0, ByteIdx = 0;
	      ItemIndex < CvnCnt;
	      ItemIndex++, ByteIdx += 4 )
	{
		sprintf_s ( Buffer,
		            CVN_BUFFER_SIZE,
		            "$%02X $%02X $%02X $%02X",
		            pINF->Data[ByteIdx],
		            pINF->Data[ByteIdx+1],
		            pINF->Data[ByteIdx+2],
		            pINF->Data[ByteIdx+3] );

		// if there is only one CVN, don't number it
		if ( CvnCnt == 1 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F806  CVN   = %s\n",
			      GetEcuId ( EcuIdx ),
			      Buffer );
		}
		// else, there are more than one CVN, number them
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F806  CVN%02d = %s\n",
			      GetEcuId ( EcuIdx ),
			      ItemIndex+1,
			      Buffer );
		}

		strcpy_s ( &gstResponse[EcuIdx].pCVNString[ItemIndex*CVN_BUFFER_SIZE], CVN_BUFFER_SIZE, Buffer );
	}

	// response size should be 1
	if ( CvnCnt != 1 &&
	     gstUserInput.eEnergyType != ZEV )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F806 CVN count = %d (should be 1 for MY 2009 and later, unless EO approved)\n",
		      GetEcuId ( EcuIdx ),
		      CvnCnt );
	}

	return PASS;
}


/*******************************************************************************
**
**  Function:  VerifyECUNameData
**
**  Purpose:   Verify the ECU Name data.
**             In the event the format fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
#define TABLE_SIZE  54
#define ACRONYM_STRING_SIZE 45
#define TEXTNAME_STRING_SIZE 16
const char szECUAcronym[TABLE_SIZE][ACRONYM_STRING_SIZE] =
	{ "ABS ABS1 ABS2 ABS3 ABS4 ABS5 ABS6 ABS7 ABS8",
	  "AFCM AFC1 AFC2 AFC3 AFC4 AFC5 AFC6 AFC7 AFC8",
	  "AHCM AHC1 AHC2 AHC3 AHC4 AHC5 AHC6 AHC7 AHC8",
	  "APCM APC1 APC2 APC3 APC4 APC5 APC6 APC7 APC8",
	  "AWDC AWD1 AWD2 AWD3 AWD4 AWD5 AWD6 AWD7 AWD8",
	  "ADCM ADC1 ADC2 ADC3 ADC4 ADC5 ADC6 ADC7 ADC8",
	  "BCCM BCC1 BCC2 BCC3 BCC4 BCC5 BCC6 BCC7 BCC8",
	  "BECM BEC1 BEC2 BEC3 BEC4 BEC5 BEC6 BEC7 BEC8",
	  "BMCM BMC1 BMC2 BMC3 BMC4 BMC5 BMC6 BMC7 BMC8",
	  "BCM BCM1 BCM2 BCM3 BCM4 BCM5 BCM6 BCM7 BCM8",
	  "BSCM BSC1 BSC2 BSC3 BSC4 BSC5 BSC6 BSC7 BSC8",
	  "CATM CAT1 CAT2 CAT3 CAT4 CAT5 CAT6 CAT7 CAT8",
	  "CMPM CMP1 CMP2 CMP3 CMP4 CMP5 CMP6 CMP7 CMP8",
	  "CHCM CHC1 CHC2 CHC3 CHC4 CHC5 CHC6 CHC7 CHC8",
	  "CRCM CRC1 CRC2 CRC3 CRC4 CRC5 CRC6 CRC7 CRC8",
	  "CTCM CTC1 CTC2 CTC3 CTC4 CTC5 CTC6 CTC7 CTC8",
	  "DCDC DCD1 DCD2 DCD3 DCD4 DCD5 DCD6 DCD7 DCD8",
	  "DMCM DMC1 DMC2 DMC3 DMC4 DMC5 DMC6 DMC7 DMC8",
	  "DMFM DMF1 DMF2 DMF3 DMF4 DMF5 DMF6 DMF7 DMF8",
	  "DMRM DMR1 DMR2 DMR3 DMR4 DMR5 DMR6 DMR7 DMR8",
	  "EACC EAC1 EAC2 EAC3 EAC4 EAC5 EAC6 EAC7 EAC8",
	  "EACM EAM1 EAM2 EAM3 EAM4 EAM5 EAM6 EAM7 EAM8",
	  "EVCM EVC1 EVC2 EVC3 EVC4 EVC5 EVC6 EVC7 EVC8",
	  "EBBC EBB1 EBB2 EBB3 EBB4 EBB5 EBB6 EBB7 EBB8",
	  "ECCI ECC1 ECC2 ECC3 ECC4 ECC5 ECC6 ECC7 ECC8",
	  "ECM ECM1 ECM2 ECM3 ECM4 ECM5 ECM6 ECM7 ECM8",
	  "FACM FAC1 FAC2 FAC3 FAC4 FAC5 FAC6 FAC7 FAC8",
	  "FCCM FCC1 FCC2 FCC3 FCC4 FCC5 FCC6 FCC7 FCC8",
	  "FICM FIC1 FIC2 FIC3 FIC4 FIC5 FIC6 FIC7 FIC8",
	  "FPCM FPC1 FPC2 FPC3 FPC4 FPC5 FPC6 FPC7 FPC8",
	  "4WDC 4WD1 4WD2 4WD3 4WD4 4WD5 4WD6 4WD7 4WD8",
	  "GWM GWM1 GWM2 GWM3 GWM4 GWM5 GWM6 GWM7 GWM8",
	  "GPCM GPC1 GPC2 GPC3 GPC4 GPC5 GPC6 GPC7 GPC8",
	  "GSM GSM1 GSM2 GSM3 GSM4 GSM5 GSM6 GSM7 GSM8",
	  "HCCM HCC1 HCC2 HCC3 HCC4 HCC5 HCC6 HCC7 HCC8",
	  "HVAC HVA1 HVA2 HVA3 HVA4 HVA5 HVA6 HVA7 HVA8",
	  "HPCM HPC1 HPC2 HPC3 HPC4 HPC5 HPC6 HPC7 HPC8",
	  "ICM ICM1 ICM2 ICM3 ICM4 ICM5 ICM6 ICM7 ICM8",
	  "IPC IPC1 IPC2 IPC3 IPC4 IPC5 IPC6 IPC7 IPC8",
	  "OFBC OFB1 OFB2 OFB3 OFB4 OFB5 OFB6 OFB7 OFB8",
	  "PDCM PDC1 PDC2 PDC3 PDC4 PDC5 PDC6 PDC7 PDC8",
	  "PCM PCM1 PCM2 PCM3 PCM4 PCM5 PCM6 PCM7 PCM8",
	  "RDCM RDC1 RDC2 RDC3 RDC4 RDC5 RDC6 RDC7 RDC8",
	  "SGCM SGC1 SGC2 SGC3 SGC4 SGC5 SGC6 SGC7 SGC8",
	  "TACM TAC1 TAC2 TAC3 TAC4 TAC5 TAC6 TAC7 TAC8",
	  "TCCM TCC1 TCC2 TCC3 TCC4 TCC5 TCC6 TCC7 TCC8",
	  "TVDC TVD1 TVD2 TVD3 TVD4 TVD5 TVD6 TVD7 TVD8",
	  "TCM TCM1 TCM2 TCM3 TCM4 TCM5 TCM6 TCM7 TCM8",
	  "TSCM TSC1 TSC2 TSC3 TSC4 TSC5 TSC6 TSC7 TSC8",
	  "VDCM VDC1 VDC2 VDC3 VDC4 VDC5 VDC6 VDC7 VDC8",
	  "VTMC VTM1 VTM2 VTM3 VTM4 VTM5 VTM6 VTM7 VTM8",
	  "ZCM ZCM1 ZCM2 ZCM3 ZCM4 ZCM5 ZCM6 ZCM7 ZCM8",
	  "ZFM ZF1 ZF2 ZF3 ZF4 ZF5 ZF6 ZF7 ZF8",
	  "ZRM ZR1 ZR2 ZR3 ZR4 ZR5 ZR6 ZR7 ZR8" };

const char szECUTextName[TABLE_SIZE][TEXTNAME_STRING_SIZE] =
	{ "AntiLockBrake",
	  "AltFuelCtrl",
	  "AuxHeatCtrl",
	  "AirPumpCtrl",
	  "AllWhlDrvCtrl",
	  "AutDrivingCtrl",
	  "B+ChargerCtrl",
	  "B+EnergyCtrl",
	  "B+ManageCtrl",
	  "BodyControl",
	  "BrakeSystem",
	  "CatHeaterCtrl",
	  "CamPosCtrl",
	  "ChassisCtrl",
	  "CruiseControl",
	  "CoolTempCtrl",
	  "DCDCConvCtrl",
	  "DriveMotorCtrl",
	  "DrvMtrCtrlFnt",
	  "DrvMtrCtrlRr",
	  "ElecACCompCtrl",
	  "ExhaustAftCtrl",
	  "ElecVehiclCtrl",
	  "ElecBrkBstCtrl",
	  "EmisCritInfo",
	  "EngineControl",
	  "FuelAddCtrl",
	  "FuelCellCtrl",
	  "FuelInjCtrl",
	  "FuelPumpCtrl",
	  "4WhlDrvClCtrl",
	  "Gateway",
	  "GlowPlugCtrl",
	  "GearShiftCtrl",
	  "HighCompCtrl",
	  "HVACCtrl",
	  "HybridPtCtrl",
	  "InfotainCtrl",
	  "InstPanelClust",
	  "OfBChargerCtrl",
	  "PowerDistCtrl",
	  "PowertrainCtrl",
	  "ReductantCtrl",
	  "Start/GenCtrl",
	  "ThrotActCtrl",
	  "TransfCaseCtrl",
	  "TrqVecDiffCtl",
	  "TransmisCtrl",
	  "TrboSupercCtrl",
	  "VehDynCtrl",
	  "ThermalMgmt",
	  "ZonalCtrl",
	  "ZonalCtrlFnt",
	  "ZonalCtrlRr" };

STATUS VerifyECUNameData ( BYTE  EcuIdx )
{
	INF  *pINF;
	BYTE  DataSize;

	unsigned int    ByteIdx;
	char            Buffer[21];
	char           *pString;
	char           *pToken = NULL;
	char            AcronymBuffer[ACRONYM_STRING_SIZE];
	char            AcronymNumber = 0;
	char            TextNameNumber = 0;
	unsigned int    CompSize;
	unsigned int    TableIndex;
	unsigned int    AcronymTableIndex;
	BOOL            bTestFailed = FALSE;
	BOOL            bMatchFound = FALSE;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// ECU Name Data must contain 20 bytes of data
	if ( DataSize != 20 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F80A (ECU NAME) Data Size Error = %d (Must be 20 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	memcpy ( Buffer,
	         &(pINF->Data[0]),
	         20 );
	// Check for zero padding of ECU Acronym
	for ( ByteIdx = 0;
	      ByteIdx < 20;
	      ByteIdx++ )
	{
		if ( Buffer[ByteIdx] == 0x00 )
		{
			Buffer[ByteIdx] = ' ';    // replace zero with space for printing to log file
		}
	}
	// insert NULL terminator at end of string
	Buffer[20] = 0x00;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F80A  ECU acronym and name = %s\n",
	      GetEcuId ( EcuIdx ),
	      Buffer );

	memcpy ( Buffer,
	         &(pINF->Data[0]),
	         20 );

	// Check all ECU Acronym characters for validity
	for ( ByteIdx = 0;
	      ByteIdx < 4;
	      ByteIdx++ )
	{
		if ( Buffer[ByteIdx] == 0x00 )
		{
			break;  // leave ECU Acronym byte index for loop
		}
		else if ( !( Buffer[ByteIdx] >= '1' && Buffer[ByteIdx] <= '9' ) &&
		          !( Buffer[ByteIdx] >= 'A' && Buffer[ByteIdx] <= 'Z' ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Invalid ECU acronym/number character (byte %d)\n",
			      GetEcuId ( EcuIdx ),
			     ByteIdx );
			bTestFailed = TRUE;
		}
	}

	// Check that ECU Acronym is approved
	for ( TableIndex = 0;
	      TableIndex < TABLE_SIZE;
	      TableIndex++ )
	{
		memcpy ( AcronymBuffer,
		         &(szECUAcronym[TableIndex]),
		         ACRONYM_STRING_SIZE );

		// get pointer to first string
		pString = strtok_s ( (char*)&(AcronymBuffer), " ", &pToken );
		do
		{
			// if found match
			if ( strncmp ( pString, &Buffer[0], ByteIdx ) == 0 )
			{
				bMatchFound = TRUE;
				break;  // leave approved ECU Acronym Table index for loop
			}

			// get pointer to next string
			pString = strtok_s ('\0', " ", &pToken );
		} while ( pString && bMatchFound != TRUE );

		if ( bMatchFound == TRUE )
		{
			break;  // leave approved ECU Acronym Table index for loop
		}
	}

	if ( TableIndex == TABLE_SIZE )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  Not an approved ECU acronym/number\n",
		      GetEcuId ( EcuIdx ) );
		bTestFailed = TRUE;
	}

	// if last character was a number
	if ( Buffer[ByteIdx-1] >= '1' && Buffer[ByteIdx-1] <= '9' )
	{
		// save the number for Acronym/Text Name verification
		AcronymNumber = Buffer[ByteIdx-1];
	}

	// save index for Acronym/Text Name verification
	AcronymTableIndex = TableIndex;

	// Check for zero padding of ECU Acronym
	for ( ;
	      ByteIdx < 4;
	      ByteIdx++ )
	{
		if ( Buffer[ByteIdx] != 0x00 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  ECU acronym/number not zero padded on right\n",
			      GetEcuId ( EcuIdx ) );
			bTestFailed = TRUE;
		}
		else
		{
			Buffer[ByteIdx] = ' ';    // replace zero with space for printing to log file
		}
	}


	// Check for invalid delimiter
	if ( Buffer[ByteIdx++] != '-' )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  Invalid ECU Name delimiter character (byte %d)\n",
		      GetEcuId ( EcuIdx ),
		      ByteIdx );
		bTestFailed = TRUE;
	}

	// Check all ECU Text Name characters for validity
	for ( ;
	      ByteIdx < 20;
	      ByteIdx++ )
	{
		if ( Buffer[ByteIdx] == 0x00 )
		{
			break;  // leave ECU Name byte index for loop
		}

		if ( !( Buffer[ByteIdx] >= '1' && Buffer[ByteIdx] <= '9' ) &&
		     !( Buffer[ByteIdx] >= 'A' && Buffer[ByteIdx] <= 'Z' ) &&
		     !( Buffer[ByteIdx] >= 'a' && Buffer[ByteIdx] <= 'z' ) &&
		     Buffer[ByteIdx] != '+' && Buffer[ByteIdx] != '/' )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Invalid ECU text name character (byte %d)\n",
			      GetEcuId ( EcuIdx ),
			      ByteIdx );
			bTestFailed = TRUE;
		}
	}

	// if last character was a number, don't use it in ECU Text Name search
	if ( Buffer[ByteIdx-1] >= '1' && Buffer[ByteIdx-1] <= '9' )
	{
		// comparison size is Buffer size less the Acronym, the Delimiter and the Text Name number
		CompSize = ByteIdx - 6;
		// save the number for Acronym/Text Name verification
		TextNameNumber = Buffer[ByteIdx-1];
	}
	else
	{
		// comparison size is Buffer size less the Acronym and the Delimiter
		CompSize = ByteIdx - 5;
	}

	// Check that ECU Text Name is approved
	for ( TableIndex = 0;
	      TableIndex < TABLE_SIZE;
	      TableIndex++ )
	{
		// if found match
		if ( strncmp ( &Buffer[5], szECUTextName[TableIndex], CompSize ) == 0 )
		{
			break;  // leave approved ECU Name Table index for loop
		}
	}

	if ( TableIndex == TABLE_SIZE )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  Not an approved ECU text name\n",
		      GetEcuId ( EcuIdx ) );
		bTestFailed = TRUE;
	}

	// Check for zero padding of ECU Text Name
	for ( ;
	      ByteIdx < 20;
	      ByteIdx++ )
	{
		if ( Buffer[ByteIdx] != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  ECU text name not zero padded on right\n",
			      GetEcuId ( EcuIdx ) );
			bTestFailed = TRUE;
		}
	}

	// Check for ECU Acronym and Text Name match
	if ( AcronymTableIndex != TableIndex ||
	     AcronymNumber != TextNameNumber )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  ECU acronym and text name do not match\n",
		      GetEcuId ( EcuIdx ) );
		bTestFailed = TRUE;
	}


	if ( bTestFailed == TRUE )
	{
		return FAIL;
	}
	else
	{
		return PASS;
	}
}


/*******************************************************************************
**
**  Function:  VerifyINF08Data
**
**  Purpose:   Verify the INF 8 data.
**             In the event the format fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF08Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;  // function result

	BYTE           DataIdx;
	unsigned short DataTemp;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	if ( gstUserInput.eFuelType == DIESEL &&
	     (gstUserInput.eComplianceType == US_OBDII ||
	      gstUserInput.eComplianceType == HD_OBD) )
	{
		// Diesel vehicles should not support INF8
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F808 response! (Not allowed for Diesel vehicles)\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// Check to see if IUMPR is supported for Compliance Type EOBD_NO_IUMPR, IOBD_NO_IUMPR, HD_IOBD_NO_IUMPR or OBDBr_NO_IUMPR
	if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR    ||
	     gstUserInput.eComplianceType == IOBD_NO_IUMPR    ||
	     gstUserInput.eComplianceType == HD_IOBD_NO_IUMPR ||
	     gstUserInput.eComplianceType == OBDBr_NO_IUMPR )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F808 response! (Conflicts with Compliance Type selected)\n",
		      GetEcuId ( EcuIdx ) );
	}

	// In-Use Performance Data must contain 32, 40, or 56 bytes of data
	if ( DataSize != 32 &&
	     DataSize != 40 &&
	     DataSize != 56 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F808 (IPT)  Data Size = %d (Must be 32, 40 or 56 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		eRetCode = ERRORS;
	}
	else
	{
		// IF Gasoline vehicle
		if ( gstUserInput.eFuelType == GASOLINE )
		{
			// If MY 2020 and later CNOBD Gasoline vehicle
			if ( gModelYear >= 2020 &&
			     gstUserInput.eComplianceType == CNOBD )
			{
				// In-Use Performance Data must contain 56 bytes of data
				// Don't include SID, INF MSB or INF LSB in INFSIZE
				if ( DataSize != 56 )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F808 (IPT)  Data Size = %d (Must be 56 bytes!)\n",
					      GetEcuId ( EcuIdx ),
					      DataSize );
				}
			}

			// If US_OBDII Gasoline vehicle
			else if ( gstUserInput.eComplianceType == US_OBDII )
			{
				// In-Use Performance Data must contain 56 bytes of data
				if ( DataSize != 56 )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F808 (IPT)  Data Size = %d (Must be 56 bytes!)\n",
					      GetEcuId ( EcuIdx ),
					      DataSize );
				}
			}
		}
		// IF Diesel vehicle
		else if ( gstUserInput.eFuelType == DIESEL )
		{
			// In-Use Performance Data must contain 32 or 40 bytes of data
			if ( DataSize != 32 &&
			     DataSize != 40 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F808 (IPT)  Data Size = %d (Must be 32 or 40 bytes!)\n",
				      GetEcuId ( EcuIdx ),
				      DataSize );
				eRetCode = ERRORS;
			}
		}
	}


	// log IPT data
	for ( DataIdx = 0;
	      DataIdx < DataSize;
	      DataIdx += 2)
	{
		DataTemp = (pINF->Data[DataIdx] << 8) +
		            pINF->Data[DataIdx+1];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F808  %-9s = %d\n",
		      GetEcuId ( EcuIdx ),
		      &szINF8[DataIdx/2][0],
		      DataTemp );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF0BData
**
**  Purpose:   Verify the INF B data.
**             In the event the format fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF0BData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;  // function result

	BYTE           DataIdx;
	unsigned short DataTemp;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	if ( gstUserInput.eFuelType == GASOLINE &&
	     (gstUserInput.eComplianceType == US_OBDII ||
	      gstUserInput.eComplianceType == HD_OBD) )
	{
		// Gasoline vehicles should not support INFB
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F80B response! (Not allowed for Gasoline vehicles)\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// Check to see if IUMPR is supported for Compliance Type EOBD_NO_IUMPR, IOBD_NO_IUMPR, HD_IOBD_NO_IUMPR or OBDBr_NO_IUMPR
	if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR    ||
	     gstUserInput.eComplianceType == IOBD_NO_IUMPR    ||
	     gstUserInput.eComplianceType == HD_IOBD_NO_IUMPR ||
	     gstUserInput.eComplianceType == OBDBr_NO_IUMPR )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F80B response! (Conflicts with Compliance Type selected)\n",
		      GetEcuId ( EcuIdx ) );
	}

	// In-Use Performance Data must contain 32 or 36 bytes of data
	if ( DataSize != 32 &&
	     DataSize != 36 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F80B (IPT)  Data Size = %d (Must be 32 or 36 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		eRetCode = FAIL;
	}


	// log IPT data
	for ( DataIdx = 0;
	      DataIdx < DataSize;
	      DataIdx += 2)
	{
		DataTemp = (pINF->Data[DataIdx] << 8) +
		            pINF->Data[DataIdx+1];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F80B  %-9s = %d\n",
		      GetEcuId ( EcuIdx ),
		      &szINFB[DataIdx/2][0],
		      DataTemp );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFD_FData
**
**  Purpose:   Verify the ESN/EROTAN data.
**             In the event the format fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF0D_0FData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned int  StartOffset = 0;
	unsigned int  MsgIndex = 0; // multi-part message index
	unsigned long ByteIdx = 0;
	char          Buffer[21];


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// ESN Data must contain 17 bytes of data
	if ( DataSize != 17 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 17 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}

	memcpy ( Buffer,
	         &(pINF->Data[0]),
	         20 );

	// strip off the pad bytes
	for ( ByteIdx = 0; ByteIdx < 17; ByteIdx++ )
	{
		if ( Buffer[ByteIdx] != 0x00 )
		{
			StartOffset = ByteIdx;
			break;
		}
	}

	if ( ByteIdx == 17 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X contains all pad bytes\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB );
		eRetCode = FAIL;
	}
	else
	{
		// Check all ESN characters for validity
		for ( ;
		      ByteIdx < 17;
		      ByteIdx++ )
		{
			if ( Buffer[ByteIdx] <  '0' || Buffer[ByteIdx] >  'Z' ||
			     Buffer[ByteIdx] == 'I' || Buffer[ByteIdx] == 'O' ||
			     Buffer[ByteIdx] == 'Q' || Buffer[ByteIdx] == ':' ||
			     Buffer[ByteIdx] == ';' || Buffer[ByteIdx] == '<' ||
			     Buffer[ByteIdx] == '>' || Buffer[ByteIdx] == '=' ||
			     Buffer[ByteIdx] == '?' || Buffer[ByteIdx] == '@' )
			{
				break;  // leave ESN byte index for loop
			}
		}

		// NULL terminate string
		Buffer[ByteIdx] = 0x00;

		if ( ByteIdx != 17 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Invalid or missing INF $F8%02X data\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB );
			eRetCode = FAIL;
		}
	}

	// Print ESN/EROTAN string to log file
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  %s = %s\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      pINF->INFLSB == 0x0D ? "ESN" : "EROTAN",
	      &Buffer[StartOffset] );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyAllINF10Data
**
**  Purpose:   Verify the PROTID data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyAllINF10Data ( void )
{
	BYTE   EcuIdx;
	STATUS eRetCode = PASS;


	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( VerifyINF10Data ( EcuIdx ) != PASS )
		{
			eRetCode = FAIL;
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF10Data
**
**  Purpose:   Verify the PROTID data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF10Data ( BYTE EcuIdx )
{
	INF   *pINF;
	BYTE   DataSize;
	STATUS eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// Protocol Identification Data must contain 1 byte of data
	if ( DataSize != 1 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F810  Data Size = %d (Must be 1 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	// log PROTID
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F810  PROTID = $%02X\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[0] );
	// Save PROTID
	gstResponse[EcuIdx].ProtocolID = pINF->Data[0];

	// All responses should be $01 for OBDonUDS or ZEVonUDS
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 2 &&
	     gstResponse[EcuIdx].ProtocolID != 0x01 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  PROTID Must be 1 for UDS vehicles\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF11Data
**
**  Purpose:   Purpose of this function is to verify the WWH-OBD GTR Number data
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF11Data ( BYTE EcuIdx )
{
	INF   *pINF;
	BYTE   DataSize;
	STATUS eRetCode = PASS;

	unsigned char GTR[12];


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// Protocol Identification Data must contain 1 byte of data
	if ( DataSize != 11 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F811  Data Size = %d (Must be 11 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	memcpy ( GTR,
	         &(pINF->Data[0]),
	         11 );
	// Null terminate the string
	GTR[11] = 0x00;

	// log PROTID
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F811  WWH-OBD GTR Number = %s\n",
	      GetEcuId ( EcuIdx ),
	      GTR );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF12Data
**
**  Purpose:   Verify the FEOCNTR data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF12Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long FEOCNTR;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// FEOCNTR Data must contain 2 bytes of data
	if ( DataSize != 2 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F812  Data Size = %d (Must be 2 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	FEOCNTR = (pINF->Data[0] << 8) +
	           pINF->Data[1];

	// If NOT test 9.16, 10.12 or 11.2, log
	if ( ( geTestPhase != eTestNoFault3DriveCycle  || gTestSubsection != 16 ) &&
	     ( geTestPhase != eTestInUseCounters       || gTestSubsection != 12 ) &&
	     ( geTestPhase != eTestPerformanceCounters || gTestSubsection != 2 ) )
	{
		// log FEOCNTR
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F812  FEOCNTR = %d\n",
		      GetEcuId ( EcuIdx ),
		      FEOCNTR );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF13Data
**
**  Purpose:   Verify the Test Group/Engine Family Number data
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF13Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned int TG_EFN_index;
	unsigned int Data_index;
	BYTE         TG_EFN[13];


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// TG/EFN Data must contain 12 bytes or less of data
	if ( DataSize > 12 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F813  Data Size = %d (Must be 1-12 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	// copy valid data to TG_EFN string
	for ( Data_index = 0, TG_EFN_index = 0;
	      Data_index < 12;
	      Data_index++ )
	{
		if ( pINF->Data[Data_index] != 0x00 && (pINF->Data[Data_index] < 0x20 || pINF->Data[Data_index] > 0x7E) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F813  byte %d  Invalid Character = $%02X (Must be $20-$7E)\n",
			      GetEcuId ( EcuIdx ),
			      Data_index+1,
			      pINF->Data[Data_index] );
			eRetCode = FAIL;
		}
		else if ( pINF->Data[Data_index] >= 0x20 && pINF->Data[Data_index] <= 0x7E )
		{
			TG_EFN[TG_EFN_index++] = pINF->Data[Data_index];
		}
	}
	TG_EFN[TG_EFN_index] = (BYTE)NULL;


	// log TG/EFN
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F813  TG/EFN = %s\n",
	      GetEcuId ( EcuIdx ),
	      TG_EFN );

	// Check that TG/EFN model year character matches user input model year
	if ( (TG_EFN[0] == '1' && gModelYear != 2001 && gModelYear != 2031) ||
	     (TG_EFN[0] == '2' && gModelYear != 2002 && gModelYear != 2032) ||
	     (TG_EFN[0] == '3' && gModelYear != 2003 && gModelYear != 2033) ||
	     (TG_EFN[0] == '4' && gModelYear != 2004 && gModelYear != 2034) ||
	     (TG_EFN[0] == '5' && gModelYear != 2005 && gModelYear != 2035) ||
	     (TG_EFN[0] == '6' && gModelYear != 2006 && gModelYear != 2036) ||
	     (TG_EFN[0] == '7' && gModelYear != 2007 && gModelYear != 2037) ||
	     (TG_EFN[0] == '8' && gModelYear != 2008 && gModelYear != 2038) ||
	     (TG_EFN[0] == '9' && gModelYear != 2009 && gModelYear != 2039) ||
	     (TG_EFN[0] == 'A' && gModelYear != 2010) ||
	     (TG_EFN[0] == 'B' && gModelYear != 1981 && gModelYear != 2011) ||
	     (TG_EFN[0] == 'C' && gModelYear != 1982 && gModelYear != 2012) ||
	     (TG_EFN[0] == 'D' && gModelYear != 1983 && gModelYear != 2013) ||
	     (TG_EFN[0] == 'E' && gModelYear != 1984 && gModelYear != 2014) ||
	     (TG_EFN[0] == 'F' && gModelYear != 1985 && gModelYear != 2015) ||
	     (TG_EFN[0] == 'G' && gModelYear != 1986 && gModelYear != 2016) ||
	     (TG_EFN[0] == 'H' && gModelYear != 1987 && gModelYear != 2017) ||
	     (TG_EFN[0] == 'J' && gModelYear != 1988 && gModelYear != 2018) ||
	     (TG_EFN[0] == 'K' && gModelYear != 1989 && gModelYear != 2019) ||
	     (TG_EFN[0] == 'L' && gModelYear != 1990 && gModelYear != 2020) ||
	     (TG_EFN[0] == 'M' && gModelYear != 1991 && gModelYear != 2021) ||
	     (TG_EFN[0] == 'N' && gModelYear != 1992 && gModelYear != 2022) ||
	     (TG_EFN[0] == 'P' && gModelYear != 1993 && gModelYear != 2023) ||
	     (TG_EFN[0] == 'R' && gModelYear != 1994 && gModelYear != 2024) ||
	     (TG_EFN[0] == 'S' && gModelYear != 1995 && gModelYear != 2025) ||
	     (TG_EFN[0] == 'T' && gModelYear != 1996 && gModelYear != 2026) ||
	     (TG_EFN[0] == 'V' && gModelYear != 1997 && gModelYear != 2027) ||
	     (TG_EFN[0] == 'W' && gModelYear != 1998 && gModelYear != 2028) ||
	     (TG_EFN[0] == 'X' && gModelYear != 1999 && gModelYear != 2029) ||
	     (TG_EFN[0] == 'Y' && gModelYear != 2000 && gModelYear != 2030) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		     "ECU %X  INF $F813 (TG/EFN)  year character (%c) does not match user entry (%d)\n",
		     GetEcuId(EcuIdx),
		      TG_EFN[0],
		     gModelYear );
		eRetCode = FAIL;
	}


	// Check that TG/EFN model year character matches VIN model year
	if ( gVINModelYear == gModelYear &&
	     TG_EFN[0] != gVINString[9] &&
	     (gstUserInput.eVehicleType == LD || gstUserInput.eVehicleType == MD) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F813 (TG/EFN)  year character (%c) does not match INF $F802 (VIN) year character (%c)\n",
		      GetEcuId ( EcuIdx ),
		      TG_EFN[0],
		      gVINString[9] );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF14Data
**
**  Purpose:   Verify the EVAP_DIST data
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF14Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long EVAP_DIST;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// EVAP_DIST Data must contain 2 bytes of data
	if ( DataSize != 2 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F814  Data Size = %d (Must be 2 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	EVAP_DIST = (pINF->Data[0] << 8) +
	             pINF->Data[1];

	// log EVAP_DIST
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F814  EVAP_DIST = %d km\n",
	      GetEcuId ( EcuIdx ),
	      EVAP_DIST );

	// if tests 11.7
	if ( geTestPhase == eTestPerformanceCounters && gTestSubsection == 7 &&
	     EVAP_DIST == 0xFFFF )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F814 should not return a value of $FFFF after evap monitor runs\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}
	// if tests 5.16
	else if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 &&
	          EVAP_DIST != 0xFFFF  && EVAP_DIST != 0x0000 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F814 should return a value of $FFFF or $0000 after a SID $14 code clear\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF16Data
**
**  Purpose:   Verify the Engine Run/Idle Time data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF16Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long IGNCNTR_R;
	unsigned long IGNCNTR_L;
	unsigned long FEOCNTR_R;
	unsigned long FEOCNTR_L;
	unsigned long ERT_R;
	unsigned long ERT_L;
	unsigned long IERT_R;
	unsigned long IERT_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// ERT/IERT Data must contain 32 bytes of data
	if ( DataSize != 32 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  Data Size = %d (Must be 32 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log IGNCNTR_R
	IGNCNTR_R = (pINF->Data[0] << 24) +
	            (pINF->Data[1] << 16) +
	            (pINF->Data[2] << 8) +
	             pINF->Data[3];

	// if it's the max value, not available
	if ( IGNCNTR_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IGNCNTR-R not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IGNCNTR-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      IGNCNTR_R );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF16_IGNCNTR_R = IGNCNTR_R;

			if ( IGNCNTR_R > 1 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F816 IGNCNTR-R must return a value of 0 or 1 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 &&  // IF Test 9.19
		          IGNCNTR_R <= Test_5_16_INF[EcuIdx].INF16_IGNCNTR_R )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F816 IGNCNTR-R must return a value greater than the value returned in Test 5.16 (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_16_INF[EcuIdx].INF16_IGNCNTR_R );
			eRetCode = FAIL;
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          IGNCNTR_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F816 IGNCNTR-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log IGNCNTR_L
	IGNCNTR_L = (pINF->Data[4] << 24) +
	            (pINF->Data[5] << 16) +
	            (pINF->Data[6] << 8) +
	             pINF->Data[7];

	// if it's the max value, not available
	if ( IGNCNTR_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IGNCNTR-L not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IGNCNTR-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      IGNCNTR_L );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				Test_5_16_INF[EcuIdx].INF16_IGNCNTR_L = IGNCNTR_L;

				if ( IGNCNTR_L < 1 || IGNCNTR_L <= IGNCNTR_R )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 IGNCNTR-L must return a value of 1 or greater and greater than IGNCNTR-R after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 &&  // IF Test 9.18
			          IGNCNTR_L <= Test_5_16_INF[EcuIdx].INF16_IGNCNTR_L )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F816 IGNCNTR-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF16_IGNCNTR_L );
				eRetCode = FAIL;
			}
		}
	}


	// log FEOCNTR_R
	FEOCNTR_R = (pINF->Data[8]  << 24) +
	            (pINF->Data[9]  << 16) +
	            (pINF->Data[10] << 8) +
	             pINF->Data[11];

	// if it's the max value, not available
	if ( FEOCNTR_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  FEOCNTR-R not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  FEOCNTR-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      FEOCNTR_R );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				Test_5_16_INF[EcuIdx].INF16_FEOCNTR_R = FEOCNTR_R;

				if ( FEOCNTR_R > 1 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 FEOCNTR-R must return a value of 0 or 1 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
			{
				if ( FEOCNTR_R <= Test_5_16_INF[EcuIdx].INF16_FEOCNTR_R &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 FEOCNTR-R must return a value greater than the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_FEOCNTR_R );
					eRetCode = FAIL;
				}
				else if ( FEOCNTR_R < Test_5_16_INF[EcuIdx].INF16_FEOCNTR_R  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 FEOCNTR-R must return a value greater than or equal to the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_FEOCNTR_R );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
			          FEOCNTR_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F816 FEOCNTR-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log FEOCNTR_L
	FEOCNTR_L = (pINF->Data[12] << 24) +
	            (pINF->Data[13] << 16) +
	            (pINF->Data[14] << 8) +
	             pINF->Data[15];

	// if it's the max value, not available
	if ( FEOCNTR_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  FEOCNTR-L not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  FEOCNTR-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      FEOCNTR_L );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				Test_5_16_INF[EcuIdx].INF16_FEOCNTR_L = FEOCNTR_L;

				if ( (FEOCNTR_L < 1 || FEOCNTR_L <= FEOCNTR_R) &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 FEOCNTR-L must return a value of 1 or greater and greater than FEOCNTR-R after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
			{
				if ( FEOCNTR_L <= Test_5_16_INF[EcuIdx].INF16_FEOCNTR_L &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 FEOCNTR-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_FEOCNTR_L );
					eRetCode = FAIL;
				}
				else if ( FEOCNTR_L < Test_5_16_INF[EcuIdx].INF16_FEOCNTR_L &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 FEOCNTR-L must return a value greater than or equal to the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_FEOCNTR_L );
					eRetCode = FAIL;
				}
			}
		}
	}

	// log ERT_R
	ERT_R = (pINF->Data[16] << 24) +
	        (pINF->Data[17] << 16) +
	        (pINF->Data[18] << 8) +
	         pINF->Data[19];

	// if it's the max value, not available
	if ( ERT_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  ERT-R     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  ERT_R     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERT_R );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				Test_5_16_INF[EcuIdx].INF16_ERT_R = ERT_R;

				if ( ERT_R <= 1 &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 ERT_R must return a value of greater than 1 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
			{
				if ( ERT_R <= Test_5_16_INF[EcuIdx].INF16_ERT_R &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 ERT_R must return a value greater than the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_ERT_R );
					eRetCode = FAIL;
				}
				else if ( ERT_R < Test_5_16_INF[EcuIdx].INF16_ERT_R  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 ERT_R must return a value greater than or equal to the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_ERT_R );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
			          ERT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F816 ERT_R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log ERT_L
	ERT_L = (pINF->Data[20] << 24) +
	        (pINF->Data[21] << 16) +
	        (pINF->Data[22] << 8) +
	         pINF->Data[23];

	// if it's the max value, not available
	if ( ERT_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  ERT-L     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  ERT-L     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERT_L );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				Test_5_16_INF[EcuIdx].INF16_ERT_L = ERT_L;

				if ( ERT_L <= 1 &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 ERT-L must return a value greater than 1 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
			{
				if ( ERT_L <= Test_5_16_INF[EcuIdx].INF16_ERT_L &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 ERT-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_ERT_L );
					eRetCode = FAIL;
				}
				else if ( ERT_L < Test_5_16_INF[EcuIdx].INF16_ERT_L  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 ERT-L must return a value greater than or equal to the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_ERT_L );
					eRetCode = FAIL;
				}
			}
		}
	}


	// log IERT_R
	IERT_R = (pINF->Data[24] << 24) +
	         (pINF->Data[25] << 16) +
	         (pINF->Data[26] << 8) +
	          pINF->Data[27];

	// if it's the max value, not available
	if ( IERT_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IERT-R    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IERT-R    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IERT_R );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				if ( IERT_R <= 1 && gbHybrid != TRUE &&  gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 IERT_R must return a value of greater than 1 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
			          IERT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F816 IERT-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log IERT_L
	IERT_L = (pINF->Data[28] << 24) +
	         (pINF->Data[29] << 16) +
	         (pINF->Data[30] << 8) +
	          pINF->Data[31];

	// if it's the max value, not available
	if ( IERT_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IERT-L    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F816  IERT-L    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IERT_L );

		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
			{
				Test_5_16_INF[EcuIdx].INF16_IERT_L = IERT_L;

				if ( IERT_L <= 1 && gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 IERT-L must return a value of greater than 1 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
			{
				if ( IERT_L <= Test_5_16_INF[EcuIdx].INF16_IERT_L &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 IERT-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_IERT_L );
					eRetCode = FAIL;
				}
				else if ( IERT_L < Test_5_16_INF[EcuIdx].INF16_IERT_L  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F816 IERT-L must return a value greater than or equal to the value returned in Test 5.16 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_16_INF[EcuIdx].INF16_IERT_L );
					eRetCode = FAIL;
				}
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF17Data
**
**  Purpose:   Verify the Distance Traveled / Fuel Consumed data
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF17Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double  DT_R;
	double  DT_L;
	double  FC_R;
	double  FC_L;

	BYTE    LifetimeSupport = 0x00;
#define     DT_SUPPORT 0x01
#define     FC_SUPPORT 0x02


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// DT/FC Data must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log DT_R
	DT_R = (double)((unsigned long)((pINF->Data[0] << 24) +
	                                (pINF->Data[1] << 16) +
	                                (pINF->Data[2] << 8) +
	                                 pINF->Data[3])) * 0.1;

	// if it's the max value, not available
	if ( DT_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817 DT-R      not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  DT-R      = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      DT_R );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF17_DT_R = DT_R;  // Save value for comaparison in Test 9.17

			if ( DT_R != 0 &&
			     (gstUserInput.ePwrTrnType == PHEV ||
			      gstUserInput.ePwrTrnType == HEV) )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 DT-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( DT_R == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 DT-R must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
			}

			if ( DT_R <= Test_5_16_INF[EcuIdx].INF17_DT_R )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 DT-R must return a value greater than the value returned in Test 5.16 (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF17_DT_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          DT_R != 0 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 DT-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
		}
	}

	// log DT_L
	DT_L = (double)((unsigned long)((pINF->Data[4] << 24) +
	                                (pINF->Data[5] << 16) +
	                                (pINF->Data[6] << 8) +
	                                 pINF->Data[7])) * 0.1;

	// if it's the max value, not available
	if ( DT_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  DT-L      not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  DT-L      = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      DT_L );

		LifetimeSupport |= DT_SUPPORT;

		if ( DT_L == 0 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 DT-L must not be zero\n",
			      GetEcuId ( EcuIdx ) );
		}

		if ( DT_L == DT_R )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 DT-L and DT-R must not be equal\n",
			      GetEcuId ( EcuIdx ) );
		}

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF17_DT_L = DT_L;  // Save value for comaparison in Test 9.18

			if ( DT_L == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 DT-L must not reset after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 &&  // IF Test 9.18
		          DT_L <= Test_5_16_INF[EcuIdx].INF17_DT_L )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 DT-L must return a value greater than the value returned in Test 5.16 (%.1f)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_16_INF[EcuIdx].INF17_DT_L );
			eRetCode = FAIL;
		}
	}


	// log FC_R
	FC_R = (double)((unsigned long)((pINF->Data[8] << 24) +
	                                (pINF->Data[9] << 16) +
	                                (pINF->Data[10] << 8) +
	                                 pINF->Data[11])) * 0.01;

	// if it's the max value, not available
	if ( FC_R == 42949672.95 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  FC-R      not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  FC-R      = %.2f l\n",
		      GetEcuId ( EcuIdx ),
		      FC_R );


		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF17_FC_R = FC_R;  // Save value for comaparison in Test 9.18

			if ( FC_R == 0 &&
			     (gstUserInput.ePwrTrnType == PHEV ||
			      gstUserInput.ePwrTrnType == HEV) )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 FC-R must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18)  // IF Test 9.18
		{
			if ( FC_R != 0 &&
			     (gbHybrid == TRUE ||
			      gbPlugIn == TRUE) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 FC-R must return a value of 0\n",
				      GetEcuId ( EcuIdx ) );
			}
			if ( FC_R <= Test_5_16_INF[EcuIdx].INF17_FC_R &&
			     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 FC-R must return a value greater than the value returned in Test 5.16 (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF17_FC_R );
				eRetCode = FAIL;
			}
			else if ( FC_R < Test_5_16_INF[EcuIdx].INF17_FC_R  &&
			          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 FC-R must return a value greater than or equal to the value returned in Test 5.16 (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF17_FC_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          FC_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 FC-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log FC_L
	FC_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                               (pINF->Data[13] << 16) +
	                               (pINF->Data[14] << 8) +
	                                pINF->Data[15])) * 0.01;

	// if it's the max value, not available
	if ( FC_L == 42949672.95 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  FC-L      not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817  FC-L      = %.2f l\n",
		      GetEcuId ( EcuIdx ),
		      FC_L );

		LifetimeSupport |= FC_SUPPORT;

		if ( FC_L == 0  &&
		     (gstUserInput.ePwrTrnType == PHEV ||
		      gstUserInput.ePwrTrnType == HEV) )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 FC-L must return a value greater than 0\n",
			      GetEcuId ( EcuIdx ) );
		}

		if ( FC_L == FC_R &&
		     (gstUserInput.ePwrTrnType == CONV ||
		      gstUserInput.ePwrTrnType == SS ) )
		{
			Log ( FAIL, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F817 FC-L and FC-R must not be equal\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF17_FC_L = FC_L;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( FC_L <= Test_5_16_INF[EcuIdx].INF17_FC_L &&
			     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 FC-L must return a value greater than the value returned in Test 5.16 (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				     Test_5_16_INF[EcuIdx].INF17_FC_L );
				eRetCode = FAIL;
			}
			else if ( FC_L < Test_5_16_INF[EcuIdx].INF17_FC_L &&
			          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F817 FC-L must return a value greater than or equal to the value returned in Test 5.16 (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF17_FC_L );
				eRetCode = FAIL;
			}
		}
	}

	if ( gstUserInput.eComplianceType == EOBD &&
	     LifetimeSupport == 0x00 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F817 Neither DT_L or FC-L are supported (Required for EOBD vehicles)\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF18Data
**
**  Purpose:   Verify the Positive Kinetic Energy and Engine Output Energy data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF18Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long  PKE_R;
	unsigned long  PKE_L;
	double         EOE_R;
	double         EOE_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// PKE/EO Data must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log PKE_R
	PKE_R = (pINF->Data[0] << 24) +
	        (pINF->Data[1] << 16) +
	        (pINF->Data[2] << 8) +
	         pINF->Data[3];

	// if it's the max value, not available
	if ( PKE_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  PKE-R     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  PKE-R     = %lu km/hr2\n",
		      GetEcuId ( EcuIdx ),
		      PKE_R );

		if ( (geTestPhase == eTestNoDTC              && gTestSubsection == 16 ||   // IF Test 5.16
		      geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19) &&  // or Test 9.19
		     PKE_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F818 PKE-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log PKE_L
	PKE_L = (pINF->Data[4] << 24) +
	        (pINF->Data[5] << 16) +
	        (pINF->Data[6] << 8) +
	         pINF->Data[7];

	// if it's the max value, not available
	if ( PKE_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  PKE-L     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  PKE-L     = %lu km/hr2\n",
		      GetEcuId ( EcuIdx ),
		      PKE_L );

		if ( PKE_L == PKE_R )
		{
			if ( gstUserInput.ePwrTrnType == CONV ||
			     gstUserInput.ePwrTrnType == SS )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 PKE-L must not be equal to PKE-R\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 PKE-L must not be equal to PKE-R\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}


	// log EOE_R
	EOE_R = (double)((unsigned long)((pINF->Data[8] << 24) +
	                                 (pINF->Data[8] << 16) +
	                                 (pINF->Data[10] << 8) +
	                                  pINF->Data[11])) * 0.1;

	// if it's the max value, not available
	if ( EOE_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  EOE-R     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  EOE-R     = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      EOE_R );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF18_EOE_R = EOE_R;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          EOE_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F818 EOE-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log EOE_L
	EOE_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                 (pINF->Data[13] << 16) +
	                                 (pINF->Data[14] << 8) +
	                                  pINF->Data[15])) * 0.1;

	// if it's the max value, not available
	if ( EOE_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  EOE-L     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F818  EOE-L     = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      EOE_L );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF18_EOE_L = EOE_L;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( EOE_L == EOE_R )
			{
				if ( gstUserInput.ePwrTrnType == CONV ||
				     gstUserInput.ePwrTrnType == SS )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F818 EOE-L must not be equal to EOE-R\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
				else
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F818 EOE-L must not be equal to EOE-R\n",
					      GetEcuId ( EcuIdx ) );
				}
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF19Data
**
**  Purpose:   Verify the Propulsion System Active data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF19Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long PSA_R;
	unsigned long PSA_L;
	unsigned long IPSA_R;
	unsigned long IPSA_L;
	unsigned long CPSA_R;
	unsigned long CPSA_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// PSA Data must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log PSA_R
	PSA_R = (pINF->Data[0] << 24) +
	        (pINF->Data[1] << 16) +
	        (pINF->Data[2] << 8) +
	         pINF->Data[3];

	// if it's the max value, not available
	if ( PSA_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  PSA-R     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  PSA-R     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_R );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF19_PSA_R = PSA_R;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( PSA_R == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 PSA-R must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			if ( PSA_R <= Test_5_16_INF[EcuIdx].INF19_PSA_R )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 PSA-R must return a value greater than the value returned in Test 5.16 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF19_PSA_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          PSA_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F819 PSA-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log PSA_L
	PSA_L = (pINF->Data[4] << 24) +
	        (pINF->Data[5] << 16) +
	        (pINF->Data[6] << 8) +
	         pINF->Data[7];

	// if it's the max value, not available
	if ( PSA_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  PSA-L     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  PSA-L     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_L );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF19_PSA_L = PSA_L;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( PSA_L == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 PSA-L must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			if ( PSA_L == PSA_R )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 PSA-L must not be equal to PSA-R\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			if ( PSA_L <= Test_5_16_INF[EcuIdx].INF19_PSA_L )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 PSA-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF19_PSA_L );
				eRetCode = FAIL;
			}
		}
	}


	// log IPSA_R
	IPSA_R = (pINF->Data[8] << 24) +
	         (pINF->Data[9] << 16) +
	         (pINF->Data[10] << 8) +
	          pINF->Data[11];

	// if it's the max value, not available
	if ( IPSA_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  IPSA-R    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  IPSA-R    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( IPSA_R == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 IPSA-R must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          IPSA_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F819 IPSA-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log IPSA_L
	IPSA_L = (pINF->Data[12] << 24) +
	         (pINF->Data[13] << 16) +
	         (pINF->Data[14] << 8) +
	          pINF->Data[15];

	// if it's the max value, not available
	if ( IPSA_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  IPSA-L    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  IPSA-L    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_L );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF19_IPSA_L = IPSA_L;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( IPSA_L == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 IPSA-L must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			if ( IPSA_L == PSA_R )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 IPSA-L must not be equal to IPSA-R\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			if ( IPSA_L <= Test_5_16_INF[EcuIdx].INF19_IPSA_L )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 IPSA-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF19_IPSA_L );
				eRetCode = FAIL;
			}
		}
	}


	// log CPSA_R
	CPSA_R = (pINF->Data[16] << 24) +
	         (pINF->Data[17] << 16) +
	         (pINF->Data[18] << 8) +
	          pINF->Data[19];

	// if it's the max value, not available
	if ( CPSA_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  CPSA-R    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  CPSA-R    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      CPSA_R );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF19_CPSA_R = CPSA_R;  // Save value for comaparison in Test 9.18

			if ( CPSA_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 CPSA-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF19_CPSA_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( CPSA_R == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 CPSA-R must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
			}

			if ( CPSA_R <= Test_5_16_INF[EcuIdx].INF19_CPSA_R )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 CPSA-R must return a value greater than the value returned in Test 5.16 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF19_CPSA_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 &&  // IF Test 9.19
		          CPSA_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F819 CPSA-R must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log CPSA_L
	CPSA_L = (pINF->Data[20] << 24) +
	         (pINF->Data[21] << 16) +
	         (pINF->Data[22] << 8) +
	          pINF->Data[23];

	// if it's the max value, not available
	if ( CPSA_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  CPSA-L    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F819  CPSA-L    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      CPSA_L );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
		{
			Test_5_16_INF[EcuIdx].INF19_CPSA_L = CPSA_L;  // Save value for comaparison in Test 9.18
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
		{
			if ( CPSA_L == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 CPSA-L must return a value greater than 0\n",
				      GetEcuId ( EcuIdx ) );
			}

			if ( CPSA_L == CPSA_R )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F818 CPSA-L must not be equal to CPSA-R\n",
				      GetEcuId ( EcuIdx ) );
			}

			if ( CPSA_L <= Test_5_16_INF[EcuIdx].INF19_CPSA_L )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F819 CPSA-L must return a value greater than the value returned in Test 5.16 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF19_CPSA_R );
				eRetCode = FAIL;
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF1AData
**
**  Purpose:   Verify the Plug-In Hybrid Vehicle Distance data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF1AData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double CDEODT_R;
	double CDEODT_L;
	double CDERDT_R;
	double CDERDT_L;
	double CIDT_R;
	double CIDT_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// PHEVDD Data must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CDEODT_R
	CDEODT_R = (double)((unsigned long)((pINF->Data[0] << 24) +
	                                    (pINF->Data[1] << 16) +
	                                    (pINF->Data[2] << 8) +
	                                     pINF->Data[3])) * 0.1;

	// if it's the max value, not available
	if ( CDEODT_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDEODT-R  not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDEODT-R  = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      CDEODT_R );

		if ( (geTestPhase == eTestNoDTC              && gTestSubsection == 16) || // IF Test 5.16
		     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19) )  // OR Test 9.19
		{
			if ( CDEODT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81A CDEODT-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CDEODT_L
	CDEODT_L = (double)((unsigned long)((pINF->Data[4] << 24) +
	                                    (pINF->Data[5] << 16) +
	                                    (pINF->Data[6] << 8) +
	                                     pINF->Data[7])) * 0.1;

	// if it's the max value, not available
	if ( CDEODT_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDEODT-L  not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDEODT-L  = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      CDEODT_L );
	}


	// log CDERDT_R
	CDERDT_R = (double)((unsigned long)((pINF->Data[8] << 24) +
	                                    (pINF->Data[9] << 16) +
	                                    (pINF->Data[10] << 8) +
	                                     pINF->Data[11])) * 0.1;

	// if it's the max value, not available
	if ( CDERDT_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDERDT-R  not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDERDT-R  = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      CDERDT_R );

		if ( (geTestPhase == eTestNoDTC              && gTestSubsection == 16) || // IF Test 5.16
		     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19) )  // OR Test 9.19
		{
			if ( CDERDT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81A CDERDT-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CDERDT_L
	CDERDT_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                    (pINF->Data[13] << 16) +
	                                    (pINF->Data[14] << 8) +
	                                     pINF->Data[15])) * 0.1;

	// if it's the max value, not available
	if ( CDERDT_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDERDT-L  not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CDERDT-L  = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      CDERDT_L );
	}

	// log CIDT_R
	CIDT_R = (double)((unsigned long)((pINF->Data[16] << 24) +
	                                  (pINF->Data[17] << 16) +
	                                  (pINF->Data[18] << 8) +
	                                   pINF->Data[19])) * 0.1;

	// if it's the max value, not available
	if ( CIDT_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CIDT-R   not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CIDT-R   = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      CIDT_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )   // IF Test 9.19
		{
			if ( CIDT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81A CIDT-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CIDT_L
	CIDT_L = (double)((unsigned long)((pINF->Data[20] << 24) +
	                                  (pINF->Data[21] << 16) +
	                                  (pINF->Data[22] << 8) +
	                                   pINF->Data[23])) * 0.1;

	// if it's the max value, not available
	if ( CIDT_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CIDT-L   not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81A  CIDT-L   = %.1f km\n",
		      GetEcuId ( EcuIdx ),
		      CIDT_L );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF1BData
**
**  Purpose:   Verify the Plug-In Hybrid Vehicle Fuel data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF1BData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double CDFC_R;
	double CDFC_L;
	double CIFC_R;
	double CIFC_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// PHEVFD Data must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CDFC_R
	CDFC_R = (double)((unsigned long)((pINF->Data[0] << 24) +
	                                  (pINF->Data[1] << 16) +
	                                  (pINF->Data[2] << 8) +
	                                   pINF->Data[3])) * 0.01;

	// if it's the max value, not available
	if ( CDFC_R == 42949672.95 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CDFC-R    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CDFC-R    = %.2f l\n",
		      GetEcuId ( EcuIdx ),
		      CDFC_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( CDFC_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81B CDFC-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CDFC_L
	CDFC_L = (double)((unsigned long)((pINF->Data[4] << 24) +
	                                  (pINF->Data[5] << 16) +
	                                  (pINF->Data[6] << 8) +
	                                   pINF->Data[7])) * 0.01;

	// if it's the max value, not available
	if ( CDFC_L == 42949672.95 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CDFC-L    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CDFC-L    = %.2f l\n",
		      GetEcuId ( EcuIdx ),
		      CDFC_L );
	}


	// log CIFC_R
	CIFC_R = (double)((unsigned long)((pINF->Data[8] << 24) +
	                                  (pINF->Data[9] << 16) +
	                                  (pINF->Data[10] << 8) +
	                                   pINF->Data[11])) * 0.01;

	// if it's the max value, not available
	if ( CIFC_R == 42949672.95 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CIFC-R    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CIFC-R    = %.2f l\n",
		      GetEcuId ( EcuIdx ),
		      CIFC_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( CIFC_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81B CIFC-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CIFC_L
	CIFC_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                  (pINF->Data[13] << 16) +
	                                  (pINF->Data[14] << 8) +
	                                   pINF->Data[15])) * 0.01;

	// if it's the max value, not available
	if ( CIFC_L == 42949672.95 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CIFC-L    not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81B  CIFC-L    = %.2f l\n",
		      GetEcuId ( EcuIdx ),
		      CIFC_L );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF1CData
**
**  Purpose:   Verify the Plug-In Hybrid Vehicle Grid data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF1CData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double CDEOGE_R;
	double CDEOGE_L;
	double CDERGE_R;
	double CDERGE_L;
	double GE_R;
	double GE_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// PHEVGD Data must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CDEOGE_R
	CDEOGE_R = (double)((unsigned long)((pINF->Data[0] << 24) +
	                                    (pINF->Data[1] << 16) +
	                                    (pINF->Data[2] << 8) +
	                                     pINF->Data[3])) * 0.1;

	// if it's the max value, not available
	if ( CDEOGE_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDEOGE-R not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDEOGE-R = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDEOGE_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if (CDEOGE_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81C CDEOGE-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CDEOGE_L
	CDEOGE_L = (double)((unsigned long)((pINF->Data[4] << 24) +
	                                    (pINF->Data[5] << 16) +
	                                    (pINF->Data[6] << 8) +
	                                     pINF->Data[7])) * 0.1;

	// if it's the max value, not available
	if ( CDEOGE_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDEOGE-L not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDEOGE-L = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDEOGE_L );
	}


	// log CDERGE_R
	CDERGE_R = (double)((unsigned long)((pINF->Data[8] << 24) +
	                                    (pINF->Data[9] << 16) +
	                                    (pINF->Data[10] << 8) +
	                                     pINF->Data[11])) * 0.1;

	// if it's the max value, not available
	if ( CDERGE_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDERGE-R not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDERGE-R = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDERGE_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( CDERGE_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81C CDERGE-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log CDERGE_L
	CDERGE_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                    (pINF->Data[13] << 16) +
	                                    (pINF->Data[14] << 8) +
	                                     pINF->Data[15])) * 0.1;

	// if it's the max value, not available
	if ( CDERGE_L == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDERGE-L not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  CDERGE-L = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDERGE_L );
	}

	// log GE_R
	GE_R = (double)((unsigned long)((pINF->Data[16] << 24) +
	                                (pINF->Data[17] << 16) +
	                                (pINF->Data[18] << 8) +
	                                 pINF->Data[19])) * 0.1;

	// if it's the max value, not available
	if ( GE_R == 429496729.5 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  GE-R     not available\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  GE-R     = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      GE_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // OR Test 9.19
		{
			if ( GE_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81C GE-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log GE_L
	GE_L = (double)((unsigned long)((pINF->Data[20] << 24) +
	                                (pINF->Data[21] << 16) +
	                                (pINF->Data[22] << 8) +
	                                 pINF->Data[23])) * 0.1;

	// if it's the max value, not available
	if ( GE_L == 429496729.5 )
	{
		if ( gstUserInput.ePwrTrnType == PHEV &&
		     gstUserInput.eComplianceType == EOBD )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F81C  GE-L     not supported\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F81C  GE-L     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81C  GE-L     = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      GE_L );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF1DData
**
**  Purpose:   Verify the Active Aerodynamic Features #1 Off-Cycle Credit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF1DData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long AGSA_TIME1_R;
	unsigned long AGSA_TIME2_R;
	unsigned long AGSA_TIME1_L;
	unsigned long AGSA_TIME2_L;
	unsigned long AGSB_TIME1_R;
	unsigned long AGSB_TIME2_R;
	unsigned long AGSB_TIME1_L;
	unsigned long AGSB_TIME2_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// AAF1OCCVD Data must contain 32 bytes of data
	if ( DataSize != 32 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  Data Size = %d (Must be 32 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log AGSA_TIME1_R
	AGSA_TIME1_R = (pINF->Data[0] << 24) +
	               (pINF->Data[1] << 16) +
	               (pINF->Data[2] << 8) +
	                pINF->Data[3];

	// if it's the max value, not available
	if ( AGSA_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AGSA_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81D AGSA_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AGSA_TIME2_R
	AGSA_TIME2_R = (pINF->Data[4] << 24) +
	               (pINF->Data[5] << 16) +
	               (pINF->Data[6] << 8) +
	                pINF->Data[7];

	// if it's the max value, not available
	if ( AGSA_TIME2_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME2-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME2-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME2_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AGSA_TIME2_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81D AGSA_TIME2-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AGSA_TIME1_L
	AGSA_TIME1_L = (pINF->Data[8] << 24) +
	               (pINF->Data[9] << 16) +
	               (pINF->Data[10] << 8) +
	                pINF->Data[11];

	// if it's the max value, not available
	if ( AGSA_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME1_L );
	}

	// log AGSA_TIME2_L
	AGSA_TIME2_L = (pINF->Data[12] << 24) +
	               (pINF->Data[13] << 16) +
	               (pINF->Data[14] << 8) +
	                pINF->Data[15];

	// if it's the max value, not available
	if ( AGSA_TIME2_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME2-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSA_TIME2-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME2_L );
	}


	// log AGSB_TIME1_R
	AGSB_TIME1_R = (pINF->Data[16] << 24) +
	               (pINF->Data[17] << 16) +
	               (pINF->Data[18] << 8) +
	                pINF->Data[19];

	// if it's the max value, not available
	if ( AGSB_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AGSB_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81D AGSB_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AGSB_TIME2_R
	AGSB_TIME2_R = (pINF->Data[20] << 24) +
	               (pINF->Data[21] << 16) +
	               (pINF->Data[22] << 8) +
	                pINF->Data[23];

	// if it's the max value, not available
	if ( AGSB_TIME2_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME2-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME2-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME2_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AGSB_TIME2_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81D AGSB_TIME2-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AGSB_TIME1_L
	AGSB_TIME1_L = (pINF->Data[24] << 24) +
	               (pINF->Data[25] << 16) +
	               (pINF->Data[26] << 8) +
	                pINF->Data[27];

	// if it's the max value, not available
	if ( AGSB_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME1_L );
	}

	// log AGSB_TIME2_L
	AGSB_TIME2_L = (pINF->Data[28] << 24) +
	               (pINF->Data[29] << 16) +
	               (pINF->Data[30] << 8) +
	                pINF->Data[31];

	// if it's the max value, not available
	if ( AGSB_TIME2_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME2-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D  AGSB_TIME2-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME2_L );
	}

	if ( NotAvailableCount == 8 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81D All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF1EData
**
**  Purpose:   Verify the ctive Aerodynamic Features #2 Off-Cycle Credit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF1EData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long VRHC_TIME1_R;
	unsigned long VRHC_TIME2_R;
	unsigned long VRHC_TIME1_L;
	unsigned long VRHC_TIME2_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// AAF2OCCVD Data must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log VRHC_TIME1_R
	VRHC_TIME1_R = (pINF->Data[0] << 24) +
	               (pINF->Data[1] << 16) +
	               (pINF->Data[2] << 8) +
	                pINF->Data[3];

	// if it's the max value, not available
	if ( VRHC_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( VRHC_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81E VRHC_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log VRHC_TIME2_R
	VRHC_TIME2_R = (pINF->Data[4] << 24) +
	               (pINF->Data[5] << 16) +
	               (pINF->Data[6] << 8) +
	                pINF->Data[7];

	// if it's the max value, not available
	if ( VRHC_TIME2_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME2-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME2-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME2_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( VRHC_TIME2_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81E VRHC_TIME2-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log VRHC_TIME1_L
	VRHC_TIME1_L = (pINF->Data[8] << 24) +
	               (pINF->Data[9] << 16) +
	               (pINF->Data[10] << 8) +
	                pINF->Data[11];

	// if it's the max value, not available
	if ( VRHC_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME1_L );
	}

	// log VRHC_TIME2_L
	VRHC_TIME2_L = (pINF->Data[12] << 24) +
	               (pINF->Data[13] << 16) +
	               (pINF->Data[14] << 8) +
	                pINF->Data[15];

	// if it's the max value, not available
	if ( VRHC_TIME2_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME2-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E  VRHC_TIME2-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME2_L );
	}

	if ( NotAvailableCount == 4 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81E All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF1FData
**
**  Purpose:   Verify the Active Aerodynamic Features #3 Off-Cycle Credit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF1FData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long AAF1_TIME1_R;
	unsigned long AAF1_TIME2_R;
	unsigned long AAF1_TIME1_L;
	unsigned long AAF1_TIME2_L;
	unsigned long AAF2_TIME1_R;
	unsigned long AAF2_TIME2_R;
	unsigned long AAF2_TIME1_L;
	unsigned long AAF2_TIME2_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// AAF3OCCVD Data must contain 32 bytes of data
	if ( DataSize != 32 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  Data Size = %d (Must be 32 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log AAF1_TIME1_R
	AAF1_TIME1_R = (pINF->Data[0] << 24) +
	               (pINF->Data[1] << 16) +
	               (pINF->Data[2] << 8) +
	                pINF->Data[3];

	// if it's the max value, not available
	if ( AAF1_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AAF1_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81F AAF1_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AAF1_TIME2_R
	AAF1_TIME2_R = (pINF->Data[4] << 24) +
	               (pINF->Data[5] << 16) +
	               (pINF->Data[6] << 8) +
	                pINF->Data[7];

	// if it's the max value, not available
	if ( AAF1_TIME2_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME2-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME2-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME2_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AAF1_TIME2_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81F AAF1_TIME2-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AAF1_TIME1_L
	AAF1_TIME1_L = (pINF->Data[8] << 24) +
	               (pINF->Data[9] << 16) +
	               (pINF->Data[10] << 8) +
	                pINF->Data[11];

	// if it's the max value, not available
	if ( AAF1_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME1_L );
	}

	// log AAF1_TIME2_L
	AAF1_TIME2_L = (pINF->Data[12] << 24) +
	               (pINF->Data[13] << 16) +
	               (pINF->Data[14] << 8) +
	                pINF->Data[15];

	// if it's the max value, not available
	if ( AAF1_TIME2_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME2-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF1_TIME2-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME2_L );
	}


	// log AAF2_TIME1_R
	AAF2_TIME1_R = (pINF->Data[16] << 24) +
	               (pINF->Data[17] << 16) +
	               (pINF->Data[18] << 8) +
	                pINF->Data[19];

	// if it's the max value, not available
	if ( AAF2_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AAF2_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81F AAF2_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AAF2_TIME2_R
	AAF2_TIME2_R = (pINF->Data[20] << 24) +
	               (pINF->Data[21] << 16) +
	               (pINF->Data[22] << 8) +
	                pINF->Data[23];

	// if it's the max value, not available
	if ( AAF2_TIME2_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME2-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME2-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME2_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( AAF2_TIME2_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F81F AAF2_TIME2-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log AAF2_TIME1_L
	AAF2_TIME1_L = (pINF->Data[24] << 24) +
	               (pINF->Data[25] << 16) +
	               (pINF->Data[26] << 8) +
	                pINF->Data[27];

	// if it's the max value, not available
	if ( AAF2_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME1_L );
	}

	// log AAF2_TIME2_L
	AAF2_TIME2_L = (pINF->Data[28] << 24) +
	               (pINF->Data[29] << 16) +
	               (pINF->Data[30] << 8) +
	                pINF->Data[31];

	// if it's the max value, not available
	if ( AAF2_TIME2_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME2-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F  AAF2_TIME2-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME2_L );
	}

	if ( NotAvailableCount == 8 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F81F All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF21Data
**
**  Purpose:   Verify the Driver Selectable Operating Modes Off-Cycle Credit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF21Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long EDSM_TIME1_R;
	unsigned long EDSM_TIME1_L;
	unsigned long DSM1_TIME1_R;
	unsigned long DSM1_TIME1_L;
	unsigned long DSM2_TIME1_R;
	unsigned long DSM2_TIME1_L;
	unsigned long DSM3_TIME1_R;
	unsigned long DSM3_TIME1_L;
	unsigned long DSM4_TIME1_R;
	unsigned long DSM4_TIME1_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// DSOMOCCVD Data must contain 40 bytes of data
	if ( DataSize != 40 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  Data Size = %d (Must be 40 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log EDSM_TIME1_R
	EDSM_TIME1_R = (pINF->Data[0] << 24) +
	               (pINF->Data[1] << 16) +
	               (pINF->Data[2] << 8) +
	                pINF->Data[3];

	// if it's the max value, not available
	if ( EDSM_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  EDSM_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  EDSM_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( EDSM_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F821 EDSM_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log EDSM_TIME1_L
	EDSM_TIME1_L = (pINF->Data[4] << 24) +
	               (pINF->Data[5] << 16) +
	               (pINF->Data[6] << 8) +
	                pINF->Data[7];

	// if it's the max value, not available
	if ( EDSM_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  EDSM_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  EDSM_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME1_L );
	}


	// log DSM1_TIME1_R
	DSM1_TIME1_R = (pINF->Data[8] << 24) +
	               (pINF->Data[9] << 16) +
	               (pINF->Data[10] << 8) +
	                pINF->Data[11];

	// if it's the max value, not available
	if ( DSM1_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM1_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM1_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM1_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DSM1_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F821 DSM1_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DSM1_TIME1_L
	DSM1_TIME1_L = (pINF->Data[12] << 24) +
	               (pINF->Data[13] << 16) +
	               (pINF->Data[14] << 8) +
	                pINF->Data[15];

	// if it's the max value, not available
	if ( DSM1_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM1_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM1_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM1_TIME1_L );
	}


	// log DSM2_TIME1_R
	DSM2_TIME1_R = (pINF->Data[16] << 24) +
	               (pINF->Data[17] << 16) +
	               (pINF->Data[18] << 8) +
	                pINF->Data[19];

	// if it's the max value, not available
	if ( DSM2_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM2_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM2_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM2_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DSM2_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F821 DSM2_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DSM2_TIME1_L
	DSM2_TIME1_L = (pINF->Data[20] << 24) +
	               (pINF->Data[21] << 16) +
	               (pINF->Data[22] << 8) +
	                pINF->Data[23];

	// if it's the max value, not available
	if ( DSM2_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM2_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM2_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM2_TIME1_L );
	}


	// log DSM3_TIME1_R
	DSM3_TIME1_R = (pINF->Data[24] << 24) +
	               (pINF->Data[25] << 16) +
	               (pINF->Data[26] << 8) +
	                pINF->Data[27];

	// if it's the max value, not available
	if ( DSM3_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM3_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM3_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM3_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DSM3_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F821 DSM3_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DSM3_TIME1_L
	DSM3_TIME1_L = (pINF->Data[28] << 24) +
	               (pINF->Data[29] << 16) +
	               (pINF->Data[30] << 8) +
	                pINF->Data[31];

	// if it's the max value, not available
	if ( DSM3_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM3_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM3_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM3_TIME1_L );
	}


	// log DSM4_TIME1_R
	DSM4_TIME1_R = (pINF->Data[32] << 24) +
	               (pINF->Data[33] << 16) +
	               (pINF->Data[34] << 8) +
	                pINF->Data[35];

	// if it's the max value, not available
	if ( DSM4_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM4_TIME1-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM4_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM4_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DSM4_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F821 DSM4_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DSM4_TIME1_L
	DSM4_TIME1_L = (pINF->Data[36] << 24) +
	               (pINF->Data[37] << 16) +
	               (pINF->Data[38] << 8) +
	                pINF->Data[39];

	// if it's the max value, not available
	if ( DSM4_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM4_TIME1-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821  DSM4_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM4_TIME1_L );
	}

	if ( NotAvailableCount == 10 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F821 All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF22Data
**
**  Purpose:   Verify the Run Time For Stop-Start and Coasting Off-Cylce Credit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF22Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long ISS_TIME1_R;
	unsigned long ISS_TIME1_L;
	unsigned long ERC_TIME1_R;
	unsigned long ERC_TIME1_L;
	unsigned long EOC_TIME1_R;
	unsigned long EOC_TIME1_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// RTSSCOCCVD Data must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log ISS_TIME1_R
	ISS_TIME1_R = (pINF->Data[0] << 24) +
	              (pINF->Data[1] << 16) +
	              (pINF->Data[2] << 8) +
	               pINF->Data[3];

	// if it's the max value, not available
	if ( ISS_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ISS_TIME1-R  not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ISS_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ISS_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( ISS_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F822 ISS_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log ISS_TIME1_L
	ISS_TIME1_L = (pINF->Data[4] << 24) +
	              (pINF->Data[5] << 16) +
	              (pINF->Data[6] << 8) +
	               pINF->Data[7];

	// if it's the max value, not available
	if ( ISS_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ISS_TIME1-L  not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ISS_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ISS_TIME1_L );
	}


	// log ERC_TIME1_R
	ERC_TIME1_R = (pINF->Data[8] << 24) +
	              (pINF->Data[9] << 16) +
	              (pINF->Data[10] << 8) +
	               pINF->Data[11];

	// if it's the max value, not available
	if ( ERC_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ERC_TIME1-R  not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ERC_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERC_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( ERC_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F822 ERC_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log ERC_TIME1_L
	ERC_TIME1_L = (pINF->Data[12] << 24) +
	              (pINF->Data[13] << 16) +
	              (pINF->Data[14] << 8) +
	               pINF->Data[15];

	// if it's the max value, not available
	if ( ERC_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ERC_TIME1-L  not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  ERC_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERC_TIME1_L );
	}


	// log EOC_TIME1_R
	EOC_TIME1_R = (pINF->Data[16] << 24) +
	              (pINF->Data[17] << 16) +
	              (pINF->Data[18] << 8) +
	               pINF->Data[19];

	// if it's the max value, not available
	if ( EOC_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  EOC_TIME1-R  not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  EOC_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EOC_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( EOC_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F822 EOC_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log EOC_TIME1_L
	EOC_TIME1_L = (pINF->Data[20] << 24) +
	              (pINF->Data[21] << 16) +
	              (pINF->Data[22] << 8) +
	               pINF->Data[23];

	// if it's the max value, not available
	if ( EOC_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  EOC_TIME1-L  not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822  EOC_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EOC_TIME1_L );
	}

	if ( NotAvailableCount == 6 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F822 All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF23Data
**
**  Purpose:   Verify the Drive Coaching Technology Off-Cycle Credit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF23Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long DCTE1_CNTS_R;
	unsigned long DCTU1_CNTS_R;
	unsigned long DCTE1_CNTS_L;
	unsigned long DCTU1_CNTS_L;
	unsigned long DCTE2_CNTS_R;
	unsigned long DCTU2_CNTS_R;
	unsigned long DCTE2_CNTS_L;
	unsigned long DCTU2_CNTS_L;
	unsigned long DCTE3_CNTS_R;
	unsigned long DCTU3_CNTS_R;
	unsigned long DCTE3_CNTS_L;
	unsigned long DCTU3_CNTS_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// DCTOCCVD Data must contain 48 bytes of data
	if ( DataSize != 48 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  Data Size = %d (Must be 48 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log DCTE1_CNTS_R
	DCTE1_CNTS_R = (pINF->Data[0] << 24) +
	               (pINF->Data[1] << 16) +
	               (pINF->Data[2] << 8) +
	                pINF->Data[3];

	// if it's the max value, not available
	if ( DCTE1_CNTS_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE1_CNTS-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE1_CNTS-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE1_CNTS_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DCTE1_CNTS_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F823 DCTE1_CNTS-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DCTU1_CNTS_R
	DCTU1_CNTS_R = (pINF->Data[4] << 24) +
	               (pINF->Data[5] << 16) +
	               (pINF->Data[6] << 8) +
	                pINF->Data[7];

	// if it's the max value, not available
	if ( DCTU1_CNTS_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU1_CNTS-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU1_CNTS-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU1_CNTS_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DCTU1_CNTS_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F823 DCTU1_CNTS-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DCTE1_CNTS_L
	DCTE1_CNTS_L = (pINF->Data[8] << 24) +
	               (pINF->Data[9] << 16) +
	               (pINF->Data[10] << 8) +
	                pINF->Data[11];

	// if it's the max value, not available
	if ( DCTE1_CNTS_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE1_CNTS-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE1_CNTS-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE1_CNTS_L );
	}

	// log DCTU1_CNTS_L
	DCTU1_CNTS_L = (pINF->Data[12] << 24) +
	               (pINF->Data[13] << 16) +
	               (pINF->Data[14] << 8) +
	                pINF->Data[15];

	// if it's the max value, not available
	if ( DCTU1_CNTS_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU1_CNTS-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU1_CNTS-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU1_CNTS_L );
	}


	// log DCTE1_CNTS_R
	DCTE2_CNTS_R = (pINF->Data[16] << 24) +
	               (pINF->Data[17] << 16) +
	               (pINF->Data[18] << 8) +
	                pINF->Data[19];

	// if it's the max value, not available
	if ( DCTE2_CNTS_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE2_CNTS-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE2_CNTS-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE2_CNTS_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DCTE2_CNTS_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F823 DCTE2_CNTS-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DCTU2_CNTS_R
	DCTU2_CNTS_R = (pINF->Data[20] << 24) +
	               (pINF->Data[21] << 16) +
	               (pINF->Data[22] << 8) +
	                pINF->Data[23];

	// if it's the max value, not available
	if ( DCTU2_CNTS_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU2_CNTS-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU2_CNTS-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU2_CNTS_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DCTU2_CNTS_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F823 DCTU2_CNTS-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DCTE2_CNTS_L
	DCTE2_CNTS_L = (pINF->Data[24] << 24) +
	               (pINF->Data[25] << 16) +
	               (pINF->Data[26] << 8) +
	                pINF->Data[27];

	// if it's the max value, not available
	if ( DCTE2_CNTS_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE2_CNTS-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE2_CNTS-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE2_CNTS_L );
	}

	// log DCTU2_CNTS_L
	DCTU2_CNTS_L = (pINF->Data[28] << 24) +
	               (pINF->Data[29] << 16) +
	               (pINF->Data[30] << 8) +
	                pINF->Data[31];

	// if it's the max value, not available
	if ( DCTU2_CNTS_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU2_CNTS-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU2_CNTS-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU2_CNTS_L );
	}


	// log DCTE3_CNTS_R
	DCTE3_CNTS_R = (pINF->Data[32] << 24) +
	               (pINF->Data[33] << 16) +
	               (pINF->Data[34] << 8) +
	                pINF->Data[35];

	// if it's the max value, not available
	if ( DCTE3_CNTS_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE3_CNTS-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE3_CNTS-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE3_CNTS_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DCTE3_CNTS_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F823 DCTE3_CNTS-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DCTU3_CNTS_R
	DCTU3_CNTS_R = (pINF->Data[36] << 24) +
	               (pINF->Data[37] << 16) +
	               (pINF->Data[38] << 8) +
	                pINF->Data[39];

	// if it's the max value, not available
	if ( DCTU3_CNTS_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU3_CNTS-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU3_CNTS-R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU3_CNTS_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( DCTU3_CNTS_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F823 DCTU3_CNTS-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log DCTE3_CNTS_L
	DCTE3_CNTS_L = (pINF->Data[40] << 24) +
	               (pINF->Data[41] << 16) +
	               (pINF->Data[42] << 8) +
	                pINF->Data[43];

	// if it's the max value, not available
	if ( DCTE3_CNTS_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE3_CNTS-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTE3_CNTS-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE3_CNTS_L );
	}

	// log DCTU3_CNTS_L
	DCTU3_CNTS_L = (pINF->Data[44] << 24) +
	               (pINF->Data[45] << 16) +
	               (pINF->Data[46] << 8) +
	                pINF->Data[47];

	// if it's the max value, not available
	if ( DCTU3_CNTS_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU3_CNTS-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F823  DCTU3_CNTS-L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU3_CNTS_L );
	}

	if ( NotAvailableCount == 12 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824 All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF24Data
**
**  Purpose:   Verify the Active Powertrain Warm-Up Features Off-CycleCredit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF24Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long EWU_TIME_R;
	unsigned long EWU_TIME_L;
	unsigned long TWU_TIME_R;
	unsigned long TWU_TIME_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// APTWUFOCCVD Data must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log EWU_TIME_R
	EWU_TIME_R = (pINF->Data[0] << 24) +
	             (pINF->Data[1] << 16) +
	             (pINF->Data[2] << 8) +
	              pINF->Data[3];

	// if it's the max value, not available
	if ( EWU_TIME_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $2F84  EWU_TIME-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  EWU_TIME-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EWU_TIME_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( EWU_TIME_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F824 EWU_TIME-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log EWU_TIME_L
	EWU_TIME_L = (pINF->Data[4] << 24) +
	             (pINF->Data[5] << 16) +
	             (pINF->Data[6] << 8) +
	              pINF->Data[7];

	// if it's the max value, not available
	if ( EWU_TIME_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  EWU_TIME-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  EWU_TIME-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EWU_TIME_L );
	}



	// log TWU_TIME_R
	TWU_TIME_R = (pINF->Data[8] << 24) +
	             (pINF->Data[9] << 16) +
	             (pINF->Data[10] << 8) +
	              pINF->Data[11];

	// if it's the max value, not available
	if ( TWU_TIME_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  TWU_TIME-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  TWU_TIME-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      TWU_TIME_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( TWU_TIME_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F824 TWU_TIME-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log TWU_TIME_L
	TWU_TIME_L = (pINF->Data[12] << 24) +
	             (pINF->Data[13] << 16) +
	             (pINF->Data[14] << 8) +
	              pINF->Data[15];

	// if it's the max value, not available
	if ( TWU_TIME_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  TWU_TIME-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824  TWU_TIME-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      TWU_TIME_L );
	}

	if ( NotAvailableCount == 4 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F824 All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF25Data
**
**  Purpose:   Verify the Off-Cycle Credit Technology Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF25_29Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long OCCT_TIME1_R;
	unsigned long OCCT_TIME2_R;
	unsigned long OCCT_TIME1_L;
	unsigned long OCCT_TIME2_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	// log OCCT_TIME1_R
	OCCT_TIME1_R = (pINF->Data[0] << 24) +
	               (pINF->Data[1] << 16) +
	               (pINF->Data[2] << 8) +
	                pINF->Data[3];

	// if it's the max value, not available
	if ( OCCT_TIME1_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%dT1-R not available\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24 );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%d_TIME1-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24,
		      OCCT_TIME1_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( OCCT_TIME1_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F8%02X OCCT%d_TIME1-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ),
				      pINF->INFLSB,
				      pINF->INFLSB - 24 );
				eRetCode = FAIL;
			}
		}
	}


	// log OCCT_TIME2_R
	OCCT_TIME2_R = (pINF->Data[4] << 24) +
	               (pINF->Data[5] << 16) +
	               (pINF->Data[6] << 8) +
	                pINF->Data[7];

	// if it's the max value, not available
	if ( OCCT_TIME2_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%dT2-R not available\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24 );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%d_TIME2-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24,
		      OCCT_TIME2_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( OCCT_TIME2_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F8%02X OCCT%d_TIME2-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ),
				      pINF->INFLSB,
				      pINF->INFLSB - 24 );
				eRetCode = FAIL;
			}
		}
	}

	// log OCCT_TIME1_L
	OCCT_TIME1_L = (pINF->Data[8] << 24) +
	               (pINF->Data[9] << 16) +
	               (pINF->Data[10] << 8) +
	                pINF->Data[11];

	// if it's the max value, not available
	if ( OCCT_TIME1_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%dT1-L not available\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24 );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%d_TIME1-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24,
		      OCCT_TIME1_L );
	}

	// log OCCT_TIME2_L
	OCCT_TIME2_L = (pINF->Data[12] << 24) +
	               (pINF->Data[13] << 16) +
	               (pINF->Data[14] << 8) +
	                pINF->Data[15];

	// if it's the max value, not available
	if ( OCCT_TIME2_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%dT2-L not available\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24 );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  OCCT%dT2-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      pINF->INFLSB - 24,
		      OCCT_TIME2_L );
	}

	if ( NotAvailableCount == 4 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF2AData
**
**  Purpose:   Verify the Active Powertrain Warm-Up Features Off-CycleCredit Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF2AData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;
	BYTE    NotAvailableCount = 0;

	unsigned long EDSM_TIME_E_R;
	unsigned long EDSM_TIME_E_L;
	unsigned long EDSM_TIME_A_R;
	unsigned long EDSM_TIME_A_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// APTWUFOCCVD Data must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	// log EWU_TIME_R
	EDSM_TIME_E_R = (pINF->Data[0] << 24) +
	                (pINF->Data[1] << 16) +
	                (pINF->Data[2] << 8) +
	                 pINF->Data[3];

	// if it's the max value, not available
	if ( EDSM_TIME_E_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  OEDSM_TIME_E-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_E_R-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME_E_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( EDSM_TIME_E_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F82A EDSM_TIME_E-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log EWU_TIME_L
	EDSM_TIME_E_L = (pINF->Data[4] << 24) +
	                (pINF->Data[5] << 16) +
	                (pINF->Data[6] << 8) +
	                 pINF->Data[7];

	// if it's the max value, not available
	if ( EDSM_TIME_E_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_E-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_E_L-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME_E_L );
	}


	// log TWU_TIME_R
	EDSM_TIME_A_R = (pINF->Data[8] << 24) +
	             (pINF->Data[9] << 16) +
	             (pINF->Data[10] << 8) +
	              pINF->Data[11];

	// if it's the max value, not available
	if ( EDSM_TIME_A_R == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_A-R not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_A-R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME_A_R );

		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
		{
			if ( EDSM_TIME_A_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F82A EDSM_TIME_A-R must return a value of 0 after a SID $14 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}

	// log TWU_TIME_L
	EDSM_TIME_A_L = (pINF->Data[12] << 24) +
	             (pINF->Data[13] << 16) +
	             (pINF->Data[14] << 8) +
	              pINF->Data[15];

	// if it's the max value, not available
	if ( EDSM_TIME_A_L == 4294967295 )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_A-L not available\n",
		      GetEcuId ( EcuIdx ) );
		NotAvailableCount++;
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A  EDSM_TIME_A-L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME_A_L );
	}

	if ( NotAvailableCount == 4 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F82A All Timers report Not Available\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF41_43_45Data
**
**  Purpose:   Verify the Engine Run Time / Distance Traveled / Engine Output Energy / Vehicle Fuel Consumption data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF41_43_45Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long ERT;
	double        DT;
	double        EOE;
	double        VFC;
	char          Letter;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $41 and $43 must contain 8 bytes of data
	if ( (pINF->INFLSB == 0x41 || pINF->INFLSB == 0x43 ) &&
	     DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}
	// INF $45 must contain 16 bytes of data
	else if ( pINF->INFLSB == 0x45 &&
	          DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F845  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	switch ( pINF->INFLSB )
	{
		case 0x41:
		{
			Letter = 'A';
		}
		break;
		case 0x43:
		{
			Letter = 'S';
		}
		break;
		case 0x45:
		{
			Letter = 'L';
		}
		break;
		default:
		{
			Letter = '-';
		}
	}


	// log ERT
	if ( pINF->INFLSB == 0x45 )
	{
		ERT = ((pINF->Data[0] << 24) +
		       (pINF->Data[1] << 16) +
		       (pINF->Data[2] << 8) +
		        pINF->Data[3]) * 10;
	}
	else
	{
		ERT = ((pINF->Data[0] << 8) +
		        pINF->Data[1]) * 10;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  ERT-%c =  %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      ERT );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x41 )
		{
			Test_5_16_INF[EcuIdx].INF41_ERT_A = ERT;

			if ( ERT <= 1 )
			{
				if ( gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F841 ERT-A must return a value of greater than 1 sec\n",
					      GetEcuId ( EcuIdx ) );
				}
				else
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F841 ERT-A must return a value of greater than 1 sec\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
		}
		else if ( pINF->INFLSB == 0x45 &&
		          gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV &&
		          ERT < Test_5_16_INF[EcuIdx].INF41_ERT_A )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F845 ERT-L must return a value of greater than ERT-A (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_16_INF[EcuIdx].INF41_ERT_A );
			eRetCode = FAIL;
		}
	}


	// log DT
	if ( pINF->INFLSB == 0x45 )
	{
		DT = (double)((unsigned long)((pINF->Data[4] << 24) +
		                              (pINF->Data[5] << 16) +
		                              (pINF->Data[6] << 8) +
		                               pINF->Data[7])) * .25;
	}
	else
	{
		DT = (double)((unsigned short)((pINF->Data[2] << 8) +
		                                pINF->Data[3])) * .25;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  DT-%c  =  %10.2f km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      DT );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x41 )
		{
			Test_5_16_INF[EcuIdx].INF41_DT_A = DT;
		}
		else if ( pINF->INFLSB == 0x43 )
		{
			Test_5_16_INF[EcuIdx].INF43_DT_S = DT;
		}
		else if ( pINF->INFLSB == 0x45 )
		{
			if ( gstUserInput.ePwrTrnType != PHEV &&
			     DT < Test_5_16_INF[EcuIdx].INF41_DT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F845 DT-L must return a value of greater than DT-A (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF41_DT_A );
				eRetCode = FAIL;
			}
		}
	}
	else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
	{
		if ( ( pINF->INFLSB == 0x41 && DT <= Test_5_16_INF[EcuIdx].INF41_DT_A ) ||
		     ( pINF->INFLSB == 0x43 && DT <= Test_5_16_INF[EcuIdx].INF43_DT_S ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F804X DT-%c must return a value of greater than in Test 5.16 (%.2f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      Letter,
			      pINF->INFLSB == 0x41 ? Test_5_16_INF[EcuIdx].INF41_DT_A : Test_5_16_INF[EcuIdx].INF43_DT_S );
			eRetCode = FAIL;
		}
	}


	// log EOE
	if ( pINF->INFLSB == 0x45 )
	{
		EOE = (double)((unsigned long)((pINF->Data[8] << 24) +
		                               (pINF->Data[9] << 16) +
		                               (pINF->Data[10] << 8) +
		                                pINF->Data[11])) * .001;
	}
	else
	{
		EOE = (double)((unsigned short)((pINF->Data[4] << 8) +
		                                 pINF->Data[5])) * .001;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  EOE-%c = %11.3f MWh\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      EOE );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x41 )
		{
			Test_5_16_INF[EcuIdx].INF41_EOE_A = EOE;
		}
		else if ( pINF->INFLSB == 0x43 )
		{
			Test_5_16_INF[EcuIdx].INF43_EOE_S = EOE;
		}
		else if ( pINF->INFLSB == 0x45 )
		{
			if ( gstUserInput.ePwrTrnType != PHEV &&
			     EOE < Test_5_16_INF[EcuIdx].INF41_EOE_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F845 EOE-L must return a value of greater than EOE-A\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}
	else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
	{
		if ( ( pINF->INFLSB == 0x41 && EOE <= Test_5_16_INF[EcuIdx].INF41_EOE_A ) ||
		     ( pINF->INFLSB == 0x43 && EOE <= Test_5_16_INF[EcuIdx].INF43_EOE_S ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X EOE-%c must return a value of greater than in Test 5.16 (%.3f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      Letter,
			      pINF->INFLSB == 0x41 ? Test_5_16_INF[EcuIdx].INF41_EOE_A : Test_5_16_INF[EcuIdx].INF43_EOE_S );
			eRetCode = FAIL;
		}
	}


	// log VFC
	if ( pINF->INFLSB == 0x45 )
	{
		VFC = (double)((unsigned long)((pINF->Data[12] << 24) +
		                               (pINF->Data[13] << 16) +
		                               (pINF->Data[14] << 8) +
		                                pINF->Data[15])) * .5;
	}
	else
	{
		VFC = (double)((unsigned short)((pINF->Data[6] << 8) +
		                                 pINF->Data[7])) * .5;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  VFC-%c =  %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      VFC );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x41 )
		{
			Test_5_16_INF[EcuIdx].INF41_VFC_A = VFC;
		}
		else if ( pINF->INFLSB == 0x43 )
		{
			Test_5_16_INF[EcuIdx].INF43_VFC_S = VFC;
		}
		else if ( pINF->INFLSB == 0x45 )
		{
			if ( VFC == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F841 VFC-L must return a value of greater than 0\n",
				      GetEcuId ( EcuIdx ) );
			}

			if ( gstUserInput.ePwrTrnType != PHEV &&
			     VFC < Test_5_16_INF[EcuIdx].INF41_VFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F845 VFC-L must return a value of greater than VFC-A\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
	}
	else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
	{
		if ( ( pINF->INFLSB == 0x41 && VFC <= Test_5_16_INF[EcuIdx].INF41_VFC_A ) ||
		     ( pINF->INFLSB == 0x43 && VFC <= Test_5_16_INF[EcuIdx].INF43_VFC_S ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X VFC-%c must return a value of greater than in Test 5.16 (%.1f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      Letter,
			      pINF->INFLSB == 0x41 ? Test_5_16_INF[EcuIdx].INF41_VFC_A : Test_5_16_INF[EcuIdx].INF43_VFC_S );
			eRetCode = FAIL;
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF42_44_46Data
**
**  Purpose:   Verify the Engine Fuel Consumption / Idle Run Time /
**             Engine Idle Fuel Consumption / Urban Speed Run Time /
**             Positive Kinetic Energy Numerator / PTO Run Time /
**             PTO Fuel Consumption data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF42_44_46Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double        EFC;
	unsigned long IERT;
	double        IEFC;
	unsigned long UERT;
	unsigned long PKE;
	unsigned long PTOERT;
	double        PTOFC;
	char          Letter;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $42 and $44 must contain 16 bytes of data
	if ( (pINF->INFLSB == 0x42 || pINF->INFLSB == 0x44 ) &&
	     DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}
	// INF $46 must contain 28 bytes of data
	else if ( pINF->INFLSB == 0x46 &&
	          DataSize != 28 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F846  Data Size = %d (Must be 28 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}

	switch ( pINF->INFLSB )
	{
		case 0x42:
		{
			Letter = 'A';
		}
		break;
		case 0x44:
		{
			Letter = 'S';
		}
		break;
		case 0x46:
		{
			Letter = 'L';
		}
		break;
		default:
		{
			Letter = '-';
		}
	}

	// log EFC
	if ( pINF->INFLSB == 0x46 )
	{
		EFC = (double)((unsigned long)((pINF->Data[0] << 24) +
		                               (pINF->Data[1] << 16) +
		                               (pINF->Data[2] << 8) +
		                                pINF->Data[3])) * .5;
	}
	else
	{
		EFC = (double)((unsigned short)((pINF->Data[0] << 8) +
		                                 pINF->Data[1])) * .5;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  EFC-%c    = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      EFC );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x42 )
		{
			Test_5_16_INF[EcuIdx].INF42_EFC_A = EFC;
		}
		else if ( pINF->INFLSB == 0x44 )
		{
			Test_5_16_INF[EcuIdx].INF44_EFC_S = EFC;
		}
		else if ( pINF->INFLSB == 0x46 )
		{
			if ( EFC == 0 )
			{
				if ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F842 EFC-L must return a value of greater than 0\n",
					      GetEcuId ( EcuIdx ) );
				}
			}

			if ( gstUserInput.ePwrTrnType != PHEV &&
			     EFC < Test_5_16_INF[EcuIdx].INF42_EFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 EFC-L must return a value of greater than EFC-A (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_EFC_A );
				eRetCode = FAIL;
			}
		}
	}
	else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 19 )  // IF Test 9.19
	{
		if ( gstUserInput.ePwrTrnType != PHEV &&
		     ( ( pINF->INFLSB == 0x42 && EFC <= Test_5_16_INF[EcuIdx].INF42_EFC_A ) ||
		       ( pINF->INFLSB == 0x44 && EFC <= Test_5_16_INF[EcuIdx].INF44_EFC_S ) ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X EFC-%c must return a value of greater than in Test 5.16 (%d)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      Letter,
			      pINF->INFLSB == 0x41 ? Test_5_16_INF[EcuIdx].INF42_EFC_A : Test_5_16_INF[EcuIdx].INF44_EFC_S );
			eRetCode = FAIL;
		}
		else if ( gstUserInput.ePwrTrnType == PHEV &&
		        ( ( pINF->INFLSB == 0x42 && EFC < Test_5_16_INF[EcuIdx].INF42_EFC_A ) ||
		          ( pINF->INFLSB == 0x44 && EFC < Test_5_16_INF[EcuIdx].INF44_EFC_S ) ) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X EFC-%c must return a value of greater than or equal to Test 5.16 (%d)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      Letter,
			      pINF->INFLSB == 0x41 ? Test_5_16_INF[EcuIdx].INF42_EFC_A : Test_5_16_INF[EcuIdx].INF44_EFC_S );
			eRetCode = FAIL;
		}
	}


	// log IERT
	if ( pINF->INFLSB == 0x46 )
	{
		IERT = (pINF->Data[4] << 24) +
		       (pINF->Data[5] << 16) +
		       (pINF->Data[6] << 8) +
		        pINF->Data[7];
	}
	else
	{
		IERT = ((pINF->Data[2] << 8) +
		         pINF->Data[3]) * 10;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  IERT-%c   = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      IERT );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x42 )
		{
			Test_5_16_INF[EcuIdx].INF42_IERT_A = IERT;

			if ( IERT == 0 )
			{
				if ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F842 IERT_A must return a value of greater than 0\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
		}
		else if ( pINF->INFLSB == 0x46 )
		{
			if ( IERT == 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F842 IERT-L must return a value of greater than 0\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}

			if ( gstUserInput.ePwrTrnType != PHEV &&
			     IERT < Test_5_16_INF[EcuIdx].INF42_IERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 IERT-L must return a value of greater than IERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_IERT_A );
				eRetCode = FAIL;
			}
		}
	}


	// log IEFC
	if ( pINF->INFLSB == 0x46 )
	{
		IEFC = (double)((unsigned long)((pINF->Data[8] << 24) +
		                                (pINF->Data[9] << 16) +
		                                (pINF->Data[10] << 8) +
		                                 pINF->Data[11])) * .5;
	}
	else
	{
		IEFC = (double)((unsigned short)((pINF->Data[4] << 8) +
		                                  pINF->Data[5])) * .5;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  IEFC-%c   = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      IEFC );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x42 )
		{
			Test_5_16_INF[EcuIdx].INF42_IEFC_A = IEFC;
		}

		else if ( pINF->INFLSB == 0x46 )
		{
			if ( IEFC == 0 )
			{
				if ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F842 IEFC-L must return a value of greater than 0\n",
					      GetEcuId ( EcuIdx ) );
				}
			}

			if ( gstUserInput.ePwrTrnType != PHEV &&
			     IEFC < Test_5_16_INF[EcuIdx].INF42_IEFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 IEFC-L must return a value of greater than IEFC-A (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_IEFC_A );
				eRetCode = FAIL;
			}
		}
	}


	// log UERT
	if ( pINF->INFLSB == 0x46 )
	{
		UERT = (pINF->Data[12] << 24) +
		       (pINF->Data[13] << 16) +
		       (pINF->Data[14] << 8) +
		        pINF->Data[15];
	}
	else
	{
		UERT = ((pINF->Data[6] << 8) +
		         pINF->Data[7]) * 10;
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  UERT-%c   = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      UERT );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x42 )
		{
			Test_5_16_INF[EcuIdx].INF42_UERT_A = UERT;
		}
		else if ( pINF->INFLSB == 0x46 )
		{
			if ( gstUserInput.ePwrTrnType != PHEV &&
			     UERT < Test_5_16_INF[EcuIdx].INF42_UERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 UERT-L must return a value of greater than UERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_UERT_A );
				eRetCode = FAIL;
			}
		}
	}


	// log PKE
	if ( pINF->INFLSB == 0x46 )
	{
		PKE = (pINF->Data[16] << 24) +
		      (pINF->Data[17] << 16) +
		      (pINF->Data[18] << 8) +
		       pINF->Data[19];
	}
	else
	{
		PKE = (pINF->Data[8] << 24) +
		      (pINF->Data[9] << 16) +
		      (pINF->Data[10] << 8) +
		       pINF->Data[11];
	}
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  PKE-%c    = %10lu km2/h2\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Letter,
	      PKE );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16  )  // IF Test 5.16
	{
		if ( pINF->INFLSB == 0x42 )
		{
			Test_5_16_INF[EcuIdx].INF42_PKE_A = PKE;
		}
		else if ( pINF->INFLSB == 0x46 )
		{
			if ( gstUserInput.ePwrTrnType != PHEV &&
			     PKE < Test_5_16_INF[EcuIdx].INF42_PKE_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 PKE-L must return a value of greater than PKE-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_PKE_A );
				eRetCode = FAIL;
			}
		}
	}


	// log PTOERT
	if ( pINF->INFLSB == 0x46 )
	{
		PTOERT = (pINF->Data[20] << 24) +
		         (pINF->Data[21] << 16) +
		         (pINF->Data[22] << 8) +
		          pINF->Data[23];
	}
	else
	{
		PTOERT = ((pINF->Data[12] << 8) +
		           pINF->Data[13]) * 10;
	}
	if ( ((pINF->INFLSB == 0x42 || pINF->INFLSB == 0x44) && PTOERT == 655350) ||
	      (pINF->INFLSB == 0x46                          && PTOERT == 4294967295) )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  PTOERT-%c not supported\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      Letter,
		      PTOERT );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  PTOERT-%c = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      Letter,
		      PTOERT );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16  )  // IF Test 5.16
		{
			if ( pINF->INFLSB == 0x42 )
			{
				Test_5_16_INF[EcuIdx].INF42_PTOERT_A = PTOERT;

				if ( PTOERT != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F842 PTOERT-A must return a value of 0 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pINF->INFLSB == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          PTOERT < Test_5_16_INF[EcuIdx].INF42_PTOERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 PTOERT-L must return a value of greater than PTOERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_PTOERT_A );
				eRetCode = FAIL;
			}
		}
	}


	// log PTOFC
	if ( pINF->INFLSB == 0x46 )
	{
		PTOFC = (double)((unsigned long)((pINF->Data[24] << 24) +
		                                 (pINF->Data[25] << 16) +
		                                 (pINF->Data[26] << 8) +
		                                  pINF->Data[27])) * .5;
	}
	else
	{
		PTOFC = (double)((unsigned short)((pINF->Data[14] << 8) +
		                                   pINF->Data[15])) * .5;
	}
	if ( ((pINF->INFLSB == 0x42 || pINF->INFLSB == 0x44) && PTOERT == 32767.5) ||
	      (pINF->INFLSB == 0x46                          && PTOERT == 2147483647.5) )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  PTOFC-%c not supported\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      Letter,
		      PTOFC );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  PTOFC-%c  = %10.1f l\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      Letter,
		      PTOFC );

		if ( geTestPhase == eTestNoDTC && gTestSubsection == 16  )  // IF Test 5.16
		{
			if ( pINF->INFLSB == 0x42 )
			{
				Test_5_16_INF[EcuIdx].INF42_PTOFC_A = PTOFC;
				if ( PTOFC != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $F842 PTOFC-A must return a value of 0 after a SID $14 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pINF->INFLSB == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          PTOFC < Test_5_16_INF[EcuIdx].INF42_PTOFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F846 PTOFC-L must return a value of greater than PTOFC-A (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_16_INF[EcuIdx].INF42_PTOFC_A );
				eRetCode = FAIL;
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF47Data
**
**  Purpose:   Verify the Total Propulsion System Active Time data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF47Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long PSA_A;
	unsigned long PSA_S;
	unsigned long PSA_L;

	unsigned long IPSA_A;
	unsigned long IPSA_S;
	unsigned long IPSA_L;

	unsigned long UPSA_A;
	unsigned long UPSA_S;
	unsigned long UPSA_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $47 must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F847  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log PSA_A
	PSA_A = ((pINF->Data[0] << 8) +
	          pINF->Data[1]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  PSA-A  = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      PSA_A );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_PSA_A = PSA_A;
	}

	// log PSA_S
	PSA_S = ((pINF->Data[2] << 8) +
	          pINF->Data[3]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  PSA-S  = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      PSA_S );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_PSA_S = PSA_S;
	}

	// log PSA_L
	PSA_L = (pINF->Data[4] << 24) +
	        (pINF->Data[5] << 16) +
	        (pINF->Data[6] << 8) +
	         pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  PSA-L  = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      PSA_L );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_PSA_L = PSA_L;

		if ( (gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV) &&
		     PSA_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 PSA-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		if ( PSA_L <= PSA_A )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 PSA-L must return a value of greater than PSA_A\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}


	// log IPSA_A
	IPSA_A = ((pINF->Data[8] << 8) +
	           pINF->Data[9]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  IPSA-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      IPSA_A );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_IPSA_A = IPSA_A;
	}

	// log IPSA_S
	IPSA_S = ((pINF->Data[10] << 8) +
	           pINF->Data[11]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  IPSA-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      IPSA_S );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_IPSA_S = IPSA_S;
	}

	// log IPSA_L
	IPSA_L = (pINF->Data[12] << 24) +
	         (pINF->Data[13] << 16) +
	         (pINF->Data[14] << 8) +
	          pINF->Data[15];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  IPSA-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      IPSA_L );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_IPSA_L = IPSA_L;

		if ( (gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV) &&
		     IPSA_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 IPSA-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		if ( IPSA_L <= IPSA_A )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 IPSA-L must return a value of greater than IPSA_A\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}


	// log UPSA_A
	UPSA_A = ((pINF->Data[16] << 8) +
	           pINF->Data[17]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  UPSA-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      UPSA_A );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_UPSA_A = UPSA_A;

		if ( UPSA_A != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 UPSA-A must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log UPSA_S
	UPSA_S = ((pINF->Data[18] << 8) +
	           pINF->Data[19]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  UPSA-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      UPSA_S );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_UPSA_S = UPSA_S;
	}

	// log UPSA_L
	UPSA_L = (pINF->Data[20] << 24) +
	         (pINF->Data[21] << 16) +
	         (pINF->Data[22] << 8) +
	          pINF->Data[23];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F847  UPSA-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      UPSA_L );
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		Test_5_16_INF[EcuIdx].INF47_UPSA_L = UPSA_L;

		if ( (gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV) &&
		     UPSA_L == 0 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 UPSA-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
		}

		if ( UPSA_L <= UPSA_A )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F847 UPSA-L must return a value of greater than UPSA_A\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF48Data
**
**  Purpose:   Verify the Charge Depleting Operation data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF48Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float  CDEODT_A;
	float  CDEODT_S;
	double CDEODT_L;

	float  CDERDT_A;
	float  CDERDT_S;
	double CDERDT_L;

	float  CIDT_A;
	float  CIDT_S;
	double CIDT_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F848  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CDEODT_A
	CDEODT_A = (float)((unsigned short)((pINF->Data[0] << 8) +
	                                     pINF->Data[1]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CDEODT-A = %9.2f km\n",
	      GetEcuId ( EcuIdx ),
	      CDEODT_A );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( CDEODT_A != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F848 CDEODT-A must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log CDEODT_S
	CDEODT_S = (float)((unsigned short)((pINF->Data[2] << 8) +
	                                     pINF->Data[3]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CDEODT-S = %8.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      CDEODT_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CDEODT_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F848 CDEODT-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CDEODT_L
	CDEODT_L = (double)((unsigned long)((pINF->Data[4] << 24) +
	                                    (pINF->Data[5] << 16) +
	                                    (pINF->Data[6] << 8) +
	                                     pINF->Data[7])) * .005;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CDEODT-L = %8.3f km\n",
	      GetEcuId ( EcuIdx ),
	      CDEODT_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CDEODT_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F848 CDEODT-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CDEODT_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F848 CDEODT-L and CDEODT-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}


	// log CDERDT_A
	CDERDT_A = (float)((unsigned short)((pINF->Data[8] << 8) +
	                                     pINF->Data[9]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CDERDT-A = %9.2f km\n",
	      GetEcuId ( EcuIdx ),
	      CDERDT_A );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( CDERDT_A != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F848 CDERDT-A must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log CDERDT_S
	CDERDT_S = (float)((unsigned short)((pINF->Data[10] << 8) +
	                                     pINF->Data[11]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CDERDT-S = %8.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      CDERDT_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CDERDT_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F848 CDERDT-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CDERDT_L
	CDERDT_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                    (pINF->Data[13] << 16) +
	                                    (pINF->Data[14] << 8) +
	                                     pINF->Data[15])) * .005;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CDERDT-L = %8.3f km\n",
	      GetEcuId ( EcuIdx ),
	      CDERDT_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CDERDT_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F848 CDERDT-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CDERDT_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F848 CDERDT-L and CDERDT-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}


	// log CIDT_A
	CIDT_A = (float)((unsigned short)((pINF->Data[16] << 8) +
	                                   pINF->Data[17]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CIDT-A   = %9.2f km\n",
	      GetEcuId ( EcuIdx ),
	      CIDT_A );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( CIDT_A != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F848 CIDT-A must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log CIDT_S
	CIDT_S = (float)((unsigned short)((pINF->Data[18] << 8) +
	                                   pINF->Data[19]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CIDT-S   = %9.2f km\n",
	      GetEcuId ( EcuIdx ),
	      CIDT_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CIDT_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F848 CIDT-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CIDT_L
	CIDT_L = (double)((unsigned long)((pINF->Data[20] << 24) +
	                                  (pINF->Data[21] << 16) +
	                                  (pINF->Data[22] << 8) +
	                                   pINF->Data[23])) * .005;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F848  CIDT-L   = %8.3f km\n",
	      GetEcuId ( EcuIdx ),
	      CIDT_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CIDT_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F848 CIDT-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CIDT_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F848 CIDT-L and CIDT-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF49Data
**
**  Purpose:   Verify the Total Fuel Consumed data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF49Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float  CDFC_A;
	float  CDFC_S;
	double CDFC_L;

	float  CIFC_A;
	float  CIFC_S;
	double CIFC_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F849  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CDFC_A
	CDFC_A = (float)((unsigned short)((pINF->Data[0] << 8) +
	                                   pINF->Data[1]) * .5);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F849  CDFC-A = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      CDFC_A );

	// log CDFC_S
	CDFC_S = (float)((unsigned short)((pINF->Data[2] << 8) +
	                                   pINF->Data[3]) * .5);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F849  CDFC-S = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      CDFC_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CDFC_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F849 CDFC-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CDFC_L
	CDFC_L = (double)((unsigned long)((pINF->Data[4] << 24) +
	                                  (pINF->Data[5] << 16) +
	                                  (pINF->Data[6] << 8) +
	                                   pINF->Data[7])) * .5;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F849  CDFC-L = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      CDFC_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CDFC_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F849 CDFC-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CDFC_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F849 CDFC-L and CDFC-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}


	// log CIFC_A
	CIFC_A = (float)((unsigned short)((pINF->Data[8] << 8) +
	                                   pINF->Data[9]) * .5);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F849  CIFC-A = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      CIFC_A );

	// log CIFC_S
	CIFC_S = (float)((unsigned short)((pINF->Data[10] << 8) +
	                                   pINF->Data[11]) * .5);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F849  CIFC-S = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      CIFC_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CIFC_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F849 CIFC-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CIFC_L
	CIFC_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                  (pINF->Data[13] << 16) +
	                                  (pINF->Data[14] << 8) +
	                                   pINF->Data[15])) * .5;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F849  CIFC-L = %10.1f l\n",
	      GetEcuId ( EcuIdx ),
	      CIFC_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CIFC_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F849 CIFC-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CIFC_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F849 CIFC-L and CIFC-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF50Data
**
**  Purpose:   Verify the Total Grid Energy Consumed In Charge Depleting Operation data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF50Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long CDEOGE_A;
	unsigned long CDEOGE_S;
	unsigned long CDEOGE_L;

	unsigned long CDERGE_A;
	unsigned long CDERGE_S;
	unsigned long CDERGE_L;

	unsigned long GE_A;
	unsigned long GE_S;
	unsigned long GE_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F850  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CDEOGE_A
	CDEOGE_A = (pINF->Data[0] << 8) +
	            pINF->Data[1];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  CDEOGE-A = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      CDEOGE_A );

	// log CDEOGE_S
	CDEOGE_S = (pINF->Data[2] << 8) +
	            pINF->Data[3];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  CDEOGE-S = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      CDEOGE_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CDEOGE_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F850 CDEOGE-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CDEOGE_L
	CDEOGE_L = (pINF->Data[4] << 24) +
	           (pINF->Data[5] << 16) +
	           (pINF->Data[6] << 8) +
	            pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  CDEOGE-L = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      CDEOGE_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CDEOGE_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F850 CDEOGE-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CDEOGE_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F8450 CDEOGE-L and CDEOGE-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}


	// log CDERGE_A
	CDERGE_A = (pINF->Data[8] << 8) +
	            pINF->Data[9];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  CDERGE-A = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      CDERGE_A );

	// log CDERGE_S
	CDERGE_S = (pINF->Data[10] << 8) +
	            pINF->Data[11];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  CDERGE-S = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      CDERGE_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     CDERGE_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F850 CDERGE-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log CDERGE_L
	CDERGE_L = (pINF->Data[12] << 24) +
	           (pINF->Data[13] << 16) +
	           (pINF->Data[14] << 8) +
	            pINF->Data[15];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  CDERGE-L = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      CDERGE_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( CDERGE_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F850 CDERGE-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( CDERGE_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F8450 CDERGE-L and CDERGE-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}


	// log GE_A
	GE_A = (pINF->Data[16] << 8) +
	        pINF->Data[17];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  GE-A     = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      GE_A );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     geTestPhase == eTestNoDTC && gTestSubsection == 16 )  // IF Test 5.16
	{
		if ( GE_A != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F850 GE-A must return a value of 0 after a SID $14 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
	}

	// log GE_S
	GE_S = (pINF->Data[18] << 8) +
	        pINF->Data[19];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  GE-S     = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      GE_S );
	if ( gstUserInput.ePwrTrnType == PHEV &&
	     GE_S == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F850 GE-S must return a value of greater than 0\n",
		      GetEcuId ( EcuIdx ) );
		eRetCode = FAIL;
	}

	// log GE_L
	GE_L = (pINF->Data[19] << 24) +
	       (pINF->Data[20] << 16) +
	       (pINF->Data[21] << 8) +
	        pINF->Data[22];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F850  GE-L     = %10lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      GE_L );
	if ( gstUserInput.ePwrTrnType == PHEV )
	{
		if ( GE_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F850 GE-L must return a value of greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;

			if ( GE_A == 0 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F8450 GE-L and GE-A must not both be equal to 0\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF51Data
**
**  Purpose:   Verify the Stop-Start Propulsion System Active Time data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF51Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long ISS_TIME_A;
	unsigned long ISS_TIME_S;
	unsigned long ISS_TIME_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F851  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log ISS_TIME_A
	ISS_TIME_A = ((pINF->Data[0] << 8) +
	               pINF->Data[1]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F851  ISS_TIME-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      ISS_TIME_A );

	// log ISS_TIME_S
	ISS_TIME_S = ((pINF->Data[2] << 8) +
	               pINF->Data[3]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F851  ISS_TIME-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      ISS_TIME_S );

	// log ISS_TIME_L
	ISS_TIME_L = (pINF->Data[4] << 24) +
	             (pINF->Data[5] << 16) +
	             (pINF->Data[6] << 8) +
	              pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F851  ISS_TIME-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      ISS_TIME_L );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF52Data
**
**  Purpose:   Verify the Automatic Engine Shutdown Technology Activation Count data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF52Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long AES_CNT_A;
	unsigned long AES_CNT_S;
	unsigned long AES_CNT_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F852  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log AES_CNT_A
	AES_CNT_A = ((pINF->Data[0] << 8) +
	              pINF->Data[1]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F852  AES_CNT-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      AES_CNT_A );

	// log AES_CNT_S
	AES_CNT_S = ((pINF->Data[2] << 8) +
	              pINF->Data[3]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F852  AES_CNT-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      AES_CNT_S );

	// log AES_CNT_L
	AES_CNT_L = (pINF->Data[4] << 24) +
	            (pINF->Data[5] << 16) +
	            (pINF->Data[6] << 8) +
	             pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F852  AES_CNT-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      AES_CNT_L );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF53Data
**
**  Purpose:   Verify the WHR Propulsion System Active Time / WHR Distance Traveled data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF53Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long  WHR_TIME_A;
	unsigned long  WHR_TIME_S;
	unsigned long  WHR_TIME_L;

	float          WHR_DT_A;
	float          WHR_DT_S;
	double         WHR_DT_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F853  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log WHR_TIME_A
	WHR_TIME_A = ((pINF->Data[0] << 8) +
	               pINF->Data[1]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F853  WHR_TIME-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      WHR_TIME_A );

	// log WHR_TIME_S
	WHR_TIME_S = ((pINF->Data[2] << 8) +
	               pINF->Data[3]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F853  WHR_TIME-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      WHR_TIME_S );

	// log WHR_TIME_L
	WHR_TIME_L = (pINF->Data[4] << 24) +
	             (pINF->Data[5] << 16) +
	             (pINF->Data[6] << 8) +
	              pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F853  WHR_TIME-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      WHR_TIME_L );


	// log WHR_DT_A
	WHR_DT_A = (float)((unsigned short)((pINF->Data[8] << 8) +
	                                     pINF->Data[9]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F853  WHR_DT-A   = %10.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      WHR_DT_A );

	// log WHR_DT_S
	WHR_DT_S = (float)((unsigned short)((pINF->Data[10] << 8) +
	                                     pINF->Data[11]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F853  WHR_DT-S   = %10.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      WHR_DT_S );

	// log WHR_DT_L
	WHR_DT_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                    (pINF->Data[13] << 16) +
	                                    (pINF->Data[14] << 8) +
	                                     pINF->Data[15])) * .005;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F853  WHR_DT-L   = %10.3f km\n",
	      GetEcuId ( EcuIdx ),
	      WHR_DT_L );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF54_5BData
**
**  Purpose:   Verify the Active Technology #X Propulsion System Active Time /
**             Active Technology #X Distance Traveled data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF54_5BData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long AT1_TIME_A;
	unsigned long AT1_TIME_S;
	unsigned long AT1_TIME_L;

	float         AT1_DT_A;
	float         AT1_DT_S;
	double        AT1_DT_L;

	unsigned long AT2_TIME_A;
	unsigned long AT2_TIME_S;
	unsigned long AT2_TIME_L;

	float         AT2_DT_A;
	float         AT2_DT_S;
	double        AT2_DT_L;

#define  MAX_NUMBER_LENGTH  3
	char          Number1String[MAX_NUMBER_LENGTH];
	char          Number2String[MAX_NUMBER_LENGTH];


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 32 bytes of data
	if ( DataSize != 32 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 32 bytes!)\n",
		      pINF->INFLSB,
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	sprintf_s ( Number1String, MAX_NUMBER_LENGTH, "%d", 1 + ((pINF->INFLSB - 0x54) * 2) );
	sprintf_s ( Number2String, MAX_NUMBER_LENGTH, "%d", 2 + ((pINF->INFLSB - 0x54) * 2) );


	// log ATx_TIME_A
	AT1_TIME_A = ((pINF->Data[0] << 8) +
	               pINF->Data[1]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_TIME-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number1String,
	      AT1_TIME_A );

	// log ATx_TIME_S
	AT1_TIME_S = ((pINF->Data[2] << 8) +
	               pINF->Data[3]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_TIME-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number1String,
	      AT1_TIME_S );

	// log ATx_TIME_L
	AT1_TIME_L = (pINF->Data[4] << 24) +
	             (pINF->Data[5] << 16) +
	             (pINF->Data[6] << 8) +
	              pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_TIME-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number1String,
	      AT1_TIME_L );


	// log ATx_DT_A
	AT1_DT_A = (float)((unsigned short)((pINF->Data[8] << 8) +
	                                     pINF->Data[9]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_DT-A   = %10.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number1String,
	      AT1_DT_A );

	// log ATx_DT_S
	AT1_DT_S = (float)((unsigned short)((pINF->Data[10] << 8) +
	                                     pINF->Data[11]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_DT-S   = %10.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number1String,
	      AT1_DT_S );

	// log ATx_DT_L
	AT1_DT_L = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                    (pINF->Data[13] << 16) +
	                                    (pINF->Data[14] << 8) +
	                                     pINF->Data[15])) * .005;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_DT-L   = %10.3f km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number1String,
	      AT1_DT_L );


	// log ATy_TIME_A
	AT2_TIME_A = ((pINF->Data[16] << 8) +
	               pINF->Data[17]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_TIME-A = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number2String,
	      AT2_TIME_A );

	// log ATy_TIME_S
	AT2_TIME_S = ((pINF->Data[18] << 8) +
	               pINF->Data[19]) * 10;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_TIME-S = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number2String,
	      AT2_TIME_S );

	// log ATy_TIME_L
	AT2_TIME_L = (pINF->Data[20] << 24) +
	             (pINF->Data[21] << 16) +
	             (pINF->Data[22] << 8) +
	              pINF->Data[23];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_TIME-L = %10lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number2String,
	      AT2_TIME_L );


	// log ATy_DT_A
	AT2_DT_A = (float)((unsigned short)((pINF->Data[24] << 8) +
	                                     pINF->Data[25]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_DT-A   = %10.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number2String,
	      AT2_DT_A );

	// log ATy_DT_S
	AT2_DT_S = (float)((unsigned short)((pINF->Data[26] << 8) +
	                                     pINF->Data[27]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_DT-S   = %10.2f  km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number2String,
	      AT2_DT_S );

	// log ATy_DT_L
	AT2_DT_L = (double)((unsigned long)((pINF->Data[28] << 24) +
	                                    (pINF->Data[29] << 16) +
	                                    (pINF->Data[30] << 8) +
	                                     pINF->Data[31])) * .005;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AT%s_DT-L   = %10.3f km\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      Number2String,
	      AT2_DT_L );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF61_62_67_68_6D_6EData
**
**  Purpose:   Verify the NOx Binning data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF61_62_67_68_6D_6EData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double         Bin[17];
	double         Bin_Sum = 0;

	unsigned short BinIndex;

	double        *pArchive = NULL;

	char           NameString[10];
	char           CompareNameString[10];
	double         Multiplier = 1.0;
#define NOX_TXT_MAX 9


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 68 bytes of data
	if ( DataSize != 68 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 68 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x61:
		{
			strcpy_s( NameString, NOX_TXT_MAX, "NOxEOB-A" );
			Multiplier = .000005;
			pArchive = &Test_5_16_INF[EcuIdx].INF61_NOxEOB_A[0];
		}
		break;
		case 0x67:
		{
			strcpy_s( NameString, NOX_TXT_MAX, "NOxEOB-S" );
			strcpy_s( CompareNameString, NOX_TXT_MAX, "NOxEOB-A" );
			Multiplier = .000005;
			pArchive = &Test_5_16_INF[EcuIdx].INF61_NOxEOB_A[0];
		}
		break;
		case 0x6D:
		{
			strcpy_s( NameString, NOX_TXT_MAX, "NOxEOB-L" );
			strcpy_s( CompareNameString, NOX_TXT_MAX, "NOxEOB-A" );
			Multiplier = .001;
			pArchive = &Test_5_16_INF[EcuIdx].INF61_NOxEOB_A[0];
		}
		break;

		case 0x62:
		{
			strcpy_s( NameString, NOX_TXT_MAX, "NOxTPB-A" );
			Multiplier = .000002;
			pArchive = &Test_5_16_INF[EcuIdx].INF62_NOxTPB_A[0];
		}
		break;
		case 0x68:
		{
			strcpy_s( NameString, NOX_TXT_MAX, "NOxTPB-S" );
			strcpy_s( CompareNameString, NOX_TXT_MAX, "NOxTPB-A" );
			Multiplier = .000002;
			pArchive = &Test_5_16_INF[EcuIdx].INF62_NOxTPB_A[0];
		}
		break;
		case 0x6E:
		{
			strcpy_s( NameString, NOX_TXT_MAX, "NOxTPB-L" );
			strcpy_s( CompareNameString, NOX_TXT_MAX, "NOxTPB-A" );
			Multiplier = .001;
			pArchive = &Test_5_16_INF[EcuIdx].INF62_NOxTPB_A[0];
		}
		break;
	}


	for ( BinIndex = 0;
	      BinIndex < 17;
	      BinIndex++ )
	{
		// log bin data
		Bin[BinIndex] = (double)((unsigned long)((pINF->Data[0 + (BinIndex * 4)] << 24) +
		                                         (pINF->Data[1 + (BinIndex * 4)] << 16) +
		                                         (pINF->Data[2 + (BinIndex * 4)] << 8) +
		                                          pINF->Data[3 + (BinIndex * 4)])) * Multiplier;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  %s[bin%d] = %11.6f kg\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      BinIndex+1,
		      Bin[BinIndex] );

		// Save -A values for later
		if ( pINF->INFLSB == 0x61 || pINF->INFLSB == 0x62 )
		{
			pArchive[BinIndex] = Bin[BinIndex];
 		}
		// -L values must be greater than -A value
		else if ( (pINF->INFLSB == 0x6D || pINF->INFLSB == 0x6E) &&
		          Bin[BinIndex] != 0 &&
		          Bin[BinIndex] < pArchive[BinIndex] )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X %s[bin%d] must be greater than %s[bin%d] (%.6f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      NameString,
			      BinIndex+1,
			      CompareNameString,
			      BinIndex+1,
			      pArchive[BinIndex] );
			eRetCode = FAIL;
		}


		// Add bins 2 through 14
		if ( BinIndex >= 1 && BinIndex <= 13 )
		{
			Bin_Sum += Bin[BinIndex];
		}
	}


	// no nox DTCs from SID $19 LEV $42 Status Mask $04 or $08 &&
	// Fail if sum of [bin2] through [bin14] != [bin1]
	if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
	     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %.6f (Must be equal to %s[bin1] (%.7f +-1%%))\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      NameString,
		      Bin_Sum,
		      NameString,
		      Bin[0] );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF63_69_6F_73Data
**
**  Purpose:   Verify the NOx Binning data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF63_69_6F_73Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double  Bin[17];
	double  Bin_Sum = 0;

	unsigned short BinIndex;

	char    NameString[10];
	double  Multiplier = 1.0;
#define EOEB_TXT_NAX 9


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $63 and $69 must contain 34 bytes of data
	if ( (pINF->INFLSB == 0x63 || pINF->INFLSB == 0x69) &&
	     DataSize != 34 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 34 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}
	// INF $63 and $69 must contain 68 bytes of data
	else if ( (pINF->INFLSB == 0x6F || pINF->INFLSB == 0x73) &&
	          DataSize != 68 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 68 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x63:
		{
			strcpy_s( NameString, EOEB_TXT_NAX, "EOEB-A" );
		}
		break;
		case 0x69:
		{
			strcpy_s( NameString, EOEB_TXT_NAX, "EOEB-S" );
		}
		break;
		case 0x6F:
		{
			strcpy_s( NameString, EOEB_TXT_NAX, "EOEB-L" );
		}
		break;
		case 0x73:
		{
			strcpy_s( NameString, EOEB_TXT_NAX, "EOEB-EAL" );
		}
		break;
	}
	Multiplier = .001;


	for ( BinIndex = 0;
	      BinIndex < 17;
	      BinIndex++ )
	{
		// log bin data
		if ( pINF->INFLSB == 0x6F || pINF->INFLSB == 0x73 )
		{
			Bin[BinIndex] = (double)((unsigned long)((pINF->Data[0 + (BinIndex * 4)] << 24) +
			                                         (pINF->Data[1 + (BinIndex * 4)] << 16) +
			                                         (pINF->Data[2 + (BinIndex * 4)] << 8) +
			                                          pINF->Data[3 + (BinIndex * 4)])) * Multiplier;
		}
		else
		{
			Bin[BinIndex] = (double)((unsigned short)((pINF->Data[0 + (BinIndex * 2)] << 8) +
			                                           pINF->Data[1 + (BinIndex * 2)])) * Multiplier;
		}

		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  %s[bin%d] = %10.3f MWh\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      BinIndex+1,
		      Bin[BinIndex] );

		// Save -A values for later
		if ( pINF->INFLSB == 0x63 )
		{
			Test_5_16_INF[EcuIdx].INF63_EOEB_A[BinIndex] = Bin[BinIndex];
		}
		// -L and EAL values must be greater than -A values
		else if ( (pINF->INFLSB == 0x6F ||
		           pINF->INFLSB == 0x73) &&
		          Bin[BinIndex] != 0     &&
		          Bin[BinIndex] < Test_5_16_INF[EcuIdx].INF63_EOEB_A[BinIndex] )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X %s[bin%d] must be greater than EOEB-A[bin%d] (%.3f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      NameString,
			      BinIndex+1,
			      BinIndex+1,
			      Test_5_16_INF[EcuIdx].INF63_EOEB_A[BinIndex] );
			eRetCode = FAIL;
		}


		// collect the sum of [bin2] through [bin14]
		if ( BinIndex >= 1 && BinIndex <= 13 )
		{
			Bin_Sum += Bin[BinIndex];
		}
	}

	// compare [bin1] against sum of [bin2] through [bin14]
	// Fail if Sum of [bin2] through [bin14] != [bin1]
	if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
	     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %.3f (Must be equal to %s[bin1] (%.3f +-1%%))\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      NameString,
		      Bin_Sum,
		      NameString,
		      Bin[0] );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF64_6A_70_74Data
**
**  Purpose:   Verify the NOx Binning data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF64_6A_70_74Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double  Bin[17];
	double  Bin_Sum = 0;

	unsigned short BinIndex;

	char    NameString[10];
	double  Multiplier = 1.0;
#define DTB_TXT_MAX 8


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $64 and $6A must contain 34 bytes of data
	if ( (pINF->INFLSB == 0x64 || pINF->INFLSB == 0x6A) &&
	     DataSize != 34 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 34 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}
	// INF $70 and $74 must contain 68 bytes of data
	else if ( (pINF->INFLSB == 0x70 || pINF->INFLSB == 0x74) &&
	          DataSize != 68 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 68 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x64:
		{
			strcpy_s( NameString, DTB_TXT_MAX, "DTB-A" );
			Multiplier = .25;
		}
		break;
		case 0x6A:
		{
			strcpy_s( NameString, DTB_TXT_MAX, "DTB-S" );
			Multiplier = .25;
		}
		break;
		case 0x70:
		{
			strcpy_s( NameString, DTB_TXT_MAX, "DTB-L" );
			Multiplier = .005;
		}
		break;
		case 0x74:
		{
			strcpy_s( NameString, DTB_TXT_MAX, "DTB-EAL" );
			Multiplier = .005;
		}
		break;
	}


	for ( BinIndex = 0;
	      BinIndex < 17;
	      BinIndex++ )
	{
		// log bin data
		if ( pINF->INFLSB == 0x70 || pINF->INFLSB == 0x74 )
		{
			Bin[BinIndex] = (double)((unsigned long)((pINF->Data[0 + (BinIndex * 4)] << 24) +
			                                         (pINF->Data[1 + (BinIndex * 4)] << 16) +
			                                         (pINF->Data[2 + (BinIndex * 4)] << 8) +
			                                          pINF->Data[3 + (BinIndex * 4)])) * Multiplier;
		}
		else
		{
			Bin[BinIndex] = (double)((unsigned short)((pINF->Data[0 + (BinIndex * 2)] << 8) +
			                                           pINF->Data[1 + (BinIndex * 2)])) * Multiplier;
		}

		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  %s[bin%d] = %7.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      BinIndex+1,
		      Bin[BinIndex] );

		// Save -A values for later
		if ( pINF->INFLSB == 0x64 )
		{
			Test_5_16_INF[EcuIdx].INF64_DTB_A[BinIndex] = Bin[BinIndex];
		}
		// -L and EAL values must be greater than -A values
		else if ( (pINF->INFLSB == 0x70 ||
		           pINF->INFLSB == 0x74) &&
		          Bin[BinIndex] != 0 &&
		          Bin[BinIndex] < Test_5_16_INF[EcuIdx].INF64_DTB_A[BinIndex] )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X %s[bin%d] must be greater than DTB-A[bin%d] (%.3f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      NameString,
			      BinIndex+1,
			      BinIndex+1,
			      Test_5_16_INF[EcuIdx].INF64_DTB_A[BinIndex] );
			eRetCode = FAIL;
		}


		if ( BinIndex >= 1 && BinIndex <= 13 )
		{
			Bin_Sum += Bin[BinIndex];
		}
	}

	// no nox DTCs from SID $19 LEV $42 Status Mask $04 or $08 &&
	// Fail if sum of [bin2] through [bin14] != [bin1]
	if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
	     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %.3f (Must be equal to %s[bin1] (%.3f +-1%%))\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      NameString,
		      Bin_Sum,
		      NameString,
		      Bin[0] );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**  Function:  VerifyINF65_6B_71_75Data
**
**  Purpose:   Verify the NOx Binning data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF65_6B_71_75Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long Bin[17];
	unsigned long Bin_Sum = 0;

	unsigned int  BinIndex;

	char          NameString[10];
	unsigned long Multiplier = 1;
#define ERTB_TXT_MAX 9


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $65 and $6B must contain 34 bytes of data
	if ( (pINF->INFLSB == 0x65 || pINF->INFLSB == 0x6B) &&
	     DataSize != 34 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 34 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}
	// INF $71 and $75 must contain 68 bytes of data
	else if ( (pINF->INFLSB == 0x71 || pINF->INFLSB == 0x75) &&
	          DataSize != 68 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 68 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x65:
		{
			strcpy_s ( NameString, ERTB_TXT_MAX, "ERTB-A" );
			Multiplier = 10;
		}
		break;
		case 0x6B:
		{
			strcpy_s ( NameString, ERTB_TXT_MAX, "ERTB-S" );
			Multiplier = 10;
		}
		break;
		case 0x71:
		{
			strcpy_s ( NameString, ERTB_TXT_MAX, "ERTB-L" );
			Multiplier = 1;
		}
		break;
		case 0x75:
		{
			strcpy_s ( NameString, ERTB_TXT_MAX, "ERTB-EAL" );
			Multiplier = 1;
		}
		break;
	}


	for ( BinIndex = 0;
	      BinIndex < 17;
	      BinIndex++ )
	{
		// log bin data
		if ( pINF->INFLSB == 0x71 || pINF->INFLSB == 0x75 )
		{
			Bin[BinIndex] = ((pINF->Data[0 + (BinIndex * 4)] << 24) +
			                 (pINF->Data[1 + (BinIndex * 4)] << 16) +
			                 (pINF->Data[2 + (BinIndex * 4)] << 8) +
			                  pINF->Data[3 + (BinIndex * 4)]) * Multiplier;
		}
		else
		{
			Bin[BinIndex] = ((pINF->Data[0 + (BinIndex * 2)] << 8) +
			                  pINF->Data[1 + (BinIndex * 2)]) * Multiplier;
		}

		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  %s[bin%d] = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      BinIndex+1,
		      Bin[BinIndex] );

		// Save -A values for later
		if ( pINF->INFLSB == 0x65 )
		{
			Test_5_16_INF[EcuIdx].INF65_ERTB_A[BinIndex] = Bin[BinIndex];
		}
		// -L and EAL values must be greater than -A values
		else if ( (pINF->INFLSB == 0x71 ||
		           pINF->INFLSB == 0x75) &&
		          Bin[BinIndex] != 0 &&
		          Bin[BinIndex] < Test_5_16_INF[EcuIdx].INF65_ERTB_A[BinIndex] )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X %s[bin%d] must be greater than ERTB-A[bin%d] (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      NameString,
			      BinIndex+1,
			      BinIndex+1,
			      Test_5_16_INF[EcuIdx].INF65_ERTB_A[BinIndex] );
			eRetCode = FAIL;
		}


		if ( BinIndex >= 1 && BinIndex <= 13 )
		{
			Bin_Sum += Bin[BinIndex];
		}
	}


	// no nox DTCs from SID $19 LEV $42 Status Mask $04 or $08 &&
	// Fail if sum of [bin2] through [bin14] != [bin1]
	if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
	     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %lu (Must be equal to %s[bin1] (%lu +-1%%))\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      NameString,
		      Bin_Sum,
		      NameString,
		      Bin[0] );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF66_6C_72_76Data
**
**  Purpose:   Verify the NOx Binning data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF66_6C_72_76Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	double  Bin[17];
	double  Bin_Sum = 0;

	unsigned short BinIndex;

	char    NameString[10];
	double  Multiplier = 1.0;
#define FCB_TXT_MAX 8


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// INF $66 and $6C must contain 34 bytes of data
	if ( (pINF->INFLSB == 0x66 || pINF->INFLSB == 0x6C) &&
	     DataSize != 34 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 34 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}
	// INF $72 and $76 must contain 68 bytes of data
	else if ( (pINF->INFLSB == 0x72 || pINF->INFLSB == 0x76) &&
	          DataSize != 68 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 68 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x66:
		{
			strcpy_s ( NameString, FCB_TXT_MAX, "FCB-A" );
		}
		break;
		case 0x6C:
		{
			strcpy_s ( NameString, FCB_TXT_MAX, "FCB-S" );
		}
		break;
		case 0x72:
		{
			strcpy_s ( NameString, FCB_TXT_MAX, "IFCB-L" );
		}
		break;
		case 0x76:
		{
			strcpy_s ( NameString, FCB_TXT_MAX, "FCB-EAL" );
		}
		break;
	}

	Multiplier = .5;


	for ( BinIndex = 0;
	      BinIndex < 17;
	      BinIndex++ )
	{
		// log bin data
		if ( pINF->INFLSB == 0x72 || pINF->INFLSB == 0x76 )
		{
			Bin[BinIndex] = (double)((unsigned long)((pINF->Data[0 + (BinIndex * 4)] << 24) +
			                                         (pINF->Data[1 + (BinIndex * 4)] << 16) +
			                                         (pINF->Data[2 + (BinIndex * 4)] << 8) +
			                                          pINF->Data[3 + (BinIndex * 4)])) * Multiplier;
		}
		else
		{
			Bin[BinIndex] = (double)((unsigned short)((pINF->Data[0 + (BinIndex * 2)] << 8) +
			                                           pINF->Data[1 + (BinIndex * 2)])) * Multiplier;
		}

		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  %s[bin%d] = %11.1f l\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      BinIndex+1,
		      Bin[BinIndex] );

		// Save -A values for later
		if ( pINF->INFLSB == 0x66 )
		{
			Test_5_16_INF[EcuIdx].INF66_FCB_A[BinIndex] = Bin[BinIndex];
		}
		// -L and EAL values must be greater than -A values
		else if ( (pINF->INFLSB == 0x72 ||
		           pINF->INFLSB == 0x76) &&
		          Bin[BinIndex] != 0 &&
		          Bin[BinIndex] < Test_5_16_INF[EcuIdx].INF66_FCB_A[BinIndex] )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X %s[bin%d] must be greater than FCB-A[bin%d] (%.1f)\n",
			      GetEcuId ( EcuIdx ),
			      pINF->INFLSB,
			      NameString,
			      BinIndex+1,
			      BinIndex+1,
			      Test_5_16_INF[EcuIdx].INF66_FCB_A[BinIndex] );
			eRetCode = FAIL;
		}


		if ( BinIndex >= 1 && BinIndex <= 13 )
		{
			Bin_Sum += Bin[BinIndex];
		}
	}


	// no nox DTCs from SID $19 LEV $42 Status Mask $04 or $08 &&
	// Fail if sum of [bin2] through [bin14] != [bin1]
	if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
	     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %.1f (Must be equal to %s[bin1] (%.1f +-1%%))\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      NameString,
		      Bin_Sum,
		      NameString,
		      Bin[0] );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF77Data
**
**  Purpose:   Verify the Total Run Time / Odometer Reading data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF77Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long NOREDUCT_TIME_L;
	unsigned long COLDEXH_TIME_L;

	double        REGEN1_SDIST;
	double        REGEN1_FDIST;
	double        REGEN2_SDIST;
	double        REGEN2_FDIST;
	double        REGEN3_SDIST;
	double        REGEN3_FDIST;

	unsigned long REGEN_CNTL_L;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 36 bytes of data
	if ( DataSize != 36 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  Data Size = %d (Must be 36 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log NOREDUCT_TIME_L
	NOREDUCT_TIME_L = (pINF->Data[0] << 24) +
	                  (pINF->Data[1] << 16) +
	                  (pINF->Data[2] << 8) +
	                   pINF->Data[3];
	if ( NOREDUCT_TIME_L == 0xFFFFFFFF )
	{
		if ( (gstResponse[EcuIdx].PIDF501.Data[2] & 0x08) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F877  NOREDUCT_TIME-L not supported (required for all vehicles supporting SCR Monitor in $F501)\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F877  NOREDUCT_TIME-L not supported\n",
			      GetEcuId ( EcuIdx ) );
		}
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  NOREDUCT_TIME-L = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      NOREDUCT_TIME_L );
	}

	// log COLDEXH_TIME_L
	COLDEXH_TIME_L = (pINF->Data[4] << 24) +
	                 (pINF->Data[5] << 16) +
	                 (pINF->Data[6] << 8) +
	                  pINF->Data[7];
	if ( COLDEXH_TIME_L == 0xFFFFFFFF )
	{
		if ( (gstResponse[EcuIdx].PIDF501.Data[2] & 0x08) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F877  COLDEXH_TIME-L  not supported (required for all vehicles supporting SCR Monitor in $F501)\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F877  COLDEXH_TIME-L  not supported\n",
			      GetEcuId ( EcuIdx ) );
		}
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  COLDEXH_TIME-L = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      COLDEXH_TIME_L );
	}


	// log REGEN1_SDIST
	REGEN1_SDIST = (double)((unsigned long)((pINF->Data[8] << 24) +
	                                        (pINF->Data[9] << 16) +
	                                        (pINF->Data[10] << 8) +
	                                         pINF->Data[11])) * .005;
	if ( pINF->Data[8]  == 0xFF &&
	     pINF->Data[9]  == 0xFF &&
	     pINF->Data[10] == 0xFF &&
	     pINF->Data[11] == 0xFF )
	{
		if ( (gstResponse[EcuIdx].PIDF501.Data[3] & 0x08) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F877  REGEN1_SDIST not supported (required for all vehicles supporting PM Monitor in $F501)\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F877  REGEN1_SDIST not supported\n",
			      GetEcuId ( EcuIdx ) );
		}
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN1_SDIST = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN1_SDIST );
	}

	// log REGEN1_FDIST
	REGEN1_FDIST = (double)((unsigned long)((pINF->Data[12] << 24) +
	                                        (pINF->Data[13] << 16) +
	                                        (pINF->Data[14] << 8) +
	                                         pINF->Data[15])) * .005;
	if ( pINF->Data[12] == 0xFF &&
	     pINF->Data[13] == 0xFF &&
	     pINF->Data[14] == 0xFF &&
	     pINF->Data[15] == 0xFF )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN1_FDIST not supported\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN1_FDIST = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN1_FDIST );
	}


	// log REGEN2_SDIST
	REGEN2_SDIST = (double)((unsigned long)((pINF->Data[16] << 24) +
	                                        (pINF->Data[17] << 16) +
	                                        (pINF->Data[18] << 8) +
	                                         pINF->Data[19])) * .005;
	if ( pINF->Data[16] == 0xFF &&
	     pINF->Data[17] == 0xFF &&
	     pINF->Data[18] == 0xFF &&
	     pINF->Data[19] == 0xFF )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN2_SDIST not supported\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN2_SDIST = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN2_SDIST );
	}

	// log REGEN2_FDIST
	REGEN2_FDIST = (double)((unsigned long)((pINF->Data[20] << 24) +
	                                        (pINF->Data[21] << 16) +
	                                        (pINF->Data[22] << 8) +
	                                         pINF->Data[23])) * .005;
	if ( pINF->Data[20] == 0xFF &&
	     pINF->Data[21] == 0xFF &&
	     pINF->Data[22] == 0xFF &&
	     pINF->Data[23] == 0xFF )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN2_FDIST not supported\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN2_FDIST = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN2_FDIST );
	}


	// log REGEN3_SDIST
	REGEN3_SDIST = (double)((unsigned long)((pINF->Data[24] << 24) +
	                                        (pINF->Data[25] << 16) +
	                                        (pINF->Data[26] << 8) +
	                                         pINF->Data[27])) * .005;
	if ( pINF->Data[24] == 0xFF &&
	     pINF->Data[25] == 0xFF &&
	     pINF->Data[26] == 0xFF &&
	     pINF->Data[27] == 0xFF )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN3_SDIST not supported\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN3_SDIST = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN3_SDIST );
	}

	// log REGEN3_FDIST
	REGEN3_FDIST = (double)((unsigned long)((pINF->Data[28] << 24) +
	                                        (pINF->Data[29] << 16) +
	                                        (pINF->Data[30] << 8) +
	                                         pINF->Data[31])) * .005;
	if ( pINF->Data[28] == 0xFF &&
	     pINF->Data[29] == 0xFF &&
	     pINF->Data[30] == 0xFF &&
	     pINF->Data[31] == 0xFF )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN3_FDIST not supported\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN3_FDIST = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN3_FDIST );
	}


	// log REGEN_CNTL_L
	REGEN_CNTL_L = (pINF->Data[32] << 24) +
	               (pINF->Data[33] << 16) +
	               (pINF->Data[34] << 8) +
	                pINF->Data[35];
	if ( REGEN_CNTL_L == 0xFFFFFFFF )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN_CNTL-L not supported\n",
		      GetEcuId ( EcuIdx ) );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F877  REGEN_CNTL-L = %11lu\n",
		      GetEcuId ( EcuIdx ),
		      REGEN_CNTL_L );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF78Data
**
**  Purpose:   Verify the Enigne Rated Power / Engine Rated Speed data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF78Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float   PWR_RATING;
	float   RPM_RATING;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 4 bytes of data
	if ( DataSize != 4 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F878  Data Size = %d (Must be 4 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log PWR_RATING
	PWR_RATING = (float)((unsigned short)((pINF->Data[0] << 8) +
	                                       pINF->Data[1]) * .5);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F878  PWR_RATING = %7.1f kW\n",
	      GetEcuId ( EcuIdx ),
	      PWR_RATING );

	if ( PWR_RATING == 0 &&
	     gstUserInput.eFuelType == DIESEL &&
	     gstUserInput.eVehicleType != LD )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F878  PWR_RATING Must be greater than 0\n",
		      GetEcuId ( EcuIdx) );
		eRetCode = FAIL;
	}


	// log RPM_RATING
	RPM_RATING = (float)((unsigned short)((pINF->Data[2] << 8) +
	                                       pINF->Data[3]) * .25);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F878  RPM_RATING = %7.2f RPM\n",
	      GetEcuId ( EcuIdx ),
	      RPM_RATING );


	if ( RPM_RATING == 0 &&
	     gstUserInput.eFuelType == DIESEL &&
	     gstUserInput.eVehicleType != LD )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F878  RPM_RATING Must be greater than 0\n",
		      GetEcuId ( EcuIdx) );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF79Data
**
**  Purpose:   Verify the Supplemental Monitor Activity Denominator data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF79Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 1 byte of data
	if ( DataSize != 1 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F879  Data Size = %d (Must be 1 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// Store the MAD value for later SMAD evaluation
	memcpy ( &gstResponse[EcuIdx].MAD, pINF, sizeof ( INF ) );

	// log MAD
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F879  MAD = $%02X (%d)\n",
	      GetEcuId ( EcuIdx ),
	      gstResponse[EcuIdx].MAD.Data[0],
	      gstResponse[EcuIdx].MAD.Data[0] );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF81Data
**
**  Purpose:   Verify the Battery Accumulation data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF81Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F881  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log High Voltage Battery Net Amp Hours 
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8) +
	                          pINF->Data[3]) * (float).001;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F881  HVB_NAH = %10.3f Ah\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );


	// log High Voltage Battery Net Energy
	TempData_Float = (float)((pINF->Data[4] << 24) +
	                         (pINF->Data[5] << 16) +
	                         (pINF->Data[6] << 8) +
	                          pINF->Data[7]) * (float).001;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F881  HVB_NE = %10.3f kWh\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );

	return eRetCode;
}




/*******************************************************************************
**
**  Function:  VerifyINF82Data
**
**  Purpose:   Verify the In-Use Performance Data for OBDonUDS data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF82Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];

	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 4 bytes of data
	if ( DataSize != 4 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F882  Data Size = %d (Must be 4 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );

		// clear IPD structure
		memset ( &gstResponse[EcuIdx].IPD,
		         0,
		         sizeof ( gstResponse[EcuIdx].IPD ) );

		gstResponse[EcuIdx].bIPDSupported = FALSE;

		return FAIL;
	}

	// save OBDCOND and IGNCNTR for the selected ECU
	SaveIPD ( EcuIdx );

	// log OBDCOND and IGNCNTR for the selected ECU
	LogIPD ( EcuIdx );

	// Check IGNCNTR for zero
	if ( gstResponse[EcuIdx].IPD[IPD_IGNCNTR_INDEX] == 0 &&
	     (gstUserInput.ePwrTrnType == CONV ||
	      gstUserInput.ePwrTrnType == SS ) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  IGNCNTR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF83Data
**
**  Purpose:   Verify the Diesel CSERS Current Drive Cycle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF83Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long TempData_Long;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 20 bytes of data
	if ( DataSize != 20 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F883  Data Size = %d (Must be 20 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CAT_CSTIME_CUR
	TempData_Long = (unsigned short)((pINF->Data[0] << 8) +
	                                  pINF->Data[1]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  CAT_CSTIME_CUR = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  CAT_CSTIME_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log CAT_EOE_CUR
	TempData_Long = (unsigned short)((pINF->Data[2] << 8) +
	                                  pINF->Data[3]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  CAT_EOE_CUR = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  CAT_EOE_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log CAT_CSTEMP_CUR
	TempData_Long = (unsigned short)((pINF->Data[4] << 8) +
	                                  pINF->Data[5]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  CAT_CSTEMP_CUR = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  CAT_CSTEMP_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EOE_CSTIME_CUR
	TempData_Long = (unsigned short)((pINF->Data[6] << 8) +
	                                  pINF->Data[7]) * 5;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  EOE_CSTIME_CUR = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EOE_CSTIME_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EOE_CSTEMP_CUR
	TempData_Long = (unsigned short)((pINF->Data[8] << 8) +
	                                  pINF->Data[9]) * 5;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  EOE_CSTEMP_CUR = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EOE_CSTEMP_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EGR_CSTIME_CUR
	TempData_Long = (unsigned short)((pINF->Data[10] << 8) +
	                                  pINF->Data[11]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  EGR_CSTIME_CUR = %d g\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EGR_CSTIME_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EGR_EOE_CUR
	TempData_Long = (unsigned short)((pINF->Data[12] << 8) +
	                                  pINF->Data[13]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  EGR_EOE_CUR = %d g\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EGR_EOE_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EGR_CSTEMP_CUR
	TempData_Long = (unsigned short)((pINF->Data[14] << 8) +
	                                  pINF->Data[15]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  EGR_CSTEMP_CUR = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EGR_CSTEMP_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log TIME_EOE_CUR
	TempData_Long = (unsigned short)((pINF->Data[16] << 8) +
	                                  pINF->Data[17]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  TIME_EOE_CUR = %d sec\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  TIME_EOE_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log TIME_CSTEMP_CUR
	TempData_Long = (unsigned short)((pINF->Data[18] << 8) +
	                                  pINF->Data[19]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F883  TIME_CSTEMP_CUR = %d sec\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  TIME_CSTEMP_CUR must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF84Data
**
**  Purpose:   Verify the Diesel CSERS Historical EWM data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF84Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned long TempData_Long;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 20 bytes of data
	if ( DataSize != 20 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F884  Data Size = %d (Must be 20 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log CAT_CSTIME_CUR
	TempData_Long = (unsigned short)((pINF->Data[0] << 8) +
	                                  pINF->Data[1]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  CAT_CSTIME_EWMA = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  CAT_CSTIME_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log CAT_EOE_EWMA
	TempData_Long = (unsigned short)((pINF->Data[2] << 8) +
	                                  pINF->Data[3]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  CAT_EOE_EWMA = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  CAT_EOE_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log CAT_CSTEMP_EWMA
	TempData_Long = (unsigned short)((pINF->Data[4] << 8) +
	                                  pINF->Data[5]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  CAT_CSTEMP_EWMA = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  CAT_CSTEMP_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EOE_CSTIME_EWMA
	TempData_Long = (unsigned short)((pINF->Data[6] << 8) +
	                                  pINF->Data[7]) * 5;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  EOE_CSTIME_EWMA = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EOE_CSTIME_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EOE_CSTEMP_EWMA
	TempData_Long = (unsigned short)((pINF->Data[8] << 8) +
	                                  pINF->Data[9]) * 5;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  EOE_CSTEMP_EWMA = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EOE_CSTEMP_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EGR_CSTIME_EWMA
	TempData_Long = (unsigned short)((pINF->Data[10] << 8) +
	                                  pINF->Data[11]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  EGR_CSTIME_EWMA = %d g\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EGR_CSTIME_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EGR_EOE_EWMA
	TempData_Long = (unsigned short)((pINF->Data[12] << 8) +
	                                  pINF->Data[13]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  EGR_EOE_EWMA = %d g\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EGR_EOE_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log EGR_CSTEMP_EWMA
	TempData_Long = (unsigned short)((pINF->Data[14] << 8) +
	                                  pINF->Data[15]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  EGR_CSTEMP_EWMA = %d kJ\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  EGR_CSTEMP_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log TIME_EOE_EWMA
	TempData_Long = (unsigned short)((pINF->Data[16] << 8) +
	                                  pINF->Data[17]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  TIME_EOE_EWMA = %d sec\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  TIME_EOE_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log TIME_CSTEMP_EWMA
	TempData_Long = (unsigned short)((pINF->Data[18] << 8) +
	                                  pINF->Data[19]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F884  TIME_CSTEMP_EWMA = %d sec\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  TIME_CSTEMP_EWMA must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF85_8D__96_97Data
**
**  Purpose:   Verify 2 x 4-Byte data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF85_8D__96_97Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

#define MAXNAMESTRING_85_8D   100
#define MAXUNITSSTRING_85_8D  6
	char   NameString1[MAXNAMESTRING_85_8D];
	char   NameString2[MAXNAMESTRING_85_8D];
	float  Multiplier = 1;
	BYTE   DecimalPlaces = 0;
	char   UnitsString[MAXUNITSSTRING_85_8D];

	float TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x85:
		{
			// Total net battery current in propulsion system active operation (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "TNBC_PSA-R" );

			// Total net battery current in propulsion system active operation (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "TNBC_PSA-L" );

			Multiplier = (float)0.001;
			DecimalPlaces = 3;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "Ah" );
		}
		break;
		case 0x86:
		{
			// Total net energy consumed in propulsion system active operation (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "TNEC_PSA-R" );

			// Total net energy consumed in propulsion system active operation (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "TNEC_PSA-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
		case 0x87:
		{
			// Total energy into battery during propulsion system active (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "TEB_PSA-R" );

			// Total energy into battery during propulsion system active (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "TEB_PSA-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
		case 0x88:
		{
			// Total grid energy into the battery during off-board charging (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "TGE_OVC-R" );

			// Total grid energy into the battery during off-board charging (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "TGE_OVC-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
		case 0x89:
		{
			// Total grid energy into the battery from off-board direct current (DC) charging (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "GE_CHG_OVC_DC-R" );

			// Total grid energy into the battery from off-board direct current (DC) charging (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "GE_CHG_OVC_DC-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
		case 0x8A:
		{
			// Total grid energy into the vehicle from off-board AC charging. (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "GE_CHG_OVC_AC-R" );

			// Total grid energy into the vehicle from off-board AC charging. (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "GE_CHG_OVC_AC-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
		case 0x8B:
		{
			// Total battery energy supplied to an off-board usage during propulsion system non-active operation (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "RESS_V2X_EN_NONPSA-R" );

			// Total battery energy supplied to an off-board usage during propulsion system non-active operation (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "RESS_V2X_EN_NONPSA-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
		case 0x8C:
		{
			// Positive Kinetic Energy (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "PKE-R" );

			// Positive Kinetic Energy (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "PKE-L" );
			Multiplier = (float)1.0;
			DecimalPlaces = 0;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "km/h2" );
		}
		break;
		case 0x8D:
		{
			// Total distance traveled (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "CDEODT-R" );

			// Total distance traveled (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "CDEODT-L" );

			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "km" );
		}
		break;
		case 0x96:
		{
			// Total number of propulsion system active events (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "QTY_PSA_TRIPS-R" );

			// Total number of propulsion system active events (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "QTY_PSA_TRIPS-L" );

			Multiplier = 1;
			DecimalPlaces = 0;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "" );
		}
		break;
		case 0x97:
		{
			// Total battery energy supplied to an off-board usage during propulsion system active operation and Zero Speed (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_85_8D, "RESS_V2X_EN_PSAV0-R" );

			// Total battery energy supplied to an off-board usage during propulsion system active operation and Zero Speed (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_85_8D, "RESS_V2X_EN_PSAV0-L" );
			Multiplier = (float)0.1;
			DecimalPlaces = 1;
			strcpy_s ( UnitsString, MAXUNITSSTRING_85_8D, "kWh" );
		}
		break;
	}


	// log Recent
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * Multiplier;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  %s = %.*f %s\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString1,
	      DecimalPlaces,
	      TempData_Float,
	      UnitsString );


	// log Lifetime
	TempData_Float = (float)((pINF->Data[4] << 24) +
	                         (pINF->Data[5] << 16) +
	                         (pINF->Data[6] << 8)  +
	                          pINF->Data[7]) * Multiplier;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  %s = %.*f %s\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString2,
	      DecimalPlaces,
	      TempData_Float,
	      UnitsString );
	if ( (pINF->INFLSB == 0x85 ||
	      pINF->INFLSB == 0x86 ||
	      pINF->INFLSB == 0x96) &&
	     TempData_Float == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  %s must be non-zero\n",
		      GetEcuId ( EcuIdx ),
		      NameString2 );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF8E_90Data
**
**  Purpose:   Verify 2 x 1-Byte data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF8E_90Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

#define MAXNAMESTRING_8E_90   100
#define MAXUNITSSTRING_8E_90  6
	char  NameString1[MAXNAMESTRING_8E_90];
	char  NameString2[MAXNAMESTRING_8E_90];

	short TempData;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 2 bytes of data
	if ( DataSize != 2 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 2 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x8E:
		{
			// Average battery temperature during Propulsion System Active (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_8E_90, "PSA-R" );

			// Average battery temperature during Propulsion System Active (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_8E_90, "PSA-L" );
		}
		break;
		case 0x8F:
		{
			// Average battery temperature during Charging (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_8E_90, "OVC-R" );

			// Average battery temperature during Charging (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_8E_90, "OVC-L" );
		}
		break;
		case 0x90:
		{
			// Average battery temperature while vehicle Off (Recent)
			strcpy_s ( NameString1, MAXNAMESTRING_8E_90, "OFF-R" );

			// Average battery temperature while vehicle Off (Lifetime)
			strcpy_s ( NameString2, MAXNAMESTRING_8E_90, "OFF-L" );
		}
		break;
	}


	// log Recent
	TempData = pINF->Data[0] - 40;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AVG_BATTEMP_%s = %d C\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString1,
	      TempData );
	if ( pINF->INFLSB != 0x8F && pINF->INFLSB != 0x90 &&
	     TempData == -40 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  %s must be greater than -40\n",
		      GetEcuId ( EcuIdx ),
		      NameString1 );
	}


	// log Lifetime
	TempData = pINF->Data[1] - 40;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  AVG_BATTEMP_%s = %d C\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString2,
	      TempData );
	if ( TempData == -40 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  %s must be greater than -40\n",
		      GetEcuId ( EcuIdx ),
		      NameString2 );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF91_93Data
**
**  Purpose:   Verify Battery Pack Time at Temperature data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF91_93Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

#define MAXNAMESTRING_91_93   100
	char  NameString[MAXNAMESTRING_91_93];

	unsigned long  TempData_Long;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x91:
		{
			// Battery Pack Time at Temperature during PSA 
			strcpy_s ( NameString, MAXNAMESTRING_91_93, "PSA" );
		}
		break;
		case 0x92:
		{
			// Battery Pack Time at Temperature with Vehicle Charging
			strcpy_s ( NameString, MAXNAMESTRING_91_93, "OVC" );
		}
		break;
		case 0x93:
		{
			// Battery Pack Time at Temperature with Vehicle Off
			strcpy_s ( NameString, MAXNAMESTRING_91_93, "OFF" );
		}
		break;
	}


	// log < Range 1
	TempData_Long = (pINF->Data[0] << 24) +
	                (pINF->Data[1] << 16) +
	                (pINF->Data[2] << 8)  +
	                 pINF->Data[3];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  RESS_T_TEMP_%s_RNG1-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Long );

	// log >= Range 1, < Range 2
	TempData_Long = (pINF->Data[4] << 24) +
	                (pINF->Data[5] << 16) +
	                (pINF->Data[6] << 8)  +
	                 pINF->Data[7];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  RESS_T_TEMP_%s_RNG12-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Long );

	// log >= Range 2, < Range 3
	TempData_Long = (pINF->Data[8]  << 24) +
	                (pINF->Data[9]  << 16) +
	                (pINF->Data[10] << 8)  +
	                 pINF->Data[11];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  RESS_T_TEMP_%s_RNG23-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Long );

	// log >= Range 3, < Range 4
	TempData_Long = (pINF->Data[12] << 24) +
	                (pINF->Data[13] << 16) +
	                (pINF->Data[14] << 8)  +
	                 pINF->Data[15];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  RESS_T_TEMP_%s_RNG34-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Long );

	// log >= Range 4, < Range 5
	TempData_Long = (pINF->Data[16] << 24) +
	                (pINF->Data[17] << 16) +
	                (pINF->Data[18] << 8)  +
	                 pINF->Data[19];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  RESS_T_TEMP_%s_RNG45-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Long );

	// log > Range 5
	TempData_Long = (pINF->Data[20] << 24) +
	                (pINF->Data[21] << 16) +
	                (pINF->Data[22] << 8)  +
	                 pINF->Data[23];
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  RESS_T_TEMP_%s_RNG5-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Long );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF94Data
**
**  Purpose:   Verify Minimum and  Maximum Pack Temperature (Lifetime) data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF94Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 2 bytes of data
	if ( DataSize != 2 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F894  Data Size = %d (Must be 2 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	// log Maximum Pack Temperature  (Lifetime)
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F894  MAX_BATTEMP-L = %d C\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[0] - 40 );

	// log Minimum Pack Temperature  (Lifetime)
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F894  MIN_BATTEMP-L = %d C\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[1] - 40 );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF95Data
**
**  Purpose:   Verify Average Battery Pack Temperature (Lifetime) data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF95Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 1 byte of data
	if ( DataSize != 1 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F895  Data Size = %d (Must be 1 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Average Battery Pack Temperature (Lifetime)
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F895  AVG_BATTEMP-L = %d C\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[0] - 40 );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF98_99Data
**
**  Purpose:   Verify Energy Storage System Depth of Discharge Counter data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF98_99Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

#define MAXRANGESTRING_98_99  10
	char  NameChar;
	char  RangeString[MAXRANGESTRING_98_99];

	BYTE  RangeIdx;
	unsigned long TempData_Long;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 16 bytes of data
	if ( DataSize != 16 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 16 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x98:
		{
			NameChar = 'R';
		}
		break;
		case 0x99:
		{
			NameChar = 'L';
		}
		break;
	}


	for ( RangeIdx = 0;
	      RangeIdx < 8;
	      RangeIdx++ )
	{
		switch ( RangeIdx )
		{
			case 0:
			{
				strcpy_s ( RangeString, MAXRANGESTRING_98_99, "RNG1" );
			}
			break;

			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			{
				sprintf_s ( RangeString, MAXRANGESTRING_98_99,
				            "RNG%d%d",
				            RangeIdx,
				            RangeIdx+1 );
			}
			break;

			case 7:
			{
				strcpy_s ( RangeString, MAXRANGESTRING_98_99, "RNG7" );
			}
			break;
		}

		// log DOD
		TempData_Long = (unsigned long)((pINF->Data[RangeIdx*2] << 8) +
		                                 pINF->Data[(RangeIdx*2)+1]);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  RESS_CNTS_DOD_%s-%c = %lu\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      RangeString,
		      NameChar,
		      TempData_Long );
		if ( pINF->INFLSB == 0x98 &&
		     TempData_Long != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  RESS_CNTS_DOD_%s-%c must be zero\n",
			      GetEcuId ( EcuIdx ),
			      RangeString,
			      NameChar );
			eRetCode = FAIL;
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF9AData
**
**  Purpose:   Verify Energy Storage System (ESS) data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF9AData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 3 bytes of data
	if ( DataSize != 3 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F89A  Data Size = %d (Must be 3 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}

	// log Energy Storage System (ESS) Time at Temperature Range Axis
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89A  RESS_T_TEMP_RNGAXIS = %d\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[0] );
	if ( pINF->Data[0] == 0 &&
	    (IsIDSupported ( EcuIdx, INFREQUEST, 0xF891 ) == TRUE ||
	     IsIDSupported ( EcuIdx, INFREQUEST, 0xF892 ) == TRUE ||
	     IsIDSupported ( EcuIdx, INFREQUEST, 0xF893 ) == TRUE) )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  RESS_T_TEMP_RNGAXIS must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log ESS Cumulative Times at SOC Range Axis
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89A  RESS_TIME_SOC_RNGAXIS = %d\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[1] );
	if ( pINF->Data[1] == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  RESS_TIME_SOC_RNGAXIS must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log ESS Depth of Discharge Charge Cycle Counters Range Axis
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89A  RESS_CNTS_DOD_RNGAXIS = %d\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[2] );
	if ( pINF->Data[2] == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  RESS_CNTS_DOD_RNGAXIS must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF9BData
**
**  Purpose:   Verify Fuel Cell data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF9BData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float          TempData_Float;
	unsigned long  TempData_Long;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 24 bytes of data
	if ( DataSize != 24 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F89B  Data Size = %d (Must be 24 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Recent Total FC Fuel Consumed
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * (float)0.01;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89B  FC-R = %10.2f kg\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );
	if ( TempData_Float == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  FC-R must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log Lifetime Total FC Fuel Consumed
	TempData_Float = (float)((pINF->Data[4] << 24) +
	                         (pINF->Data[5] << 16) +
	                         (pINF->Data[6] << 8)  +
	                          pINF->Data[7]) * (float)0.01;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89B  FC-L = %10.2f kg\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );
	if ( TempData_Float == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  FC-L must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log Recent Total FC Active Time
	TempData_Long = (unsigned long)((pINF->Data[8]  << 24) +
	                                (pINF->Data[9]  << 16) +
	                                (pINF->Data[10] << 8)  +
	                                 pINF->Data[11]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89B  FCAT-R = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  FCAT-R must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log Lifetime Total FC Active Time
	TempData_Long = (unsigned long)((pINF->Data[12] << 24) +
	                                (pINF->Data[13] << 16) +
	                                (pINF->Data[14] << 8)  +
	                                 pINF->Data[15]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89B  FCAT-L = %lu sec\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  FCAT-L must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log Recent Total FC System Energy Generated
	TempData_Long = (unsigned long)((pINF->Data[16] << 24) +
	                                (pINF->Data[17] << 16) +
	                                (pINF->Data[18] << 8)  +
	                                 pINF->Data[19]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89B  TFSEG-R = %d kWh\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  TFSEG-R must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}


	// log Lifetime Total FC Fuel Consumed
	TempData_Long = (unsigned long)((pINF->Data[20] << 24) +
	                                (pINF->Data[21] << 16) +
	                                (pINF->Data[22] << 8)  +
	                                 pINF->Data[23]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F89B  TFSEG-L = %d kWh\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Long );
	if ( TempData_Long == 0 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  TFSEG-L must be non-zero\n",
		      GetEcuId ( EcuIdx ) );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINF9C_A1Data
**
**  Purpose:   Verify Traction Motor (A-E) Total Output Energy data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINF9C_A1Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	char  MotorChar;

	unsigned long TempData_Long;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0x9C:
		{
			MotorChar = 'A';
		}
		break;
		case 0x9D:
		{
			MotorChar = 'B';
		}
		break;
		case 0x9E:
		{
			MotorChar = 'C';
		}
		break;
		case 0x9F:
		{
			MotorChar = 'D';
		}
		break;
		case 0xA1:
		{
			MotorChar = 'E';
		}
		break;
	}


	// log Recent
	TempData_Long = (unsigned long)((pINF->Data[0] << 24) +
	                                (pINF->Data[1] << 16) +
	                                (pINF->Data[2] << 8)  +
	                                 pINF->Data[3]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  ETM_%c_TOE-R = %lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      MotorChar,
	      TempData_Long );


	// log Lifetime
	TempData_Long = (unsigned long)((pINF->Data[4] << 24) +
	                                (pINF->Data[5] << 16) +
	                                (pINF->Data[6] << 8)  +
	                                 pINF->Data[7]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  ETM_%c_TOE-L = %lu kWh\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      MotorChar,
	      TempData_Long );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA2Data
**
**  Purpose:   Verify Date of Manufacture of Vehicle data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA2Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A2  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	// log Date of Manufacture of Vehicle
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A2  MANF_DATE = %c%c%c%c:%c%c:%c%c\n",
	      GetEcuId ( EcuIdx ),
	      pINF->Data[0], pINF->Data[1], pINF->Data[2], pINF->Data[3],  // year
	      pINF->Data[4], pINF->Data[5],                                // month
	      pINF->Data[6], pINF->Data[7] );                              // day

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA3Data
**
**  Purpose:   Verify Energy Storage Distance Travelled (Virtual Odometer/Virtual Distance) data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA3Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float   TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 4 bytes of data
	if ( DataSize != 4 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A3  Data Size = %d (Must be 4 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Energy Storage Distance Travelled (Virtual Odometer/Virtual Distance)
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * (float)0.1;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A3  ES_DT = %10.1f km\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA4Data
**
**  Purpose:   Verify Total energy supplied to a non-propulsion usage during propulsion system active operation and vehicle in motion data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA4Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float   TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A4  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Total energy supplied to a non-propulsion usage during propulsion system active operation and vehicle in motion (Recent)
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * (float)0.1;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A4  RESS_V2X_EN_PSAMOVING-R = %10.1f kWh\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );


	// log Total energy supplied to a non-propulsion usage during propulsion system active operation and vehicle in motion (Lifetime)
	TempData_Float = (float)((pINF->Data[4] << 24) +
	                         (pINF->Data[5] << 16) +
	                         (pINF->Data[6] << 8)  +
	                          pINF->Data[7]) * (float)0.1;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A4  RESS_V2X_EN_PSAMOVING-L = %10.1f kWh\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA5Data
**
**  Purpose:   Verify V2X Ratio data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA5Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float   TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 1 byte of data
	if ( DataSize != 1 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A5  Data Size = %d (Must be 1 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log V2X Ratio
	TempData_Float = (float)(pINF->Data[0]) * (float)(100.0 / 255.0);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A5  V2X_RAT = %10.8f %%\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA6Data
**
**  Purpose:   Verify Certified Energy Consumption data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA6Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float   TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 2 bytes of data
	if ( DataSize != 2 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A3  Data Size = %d (Must be 2 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Certified Energy Consumption
	TempData_Float = (float)((pINF->Data[0] << 8)  +
	                          pINF->Data[1]) * (float)0.1;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A6  CEC_WC = %10.1f Wh/km",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA7Data
**
**  Purpose:   Verify Certified Energy Consumption data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA7Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	unsigned short  TempData;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 2 bytes of data
	if ( DataSize != 2 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A7  Data Size = %d (Must be 2 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Certified Energy Consumption
	TempData = (unsigned short)((pINF->Data[0] << 8) +
	                             pINF->Data[1]);
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A7  SOC_T_50PCT_SWG = %d days",
	      GetEcuId ( EcuIdx ),
	      TempData );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA8Data
**
**  Purpose:   Verify Energy Storage Distance Travelled (Virtual Odometer/Virtual Distance) data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA8Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float   TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 4 bytes of data
	if ( DataSize != 4 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8A8  Data Size = %d (Must be 4 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      DataSize );
		return FAIL;
	}


	// log Energy Storage Distance Travelled (Virtual Odometer/Virtual Distance)
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * (float)0.001;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8A8  UBE_CERT = %10.3f kWh\n",
	      GetEcuId ( EcuIdx ),
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFA9_AEData
**
**  Purpose:   Verify ESS Accumulated Time at SOC data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFA9_AEData ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

#define MAXNAMESTRING_A9_AE   4
#define MAXRANGESTRING_A9_AE  6
	char  NameString[MAXNAMESTRING_A9_AE];
	char  NameChar;
	char  RangeString[MAXRANGESTRING_A9_AE];

	BYTE  RangeIdx;
	unsigned long TempData_Long;
	BYTE  ZeroCnt = 0;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 32 bytes of data
	if ( DataSize != 32 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 32 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0xA9:
		{
			strcpy_s ( NameString, MAXNAMESTRING_A9_AE, "PSA" );
			NameChar = 'R';
		}
		break;
		case 0xAA:
		{
			strcpy_s ( NameString, MAXNAMESTRING_A9_AE, "PSA" );
			NameChar = 'L';
		}
		break;
		case 0xAB:
		{
			strcpy_s ( NameString, MAXNAMESTRING_A9_AE, "CHG" );
			NameChar = 'R';
		}
		break;
		case 0xAC:
		{
			strcpy_s ( NameString, MAXNAMESTRING_A9_AE, "CHG" );
			NameChar = 'L';
		}
		break;
		case 0xAD:
		{
			strcpy_s ( NameString, MAXNAMESTRING_A9_AE, "OFF" );
			NameChar = 'R';
		}
		break;
		case 0xAE:
		{
			strcpy_s ( NameString, MAXNAMESTRING_A9_AE, "OFF" );
			NameChar = 'L';
		}
		break;
	}


	for ( RangeIdx = 0;
	      RangeIdx < 8;
	      RangeIdx++ )
	{
		switch ( RangeIdx )
		{
			case 0:
			{
				strcpy_s ( RangeString, MAXRANGESTRING_A9_AE, "RNG1" );
			}
			break;

			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			{
				sprintf_s ( RangeString, MAXRANGESTRING_A9_AE,
				            "RNG%d%d",
				            RangeIdx,
				            RangeIdx+1 );
			}
			break;

			case 7:
			{
				strcpy_s ( RangeString, MAXRANGESTRING_A9_AE, "RNG7" );
			}
			break;
		}

		// log Energy Storage Accumulated Time at SOC
		TempData_Long = (unsigned long)((pINF->Data[RangeIdx*4]     << 24) +
		                                (pINF->Data[(RangeIdx*4)+1] << 16) +
		                                (pINF->Data[(RangeIdx*4)+2] << 8)  +
		                                 pINF->Data[(RangeIdx*4)+3]);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  RESS_TIME_SOC_%s_%s-%c = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      NameString,
		      RangeString,
		      NameChar,
		      TempData_Long );
		if ( TempData_Long == 0 )
		{
			ZeroCnt++;
		}
	}

	if ( (pINF->INFLSB == 0xA9 ||
	      pINF->INFLSB == 0xAA ) &&
	     ZeroCnt == 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  %s must not all be zero\n",
		      GetEcuId ( EcuIdx ),
		      NameString );
	}
	else if ( pINF->INFLSB == 0xAE &&
	          ZeroCnt == 8 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  %s should not all be zero\n",
		      GetEcuId ( EcuIdx ),
		      NameString,
		      RangeString );
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFAF_B3Data
**
**  Purpose:   Verify Total Energy data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFAF_B3Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

#define MAXNAMESTRING_AF_B3   20
	char  NameString[MAXNAMESTRING_AF_B3];

	float TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8%02X  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	switch ( pINF->INFLSB )
	{
		case 0xAF:
		{
			strcpy_s ( NameString, MAXNAMESTRING_AF_B3, "RESS_V2X_TOT_EN" );
		}
		break;
		case 0xB0:
		{
			strcpy_s ( NameString, MAXNAMESTRING_AF_B3, "RESS_V2X_EN_PSAV0" );
		}
		break;
		case 0xB1:
		{
			strcpy_s ( NameString, MAXNAMESTRING_AF_B3, "RESS_V2X_EN_PSAV0" );
		}
		break;
		case 0xB2:
		{
			strcpy_s ( NameString, MAXNAMESTRING_AF_B3, "RESS_V2X_EN_TOT" );
		}
		break;
		case 0xB3:
		{
			strcpy_s ( NameString, MAXNAMESTRING_AF_B3, "RESS_EN_ACCUM" );
		}
		break;
	}

	// log Energy Storage (Recent)
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * (float)0.1;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  %s-R = %10.1f kWh\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Float );

	// log Energy Storage (Accumulated Time at SOC (Lifetime)
	TempData_Float = (float)((pINF->Data[4] << 24) +
	                         (pINF->Data[5] << 16) +
	                         (pINF->Data[6] << 8)  +
	                          pINF->Data[7]) * (float)0.1;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  %s-L = %10.1f kWh\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      NameString,
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFB4Data
**
**  Purpose:   Verify Gaseous Fuel Consumption data.
**             In the event the data fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyINFB4Data ( BYTE EcuIdx )
{
	INF    *pINF;
	BYTE    DataSize;
	STATUS  eRetCode = PASS;

	float TempData_Float;


	pINF = (INF*)&gstResponse[EcuIdx].INF[0];
	// Don't include INF MSB or INF LSB in Data Size
	DataSize = gstResponse[EcuIdx].INFSize - 2;

	// Check the Data Size
	// must contain 8 bytes of data
	if ( DataSize != 8 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $F8B4  Data Size = %d (Must be 8 bytes!)\n",
		      GetEcuId ( EcuIdx ),
		      pINF->INFLSB,
		      DataSize );
		return FAIL;
	}


	// log Total Gaseous Fuel Consumed (Recent)
	TempData_Float = (float)((pINF->Data[0] << 24) +
	                         (pINF->Data[1] << 16) +
	                         (pINF->Data[2] << 8)  +
	                          pINF->Data[3]) * (float)0.01;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  FC-R = %10.2f kg\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      TempData_Float );

	// log Total Gaseous Fuel Consumed (Lifetime)
	TempData_Float = (float)((pINF->Data[4] << 24) +
	                         (pINF->Data[5] << 16) +
	                         (pINF->Data[6] << 8)  +
	                          pINF->Data[7]) * (float)0.01;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $F8%02X  FC-L = %10.2f kg\n",
	      GetEcuId ( EcuIdx ),
	      pINF->INFLSB,
	      TempData_Float );

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFChange
**
**  Purpose:
**
*******************************************************************************/
STATUS VerifyINFChange ( void )
{
	REQ_MSG        stReqMsg;
	INF           *pINF;
	BYTE           EcuIdx;     // ECU Index
	unsigned short IdIdx;      // INF ID index
	unsigned short MaxId;      // Maximum INF ID

	BOOL           bTestFailed = FALSE;
	unsigned long  InitialFailureCount = 0;


	InitialFailureCount = GetFailureCount ( );


	// Request INF support data
	if ( RequestIDSupportData ( INFREQUEST, TRUE ) != PASS )
	{
		return FAIL;
	}


	if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 18 )  // IF Test 9.18
	{
		if ( gModelYear >= 2022 &&
		     gstUserInput.eVehicleType == HD )
		{
			MaxId = 0xF844;
		}
		else
		{
			MaxId = 0xF819;
		}
	}
	else
	{
		MaxId = 0xF829;
	}


	// For each INF group verify that all INF data is valid
	//  Request user supplied expected OBD ECU responses
	for ( IdIdx = 0xF816;
	      IdIdx <= MaxId;
	      IdIdx++ )
	{
		// If INF is supported by any ECU, request it
		if ( IsIDSupported ( ALLECUS, INFREQUEST, IdIdx ) == TRUE  )
		{
			stReqMsg.SID      = 0x22;
			stReqMsg.NumIds   = 1;
			stReqMsg.u.DID[0] = IdIdx;
			if ( RequestSID ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
			{
				bTestFailed = TRUE;
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $%04X request\n",
				      IdIdx );

				continue;  // just go to the next itteration of the INF for loop
			}

			for ( EcuIdx = 0;
			      EcuIdx < gUserNumOfECUs;
			      EcuIdx++ )
			{
				// If INF is not supported, skip to next ECU
				if ( IsIDSupported ( EcuIdx, INFREQUEST, IdIdx ) == FALSE )
				{
					continue;  // just go to the next itteration of the ECU for loop
				}


				// Check the data to see if it is valid
				pINF = (INF *)&gstResponse[EcuIdx].INF[0];

				// if there is no data, don't check it
				if ( gstResponse[EcuIdx].INFSize == 0 )
				{
					bTestFailed = TRUE;
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  No INF $%04X data\n",
					      GetEcuId ( EcuIdx ),
					      IdIdx );
					continue;  // just go to the next itteration of the ECU for loop
				}

				// Check various INF values for validity
				switch ( IdIdx )
				{
					case INF_TYPE_ER_IT:  // INFOTYPE $16 Engine Run/Idle Time
					{
						if ( VerifyINF16Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_DT_FC:  // INFOTYPE $17 Distance/Fuel Used
					{
						if ( VerifyINF17Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_PKE_EOE:  // INFOTYPE $18 PKE/EOE
					{
						if ( VerifyINF18Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_PSA:  // INFOTYPE $19 PSA
					{
						if ( VerifyINF19Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_PHEVDD:  // INFOTYPE 0x1A PHEVDD
					{
						if ( VerifyINF1AData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_PHEVFD:  // INFOTYPE 0x1B PHEVFD
					{
						if ( VerifyINF1BData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_PHEVGD:  // INFOTYPE 0x1C PHEVGD
					{
						if ( VerifyINF1CData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_AAF1OCCVD:  // INFOTYPE 0x1D AAF1OCCVD
					{
						if ( VerifyINF1DData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_AAF2OCCVD:  // INFOTYPE 0x1E AAF2OCCVD
					{
						if ( VerifyINF1EData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_AAF3OCCVD:  // INFOTYPE 0x1F AAF3OCCVD
					{
						if ( VerifyINF1FData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_DSOMOCCVD:  // INFOTYPE 0x21 DSOMOCCVD
					{
						if ( VerifyINF21Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_RTSSCOCCVD:  // INFOTYPE 0x22 RTSSCOCCVD
					{
						if ( VerifyINF22Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_DCTOCCVD:  // INFOTYPE 0x23 DCTOCCVD
					{
						if ( VerifyINF23Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_APTWUFOCCVD:  // INFOTYPE 0x24 APTWUFOCCVD
					{
						if ( VerifyINF24Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_OCCT1VD:  // INFOTYPE 0x25 OCCT1VD
					case INF_TYPE_OCCT2VD:  // INFOTYPE 0x26 OCCT2VD
					case INF_TYPE_OCCT3VD:  // INFOTYPE 0x27 OCCT3VD
					case INF_TYPE_OCCT4VD:  // INFOTYPE 0x28 OCCT4VD
					case INF_TYPE_OCCT5VD:  // INFOTYPE 0x29 OCCT5VD
					{
						if ( VerifyINF25_29Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_HDGHGA100HD1:  // INFOTYPE 0x41
					case INF_TYPE_HDGHGS100HD1:  // INFOTYPE 0x43
					{
						if ( VerifyINF41_43_45Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_HDGHGA100HD2:  // INFOTYPE 0x42
					case INF_TYPE_HDGHGS100HD2:  // INFOTYPE 0x44
					{
						if ( VerifyINF42_44_46Data ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

				} // end switch ( pINF->INFLSB )
			} // end for ( EcuIdx )
		} // end if ( IsIDSupported ( ALLECUS, IdIdx)  == TRUE )

		// Verify that required INFs are supported by the appropriate vehicles
		else
		{
			if ( gModelYear >= 2019 )
			{
				if ( gstUserInput.eComplianceType == US_OBDII &&
				     (gstUserInput.eVehicleType == LD || gstUserInput.eVehicleType == MD) )
				{
					if ( IdIdx <= 0xF819 )
					{
						if ( gModelYear == 2019 || gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n",
							      IdIdx );
						}
						else
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}
					else if ( IdIdx >= 0xF81A && IdIdx <= 0xF81C &&
					          gstUserInput.ePwrTrnType == PHEV )
					{
						if ( gModelYear == 2019 || gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2019 and later Light Duty PHEV vehicles)\n",
							      IdIdx );
						}
						else
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2019 and later Light Duty PHEV vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}
				}

				else if ( (gstUserInput.eComplianceType == EOBD ||
				           gstUserInput.eComplianceType == EOBD_NO_IUMPR) &&
				          (gstUserInput.eVehicleType == LD || gstUserInput.eVehicleType == MD) )
				{
					if ( IdIdx == 0xF817 )
					{
						if ( gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2020 and later Light Duty vehicles)\n",
							      IdIdx );
						}
						else if ( gModelYear > 2020 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2020 and later Light Duty vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}

					else if ( IdIdx >= 0xF81A && IdIdx <= 0xF81C &&
					          gstUserInput.ePwrTrnType == PHEV )
					{
						if ( gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2020 and later Light Duty PHEV vehicles)\n",
							      IdIdx );
						}
						else if ( gModelYear > 2020 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%04X is not supported by any ECU! (Required for MY 2020 and later Light Duty PHEV vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}
				}
			}


			if ( gModelYear >= 2022 && HD )
			{
				if ( IdIdx >= 0xF841 && IdIdx <= 0xF844 )
				{
					if ( gModelYear == 2022 || gModelYear == 2023 )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $%04X is not supported by any ECU! (Required for MY 2022 and later Heavy Duty vehicles)\n",
						      IdIdx );
					}
					else
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $%04X is not supported by any ECU! (Required for MY 2022 and later Heavy Duty vehicles)\n",
						      IdIdx );
						bTestFailed = TRUE;
					}
				}
			}
		}


		if ( IdIdx == 0x19 && MaxId == 0xF844 )
		{
			IdIdx = 0xF840;
		}
	} // end for ( IdIdx )


	// If there where any errors in the responses, fail
	if ( bTestFailed == TRUE || InitialFailureCount != GetFailureCount ( ) )
	{
		// There could have been early/late responses that weren't treated as FAIL
		return FAIL;
	}
	else
	{
		return PASS;
	}
}
