/*******************************************************************************
********************************************************************************
**
**  Copyright(c) 2022, Alliance for Automotive Innovation
**  Used only under license from the Alliance for Automotive Innovation. All Rights Reserved.
**
**  Project:  J1699-3
**  FileName: VerifyVehicleInformationSupportAndData.c
**  Author:   EnGenius
**  Date:     2/25/2022
**  Email:    <support@autosinnovate.org>
**
**  Purpose:  SAE J1699-3 Vehicle OBD II Compliance Test Cases Source Code.
**            This source code is intended to run the tests described in
**            the SAE J1699-3 document in an automated manner, when compiled
**            and used with an SAE J2534-compatible pass-thru device.
**
**            File j1699.c contains information on building and running this test.
**
**  Description:
**
**  Modifications:  12/07/2022  Initial Version
**
********************************************************************************
*******************************************************************************/

#include <stdio.h>    // C Library input and output declarations
#include <stdlib.h>   // C Library general 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


// Function Prototypes
STATUS VerifyVINData   ( BYTE EcuIdx );
STATUS VerifyCALIDData ( BYTE EcuIdx, unsigned long Inf3NumItems );
STATUS VerifyCVNData   ( BYTE EcuIdx, unsigned long Inf5NumItems );
STATUS VerifyECUNameData ( BYTE EcuIdx );
STATUS VerifyInf8Data  ( BYTE EcuIdx );
STATUS VerifyInfBData  ( BYTE EcuIdx );
STATUS VerifyInfD_FData ( 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 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 );


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;

	float         INF17_DT_R;
	float         INF17_DT_L;

	float         INF17_FC_R;
	float         INF17_FC_L;

	float         INF18_EOE_R;
	float         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;
	float         INF41_DT_A;
	float         INF41_EOE_A;
	float         INF41_VFC_A;

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

	float         INF43_DT_S;
	float         INF43_EOE_S;
	float         INF43_VFC_S;

	float         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;

	float         INF61_NOxEOB_A[17];

	float         INF62_NOxTPB_A[17];

	float         INF63_EOEB_A[17];

	float         INF64_DTB_A[17];
} INFCOMP;
INFCOMP  Test_5_17_Inf[MAX_ECUS];


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

	BYTE           EcuIdx;      // ECU Index
	BYTE           EcuLoopIdx;  // nested ECU Index
	unsigned long  IdIdx;       // INF ID index
	unsigned long  Index;       // multi-part message index

	unsigned long  Inf3NumItems[MAX_ECUS];
	unsigned long  Inf5NumItems[MAX_ECUS];
	unsigned long  Inf7NumItems[MAX_ECUS];
	unsigned long  Inf9NumItems[MAX_ECUS];
	unsigned long  InfCNumItems[MAX_ECUS];
	unsigned long  InfENumItems[MAX_ECUS];

	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
	BYTE           Inf8NumResponses = 0;      // number of INF $08 responses
	BOOL           bInfAResponded[MAX_ECUS];  // per ECU INF $A response indicator
	BYTE           InfBNumResponses = 0;      // number of INF $0B responses
	BYTE           InfDNumResponses = 0;      // number of INF $0D responses
	BYTE           Inf13NumResponses = 0;     // number of INF $13 responses

	#define  MAX_INF_ID 0x78
	BYTE  InfSupportCountList[] =
	{0x02,0x04,0x06,0x08,0x0A,0x0B,0x0D,
	 0x12,0x13,0x14,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
	 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,
	 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
	 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,
	 0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
	 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78};
	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  bTestFailed = FALSE;

	unsigned long InitialFailureCount = 0;


	InitialFailureCount = GetFailureCount ( );

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

	// Request SID 9 support data
	if ( RequestIDSupportData ( INFREQUEST, FALSE ) != PASS )
	{
		return FAIL;
	}


	// Determine number of ECUs supporting required INFs
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		// initialize the array values for this EcuIdx before use
		Inf3NumItems[EcuIdx] = 0;
		Inf5NumItems[EcuIdx] = 0;
		Inf7NumItems[EcuIdx] = 0;
		Inf9NumItems[EcuIdx] = 0;
		InfCNumItems[EcuIdx] = 0;
		InfENumItems[EcuIdx] = 0;
		bInf4Responded[EcuIdx] = FALSE;
		bInfAResponded[EcuIdx] = FALSE;
		bInf2Supported[EcuIdx] = FALSE;
		bInf13Supported[EcuIdx] = FALSE;


		for ( IdIdx = 0;
		      IdIdx <= sizeof ( InfSupportCountList );
		      IdIdx++ )
		{
			if ( IsIDSupported ( EcuIdx, INFREQUEST, InfSupportCountList[IdIdx] ) == TRUE )
			{
				InfSupportCount[InfSupportCountList[IdIdx]]++;

				if ( InfSupportCountList[IdIdx] == 0x02 )
				{
					bInf2Supported[EcuIdx] = TRUE;
				}

				// Spark Ignition IPT support
				else if ( InfSupportCountList[IdIdx] == 0x08 )
				{
					// if ECU does not only supports CCM requirements (SID 1 PID 1 Data B bit 2==1)
					if ( (gstEcuSIDData[EcuIdx].Pid01.Data[1] & 0x03) != 0x00 ||
					     (gstEcuSIDData[EcuIdx].Pid01.Data[2] & 0xFF) != 0x00 )
					{
						// Spark Ignition operator selection
						if ( gbDiesel == FALSE )
						{
							// Compression Ignition PID 01 DATA_B Bit_3
							if ( (gstEcuSIDData[EcuIdx].Pid01.Data[1] & 0x08) != 0 &&
							     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD ||
							      gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD ||
							      gstUserInput.eComplianceType == CNOBD_NO_IUMPR) )
							{
								if ( gModelYear >= 2010 )
								{
									Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
									bTestFailed = TRUE;
								}
								else
								{
									Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
								}
							}
						}
						// Compression Ignition operator selection
						else
						{
							if ( gModelYear >= 2010 )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  SID $09 IPT (INF $08) support does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
								      GetEcuId ( EcuIdx ) );
								bTestFailed = TRUE;
							}
							else
							{
								Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  SID $09 IPT (INF $08) support does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
								      GetEcuId ( EcuIdx ) );
							}

							// Spark Ignition PID 01 DATA_B Bit_3
							if ( (gstEcuSIDData[EcuIdx].Pid01.Data[1] & 0x08) == 0 )
							{
								if ( gModelYear >= 2010 )
								{
									Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
									bTestFailed = TRUE;
								}
								else
								{
									Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
								}
							}
						}
					} // end if ECU does not only supports CCM requirements (SID 1 PID 1 Data B bit 2==1)
				} // end if ( IdIdx == 0x08 )

				// Compression Ignition IPT support
				else if ( InfSupportCountList[IdIdx] == 0x0B )
				{
					// if ECU does not only supports CCM requirements (SID 1 PID 1 Data B bit 2==1)
					if ( (gstEcuSIDData[EcuIdx].Pid01.Data[1] & 0x03) != 0x00 ||
					     (gstEcuSIDData[EcuIdx].Pid01.Data[2] & 0xFF) != 0x00 )
					{
						// Compression Ignition operator selection
						if ( gbDiesel == TRUE )
						{
							// Compression Ignition PID 01 DATA_B Bit_3
							if ( (gstEcuSIDData[EcuIdx].Pid01.Data[1] & 0x08) == 0 )
							{
								if ( gModelYear >= 2010 )
								{
									Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
									bTestFailed = TRUE;
								}
								else
								{
									Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
								}
							}
						}
						// Spark Ignition operator selection
						else
						{
							if ( gModelYear >= 2010 )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  SID $09 IPT (INF $0B) support does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
								      GetEcuId ( EcuIdx ) );
								bTestFailed = TRUE;
							}
							else
							{
								Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  SID $09 IPT (INF $0B) support does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
								      GetEcuId ( EcuIdx ) );
							}

							// Compression Ignition PID 01 DATA_B Bit_3
							if ( (gstEcuSIDData[EcuIdx].Pid01.Data[1] & 0x08) != 0 )
							{
								if ( gModelYear >= 2010 )
								{
									Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  SID $01 PID $01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
									bTestFailed = TRUE;
								}
								else
								{
									Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  PID 01 DATA_B Bit_3 does not match Operator Selected Ignition Type (Required for MY 2010 and later vehicles)\n",
									      GetEcuId ( EcuIdx ) );
								}
							}
						} // end gbDiesel == FALSE
					} // end if ECU does not only supports CCM requirements (SID 1 PID 1 Data B bit 2==1)
				} // end if ( IdIdx == 0x0B )

				else if ( InfSupportCountList[IdIdx] == 0x13 )
				{
					bInf13Supported[EcuIdx] = TRUE;
				}
			} // end if INF supported

			// if INF not supported
			else
			{
				if ( InfSupportCountList[IdIdx] == 0x0A )
				{
					// Verify that INF $A is supported for MY 2010 and later
					if ( gModelYear >= 2010 &&
					     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD ||
					      gstUserInput.eComplianceType == CNOBD_NO_IUMPR) )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $A not supported! (Required for MY 2010 and later vehicles)\n",
						      GetEcuId ( EcuIdx ) );
						bTestFailed = TRUE;
					}
				}
			} // end if INF notsupported
		} // end for ( IdIdx

		// Check if INF $15 is supported, this is a failure
		if ( IsIDSupported ( EcuIdx, INFREQUEST, 0x15 ) == TRUE )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Supports INF $15 (Must not support INF $15)\n",
			      GetEcuId ( EcuIdx ) );
			bTestFailed = TRUE;
		}
	} // end for ( EcuIdx


	// Check support of required INFs
	// Verify that one and only one ECU supports INF $2 (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 $2 (VIN) not supported by any ECUs\n" );
			bTestFailed = TRUE;
		}
		else
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $2 (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,
				      "INF $2 (VIN) supported by multiple ECUs ( ECU %X )\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		bTestFailed = TRUE;
	}

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

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

	// Verify that INF $8 and INF $B are not both supported
	if ( InfSupportCount[0x08] != 0 && InfSupportCount[0x0B] != 0 &&
	     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD ||
	      gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD ||
	      gstUserInput.eComplianceType == CNOBD_NO_IUMPR) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Both INF $8 and INF $B are supported!\n" );
		bTestFailed = TRUE;
	}

	if ( InfSupportCount[0x08] == 0 && InfSupportCount[0x0B] == 0 )
	{
		// Verify that INF $8 or INF $B (IPT) is supported by at least one ECU for MY 2007 and later - OBD II
		if ( gModelYear >= 2007 &&
		     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Neither INF $8 nor INF $B is supported! (Support for one required for MY 2007 and later vehicles)\n" );
			bTestFailed = TRUE;
		}
		// Verify that INF $8 or INF $B (IPT) is supported by at least one ECU - EOBD with IUMPR or HD_EOB
		else if ( gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD ||
		          gstUserInput.eComplianceType == IOBD_NO_IUMPR   || gstUserInput.eComplianceType == HD_IOBD_NO_IUMPR ||
		          gstUserInput.eComplianceType == CNOBD_NO_IUMPR )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Neither INF $8 nor INF $B is supported!\n" );
			bTestFailed = TRUE;
		}
	}

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

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

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

	// Verify that INF $14 is supported for MY 2017 and later OBDII vehicles
	if ( InfSupportCount[0x14] == 0 &&
	     gstUserInput.eComplianceType == US_OBDII &&
	     gbDiesel == FALSE &&
	     gModelYear >= 2017 )
	{
		Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "INF $14 (EVAP_DIST) is not supported by any ECU! (Required for vehicles that meet the LEV III / Tier 3 EVAP requirements)\n" );
	}


	// Verify that INFs $13, $16-$1C are supported by MY 2019 and later Ligth Duty OBDII vehicles
	if ( gstUserInput.eVehicleType == LD &&
	     gstUserInput.eComplianceType == US_OBDII &&
	     gModelYear >= 2019 )
	{
		// Verify that INF $13 is supported for MY 2019 and later Light Duty vehicles
		if ( InfSupportCount[0x13] == 0 )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $13 (TG/EFN) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $13 (TG/EFN) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
		}
		else if ( InfSupportCount[0x13] > 1  )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $13 (TG/EFN) supported by more than one ECU!\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $13 (TG/EFN) supported by more than one ECU!\n" );
				bTestFailed = TRUE;
			}
		}

		// Verify that INF $16 is supported for MY 2019 and later Light Duty vehicles
		if ( InfSupportCount[0x16] == 0 )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $16 (ERT/IERT) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $16 (ERT/IERT) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
		}

		// Verify that INF $17 is supported for MY 2019 and later Light Duty vehicles
		if ( InfSupportCount[0x17] == 0 )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $17 (DT/FC) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $17 (DT/FC) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
		}

		// Verify that INF $18 is supported for MY 2019 and later Light Duty vehicles
		if ( InfSupportCount[0x18] == 0 )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $18 (PKE/EOE) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $18 (PKE/EOE) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
		}

		// Verify that INF $19 is supported for MY 2019 and later Light Duty vehicles
		if ( InfSupportCount[0x19] == 0 )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $19 (PSA) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $19 (PSA) is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
		}

		// Verify that INF $1A is supported for MY 2019 and later Light Duty PHEV vehicles
		if ( InfSupportCount[0x1A] == 0 && gstUserInput.ePwrTrnType == PHEV )
		{
			if ( gModelYear == 2019 || gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $1A (PHEVDD) is not supported by any ECU! (Required for MY 2019 and later Light Duty PHEV vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $1A (PHEVDD) is not supported by any ECU! (Required for MY 2019 and later Light Duty PHEV vehicles)\n" );
				bTestFailed = TRUE;
			}
		}

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

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


	// Verify that INFs $17, $1A-$1C are supported by MY 2019 and later Ligth Duty EOBD vehicles
	if ( gstUserInput.eVehicleType == LD &&
	     (gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
	      gstUserInput.eComplianceType == EOBD_NO_IUMPR) &&
	     gModelYear >= 2020 )
	{
		// Verify that INF $17 is supported for MY 2020 and later Light Duty vehicles
		if ( InfSupportCount[0x17] == 0 )
		{
			if ( gModelYear == 2020 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $17 (DT/FC) is not supported by any ECU! (Required for MY 2020 and later Light Duty vehicles)\n" );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $17 (DT/FC) is not supported by any ECU! (Required for MY 2020 and later Light Duty vehicles)\n" );
				bTestFailed = TRUE;
			}
		}

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

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

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


	// Verify that INFs $41-5B are supported by MY 2024 and later Heavy Duty US vehicles
	for ( IdIdx = 0x41;
	      IdIdx <= 0x5B;
	      IdIdx++ )
	{
		if ( IdIdx >= 0x4A && IdIdx <= 0x4F )
		{
			if ( InfSupportCount[IdIdx] != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $%02X is supported by an ECU! (Reserved infotype)\n",
				      IdIdx );
				bTestFailed = TRUE;
			}
		}
		// MY 2024 and later Heavy Duty US vehicles should support
		else if ( gbHybrid == FALSE &&
		          gstUserInput.eVehicleType == HD &&
		          gstUserInput.eComplianceType == HD_OBD &&
		          gModelYear >= 2022 &&
		          InfSupportCount[IdIdx] == 0 )
		{
			if ( gModelYear == 2022 || gModelYear == 2023 )
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $%02X 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 $%02X is not supported by any ECU! (Required for MY 2022 and later Heavy Duty vehicles)\n",
				      IdIdx );
				bTestFailed = TRUE;
			}
		}
		else if ( (gbHybrid == TRUE ||
		           gstUserInput.eVehicleType != HD) &&
		          gstUserInput.eComplianceType == US_OBDII &&
		          InfSupportCount[IdIdx] != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $%02X is supported by an ECU! (Should only be supported by Heavy Duty vehicles)\n",
			      IdIdx );
			bTestFailed = TRUE;
		}
	}


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


	// Verify that INF $78 is supported for MY 2024 and later Light Duty vehicles or Heavy and Medium Duty Non-Hybrid vehicles
	if ( (gstUserInput.eVehicleType == LD ||
	      (gbHybrid == FALSE &&
	       (gstUserInput.eVehicleType == HD || gstUserInput.eVehicleType == MD))) &&
	     (gstUserInput.eComplianceType == HD_OBD || gstUserInput.eComplianceType == US_OBDII) &&
	     gModelYear >= 2022 &&
	     InfSupportCount[0x78] == 0 )
	{
		if ( gModelYear == 2022 || gModelYear == 2023 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $78 is not supported by any ECU! (Required for MY 2022 and later Heavy Duty and Medium Duty Diesel vehicles)\n" );
		}
		else
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $78 is not supported by any ECU! (Required for MY 2022 and later Heavy Duty and Medium Duty Diesel vehicles)\n" );
			bTestFailed = TRUE;
		}
	}


	// For each INF group
	// Verify that all SID 9 INF data is valid
	// Request user supplied expected OBD ECU responses
	for ( IdIdx  = 0x01;
	      IdIdx <= 0x100;
	      IdIdx++ )
	{
		// If INF is supported by any ECU, request it
		if ( IsIDSupported ( ALLECUS, INFREQUEST, IdIdx ) == TRUE )
		{
			stReqMsg.SID    = 0x09;
			stReqMsg.NumIds = 1;
			stReqMsg.ID[0]  = (BYTE)IdIdx;
			if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
			{
				bTestFailed = TRUE;
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $%X 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 protocol is ISO15765
				if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
				{
					if ( IdIdx ==  0x01 || IdIdx ==  0x03 ||
					     IdIdx ==  0x05 || IdIdx ==  0x07 ||
					     IdIdx ==  0x09 || IdIdx ==  0x0C ||
					     IdIdx ==  0x0E )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $%X is supported (Should not be supported by ISO15765 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 $%02X 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_COUNT:
					{
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     pInf->NODI != 0x05 )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $1 (VIN Count) NODI = %d (should be 5)\n",
							      GetEcuId ( EcuIdx ),
							      pInf->NODI );
						}
					}
					break;

					case INF_TYPE_VIN:
					{
						// Copy the VIN into the global array
						if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
						{
							memcpy ( &gVINString[0],
							         &pInf[0].Data[0],
							         17 );

							/// Check that there are no pad bytes included in message
							if ( pInf[0].Data[20] != 0x00 )
							{
								bTestFailed = TRUE;
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  INF $2 format error! (Must be 17 chars and no pad bytes)\n",
								      GetEcuId ( EcuIdx ) );
							}

							// INF2 NODI must equal $01
							if ( pInf->NODI != 0x01 )
							{
								bTestFailed = TRUE;
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  INF $2 NODI = %d (Must be 1)\n",
								      GetEcuId ( EcuIdx ),
								      pInf->NODI );
							}
						}
						else
						{
							// INF $02 (VIN) should not be supported if INF $01 (VIN msg count) not supported for non-15765 protocols
							if ( IsIDSupported ( EcuIdx, INFREQUEST, 0x01 ) == FALSE )
							{
								bTestFailed = TRUE;
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  INF $2 (VIN) is supported but not INF $1 (VIN msg count)\n",
								      GetEcuId ( EcuIdx ) );
							}

							for ( Index = 0;
							      Index < (gstResponse[EcuIdx].InfSize / sizeof ( INF ));
							      Index++ )
							{
								if ( Index == 0 )
								{
									gVINString[0] = pInf[Index].Data[3];
								}
								else if ( Index < 5 )
								{
									memcpy ( &gVINString[Index*4 - 3],
									         &pInf[Index].Data[0],
									         4 );
								}
							}
						}

						// Check for INF2 (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 $02 (VIN) response from multiple controllers!\n" );
						}
						else if ( Inf2NumResponses != 0x01 &&
						          (gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == EOBD_NO_IUMPR ||
						           gstUserInput.eComplianceType == IOBD_NO_IUMPR   || gstUserInput.eComplianceType == OBDBr_NO_IUMPR ||
						           gstUserInput.eComplianceType == CNOBD_NO_IUMPR) )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $02 (VIN) response from multiple controllers!\n" );
						}

						// Isolated VIN verification logic
						if ( VerifyVINData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_CALID_COUNT:
					{
						// Response should be a multiple of four if not ISO15765
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     (pInf->NODI & 0x03) )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $3 (CALID Count) NODI = %d (should be a multiple of 4)\n",
							      GetEcuId ( EcuIdx ),
							      pInf->NODI );
						}

						Inf3NumItems[EcuIdx] = pInf->NODI;
					}
					break;

					case INF_TYPE_CALID:
					{
						bInf4Responded[EcuIdx] = TRUE;

						if ( VerifyCALIDData ( EcuIdx, Inf3NumItems[EcuIdx] ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_CVN_COUNT:
					{
						Inf5NumItems[EcuIdx] = pInf->NODI;
					}
					break;

					case INF_TYPE_CVN:
					{
						Inf6NumResponses++;

						if ( VerifyCVNData ( EcuIdx, Inf5NumItems[EcuIdx] ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_IPT_COUNT:
					{
						// non-ISO15765 should report 0x08, 0x9, or 0xA
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     pInf->NODI != 0x08 &&
						     pInf->NODI != 0x09 &&
						     pInf->NODI != 0x0A )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $7 (IPT Count) is invalid   Message Count = %d\n",
							      GetEcuId ( EcuIdx ),
							      pInf->NODI );
						}

						Inf7NumItems[EcuIdx] = pInf->NODI;
					}
					break;

					case INF_TYPE_IPT_GAS:
					{
						Inf8NumResponses++;

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

						// Response should match INF7 if not ISO15765
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						    gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != Inf7NumItems[EcuIdx] )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $8 (IPT) Message Count = %d (should match INF7)\n",
							      GetEcuId ( EcuIdx ),
							      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
						}
					}
					break;

					case INF_TYPE_ECUNAME_COUNT:
					{
						// non-ISO15765 should report 0x05 messages
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     pInf->NODI != 0x05 )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $9 (IPT Count) is invalid   Message Count = %d (should be 0x05)\n",
							      GetEcuId ( EcuIdx ),
							      pInf->NODI );
						}

						Inf9NumItems[EcuIdx] = pInf->NODI;
					}
					break;

					case INF_TYPE_ECUNAME:
					{
						bInfAResponded[EcuIdx] = TRUE;

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

						// Response should match INF9 if not ISO15765
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != Inf9NumItems[EcuIdx] )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $A (ECU Name) Message Count = %d (should match INF9)\n",
							      GetEcuId ( EcuIdx ),
							      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
						}

						// 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 $A, Duplicate ECU names\n",
								      GetEcuId ( EcuIdx ),
								      GetEcuId ( EcuLoopIdx ) );
							}
						}
					}
					break;

					case INF_TYPE_IPT_DIESEL:
					{
						InfBNumResponses++;

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

						// Response should match INF7 if not ISO15765
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != Inf7NumItems[EcuIdx] )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $B (IPT) Message Count = %d (should match INF7)\n",
							      GetEcuId ( EcuIdx ),
							      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
						}
					}
					break;

					case INF_TYPE_ESN_COUNT:   // INFOTYPE $0C Engine Serial Number Message Count
					{
						// non-ISO15765 should report 0x05 messages
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     pInf->NODI != 0x05 )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $C (ESN Count) is invalid   Message Count = %d (should be 0x05)\n",
							      GetEcuId ( EcuIdx ),
							      pInf->NODI );
						}
						InfCNumItems[EcuIdx] = pInf->NODI;
					}
					break;

					case INF_TYPE_ESN:   // INFOTYPE $0D Engine Serial Number
					{
						if ( VerifyInfD_FData ( EcuIdx ) != PASS )
						{
							bTestFailed = TRUE;
						}
					}
					break;

					case INF_TYPE_EROTAN_COUNT:   // INFOTYPE $0E Exhaust Regulation or Type Approval Number Message Count
					{
						// non-ISO15765 should report 0x05 messages
						if ( gstProtocolList[gProtocolIdx].eProtocol != ISO15765 &&
						     pInf->NODI != 0x05 )
						{
							bTestFailed = TRUE;
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  INF $E (EROTAN Count) is invalid   Message Count = %d (should be 0x05)\n",
							      GetEcuId ( EcuIdx ),
							      pInf->NODI );
						}
						InfENumItems[EcuIdx] = pInf->NODI;
					}
					break;

					case INF_TYPE_EROTAN:   // INFOTYPE $0F Exhaust Regulation or Type Approval
					{
						if ( VerifyInfD_FData ( 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_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;

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


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

				// Verify that INF $A is supported for MY 2010 and later
				if ( IdIdx == 0x0A &&
				     gModelYear >= 2010 &&
				     bInfAResponded[EcuIdx] == FALSE &&
				     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD || gstUserInput.eComplianceType == CNOBD_NO_IUMPR) )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Did not report INF $0A (ECUNAME) (Required for MY 2010 and later vehicles)\n",
					      GetEcuId ( EcuIdx ) );
					bTestFailed = TRUE;
				}

				// If INFs higher than the max are supported, this is a failure
				if ( IdIdx > 0x78 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Supports INF $%02X (Must not support INF higher than $78)\n",
					      GetEcuId ( EcuIdx ),
					      IdIdx );
					bTestFailed = TRUE;
				}
			} // end for ( EcuIdx )

		} // end if ( IsIDSupported (ALLECUS, IdIdx) == TRUE )

	} // 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 $02 (VIN) must be reported by one ECU\n" );
			bTestFailed = TRUE;
		}
		else
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $02 (VIN) not reported by any ECUs\n" );
		}
	}

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

	if ( gbDiesel == FALSE && Inf8NumResponses == 0 )
	{
		if ( gModelYear >= 2005 &&
		     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
		{
			// If M/Y 2005 or greater and OBD II, INFO type 8 must be supported
			// If not supported then OEM will present Infotype phase in plan
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "No INF $08 (IPT) response (Required for Spark Ignition vehicles MY 2005 and later)\n" );
			bTestFailed = TRUE;
		}
		else if ( gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD ||
		          gstUserInput.eComplianceType == IOBD_NO_IUMPR   || gstUserInput.eComplianceType == HD_IOBD_NO_IUMPR ||
		          gstUserInput.eComplianceType == OBDBr_NO_IUMPR  || gstUserInput.eComplianceType == CNOBD_NO_IUMPR )
		{
			// If EOBD with IUMPR, INFO type 8 must be supported
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "No INF $08 (IPT) response (Required for Spark Ignition vehicles)\n" );
			bTestFailed = TRUE;
		}
	}

	if ( gbDiesel == TRUE && InfBNumResponses == 0 )
	{
		if ( gModelYear >= 2010 &&
		     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
		{
			// If M/Y 2010 or greater, INFO type B must be supported
			// If not supported then OEM will present Infotype phase in plan
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "No INF $0B (IPT) response (Required for Compression Ignition vehicles MY 2010 and later)\n" );
			bTestFailed = TRUE;
		}
		else if ( gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD ||
		          gstUserInput.eComplianceType == IOBD_NO_IUMPR   || gstUserInput.eComplianceType == HD_IOBD_NO_IUMPR ||
		          gstUserInput.eComplianceType == OBDBr_NO_IUMPR  || gstUserInput.eComplianceType == CNOBD_NO_IUMPR )
		{
			// If EOBD with IUMPR, INFO type 8 must be supported
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "No INF $0B (IPT) response (Required for Compression Ignition vehicles)\n" );
			bTestFailed = TRUE;
		}
	}


	// Try group support if ISO15765
	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		if ( RequestGroupIDSupportData ( 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 )
{
	STATUS  eRetCode = PASS;

	BYTE    VinIndex;


	// Print VIN string to log file
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $02  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) ||
	      (gVINString[9] == '2' && gVINModelYear != 2002) ||
	      (gVINString[9] == '3' && gVINModelYear != 2003) ||
	      (gVINString[9] == '4' && gVINModelYear != 2004) ||
	      (gVINString[9] == '5' && gVINModelYear != 2005) ||
	      (gVINString[9] == '6' && gVINModelYear != 2006) ||
	      (gVINString[9] == '7' && gVINModelYear != 2007) ||
	      (gVINString[9] == '8' && gVINModelYear != 2008) ||
	      (gVINString[9] == '9' && gVINModelYear != 2009) ||
	      (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) ||
	      (gVINString[9] == 'V' && gVINModelYear != 1997) ||
	      (gVINString[9] == 'W' && gVINModelYear != 1998) ||
	      (gVINString[9] == 'X' && gVINModelYear != 1999) ||
	      (gVINString[9] == 'Y' && gVINModelYear != 2000)) &&
	     (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 > 2025) &&
	          (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
	{
		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;
	}

	gstEcuSIDData[EcuIdx].bVinValid = TRUE;
	strncpy_s ( gstEcuSIDData[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,
                         unsigned long Inf3NumItems )
{
	INF           *pInf;
	STATUS         eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $04 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		CalidCnt = pInf->NODI;

		// INF4 NODI must equal number of CALIDs
		// Don't include SID or INF ID in INFSIZE
		if ( (pInf->NODI) * 16 != (gstResponse[EcuIdx].InfSize - 2) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $04 (CALID) NODI = %d mis-matched with Data Size\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			return FAIL;
		}

		CalidStringSize = CalidCnt * CALID_BUFFER_SIZE;
		// allocate memory for copying end-of-test stats
		if ( gstEcuSIDData[EcuIdx].pCalidString != NULL && gstEcuSIDData[EcuIdx].CalidCount != CalidCnt )
		{
			if ( (gstEcuSIDData[EcuIdx].pCalidString = realloc ( gstEcuSIDData[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 ( (gstEcuSIDData[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 ( gstEcuSIDData[EcuIdx].pCalidString,
		         0x00,
		         CalidStringSize );
		gstEcuSIDData[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 $04  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 $04  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 ( &gstEcuSIDData[EcuIdx].pCalidString[ItemIndex * CALID_BUFFER_SIZE],
			           CALID_BUFFER_SIZE,
			           Buffer );
		}  // end for (ItemIndex...

		// if ISO15765, response size should be 1 for MY 2009
		if ( gModelYear >= 2009 &&
		     pInf[0].NODI != 1 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $04 (CALID) NODI = %d (should be 1 for MY 2009 and later, unless EO approved)\n",
			      GetEcuId ( EcuIdx ),
			      pInf[0].NODI );
		}
	}  // end if ( ISO15765 )
	else  // not ISO15765
	{
		// size of each CALIDs messsage checked in SaveSidResponseData.c

		CalidCnt = gstResponse[EcuIdx].InfSize / sizeof ( INF );

		CalidStringSize = CalidCnt * CALID_BUFFER_SIZE;
		// allocate memory for copying end-of-test stats
		if ( gstEcuSIDData[EcuIdx].pCalidString != NULL &&
		     gstEcuSIDData[EcuIdx].CalidCount != CalidCnt )
		{
			if ( (gstEcuSIDData[EcuIdx].pCalidString = realloc ( gstEcuSIDData[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 ( (gstEcuSIDData[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 ( gstEcuSIDData[EcuIdx].pCalidString,
		         0x00,
		         CalidStringSize );
		gstEcuSIDData[EcuIdx].CalidCount = CalidCnt;


		for ( Index = 0;
		      Index < CalidCnt;
		      Index += 4 )
		{
			bCalidEnd = FALSE;
			for ( ItemIndex = 0, ByteIdx = 0;
			      ItemIndex < 4;
			      ItemIndex++, pInf++ )
			{
				Buffer[ByteIdx++] = pInf->Data[0];
				Buffer[ByteIdx++] = pInf->Data[1];
				Buffer[ByteIdx++] = pInf->Data[2];
				Buffer[ByteIdx++] = pInf->Data[3];
			}

			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...

			Buffer[ByteIdx] = 0;
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  CALID: %s\n",
			      GetEcuId ( EcuIdx ),
			      Buffer );

			//  add the current CALID to this ECU's CALID list
			strcpy_s ( &gstEcuSIDData[EcuIdx].pCalidString[Index * CALID_BUFFER_SIZE], CALID_BUFFER_SIZE, Buffer );
		}

		// reload INF pointer for next check, it should be pointing at the last item
		pInf--;

		// Response should match INF $3
		// pInf[Inf3NumItems[EcuIdx]-1].NumItems is actually
		// the message count (1-XX) of the last 4-byte block in the message
		// (ie if Inf3NumItems[EcuIdx] == 4 (1 16 byte CALID is made up of 4 4-byte messages)
		// the last block of the message should have a message count of 4
		if ( pInf->NODI != Inf3NumItems )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $4 (CALID) NODI = %d (should match INF $3 CALID Count %d)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI,
			      Inf3NumItems );
		}

		// Response size should be 1 (16-byte CALID made up of 4 4-byte messages) for MY 2009
		if ( gModelYear >= 2009 &&
		     pInf->NODI != 4 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $4 (CALID) NODI = %d (should be 4 (for 1 16-byte CALID) for MY 2009 and later, unless EO approved)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
		}
	}

	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,
                       unsigned long Inf5NumItems )
{
	INF           *pInf;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $06 (CVN) data\n",
		      GetEcuId ( EcuIdx ) );
		return PASS;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		CvnCnt = pInf->NODI;

		// INF 6 NODI must equal number of CVNs
		// Don't include SID or INF ID in INFSIZE
		if ( (pInf->NODI) * 4 != (gstResponse[EcuIdx].InfSize - 2) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $06 (CVN) NODI = %d mis-matched with Data Size\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			return FAIL;
		}


		// allocate memory for copying end-of-test stats
		CvnStringSize = CvnCnt * CVN_BUFFER_SIZE;
		if ( gstEcuSIDData[EcuIdx].pCvnString != NULL &&
		     gstEcuSIDData[EcuIdx].CvnCount != CvnCnt )
		{
			if ( (gstEcuSIDData[EcuIdx].pCvnString = realloc ( gstEcuSIDData[EcuIdx].pCvnString, CvnStringSize )) == NULL )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Unable to allocate memory for ECU %X CVN storage\n",
				      GetEcuId ( EcuIdx ) );
				return FAIL;
			}
		}
		else
		{
			if ( (gstEcuSIDData[EcuIdx].pCvnString = (char *) malloc ( CvnStringSize )) == NULL )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "Unable to allocate memory for ECU %X CVN storage\n",
				      GetEcuId ( EcuIdx ) );
				return FAIL;
			}
		}
		memset ( gstEcuSIDData[EcuIdx].pCvnString,
		         0x00,
		         CvnStringSize );
		gstEcuSIDData[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 $06  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 $06  CVN%02d = %s\n",
				      GetEcuId ( EcuIdx ),
				      ItemIndex+1,
				      Buffer );
			}

			strcpy_s ( &gstEcuSIDData[EcuIdx].pCvnString[ItemIndex*CVN_BUFFER_SIZE], CVN_BUFFER_SIZE, Buffer );
		}

		// If ISO15765, response size should be 1 for MY 2009
		if ( gModelYear >= 2009 &&
		     pInf[0].NODI != 1 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $06 (CVN) NODI = %d (should be 1 for MY 2009 and later, unless EO approved)\n",
			      GetEcuId ( EcuIdx ),
			      pInf[0].NODI );
		}
	}
	else
	{
		// size of each CVN checked in SaveSidResponseData.c

		CvnCnt = gstResponse[EcuIdx].InfSize / sizeof ( INF );

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


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

				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  CVN: %s\n",
				      GetEcuId ( EcuIdx ),
				      Buffer );
				strcpy_s ( &gstEcuSIDData[EcuIdx].pCvnString[ItemIndex*CVN_BUFFER_SIZE], CVN_BUFFER_SIZE, Buffer );
			}
		}

		// reload INF pointer for next check
		pInf--;

		if ( pInf->NODI != Inf5NumItems )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $06 NODI = %d (should match INF $5 CVN Count %d)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI,
			      Inf5NumItems );
		}

		// Response size should be 1 for MY 2009
		if ( gModelYear >= 2009 &&
		     pInf->NODI != 1 )
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $6 (CVN) NODI = %d (should be 1 for MY 2009 and later, unless EO approved)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
		}
	}

	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  41
