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

	double        INF17_DT_R;
	double        INF17_DT_L;

	double        INF17_FC_R;
	double        INF17_FC_L;

	unsigned long INF19_PSA_R;
	unsigned long INF19_PSA_L;

	unsigned long INF19_IPSA_L;

	unsigned long INF19_CPSA_R;
	unsigned long INF19_CPSA_L;

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

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

	double        INF43_DT_S;
	double        INF43_EOE_S;
	double        INF43_VFC_S;

	double        INF44_EFC_S;

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

	double        INF61_NOxEOB_A[17];

	double        INF62_NOxTPB_A[17];

	double        INF63_EOEB_A[17];

	double        INF64_DTB_A[17];

	double        INF65_ERTB_A[17];

	double        INF66_FCB_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

	BYTE  InfSupportCountList[] =
	{0x02,0x04,0x06,0x08,0x0A,0x0B,0x0D,
	 0x12,0x13,0x14,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,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[0xFF];

	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],
		      gUserNumOfECUsReprgm );
		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-$19 are supported by MY 2019 and later Light and Medium Duty OBDII vehicles
	if ( (gstUserInput.eVehicleType == LD || gstUserInput.eVehicleType == MD) &&
	      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;
			}
		}
	}  // end verify INF $13, $16-$19 support

	// Verify that INFs $1A-$1C are supported by MY 2019 and later Light Duty PHEV OBDII vehicles
	if ( (gstUserInput.eVehicleType == LD || gstUserInput.eVehicleType == MD) &&
	     gstUserInput.ePwrTrnType == PHEV &&
	     gstUserInput.eComplianceType == US_OBDII &&
	     gModelYear >= 2019)
	{
		// Verify that INF $1A is supported for MY 2019 and later Light Duty PHEV vehicles
		if ( InfSupportCount[0x1A] == 0 )
		{
			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 )
		{
			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 )
		{
			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;
			}
		}
	}  // end verify INF $1A-$1C support


	// 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;
			}
		}
	}  // end verify INF $17, $1A-$1C support


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

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

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

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

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


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


	// For each INF group
	// Verify that all SID 9 INF data is valid
	// Request user supplied expected OBD ECU responses
	for ( IdIdx  = 0x01;
	      IdIdx <= 0xFF;
	      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 ||
						      gstUserInput.eComplianceType == OBDBr_WITH_IUMPR || gstUserInput.eComplianceType == OBDBr_NO_IUMPR ) )
						{
							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;
				}
			} // 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 && gVINModelYear != 2031) ||
	      (gVINString[9] == '2' && gVINModelYear != 2002 && gVINModelYear != 2032) ||
	      (gVINString[9] == '3' && gVINModelYear != 2003 && gVINModelYear != 2033) ||
	      (gVINString[9] == '4' && gVINModelYear != 2004 && gVINModelYear != 2034) ||
	      (gVINString[9] == '5' && gVINModelYear != 2005 && gVINModelYear != 2035) ||
	      (gVINString[9] == '6' && gVINModelYear != 2006 && gVINModelYear != 2036) ||
	      (gVINString[9] == '7' && gVINModelYear != 2007 && gVINModelYear != 2037) ||
	      (gVINString[9] == '8' && gVINModelYear != 2008 && gVINModelYear != 2038) ||
	      (gVINString[9] == '9' && gVINModelYear != 2009 && gVINModelYear != 2039) ||
	      (gVINString[9] == 'A' && gVINModelYear != 2010) ||
	      (gVINString[9] == 'B' && gVINModelYear != 1981 && gVINModelYear != 2011) ||
	      (gVINString[9] == 'C' && gVINModelYear != 1982 && gVINModelYear != 2012) ||
	      (gVINString[9] == 'D' && gVINModelYear != 1983 && gVINModelYear != 2013) ||
	      (gVINString[9] == 'E' && gVINModelYear != 1984 && gVINModelYear != 2014) ||
	      (gVINString[9] == 'F' && gVINModelYear != 1985 && gVINModelYear != 2015) ||
	      (gVINString[9] == 'G' && gVINModelYear != 1986 && gVINModelYear != 2016) ||
	      (gVINString[9] == 'H' && gVINModelYear != 1987 && gVINModelYear != 2017) ||
	      (gVINString[9] == 'J' && gVINModelYear != 1988 && gVINModelYear != 2018) ||
	      (gVINString[9] == 'K' && gVINModelYear != 1989 && gVINModelYear != 2019) ||
	      (gVINString[9] == 'L' && gVINModelYear != 1990 && gVINModelYear != 2020) ||
	      (gVINString[9] == 'M' && gVINModelYear != 1991 && gVINModelYear != 2021) ||
	      (gVINString[9] == 'N' && gVINModelYear != 1992 && gVINModelYear != 2022) ||
	      (gVINString[9] == 'P' && gVINModelYear != 1993 && gVINModelYear != 2023) ||
	      (gVINString[9] == 'R' && gVINModelYear != 1994 && gVINModelYear != 2024) ||
	      (gVINString[9] == 'S' && gVINModelYear != 1995 && gVINModelYear != 2025) ||
	      (gVINString[9] == 'T' && gVINModelYear != 1996 && gVINModelYear != 2026) ||
	      (gVINString[9] == 'V' && gVINModelYear != 1997 && gVINModelYear != 2027) ||
	      (gVINString[9] == 'W' && gVINModelYear != 1998 && gVINModelYear != 2028) ||
	      (gVINString[9] == 'X' && gVINModelYear != 1999 && gVINModelYear != 2029) ||
	      (gVINString[9] == 'Y' && gVINModelYear != 2000 && gVINModelYear != 2030)) &&
	     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  VIN year character (%c) does not match user entry (%d)\n",
		      GetEcuId ( EcuIdx ),
		      gVINString[9],
		      gVINModelYear );
		eRetCode = FAIL;
	}

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

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

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