#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",
  "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",
  "EACC EAC1 EAC2 EAC3 EAC4 EAC5 EAC6 EAC7 EAC8",
  "EACM EAM1 EAM2 EAM3 EAM4 EAM5 EAM6 EAM7 EAM8",
  "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",
  "HVAC HVA1 HVA2 HVA3 HVA4 HVA5 HVA6 HVA7 HVA8",
  "HPCM HPC1 HPC2 HPC3 HPC4 HPC5 HPC6 HPC7 HPC8",
  "IPC IPC1 IPC2 IPC3 IPC4 IPC5 IPC6 IPC7 IPC8",
  "OBCC OBC1 OBC2 OBC3 OBC4 OBC5 OBC6 OBC7 OBC8",
  "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",
  "TCM TCM1 TCM2 TCM3 TCM4 TCM5 TCM6 TCM7 TCM8",
  "VTMC VTM1 VTM2 VTM3 VTM4 VTM5 VTM6 VTM7 VTM8" };

const char szECUTextName[TABLE_SIZE][TEXTNAME_STRING_SIZE] =
{ "AntiLockBrake",
  "AltFuelCtrl",
  "AuxHeatCtrl",
  "AirPumpCtrl",
  "AllWhlDrvCtrl",
  "B+ChargerCtrl",
  "B+EnergyCtrl",
  "B+ManageCtrl",
  "BodyControl",
  "BrakeSystem",
  "CatHeaterCtrl",
  "CamPosCtrl",
  "ChassisCtrl",
  "CruiseControl",
  "CoolTempCtrl",
  "DCDCConvCtrl",
  "DriveMotorCtrl",
  "ElecACCompCtrl",
  "ExhaustAftCtrl",
  "ElecBrkBstCtrl",
  "EmisCritInfo",
  "EngineControl",
  "FuelAddCtrl",
  "FuelCellCtrl",
  "FuelInjCtrl",
  "FuelPumpCtrl",
  "4WhlDrvClCtrl",
  "Gateway",
  "GlowPlugCtrl",
  "GearShiftCtrl",
  "HVACCtrl",
  "HybridPtCtrl",
  "InstPanelClust",
  "OBChargerCtrl",
  "PowertrainCtrl",
  "ReductantCtrl",
  "Start/GenCtrl",
  "ThrotActCtrl",
  "TransfCaseCtrl",
  "TransmisCtrl",
  "ThermalMgmt" };

STATUS VerifyECUNameData ( BYTE EcuIdx )
{
	INF            *pInf;

	unsigned int    ByteIdx;
	unsigned int    MsgIndex;        // multi-part message index
	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $A data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];


	// copy to a protocol independent buffer
	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// ECU Name Data must contain 20 bytes of data
		// Don't include SID or INF ID in INFSIZE
		if ( gstResponse[EcuIdx].InfSize - 0x02 != 20 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0A (ECU NAME) Data Size Error = %d (Must be 20 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}

		// INF A NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			bTestFailed = TRUE;
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0A (ECU NAME) NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
		}

		memcpy ( Buffer,
		         &(pInf->Data[0]),
		         20 );
	}
	else
	{
		// For non-CAN, calculate the number of responses.  Expected is
		// 5 (20 bytes) records.  Each response from controller held in
		// data structure INF.
		if ( gstResponse[EcuIdx].InfSize / sizeof ( INF ) != 0x05 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0A (ECU Name)  Data Size Error (Must be 20 bytes!)\n",
			      GetEcuId ( EcuIdx ) );
			return FAIL;
		}

		// INF A message count must equal $05
		if ( gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != 0x05 ) // check to message number byte
		{
			bTestFailed = TRUE;
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0A  Message Count = %d (Must be 5 ($05))\n",
			      GetEcuId ( EcuIdx ),
			      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
		}

		// save ECU Name data to Buffer
		for ( MsgIndex = 0;
		      MsgIndex < (gstResponse[EcuIdx].InfSize / sizeof ( INF ));
		      MsgIndex++ )
		{
			memcpy ( &(Buffer[MsgIndex * 4]),
			         &(pInf[MsgIndex].Data[0]),
			         4 );
		}
	}


	// insert NULL terminator at end of string
	Buffer[20] = 0;
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $0A  ECU acronym and name = %s\n",
	      GetEcuId ( EcuIdx ),
	      Buffer );

	// 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' ) )
		{
			if ( gModelYear >= 2010 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Invalid ECU acronym/number character (byte %d)\n",
				      GetEcuId ( EcuIdx ),
				     ByteIdx );
				bTestFailed = TRUE;
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Invalid ECU acronym/number character (byte %d)\n",
				      GetEcuId ( EcuIdx ),
				      ByteIdx );
			}
		}
	}

	// 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 )
	{
		if ( gModelYear >= 2010 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Not an approved ECU acronym/number\n",
			      GetEcuId ( EcuIdx ) );
			bTestFailed = TRUE;
		}
		else
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Not an approved ECU acronym/number\n",
			      GetEcuId ( EcuIdx ) );
		}
	}

	// 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 )
		{
			if ( gModelYear >= 2010 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  ECU acronym/number not zero padded on right\n",
				      GetEcuId ( EcuIdx ) );
				bTestFailed = TRUE;
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  ECU acronym/number not zero padded on right\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Buffer[ByteIdx] = ' ';    // replace zero with space for printing to log file
		}
	}


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

	// 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] != '/' )
		{
			if ( gModelYear >= 2010 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Invalid ECU text name character (byte %d)\n",
				      GetEcuId ( EcuIdx ),
				      ByteIdx );
				bTestFailed = TRUE;
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Invalid ECU text name character (byte %d)\n",
				      GetEcuId ( EcuIdx ),
				      ByteIdx );
			}
		}
	}

	// 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 )
	{
		if ( gModelYear >= 2010 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Not an approved ECU text name\n",
			      GetEcuId ( EcuIdx ) );
			bTestFailed = TRUE;
		}
		else
		{
			Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  Not an approved ECU text name\n",
			      GetEcuId ( EcuIdx ) );
		}
	}

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

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


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


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

	if ( gbDiesel == TRUE && gModelYear >= 2010 &&
	     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
	{
		// Compression Ignition vehicles MY 2010 and later should not support INF8
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $08 response! (Not allowed for MY 2010 and later compression ignition vehicles)\n",
		      GetEcuId ( EcuIdx ) );
		return 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 $8 response! (Conflicts with Compliance Type selected)\n",
		      GetEcuId ( EcuIdx ) );
	}

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// In-Use Performance Data must contain 32, 40, or 56 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 32 &&
		     gstResponse[EcuIdx].InfSize - 2 != 40 &&
		     gstResponse[EcuIdx].InfSize - 2 != 56 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $08 (IPT) Data Size = %d (Must be 32, 40 or 56 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );

			// INF 8 NODI must equal $10 (16), $14 (20), or $1C (28)
			if ( gstResponse[EcuIdx].Inf[1] != 0x10 &&
			     gstResponse[EcuIdx].Inf[1] != 0x14 &&
			     gstResponse[EcuIdx].Inf[1] != 0x1C )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $08 (IPT) NODI = %d (Must be 16 ($1C), 20 ($14), or 28 ($1C))\n",
				      GetEcuId ( EcuIdx ),
				      gstResponse[EcuIdx].Inf[1] );
			}
			eRetCode = ERRORS;

		}
		else
		{
			// IF spark ignition (GAS) vehicle
			if ( gbDiesel == FALSE )
			{
				// If MY 2020 and later CNOBD spark ignition vehicle
				if ( gModelYear >= 2020 &&
				     gstUserInput.eComplianceType == CNOBD_NO_IUMPR )
				{
					// In-Use Performance Data must contain 56 bytes of data
					if ( gstResponse[EcuIdx].InfSize - 2 != 56 )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 (IPT) Data Size = %d (Must be 56 bytes!)\n",
						      GetEcuId ( EcuIdx ),
						      (gstResponse[EcuIdx].InfSize - 2) );
					}

					// INF 8 NODI must equal 28 ($1C)
					if ( gstResponse[EcuIdx].Inf[1] != 0x1C )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 NODI = %d (Must be 28 ($1C))\n",
						      GetEcuId ( EcuIdx ),
						      gstResponse[EcuIdx].Inf[1] );
					}
				}

				// If MY 2019 and later US_OBDII spark ignition vehicle
				else if ( gModelYear >= 2019 && gstUserInput.eComplianceType == US_OBDII )
				{
					// In-Use Performance Data must contain 56 bytes of data
					if ( gstResponse[EcuIdx].InfSize - 2 != 56 )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 (IPT) Data Size = %d (Must be 56 bytes!)\n",
						      GetEcuId ( EcuIdx ),
						      (gstResponse[EcuIdx].InfSize - 2) );
					}

					// INF8 NODI must equal 28 ($1C)
					if ( gstResponse[EcuIdx].Inf[1] != 0x1C )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 NODI = %d (Must be 28 ($1C))\n",
						      GetEcuId ( EcuIdx ),
						      gstResponse[EcuIdx].Inf[1] );
					}
				}

				// If MY 2010 and later US_OBDII spark ignition vehicle
				else if ( gModelYear >= 2010 &&
				          gstUserInput.eComplianceType == US_OBDII )
				{
					// In-Use Performance Data must contain 40 bytes of data
					if ( gstResponse[EcuIdx].InfSize - 2 != 40 &&
					     gstResponse[EcuIdx].InfSize - 2 != 56 )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 (IPT) Data Size = %d (Must be 40 or 56 bytes!)\n",
						      GetEcuId ( EcuIdx ),
						      (gstResponse[EcuIdx].InfSize - 2) );
						eRetCode = ERRORS;
					}

					// INF8 NODI must equal $14
					if ( gstResponse[EcuIdx].Inf[1] != 0x14 &&
					     gstResponse[EcuIdx].Inf[1] != 0x1C )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 (IPT) NODI = %d (Must be 20 ($14) or 28 ($1C))\n",
						      GetEcuId ( EcuIdx ),
						      gstResponse[EcuIdx].Inf[1] );
						eRetCode = ERRORS;
					}
				}
				else
				{
					// INF8 NODI must equal $10 (16), $14 (20), or $1C (28)
					if ( gstResponse[EcuIdx].Inf[1] != 0x10 &&
					     gstResponse[EcuIdx].Inf[1] != 0x14 &&
					     gstResponse[EcuIdx].Inf[1] != 0x1C )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $08 NODI = %d (Must be 16 ($1C), 20 ($14), or 28 ($1C))\n",
						      GetEcuId ( EcuIdx ),
						      gstResponse[EcuIdx].Inf[1] );
						eRetCode = ERRORS;
					}
				}
			}
			// IF compression ignition (DIESEL) vehicle
			else
			{
				// In-Use Performance Data must contain 32 or 40 bytes of data
				if ( gstResponse[EcuIdx].InfSize - 2 != 32 &&
				     gstResponse[EcuIdx].InfSize - 2 != 40 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $08 (IPT) Data Size = %d (Must be 32 or 40 bytes!)\n",
					      GetEcuId ( EcuIdx ),
					      (gstResponse[EcuIdx].InfSize - 2) );
					eRetCode = ERRORS;
				}

				// INF8 NODI must equal $10 or $14
				if ( gstResponse[EcuIdx].Inf[1] != 0x10 &&
				     gstResponse[EcuIdx].Inf[1] != 0x14 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $08 NODI = %d (Must be 16 ($10) or 20 ($14))\n",
					      GetEcuId ( EcuIdx ),
					      gstResponse[EcuIdx].Inf[1] );
					eRetCode = ERRORS;
				}
			}
		}
	}
	else
	{
		// For non-CAN, calculate the number of responses.  Expected is
		// 8 (32 bytes) or 10 (40 bytes) records.  Each response from controller held in
		// data structure INF.
		if ( gstResponse[EcuIdx].InfSize / sizeof ( INF ) != 0x08 &&
		     gstResponse[EcuIdx].InfSize / sizeof ( INF ) != 0x0A )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $08 (IPT) Data Size Error (Must be 32 or 40 bytes!)\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = ERRORS;
		}

		// INF8 message count must equal $08 or $10
		if ( gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != 0x08 && // check to message number byte
		     gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != 0x0A )  // check to message number byte
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $08 Message Count = %d (Must be 8 ($08) or 10 ($0A))\n",
			      GetEcuId ( EcuIdx ),
			      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
			eRetCode = ERRORS;
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyInfBData
**
**  Purpose:   Verify the INF B data.
**             In the event the format fails defined criteria,
**             an error is returned.
**
*******************************************************************************/
STATUS VerifyInfBData ( BYTE EcuIdx )
{
	if ( gbDiesel == FALSE && gModelYear >= 2010 &&
	     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
	{
		// Spark Ignition vehicles MY 2010 and later should not support INFB
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $0B response! (Not allowed for MY 2010 and later spark ignition vehicles)\n",
		      GetEcuId ( EcuIdx ) );
		return 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 $0B response! (Conflicts with Compliance Type selected)\n",
		      GetEcuId ( EcuIdx ) );
	}

	// 32 or 36 bytes of data returned
	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// In-Use Performance Data must contain 32 or 36 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 32 &&
		     gstResponse[EcuIdx].InfSize - 2 != 36 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0B (IPT) Data Size Error = %d (Must be 32 or 36 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		if ( gstResponse[EcuIdx].InfSize - 2 == 32 &&
		     gstResponse[EcuIdx].Inf[1] != 0x10 )
		{
			// INFB NODI must equal 16 if the data size is 32
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0B NODI = %d (Must be 16)\n",
			      GetEcuId ( EcuIdx ),
			      gstResponse[EcuIdx].Inf[1] );
			return FAIL;
		}

		if ( gstResponse[EcuIdx].InfSize - 2 == 36 &&
		     gstResponse[EcuIdx].Inf[1] != 0x12 )
		{
			// INFB NODI must equal 18 if the data size is 36
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0B NODI = %d (Must be 18)\n",
			      GetEcuId ( EcuIdx ),
			      gstResponse[EcuIdx].Inf[1] );
			return FAIL;
		}
	}
	else
	{
		// For non-CAN, calculate the number of responses.  Expected is
		// 8 (32 bytes) or 9 (36 bytes) records.  Each response from controller held in
		// data structure INF.
		if ( gstResponse[EcuIdx].InfSize / sizeof ( INF ) != 0x08 &&
		     gstResponse[EcuIdx].InfSize / sizeof ( INF ) != 0x09 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0B (IPT) Data Size Error (Must be 32 or 36 bytes!)\n",
			      GetEcuId ( EcuIdx ) );
			return FAIL;
		}
		// INFB message count must equal $08 or $09
		if ( gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != 0x08 && // check to message number byte
		     gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != 0x09 )  // check to message number byte
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $0B Message Count = %d (Must be 8 ($08) or 9 ($09))\n",
			      GetEcuId ( EcuIdx ),
			      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
			return FAIL;
		}
	}

	return PASS;
}


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

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	// copy to a protocol independent Buffer
	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// ESN Data must contain 17 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 17 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size Error = %d (Must be 17 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF C NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}

		memcpy ( Buffer,
		         &(pInf->Data[0]),
		         20 );
	}
	else
	{
		// For non-CAN, calculate the number of responses.  Expected is
		// 5 (20 bytes) records.  Each response from controller held in
		// data structure INF.
		if ( gstResponse[EcuIdx].InfSize / sizeof ( INF ) != 0x05 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size Error (Must be 20 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID );
			return FAIL;
		}

		// INFC message count must equal $05
		if ( gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] != 0x05 ) // check to message number byte
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Message Count = %d (Must be 5)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      gstResponse[EcuIdx].Inf[gstResponse[EcuIdx].InfSize - 5] );
			eRetCode = FAIL;
		}

		// save ESN data to Buffer
		for ( MsgIndex = 0;
		      MsgIndex < (gstResponse[EcuIdx].InfSize / sizeof ( INF ));
		      MsgIndex++ )
		{
			if ( MsgIndex == 0 )
			{
				// get rid of the three leading NULLs in the first message
				Buffer[0] = pInf[0].Data[3];
			}
			else
			{
				// extract the data from the remaining messages
				memcpy ( &(Buffer[1 + ((MsgIndex - 1) * 4)]),
				         &(pInf[MsgIndex].Data[0]),
				         4 );
			}
		}
	}

	// strip of the pad bytes
	for ( ByteIdx = 0;
	      ByteIdx < 17;
	      ByteIdx++ )
	{
		if ( Buffer[ByteIdx] != 0x00 )
		{
			StartOffset = ByteIdx;
			break;  // leave ESN byte index for loop
		}
	}

	if ( ByteIdx == 17 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X contains all pad bytes\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID );
		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 $%02X data\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID );
			eRetCode = FAIL;
		}
	}

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

	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;
	STATUS eRetCode = PASS;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $10 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	// copy to a protocol independent buffer

	// Protocol Identification Data must contain 1 byte of data
	// Don't include SID or INF ID in INFSIZE
	if ( gstResponse[EcuIdx].InfSize - 2 != 1 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $10 Data Size = %d (Must be 1 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      (gstResponse[EcuIdx].InfSize - 2) );
		return FAIL;
	}

	// INF 10 NODI must equal $01
	if ( pInf->NODI != 1 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $10 NODI = %d (Must be 1)\n",
		      GetEcuId ( EcuIdx ),
		      pInf->NODI );
		eRetCode = FAIL;
	}

	// log PROTID
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $10  PROTID    = $%02X\n",
	      GetEcuId ( EcuIdx ),
	      gstResponse[EcuIdx].Inf[0] );

	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;
	STATUS eRetCode = PASS;

	unsigned char Index;
	unsigned char GTR[12];


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $11 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	// copy to a protocol independent buffer

	// Protocol Identification Data must contain 1 byte of data
	// Don't include SID or INF ID in INFSIZE
	if ( gstResponse[EcuIdx].InfSize - 2 != 11 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $11 Data Size = %d (Must be 11 byte!)\n",
		      GetEcuId ( EcuIdx ),
		      (gstResponse[EcuIdx].InfSize - 2) );
		return FAIL;
	}

	// INF $11 NODI must equal $01
	if ( pInf->NODI != 0x01 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $11 NODI = %d (Must be 1)\n",
		      GetEcuId ( EcuIdx ),
		      pInf->NODI );
		eRetCode = FAIL;
	}

	for ( Index = 0;
	      Index < 10;
	      Index++ )
	{
		GTR[Index] = pInf->Data[Index];
	}
	GTR[Index] = (unsigned char)NULL;

	// log PROTID
	Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "ECU %X  INF $11  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;
	STATUS eRetCode = PASS;

	unsigned long FEOCNTR;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $12 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	// copy to a protocol independent buffer
	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// FEOCNTR Data must contain 2 bytes of data
		// Don't include SID or INF ID in INFSIZE
		if ( gstResponse[EcuIdx].InfSize - 2 != 2 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $12 Data Size = %d (Must be 2 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF12 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $12 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		FEOCNTR = (gstResponse[EcuIdx].Inf[2] << 8) +
		           gstResponse[EcuIdx].Inf[3];

		// If NOT test 9.19, 10.12 or 11.2, log
		if ( (geTestPhase != eTestNoFault3DriveCycle  || gTestSubsection != 19) &&
		     (geTestPhase != eTestInUseCounters       || gTestSubsection != 12) &&
		     (geTestPhase != eTestPerformanceCounters || gTestSubsection != 2) )
		{
			// log FEOCNTR
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $12  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;
	STATUS        eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $13 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// TG/EFN Data must contain 12 bytes or less of data
		// Don't include SID or INF ID in INFSIZE
		if ( (gstResponse[EcuIdx].InfSize - 2) > 12 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $13 Data Size Error = %d (Must be 1-12 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 13 NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $13 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = 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 $13 byte %d  Invalid Character = $%2X (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 $13  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) ||
		     (TG_EFN[0] == '2' && gModelYear != 2002) ||
		     (TG_EFN[0] == '3' && gModelYear != 2003) ||
		     (TG_EFN[0] == '4' && gModelYear != 2004) ||
		     (TG_EFN[0] == '5' && gModelYear != 2005) ||
		     (TG_EFN[0] == '6' && gModelYear != 2006) ||
		     (TG_EFN[0] == '7' && gModelYear != 2007) ||
		     (TG_EFN[0] == '8' && gModelYear != 2008) ||
		     (TG_EFN[0] == '9' && gModelYear != 2009) ||
		     (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) ||
		     (TG_EFN[0] == 'V' && gModelYear != 1997) ||
		     (TG_EFN[0] == 'W' && gModelYear != 1998) ||
		     (TG_EFN[0] == 'X' && gModelYear != 1999) ||
		     (TG_EFN[0] == 'Y' && gModelYear != 2000) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $13 (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 ( TG_EFN[0] != gVINString[9] &&
		     gstUserInput.eVehicleType == LD )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $13 (TG/EFN) year character (%c) does not match INF $02 (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;
	STATUS eRetCode = PASS;

	unsigned long EVAP_DIST;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $14 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	// copy to a protocol independent buffer
	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// EVAP_DIST Data must contain 2 bytes of data
		// Don't include SID or INF ID in INFSIZE
		if ( gstResponse[EcuIdx].InfSize - 2 != 2 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $14 Data Size Error = %d (Must be 2 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 14 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $14 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		EVAP_DIST = (gstResponse[EcuIdx].Inf[2] << 8) +
		             gstResponse[EcuIdx].Inf[3];

		// log EVAP_DIST
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $14  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 $14 should not return a value of $FFFF after evap monitor runs\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
		// if tests 5.17
		else if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 && EVAP_DIST != 0xFFFF  && EVAP_DIST != 0x0000 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $14 should return a value of $FFFF or $0000 after a Service $04 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;
	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $16 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// ERT/IERT Data must contain 32 bytes of data
		// Don't include SID or INF ID in INFSIZE
		if ( gstResponse[EcuIdx].InfSize - 2 != 32 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16 Data Size = %d (Must be 32 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 16 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log IGNCNTR_R
		IGNCNTR_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		            (gstResponse[EcuIdx].Inf[3] << 16) +
		            (gstResponse[EcuIdx].Inf[4] << 8) +
		             gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  IGNCNTR_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      IGNCNTR_R );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF16_IGNCNTR_R = IGNCNTR_R;

			if ( IGNCNTR_R > 1 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $16 IGNCNTR_R must return a value of 0 or 1 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          IGNCNTR_R <= Test_5_17_Inf[EcuIdx].INF16_IGNCNTR_R )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16 IGNCNTR_R must return a value greater than the value returned in Test 5.17 (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_17_Inf[EcuIdx].INF16_IGNCNTR_R );
			eRetCode = FAIL;
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		          IGNCNTR_R != 0 && IGNCNTR_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16 IGNCNTR_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log IGNCNTR_L
		IGNCNTR_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		            (gstResponse[EcuIdx].Inf[7] << 16) +
		            (gstResponse[EcuIdx].Inf[8] << 8) +
		             gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  IGNCNTR_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      IGNCNTR_L );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_Inf[EcuIdx].INF16_IGNCNTR_L = IGNCNTR_L;

				if ( IGNCNTR_L < 1 || IGNCNTR_L <= IGNCNTR_R )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 IGNCNTR_L must return a value of 1 or greater and greater than IGNCNTR_R after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
			          IGNCNTR_L <= Test_5_17_Inf[EcuIdx].INF16_IGNCNTR_L )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $16 IGNCNTR_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF16_IGNCNTR_L );
				eRetCode = FAIL;
			}
		}

		// log FEOCNTR_R
		FEOCNTR_R = (gstResponse[EcuIdx].Inf[10] << 24) +
		            (gstResponse[EcuIdx].Inf[11] << 16) +
		            (gstResponse[EcuIdx].Inf[12] << 8) +
		             gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  FEOCNTR_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      FEOCNTR_R );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_R = FEOCNTR_R;

				if ( FEOCNTR_R > 1 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 FEOCNTR_R must return a value of 0 or 1 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 )  // IF Test 9.22
			{
				if ( FEOCNTR_R <= Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_R &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 FEOCNTR_R must return a value greater than the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_R );
					eRetCode = FAIL;
				}
				else if ( FEOCNTR_R < Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_R  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 FEOCNTR_R must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_R );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			          FEOCNTR_R != 0 &&  FEOCNTR_R != 4294967295 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $16 FEOCNTR_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log FEOCNTR_L
		FEOCNTR_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		            (gstResponse[EcuIdx].Inf[15] << 16) +
		            (gstResponse[EcuIdx].Inf[16] << 8) +
		             gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  FEOCNTR_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      FEOCNTR_L );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_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 $16 FEOCNTR_L must return a value of 1 or greater and greater than FEOCNTR_R after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22)  // IF Test 9.22
			{
				if ( FEOCNTR_L <= Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_L &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 FEOCNTR_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_L );
					eRetCode = FAIL;
				}
				else if ( FEOCNTR_L < Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_L &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 FEOCNTR_R must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_FEOCNTR_L );
					eRetCode = FAIL;
				}
			}
		}

		// log ERT_R
		ERT_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		        (gstResponse[EcuIdx].Inf[19] << 16) +
		        (gstResponse[EcuIdx].Inf[20] << 8) +
		         gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  ERT_R     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERT_R );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_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 $16 ERT_R must return a value of greater than 1 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 )  // IF Test 9.22
			{
				if ( ERT_R <= Test_5_17_Inf[EcuIdx].INF16_ERT_R &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 ERT_R must return a value greater than the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_ERT_R );
					eRetCode = FAIL;
				}
				else if ( ERT_R < Test_5_17_Inf[EcuIdx].INF16_ERT_R  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 ERT_R must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_ERT_R );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			          ERT_R != 0 && ERT_R != 4294967295 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $16 ERT_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log ERT_L
		ERT_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		        (gstResponse[EcuIdx].Inf[23] << 16) +
		        (gstResponse[EcuIdx].Inf[24] << 8) +
		         gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  ERT_L     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERT_L );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_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 $16 ERT_L must return a value greater than 1 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22)  // IF Test 9.22
			{
				if ( ERT_L <= Test_5_17_Inf[EcuIdx].INF16_ERT_L &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 ERT_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_ERT_L );
					eRetCode = FAIL;
				}
				else if ( ERT_L < Test_5_17_Inf[EcuIdx].INF16_ERT_L  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 ERT_L must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_ERT_L );
					eRetCode = FAIL;
				}
			}
		}

		// log IERT_R
		IERT_R = (gstResponse[EcuIdx].Inf[26] << 24) +
		         (gstResponse[EcuIdx].Inf[27] << 16) +
		         (gstResponse[EcuIdx].Inf[28] << 8) +
		          gstResponse[EcuIdx].Inf[29];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  IERT_R    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IERT_R );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				if ( IERT_R <= 1 &&
				     gbHybrid != TRUE &&  gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 IERT_R must return a value of greater than 1 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			          IERT_R != 0 && IERT_R != 4294967295 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $16 IERT_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log IERT_L
		IERT_L = (gstResponse[EcuIdx].Inf[30] << 24) +
		         (gstResponse[EcuIdx].Inf[31] << 16) +
		         (gstResponse[EcuIdx].Inf[32] << 8) +
		          gstResponse[EcuIdx].Inf[33];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $16  IERT_L    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IERT_L );
		if ( gstUserInput.eComplianceType == US_OBDII )
		{
			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_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 $16 IERT_L must return a value of greater than 1 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22)  // IF Test 9.22
			{
				if ( IERT_L <= Test_5_17_Inf[EcuIdx].INF16_IERT_L &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 IERT_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF16_IERT_L );
					eRetCode = FAIL;
				}
				else if ( IERT_L < Test_5_17_Inf[EcuIdx].INF16_IERT_L  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $16 IERT_L must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_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;
	STATUS eRetCode = PASS;

	float  DT_R;
	float  DT_L;
	float  FC_R;
	float  FC_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $17 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// DT/FC Data must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 0x02 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17 Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}

		// INF17 NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log DT_R
		DT_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 24) +
		                              (gstResponse[EcuIdx].Inf[3] << 16) +
		                              (gstResponse[EcuIdx].Inf[4] << 8) +
		                               gstResponse[EcuIdx].Inf[5]) * 0.1);

		// if it's the max value, not supported
		if ( DT_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_R not supported\n",
				     GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  DT_R      = %.1f km\n",
			      GetEcuId ( EcuIdx ),
			      DT_R );

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

				if ( DT_R != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $17 DT_R must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
			          DT_R <= Test_5_17_Inf[EcuIdx].INF17_DT_R )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_R must return a value greater than the value returned in Test 5.17 (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF17_DT_R );
				eRetCode = FAIL;
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			          DT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log DT_L
		DT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                              (gstResponse[EcuIdx].Inf[7] << 16) +
		                              (gstResponse[EcuIdx].Inf[8] << 8) +
		                               gstResponse[EcuIdx].Inf[9]) * 0.1);

		// if it's the max value, not supported
		if ( DT_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  DT_L      = %.1f km\n",
			      GetEcuId ( EcuIdx ),
			      DT_L );

			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_Inf[EcuIdx].INF17_DT_L = DT_L;  // Save value for comaparison in Test 9.22
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
			          DT_L <= Test_5_17_Inf[EcuIdx].INF17_DT_L )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 DT_L must return a value greater than the value returned in Test 5.17 (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF17_DT_L );
				eRetCode = FAIL;
			}
		}

		// log FC_R
		FC_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
		                              (gstResponse[EcuIdx].Inf[11] << 16) +
		                              (gstResponse[EcuIdx].Inf[12] << 8) +
		                               gstResponse[EcuIdx].Inf[13]) * 0.01);

		// if it's the max value, not supported
		if ( FC_R == 42949672.95 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 FC_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 FC_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  FC_R      = %.2f l\n",
			      GetEcuId ( EcuIdx ),
			      FC_R );

			if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
			{
				Test_5_17_Inf[EcuIdx].INF17_FC_R = FC_R;  // Save value for comaparison in Test 9.22
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22)  // IF Test 9.22
			{
				if ( FC_R <= Test_5_17_Inf[EcuIdx].INF17_FC_R &&
				     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $17 FC_R must return a value greater than the value returned in Test 5.17 (%.2f)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF17_FC_R );
					eRetCode = FAIL;
				}
				else if ( FC_R < Test_5_17_Inf[EcuIdx].INF17_FC_R  &&
				          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $17 FC_R must return a value greater than or equal to the value returned in Test 5.17 (%.2f)\n",
					      GetEcuId ( EcuIdx ),
					      Test_5_17_Inf[EcuIdx].INF17_FC_R );
					eRetCode = FAIL;
				}
			}
			else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			          FC_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 FC_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log FC_L
		FC_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                              (gstResponse[EcuIdx].Inf[15] << 16) +
		                              (gstResponse[EcuIdx].Inf[16] << 8) +
		                               gstResponse[EcuIdx].Inf[17]) * 0.01);

		// if it's the max value, not supported
		if ( FC_L == 42949672.95 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 FC_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $17 FC_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  FC_L      = %.2f l\n",
			      GetEcuId ( EcuIdx ),
			      FC_L );

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

	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;
	STATUS eRetCode = PASS;

	unsigned long  PKE_R;
	unsigned long  PKE_L;
	float EOE_R;
	float EOE_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $18 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// PKE/EO Data must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF18 NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log PKE_R
		PKE_R = (gstResponse[EcuIdx].Inf[2] << 24 ) +
		        (gstResponse[EcuIdx].Inf[3] << 16 ) +
		        (gstResponse[EcuIdx].Inf[4] << 8 ) +
		         gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $18  PKE_R     = %lu km/hr2\n",
		      GetEcuId ( EcuIdx ),
		      PKE_R );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 &&  // IF Test 5.17
		     PKE_R != 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 PKE_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          PKE_R == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 PKE_R must return a value greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		          PKE_R != 0 && PKE_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 PKE_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log PKE_L
		PKE_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		        (gstResponse[EcuIdx].Inf[7] << 16) +
		        (gstResponse[EcuIdx].Inf[8] << 8) +
		         gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $18  PKE_L     = %lu km/hr2\n",
		      GetEcuId ( EcuIdx ),
		      PKE_L );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		     PKE_L == 0 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 PKE_L must return a value greater than 0\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log EOE_R
		EOE_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
		                               (gstResponse[EcuIdx].Inf[11] << 16) +
		                               (gstResponse[EcuIdx].Inf[12] << 8) +
		                                gstResponse[EcuIdx].Inf[13])) * (float)(0.1);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $18  EOE_R     = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      EOE_R );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF18_EOE_R = EOE_R;  // Save value for comaparison in Test 9.22
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 )  // IF Test 9.22
		{
			if ( EOE_R <= Test_5_17_Inf[EcuIdx].INF18_EOE_R &&
			     gstUserInput.ePwrTrnType != PHEV && gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $18 EOE_R must return a value greater than the value returned in Test 5.17 (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF18_EOE_R );
				eRetCode = FAIL;
			}
			else if ( EOE_R < Test_5_17_Inf[EcuIdx].INF18_EOE_R  &&
			          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $18 EOE_R must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF18_EOE_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		          EOE_R != 0 && EOE_R != 429496729.5 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18 EOE_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log EOE_L
		EOE_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                               (gstResponse[EcuIdx].Inf[15] << 16) +
		                               (gstResponse[EcuIdx].Inf[16] << 8) +
		                                gstResponse[EcuIdx].Inf[17])) * (float)(0.1);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $18  EOE_L     = %.1f kWh\n",
		      GetEcuId ( EcuIdx ),
		      EOE_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF18_EOE_L = EOE_L;  // Save value for comaparison in Test 9.22
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 )  // IF Test 9.22
		{
			if ( EOE_L <= Test_5_17_Inf[EcuIdx].INF18_EOE_L &&
			     gbHybrid != TRUE && gbPlugIn != TRUE )  // NOT Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $18 EOE_L must return a value greater than the value returned in Test 5.17 (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF18_EOE_L );
				eRetCode = FAIL;
			}
			else if ( EOE_L < Test_5_17_Inf[EcuIdx].INF18_EOE_L &&
			          (gbHybrid == TRUE || gbPlugIn == TRUE) )  // Hybrid/PHEV
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $18 EOE_L must return a value greater than or equal to the value returned in Test 5.17 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF18_EOE_L );
				eRetCode = FAIL;
			}
		}
	}

	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;
	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $19 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// PSA Data must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF19 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log PSA_R
		PSA_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		        (gstResponse[EcuIdx].Inf[3] << 16) +
		        (gstResponse[EcuIdx].Inf[4] << 8) +
		         gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $19  PSA_R     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_R );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF19_PSA_R = PSA_R;  // Save value for comaparison in Test 9.22
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          PSA_R <= Test_5_17_Inf[EcuIdx].INF19_PSA_R )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 PSA_R must return a value greater than the value returned in Test 5.17 (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_17_Inf[EcuIdx].INF19_PSA_R );
			eRetCode = FAIL;
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		          PSA_R != 0 && PSA_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 PSA_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log PSA_L
		PSA_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		        (gstResponse[EcuIdx].Inf[7] << 16) +
		        (gstResponse[EcuIdx].Inf[8] << 8) +
		         gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $19  PSA_L     = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF19_PSA_L = PSA_L;  // Save value for comaparison in Test 9.22
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          PSA_L <= Test_5_17_Inf[EcuIdx].INF19_PSA_L )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 PSA_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_17_Inf[EcuIdx].INF19_PSA_L );
			eRetCode = FAIL;
		}

		// log IPSA_R
		IPSA_R = (gstResponse[EcuIdx].Inf[10] << 24) +
		         (gstResponse[EcuIdx].Inf[11] << 16) +
		         (gstResponse[EcuIdx].Inf[12] << 8) +
		          gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $19  IPSA_R    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     IPSA_R != 0 && IPSA_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 IPSA_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log IPSA_L
		IPSA_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		         (gstResponse[EcuIdx].Inf[15] << 16) +
		         (gstResponse[EcuIdx].Inf[16] << 8) +
		          gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $19  IPSA_L    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF19_IPSA_L = IPSA_L;  // Save value for comaparison in Test 9.22
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          IPSA_L <= Test_5_17_Inf[EcuIdx].INF19_IPSA_L )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 IPSA_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_17_Inf[EcuIdx].INF19_IPSA_L );
			eRetCode = FAIL;
		}

		// log CPSA_R
		CPSA_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		         (gstResponse[EcuIdx].Inf[19] << 16) +
		         (gstResponse[EcuIdx].Inf[20] << 8) +
		          gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $19  CPSA_R    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      CPSA_R );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF19_CPSA_R = CPSA_R;  // Save value for comaparison in Test 9.22

			if ( CPSA_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $19 CPSA_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF19_CPSA_R );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          CPSA_R <= Test_5_17_Inf[EcuIdx].INF19_CPSA_R )
		{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $19 CPSA_R must return a value greater than the value returned in Test 5.17 (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF19_CPSA_R );
				eRetCode = FAIL;
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		          CPSA_R != 0 && CPSA_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 CPSA_R must return a value of 0 after a Service $04 code clear\n",
			     GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log CPSA_L
		CPSA_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		         (gstResponse[EcuIdx].Inf[23] << 16) +
		         (gstResponse[EcuIdx].Inf[24] << 8) +
		          gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $19  CPSA_L    = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      CPSA_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF19_CPSA_L = CPSA_L;  // Save value for comaparison in Test 9.22
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 &&  // IF Test 9.22
		          CPSA_L <= Test_5_17_Inf[EcuIdx].INF19_CPSA_L )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19 CPSA_L must return a value greater than the value returned in Test 5.17 (%lu)\n",
			      GetEcuId ( EcuIdx ),
			      Test_5_17_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;
	STATUS eRetCode = PASS;

	float  CDEODT_R;
	float  CDEODT_L;
	float  CDERDT_R;
	float  CDERDT_L;
	float  CIDT_R;
	float  CIDT_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $1A data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// PHEVDD Data must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF1A NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log CDEODT_R
		CDEODT_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 24) +
		                                  (gstResponse[EcuIdx].Inf[3] << 16) +
		                                  (gstResponse[EcuIdx].Inf[4] << 8) +
		                                   gstResponse[EcuIdx].Inf[5]) * 0.1);

		// if it's the max value, not supported
		if ( CDEODT_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDEODT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDEODT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDEODT_R  = %.1f km\n",
			      GetEcuId ( EcuIdx ),
			      CDEODT_R );

			if ( ((geTestPhase == eTestNoDTC              && gTestSubsection == 17) ||  // IF Test 5.17
			      (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23)) &&  // OR Test 9.23
			     CDEODT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDEODT_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDEODT_L
		CDEODT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                  (gstResponse[EcuIdx].Inf[7] << 16) +
		                                  (gstResponse[EcuIdx].Inf[8] << 8) +
		                                   gstResponse[EcuIdx].Inf[9]) * 0.1);

		// if it's the max value, not supported
		if ( CDEODT_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDEODT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDEODT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDEODT_L  = %.1f km\n",
			      GetEcuId ( EcuIdx ),
			      CDEODT_L );
		}

		// log CDERDT_R
		CDERDT_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
		                                  (gstResponse[EcuIdx].Inf[11] << 16) +
		                                  (gstResponse[EcuIdx].Inf[12] << 8) +
		                                   gstResponse[EcuIdx].Inf[13]) * 0.1);

		// if it's the max value, not supported
		if ( CDERDT_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDERDT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDERDT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDERDT_R  = %.1f km\n",
			      GetEcuId ( EcuIdx ),
			      CDERDT_R );

			if ( ((geTestPhase == eTestNoDTC              && gTestSubsection == 17) ||                 // IF Test 5.17
			      (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23)) &&  // OR Test 9.23
			     CDERDT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDERDT_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDERDT_L
		CDERDT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                  (gstResponse[EcuIdx].Inf[15] << 16) +
		                                  (gstResponse[EcuIdx].Inf[16] << 8) +
		                                   gstResponse[EcuIdx].Inf[17]) * 0.1);

		// if it's the max value, not supported
		if ( CDERDT_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDERDT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CDERDT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDERDT_L  = %.1f km\n",
			     GetEcuId ( EcuIdx ),
			     CDERDT_L );
		}

		// log CIDT_R
		CIDT_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[18] << 24) +
		                                (gstResponse[EcuIdx].Inf[19] << 16) +
		                                (gstResponse[EcuIdx].Inf[20] << 8) +
		                                 gstResponse[EcuIdx].Inf[21]) * 0.1);

		// if it's the max value, not supported
		if ( CIDT_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR ||  gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CIDT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CIDT_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CIDT_R    = %.1f km\n",
			      GetEcuId ( EcuIdx ),
			      CIDT_R );

			if ( ((geTestPhase == eTestNoDTC              && gTestSubsection == 17) ||                 // IF Test 5.17
			      (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23)) &&  // OR Test 9.23
			     CIDT_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CIDT_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CIDT_L
		CIDT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[22] << 24) +
		                                (gstResponse[EcuIdx].Inf[23] << 16) +
		                                (gstResponse[EcuIdx].Inf[24] << 8) +
		                                 gstResponse[EcuIdx].Inf[25]) * 0.1);

		// if it's the max value, not supported
		if ( CIDT_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CIDT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1A CIDT_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  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;
	STATUS eRetCode = PASS;

	float  CDFC_R;
	float  CDFC_L;
	float  CIFC_R;
	float  CIFC_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $1B data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// PHEVFD Data must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF1B NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log CDFC_R
		CDFC_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 24) +
		                                (gstResponse[EcuIdx].Inf[3] << 16) +
		                                (gstResponse[EcuIdx].Inf[4] << 8) +
		                                 gstResponse[EcuIdx].Inf[5]) * 0.01);
		// if it's the max value, not supported
		if ( CDFC_R == 42949672.95 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CDFC_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CDFC_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CDFC_R    = %.2f l\n",
			      GetEcuId ( EcuIdx ),
			      CDFC_R );

			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			     CDFC_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CDFC_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDFC_L
		CDFC_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                (gstResponse[EcuIdx].Inf[7] << 16) +
		                                (gstResponse[EcuIdx].Inf[8] << 8) +
		                                 gstResponse[EcuIdx].Inf[9]) * 0.01);

		// if it's the max value, not supported
		if ( CDFC_L == 42949672.95 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CDFC_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CDFC_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CDFC_L    = %.2f l\n",
			      GetEcuId ( EcuIdx ),
			      CDFC_L );
		}

		// log CIFC_R
		CIFC_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
		                                (gstResponse[EcuIdx].Inf[11] << 16) +
		                                (gstResponse[EcuIdx].Inf[12] << 8) +
		                                 gstResponse[EcuIdx].Inf[13]) * 0.01);

		// if it's the max value, not supported
		if ( CIFC_R == 42949672.95 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CIFC_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CIFC_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CIFC_R    = %.2f l\n",
			      GetEcuId ( EcuIdx ),
			      CIFC_R );

			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			     CIFC_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CIFC_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CIFC_L
		CIFC_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                (gstResponse[EcuIdx].Inf[15] << 16) +
		                                (gstResponse[EcuIdx].Inf[16] << 8) +
		                                 gstResponse[EcuIdx].Inf[17]) * 0.01);

		// if it's the max value, not supported
		if ( CIFC_L == 42949672.95 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CIFC_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1B CIFC_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  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;
	STATUS eRetCode = PASS;

	float  CDEOGE_R;
	float  CDEOGE_L;
	float  CDERGE_R;
	float  CDERGE_L;
	float  GE_R;
	float  GE_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $1C data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// PHEVGD Data must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 1C NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log CDEOGE_R
		CDEOGE_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 24) +
		                                  (gstResponse[EcuIdx].Inf[3] << 16) +
		                                  (gstResponse[EcuIdx].Inf[4] << 8) +
		                                   gstResponse[EcuIdx].Inf[5]) * 0.1);

		// if it's the max value, not supported
		if ( CDEOGE_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDEOGE_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDEOGE_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDEOGE_R  = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      CDEOGE_R );

			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			     CDEOGE_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDEOGE_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDEOGE_L
		CDEOGE_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                  (gstResponse[EcuIdx].Inf[7] << 16) +
		                                  (gstResponse[EcuIdx].Inf[8] << 8) +
		                                   gstResponse[EcuIdx].Inf[9]) * 0.1);

		// if it's the max value, not supported
		if ( CDEOGE_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDEOGE_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDEOGE_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDEOGE_L  = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      CDEOGE_L );
		}

		// log CDERGE_R
		CDERGE_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
		                                  (gstResponse[EcuIdx].Inf[11] << 16) +
		                                  (gstResponse[EcuIdx].Inf[12] << 8) +
		                                   gstResponse[EcuIdx].Inf[13]) * 0.1);

		// if it's the max value, not supported
		if ( CDERGE_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDERGE_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDERGE_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDERGE_R  = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      CDERGE_R );

			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			     CDERGE_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				       "ECU %X  INF $1C CDERGE_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDERGE_L
		CDERGE_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                  (gstResponse[EcuIdx].Inf[15] << 16) +
		                                  (gstResponse[EcuIdx].Inf[16] << 8) +
		                                   gstResponse[EcuIdx].Inf[17]) * 0.1);

		// if it's the max value, not supported
		if ( CDERGE_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDERGE_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C CDERGE_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDERGE_L  = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      CDERGE_L );
		}

		// log GE_R
		GE_R = (float)((unsigned int)((gstResponse[EcuIdx].Inf[18] << 24) +
		                              (gstResponse[EcuIdx].Inf[19] << 16) +
		                              (gstResponse[EcuIdx].Inf[20] << 8) +
		                               gstResponse[EcuIdx].Inf[21]) * 0.1);

		// if it's the max value, not supported
		if ( GE_R == 429496729.5 )
		{
			if ( gstUserInput.eComplianceType == EOBD_NO_IUMPR || gstUserInput.eComplianceType == EOBD_WITH_IUMPR ||
			     (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23) )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C GE_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C GE_R not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  GE_R      = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      GE_R );

			if ( ((geTestPhase == eTestNoDTC              && gTestSubsection == 17) ||                 // IF Test 5.17
			      (geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23)) &&  // OR Test 9.23
			     GE_R != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C GE_R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log GE_L
		GE_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[22] << 24) +
		                              (gstResponse[EcuIdx].Inf[23] << 16) +
		                              (gstResponse[EcuIdx].Inf[24] << 8) +
		                               gstResponse[EcuIdx].Inf[25]) * 0.1);

		// if it's the max value, not supported
		if ( GE_L == 429496729.5 )
		{
			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C GE_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
			else
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $1C GE_L not supported\n",
				      GetEcuId ( EcuIdx ) );
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  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;
	STATUS eRetCode = PASS;

	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $1D data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// AAF1OCCVD Data must contain 32 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 32 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D Data Size = %d (Must be 32 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 1D NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log AGSA_TIME1_R
		AGSA_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSA_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AGSA_TIME1_R != 0 && AGSA_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D AGSA_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AGSA_TIME2_R
		AGSA_TIME2_R = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8) +
		                gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSA_TIME2_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME2_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AGSA_TIME2_R != 0 && AGSA_TIME2_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D AGSA_TIME2_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AGSA_TIME1_L
		AGSA_TIME1_L = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8) +
		                gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSA_TIME1_L = %lu sec\n",
		     GetEcuId ( EcuIdx ),
		     AGSA_TIME1_L );

		// log AGSA_TIME2_L
		AGSA_TIME2_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSA_TIME2_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSA_TIME2_L );

		// log AGSB_TIME1_R
		AGSB_TIME1_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		               (gstResponse[EcuIdx].Inf[19] << 16) +
		               (gstResponse[EcuIdx].Inf[20] << 8) +
		                gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSB_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AGSB_TIME1_R != 0 && AGSB_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D AGSB_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AGSB_TIME2_R
		AGSB_TIME2_R = (gstResponse[EcuIdx].Inf[22] << 24) +
		               (gstResponse[EcuIdx].Inf[23] << 16) +
		               (gstResponse[EcuIdx].Inf[24] << 8) +
		                gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSB_TIME2_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME2_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AGSB_TIME2_R != 0 && AGSB_TIME2_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D AGSB_TIME2_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AGSB_TIME1_L
		AGSB_TIME1_L = (gstResponse[EcuIdx].Inf[26] << 24) +
		               (gstResponse[EcuIdx].Inf[27] << 16) +
		               (gstResponse[EcuIdx].Inf[28] << 8) +
		                gstResponse[EcuIdx].Inf[29];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSB_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME1_L );

		// log AGSB_TIME2_L
		AGSB_TIME2_L = (gstResponse[EcuIdx].Inf[30] << 24) +
		               (gstResponse[EcuIdx].Inf[31] << 16) +
		               (gstResponse[EcuIdx].Inf[32] << 8) +
		                gstResponse[EcuIdx].Inf[33];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1D  AGSB_TIME2_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AGSB_TIME2_L );
	}

	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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $1E data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// AAF2OCCVD Data must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E Data Size = %d (Must be 16 bytes!)\n",
			     GetEcuId ( EcuIdx ),
			     (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 1E NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E NODI = %d (Must be 1)\n",
			     GetEcuId ( EcuIdx ),
			     pInf->NODI );
			eRetCode = FAIL;
		}

		// log VRHC_TIME1_R
		VRHC_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1E  VRHC_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     VRHC_TIME1_R != 0 && VRHC_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E VRHC_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log VRHC_TIME2_R
		VRHC_TIME2_R = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8) +
		                gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1E  VRHC_TIME2_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME2_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     VRHC_TIME2_R != 0 && VRHC_TIME2_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E VRHC_TIME2_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log VRHC_TIME1_L
		VRHC_TIME1_L = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8) +
		                gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1E  VRHC_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME1_L );

		// log VRHC_TIME2_L
		VRHC_TIME2_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1E  VRHC_TIME2_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      VRHC_TIME2_L );
	}

	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;
	STATUS eRetCode = PASS;

	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $1F data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// AAF3OCCVD Data must contain 32 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 32 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F Data Size = %d (Must be 32 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 1F NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F NODI = %d (Must be 1)\n",
			     GetEcuId ( EcuIdx ),
			     pInf->NODI );
			eRetCode = FAIL;
		}

		// log AAF1_TIME1_R
		AAF1_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF1_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AAF1_TIME1_R != 0 && AAF1_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F AAF1_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AAF1_TIME2_R
		AAF1_TIME2_R = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8 ) +
		                gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF1_TIME2_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME2_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AAF1_TIME2_R != 0 && AAF1_TIME2_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F AAF1_TIME2_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AAF1_TIME1_L
		AAF1_TIME1_L = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8) +
		                gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF1_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME1_L );

		// log AAF1_TIME2_L
		AAF1_TIME2_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF1_TIME2_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF1_TIME2_L );

		// log AAF2_TIME1_R
		AAF2_TIME1_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		               (gstResponse[EcuIdx].Inf[19] << 16) +
		               (gstResponse[EcuIdx].Inf[20] << 8) +
		                gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF2_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AAF2_TIME1_R != 0 && AAF2_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F AAF2_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AAF2_TIME2_R
		AAF2_TIME2_R = (gstResponse[EcuIdx].Inf[22] << 24) +
		               (gstResponse[EcuIdx].Inf[23] << 16) +
		               (gstResponse[EcuIdx].Inf[24] << 8) +
		                gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF2_TIME2_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME2_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     AAF2_TIME2_R != 0 && AAF2_TIME2_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F AAF2_TIME2_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log AAF2_TIME1_L
		AAF2_TIME1_L = (gstResponse[EcuIdx].Inf[26] << 24) +
		               (gstResponse[EcuIdx].Inf[27] << 16) +
		               (gstResponse[EcuIdx].Inf[28] << 8 ) +
		                gstResponse[EcuIdx].Inf[29];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF2_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME1_L );

		// log AAF2_TIME2_L
		AAF2_TIME2_L = (gstResponse[EcuIdx].Inf[30] << 24) +
		               (gstResponse[EcuIdx].Inf[31] << 16) +
		               (gstResponse[EcuIdx].Inf[32] << 8) +
		                gstResponse[EcuIdx].Inf[33];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $1F  AAF2_TIME2_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AAF2_TIME2_L );
	}

	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;
	STATUS eRetCode = PASS;

	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $21 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// DSOMOCCVD Data must contain 40 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 40 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 Data Size = %d (Must be 40 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 21 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log EDSM_TIME1_R
		EDSM_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  EDSM_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     EDSM_TIME1_R != 0 && EDSM_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 EDSM_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log EDSM_TIME1_L
		EDSM_TIME1_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8) +
		                gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  EDSM_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EDSM_TIME1_L );

		// log DSM1_TIME1_R
		DSM1_TIME1_R = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8) +
		                gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM1_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM1_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DSM1_TIME1_R != 0 && DSM1_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 DSM1_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DSM1_TIME1_L
		DSM1_TIME1_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM1_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM1_TIME1_L );

		// log DSM2_TIME1_R
		DSM2_TIME1_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		               (gstResponse[EcuIdx].Inf[19] << 16) +
		               (gstResponse[EcuIdx].Inf[20] << 8) +
		                gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM2_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM2_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DSM2_TIME1_R != 0 && DSM2_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 DSM2_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DSM2_TIME1_L
		DSM2_TIME1_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		               (gstResponse[EcuIdx].Inf[23] << 16) +
		               (gstResponse[EcuIdx].Inf[24] << 8) +
		                gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM2_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM2_TIME1_L );

		// log DSM3_TIME1_R
		DSM3_TIME1_R = (gstResponse[EcuIdx].Inf[26] << 24) +
		               (gstResponse[EcuIdx].Inf[27] << 16) +
		               (gstResponse[EcuIdx].Inf[28] << 8) +
		                gstResponse[EcuIdx].Inf[29];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM3_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM3_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DSM3_TIME1_R != 0 && DSM3_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 DSM3_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DSM3_TIME1_L
		DSM3_TIME1_L = (gstResponse[EcuIdx].Inf[30] << 24) +
		               (gstResponse[EcuIdx].Inf[31] << 16) +
		               (gstResponse[EcuIdx].Inf[32] << 8) +
		                gstResponse[EcuIdx].Inf[33];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM3_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM3_TIME1_L );

		// log DSM4_TIME1_R
		DSM4_TIME1_R = (gstResponse[EcuIdx].Inf[34] << 24) +
		               (gstResponse[EcuIdx].Inf[35] << 16) +
		               (gstResponse[EcuIdx].Inf[36] << 8) +
		                gstResponse[EcuIdx].Inf[37];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM4_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM4_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DSM4_TIME1_R != 0 && DSM4_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21 DSM4_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DSM4_TIME1_L
		DSM4_TIME1_L = (gstResponse[EcuIdx].Inf[38] << 24) +
		               (gstResponse[EcuIdx].Inf[39] << 16) +
		               (gstResponse[EcuIdx].Inf[40] << 8) +
		                gstResponse[EcuIdx].Inf[41];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $21  DSM4_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      DSM4_TIME1_L );
	}

	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;
	STATUS eRetCode = PASS;

	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $22 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// RTSSCOCCVD Data must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22 Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 22 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log ISS_TIME1_R
		ISS_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24)  +
		              (gstResponse[EcuIdx].Inf[3] << 16) +
		              (gstResponse[EcuIdx].Inf[4] << 8) +
		               gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $22  ISS_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ISS_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     ISS_TIME1_R != 0 && ISS_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22 ISS_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log ISS_TIME1_L
		ISS_TIME1_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		              (gstResponse[EcuIdx].Inf[7] << 16) +
		              (gstResponse[EcuIdx].Inf[8] << 8) +
		               gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $22  ISS_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ISS_TIME1_L );

		// log ERC_TIME1_R
		ERC_TIME1_R = (gstResponse[EcuIdx].Inf[10] << 24) +
		              (gstResponse[EcuIdx].Inf[11] << 16) +
		              (gstResponse[EcuIdx].Inf[12] << 8) +
		               gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $22  ERC_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERC_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     ERC_TIME1_R != 0 && ERC_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22 ERC_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log ERC_TIME1_L
		ERC_TIME1_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		              (gstResponse[EcuIdx].Inf[15] << 16) +
		              (gstResponse[EcuIdx].Inf[16] << 8) +
		               gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $22  ERC_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ERC_TIME1_L );

		// log EOC_TIME1_R
		EOC_TIME1_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		              (gstResponse[EcuIdx].Inf[19] << 16) +
		              (gstResponse[EcuIdx].Inf[20] << 8) +
		               gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $22  EOC_TIME1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EOC_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     EOC_TIME1_R != 0 && EOC_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22 EOC_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log EOC_TIME1_L
		EOC_TIME1_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		              (gstResponse[EcuIdx].Inf[23] << 16) +
		              (gstResponse[EcuIdx].Inf[24] << 8) +
		               gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $22  EOC_TIME1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EOC_TIME1_L );
	}

	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;
	STATUS eRetCode = PASS;

	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $23 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// DCTOCCVD Data must contain 48 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 48 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 Data Size = %d (Must be 48 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 23 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log DCTE1_CNTS_R
		DCTE1_CNTS_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTE1_CNTS_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE1_CNTS_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DCTE1_CNTS_R != 0 && DCTE1_CNTS_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 DCTE1_CNTS_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DCTU1_CNTS_R
		DCTU1_CNTS_R = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8) +
		                gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTU1_CNTS_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU1_CNTS_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DCTU1_CNTS_R != 0 && DCTU1_CNTS_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 DCTU1_CNTS_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DCTE1_CNTS_L
		DCTE1_CNTS_L = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8 ) +
		                gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTE1_CNTS_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE1_CNTS_L );

		// log DCTU1_CNTS_L
		DCTU1_CNTS_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTU1_CNTS_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU1_CNTS_L );

		// log DCTE1_CNTS_R
		DCTE2_CNTS_R = (gstResponse[EcuIdx].Inf[18] << 24) +
		               (gstResponse[EcuIdx].Inf[19] << 16) +
		               (gstResponse[EcuIdx].Inf[20] << 8 ) +
		                gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTE2_CNTS_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE2_CNTS_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DCTE2_CNTS_R != 0 && DCTE2_CNTS_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 DCTE2_CNTS_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DCTU2_CNTS_R
		DCTU2_CNTS_R = (gstResponse[EcuIdx].Inf[22] << 24) +
		               (gstResponse[EcuIdx].Inf[23] << 16) +
		               (gstResponse[EcuIdx].Inf[24] << 8) +
		                gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTU2_CNTS_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU2_CNTS_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DCTU2_CNTS_R != 0 && DCTU2_CNTS_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 DCTU2_CNTS_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DCTE2_CNTS_L
		DCTE2_CNTS_L = (gstResponse[EcuIdx].Inf[26] << 24) +
		               (gstResponse[EcuIdx].Inf[27] << 16) +
		               (gstResponse[EcuIdx].Inf[28] << 8) +
		                gstResponse[EcuIdx].Inf[29];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTE2_CNTS_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE2_CNTS_L );

		// log DCTU2_CNTS_L
		DCTU2_CNTS_L = (gstResponse[EcuIdx].Inf[30] << 24) +
		               (gstResponse[EcuIdx].Inf[31] << 16) +
		               (gstResponse[EcuIdx].Inf[32] << 8) +
		                gstResponse[EcuIdx].Inf[33];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTU2_CNTS_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU2_CNTS_L );

		// log DCTE3_CNTS_R
		DCTE3_CNTS_R = (gstResponse[EcuIdx].Inf[34] << 24) +
		               (gstResponse[EcuIdx].Inf[35] << 16) +
		               (gstResponse[EcuIdx].Inf[36] << 8) +
		                gstResponse[EcuIdx].Inf[37];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTE3_CNTS_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE3_CNTS_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DCTE3_CNTS_R != 0 && DCTE3_CNTS_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 DCTE3_CNTS_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DCTU3_CNTS_R
		DCTU3_CNTS_R = (gstResponse[EcuIdx].Inf[38] << 24) +
		               (gstResponse[EcuIdx].Inf[39] << 16) +
		               (gstResponse[EcuIdx].Inf[40] << 8 ) +
		                gstResponse[EcuIdx].Inf[41];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTU3_CNTS_R = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU3_CNTS_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     DCTU3_CNTS_R != 0 && DCTU3_CNTS_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23 DCTU3_CNTS_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log DCTE3_CNTS_L
		DCTE3_CNTS_L = (gstResponse[EcuIdx].Inf[42] << 24) +
		               (gstResponse[EcuIdx].Inf[43] << 16) +
		               (gstResponse[EcuIdx].Inf[44] << 8) +
		                gstResponse[EcuIdx].Inf[45];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTE3_CNTS_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTE3_CNTS_L );

		// log DCTU3_CNTS_L
		DCTU3_CNTS_L = (gstResponse[EcuIdx].Inf[46] << 24) +
		               (gstResponse[EcuIdx].Inf[47] << 16) +
		               (gstResponse[EcuIdx].Inf[48] << 8) +
		                gstResponse[EcuIdx].Inf[49];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $23  DCTU3_CNTS_L = %lu\n",
		      GetEcuId ( EcuIdx ),
		      DCTU3_CNTS_L );
	}

	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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $24 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// APTWUFOCCVD Data must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24 Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF 24 NODI must equal $01
		if ( pInf->NODI != 1 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log EWU_TIME_R
		EWU_TIME_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		             (gstResponse[EcuIdx].Inf[3] << 16) +
		             (gstResponse[EcuIdx].Inf[4] << 8) +
		              gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $24  EWU_TIME_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EWU_TIME_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     EWU_TIME_R != 0 && EWU_TIME_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24 EWU_TIME_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log EWU_TIME_L
		EWU_TIME_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		             (gstResponse[EcuIdx].Inf[7] << 16) +
		             (gstResponse[EcuIdx].Inf[8] << 8) +
		              gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $24  EWU_TIME_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      EWU_TIME_L );

		// log TWU_TIME_R
		TWU_TIME_R = (gstResponse[EcuIdx].Inf[10] << 24) +
		             (gstResponse[EcuIdx].Inf[11] << 16) +
		             (gstResponse[EcuIdx].Inf[12] << 8) +
		              gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $24  TWU_TIME_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      TWU_TIME_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     TWU_TIME_R != 0 && TWU_TIME_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24 TWU_TIME_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ) );
			eRetCode = FAIL;
		}

		// log TWU_TIME_L
		TWU_TIME_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		             (gstResponse[EcuIdx].Inf[15] << 16 ) +
		             (gstResponse[EcuIdx].Inf[16] << 8 ) +
		              gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $24  TWU_TIME_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      TWU_TIME_L );
	}

	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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// Data must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// INF2x NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log AOCCTxT1_R
		OCCT_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  OCCT%dT1_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      pInf->ID - 24,
		      OCCT_TIME1_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     OCCT_TIME1_R != 0 && OCCT_TIME1_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X OCCT_TIME1_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID );
			eRetCode = FAIL;
		}

		// log AOCCTxT2_R
		OCCT_TIME2_R = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8) +
		                gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  OCCT%dT2_R = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      pInf->ID - 24,
		      OCCT_TIME2_R );
		if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
		     OCCT_TIME2_R != 0 && OCCT_TIME2_R != 4294967295 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X OCCT_TIME2_R must return a value of 0 after a Service $04 code clear\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID );
			eRetCode = FAIL;
		}

		// log AOCCTxT1_L
		OCCT_TIME1_L = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8) +
		                gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  OCCT%dT1_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      pInf->ID - 24,
		      OCCT_TIME1_L );

		// log AOCCTxT2_L
		OCCT_TIME2_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  OCCT%dT2_L = %lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      pInf->ID - 24,
		      OCCT_TIME2_L );
	}

	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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// INF $41 and $43 must contain 8 bytes of data
		if ( (pInf->ID == 0x41 || pInf->ID == 0x43 ) && gstResponse[EcuIdx].InfSize - 0x02 != 8 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 8 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			     (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}
		// INF $45 must contain 16 bytes of data
		else if ( pInf->ID == 0x45 && gstResponse[EcuIdx].InfSize - 0x02 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $45 Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


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


		// log ERT
		if ( pInf->ID == 0x45 )
		{
			ERT = ((gstResponse[EcuIdx].Inf[2] << 24) +
		           (gstResponse[EcuIdx].Inf[3] << 16) +
		           (gstResponse[EcuIdx].Inf[4] << 8) +
		            gstResponse[EcuIdx].Inf[5]) * 10;
		}
		else
		{
			ERT = ((gstResponse[EcuIdx].Inf[2] << 8) +
			        gstResponse[EcuIdx].Inf[3]) * 10;
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  ERT-%c =  %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      ERT );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x41 )
			{
				Test_5_17_Inf[EcuIdx].INF41_ERT_A = ERT;
			}

			if ( pInf->ID == 0x41 &&
			     gstUserInput.ePwrTrnType != PHEV &&
			     ERT <= 1 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X ERT-%c must return a value of greater than 1 sec\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter );
				eRetCode = FAIL;
			}
			else if ( pInf->ID == 0x45 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          ERT < Test_5_17_Inf[EcuIdx].INF41_ERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $45 ERT-L must return a value of greater than ERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF41_ERT_A );
				eRetCode = FAIL;
			}
		}


		// log DT
		if ( pInf->ID == 0x45 )
		{
			DT = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                (gstResponse[EcuIdx].Inf[7] << 16) +
		                                (gstResponse[EcuIdx].Inf[8] << 8) +
		                                 gstResponse[EcuIdx].Inf[9]) * .25);
		}
		else
		{
			DT = (float)((unsigned int)((gstResponse[EcuIdx].Inf[4] << 8) +
			                             gstResponse[EcuIdx].Inf[5]) * .25);
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  DT-%c  =  %10.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      DT );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x41 )
			{
				Test_5_17_Inf[EcuIdx].INF41_DT_A = DT;
				if ( DT != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $41 DT-A must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x43 )
			{
				Test_5_17_Inf[EcuIdx].INF43_DT_S = DT;
			}
			else if ( pInf->ID == 0x45 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          DT < Test_5_17_Inf[EcuIdx].INF41_DT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $45 DT-L must return a value of greater than DT-A (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF41_DT_A );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )  // IF Test 9.23
		{
			if ( (pInf->ID == 0x41 && DT <= Test_5_17_Inf[EcuIdx].INF41_DT_A) ||
			     (pInf->ID == 0x43 && DT <= Test_5_17_Inf[EcuIdx].INF43_DT_S) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X DT-%c must return a value of greater than in Test 5.17 (%.2f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter,
				      pInf->ID == 0x41 ? Test_5_17_Inf[EcuIdx].INF41_DT_A : Test_5_17_Inf[EcuIdx].INF43_DT_S );
				eRetCode = FAIL;
			}
		}


		// log EOE
		if ( pInf->ID == 0x45 )
		{
			EOE = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
			                             (gstResponse[EcuIdx].Inf[11] << 16) +
			                             (gstResponse[EcuIdx].Inf[12] << 8) +
			                              gstResponse[EcuIdx].Inf[13]) * .001);
		}
		else
		{
			EOE = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 8) +
			                              gstResponse[EcuIdx].Inf[7]) * .001);
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  EOE-%c = %11.3f MWh\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      EOE );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x41 )
			{
				Test_5_17_Inf[EcuIdx].INF41_EOE_A = EOE;
			}
			else if ( pInf->ID == 0x43 )
			{
				Test_5_17_Inf[EcuIdx].INF43_EOE_S = EOE;
			}
			else if ( pInf->ID == 0x45 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          EOE < Test_5_17_Inf[EcuIdx].INF41_EOE_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $45 EOE-L must return a value of greater than EOE-A\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )  // IF Test 9.23
		{
			if ( (pInf->ID == 0x41 && EOE <= Test_5_17_Inf[EcuIdx].INF41_EOE_A) ||
			     (pInf->ID == 0x43 && EOE <= Test_5_17_Inf[EcuIdx].INF43_EOE_S) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $02X EOE-%c must return a value of greater than in Test 5.17 (%.3f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter,
				      pInf->ID == 0x41 ? Test_5_17_Inf[EcuIdx].INF41_EOE_A : Test_5_17_Inf[EcuIdx].INF43_EOE_S );
				eRetCode = FAIL;
			}
		}


		// log VFC
		if ( pInf->ID == 0x45 )
		{
			VFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
			                             (gstResponse[EcuIdx].Inf[15] << 16) +
			                             (gstResponse[EcuIdx].Inf[16] << 8) +
			                              gstResponse[EcuIdx].Inf[17]) * .5);
		}
		else
		{
			VFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[8] << 8) +
			                              gstResponse[EcuIdx].Inf[9]) * .5);
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  VFC-%c =  %10.1f l\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      VFC );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x41 )
			{
				Test_5_17_Inf[EcuIdx].INF41_VFC_A = VFC;
			}
			else if ( pInf->ID == 0x43 )
			{
				Test_5_17_Inf[EcuIdx].INF43_VFC_S = VFC;
			}
			else if ( pInf->ID == 0x45 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          VFC < Test_5_17_Inf[EcuIdx].INF41_VFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $45 VFC-L must return a value of greater than VFC-A\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )  // IF Test 9.23
		{
			if ( ( pInf->ID == 0x41 && VFC <= Test_5_17_Inf[EcuIdx].INF41_VFC_A ) ||
			     ( pInf->ID == 0x43 && VFC <= Test_5_17_Inf[EcuIdx].INF43_VFC_S ) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $02X VFC-%c must return a value of greater than in Test 5.17 (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter,
				      pInf->ID == 0x41 ? Test_5_17_Inf[EcuIdx].INF41_VFC_A : Test_5_17_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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// INF $42 and $44 must contain 16 bytes of data
		if ( (pInf->ID == 0x42 || pInf->ID == 0x44 ) &&
		     gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}
		// INF $46 must contain 16 bytes of data
		else if ( pInf->ID == 0x46 &&
		          gstResponse[EcuIdx].InfSize - 2 != 28 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $46 Data Size = %d (Must be 28 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


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


		// log EFC
		if ( pInf->ID == 0x46 )
		{
			EFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 24) +
			                             (gstResponse[EcuIdx].Inf[3] << 16) +
			                             (gstResponse[EcuIdx].Inf[4] << 8) +
			                              gstResponse[EcuIdx].Inf[5]) * .5);
		}
		else
		{
			EFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 8) +
			                              gstResponse[EcuIdx].Inf[3]) * .5);
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  EFC-%c = %13.1f l\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      EFC );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_EFC_A = EFC;
				if ( EFC != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $42 ERT-A must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x44 )
			{
				Test_5_17_Inf[EcuIdx].INF44_EFC_S = EFC;
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          EFC < Test_5_17_Inf[EcuIdx].INF42_EFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 EFC-L must return a value of greater than EFC-A (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF42_EFC_A );
				eRetCode = FAIL;
			}
		}
		else if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 )  // IF Test 9.23
		{
			if ( gstUserInput.ePwrTrnType != PHEV &&
			     ((pInf->ID == 0x42 && EFC <= Test_5_17_Inf[EcuIdx].INF42_EFC_A) ||
			      (pInf->ID == 0x44 && EFC <= Test_5_17_Inf[EcuIdx].INF44_EFC_S)) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $02X EFC-%c must return a value of greater than in Test 5.17 (%d)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter,
				      pInf->ID == 0x41 ? Test_5_17_Inf[EcuIdx].INF42_EFC_A : Test_5_17_Inf[EcuIdx].INF44_EFC_S );
				eRetCode = FAIL;
			}
			else if ( PHEV &&
			          ((pInf->ID == 0x42 && EFC < Test_5_17_Inf[EcuIdx].INF42_EFC_A) ||
			           (pInf->ID == 0x44 && EFC < Test_5_17_Inf[EcuIdx].INF44_EFC_S)) )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $02X EFC-%c must return a value of greater than or equal to Test 5.17 (%d)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter,
				      pInf->ID == 0x41 ? Test_5_17_Inf[EcuIdx].INF42_EFC_A : Test_5_17_Inf[EcuIdx].INF44_EFC_S );
				eRetCode = FAIL;
			}
		}


		// log IERT
		if ( pInf->ID == 0x46 )
		{
			IERT = (gstResponse[EcuIdx].Inf[6] << 24) +
			       (gstResponse[EcuIdx].Inf[7] << 16) +
			       (gstResponse[EcuIdx].Inf[8] << 8) +
			        gstResponse[EcuIdx].Inf[9];
		}
		else
		{
			IERT = ((gstResponse[EcuIdx].Inf[4] << 8) +
			         gstResponse[EcuIdx].Inf[5]) * 10;
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  IERT-%c = %12lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      IERT );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_IERT_A = IERT;
			}

			if ( pInf->ID == 0x42 &&
			     gstUserInput.ePwrTrnType != PHEV &&
			     IERT <= 1 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X IERT-%c must return a value of greater than 1\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter );
				eRetCode = FAIL;
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          IERT < Test_5_17_Inf[EcuIdx].INF42_IERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 IERT-L must return a value of greater than IERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF42_IERT_A );
				eRetCode = FAIL;
			}
		}


		// log IEFC
		if ( pInf->ID == 0x46 )
		{
			IEFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
			                              (gstResponse[EcuIdx].Inf[11] << 16) +
			                              (gstResponse[EcuIdx].Inf[12] << 8) +
			                               gstResponse[EcuIdx].Inf[13]) * .5);
		}
		else
		{
			IEFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 8) +
			                               gstResponse[EcuIdx].Inf[7]) * .5);
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  IEFC-%c = %12.1f l\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      IEFC );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_IEFC_A = IEFC;
			}

			if ( pInf->ID == 0x42 &&
			     gstUserInput.ePwrTrnType != PHEV &&
			     IEFC <= 1 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X IEFC-%c must return a value of greater than 1\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      Letter );
				eRetCode = FAIL;
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          IEFC < Test_5_17_Inf[EcuIdx].INF42_IEFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 IEFC-L must return a value of greater than IEFC-A (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF42_IEFC_A );
				eRetCode = FAIL;
			}
		}


		// log UERT
		if ( pInf->ID == 0x46 )
		{
			UERT = (gstResponse[EcuIdx].Inf[14] << 24) +
			       (gstResponse[EcuIdx].Inf[15] << 16) +
			       (gstResponse[EcuIdx].Inf[16] << 8) +
			        gstResponse[EcuIdx].Inf[17];
		}
		else
		{
			UERT = ((gstResponse[EcuIdx].Inf[8] << 8) +
			         gstResponse[EcuIdx].Inf[9]) * 10;
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  UERT-%c = %12lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      UERT );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_UERT_A = UERT;
				if ( UERT != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $42 UERT-A must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          UERT < Test_5_17_Inf[EcuIdx].INF42_UERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 UERT-L must return a value of greater than UERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF42_UERT_A );
				eRetCode = FAIL;
			}
		}


		// log PKE
		if ( pInf->ID == 0x46 )
		{
			PKE = ((gstResponse[EcuIdx].Inf[18] << 24) +
			       (gstResponse[EcuIdx].Inf[19] << 16) +
			       (gstResponse[EcuIdx].Inf[20] << 8) +
			        gstResponse[EcuIdx].Inf[21]) * 5;
		}
		else
		{
			PKE = (gstResponse[EcuIdx].Inf[10] << 24) +
			      (gstResponse[EcuIdx].Inf[11] << 16) +
			      (gstResponse[EcuIdx].Inf[12] << 8) +
			       gstResponse[EcuIdx].Inf[13];
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  PKE-%c = %13lu km2/h2\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      PKE );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17  )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_PKE_A = PKE;
				if ( PKE != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $42 PKE-A must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          PKE < Test_5_17_Inf[EcuIdx].INF42_PKE_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 PKE-L must return a value of greater than PKE-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF42_PKE_A );
				eRetCode = FAIL;
			}
		}


		// log PTOERT
		if ( pInf->ID == 0x46 )
		{
			PTOERT = (gstResponse[EcuIdx].Inf[22] << 24) +
			         (gstResponse[EcuIdx].Inf[23] << 16) +
			         (gstResponse[EcuIdx].Inf[24] << 8) +
			          gstResponse[EcuIdx].Inf[25];
		}
		else
		{
			PTOERT = ((gstResponse[EcuIdx].Inf[14] << 8) +
			           gstResponse[EcuIdx].Inf[15]) * 10;
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  PTOERT-%c = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      PTOERT );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17  )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_PTOERT_A = PTOERT;
				if ( PTOERT != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $42 PTOERT-A must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          PTOERT < Test_5_17_Inf[EcuIdx].INF42_PTOERT_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 PTOERT-L must return a value of greater than PTOERT-A (%lu)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_Inf[EcuIdx].INF42_PTOERT_A );
				eRetCode = FAIL;
			}
		}


		// log PTOFC
		if ( pInf->ID == 0x46 )
		{
			PTOFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[26] << 24) +
			                               (gstResponse[EcuIdx].Inf[27] << 16) +
			                               (gstResponse[EcuIdx].Inf[28] << 8) +
			                                gstResponse[EcuIdx].Inf[29]) * .5);
		}
		else
		{
			PTOFC = (float)((unsigned int)((gstResponse[EcuIdx].Inf[16] << 8) +
			                                gstResponse[EcuIdx].Inf[17]) * .5);
		}
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  PTOFC-%c = %11.1f l\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Letter,
		      PTOFC );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17  )  // IF Test 5.17
		{
			if ( pInf->ID == 0x42 )
			{
				Test_5_17_Inf[EcuIdx].INF42_PTOFC_A = PTOFC;
				if ( PTOFC != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $42 PTOFC-A must return a value of 0 after a Service $04 code clear\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV &&
			          PTOFC < Test_5_17_Inf[EcuIdx].INF42_PTOFC_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $46 PTOFC-L must return a value of greater than PTOFC-A (%.1f)\n",
				      GetEcuId ( EcuIdx ),
				      Test_5_17_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;
	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $47 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $47 Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			     (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $47 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log PSA_A
		PSA_A = ((gstResponse[EcuIdx].Inf[2] << 8) +
		          gstResponse[EcuIdx].Inf[3]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  PSA-A = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_PSA_A = PSA_A;
		}

		// log PSA_S
		PSA_S = ((gstResponse[EcuIdx].Inf[4] << 8) +
		          gstResponse[EcuIdx].Inf[5]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  PSA-S = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_S );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_PSA_S = PSA_S;
		}

		// log PSA_L
		PSA_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		        (gstResponse[EcuIdx].Inf[7] << 16) +
		        (gstResponse[EcuIdx].Inf[8] << 8) +
		         gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  PSA-L = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      PSA_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_PSA_L = PSA_L;

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


		// log IPSA_A
		IPSA_A = ((gstResponse[EcuIdx].Inf[10] << 8) +
		           gstResponse[EcuIdx].Inf[11]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  IPSA-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_IPSA_A = IPSA_A;
		}

		// log IPSA_S
		IPSA_S = ((gstResponse[EcuIdx].Inf[12] << 8) +
		           gstResponse[EcuIdx].Inf[13]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  IPSA-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_S );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_IPSA_S = IPSA_S;
		}

		// log IPSA_L
		IPSA_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		         (gstResponse[EcuIdx].Inf[15] << 16) +
		         (gstResponse[EcuIdx].Inf[16] << 8) +
		          gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  IPSA-L = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      IPSA_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_IPSA_L = IPSA_L;

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


		// log UPSA_A
		UPSA_A = ((gstResponse[EcuIdx].Inf[18] << 8) +
		           gstResponse[EcuIdx].Inf[19]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  UPSA-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      UPSA_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_UPSA_A = UPSA_A;

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

		// log UPSA_S
		UPSA_S = ((gstResponse[EcuIdx].Inf[20] << 8) +
		           gstResponse[EcuIdx].Inf[21]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  UPSA-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      UPSA_S );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_UPSA_S = UPSA_S;
		}

		// log UPSA_L
		UPSA_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		         (gstResponse[EcuIdx].Inf[23] << 16) +
		         (gstResponse[EcuIdx].Inf[24] << 8) +
		          gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $47  UPSA-L = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      UPSA_L );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			Test_5_17_Inf[EcuIdx].INF47_UPSA_L = UPSA_L;

			if ( UPSA_L <= UPSA_A )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $47 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;
	STATUS eRetCode = PASS;

	float  CDEODT_A;
	float  CDEODT_S;
	float  CDEODT_L;

	float  CDERDT_A;
	float  CDERDT_S;
	float  CDERDT_L;

	float  CIDT_A;
	float  CIDT_S;
	float  CIDT_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $48 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $48 Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $48 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log CDEODT_A
		CDEODT_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 8) +
		                                   gstResponse[EcuIdx].Inf[3]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDEODT-A = %9.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDEODT_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( CDEODT_A != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $48 CDEODT-A must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDEODT_S
		CDEODT_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[4] << 8) +
		                                   gstResponse[EcuIdx].Inf[5]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDEODT-S = %8.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDEODT_S );

		// log CDEODT_L
		CDEODT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                  (gstResponse[EcuIdx].Inf[7] << 16) +
		                                  (gstResponse[EcuIdx].Inf[8] << 8) +
		                                   gstResponse[EcuIdx].Inf[9]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDEODT-L = %8.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDEODT_L );


		// log CDERDT_A
		CDERDT_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 8) +
		                                   gstResponse[EcuIdx].Inf[11]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDERDT-A = %9.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDERDT_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( CDERDT_A != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $48 CDERDT-A must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CDERDT_S
		CDERDT_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[12] << 8) +
		                                   gstResponse[EcuIdx].Inf[13]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDERDT-S = %8.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDERDT_S );

		// log CDERDT_L
		CDERDT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                  (gstResponse[EcuIdx].Inf[15] << 16) +
		                                  (gstResponse[EcuIdx].Inf[16] << 8) +
		                                   gstResponse[EcuIdx].Inf[17]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDERDT-L = %8.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDERDT_L );


		// log CIDT_A
		CIDT_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[18] << 8) +
		                                 gstResponse[EcuIdx].Inf[19]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CIDT-A = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CIDT_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( CIDT_A != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $48 CIDT-A must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log CIDT_S
		CIDT_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[20] << 8) +
		                                 gstResponse[EcuIdx].Inf[21]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CIDT-S = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CIDT_S );

		// log CIDT_L
		CIDT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[22] << 24) +
		                                (gstResponse[EcuIdx].Inf[23] << 16) +
		                                (gstResponse[EcuIdx].Inf[24] << 8) +
		                                 gstResponse[EcuIdx].Inf[25]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CIDT-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CIDT_L );
	}

	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;
	STATUS eRetCode = PASS;

	float  CDFC_A;
	float  CDFC_S;
	float  CDFC_L;

	float  CIFC_A;
	float  CIFC_S;
	float  CIFC_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $49 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $49 Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $49 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log CDFC_A
		CDFC_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 8) +
		                                 gstResponse[EcuIdx].Inf[3]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $49  CDFC-A = %12.1f l\n",
		      GetEcuId ( EcuIdx ),
		      CDFC_A );

		// log CDFC_S
		CDFC_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[4] << 8) +
		                                 gstResponse[EcuIdx].Inf[5]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $49  CDFC-S = %12.1f l\n",
		      GetEcuId ( EcuIdx ),
		      CDFC_S );

		// log CDFC_L
		CDFC_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                (gstResponse[EcuIdx].Inf[7] << 16) +
		                                (gstResponse[EcuIdx].Inf[8] << 8) +
		                                 gstResponse[EcuIdx].Inf[9]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $49  CDFC-L = %10.1f l\n",
		      GetEcuId ( EcuIdx ),
		      CDFC_L );


		// log CIFC_A
		CIFC_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 8) +
		                                 gstResponse[EcuIdx].Inf[11]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $49  CIFC-A = %12.1f l\n",
		      GetEcuId ( EcuIdx ),
		      CIFC_A );

		// log CIFC_S
		CIFC_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[12] << 8) +
		                                 gstResponse[EcuIdx].Inf[13]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $49  CIFC-S = %12.1f l\n",
		       GetEcuId ( EcuIdx ),
		       CIFC_S );

		// log CIFC_L
		CIFC_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                (gstResponse[EcuIdx].Inf[15] << 16) +
		                                (gstResponse[EcuIdx].Inf[16] << 8) +
		                                 gstResponse[EcuIdx].Inf[17]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $49  CIFC-L = %10.1f l\n",
		      GetEcuId ( EcuIdx ),
		      CIFC_L );
	}

	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;
	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;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $50 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 24 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 24 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $50 Data Size = %d (Must be 24 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $50 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log CDEOGE_A
		CDEOGE_A = (gstResponse[EcuIdx].Inf[2] << 8) +
		            gstResponse[EcuIdx].Inf[3];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  CDEOGE-A = %10lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDEOGE_A );

		// log CDEOGE_S
		CDEOGE_S = (gstResponse[EcuIdx].Inf[4] << 8) +
		            gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  CDEOGE-S = %10lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDEOGE_S );

		// log CDEOGE_L
		CDEOGE_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		           (gstResponse[EcuIdx].Inf[7] << 16) +
		           (gstResponse[EcuIdx].Inf[8] << 8) +
		            gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  CDEOGE-L = %10lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDEOGE_L );


		// log CDERGE_A
		CDERGE_A = (gstResponse[EcuIdx].Inf[10] << 8) +
		            gstResponse[EcuIdx].Inf[11];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  CDERGE-A = %10lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDERGE_A );

		// log CDERGE_S
		CDERGE_S = (gstResponse[EcuIdx].Inf[12] << 8) +
		            gstResponse[EcuIdx].Inf[13];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  CDERGE-S = %10lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDERGE_S );

		// log CDERGE_L
		CDERGE_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		           (gstResponse[EcuIdx].Inf[15] << 16) +
		           (gstResponse[EcuIdx].Inf[16] << 8) +
		            gstResponse[EcuIdx].Inf[17];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  CDERGE-L = %10lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      CDERGE_L );


		// log GE_A
		GE_A = (gstResponse[EcuIdx].Inf[18] << 8) +
		        gstResponse[EcuIdx].Inf[19];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  GE-A = %14lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      GE_A );
		if ( geTestPhase == eTestNoDTC && gTestSubsection == 17 )  // IF Test 5.17
		{
			if ( GE_A != 0 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $50 GE-A must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ) );
				eRetCode = FAIL;
			}
		}

		// log GE_S
		GE_S = (gstResponse[EcuIdx].Inf[20] << 8) +
		        gstResponse[EcuIdx].Inf[21];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  GE-S = %14lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      GE_S );

		// log GE_L
		GE_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		       (gstResponse[EcuIdx].Inf[23] << 16) +
		       (gstResponse[EcuIdx].Inf[24] << 8) +
		        gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $50  GE-L = %14lu kWh\n",
		      GetEcuId ( EcuIdx ),
		      GE_L );
	}

	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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $51 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 8 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 0x02 != 8 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $51 Data Size = %d (Must be 8 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $51 NODI = %d (Must be 1)\n",
			     GetEcuId ( EcuIdx ),
			     pInf->NODI );
			eRetCode = FAIL;
		}


		// log ISS_TIME_A
		ISS_TIME_A = ((gstResponse[EcuIdx].Inf[2] << 8) +
		               gstResponse[EcuIdx].Inf[3]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $51  ISS_TIME-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ISS_TIME_A );

		// log ISS_TIME_S
		ISS_TIME_S = ((gstResponse[EcuIdx].Inf[4] << 8) +
		               gstResponse[EcuIdx].Inf[5]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $51  ISS_TIME-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      ISS_TIME_S );

		// log ISS_TIME_L
		ISS_TIME_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		             (gstResponse[EcuIdx].Inf[7] << 16) +
		             (gstResponse[EcuIdx].Inf[8] << 8) +
		              gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $51  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;
	STATUS eRetCode = PASS;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $52 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 8 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 0x02 != 8 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $52 Data Size = %d (Must be 8 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $52 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log AES_CNT_A
		AES_CNT_A = ((gstResponse[EcuIdx].Inf[2] << 8) +
		              gstResponse[EcuIdx].Inf[3]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $52  AES_CNT-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AES_CNT_A );

		// log AES_CNT_S
		AES_CNT_S = ((gstResponse[EcuIdx].Inf[4] << 8) +
		              gstResponse[EcuIdx].Inf[5]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $52  AES_CNT-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      AES_CNT_S );

		// log AES_CNT_L
		AES_CNT_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		            (gstResponse[EcuIdx].Inf[7] << 16) +
		            (gstResponse[EcuIdx].Inf[8] << 8) +
		             gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $52  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;
	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;
	float         WHR_DT_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $53 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 16 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 16 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $53 Data Size = %d (Must be 16 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $53 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log WHR_TIME_A
		WHR_TIME_A = ((gstResponse[EcuIdx].Inf[2] << 8) +
		               gstResponse[EcuIdx].Inf[3]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $53  WHR_TIME-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      WHR_TIME_A );

		// log WHR_TIME_S
		WHR_TIME_S = ((gstResponse[EcuIdx].Inf[4] << 8) +
		               gstResponse[EcuIdx].Inf[5]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $53  WHR_TIME-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      WHR_TIME_S );

		// log WHR_TIME_L
		WHR_TIME_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		             (gstResponse[EcuIdx].Inf[7] << 16) +
		             (gstResponse[EcuIdx].Inf[8] << 8) +
		              gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $53  WHR_TIME-L = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		     WHR_TIME_L );


		// log WHR_DT_A
		WHR_DT_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 8) +
		                                   gstResponse[EcuIdx].Inf[11]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $53  WHR_DT-A = %12.3f km\n",
		     GetEcuId ( EcuIdx ),
		     WHR_DT_A );

		// log WHR_DT_S
		WHR_DT_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[12] << 8) +
		                                   gstResponse[EcuIdx].Inf[13]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $53  WHR_DT-S = %12.3f km\n",
		      GetEcuId ( EcuIdx ),
		      WHR_DT_S );

		// log WHR_DT_L
		WHR_DT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                  (gstResponse[EcuIdx].Inf[15] << 16) +
		                                  (gstResponse[EcuIdx].Inf[16] << 8) +
		                                   gstResponse[EcuIdx].Inf[17]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $53  WHR_DT-L = %12.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;
	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;
	float         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;
	float         AT2_DT_L;

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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 32 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 32 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 32 bytes!)\n",
			      pInf->ID,
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


		sprintf_s ( Number1String, sizeof ( Number1String ), "%d", 1 + ((pInf->ID - 0x54) * 2) );
		sprintf_s ( Number2String, sizeof ( Number2String ), "%d", 2 + ((pInf->ID - 0x54) * 2) );


		// log ATx_TIME_A
		AT1_TIME_A = ((gstResponse[EcuIdx].Inf[2] << 8) +
		               gstResponse[EcuIdx].Inf[3]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_TIME-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number1String,
		     AT1_TIME_A );

		// log ATx_TIME_S
		AT1_TIME_S = ((gstResponse[EcuIdx].Inf[4] << 8) +
		               gstResponse[EcuIdx].Inf[5]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_TIME-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number1String,
		      AT1_TIME_S );

		// log ATx_TIME_L
		AT1_TIME_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		             (gstResponse[EcuIdx].Inf[7] << 16) +
		             (gstResponse[EcuIdx].Inf[8] << 8) +
		              gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_TIME-L = %10lu sec\n",
		     GetEcuId ( EcuIdx ),
		     pInf->ID,
		     Number1String,
		     AT1_TIME_L );


		// log ATx_DT_A
		AT1_DT_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 8) +
		                                   gstResponse[EcuIdx].Inf[11]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_DT-A = %12.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number1String,
		      AT1_DT_A );

		// log ATx_DT_S
		AT1_DT_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[12] << 8) +
		                                   gstResponse[EcuIdx].Inf[13]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_DT-S = %12.3f km\n",
		       GetEcuId ( EcuIdx ),
		       pInf->ID,
		       Number1String,
		       AT1_DT_S );

		// log ATx_DT_L
		AT1_DT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                  (gstResponse[EcuIdx].Inf[15] << 16) +
		                                  (gstResponse[EcuIdx].Inf[16] << 8) +
		                                   gstResponse[EcuIdx].Inf[17]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_DT-L = %12.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number1String,
		      AT1_DT_L );


		// log ATy_TIME_A
		AT2_TIME_A = ((gstResponse[EcuIdx].Inf[18] << 8) +
		               gstResponse[EcuIdx].Inf[19]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_TIME-A = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number2String,
		      AT2_TIME_A );

		// log ATy_TIME_S
		AT2_TIME_S = ((gstResponse[EcuIdx].Inf[20] << 8) +
		               gstResponse[EcuIdx].Inf[21]) * 10;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_TIME-S = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number2String,
		      AT2_TIME_S );

		// log ATy_TIME_L
		AT2_TIME_L = (gstResponse[EcuIdx].Inf[22] << 24) +
		             (gstResponse[EcuIdx].Inf[23] << 16) +
		             (gstResponse[EcuIdx].Inf[24] << 8) +
		              gstResponse[EcuIdx].Inf[25];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_TIME-L = %10lu sec\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number2String,
		      AT2_TIME_L );


		// log ATy_DT_A
		AT2_DT_A = (float)((unsigned int)((gstResponse[EcuIdx].Inf[26] << 8) +
		                                   gstResponse[EcuIdx].Inf[27]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_DT-A = %12.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number2String,
		      AT2_DT_A );

		// log ATy_DT_S
		AT2_DT_S = (float)((unsigned int)((gstResponse[EcuIdx].Inf[28] << 8) +
		                                   gstResponse[EcuIdx].Inf[29]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_DT-S = %12.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      Number2String,
		      AT2_DT_S );

		// log ATy_DT_L
		AT2_DT_L = (float)((unsigned int)((gstResponse[EcuIdx].Inf[30] << 24) +
		                                  (gstResponse[EcuIdx].Inf[31] << 16) +
		                                  (gstResponse[EcuIdx].Inf[32] << 8) +
		                                   gstResponse[EcuIdx].Inf[33]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $%02X  AT%s_DT-L = %12.3f km\n",
		      GetEcuId ( EcuIdx ),
		      pInf->ID,
		      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;
	STATUS eRetCode = PASS;

	float  Bin[17];
	float  Bin_Sum = 0;

	unsigned short BinIndex;

	float *pArchive = NULL;

	char   NameString[10];
	char   CompareNameString[10];
	float  Multiplier = 0.0;
#define NOX_TXT_MAX 9


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 68 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 0x02 != 68 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 68 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


		switch ( pInf->ID )
		{
			case 0x61:
			{
				strcpy_s( NameString, NOX_TXT_MAX, "NOxEOB-A" );
				Multiplier = (float).000005;
				pArchive = &Test_5_17_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 = (float).000005;
				pArchive = &Test_5_17_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 = (float).001;
				pArchive = &Test_5_17_Inf[EcuIdx].INF61_NOxEOB_A[0];
			}
			break;

			case 0x62:
			{
				strcpy_s( NameString, NOX_TXT_MAX, "NOxTPB-A" );
				Multiplier = (float).000002;
				pArchive = &Test_5_17_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 = (float).000002;
				pArchive = &Test_5_17_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 = (float).001;
				pArchive = &Test_5_17_Inf[EcuIdx].INF62_NOxTPB_A[0];
			}
			break;
		}


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 4)] << 24) +
			                                       (gstResponse[EcuIdx].Inf[3 + (BinIndex * 4)] << 16) +
			                                       (gstResponse[EcuIdx].Inf[4 + (BinIndex * 4)] << 8) +
			                                        gstResponse[EcuIdx].Inf[5 + (BinIndex * 4)]) * Multiplier);
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X  %s[bin%d] = %11.7f kg\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      NameString,
			      BinIndex+1,
			      Bin[BinIndex] );

			// Save -A values for later
			if ( pInf->ID == 0x61 || pInf->ID == 0x62 )
			{
				pArchive[BinIndex] = Bin[BinIndex];
			}

			// -S and -L values must be greater than -A value
			else if ( (pInf->ID == 0x6D || pInf->ID == 0x6E) &&
			          Bin[BinIndex] != 0 &&
			          Bin[BinIndex] < pArchive[BinIndex] )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X %s[bin%d] must be greater than %s[bin%d] (%.7f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      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 $03 or SID $07 &&
		// 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 $%02X the sum of %s[bin2] through %s[bin14] = %.7f (Must be equal to %s[bin1] (%.7f +-1%%))\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      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;
	STATUS eRetCode = PASS;

	float  Bin[17];
	float  Bin_Sum = 0;

	unsigned short BinIndex;

	char   NameString[10];
	float  Multiplier;
#define EOEB_TXT_NAX 9


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		     GetEcuId ( EcuIdx ),
		     gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// INF $63 and $69 must contain 34 bytes of data
		if ( (pInf->ID == 0x63 || pInf->ID == 0x69) &&
		     gstResponse[EcuIdx].InfSize - 2 != 34 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 34 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}
		// INF $63 and $69 must contain 68 bytes of data
		else if ( (pInf->ID == 0x6F || pInf->ID == 0x73) &&
		          gstResponse[EcuIdx].InfSize - 2 != 68 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 68 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			     (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


		switch ( pInf->ID )
		{
			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 = (float).001;


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			if ( pInf->ID == 0x6F || pInf->ID == 0x73 )
			{
				Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 4)] << 24) +
				                                       (gstResponse[EcuIdx].Inf[3 + (BinIndex * 4)] << 16) +
				                                       (gstResponse[EcuIdx].Inf[4 + (BinIndex * 4)] << 8) +
				                                        gstResponse[EcuIdx].Inf[5 + (BinIndex * 4)]) * Multiplier);
			}
			else
			{
				Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 2)] << 8) +
				                                        gstResponse[EcuIdx].Inf[3 + (BinIndex * 2)]) * Multiplier);
			}

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

			// Save -A values for later
			if ( pInf->ID == 0x63 )
			{
				Test_5_17_Inf[EcuIdx].INF63_EOEB_A[BinIndex] = Bin[BinIndex];
			}

			// -S and -L values must be greater than -A values
			else if ( pInf->ID == 0x6F &&
			          Bin[BinIndex] != 0 &&
			          Bin[BinIndex] < Test_5_17_Inf[EcuIdx].INF63_EOEB_A[BinIndex] )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X %s[bin%d] must be greater than EOEB-A[bin%d] (%.6f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      NameString,
				      BinIndex+1,
				      BinIndex+1,
				      Test_5_17_Inf[EcuIdx].INF63_EOEB_A[BinIndex] );
				eRetCode = FAIL;
			}


			// if INF 63, 69, or 6f, collect the sum of [bin2] through [bin14]
			if ( pInf->ID == 0x63 ||
			     pInf->ID == 0x69 ||
			     pInf->ID == 0x6F )
			{
				if ( BinIndex >= 1 && BinIndex <= 13 )
				{
					Bin_Sum += Bin[BinIndex];
				}
			}
		}

		// if INF 63, 69, or 6f, compare [bin1] against sum of [bin2] through [bin14]
		if ( pInf->ID == 0x63 ||
		     pInf->ID == 0x69 ||
		     pInf->ID == 0x6F )
		{
			// no nox DTCs from SID $03 or SID $07 &&
			// 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 $%02X the sum of %s[bin2] through %s[bin14] = %.3f (Must be equal to %s[bin1] (%.3f +-1%%))\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      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;
	STATUS eRetCode = PASS;

	float  Bin[17];
	float  Bin_Sum = 0;

	unsigned short BinIndex;

	char   NameString[10];
	float  Multiplier = 0;
#define DTB_TXT_MAX 8


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// INF $64 and $6A must contain 34 bytes of data
		if ( (pInf->ID == 0x64 || pInf->ID == 0x6A) &&
		     gstResponse[EcuIdx].InfSize - 0x02 != 34 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 34 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}
		// INF $70 and $74 must contain 68 bytes of data
		else if ( (pInf->ID == 0x70 || pInf->ID == 0x74) &&
		          gstResponse[EcuIdx].InfSize - 0x02 != 68 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 68 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 0x02) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


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


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			if ( pInf->ID == 0x70 || pInf->ID == 0x74 )
			{
				Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 4)] << 24) +
				                                       (gstResponse[EcuIdx].Inf[3 + (BinIndex * 4)] << 16) +
				                                       (gstResponse[EcuIdx].Inf[4 + (BinIndex * 4)] << 8) +
				                                        gstResponse[EcuIdx].Inf[5 + (BinIndex * 4)]) * Multiplier);
			}
			else
			{
				Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 2)] << 8) +
				                                        gstResponse[EcuIdx].Inf[3 + (BinIndex * 2)]) * Multiplier);
			}

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

			// Save -A values for later
			if ( pInf->ID == 0x64 )
			{
				Test_5_17_Inf[EcuIdx].INF64_DTB_A[BinIndex] = Bin[BinIndex];
			}

			// -S and -L values must be greater than -A values
			else if ( pInf->ID == 0x70 &&
			          Bin[BinIndex] != 0 &&
			          Bin[BinIndex] < Test_5_17_Inf[EcuIdx].INF64_DTB_A[BinIndex] )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X %s[bin%d] must be greater than DTB-A[bin%d] (%.3f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      NameString,
				      BinIndex+1,
				      BinIndex+1,
				      Test_5_17_Inf[EcuIdx].INF64_DTB_A[BinIndex] );
				eRetCode = FAIL;
			}


			// if INF 64, 6A, 70, collect the sum of [bin2] through [bin14]
			if ( pInf->ID == 0x64 ||
			     pInf->ID == 0x6A ||
			     pInf->ID == 0x70 )
			{
				if ( BinIndex >= 1 && BinIndex <= 13 )
				{
					Bin_Sum += Bin[BinIndex];
				}
			}
		}

		// if INF 64, 6A, 70, compare [bin1] against sum of [bin2] through [bin14]
		if ( pInf->ID == 0x64 ||
		     pInf->ID == 0x6A ||
		     pInf->ID == 0x70 )
		{
			// no nox DTCs from SID $03 or SID $07 &&
			// 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 $%02X the sum of %s[bin2] through %s[bin14] = %.3f (Must be equal to %s[bin1] (%.3f +-1%%))\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      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;
	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


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// INF $65 and $6B must contain 34 bytes of data
		if ( (pInf->ID == 0x65 || pInf->ID == 0x6B) &&
		     gstResponse[EcuIdx].InfSize - 2 != 34 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 34 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}
		// INF $71 and $75 must contain 68 bytes of data
		else if ( (pInf->ID == 0x71 || pInf->ID == 0x75) &&
		          gstResponse[EcuIdx].InfSize - 2 != 68 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 68 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


		switch ( pInf->ID )
		{
			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->ID == 0x71 || pInf->ID == 0x75 )
			{
				Bin[BinIndex] = ((gstResponse[EcuIdx].Inf[2 + (BinIndex * 4)] << 24) +
				                 (gstResponse[EcuIdx].Inf[3 + (BinIndex * 4)] << 16) +
				                 (gstResponse[EcuIdx].Inf[4 + (BinIndex * 4)] << 8) +
				                  gstResponse[EcuIdx].Inf[5 + (BinIndex * 4)]) * Multiplier;
			}
			else
			{
				Bin[BinIndex] = ((gstResponse[EcuIdx].Inf[2 + (BinIndex * 2)] << 8) +
				                  gstResponse[EcuIdx].Inf[3 + (BinIndex * 2)]) * Multiplier;
			}

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

	}

	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;
	STATUS eRetCode = PASS;

	float  Bin[17];
	float  Bin_Sum = 0;

	unsigned short BinIndex;

	char   NameString[10];
	float  Multiplier;
#define FCB_TXT_MAX 8


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $%02X data\n",
		      GetEcuId ( EcuIdx ),
		      gstResponse[EcuIdx].Inf[0] );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// INF $66 and $6C must contain 34 bytes of data
		if ( (pInf->ID == 0x66 || pInf->ID == 0x6C) &&
		     gstResponse[EcuIdx].InfSize - 2 != 34 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 34 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}
		// INF $72 and $76 must contain 68 bytes of data
		else if ( (pInf->ID == 0x72 || pInf->ID == 0x76) &&
		          gstResponse[EcuIdx].InfSize - 2 != 68 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X Data Size = %d (Must be 68 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}


		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->NODI );
			eRetCode = FAIL;
		}


		switch ( pInf->ID )
		{
			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 = (float).5;


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			if ( pInf->ID == 0x72 || pInf->ID == 0x76 )
			{
				Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 4)] << 24) +
				                                       (gstResponse[EcuIdx].Inf[3 + (BinIndex * 4)] << 16) +
				                                       (gstResponse[EcuIdx].Inf[4 + (BinIndex * 4)] << 8) +
				                                        gstResponse[EcuIdx].Inf[5 + (BinIndex * 4)]) * Multiplier);
			}
			else
			{
				Bin[BinIndex] = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2 + (BinIndex * 2)] << 8) +
				                                        gstResponse[EcuIdx].Inf[3 + (BinIndex * 2)]) * Multiplier);
			}

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

	}

	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;
	STATUS eRetCode = PASS;

	unsigned long NOREDUCT_TIME_L;
	unsigned long COLDEXH_TIME_L;

	float         REGEN1_SDIST;
	float         REGEN1_FDIST;
	float         REGEN2_SDIST;
	float         REGEN2_FDIST;
	float         REGEN3_SDIST;
	float         REGEN3_FDIST;

	unsigned long REGEN_CNTL_L;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $77 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 36 bytes of data
		if ( gstResponse[EcuIdx].InfSize - 2 != 36 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $77 Data Size = %d (Must be 36 bytes!)\n",
			       GetEcuId ( EcuIdx ),
			       (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $77 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}

		// log NOREDUCT_TIME_L
		NOREDUCT_TIME_L = (gstResponse[EcuIdx].Inf[2] << 24) +
		                  (gstResponse[EcuIdx].Inf[3] << 16) +
		                  (gstResponse[EcuIdx].Inf[4] << 8) +
		                   gstResponse[EcuIdx].Inf[5];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  NOREDUCT_TIME-L = %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      NOREDUCT_TIME_L );

		// log COLDEXH_TIME_L
		COLDEXH_TIME_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		                 (gstResponse[EcuIdx].Inf[7] << 16) +
		                 (gstResponse[EcuIdx].Inf[8] << 8) +
		                  gstResponse[EcuIdx].Inf[9];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  COLDEXH_TIME-L =  %11lu sec\n",
		      GetEcuId ( EcuIdx ),
		      COLDEXH_TIME_L );


		// log REGEN1_SDIST
		REGEN1_SDIST = (float)((unsigned int)((gstResponse[EcuIdx].Inf[10] << 24) +
		                                      (gstResponse[EcuIdx].Inf[11] << 16) +
		                                      (gstResponse[EcuIdx].Inf[12] << 8) +
		                                       gstResponse[EcuIdx].Inf[13]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  REGEN1_SDIST-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN1_SDIST );

		// log REGEN1_FDIST
		REGEN1_FDIST = (float)((unsigned int)((gstResponse[EcuIdx].Inf[14] << 24) +
		                                      (gstResponse[EcuIdx].Inf[15] << 16) +
		                                      (gstResponse[EcuIdx].Inf[16] << 8) +
		                                       gstResponse[EcuIdx].Inf[17]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  REGEN1_FDIST-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN1_FDIST );


		// log REGEN2_SDIST
		REGEN2_SDIST = (float)((unsigned int)((gstResponse[EcuIdx].Inf[18] << 24) +
		                                      (gstResponse[EcuIdx].Inf[19] << 16) +
		                                      (gstResponse[EcuIdx].Inf[20] << 8) +
		                                       gstResponse[EcuIdx].Inf[21]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  REGEN2_SDIST-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN2_SDIST );

		// log REGEN2_FDIST
		REGEN2_FDIST = (float)((unsigned int)((gstResponse[EcuIdx].Inf[22] << 24) +
		                                      (gstResponse[EcuIdx].Inf[23] << 16) +
		                                      (gstResponse[EcuIdx].Inf[24] << 8) +
		                                       gstResponse[EcuIdx].Inf[25]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  REGEN2_FDIST-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN2_FDIST );


		// log REGEN3_SDIST
		REGEN3_SDIST = (float)((unsigned int)((gstResponse[EcuIdx].Inf[26] << 24) +
		                                      (gstResponse[EcuIdx].Inf[27] << 16) +
		                                      (gstResponse[EcuIdx].Inf[28] << 8) +
		                                       gstResponse[EcuIdx].Inf[29]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  REGEN3_SDIST-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN3_SDIST );

		// log REGEN3_FDIST
		REGEN3_FDIST = (float)((unsigned int)((gstResponse[EcuIdx].Inf[30] << 24) +
		                                      (gstResponse[EcuIdx].Inf[31] << 16) +
		                                      (gstResponse[EcuIdx].Inf[32] << 8) +
		                                       gstResponse[EcuIdx].Inf[33]) * .005);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  REGEN3_FDIST-L = %11.3f km\n",
		      GetEcuId ( EcuIdx ),
		      REGEN3_FDIST );


		// log REGEN_CNTL_L
		REGEN_CNTL_L = (gstResponse[EcuIdx].Inf[34] << 24) +
		               (gstResponse[EcuIdx].Inf[35] << 16) +
		               (gstResponse[EcuIdx].Inf[36] << 8) +
		                gstResponse[EcuIdx].Inf[37];
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $77  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;
	STATUS eRetCode = PASS;

	float  PWR_RATING;
	float  RPM_RATING;


	if ( gstResponse[EcuIdx].InfSize == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  No INF $78 data\n",
		      GetEcuId ( EcuIdx ) );
		return FAIL;
	}

	pInf = (INF *)&gstResponse[EcuIdx].Inf[0];

	if ( gstProtocolList[gProtocolIdx].eProtocol == ISO15765 )
	{
		// must contain 4 bytes of data
		// Don't include SID or INF ID in INFSIZE
		if ( gstResponse[EcuIdx].InfSize - 2 != 4 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $78 Data Size = %d (Must be 4 bytes!)\n",
			      GetEcuId ( EcuIdx ),
			      (gstResponse[EcuIdx].InfSize - 2) );
			return FAIL;
		}

		// NODI must equal $01
		if ( pInf->NODI != 0x01 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $78 NODI = %d (Must be 1)\n",
			      GetEcuId ( EcuIdx ),
			      pInf->NODI );
			eRetCode = FAIL;
		}


		// log PWR_RATING
		PWR_RATING = (float)((unsigned int)((gstResponse[EcuIdx].Inf[2] << 8) +
		                                     gstResponse[EcuIdx].Inf[3]) * .5);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $78  PWR_RATING = %6.1f kW\n",
		      GetEcuId ( EcuIdx ),
		      PWR_RATING );


		// log RPM_RATING
		RPM_RATING = (float)((unsigned int)((gstResponse[EcuIdx].Inf[4] << 8) +
		                                     gstResponse[EcuIdx].Inf[5]) * .25);
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $78  RPM_RATING = %7.2f RPM\n",
		      GetEcuId ( EcuIdx ),
		      RPM_RATING );


		if ( RPM_RATING < 300.00 || RPM_RATING > 5000.00 )
		{
			if ( !(gbDiesel &&
			       RPM_RATING >= 1.00 && RPM_RATING <= 299.00) )
			{
				if ( PHEV &&
				     RPM_RATING >= 1.00 && RPM_RATING <= 299.00 )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $78 RPM_RATING Must be greater than 300 and less than 5000\n",
					      GetEcuId ( EcuIdx ) );
				}
				else
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $78 RPM_RATING Must be greater than 300 and less than 5000\n",
					      GetEcuId ( EcuIdx ) );
					eRetCode = FAIL;
				}
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyINFChange
**
**  Purpose:
**
*******************************************************************************/
STATUS VerifyINFChange ( void )
{
	REQ_MSG       stReqMsg;
	INF          *pInf;
	BYTE          EcuIdx;     // ECU Index
	BYTE          IdIdx;      // INF ID index
	BYTE          MaxId;        // Maximum INF ID

	BOOL          bTestFailed = FALSE;
	unsigned long InitialFailureCount = 0;


	InitialFailureCount = GetFailureCount ( );


	// Request SID 9 support data
	if ( RequestIDSupportData ( INFREQUEST, TRUE ) != PASS )
	{
		return FAIL;
	}


	if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 22 )  // IF Test 9.22
	{
		if ( gModelYear >= 2022 &&
		     gstUserInput.eVehicleType == HD )
		{
			MaxId = 0x44;
		}
		else
		{
			MaxId = 0x19;
		}
	}
	else
	{
		MaxId = 0x29;
	}


	// For each INF group
	// Verify that all SID 9 INF data is valid
	// Request user supplied expected OBD ECU responses
	for ( IdIdx = 0x16;
	      IdIdx <= MaxId;
	      IdIdx++ )
	{
		// If INF is supported by any ECU, request it
		if ( IsIDSupported ( ALLECUS, INFREQUEST, IdIdx ) == TRUE  )
		{
			stReqMsg.SID    = 0x09;
			stReqMsg.NumIds = 1;
			stReqMsg.ID[0]  = (BYTE)IdIdx;
			if ( RequestSid( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
			{
				bTestFailed = TRUE;
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "INF $%02X request\n",
				      IdIdx );

				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
				}


				// 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 $%02X data\n",
					      GetEcuId ( EcuIdx ),
					      IdIdx );
					continue;  // just go to the next itteration of the ECU for loop
				}

				// Check various INF values for validity
				switch ( pInf->ID )
				{
					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->ID)
			} // 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 )
				{
					if ( IdIdx <= 0x19 )
					{
						if ( gModelYear == 2019 || gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%02X 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 $%02X is not supported by any ECU! (Required for MY 2019 and later Light Duty vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}
					else if ( IdIdx >= 0x1A && IdIdx <= 0x1C &&
					          gstUserInput.ePwrTrnType == PHEV )
					{
						if ( gModelYear == 2019 || gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%02X 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 $%02X 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_WITH_IUMPR || gstUserInput.eComplianceType == EOBD_NO_IUMPR) &&
				          gstUserInput.eVehicleType == LD )
				{
					if ( IdIdx == 0x17 )
					{
						if ( gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%02X 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 $%02X is not supported by any ECU! (Required for MY 2020 and later Light Duty vehicles)\n",
							      IdIdx );
							bTestFailed = TRUE;
						}
					}

					else if ( IdIdx >= 0x1A && IdIdx <= 0x1C &&
					          gstUserInput.ePwrTrnType == PHEV )
					{
						if ( gModelYear == 2020 )
						{
							Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "INF $%02X 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 $%02X 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 >= 0x41 && IdIdx <= 0x44 )
				{
					if ( gModelYear == 2022 || gModelYear == 2023 )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "INF $%02X 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 $%02X is not supported by any ECU! (Required for MY 2022 and later Heavy Duty vehicles)\n",
						      IdIdx );
						bTestFailed = TRUE;
					}
				}
			}
		}


		if ( IdIdx == 0x19 && MaxId == 0x44 )
		{
			IdIdx = 0x40;
		}
	} // 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;
	}
}