STATUS VerifyECUNameData ( BYTE EcuIdx )
{
	INF            *pInf;

	unsigned int    ByteIdx;
	unsigned int    MsgIndex;        // multi-part message index
	char            Buffer[21];
	char            Buffer2[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;


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

	// 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 && gModelYear != 2031) ||
		     (TG_EFN[0] == '2' && gModelYear != 2002 && gModelYear != 2032) ||
		     (TG_EFN[0] == '3' && gModelYear != 2003 && gModelYear != 2033) ||
		     (TG_EFN[0] == '4' && gModelYear != 2004 && gModelYear != 2034) ||
		     (TG_EFN[0] == '5' && gModelYear != 2005 && gModelYear != 2035) ||
		     (TG_EFN[0] == '6' && gModelYear != 2006 && gModelYear != 2036) ||
		     (TG_EFN[0] == '7' && gModelYear != 2007 && gModelYear != 2037) ||
		     (TG_EFN[0] == '8' && gModelYear != 2008 && gModelYear != 2038) ||
		     (TG_EFN[0] == '9' && gModelYear != 2009 && gModelYear != 2039) ||
		     (TG_EFN[0] == 'A' && gModelYear != 2010) ||
		     (TG_EFN[0] == 'B' && gModelYear != 1981 && gModelYear != 2011) ||
		     (TG_EFN[0] == 'C' && gModelYear != 1982 && gModelYear != 2012) ||
		     (TG_EFN[0] == 'D' && gModelYear != 1983 && gModelYear != 2013) ||
		     (TG_EFN[0] == 'E' && gModelYear != 1984 && gModelYear != 2014) ||
		     (TG_EFN[0] == 'F' && gModelYear != 1985 && gModelYear != 2015) ||
		     (TG_EFN[0] == 'G' && gModelYear != 1986 && gModelYear != 2016) ||
		     (TG_EFN[0] == 'H' && gModelYear != 1987 && gModelYear != 2017) ||
		     (TG_EFN[0] == 'J' && gModelYear != 1988 && gModelYear != 2018) ||
		     (TG_EFN[0] == 'K' && gModelYear != 1989 && gModelYear != 2019) ||
		     (TG_EFN[0] == 'L' && gModelYear != 1990 && gModelYear != 2020) ||
		     (TG_EFN[0] == 'M' && gModelYear != 1991 && gModelYear != 2021) ||
		     (TG_EFN[0] == 'N' && gModelYear != 1992 && gModelYear != 2022) ||
		     (TG_EFN[0] == 'P' && gModelYear != 1993 && gModelYear != 2023) ||
		     (TG_EFN[0] == 'R' && gModelYear != 1994 && gModelYear != 2024) ||
		     (TG_EFN[0] == 'S' && gModelYear != 1995 && gModelYear != 2025) ||
		     (TG_EFN[0] == 'T' && gModelYear != 1996 && gModelYear != 2026) ||
		     (TG_EFN[0] == 'V' && gModelYear != 1997 && gModelYear != 2027) ||
		     (TG_EFN[0] == 'W' && gModelYear != 1998 && gModelYear != 2028) ||
		     (TG_EFN[0] == 'X' && gModelYear != 1999 && gModelYear != 2029) ||
		     (TG_EFN[0] == 'Y' && gModelYear != 2000 && gModelYear != 2030) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $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 ( gVINModelYear == gModelYear &&
		     TG_EFN[0] != gVINString[9] &&
		     (gstUserInput.eVehicleType == LD || gstUserInput.eVehicleType == MD) )
		{
			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];

		// if it's the max value, not available
		if ( IGNCNTR_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  IGNCNTR-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];

		// if it's the max value, not available
		if ( IGNCNTR_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  IGNCNTR-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];

		// if it's the max value, not available
		if ( FEOCNTR_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  FEOCNTR-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
				{
					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];

		// if it's the max value, not available
		if ( FEOCNTR_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  FEOCNTR-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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-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_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];

		// if it's the max value, not available
		if ( ERT_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  ERT-R     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
				{
					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];

		// if it's the max value, not available
		if ( ERT_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  ERT-L     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];

		// if it's the max value, not available
		if ( IERT_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  IERT-R    not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
				{
					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];

		// if it's the max value, not available
		if ( IERT_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $16  IERT-L    not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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;

	double  DT_R;
	double  DT_L;
	double  FC_R;
	double  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 = (double)((unsigned long)((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 available
		if ( DT_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  DT-R      not available\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 = (double)((unsigned long)((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 available
		if ( DT_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  DT-L      not available\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 = (double)((unsigned long)((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 available
		if ( FC_R == 42949672.95 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  FC-R      not available\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 = (double)((unsigned long)((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 available
		if ( FC_L == 42949672.95 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $17  FC-L     not available\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;
	double EOE_R;
	double 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];

		// if it's the max value, not available
		if ( PKE_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18  PKE-R     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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
			      ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23)) &&  // OR Test 9.23
			     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;
			}
		}

		// log PKE_L
		PKE_L = (gstResponse[EcuIdx].Inf[6] << 24) +
		        (gstResponse[EcuIdx].Inf[7] << 16) +
		        (gstResponse[EcuIdx].Inf[8] << 8) +
		         gstResponse[EcuIdx].Inf[9];

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


		// log EOE_R
		EOE_R = (double)((unsigned long)((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 available
		if ( EOE_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18  EOE-R     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18  EOE-R     = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      EOE_R );

			if ( geTestPhase == eTestNoFault3DriveCycle && gTestSubsection == 23 &&  // IF Test 9.23
			          EOE_R != 0 )
			{
				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 = (double)((unsigned long)((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 available
		if ( EOE_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18  EOE-L     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $18  EOE-L     = %.1f kWh\n",
			      GetEcuId ( EcuIdx ),
			      EOE_L );
		}
	}

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

		// if it's the max value, not available
		if ( PSA_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19  PSA-R     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];

		// if it's the max value, not available
		if ( PSA_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19  PSA-L     not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];

		// if it's the max value, not available
		if ( IPSA_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19  IPSA-R    not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];

		// if it's the max value, not available
		if ( IPSA_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19  IPSA-L    not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];

		// if it's the max value, not available
		if ( CPSA_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19  CPSA-R    not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];

		// if it's the max value, not available
		if ( CPSA_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $19  CPSA-L    not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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;

	double  CDEODT_R;
	double  CDEODT_L;
	double  CDERDT_R;
	double  CDERDT_L;
	double  CIDT_R;
	double  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 = (double)((unsigned long)((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 available
		if ( CDEODT_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDEODT-R  not available\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 = (double)((unsigned long)((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 available
		if ( CDEODT_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDEODT-L  not available\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 = (double)((unsigned long)((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 available
		if ( CDERDT_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDERDT-R  not available\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 = (double)((unsigned long)((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 available
		if ( CDERDT_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CDERDT-L  not available\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 = (double)((unsigned long)((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 available
		if ( CIDT_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CIDT-R    not available\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 = (double)((unsigned long)((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 available
		if ( CIDT_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1A  CIDT-L    not available\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;

	double  CDFC_R;
	double  CDFC_L;
	double  CIFC_R;
	double  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 = (double)((unsigned long)((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 available
		if ( CDFC_R == 42949672.95 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CDFC-R    not available\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 = (double)((unsigned long)((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 available
		if ( CDFC_L == 42949672.95 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CDFC-L    not available\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 = (double)((unsigned long)((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 available
		if ( CIFC_R == 42949672.95 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CIFC-R    not available\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 = (double)((unsigned long)((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 available
		if ( CIFC_L == 42949672.95 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1B  CIFC-L    not available\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;

	double  CDEOGE_R;
	double  CDEOGE_L;
	double  CDERGE_R;
	double  CDERGE_L;
	double  GE_R;
	double  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 = (double)((unsigned long)((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 available
		if ( CDEOGE_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDEOGE-R  not available\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 = (double)((unsigned long)((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 available
		if ( CDEOGE_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDEOGE-L  not available\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 = (double)((unsigned long)((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 available
		if ( CDERGE_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDERGE-R  not available\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 = (double)((unsigned long)((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 available
		if ( CDERGE_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  CDERGE-L  not available\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 = (double)((unsigned long)((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 available
		if ( GE_R == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  GE-R      not available\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 = (double)((unsigned long)((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 available
		if ( GE_L == 429496729.5 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1C  GE-L      not available\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];

		// if it's the max value, not available
		if ( AGSA_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSA_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];

		// if it's the max value, not available
		if ( AGSA_TIME2_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSA_TIME2-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AGSA_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSA_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AGSA_TIME2_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSA_TIME2-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AGSB_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSB_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AGSB_TIME2_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSB_TIME2-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AGSB_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSB_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AGSB_TIME2_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1D  AGSB_TIME2-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( VRHC_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E  VRHC_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( VRHC_TIME2_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E  VRHC_TIME2-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( VRHC_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E  VRHC_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( VRHC_TIME2_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1E  VRHC_TIME2-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AAF1_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF1_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AAF1_TIME2_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF1_TIME2-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AAF1_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF1_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AAF1_TIME2_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF1_TIME2-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AAF2_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF2_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AAF2_TIME2_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF2_TIME2-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( AAF2_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF2_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( AAF2_TIME2_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $1F  AAF2_TIME2-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( EDSM_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  EDSM_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( EDSM_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  EDSM_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DSM1_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM1_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DSM1_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM1_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DSM2_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM2_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DSM2_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM2_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DSM3_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM3_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DSM3_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM3_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DSM4_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM4_TIME1-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DSM4_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $21  DSM4_TIME1-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( ISS_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22  ISS_TIME1-R  not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( ISS_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22  ISS_TIME1-L  not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( ERC_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22  ERC_TIME1-R  not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( ERC_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22  ERC_TIME1-L  not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( EOC_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22  EOC_TIME1-R  not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( EOC_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $22  EOC_TIME1-L  not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DCTE1_CNTS_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTE1_CNTS-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DCTU1_CNTS_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTU1_CNTS-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DCTE1_CNTS_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTE1_CNTS-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DCTU1_CNTS_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTU1_CNTS-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DCTE2_CNTS_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTE2_CNTS-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DCTU2_CNTS_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTU2_CNTS-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DCTE2_CNTS_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTE2_CNTS-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DCTU2_CNTS_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTU2_CNTS-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DCTE3_CNTS_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTE3_CNTS-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DCTU3_CNTS_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTU3_CNTS-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( DCTE3_CNTS_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTE3_CNTS-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( DCTU3_CNTS_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $23  DCTU3_CNTS-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];
	
		// if it's the max value, not available
		if ( EWU_TIME_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24  EWU_TIME-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( EWU_TIME_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24  EWU_TIME-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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];

		// if it's the max value, not available
		if ( TWU_TIME_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24  TWU_TIME-R not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 )
			{
				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];
	
		// if it's the max value, not available
		if ( TWU_TIME_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $24  TWU_TIME-L not available\n",
			      GetEcuId ( EcuIdx ) );
		}
		else
		{
			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 OCCT_TIME1_R
		OCCT_TIME1_R = (gstResponse[EcuIdx].Inf[2] << 24) +
		               (gstResponse[EcuIdx].Inf[3] << 16) +
		               (gstResponse[EcuIdx].Inf[4] << 8) +
		                gstResponse[EcuIdx].Inf[5];
	
		// if it's the max value, not available
		if ( OCCT_TIME1_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X  OCCT%dT1-R not available\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->ID - 24 );
		}
		else
		{
			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 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X OCCT%dT1-R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      pInf->ID - 24 );
				eRetCode = FAIL;
			}
		}


		// log OCCT_TIME2_R
		OCCT_TIME2_R = (gstResponse[EcuIdx].Inf[6] << 24) +
		               (gstResponse[EcuIdx].Inf[7] << 16) +
		               (gstResponse[EcuIdx].Inf[8] << 8) +
		                gstResponse[EcuIdx].Inf[9];
	
		// if it's the max value, not available
		if ( OCCT_TIME2_R == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X  OCCT%dT2-R not available\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->ID - 24 );
		}
		else
		{
			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 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $%02X OCCT%dT2-R must return a value of 0 after a Service $04 code clear\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      pInf->ID - 24 );
				eRetCode = FAIL;
			}
		}

		// log OCCT_TIME1_L
		OCCT_TIME1_L = (gstResponse[EcuIdx].Inf[10] << 24) +
		               (gstResponse[EcuIdx].Inf[11] << 16) +
		               (gstResponse[EcuIdx].Inf[12] << 8) +
		                gstResponse[EcuIdx].Inf[13];
	
		// if it's the max value, not available
		if ( OCCT_TIME1_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X  OCCT%dT1-L not available\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->ID - 24 );
		}
		else
		{
			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 OCCT_TIME2_L
		OCCT_TIME2_L = (gstResponse[EcuIdx].Inf[14] << 24) +
		               (gstResponse[EcuIdx].Inf[15] << 16) +
		               (gstResponse[EcuIdx].Inf[16] << 8) +
		                gstResponse[EcuIdx].Inf[17];
	
		// if it's the max value, not available
		if ( OCCT_TIME2_L == 4294967295 )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%02X  OCCT%dT2-L not available\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      pInf->ID - 24 );
		}
		else
		{
			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;
	double        DT;
	double        EOE;
	double        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 && gstUserInput.ePwrTrnType != HEV &&
			     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 && gstUserInput.ePwrTrnType != HEV &&
			          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 = (double)((unsigned long)((gstResponse[EcuIdx].Inf[6] << 24) +
		                                  (gstResponse[EcuIdx].Inf[7] << 16) +
		                                  (gstResponse[EcuIdx].Inf[8] << 8) +
		                                   gstResponse[EcuIdx].Inf[9])) * .25;
		}
		else
		{
			DT = (double)((unsigned short)((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 && gstUserInput.ePwrTrnType != HEV &&
			          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 = (double)((unsigned long)((gstResponse[EcuIdx].Inf[10] << 24) +
			                               (gstResponse[EcuIdx].Inf[11] << 16) +
			                               (gstResponse[EcuIdx].Inf[12] << 8) +
			                                gstResponse[EcuIdx].Inf[13])) * .001;
		}
		else
		{
			EOE = (double)((unsigned short)((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 && gstUserInput.ePwrTrnType != HEV &&
			          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 = (double)((unsigned long)((gstResponse[EcuIdx].Inf[14] << 24) +
			                               (gstResponse[EcuIdx].Inf[15] << 16) +
			                               (gstResponse[EcuIdx].Inf[16] << 8) +
			                                gstResponse[EcuIdx].Inf[17])) * .5;
		}
		else
		{
			VFC = (double)((unsigned short)((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 && gstUserInput.ePwrTrnType != HEV &&
			          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;

	double        EFC;
	unsigned long IERT;
	double        IEFC;
	unsigned long UERT;
	unsigned long PKE;
	unsigned long PTOERT;
	double        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 = (double)((unsigned long)((gstResponse[EcuIdx].Inf[2] << 24) +
			                               (gstResponse[EcuIdx].Inf[3] << 16) +
			                               (gstResponse[EcuIdx].Inf[4] << 8) +
			                                gstResponse[EcuIdx].Inf[5])) * .5;
		}
		else
		{
			EFC = (double)((unsigned short)((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 )
				{
					if ( gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $42 EFC-A must return a value of greater than 0\n",
						      GetEcuId ( EcuIdx ) );
					}
					else
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $F42 EFC-A must return a value of greater than 0\n",
						      GetEcuId ( EcuIdx ) );
						eRetCode = FAIL;
					}
				}
			}
			else if ( pInf->ID == 0x44 )
			{
				Test_5_17_Inf[EcuIdx].INF44_EFC_S = EFC;
			}
			else if ( pInf->ID == 0x46 )
			{
				if ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV &&
				     EFC == 0 )
				{
					Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $46 EFC-L must return a value of greater than 0\n",
					      GetEcuId ( EcuIdx ) );
				}

				if ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV &&
				     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 && gstUserInput.ePwrTrnType != HEV &&
			     ((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 ( (gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV) &&
			          ((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 ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV &&
				     IERT <= 1 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  INF $42 IERT-A must return a value of greater than 1\n",
					      GetEcuId ( EcuIdx ),
					      pInf->ID,
					      Letter );
					eRetCode = FAIL;
				}
			}
			else if ( pInf->ID == 0x46 &&
			          gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV &&
			          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 = (double)((unsigned long)((gstResponse[EcuIdx].Inf[10] << 24) +
			                                (gstResponse[EcuIdx].Inf[11] << 16) +
			                                (gstResponse[EcuIdx].Inf[12] << 8) +
			                                 gstResponse[EcuIdx].Inf[13])) * .5;
		}
		else
		{
			IEFC = (double)((unsigned short)((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 ( IEFC == 0 )
				{
					if ( gstUserInput.ePwrTrnType == PHEV || gstUserInput.ePwrTrnType == HEV )
					{
						Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $42 IEFC-A must return a value of greater than 0\n",
						      GetEcuId ( EcuIdx ) );
					}
					else
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  INF $42 IEFC-A must return a value of greater than 0\n",
						      GetEcuId ( EcuIdx ) );
						eRetCode = FAIL;
					}
				}
			}

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

				if ( gstUserInput.ePwrTrnType != PHEV && gstUserInput.ePwrTrnType != HEV &&
				     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 && gstUserInput.ePwrTrnType != HEV &&
			          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 && gstUserInput.ePwrTrnType != HEV &&
			          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;
		}

		if ( ((pInf->ID == 0x42 || pInf->ID == 0x44) && PTOERT == 0xFFFF) ||
		     (pInf->ID == 0x46 && PTOERT == 0xFFFFFFFF ) )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X  PTOERT-%c not supported\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      Letter,
			      PTOERT );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%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 &&
				     (((pInf->ID == 0x42 || pInf->ID == 0x44) && PTOERT != 0xFFFF) ||
				      (pInf->ID == 0x46 && PTOERT != 0xFFFFFFFF)) )
				{
					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 && gstUserInput.ePwrTrnType != HEV &&
			          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 = (double)((unsigned long)((gstResponse[EcuIdx].Inf[26] << 24) +
			                                 (gstResponse[EcuIdx].Inf[27] << 16) +
			                                 (gstResponse[EcuIdx].Inf[28] << 8) +
			                                  gstResponse[EcuIdx].Inf[29])) * .5;
		}
		else
		{
			PTOFC = (double)((unsigned short)((gstResponse[EcuIdx].Inf[16] << 8) +
			                                   gstResponse[EcuIdx].Inf[17])) * .5;
		}

		if ( ((pInf->ID == 0x42 || pInf->ID == 0x44) && PTOFC == 0xFFFF) ||
		     (pInf->ID == 0x46 && PTOFC == 0xFFFFFFFF ) )
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X  PTOFC-%c not supported\n",
			      GetEcuId ( EcuIdx ),
			      pInf->ID,
			      Letter,
			      PTOFC );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X  PTOFC-%c  = %10.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 &&
				     (((pInf->ID == 0x42 || pInf->ID == 0x44) && PTOFC != 0xFFFF) ||
				      (pInf->ID == 0x46 && PTOFC != 0xFFFFFFFF)) )
				{
					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 && gstUserInput.ePwrTrnType != HEV &&
			          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;
	double CDEODT_L;

	float  CDERDT_A;
	float  CDERDT_S;
	double CDERDT_L;

	float  CIDT_A;
	float  CIDT_S;
	double 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 short)((gstResponse[EcuIdx].Inf[2] << 8) +
		                                     gstResponse[EcuIdx].Inf[3])) * (float).25;
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "ECU %X  INF $48  CDEODT-A = %9.3f km\n",
		      GetEcuId ( EcuIdx ),
		      CDEODT_A );
		if ( gstUserInput.ePwrTrnType == PHEV &&
		     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 short)((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 = (double)((unsigned long)((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 short)((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 ( gstUserInput.ePwrTrnType == PHEV &&
		     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 short)((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 = (double)((unsigned long)((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 short)((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 ( gstUserInput.ePwrTrnType == PHEV &&
		     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 short)((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 = (double)((unsigned long)((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;
	double CDFC_L;

	float  CIFC_A;
	float  CIFC_S;
	double 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 short)((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 short)((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 = (double)((unsigned long)((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 short)((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 short)((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 = (double)((unsigned long)((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 ( gstUserInput.ePwrTrnType == PHEV &&
		     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;
	double        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 short)((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 short)((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 = (double)((unsigned long)((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;
	double        AT1_DT_L;

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

	float         AT2_DT_A;
	float         AT2_DT_S;
	double        AT2_DT_L;

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


	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 short)((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 short)((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 = (double)((unsigned long)((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 short)((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 short)((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 = (double)((unsigned long)((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;

	double Bin[17];
	double Bin_Sum = 0;

	unsigned short BinIndex;

	double *pArchive = NULL;

	char   NameString[10];
	char   CompareNameString[10];
	double 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 = .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 = .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 = .001;
				pArchive = &Test_5_17_Inf[EcuIdx].INF61_NOxEOB_A[0];
			}
			break;

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


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			Bin[BinIndex] = (double)((unsigned long)((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];
			}

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

	double  Bin[17];
	double  Bin_Sum = 0;

	unsigned short BinIndex;

	char   NameString[10];
	double 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 = .001;


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			if ( pInf->ID == 0x6F || pInf->ID == 0x73 )
			{
				Bin[BinIndex] = (double)((unsigned long)((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] = (double)((unsigned short)((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];
			}

			// -L and -EAL values must be greater than -A values
			else if ( (pInf->ID == 0x6F || pInf->ID == 0x73) &&
			          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;
			}


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

		// compare [bin1] against sum of [bin2] through [bin14]
		// Fail if Sum of [bin2] through [bin14] != [bin1]
		if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
		     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $%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;

	double  Bin[17];
	double  Bin_Sum = 0;

	unsigned short BinIndex;

	char   NameString[10];
	double 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 = .25;
			}
			break;
			case 0x6A:
			{
				strcpy_s( NameString, DTB_TXT_MAX, "DTB-S" );
				Multiplier = .25;
			}
			break;
			case 0x70:
			{
				strcpy_s( NameString, DTB_TXT_MAX, "DTB-L" );
				Multiplier = .005;
			}
			break;
			case 0x74:
			{
				strcpy_s( NameString, DTB_TXT_MAX, "DTB-EAL" );
				Multiplier = .005;
			}
			break;
		}


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			if ( pInf->ID == 0x70 || pInf->ID == 0x74 )
			{
				Bin[BinIndex] = (double)((unsigned long)((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] = (double)((unsigned short)((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];
			}

			// -L and -EAL values must be greater than -A values
			else if ( (pInf->ID == 0x70 || pInf->ID == 0x74) &&
			          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;
			}


			// collect the sum of [bin2] through [bin14]
			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] = %.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] );

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


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


		// no nox DTCs from SID $19 LEV $42 Status Mask $04 or $08 &&
		// Fail if sum of [bin2] through [bin14] != [bin1]
		if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
		     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %.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:  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;

	double  Bin[17];
	double  Bin_Sum = 0;

	unsigned short BinIndex;

	char   NameString[10];
	double 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 = .5;


		for ( BinIndex = 0;
		      BinIndex < 17;
		      BinIndex++ )
		{
			// log bin data
			if ( pInf->ID == 0x72 || pInf->ID == 0x76 )
			{
				Bin[BinIndex] = (double)((unsigned long)((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] = (double)((unsigned short)((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] );

			// Save -A values for later
			if ( pInf->ID == 0x66 )
			{
				Test_5_17_Inf[EcuIdx].INF66_FCB_A[BinIndex] = Bin[BinIndex];
			}
			// -L and EAL values must be greater than -A values
			else if ( (pInf->ID == 0x72 ||
			           pInf->ID == 0x76) &&
			          Bin[BinIndex] != 0 &&
			          Bin[BinIndex] < Test_5_17_Inf[EcuIdx].INF66_FCB_A[BinIndex] )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  INF $F8%02X %s[bin%d] must be greater than FCB-A[bin%d] (%.3f)\n",
				      GetEcuId ( EcuIdx ),
				      pInf->ID,
				      NameString,
				      BinIndex+1,
				      BinIndex+1,
				      Test_5_17_Inf[EcuIdx].INF66_FCB_A[BinIndex] );
				eRetCode = FAIL;
			}
	
	
			if ( BinIndex >= 1 && BinIndex <= 13 )
			{
				Bin_Sum += Bin[BinIndex];
			}
		}
	
	
		// no nox DTCs from SID $19 LEV $42 Status Mask $04 or $08 &&
		// Fail if sum of [bin2] through [bin14] != [bin1]
		if ( Bin_Sum < (Bin[0] - (Bin[0]*.01)) ||
		     Bin_Sum > (Bin[0] + (Bin[0]*.01)) )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $F8%02X the sum of %s[bin2] through %s[bin14] = %.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:  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;

	double         REGEN1_SDIST;
	double         REGEN1_FDIST;
	double         REGEN2_SDIST;
	double         REGEN2_FDIST;
	double         REGEN3_SDIST;
	double         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 = (double)((unsigned long)((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 = (double)((unsigned long)((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 = (double)((unsigned long)((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 = (double)((unsigned long)((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 = (double)((unsigned long)((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 = (double)((unsigned long)((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 short)((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 );

		if ( PWR_RATING == 0 &&
		     gModelYear >= 2024 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $78  PWR_RATING Must be greater than 0\n",
			      GetEcuId ( EcuIdx) );
			eRetCode = FAIL;
		}


		// log RPM_RATING
		RPM_RATING = (float)((unsigned short)((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 == 0 &&
		     gModelYear >= 2024 )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  INF $78 RPM_RATING Must be greater than 0\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 || gstUserInput.eVehicleType == MD) )
				{
					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 || gstUserInput.eVehicleType == MD) )
				{
					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;
	}
}
