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

#include <stdio.h>    // C Library input and output declarations
#include <stdlib.h>   // C Library general function declarations
#include <string.h>   // C Library character array declarations
#include <time.h>     // C Library time and date declarations
#include <conio.h>    // MS-DOS console input and output declarations
#include <windows.h>  // Windows API declarations
#include "j2534.h"    // j1699 project j2534 declarations
#include "j1699.h"    // j1699 project general declarations
#include "ScreenOutput.h"  // j1699 project console output declarations


// Function Prototypes
BOOL   IsIM_ReadinessComplete ( PID *pPid );
STATUS EvaluateInf14 ( void );
BOOL   ReadIptFromLogFile ( const char *szTestSectionStart,
                            const char *szTestSectionEnd );
BOOL   ReadIpt ( const char *szTestSectionEnd );
BOOL   SaveIptData ( BYTE EcuIdx,
                     IPT *pIpt );
STATUS EvaluateIpt ( BYTE          EcuIdx,
                     unsigned int *pIptStatusFlags,
                     BOOL          bDisplayErrorMsg );
STATUS RunDynamicTest11 ( BOOL          bDisplayCARBTimers,
                          unsigned long EngineStartTimestampMsecs );
void   PrintEcuData ( unsigned int  IptId );


extern STATUS VerifyInf14Data ( BYTE EcuIdx );
extern STATUS GetIptData ( BYTE EcuIdx,
                           IPT *pIpt );
extern STATUS LogIpt  ( void );
extern void   LogLastTransaction ( void );          // copies last transaction from ring buffer to log file
extern void   DumpTransactionBuffer ( void );       // copies transaction ring buffer to log file
extern void   SaveTransactionStart ( void );        // marks the start of a new transaction in the ring buffer


// Variable Definitions
typedef enum
{
	COMPLETE=0,
	INCOMPLETE=1,
	NOTSUPPORTED=2,
	DISABLED=3,
	INVALID=4
} IM_Status;
IM_Status **Test11IMStatus;
IM_Status   eCurrentIMStatus[11];

PID *pTest11_Pid01 = NULL;

IPT *pTest11_5_Ipt = NULL;
IPT *pTest11_11_Ipt = NULL;
IPT *pTest11CurrentDisplayData = NULL;

PID *pPreviousPid1 = NULL;
PID *pPid41 = NULL;   // capture the response from SID01 pPid41 response.


typedef struct
{
	BOOL bCatBank1;
	BOOL bCatBank2;
	BOOL bO2Bank1;
	BOOL bO2Bank2;
	BOOL bSO2Bank1;
	BOOL bSO2Bank2;
	BOOL bNCAT;
	BOOL bNADS;
	BOOL bAFRIBank1;
	BOOL bAFRIBank2;
	BOOL bPFBank1;
	BOOL bPFBank2;
} BANK_SUPPORT;
static BANK_SUPPORT BankSupport[MAX_ECUS];

const char *szIM_Status[] =
{
	"Complete",
	"Incomplete",
	"Not Supported",
	"Disabled",
	"Invalid"
};

const char *szTest_Status[] =
{
	"Normal",
	"FAILURE"
};

//******************************************************************************
// Dynamic Test 11.x screen
//******************************************************************************
#define COL1            1
#define COL2            25
#define COL3            40
#define COL4            60
#define COL5            65
#define COL6            70
#define COL7            75

#define COL_PAGE        (COL1+7)
#define COL_ECU         (COL1+12)
#define SPACE           9

#define STATUS_ROW      5
#define PRESS_ESC_ROW   26

#define IMSTATUS_ELEMENT_INDEX  11
#define COUNTER_ELEMENT_INDEX   32

#define STRING_WIDTH    13
#define NUMERIC_WIDTH   5
#define HEX_WIDTH       4
#define ECU_WIDTH       8


StaticTextElement  _string_elements11_INF856[] =
{
	// ECU List
	{"Page:",                     COL1, 1},
	{"ECU List:",                 COL1, 2},
	{"ECU Status:",               COL1, 3},
	{"1",          COL_ECU + 0 * SPACE, 1},
	{"2",          COL_ECU + 1 * SPACE, 1},
	{"3",          COL_ECU + 2 * SPACE, 1},
	{"4",          COL_ECU + 3 * SPACE, 1},
	{"5",          COL_ECU + 4 * SPACE, 1},
	{"6",          COL_ECU + 5 * SPACE, 1},
	{"7",          COL_ECU + 6 * SPACE, 1},
	{"8",          COL_ECU + 7 * SPACE, 1},

	// column 1
	{"I/M STATUS",                COL1, STATUS_ROW+0},
	{"Oxygen Sensor Monitor",     COL1, STATUS_ROW+1},
	{"Oxygen Sensor Heater",      COL1, STATUS_ROW+2},
	{"Catalyst Monitor",          COL1, STATUS_ROW+3},
	{"Catalyst Heater",           COL1, STATUS_ROW+4},
	{"GPF",                       COL1, STATUS_ROW+5},
	{"Evaporative Emissions",     COL1, STATUS_ROW+6},
	{"EGR/VVT",                   COL1, STATUS_ROW+7},
	{"AIR",                       COL1, STATUS_ROW+8},
	{"Fuel Trim",                 COL1, STATUS_ROW+9},
	{"Misfire",                   COL1, STATUS_ROW+10},
	{"Comp / Comp",               COL1, STATUS_ROW+11},

	// column 2
	{"RATE BASED COUNTER",        COL3, STATUS_ROW+0},
	{"OBD Monitoring Conditions", COL3, STATUS_ROW+1},
	{"Ignition Counter",          COL3, STATUS_ROW+2},

	{"Initial",                   COL4, STATUS_ROW+4},
	{"Current",                   COL6, STATUS_ROW+4},

	{"N",                         COL4, STATUS_ROW+5},
	{"D",                         COL5, STATUS_ROW+5},

	{"N",                         COL6, STATUS_ROW+5},
	{"D",                         COL7, STATUS_ROW+5},

	// column 2 - two values
	{"Catalyst B1",               COL3, STATUS_ROW+6},
	{"Catalyst B2",               COL3, STATUS_ROW+7},
	{"Oxygen Sensor B1",          COL3, STATUS_ROW+8},
	{"Oxygen Sensor B2",          COL3, STATUS_ROW+9},
	{"EGR/VVT",                   COL3, STATUS_ROW+10},
	{"AIR",                       COL3, STATUS_ROW+11},
	{"EVAP",                      COL3, STATUS_ROW+12},
	{"Sec O2 Sensor B1",          COL3, STATUS_ROW+13},
	{"Sec O2 Sensor B2",          COL3, STATUS_ROW+14},
	{"AFRI Sensor B1",            COL3, STATUS_ROW+15},
	{"AFRI Sensor B2",            COL3, STATUS_ROW+16},
	{"PF Sensor B1",              COL3, STATUS_ROW+17},
	{"PF Sensor B2",              COL3, STATUS_ROW+18},

	// misc
	{"Test Status:",              COL1, PRESS_ESC_ROW-1},
	{"Press ESC to exit, a number to change ECU display, or F to FAIL", COL1, PRESS_ESC_ROW},
	{"",                             0, PRESS_ESC_ROW+1}
};
const int _num_string_elements11_INF856 = sizeof ( _string_elements11_INF856) / sizeof ( _string_elements11_INF856[0] );


StaticTextElement  _string_elements11_INFB36[] =
{
	// ECU List
	{"Page:",                     COL1, 1},
	{"ECU List:",                 COL1, 2},
	{"ECU Status:",               COL1, 3},
	{"1",          COL_ECU + 0 * SPACE, 1},
	{"2",          COL_ECU + 1 * SPACE, 1},
	{"3",          COL_ECU + 2 * SPACE, 1},
	{"4",          COL_ECU + 3 * SPACE, 1},
	{"5",          COL_ECU + 4 * SPACE, 1},
	{"6",          COL_ECU + 5 * SPACE, 1},
	{"7",          COL_ECU + 6 * SPACE, 1},
	{"8",          COL_ECU + 7 * SPACE, 1},

	// column 1
	{"I/M STATUS",                COL1, STATUS_ROW+0},
	{"EGS",                       COL1, STATUS_ROW+1},
	{"PM",                        COL1, STATUS_ROW+2},
	{"NMHC Catalyst",             COL1, STATUS_ROW+3},
	{"NOx Aftertreatment",        COL1, STATUS_ROW+4},
	{"Reserved",                  COL1, STATUS_ROW+5},
	{"Reserved",                  COL1, STATUS_ROW+6},
	{"EGR/VVT",                   COL1, STATUS_ROW+7},
	{"BP",                        COL1, STATUS_ROW+8},
	{"Fuel Trim",                 COL1, STATUS_ROW+9},
	{"Misfire",                   COL1, STATUS_ROW+10},
	{"Comp / Comp",               COL1, STATUS_ROW+11},

	// column 2
	{"RATE BASED COUNTER",        COL3, STATUS_ROW+0},
	{"OBD Monitoring Conditions", COL3, STATUS_ROW+1},
	{"Ignition Counter",          COL3, STATUS_ROW+2},

	{"Initial",                   COL4, STATUS_ROW+4},
	{"Current",                   COL6, STATUS_ROW+4},

	{"N",                         COL4, STATUS_ROW+5},
	{"D",                         COL5, STATUS_ROW+5},

	{"N",                         COL6, STATUS_ROW+5},
	{"D",                         COL7, STATUS_ROW+5},

	// column 2 - two values
	{"HCCAT",                     COL3, STATUS_ROW+6},
	{"NCAT",                      COL3, STATUS_ROW+7},
	{"NADS",                      COL3, STATUS_ROW+8},
	{"PM",                        COL3, STATUS_ROW+9},
	{"EGS",                       COL3, STATUS_ROW+10},
	{"EGR/VVT",                   COL3, STATUS_ROW+11},
	{"BP",                        COL3, STATUS_ROW+12},
	{"FUEL",                      COL3, STATUS_ROW+13},
	{"                ",          COL3, STATUS_ROW+14},

	// misc
	{"Test Status:",              COL1, PRESS_ESC_ROW-1},
	{"Press ESC to exit, a number to change ECU display, or F to FAIL", COL1, PRESS_ESC_ROW},
	{"",                             0, PRESS_ESC_ROW+1}
};
const int _num_string_elements11_INFB36 = sizeof ( _string_elements11_INFB36 ) / sizeof ( _string_elements11_INFB36[0] );

StaticTextElement  _string_elements_timers[] =
{
	{"Cont. Idle (Sec.):",         COL1, PRESS_ESC_ROW-2},
	{"At Speed (Sec.):",             30, PRESS_ESC_ROW-2},
	{"Run Time (Sec.):",             56, PRESS_ESC_ROW-2}
};
const int _num_string_elements_timers = sizeof ( _string_elements_timers ) / sizeof ( _string_elements_timers[0] );


DynamicValueElement  _dynamic_elements11[] =
{
	// ECU Page
	{COL_PAGE, 1, NUMERIC_WIDTH},        // Curent ECU Page

	// ECUs
	{COL_ECU + 0 * SPACE, 2, ECU_WIDTH}, // ECU 1
	{COL_ECU + 1 * SPACE, 2, ECU_WIDTH}, // ECU 2
	{COL_ECU + 2 * SPACE, 2, ECU_WIDTH}, // ECU 3
	{COL_ECU + 3 * SPACE, 2, ECU_WIDTH}, // ECU 4
	{COL_ECU + 4 * SPACE, 2, ECU_WIDTH}, // ECU 5
	{COL_ECU + 5 * SPACE, 2, ECU_WIDTH}, // ECU 6
	{COL_ECU + 6 * SPACE, 2, ECU_WIDTH}, // ECU 7
	{COL_ECU + 7 * SPACE, 2, ECU_WIDTH}, // ECU 8

	// ECU Done
	{COL_ECU + 0 * SPACE, 3, HEX_WIDTH}, // ECU Status 1
	{COL_ECU + 1 * SPACE, 3, HEX_WIDTH}, // ECU Status 2
	{COL_ECU + 2 * SPACE, 3, HEX_WIDTH}, // ECU Status 3
	{COL_ECU + 3 * SPACE, 3, HEX_WIDTH}, // ECU Status 4
	{COL_ECU + 4 * SPACE, 3, HEX_WIDTH}, // ECU Status 5
	{COL_ECU + 5 * SPACE, 3, HEX_WIDTH}, // ECU Status 6
	{COL_ECU + 6 * SPACE, 3, HEX_WIDTH}, // ECU Status 7
	{COL_ECU + 7 * SPACE, 3, HEX_WIDTH}, // ECU Status 8

	// column 1                             INF 8                 / INF B
	{COL2, STATUS_ROW+1,  STRING_WIDTH}, // Oxygen Sensor Monitor / EGS
	{COL2, STATUS_ROW+2,  STRING_WIDTH}, // Oxygen Sensor Heater  / PM
	{COL2, STATUS_ROW+3,  STRING_WIDTH}, // Catalyst Monitor      / NMHC
	{COL2, STATUS_ROW+4,  STRING_WIDTH}, // Catalyst Heater       / NOx
	{COL2, STATUS_ROW+5,  STRING_WIDTH}, // Reserved              / Reserved
	{COL2, STATUS_ROW+6,  STRING_WIDTH}, // Evaportive Emissions  / Reserved
	{COL2, STATUS_ROW+7,  STRING_WIDTH}, // EGR/VVT               / EGR/VVT
	{COL2, STATUS_ROW+8,  STRING_WIDTH}, // AIR                   / BP
	{COL2, STATUS_ROW+9,  STRING_WIDTH}, // Fuel Trim
	{COL2, STATUS_ROW+10, STRING_WIDTH}, // Misfire
	{COL2, STATUS_ROW+11, STRING_WIDTH}, // Comp / Comp

	// column 2
	{COL6, STATUS_ROW+1, NUMERIC_WIDTH}, // OBD Monitoring Conditions
	{COL6, STATUS_ROW+2, NUMERIC_WIDTH}, // Ignition Counter

	// column 2 - initial values               INF 8              / INF B
	{COL4, STATUS_ROW+6, NUMERIC_WIDTH},    // Catalyst B1 N      / HCCAT N
	{COL5, STATUS_ROW+6, NUMERIC_WIDTH},    // Catalyst B1 D      / HCCAT D

	{COL4, STATUS_ROW+7, NUMERIC_WIDTH},    // Catalyst B2 N      / NCAT N
	{COL5, STATUS_ROW+7, NUMERIC_WIDTH},    // Catalyst B2 D      / NCAT D

	{COL4, STATUS_ROW+8, NUMERIC_WIDTH},    // Oxygen Sensor B1 N / NADS N
	{COL5, STATUS_ROW+8, NUMERIC_WIDTH},    // Oxygen Sensor B1 D / NADS N

	{COL4, STATUS_ROW+9, NUMERIC_WIDTH},    // Oxygen Sensor B2 N / PM N
	{COL5, STATUS_ROW+9, NUMERIC_WIDTH},    // Oxygen Sensor B2 D / PM D

	{COL4, STATUS_ROW+10, NUMERIC_WIDTH},   // EGR/VVT N          / EGS N
	{COL5, STATUS_ROW+10, NUMERIC_WIDTH},   // EGR/VVT D          / EGS D

	{COL4, STATUS_ROW+11, NUMERIC_WIDTH},   // AIR N              / EGR N
	{COL5, STATUS_ROW+11, NUMERIC_WIDTH},   // AIR D              / EGR D

	{COL4, STATUS_ROW+12, NUMERIC_WIDTH},   // EVAP N             / BP N
	{COL5, STATUS_ROW+12, NUMERIC_WIDTH},   // EVAP D             / BP D

	{COL4, STATUS_ROW+13, NUMERIC_WIDTH},   // Sec O2 Sensor B1 N / FUEL N
	{COL5, STATUS_ROW+13, NUMERIC_WIDTH},   // Sec O2 Sensor B1 D / FUEL D

	{COL4, STATUS_ROW+14, NUMERIC_WIDTH},   // Sec O2 Sensor B2 N
	{COL5, STATUS_ROW+14, NUMERIC_WIDTH},   // Sec O2 Sensor B2 D

	{COL4, STATUS_ROW+15, NUMERIC_WIDTH},   // AFRI Sensor B1 N
	{COL5, STATUS_ROW+15, NUMERIC_WIDTH},   // AFRI Sensor B1 D

	{COL4, STATUS_ROW+16, NUMERIC_WIDTH},   // AFRI Sensor B2 N
	{COL5, STATUS_ROW+16, NUMERIC_WIDTH},   // AFRI Sensor B2 D

	{COL4, STATUS_ROW+17, NUMERIC_WIDTH},   // PF Sensor B1 N
	{COL5, STATUS_ROW+17, NUMERIC_WIDTH},   // PF Sensor B1 D

	{COL4, STATUS_ROW+18, NUMERIC_WIDTH},   // PF Sensor B2 N
	{COL5, STATUS_ROW+18, NUMERIC_WIDTH},   // PF Sensor B2 D

	// column 2 - current values               INF 8              / INF B
	{COL6, STATUS_ROW+6, NUMERIC_WIDTH},    // Catalyst B1 N      / HCCAT N
	{COL7, STATUS_ROW+6, NUMERIC_WIDTH},    // Catalyst B1 D      / HCCAT D

	{COL6, STATUS_ROW+7, NUMERIC_WIDTH},    // Catalyst B2 N      / NCAT N
	{COL7, STATUS_ROW+7, NUMERIC_WIDTH},    // Catalyst B2 D      / NCAT D

	{COL6, STATUS_ROW+8, NUMERIC_WIDTH},    // Oxygen Sensor B1 N / NADS N
	{COL7, STATUS_ROW+8, NUMERIC_WIDTH},    // Oxygen Sensor B1 D / NADS N

	{COL6, STATUS_ROW+9, NUMERIC_WIDTH},    // Oxygen Sensor B2 N / PM N
	{COL7, STATUS_ROW+9, NUMERIC_WIDTH},    // Oxygen Sensor B2 D / PM D

	{COL6, STATUS_ROW+10, NUMERIC_WIDTH},   // EGR/VVT N          / EGS N
	{COL7, STATUS_ROW+10, NUMERIC_WIDTH},   // EGR/VVT D          / EGS D

	{COL6, STATUS_ROW+11, NUMERIC_WIDTH},   // AIR N              / EGR N
	{COL7, STATUS_ROW+11, NUMERIC_WIDTH},   // AIR D              / EGR D

	{COL6, STATUS_ROW+12, NUMERIC_WIDTH},   // EVAP N             / BP N
	{COL7, STATUS_ROW+12, NUMERIC_WIDTH},   // EVAP D             / BP D

	{COL6, STATUS_ROW+13, NUMERIC_WIDTH},   // Sec O2 Sensor B1 N / FUEL N
	{COL7, STATUS_ROW+13, NUMERIC_WIDTH},   // Sec O2 Sensor B1 D / FUEL D

	{COL6, STATUS_ROW+14, NUMERIC_WIDTH},   // Sec O2 Sensor B2 N
	{COL7, STATUS_ROW+14, NUMERIC_WIDTH},   // Sec O2 Sensor B2 D

	{COL6, STATUS_ROW+15, NUMERIC_WIDTH},   // AFRI Sensor B1 N
	{COL7, STATUS_ROW+15, NUMERIC_WIDTH},   // AFRI Sensor B1 D

	{COL6, STATUS_ROW+16, NUMERIC_WIDTH},   // AFRI Sensor B2 N
	{COL7, STATUS_ROW+16, NUMERIC_WIDTH},   // AFRI Sensor B2 D

	{COL6, STATUS_ROW+17, NUMERIC_WIDTH},   // PF Sensor B1 N
	{COL7, STATUS_ROW+17, NUMERIC_WIDTH},   // PF Sensor B1 D

	{COL6, STATUS_ROW+18, NUMERIC_WIDTH},   // PF Sensor B2 N
	{COL7, STATUS_ROW+18, NUMERIC_WIDTH},   // PF Sensor B2 D


	{20, PRESS_ESC_ROW-2, NUMERIC_WIDTH},   // CARB Idle Timer
	{47, PRESS_ESC_ROW-2, NUMERIC_WIDTH},   // CARB At Speed Timer
	{73, PRESS_ESC_ROW-2, NUMERIC_WIDTH},   // CARB Run Time


	{14, PRESS_ESC_ROW-1, STRING_WIDTH},    // Test Status
	{COL3, PRESS_ESC_ROW-1, STRING_WIDTH}   // DTC Status
};
const int _num_dynamic_elements11 = sizeof ( _dynamic_elements11 ) / sizeof ( _dynamic_elements11[0] );

#define ECU_PAGE_INDEX              0
#define ECU_ID_INDEX                1
#define ECU_STATUS_INDEX            9

#define IM_READINESS_INDEX          17
// O2_SENSOR_RESP_INDEX             17
// O2_SENSOR_HEATER_INDEX           18
// CATALYST_MONITOR_INDEX           19
// CATALYST_HEATER_INDEX            10
// AIR_COND_INDEX                   21
// EVAP_EMMISION_INDEX              22
// EGR_INDEX                        23
// AIR_INDEX                        24
// FUEL_TRIM_INDEX                  25
// MISFIRE_INDEX                    26
// COMP_COMP_INDEX                  27

#define OBD_MONITOR_COND_INDEX      28
#define IGNITION_COUNTER_INDEX      29

#define IPT_INIT_INDEX              30
// CATCOMP1   /  HCCATCOMP          30
// CATCOND1   /  HCCATCOND
// CATCOMP2   /  NCATCOMP           32
// CATCOND2   /  NCATCOND
// O2SCOMP1   /  NADSCOMP           34
// O2SCOND1   /  NADSCOND
// O2SCOMP2   /  PMCOMP             36
// O2SCOND2   /  PMCOND
// EGRCOMP    /  EGSCOMP            38
// EGRCOND    /  EGSCOND
// AIRCOMP    /  EGRCOMP            40
// AIRCOND    /  EGRCOND
// EVAPCOMP   /  BPCOMP             42
// EVAPCOND   /  BPCOND
// SO2SCOMP1  /  FUEL               44
// SO2SCOND1  /  FUEL
// SO2SCOMP2                        46
// SO2SCOND2
// AFRICOMP1                        48
// AFRICOND1
// AFRICOMP2                        50
// AFRICOND2
// PFCOMP1                          52
// PFCOND1
// PFCOMP2                          54
// PFCOND2

#define IPT_CUR_INDEX               56
// CATCOMP1   /  HCCATCOMP          56
// CATCOND1   /  HCCATCOND
// CATCOMP2   /  NCATCOMP           58
// CATCOND2   /  NCATCOND
// O2SCOMP1   /  NADSCOMP           60
// O2SCOND1   /  NADSCOND
// O2SCOMP2   /  PMCOMP             62
// O2SCOND2   /  PMCOND
// EGRCOMP    /  EGSCOMP            64
// EGRCOND    /  EGSCOND
// AIRCOMP    /  EGRCOMP            66
// AIRCOND    /  EGRCOND
// EVAPCOMP   /  BPCOMP             68
// EVAPCOND   /  BPCOND
// SO2SCOMP1  /  FUEL               70
// SO2SCOND1  /  FUEL
// SO2SCOMP2                        72
// SO2SCOND2
// AFRICOMP1                        74
// AFRICOND1
// AFRICOMP2                        76
// AFRICOND2
// PFCOMP1                          78
// PFCOND1
// PFCOMP2                          80
// PFCOND2

#define CARB_TIMER_INDEX            82
#define IDLE_TIMER                  82
#define SPEED_25_MPH_TIMER          83
#define TOTAL_DRIVE_TIMER           84

#define IPT_TESTSTATUS_INDEX        85
// Normal / FAILURE                 85
// blank / DTC Detected             86


#define OBDCOND_NOT_DONE    0xFFFFFFFE
#define IGNCNTR_NOT_DONE    0xFFFFFFFD

#define CATCOMP1_NOT_DONE   0xFFFFFFFB
#define CATCOND1_NOT_DONE   0xFFFFFFF7
#define CATCOMP2_NOT_DONE   0xFFFFFFEF
#define CATCOND2_NOT_DONE   0xFFFFFFDF
#define O2SCOMP1_NOT_DONE   0xFFFFFFBF
#define O2SCOND1_NOT_DONE   0xFFFFFF7F
#define O2SCOMP2_NOT_DONE   0xFFFFFEFF
#define O2SCOND2_NOT_DONE   0xFFFFFDFF
#define EGRCOMP8_NOT_DONE   0xFFFFFBFF
#define EGRCOND8_NOT_DONE   0xFFFFF7FF
#define AIRCOMP_NOT_DONE    0xFFFFEFFF
#define AIRCOND_NOT_DONE    0xFFFFDFFF
#define EVAPCOMP_NOT_DONE   0xFFFFBFFF
#define EVAPCOND_NOT_DONE   0xFFFF7FFF
#define SO2SCOMP1_NOT_DONE  0xFFFEFFFF
#define SO2SCOND1_NOT_DONE  0xFFFDFFFF
#define SO2SCOMP2_NOT_DONE  0xFFFBFFFF
#define SO2SCOND2_NOT_DONE  0xFFF7FFFF
#define AFRICOMP1_NOT_DONE  0xFFEFFFFF
#define AFRICOND1_NOT_DONE  0xFFDFFFFF
#define AFRICOMP2_NOT_DONE  0xFFBFFFFF
#define AFRICOND2_NOT_DONE  0xFF7FFFFF
#define PFCOMP1_NOT_DONE    0xFEFFFFFF
#define PFCOND1_NOT_DONE    0xFDFFFFFF
#define PFCOMP2_NOT_DONE    0xFBFFFFFF
#define PFCOND2_NOT_DONE    0xF7FFFFFF

#define HCCATCOMP_NOT_DONE  0xFFFFFFFB
#define HCCATCOND_NOT_DONE  0xFFFFFFF7
#define NCATCOMP_NOT_DONE   0xFFFFFFEF
#define NCATCOND_NOT_DONE   0xFFFFFFDF
#define NADSCOMP_NOT_DONE   0xFFFFFFBF
#define NADSCOND_NOT_DONE   0xFFFFFF7F
#define PMCOMP_NOT_DONE     0xFFFFFEFF
#define PMCOND_NOT_DONE     0xFFFFFDFF
#define EGSCOMP_NOT_DONE    0xFFFFFBFF
#define EGSCOND_NOT_DONE    0xFFFFF7FF
#define EGRCOMPB_NOT_DONE   0xFFFFEFFF
#define EGRCONDB_NOT_DONE   0xFFFFDFFF
#define BPCOMP_NOT_DONE     0xFFFFBFFF
#define BPCOND_NOT_DONE     0xFFFF7FFF
#define FUELCOMP_NOT_DONE   0xFFFEFFFF
#define FUELCOND_NOT_DONE   0xFFFDFFFF


#define IPT_OBDCOND_INDEX       0   //INF8 & INFB
#define IPT_IGNCNTR_INDEX       1   //INF8 & INFB
#define IPT_CATCOMP1_INDEX      2   //INF8
#define IPT_HCCATCOMP_INDEX     2   //INFB
#define IPT_CATCOND1_INDEX      3   //INF8
#define IPT_HCCATCOND_INDEX     3   //INFB
#define IPT_CATCOMP2_INDEX      4   //INF8
#define IPT_NCATCOMP_INDEX      4   //INFB
#define IPT_CATCOND2_INDEX      5   //INF8
#define IPT_NCATCOND_INDEX      5   //INFB
#define IPT_O2SCOMP1_INDEX      6   //INF8
#define IPT_NADSCOMP_INDEX      6   //INFB
#define IPT_O2SCOND1_INDEX      7   //INF8
#define IPT_NADSCOND_INDEX      7   //INFB
#define IPT_O2SCOMP2_INDEX      8   //INF8
#define IPT_PMCOMP_INDEX        8   //INFB
#define IPT_O2SCOND2_INDEX      9   //INF8
#define IPT_PMCOND_INDEX        9   //INFB
#define IPT_INF8_EGRCOMP_INDEX  10  //INF8
#define IPT_EGSCOMP_INDEX       10  //INFB
#define IPT_INF8_EGRCOND_INDEX  11  //INF8
#define IPT_EGSCOND_INDEX       11  //INFB
#define IPT_AIRCOMP_INDEX       12  //INF8
#define IPT_INFB_EGRCOMP_INDEX  12  //INFB
#define IPT_AIRCOND_INDEX       13  //INF8
#define IPT_INFB_EGRCOND_INDEX  13  //INFB
#define IPT_EVAPCOMP_INDEX      14  //INF8
#define IPT_BPCOMP_INDEX        14  //INFB
#define IPT_EVAPCOND_INDEX      15  //INF8
#define IPT_BPCOND_INDEX        15  //INFB
#define IPT_SO2SCOMP1_INDEX     16  //INF8
#define IPT_FUELCOMP_INDEX      16  //INFB
#define IPT_SO2SCOND1_INDEX     17  //INF8
#define IPT_FUELCOND_INDEX      17  //INFB
#define IPT_SO2SCOMP2_INDEX     18  //INF8 NODI 20 & 28
#define IPT_SO2SCOND2_INDEX     19  //INF8 NODI 20 & 28
#define IPT_AFRICOMP1_INDEX     20  //INF8 NODI 28
#define IPT_AFRICOND1_INDEX     21  //INF8 NODI 28
#define IPT_AFRICOMP2_INDEX     22  //INF8 NODI 28
#define IPT_AFRICOND2_INDEX     23  //INF8 NODI 28
#define IPT_PFCOMP1_INDEX       24  //INF8 NODI 28
#define IPT_PFCOND1_INDEX       25  //INF8 NODI 28
#define IPT_PFCOMP2_INDEX       26  //INF8 NODI 28
#define IPT_PFCOND2_INDEX       27  //INF8 NODI 28


// used with the on-screen test status
#define SUB_TEST_NORMAL     0x00
#define SUB_TEST_FAIL       0x01
#define SUB_TEST_DTC        0x02
#define SUB_TEST_INITIAL    0x80


#define SetFieldDec(index,val)  (update_screen_dec(_dynamic_elements11,_num_dynamic_elements11,index,val))
#define SetFieldHex(index,val)  (update_screen_hex(_dynamic_elements11,_num_dynamic_elements11,index,val))
#define SetFieldText(index,val) (update_screen_text(_dynamic_elements11,_num_dynamic_elements11,index,val))


#define NORMAL_TEXT      -1
#define HIGHLIGHTED_TEXT  8
#define RED_TEXT          1


extern FILE         *gLogFileHandle;

extern const char szECUID[];
extern int ECUID_Size;
extern const char szINF_SIZE[];
extern int INF_SIZE_Size;
extern const char szINF8[][10];
extern const char szINFB[][10];


/*******************************************************************************
**
**  Function:  Test11_PerformanceCounters
**
**  Purpose:   Run Test 11 to verify performance counters
**
*******************************************************************************/
STATUS Test11_PerformanceCounters ( BOOL *pbTestReEntered )
{
	REQ_MSG        stReqMsg;
	PID           *pPid;
	BYTE           EcuIdx;
	STATUS         eRetVal;

	unsigned long  EngineStartTimestampMsecs = 0;
	BOOL           bRunTest11_2;
	BOOL           bSubTestFailed = FALSE;
	unsigned int   IptStatusFlags;        // Bit Map of Items Completed


	// initialize arrays
	memset ( BankSupport,
	         FALSE,
	         sizeof ( BankSupport ) );


//*******************************************************************************
//  Test 11.1 - Verify performance counters
//*******************************************************************************
	gTestSubsection = 1;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify performance counters)" );

	if ( gbEngineRunning == FALSE )
	{
		Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
		      "Turn ignition to crank position and start engine.\n" );
		gbEngineRunning = TRUE;
		EngineStartTimestampMsecs = GetTickCount ( );
	}

	// Verify still connected
	if ( VerifyECUCommunication ( ) == FAIL )
	{
		bSubTestFailed = TRUE;

		// lost connection, probably due to crank - so re-establish connection
		DisconnectOBDProtocol ( );

		if ( ConnectOBDProtocol ( ) == FAIL )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "Connect Protocol unsuccessful\n" );
			Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
			return FAIL;
		}
	}

	// check if need to run test 11.2
	stReqMsg.SID    = 0x01;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = 0x01;
	if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $01 PID $01 request unsuccessful\n" );
		Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
		return FAIL;
	}

	bRunTest11_2 = FALSE;
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( IsIDSupported ( EcuIdx, PIDREQUEST, 0x01 ) == TRUE )
		{
			pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

			// save for EvaluateIpt ( )
			pTest11_Pid01[EcuIdx].ID = pPid->ID;
			pTest11_Pid01[EcuIdx].Data[0] = pPid->Data[0];
			pTest11_Pid01[EcuIdx].Data[1] = pPid->Data[1];
			pTest11_Pid01[EcuIdx].Data[2] = pPid->Data[2];
			pTest11_Pid01[EcuIdx].Data[3] = pPid->Data[3];

			if ( IsIM_ReadinessComplete ( pPid ) == FALSE )
			{
				bRunTest11_2 = TRUE;
			}
		}
	}

	if ( LogIpt ( ) != PASS )
	{
		bSubTestFailed = TRUE;
		gbTestSubsectionFailed = FALSE;
	}

	// Retrieve Sid 9 IPT from the first run of test 10.10
	if ( ReadIptFromLogFile ( "**** Test 10.10 (", "**** Test 10.10" ) == FALSE )
	{
		bSubTestFailed = TRUE;
		gbTestSubsectionFailed = FALSE;
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Could not find Test 10.10 SID $09 IPT data in log file.\n" );
	}


	// collect current Sid 9 IPT data
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_GAS ) == TRUE ||
		     IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_DIESEL ) == TRUE )
		{
			if ( GetIptData ( EcuIdx, &pTest11_5_Ipt[EcuIdx] ) == PASS )
			{
				// Initialize pTest11CurrentDisplayData for first DisplayEcuData
				SaveIptData ( EcuIdx, &pTest11_5_Ipt[EcuIdx] );

				eRetVal = EvaluateIpt ( EcuIdx, &IptStatusFlags, FALSE );
				// if conditions require running of test 11.2
				if ( (eRetVal & FAIL) == FAIL )
				{
					bRunTest11_2 = TRUE;
				}
				// if conditions indicate that test 11.2 may not finish normally
				if ( (eRetVal & ERRORS) == ERRORS )
				{
					bSubTestFailed = TRUE;
				}
			}
		}
	}


	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( bSubTestFailed == TRUE || gbTestSubsectionFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT,
		           "Errors detected that may cause the next test,\n"
		           "Test 11.2 (Complete Drive Cycle and Clear IM Readiness Bits),\n"
		           "to fail even when the test exits normally.\n" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.2 - Manufacture Specific Drive Cycle
//*******************************************************************************
	gTestSubsection = 2;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Manufacture Specific Drive Cycle)" );

	if ( bRunTest11_2 == TRUE )
	{
		// tester-present message should already be active

		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "\n"
		      "Drive the vehicle in the manufacturer-specified manner to complete all the\n"
		      "OBD monitors required to set all the supported I/M Readiness bits to a \"Ready\"\n"
		      "condition. The vehicle may have to \"soak\" with the ignition off (engine off).\n"
		      "Allow vehicle to soak according to the manufacturer-specified conditions in\n"
		      "order to run any engine-off diagnostics and/or prepare the vehicle for any \n"
		      "engine-running diagnostics on the next drive cycle that requires an engine-off\n"
		      "soak period.\n\n" );

		if ( Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		           "Would you like to use the J1699 software as a monitor to view\n"
		           "the status of the I/M Readiness bits?\n"
		           "(Enter 'N' to exit the software if you are going to turn the vehicle off\n"
		           "or don't need a monitor. You can return to this point, at any time,\n"
		           "by re-starting the J1699 software and selecting 'Dynamic Tests'.)\n" ) != 'Y' )
		{
			Log ( SUBSECTION_INCOMPLETE_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
			ABORT_RETURN;
		}


		// stop tester-present message
		StopPeriodicMsg ( TRUE );
		Sleep ( gRequestDelayTimeMsecs );


		eRetVal = RunDynamicTest11 ( *pbTestReEntered, EngineStartTimestampMsecs );


		// re-start tester-present message
		StartPeriodicMsg ( );


		if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
		{
			bSubTestFailed = TRUE;
		}

		if ( eRetVal == FAIL || gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
		{
			if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
			{
				return FAIL;
			}
		}
		else if ( eRetVal == ABORT || gbTestSectionAborted == TRUE )
		{
			Log ( SUBSECTION_INCOMPLETE_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
			ABORT_RETURN;
		}
		else
		{
			Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.3 -
//*******************************************************************************
	gTestSubsection = 3;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Turn engine off to allow drive cycle data to be collected without it changing during data collection process.))" );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Pull over to a safe spot and turn the ignition off for at least 30 sec.\n"
	      "Keep tool connected to the J1962 connector.  " );

	Log ( PROMPT, SCREENOUTPUTON, LOGOUTPUTON, ENTER_PROMPT,
	      "Turn key on without cranking or starting engine.\n" );

	Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );

	// Engine should now be not running
	gbEngineRunning = FALSE;


//*******************************************************************************
//  Test 11.4 - Re-establish communication, ignition on, engine off
//*******************************************************************************
	gTestSubsection = 4;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Re-establish communication, ignition on, engine off)" );

	if ( DetermineOBDProtocol ( ) != PASS )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Protocol determination unsuccessful.\n" );
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.5 - Verify Diagnostic Data, Engine Off
//*******************************************************************************
	gTestSubsection = 5;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Diagnostic Data (Service $01), Engine Off)" );

	if ( VerifyIM_Ready ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.6 - Verify Monitor Test Results, Engine Off
//*******************************************************************************
	gTestSubsection = 6;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Monitor Test Results (Service $06), Engine Off)" );

	if ( VerifyMIDSupportAndResults ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.7 - Verify Vehicle Information, Engine Off
//*******************************************************************************
	gTestSubsection = 7;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Vehicle Information (Sevice $09), Engine Off)" );

	if ( LogIpt ( ) != PASS || gbTestSubsectionFailed == TRUE )
	{
		bSubTestFailed = TRUE;
		gbTestSubsectionFailed = FALSE;
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $09 IPT data error\n" );
	}
	else
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( GetIptData ( EcuIdx, &pTest11_5_Ipt[EcuIdx] ) == PASS )
			{
				if ( EvaluateIpt ( EcuIdx, &IptStatusFlags, TRUE ) != PASS )
				{
					bSubTestFailed = TRUE;
				}
			}
		}
	}

	if ( EvaluateInf14 ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( bSubTestFailed == TRUE || gbTestSubsectionFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.8 - Verify Diagnostic Data, Engine Off
//*******************************************************************************
	gTestSubsection = 8;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Diagnostic Data (Service $01), Engine Off)" );

	if ( VerifyIM_Ready ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.9 - Verify DTCs, Engine Off
//*******************************************************************************
	gTestSubsection = 9;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify DTCs (Service $03), Engine Off)" );

	if ( VerifyStoredDTCData ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.10 - Verify Pending DTCs, Engine Off
//*******************************************************************************
	gTestSubsection = 10;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Pending DTCs (Service $07), Engine Off)" );

	if ( VerifyPendingDTCData ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.11 - Clear DTCs, Engine Off
//*******************************************************************************
	gTestSubsection = 11;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Clear DTCs (Service $04), Engine Off)" );

	if ( ClearCodes ( ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}


//*******************************************************************************
//  Test 11.12 - Verify Vehicle Information, Engine Off
//*******************************************************************************
	gTestSubsection = 12;
	gbTestSubsectionFailed = FALSE;
	bSubTestFailed = FALSE;

	Log ( SUBSECTION_BEGIN, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
	      "(Verify Vehicle Information (Service $09), Engine Off)" );

	if ( LogIpt ( ) != PASS || gbTestSubsectionFailed == TRUE )
	{
		bSubTestFailed = TRUE;
		gbTestSubsectionFailed = FALSE;
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $09 IPT data error\n" );
	}

	else
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( GetIptData ( EcuIdx, &pTest11_11_Ipt[EcuIdx] ) == PASS )
			{
				if ( EvaluateIpt ( EcuIdx, &IptStatusFlags, TRUE ) != PASS )
				{
					bSubTestFailed = TRUE;
				}
			}
		}
	}

	if ( VerifyVehicleState ( gbEngineRunning, gbHybrid ) != PASS )
	{
		bSubTestFailed = TRUE;
	}

	if ( gbTestSubsectionFailed == TRUE || bSubTestFailed == TRUE )
	{
		if ( Log ( SUBSECTION_FAILED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT, "" ) == 'N' )
		{
			return FAIL;
		}
	}
	else
	{
		Log ( SUBSECTION_PASSED_RESULT, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "" );
	}

	return  PASS;
}


/*******************************************************************************
**
**  Function:  IsIM_ReadinessComplete
**
**  Purpose:
**
**  NOTE:      supported bits :: 1 -> supported,    0 -> not supported
**
**             status    bits :: 1 -> not complete, 0 -> complete (or not applicable)
**
*******************************************************************************/
BOOL IsIM_ReadinessComplete ( PID *pPid )
{
	if ( pPid->ID != 1 )
	{
		return FALSE;
	}

	//     supported bits    status bits
	if ( ((pPid->Data[1] & (pPid->Data[1] >> 4)) & 0x07) != 0 )
	{
		return FALSE;
	}

	//    supported bits   status bits
	if ( (pPid->Data[2] & pPid->Data[3]) != 0 )
	{
		return FALSE;
	}

	return TRUE;
}


/*******************************************************************************
**
**  Function:  EvaluateIpt
**
**  Purpose:
**
*******************************************************************************/
STATUS EvaluateIpt ( BYTE          EcuIdx,
                     unsigned int *pIptStatusFlags,
                     BOOL          bDisplayErrorMsg )
{
	STATUS  eRetCode = PASS;
	BYTE    ECUIdx;

	BOOL    bEvapCounts = FALSE;
	int     IptIndex;
	int     count;
	int     count1;
	int     count2;
	int     count3;
	int     count4;


	// if not supported, then cannot do comparsions
	if ( IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_GAS ) == TRUE ||
	     IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_DIESEL ) == TRUE )
	{
		// Test 11.1, 11.2, 11.5, 11.7
		if ( gTestSubsection != 11 )
		{
			// IGNCNTR must be >= OBDCOND
			if ( pTest11_5_Ipt[EcuIdx].Data[IPT_IGNCNTR_INDEX] < pTest11_5_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] )
			{
				if ( bDisplayErrorMsg == TRUE )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  IGNCNTR less than OBDCOND\n",
					      GetEcuId ( EcuIdx ) );
				}
				eRetCode |= FAIL;
				*pIptStatusFlags &= IGNCNTR_NOT_DONE;
			}

			// IGNCNTR must be greater than the value in test 10.10
			if ( (pTest11_5_Ipt[EcuIdx].Flags&VALIDDATA)  != 0 &&
			     (gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Flags&VALIDDATA) != 0 )
			{
				count = pTest11_5_Ipt[EcuIdx].Data[IPT_IGNCNTR_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_IGNCNTR_INDEX];
				if ( count < 1 )
				{
					if ( bDisplayErrorMsg == TRUE )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  IGNCNTR incremented less than 1 since Test 10.10\n",
						      GetEcuId ( EcuIdx ) );
					}
					eRetCode |= FAIL;
					*pIptStatusFlags &= IGNCNTR_NOT_DONE;
				}
			}

			// OBDCOND must be >= other monitor condition counters
			for ( IptIndex = 3;
			      IptIndex < pTest11_5_Ipt[EcuIdx].NODI;
			      IptIndex += 2 )
			{
				if ( pTest11_5_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] < pTest11_5_Ipt[EcuIdx].Data[IptIndex] )
				{
					if ( bDisplayErrorMsg == TRUE )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  OBDCOND not greater than all other monitor condition counters\n",
						      GetEcuId ( EcuIdx ) );
					}
					eRetCode |= FAIL;
					*pIptStatusFlags &= OBDCOND_NOT_DONE;
				}
			}

			// OBDCOND must have incremented by at least 1 since test 10.10
			if ( (pTest11_5_Ipt[EcuIdx].Flags & VALIDDATA) != 0 &&
			     (gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Flags & VALIDDATA) != 0 )
			{
				count = pTest11_5_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_OBDCOND_INDEX];
				if ( count < 1 )
				{
					if ( bDisplayErrorMsg == TRUE )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  OBDCOND incremented less than 1 since Test 10.10\n",
						      GetEcuId ( EcuIdx ) );
					}
					eRetCode |= FAIL;
					*pIptStatusFlags &= OBDCOND_NOT_DONE;
				}
			}

			// if this vehicle supports SID 9 INF 8
			if ( pTest11_5_Ipt[EcuIdx].ID == 0x08 )
			{
				// if CAT monitoring not supported (CAT_SUP and HCAT_SUP == 0), must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x03) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOMP1_INDEX] != 0 ||  // CATCOMP1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOND1_INDEX] != 0 ||  // CATCOND1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOMP2_INDEX] != 0 ||  // CATCOMP2
					     pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOND2_INDEX] != 0 )   // CATCOND2
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  CATCOMP1, CATCOMP2, CATCOND1, CATCOND2 not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}
				// if CAT monitoring is supported, at least one bank must have increased
				else
				{
					// Check if Bank 1 is supported
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOMP1_INDEX] > 0 ||  // CATCOMP1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOND1_INDEX] > 0 ||  // CATCOND1
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOMP1_INDEX] > 0 ||  // CATCOMP1
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOND1_INDEX] > 0 )   // CATCOND1
					{
						BankSupport[EcuIdx].bCatBank1 = TRUE;
					}

					// Check if Bank 2 is supported
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOMP2_INDEX] > 0 ||  // CATCOMP2
					     pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOND2_INDEX] > 0 ||  // CATCOND2
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOMP2_INDEX] > 0 ||  // CATCOMP2
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOND2_INDEX] > 0 )   // CATCOND2
					{
						BankSupport[EcuIdx].bCatBank2 = TRUE;
					}

					// Check for change
					count1 = pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOMP1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOMP1_INDEX];
					count2 = pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOND1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOND1_INDEX];
					count3 = pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOMP2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOMP2_INDEX];
					count4 = pTest11_5_Ipt[EcuIdx].Data[IPT_CATCOND2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_CATCOND2_INDEX];

					if ( count1 == 0 && count2 == 0 && BankSupport[EcuIdx].bCatBank1 == FALSE &&
					     count3 == 0 && count4 == 0 && BankSupport[EcuIdx].bCatBank2 == FALSE )
					{
						// can't tell which bank is supported, so highlight them both till we see one change
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  Neither bank of the CAT monitor changed since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						*pIptStatusFlags &= CATCOMP1_NOT_DONE;
						*pIptStatusFlags &= CATCOND1_NOT_DONE;
						*pIptStatusFlags &= CATCOMP2_NOT_DONE;
						*pIptStatusFlags &= CATCOND2_NOT_DONE;
						eRetCode |= FAIL;
					}
					else
					{
						if ( (count1 == 0 || count2 == 0) && BankSupport[EcuIdx].bCatBank1 )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  Bank 1 of the CAT monitor has not changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= FAIL;
						}

						if ( (count3 == 0 || count4 == 0) && BankSupport[EcuIdx].bCatBank2 )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  Bank 2 of the CAT monitor has not changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= FAIL;
						}

						if ( count1 == 0 && BankSupport[EcuIdx].bCatBank1 == TRUE )
						{
							*pIptStatusFlags &= CATCOMP1_NOT_DONE;
						}
						if ( count2 == 0 && BankSupport[EcuIdx].bCatBank1 == TRUE )
						{
							*pIptStatusFlags &= CATCOND1_NOT_DONE;
						}
						if ( count3 == 0 && BankSupport[EcuIdx].bCatBank2 == TRUE )
						{
							*pIptStatusFlags &= CATCOMP2_NOT_DONE;
						}
						if ( count4 == 0 && BankSupport[EcuIdx].bCatBank2 == TRUE )
						{
							*pIptStatusFlags &= CATCOND2_NOT_DONE;
						}
					}
				}

				// if O2 monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x20) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOMP1_INDEX] != 0 ||  // O2SCOMP1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOND1_INDEX] != 0 ||  // O2SCOND1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOMP2_INDEX] != 0 ||  // O2SCOMP2
					     pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOND2_INDEX] != 0 )   // O2SCOND2
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  O2SCOMP1, O2SCOMP2, O2SCOND1, O2SCOND2 not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}

					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOMP1_INDEX] != 0 ||  // SO2SCOMP1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOND1_INDEX] != 0 ||  // SO2SCOND1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOMP2_INDEX] != 0 ||  // SO2SCOMP2
					     pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOND2_INDEX] != 0 )   // SO2SCOND2
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  SO2SCOMP1, SO2SCOMP2, SO2SCOND1, SO2SCOND2 not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}
				// if O2 monitoring is supported, at least one bank must have increased
				else
				{
					//
					// O2 checks
					//
					// Check if Bank 1 is supported
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOMP1_INDEX] > 0 ||  // O2SCOMP1
					     pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOND1_INDEX] > 0 ||  // O2SCOND1
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOMP1_INDEX] > 0 ||  // O2SCOMP1
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOND1_INDEX] > 0 )   // O2SCOND1
					{
						BankSupport[EcuIdx].bO2Bank1 = TRUE;
					}

					// Check if Bank 2 is supported
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOMP2_INDEX] > 0 ||  // O2SCOMP2
					     pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOND2_INDEX] > 0 ||  // O2SCOND2
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOMP2_INDEX] > 0 ||  // O2SCOMP2
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOND2_INDEX] > 0 )   // O2SCOND2
					{
						BankSupport[EcuIdx].bO2Bank2 = TRUE;
					}

					// Check for change
					count1 = pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOMP1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOMP1_INDEX];
					count2 = pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOND1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOND1_INDEX];
					count3 = pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOMP2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOMP2_INDEX];
					count4 = pTest11_5_Ipt[EcuIdx].Data[IPT_O2SCOND2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_O2SCOND2_INDEX];

					if ( count1 == 0 && count2 == 0 && BankSupport[EcuIdx].bO2Bank1 == FALSE &&
					     count3 == 0 && count4 == 0 && BankSupport[EcuIdx].bO2Bank2 == FALSE )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  Neither bank of the O2 monitor changed since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						*pIptStatusFlags &= O2SCOMP1_NOT_DONE;
						*pIptStatusFlags &= O2SCOND1_NOT_DONE;
						*pIptStatusFlags &= O2SCOMP2_NOT_DONE;
						*pIptStatusFlags &= O2SCOND2_NOT_DONE;
						eRetCode |= FAIL;
					}
					else
					{
						if ( (count1 == 0 || count2 == 0) && BankSupport[EcuIdx].bO2Bank1 )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  Bank 1 of the O2 monitor has not changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= FAIL;
						}

						if ( (count3 == 0 || count4 == 0) && BankSupport[EcuIdx].bO2Bank2 )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  Bank 2 of the O2 monitor has not changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= FAIL;
						}

						if ( count1 == 0 && BankSupport[EcuIdx].bO2Bank1 == TRUE )
						{
							*pIptStatusFlags &= O2SCOMP1_NOT_DONE;
						}
						if ( count2 == 0 && BankSupport[EcuIdx].bO2Bank1 == TRUE )
						{
							*pIptStatusFlags &= O2SCOND1_NOT_DONE;
						}
						if ( count3 == 0 && BankSupport[EcuIdx].bO2Bank2 == TRUE )
						{
							*pIptStatusFlags &= O2SCOMP2_NOT_DONE;
						}
						if ( count4 == 0 && BankSupport[EcuIdx].bO2Bank2 == TRUE )
						{
							*pIptStatusFlags &= O2SCOND2_NOT_DONE;
						}
					}

					//
					// SO2 checks
					//
					if ( pTest11_5_Ipt[EcuIdx].NODI == 0x14 || pTest11_5_Ipt[EcuIdx].NODI == 0x1C )
					{
						// Check if Bank 1 is supported
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOMP1_INDEX] > 0 ||  // SO2SCOMP1
						     pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOND1_INDEX] > 0 ||  // SO2SCOND1
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOMP1_INDEX] > 0 ||  // SO2SCOMP1
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOND1_INDEX] > 0 )   // SO2SCOND1
						{
							BankSupport[EcuIdx].bSO2Bank1 = TRUE;
						}

						// Check if Bank 2 is supported
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOMP2_INDEX] > 0 ||  // SO2SCOMP2
						     pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOND2_INDEX] > 0 ||  // SO2SCOND2
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOMP2_INDEX] > 0 ||  // SO2SCOMP2
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOND2_INDEX] > 0 )   // SO2SCOND2
						{
							BankSupport[EcuIdx].bSO2Bank2 = TRUE;
						}

						// Check for change
						count1 = pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOMP1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOMP1_INDEX];
						count2 = pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOND1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOND1_INDEX];
						count3 = pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOMP2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOMP2_INDEX];
						count4 = pTest11_5_Ipt[EcuIdx].Data[IPT_SO2SCOND2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_SO2SCOND2_INDEX];

						if ( count1 == 0 && count2 == 0 && BankSupport[EcuIdx].bSO2Bank1 == FALSE &&
						     count3 == 0 && count4 == 0 && BankSupport[EcuIdx].bSO2Bank2 == FALSE )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  Neither bank of the SO2 monitor changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							*pIptStatusFlags &= SO2SCOMP1_NOT_DONE;
							*pIptStatusFlags &= SO2SCOND1_NOT_DONE;
							*pIptStatusFlags &= SO2SCOMP2_NOT_DONE;
							*pIptStatusFlags &= SO2SCOND2_NOT_DONE;
							eRetCode |= FAIL;
						}
						else
						{
							if ( (count1 == 0 || count2 == 0) && BankSupport[EcuIdx].bSO2Bank1 )
							{
								if ( bDisplayErrorMsg == TRUE )
								{
									Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  Bank 1 of the SO2 monitor has not changed since Test 10.10\n",
									      GetEcuId ( EcuIdx ) );
								}
								eRetCode |= FAIL;
							}

							if ( (count3 == 0 || count4 == 0) && BankSupport[EcuIdx].bSO2Bank2 )
							{
								if ( bDisplayErrorMsg == TRUE )
								{
									Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  Bank 2 of the SO2 monitor has not changed since Test 10.10\n",
									      GetEcuId ( EcuIdx ) );
								}
								eRetCode |= FAIL;
							}

							if ( count1 == 0 && BankSupport[EcuIdx].bSO2Bank1 == TRUE )
							{
								*pIptStatusFlags &= SO2SCOMP1_NOT_DONE;
							}
							if ( count2 == 0 && BankSupport[EcuIdx].bSO2Bank1 == TRUE )
							{
								*pIptStatusFlags &= SO2SCOND1_NOT_DONE;
							}
							if ( count3 == 0 && BankSupport[EcuIdx].bSO2Bank2 == TRUE )
							{
								*pIptStatusFlags &= SO2SCOMP2_NOT_DONE;
							}
							if ( count4 == 0 && BankSupport[EcuIdx].bSO2Bank2 == TRUE )
							{
								*pIptStatusFlags &= SO2SCOND2_NOT_DONE;
							}
						}
					} // end if ( pTest11_5_Ipt[EcuIdx].NODI == 0x14 || 0x1C)
				}

				//
				// IF INF 8 56 bytes (28 data items), do AFRI & PF checks
				//
				if ( pTest11_5_Ipt[EcuIdx].NODI == 0x1C )
				{
					// if Fuel monitoring not supported, must be zero
					if ( (pTest11_Pid01[EcuIdx].Data[1] & 0x02) == 0 )
					{
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOMP1_INDEX] != 0 ||  // AFRICOMP1
						     pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOND1_INDEX] != 0 ||  // AFRICOND1
						     pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOMP2_INDEX] != 0 ||  // AFRICOMP2
						     pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOND2_INDEX] != 0 )   // AFRICOND2
						{
							if ( bDisplayErrorMsg == TRUE ||
							     gTestSubsection == 1 )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  AFRICOMP1, AFRICOND1, AFRICOMP2, AFRICOND2 not supported, must be zero\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= ERRORS;
						}
					}
					else
					{
						// Check if AFRI Bank 1 is supported
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOMP1_INDEX] > 0 ||   // AFRICOMP1
						     pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOND1_INDEX] > 0 ||   // AFRICOND1
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOMP1_INDEX] > 0 ||  // AFRICOMP1
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOND1_INDEX] > 0 )   // AFRICOND1
						{
							BankSupport[EcuIdx].bAFRIBank1 = TRUE;
						}

						// Check if AFRI Bank 2 is supported
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOMP2_INDEX] > 0 ||   // AFRICOMP2
						     pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOND2_INDEX] > 0 ||   // AFRICOND2
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOMP2_INDEX] > 0 ||  // AFRICOMP2
						     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOND2_INDEX] > 0 )   // AFRICOND2
						{
							BankSupport[EcuIdx].bAFRIBank2 = TRUE;
						}

						// Check for AFRI change
						count1 = pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOMP1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOMP1_INDEX];
						count2 = pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOND1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOND1_INDEX];
						count3 = pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOMP2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOMP2_INDEX];
						count4 = pTest11_5_Ipt[EcuIdx].Data[IPT_AFRICOND2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AFRICOND2_INDEX];

						if ( gstUserInput.eComplianceType != EOBD_WITH_IUMPR &&
						     gstUserInput.eComplianceType != EOBD_NO_IUMPR   &&
						     gstUserInput.eComplianceType != HD_EOBD         &&
						     gstUserInput.eComplianceType != CNOBD_NO_IUMPR )
						{
							if ( count1 == 0 && count2 == 0 && BankSupport[EcuIdx].bAFRIBank1 == FALSE &&
							     count3 == 0 && count4 == 0 && BankSupport[EcuIdx].bAFRIBank2 == FALSE )
							{
								if ( bDisplayErrorMsg == TRUE )
								{
									Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
									      "ECU %X  Neither bank of the AFRI monitor changed since Test 10.10\n",
									      GetEcuId ( EcuIdx ) );
								}
							}
							else
							{
								if ( (count1 == 0 || count2 == 0) && BankSupport[EcuIdx].bAFRIBank1 )
								{
									if ( gModelYear >= 2019 && gModelYear < 2021 )
									{
										if ( bDisplayErrorMsg == TRUE )
										{
											Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
											      "ECU %X  Bank 1 of the AFRI monitor has not changed since Test 10.10\n",
											      GetEcuId ( EcuIdx ) );
										}
									}
									else if ( gModelYear >= 2021 )
									{
										if ( bDisplayErrorMsg == TRUE )
										{
											Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
											      "ECU %X  Bank 1 of the AFRI monitor has not changed since Test 10.10\n",
											      GetEcuId ( EcuIdx ) );
										}
										eRetCode |= FAIL;
									}
								}

								if ( (count3 == 0 || count4 == 0) && BankSupport[EcuIdx].bAFRIBank2 )
								{
									if ( gModelYear >= 2019 && gModelYear < 2021 )
									{
										if ( bDisplayErrorMsg == TRUE )
										{
											Log ( WARNING, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
											      "ECU %X  Bank 2 of the AFRI monitor has not changed since Test 10.10\n",
											      GetEcuId ( EcuIdx ) );
										}
									}
									else if ( gModelYear >= 2021 )
									{
										if ( bDisplayErrorMsg == TRUE )
										{
											Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
											      "ECU %X  Bank 2 of the AFRI monitor has not changed since Test 10.10\n",
											      GetEcuId ( EcuIdx ) );
										}
										eRetCode |= FAIL;
									}
								}

								if ( gModelYear >= 2021 )
								{
									if ( count1 == 0 && BankSupport[EcuIdx].bAFRIBank1 == TRUE )
									{
										*pIptStatusFlags &= AFRICOMP1_NOT_DONE;
									}
									if ( count2 == 0 && BankSupport[EcuIdx].bAFRIBank1 == TRUE )
									{
										*pIptStatusFlags &= AFRICOND1_NOT_DONE;
									}
									if ( count3 == 0 && BankSupport[EcuIdx].bAFRIBank2 == TRUE )
									{
										*pIptStatusFlags &= AFRICOMP2_NOT_DONE;
									}
									if ( count4 == 0 && BankSupport[EcuIdx].bAFRIBank2 == TRUE )
									{
										*pIptStatusFlags &= AFRICOND2_NOT_DONE;
									}
								}
							}
						} //END if not EOBD
					} //END if fuel monitoring supported

//					// Check if PF Bank 1 is supported
//					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOMP1_INDEX] > 0 ||   // PFCOMP1
//					     pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOND1_INDEX] > 0 ||   // PFCOND1
//					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOMP1_INDEX] > 0 ||  // PFCOMP1
//					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOND1_INDEX] > 0 )   // PFCOND1
//					{
//						BankSupport[EcuIdx].bPFBank1 = TRUE;
//					}
//
//					// Check if PF Bank 2 is supported
//					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOMP2_INDEX] > 0 ||   // PFCOMP2
//					     pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOND2_INDEX] > 0 ||   // PFCOND2
//					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOMP2_INDEX] > 0 ||  // PFCOMP2
//					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOND2_INDEX] > 0 )   // PFCOND2
//					{
//						BankSupport[EcuIdx].bPFBank2 = TRUE;
//					}
//
//					if ( BankSupport[EcuIdx].bPFBank1 || BankSupport[EcuIdx].bPFBank2 )
//					{
//						// Check for PF change
//						count1 = pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOMP1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOMP1_INDEX];
//						count2 = pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOND1_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOND1_INDEX];
//						count3 = pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOMP2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOMP2_INDEX];
//						count4 = pTest11_5_Ipt[EcuIdx].Data[IPT_PFCOND2_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_PFCOND2_INDEX];
//
//						if ( (count1 == 0 || count2 == 0) && BankSupport[EcuIdx].bPFBank1 )
//						{
//							if ( bDisplayErrorMsg == TRUE )
//							{
//								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
//								      "ECU %X  Bank 1 of the PF monitor has not changed since Test 10.10\n",
//								      GetEcuId ( EcuIdx ) );
//							}
//							eRetCode |= FAIL;
//						}
//
//						if ( (count3 == 0 || count4 == 0) && BankSupport[EcuIdx].bPFBank2 )
//						{
//							if ( bDisplayErrorMsg == TRUE )
//							{
//								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
//								      "ECU %X  Bank 2 of the PF monitor has not changed since Test 10.10\n",
//								      GetEcuId ( EcuIdx ) );
//							}
//							eRetCode |= FAIL;
//						}
//
//						if ( count1 == 0 && BankSupport[EcuIdx].bPFBank1 == TRUE )
//						{
//							*pIptStatusFlags &= PFCOMP1_NOT_DONE;
//						}
//						if ( count2 == 0 && BankSupport[EcuIdx].bPFBank1 == TRUE )
//						{
//							*pIptStatusFlags &= PFCOND1_NOT_DONE;
// 						}
//						if ( count3 == 0 && BankSupport[EcuIdx].bPFBank2 == TRUE )
//						{
//							*pIptStatusFlags &= PFCOMP2_NOT_DONE;
//						}
//						if ( count4 == 0 && BankSupport[EcuIdx].bPFBank2 == TRUE )
//						{
//							*pIptStatusFlags &= PFCOND2_NOT_DONE;
//						}
//					}
				} // end if ( pTest11_5_Ipt[EcuIdx].NODI == 0x1C)


				// if EGR monitor not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x80) == 0 )
				{
					if ( gModelYear >= 2011 )
					{
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_INF8_EGRCOMP_INDEX] != 0 || // EGRCOMP
						     pTest11_5_Ipt[EcuIdx].Data[IPT_INF8_EGRCOND_INDEX] != 0 )  // EGRCOND
						{
							if ( bDisplayErrorMsg == TRUE ||
							     gTestSubsection == 1 )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  EGRCOMP and EGRCOND not supported, must be zero\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= ERRORS;
						}
					}
				}
				// if EGR monitor supported, EGRCOMP, EGRCOND must have changed since test 10.10
				else
				{
					count = pTest11_5_Ipt[EcuIdx].Data[IPT_INF8_EGRCOMP_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_INF8_EGRCOMP_INDEX];
					if ( count == 0 )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EGRCOMP unchanged since Test 10.10\n" ,
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= EGRCOMP8_NOT_DONE;
					}

					count = pTest11_5_Ipt[EcuIdx].Data[IPT_INF8_EGRCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_INF8_EGRCOND_INDEX];
					if ( count == 0 )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EGRCOND unchanged since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= EGRCOND8_NOT_DONE;
					}
				}

				// if AIR monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x08) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_AIRCOMP_INDEX] != 0 || // AIRCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_AIRCOND_INDEX] != 0 )  // AIRCOND
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  AIRCOMP and AIRCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}
				// if Air monitor supported, AIRCOMP, AIRCOND must have changed since test 10.10
				else
				{
					count = pTest11_5_Ipt[EcuIdx].Data[IPT_AIRCOMP_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AIRCOMP_INDEX];
					if ( count == 0 )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  AIRCOMP unchanged since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= AIRCOMP_NOT_DONE;
					}

					count = pTest11_5_Ipt[EcuIdx].Data[IPT_AIRCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_AIRCOND_INDEX];
					if ( count == 0 )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  AIRCOND unchanged since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= AIRCOND_NOT_DONE;
					}
				}

				// if EVAP monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x04) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOMP_INDEX] != 0 || // EVAPCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOND_INDEX] != 0 )  // EVAPCOND
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EVAPCOMP and EVAPCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}
				// if EVAP monitor supported, EVAPCOMP & EVAPCOND for at least one ECU must have changed since test 10.10
				else
				{
					for ( ECUIdx = 0;
					      ECUIdx < gNumOfECUs;
					      ECUIdx++ )
					{
						if ( (pTest11_Pid01[ECUIdx].Data[2] & 0x04) == 0x04 )
						{
							// EVAP is supported
							if ( pTest11_5_Ipt[ECUIdx].Data[IPT_EVAPCOMP_INDEX] != 0 ||
							     pTest11_5_Ipt[ECUIdx].Data[IPT_EVAPCOND_INDEX] != 0 )
							{
								// at least one count is non-zero
								bEvapCounts = TRUE;
								break;  // leave ECU for loop
							}

						}
					}

					count = pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOMP_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_EVAPCOMP_INDEX];
					if ( (bEvapCounts == TRUE &&
					      pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOMP_INDEX] == 0 &&
					      pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOND_INDEX] == 0) ||
					     count != 0 )
					{
						// skip this, don't highlight
					}
					else
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							     "ECU %X  EVAPCOMP unchanged since Test 10.10\n",
							     GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= EVAPCOMP_NOT_DONE;
					}

					count = pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_EVAPCOND_INDEX];
					if ( (bEvapCounts == TRUE &&
					      pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOMP_INDEX] == 0 &&
					      pTest11_5_Ipt[EcuIdx].Data[IPT_EVAPCOND_INDEX] == 0) ||
					     count != 0 )
					{
						// skip this, don't highlight
					}
					else
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EVAPCOND unchanged since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= EVAPCOND_NOT_DONE;
					}
				}
			} // end if this vehicle supports SID 9 INF 8

			// if this vehicle supports SID 9 INF B
			else if ( pTest11_5_Ipt[EcuIdx].ID == 0x0B )
			{
				// if HCAT monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x01) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_HCCATCOMP_INDEX] != 0 ||  // HCCATCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_HCCATCOND_INDEX] != 0 )   // HCCATCOND
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  HCCATCOMP, HCCATCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}

				// if NCAT/NADS monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x02) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_NCATCOMP_INDEX] != 0 ||  // NCATCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_NCATCOND_INDEX] != 0 ||  // NCATCOND
					     pTest11_5_Ipt[EcuIdx].Data[IPT_NADSCOMP_INDEX] != 0 ||  // NADSCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_NADSCOND_INDEX] != 0 )   // NADSCOND
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  NCATCOMP, NADSCOMP, NCATCOND, NADSCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}
				// if NCAT monitoring is supported, at least one bank must have increased
				else
				{
					// Check if NCAT is supported
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_NCATCOMP_INDEX] > 0 ||  // NCATCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_NCATCOND_INDEX] > 0 ||  // NCATCOND
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NCATCOMP_INDEX] > 0 ||  // NCATCOMP
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NCATCOND_INDEX] > 0 )   // NCATCOND
					{
						BankSupport[EcuIdx].bNCAT = TRUE;
					}

					// Check if NADS is supported
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_NADSCOMP_INDEX] > 0 ||  // NADSCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_NADSCOND_INDEX] > 0 ||  // NADSCOND
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NADSCOMP_INDEX] > 0 ||  // NADSCOMP
					     gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NADSCOND_INDEX] > 0 )   // NADSCOND
					{
						BankSupport[EcuIdx].bNADS = TRUE;
					}

					count1 = pTest11_5_Ipt[EcuIdx].Data[IPT_NCATCOMP_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NCATCOMP_INDEX];
					count2 = pTest11_5_Ipt[EcuIdx].Data[IPT_NCATCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NCATCOND_INDEX];
					count3 = pTest11_5_Ipt[EcuIdx].Data[IPT_NADSCOMP_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NADSCOMP_INDEX];
					count4 = pTest11_5_Ipt[EcuIdx].Data[IPT_NADSCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_NADSCOND_INDEX];

					if ( count1 == 0 && count2 == 0 && BankSupport[EcuIdx].bNCAT == FALSE &&
					     count3 == 0 && count4 == 0 && BankSupport[EcuIdx].bNADS == FALSE )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  Neither NCAT or NADS changed since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						*pIptStatusFlags &= NCATCOMP_NOT_DONE;
						*pIptStatusFlags &= NCATCOND_NOT_DONE;
						*pIptStatusFlags &= NADSCOMP_NOT_DONE;
						*pIptStatusFlags &= NADSCOND_NOT_DONE;
						eRetCode |= FAIL;
					}
					else
					{
						if ( (count1 == 0 || count2 == 0) && BankSupport[EcuIdx].bNCAT )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  NCAT monitor has not changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= FAIL;
						}

						if ( (count3 == 0 || count4 == 0) && BankSupport[EcuIdx].bNADS )
						{
							if ( bDisplayErrorMsg == TRUE )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  NADS monitor has not changed since Test 10.10\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= FAIL;
						}

						if ( count1 == 0 && BankSupport[EcuIdx].bNCAT )
						{
							*pIptStatusFlags &= NCATCOMP_NOT_DONE;
						}
						if ( count2 == 0 && BankSupport[EcuIdx].bNCAT )
						{
							*pIptStatusFlags &= NCATCOND_NOT_DONE;
						}
						if ( count3 == 0 && BankSupport[EcuIdx].bNADS )
						{
							*pIptStatusFlags &= NADSCOMP_NOT_DONE;
						}
						if ( count4 == 0 && BankSupport[EcuIdx].bNADS )
						{
							*pIptStatusFlags &= NADSCOND_NOT_DONE;
						}
					}
				}

				// if PM monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x40) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_PMCOMP_INDEX] != 0 ||  // PMCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_PMCOND_INDEX] != 0 )   // PMCOND
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  PMCOMP and PMCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}

				// if EGS monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x20) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_EGSCOMP_INDEX] != 0 || // EGSCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_EGSCOND_INDEX] != 0 )  // EGSCOMP
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EGSCOMP and EGSCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}
				}

				// if EGR monitor not supported, must be zero MY 2011 and later
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x80) == 0 )
				{
					if ( gModelYear >= 2011 )
					{
						if ( pTest11_5_Ipt[EcuIdx].Data[IPT_INFB_EGRCOMP_INDEX] != 0 || // EGRCOMP
						     pTest11_5_Ipt[EcuIdx].Data[IPT_INFB_EGRCOND_INDEX] != 0 )  // EGRCOND
						{
							if ( bDisplayErrorMsg == TRUE ||
							     gTestSubsection == 1 )
							{
								Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "ECU %X  EGRCOMP and EGRCOND not supported, must be zero\n",
								      GetEcuId ( EcuIdx ) );
							}
							eRetCode |= ERRORS;
						}
					}
				}
				// if EGR monitor supported, EGRCOMP, EGRCOND must have incremented since test 10.10
				else
				{
					count = pTest11_5_Ipt[EcuIdx].Data[IPT_INFB_EGRCOMP_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_INFB_EGRCOMP_INDEX];
					if ( count == 0 )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EGRCOMP unchanged since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= EGRCOMPB_NOT_DONE;
					}

					count = pTest11_5_Ipt[EcuIdx].Data[IPT_INFB_EGRCOND_INDEX] - gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[IPT_INFB_EGRCOND_INDEX];
					if ( count == 0 )
					{
						if ( bDisplayErrorMsg == TRUE )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  EGRCOND unchanged since Test 10.10\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= FAIL;
						*pIptStatusFlags &= EGRCONDB_NOT_DONE;
					}
				}

				// if BP monitoring not supported, must be zero
				if ( (pTest11_Pid01[EcuIdx].Data[2] & 0x08) == 0 )
				{
					if ( pTest11_5_Ipt[EcuIdx].Data[IPT_BPCOMP_INDEX] != 0 ||   // BPCOMP
					     pTest11_5_Ipt[EcuIdx].Data[IPT_BPCOND_INDEX] != 0 )    // BPCOND
					{
						if ( bDisplayErrorMsg == TRUE ||
						     gTestSubsection == 1 )
						{
							Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
							      "ECU %X  BPCOMP and BPCOND not supported, must be zero\n",
							      GetEcuId ( EcuIdx ) );
						}
						eRetCode |= ERRORS;
					}

				// No Tests for FUEL

				}
			}  // end if this vehicle supports SID 9 INF B
		}  // end if (gTestSubsection == 2 || gTestSubsection == 5)  // Test 11.2 & 11.5

		// Test 11.11
		if ( gTestSubsection == 11 )
		{
			// IGNCNTR must be >= OBDCOND
			if ( pTest11_11_Ipt[EcuIdx].Data[IPT_IGNCNTR_INDEX] < pTest11_11_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] )
			{
				if ( bDisplayErrorMsg == TRUE )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  IGNCNTR less than OBDCOND\n",
					      GetEcuId ( EcuIdx ) );
				}
				eRetCode |= FAIL;
			}

			// OBDCOND must be >= other monitor condition counters
			for ( IptIndex = 3;
			      IptIndex < pTest11_11_Ipt[EcuIdx].NODI;
			      IptIndex += 2 )
			{
				if ( pTest11_11_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] < pTest11_11_Ipt[EcuIdx].Data[IptIndex] )
				{
					if ( bDisplayErrorMsg == TRUE )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  OBDCOND not greater than all other monitor condition counters\n",
						      GetEcuId ( EcuIdx ) );
					}
					eRetCode |= FAIL;
				}
			}

			// IGNCNTR and OBDCOND must have the same values as recorded in step 11.5
			if ( pTest11_11_Ipt[EcuIdx].Data[IPT_IGNCNTR_INDEX]  != pTest11_5_Ipt[EcuIdx].Data[IPT_IGNCNTR_INDEX] )
			{
				if ( bDisplayErrorMsg == TRUE )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  IGNCNTR different from value in test 11.5\n",
					      GetEcuId ( EcuIdx ) );
				}
				eRetCode |= FAIL;
			}

			if ( pTest11_11_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] != pTest11_5_Ipt[EcuIdx].Data[IPT_OBDCOND_INDEX] )
			{
				if ( bDisplayErrorMsg == TRUE )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  OBDCOND different from value in test 11.5\n",
					      GetEcuId ( EcuIdx ) );
				}
				eRetCode |= FAIL;
			}

			// OBD condition counters must continue to be non-zero if they were non-zero in test 11.5
			for ( IptIndex = 2;
			      IptIndex < pTest11_11_Ipt[EcuIdx].NODI;
			      IptIndex++ )
			{
				if ( pTest11_5_Ipt[EcuIdx].Data[IptIndex]  !=0 &&
				     pTest11_11_Ipt[EcuIdx].Data[IptIndex] == 0 )
				{
					if ( bDisplayErrorMsg == TRUE )
					{
						Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
						      "ECU %X  An OBD counter which was non-zero in test 11.5 is now zero\n",
						      GetEcuId ( EcuIdx ) );
					}
					eRetCode |= FAIL;
				}
			}
		}  // end if ( gTestSubsection == 11 )  // Test 11.11
	}  // end if INF $8 or INF $B supported

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  EvaluateInf14
**
**  Purpose:
**
*******************************************************************************/
STATUS EvaluateInf14 ( void )
{
	REQ_MSG  stReqMsg;
	BYTE     EcuIdx;
	STATUS   eRetCode = PASS;


	stReqMsg.SID    = 0x09;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = 0x14;
	if ( IsIDSupported ( ALLECUS, INFREQUEST, INF_TYPE_EVAP_DIST ) == TRUE )
	{
		if ( RequestSid ( &stReqMsg, REQ_MSG_NORMAL ) == FAIL )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "INF $14 request\n" );
			return FAIL;
		}

		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_EVAP_DIST ) == TRUE &&
			     VerifyInf14Data ( EcuIdx ) == FAIL )
			{
				eRetCode = FAIL;
			}
		}
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  SelectECU
**
**  Purpose:
**
*******************************************************************************/
void SelectECU ( int NewIndex,
                 int OldIndex ,
                 int Offset )
{
	int EcuIdx;


	// un-highlite previous selection
	setrgb ( NORMAL_TEXT );
	EcuIdx = ECU_ID_INDEX + OldIndex;
	if ( ECU_ID_INDEX <= EcuIdx && EcuIdx <= (ECU_ID_INDEX+MAX_ECUS_PER_PAGE) )
	{
		SetFieldHex ( EcuIdx, GetEcuId ( Offset+OldIndex ) );
	}

	// highlite new selection
	setrgb ( HIGHLIGHTED_TEXT );
	EcuIdx = ECU_ID_INDEX + NewIndex;
	if ( ECU_ID_INDEX <= EcuIdx && EcuIdx <= (ECU_ID_INDEX+MAX_ECUS_PER_PAGE) )
	{
		SetFieldHex ( EcuIdx, GetEcuId ( Offset+NewIndex ) );
	}

	// restore screen attributes
	setrgb ( NORMAL_TEXT );
}


/*******************************************************************************
**
**  Function:  DisplayEcuData
**
**  Purpose:
**
*******************************************************************************/
void DisplayEcuData ( int           EcuIdx,
                      unsigned int  IptStatusFlags )
{
	int  index;


	// write IM Status
	for ( index = 0;
	      index < 11;
	      index++ )
	{
		// copy IM Status for active ECUs
		eCurrentIMStatus[index] = Test11IMStatus[EcuIdx][index];

		if ( Test11IMStatus[EcuIdx][index] == INCOMPLETE )
		{
			setrgb ( HIGHLIGHTED_TEXT );
		}
		else if ( Test11IMStatus[EcuIdx][index] == DISABLED )
		{
			setrgb ( RED_TEXT );
		}

		SetFieldText ( IM_READINESS_INDEX+index, szIM_Status[Test11IMStatus[EcuIdx][index]] );
		setrgb ( NORMAL_TEXT );
	}

	// if IPT data is supported
	if ( IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_GAS ) == TRUE ||
	     IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_DIESEL ) == TRUE )
	{
		// clear possible "Not Supported" from previous ECU
		SetFieldText ( OBD_MONITOR_COND_INDEX, "          " );
		SetFieldText ( IGNITION_COUNTER_INDEX, "          " );

		// write rate based counter
		if ( (IptStatusFlags & 0x01) == 0 )
		{
			setrgb ( HIGHLIGHTED_TEXT );
		}
		SetFieldDec ( OBD_MONITOR_COND_INDEX, pTest11CurrentDisplayData[EcuIdx].Data[0] );
		setrgb ( NORMAL_TEXT );

		if ( ((IptStatusFlags >>= 1) & 0x01) == 0 )
		{
			setrgb(HIGHLIGHTED_TEXT);
		}
		SetFieldDec ( IGNITION_COUNTER_INDEX, pTest11CurrentDisplayData[EcuIdx].Data[1] );
		setrgb(NORMAL_TEXT);

		// write initial values for rate based counters
		for ( index = 2;
		      index < gstEcuSIDData[EcuIdx].pTest10_10_Ipt->NODI;
		      index++ )
		{
			SetFieldDec ( OBD_MONITOR_COND_INDEX + index, gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index] );
		}

		// write current values for rate based counters
		for ( index = 2;
		      index < pTest11CurrentDisplayData[EcuIdx].NODI;
		      index++ )
		{
			if ( ((IptStatusFlags >>= 1) & 0x01) == 0 )
			{
				setrgb ( HIGHLIGHTED_TEXT );
			}
			SetFieldDec ( (IPT_CUR_INDEX + (index - 2)), pTest11CurrentDisplayData[EcuIdx].Data[index] );
			setrgb ( NORMAL_TEXT );
		}
	}
	else
	{
		SetFieldText ( OBD_MONITOR_COND_INDEX, "No Support" );

		SetFieldText ( IGNITION_COUNTER_INDEX, "No Support" );

		index = 2;
	}

	// set the remaining fields to 'Not Supported'
	for ( ;
		index < (gbDiesel == FALSE ? 28 : 18);
	      index += 2 )
	{
		SetFieldText ( OBD_MONITOR_COND_INDEX + index, "Not Supported       " );
	}
}


/*******************************************************************************
**
**  Function:  ReadIptFromLogFile
**
**  Purpose:
**
*******************************************************************************/
BOOL ReadIptFromLogFile ( const char * szTestSectionStart,
                          const char * szTestSectionEnd )
{
	char buf[256];
	BYTE EcuIdx;

	// log file should be open
	if ( gLogFileHandle == NULL )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTOFF, NO_PROMPT,
		      "Log File not open\n" );
		return FALSE;
	}

	// search from beginning of file
	fseek ( gLogFileHandle, 0, SEEK_SET );

	while ( fgets ( buf, sizeof ( buf ), gLogFileHandle ) != 0 )
	{
		if ( substring ( buf, szTestSectionStart ) != 0 )
		{
			for ( EcuIdx = 0;
			      EcuIdx < gNumOfECUs;
			      EcuIdx++ )
			{
				if ( ReadIpt ( szTestSectionEnd ) == FALSE)
				{
					break;
				}
			}
			fseek ( gLogFileHandle, 0, SEEK_END );

			return TRUE;
		}
	}

	// move to end of file
	fseek ( gLogFileHandle, 0, SEEK_END );

	return FALSE;
}


/*******************************************************************************
**
**  Function:  ReadIpt
**
**  Purpose:
**
*******************************************************************************/
BOOL ReadIpt ( const char* szTestSectionEnd )
{
	char         Buffer[256];
	char        *pSubString;
	int          CounterIndex;
	BYTE         EcuIdx;
	unsigned int EcuId = 0;


	// search for ECU ID
	while ( fgets ( Buffer, sizeof ( Buffer ), gLogFileHandle ) != 0 )
	{
		if ( substring ( Buffer, szTestSectionEnd ) != 0 )     // end of Test XX section
		{
			return FALSE;
		}

		if ( (pSubString = substring ( Buffer, szECUID )) != 0 )
		{
			pSubString += ECUID_Size;
			EcuId = strtoul ( pSubString, NULL, 16 );
			break;  // leave while (not end of file) loop
		}
	}

	// find EcuIdx
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( EcuId == GetEcuId ( EcuIdx ) )
		{
			break;  // leave ECU for loop
		}
	}

	if ( EcuIdx >= gNumOfECUs )
	{
		return FALSE;
	}

	// search for IPT INFOTYPE and SIZE
	while ( fgets ( Buffer, sizeof ( Buffer ), gLogFileHandle ) != 0 )
	{
		if ( substring ( Buffer, szTestSectionEnd ) != 0 )     // end of Test XX section
		{
			return FALSE;
		}

		if ( (pSubString = substring ( Buffer, szINF_SIZE )) != 0 )
		{
			pSubString += INF_SIZE_Size;
			gstEcuSIDData[EcuIdx].pTest10_10_Ipt->ID = (BYTE) strtoul ( pSubString, NULL, 16 );
			pSubString += 3;
			gstEcuSIDData[EcuIdx].pTest10_10_Ipt->NODI = (BYTE) strtod ( pSubString, NULL );
			break;  // leave while (not end of file) loop
		}
	}

	// read counters
	for ( CounterIndex = 0;
	      CounterIndex < gstEcuSIDData[EcuIdx].pTest10_10_Ipt->NODI;
	      CounterIndex++ )
	{
		fgets ( Buffer, sizeof ( Buffer), gLogFileHandle );

		if ( (gstEcuSIDData[EcuIdx].pTest10_10_Ipt->ID == 0x08 && (pSubString = substring ( Buffer, szINF8[CounterIndex] )) != 0 ) ||
		     (gstEcuSIDData[EcuIdx].pTest10_10_Ipt->ID == 0x0B && (pSubString = substring ( Buffer, szINFB[CounterIndex] )) != 0 ) )
		{
			pSubString = substring(pSubString, "=") + 1;
			gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[CounterIndex] = (unsigned short) strtoul ( pSubString, NULL, 10 );
		}
		else
		{
			return FALSE;
		}
	}

	// Sid 9 Inf 8 data valid
	gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Flags |= VALIDDATA;

	return TRUE;
}


/*******************************************************************************
**
**  Function:  SaveIptData
**
**  Purpose:
**
*******************************************************************************/
BOOL SaveIptData ( BYTE EcuIdx,
                   IPT *pIpt )
{
	int  index;
	BOOL bUpdated = FALSE;


	// save Infotype and NODI
	pTest11CurrentDisplayData[EcuIdx].ID = pIpt->ID;
	pTest11CurrentDisplayData[EcuIdx].NODI = pIpt->NODI;

	// copy current counter values for active ECUs
	for ( index = 0;
	      index < pIpt->NODI;
	      index++ )
	{
		// note changes
		if ( pTest11CurrentDisplayData[EcuIdx].Data[index] != pIpt->Data[index] )
		{
			// save current value of rate based counters
			pTest11CurrentDisplayData[EcuIdx].Data[index] = pIpt->Data[index];

			bUpdated = TRUE;
		}
	}

	return bUpdated;
}


/*******************************************************************************
**
**  Function:  UpdateIptDisplay
**
**  Purpose:
**
*******************************************************************************/
void UpdateIptDisplay ( BYTE         EcuIdx,
                        unsigned int IptStatusFlags,
                        IPT         *pIpt )
{
	int index;


	// if IPT data is supported
	if ( IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_GAS ) == TRUE ||
		 IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_DIESEL ) == TRUE )
	{
		// update OBDCOND counter
		if ( (IptStatusFlags & 0x01) == 0 )
		{
			setrgb ( HIGHLIGHTED_TEXT );
		}
		SetFieldDec ( OBD_MONITOR_COND_INDEX, pTest11CurrentDisplayData[EcuIdx].Data[0] );
		setrgb ( NORMAL_TEXT );

		// update IGN counter
		if ( ((IptStatusFlags >>= 1) & 0x01) == 0 )
		{
			setrgb ( HIGHLIGHTED_TEXT );
		}
		SetFieldDec ( IGNITION_COUNTER_INDEX, pTest11CurrentDisplayData[EcuIdx].Data[1] );
		setrgb ( NORMAL_TEXT );
	}
	else
	{
		SetFieldText ( OBD_MONITOR_COND_INDEX, "No Support" );

		SetFieldText ( IGNITION_COUNTER_INDEX, "No Support" );
	}


	// update rate based counter values
	for ( index = 2;
	      index < pIpt->NODI;
	      index++ )
	{
		if ( ((IptStatusFlags >>= 1) & 0x01) == 0 )
		{
			setrgb ( HIGHLIGHTED_TEXT );
		}
		SetFieldDec ( (IPT_CUR_INDEX+(index-2)), pIpt->Data[index] );
		setrgb ( NORMAL_TEXT );
	}
}


/*******************************************************************************
**
**  Function:  SavePid1Data
**
**  Purpose:
**
*******************************************************************************/
BOOL SavePid01Data ( BYTE EcuIdx )
{
	PID  *pPid;
	BOOL  bUpdated = FALSE;


	pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

	if ( pPid->ID == 1 )
	{
		// note any differences
		if ( pPreviousPid1[EcuIdx].Data[0] != pPid->Data[0] ||
		     pPreviousPid1[EcuIdx].Data[1] != pPid->Data[1] ||
		     pPreviousPid1[EcuIdx].Data[2] != pPid->Data[2] ||
		     pPreviousPid1[EcuIdx].Data[3] != pPid->Data[3] )
		{
			pPreviousPid1[EcuIdx].Data[0] = pPid->Data[0];
			pPreviousPid1[EcuIdx].Data[1] = pPid->Data[1];
			pPreviousPid1[EcuIdx].Data[2] = pPid->Data[2];
			pPreviousPid1[EcuIdx].Data[3] = pPid->Data[3];
			bUpdated = TRUE;
		}

		// if Oxygen Sensor (spark) or Exhaust Gas Sensor (compression) supported
		if ( pPid->Data[2] & 0x20 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x20) )
			{
				Test11IMStatus[EcuIdx][0] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x20) )
			{
				Test11IMStatus[EcuIdx][0] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][0] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][0] = NOTSUPPORTED;
		}

		// if Oxygen Sensor Heater (spark) or PM Filter (compression) supported
		if ( pPid->Data[2] & 0x40 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x40) )
			{
				Test11IMStatus[EcuIdx][1] = COMPLETE;

			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x40) )
			{
				Test11IMStatus[EcuIdx][1] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][1] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][1] = NOTSUPPORTED;
		}

		// if Catalyst (spark) or NMHC Catalyst (compression) supported
		if ( pPid->Data[2] & 0x01 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x01) )
			{
				Test11IMStatus[EcuIdx][2] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x01) )
			{
				Test11IMStatus[EcuIdx][2] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][2] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][2] = NOTSUPPORTED;
		}

		// if Heated Catalyst (spark) or NOx/SCR Aftertreatment (compression) supported
		if ( pPid->Data[2] & 0x02 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x02) )
			{
				Test11IMStatus[EcuIdx][3] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x02) )
			{
				Test11IMStatus[EcuIdx][3] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][3] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][3] = NOTSUPPORTED;
		}

		// if A/C supported
		if ( pPid->Data[2] & 0x10 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x10) )
			{
				Test11IMStatus[EcuIdx][4] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x10) )
			{
				Test11IMStatus[EcuIdx][4] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][4] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][4] = NOTSUPPORTED;
		}

		// if Evaportive Emissions (spark) supported
		if ( pPid->Data[2] & 0x04 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x04) )
			{
				Test11IMStatus[EcuIdx][5] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x04) )
			{
				Test11IMStatus[EcuIdx][5] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][5] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][5] = NOTSUPPORTED;
		}

		// if EGR/VVT (spark and compression) supported
		if ( pPid->Data[2] & 0x80 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x80) )
			{
				Test11IMStatus[EcuIdx][6] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x80) )
			{
				Test11IMStatus[EcuIdx][6] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][6] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][6] = NOTSUPPORTED;
		}

		// if Secondary Air (spark) or Boost Pressure (compression) supported
		if ( pPid->Data[2] & 0x08 )
		{
			// if completed
			if ( !(pPid->Data[3] & 0x08) )
			{
				Test11IMStatus[EcuIdx][7] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[2] & 0x08) )
			{
				Test11IMStatus[EcuIdx][7] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][7] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][7] = NOTSUPPORTED;
		}

		// if Comp / Comp supported
		if ( pPid->Data[1] & 0x04 )
		{
			Test11IMStatus[EcuIdx][10] = (pPid->Data[1] & 0x40) ? INCOMPLETE : COMPLETE;
		}
		else
		{
			Test11IMStatus[EcuIdx][10] = NOTSUPPORTED;
		}

		// if Fuel Trim supported
		if ( pPid->Data[1] & 0x02 )
		{
			// if completed
			if ( !(pPid->Data[1] & 0x20) )
			{
				Test11IMStatus[EcuIdx][8] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[1] & 0x02) )
			{
				Test11IMStatus[EcuIdx][8] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][8] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][8] = NOTSUPPORTED;
		}

		// if Misfire supported
		if ( pPid->Data[1] & 0x01 )
		{
			// if completed
			if ( !(pPid->Data[1] & 0x10) )
			{
				Test11IMStatus[EcuIdx][9] = COMPLETE;
			}
			// if disabled for this monitoring cycle
			else if ( !(pPid41[EcuIdx].Data[1] & 0x01) )
			{
				Test11IMStatus[EcuIdx][9] = DISABLED;
			}
			else
			{
				Test11IMStatus[EcuIdx][9] = INCOMPLETE;
			}
		}
		else
		{
			Test11IMStatus[EcuIdx][9] = NOTSUPPORTED;
		}
	}  //  end if ( pPid->ID == 1 )

	return bUpdated;
}


/*******************************************************************************
**
**  Function:  SavePid41Data
**
**  Purpose:
**
*******************************************************************************/
STATUS SavePid41Data ( void )
{
	REQ_MSG  stReqMsg;
	PID     *pPid;
	BYTE     EcuIdx;
	STATUS   eRetVal = FAIL;


	//-------------------------------------------
	// request SID 1 PID 41
	//-------------------------------------------
	stReqMsg.SID    = 0x01;
	stReqMsg.NumIds = 1;
	stReqMsg.ID[0]  = 0x41;
	if ( (eRetVal = RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE )) == PASS )
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( IsIDSupported ( EcuIdx, PIDREQUEST, 0x41 ) )
			{
				if ( gstResponse[EcuIdx].PidSize > 0 )
				{
					pPid = (PID *)&gstResponse[EcuIdx].Pid[0];

					gstEcuSIDData[EcuIdx].Pid41.Data[0] = pPid->Data[0];
					gstEcuSIDData[EcuIdx].Pid41.Data[1] = pPid->Data[1];
					gstEcuSIDData[EcuIdx].Pid41.Data[2] = pPid->Data[2];
					gstEcuSIDData[EcuIdx].Pid41.Data[3] = pPid->Data[3];
				}
			}
			else
			{
				gstEcuSIDData[EcuIdx].Pid41.Data[0] = 0xFF;
				gstEcuSIDData[EcuIdx].Pid41.Data[1] = 0xFF;
				gstEcuSIDData[EcuIdx].Pid41.Data[2] = 0xFF;
				gstEcuSIDData[EcuIdx].Pid41.Data[3] = 0xFF;
			}
		}
	}
	else
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			gstEcuSIDData[EcuIdx].Pid41.Data[0] = 0xFF;
			gstEcuSIDData[EcuIdx].Pid41.Data[1] = 0xFF;
			gstEcuSIDData[EcuIdx].Pid41.Data[2] = 0xFF;
			gstEcuSIDData[EcuIdx].Pid41.Data[3] = 0xFF;
		}
	}

	return eRetVal;
}


/*******************************************************************************
**
**  Function:  UpdatePid01Display
**
**  Purpose:
**
*******************************************************************************/
void UpdatePid01Display ( BYTE EcuIdx )
{
	int index;


	for ( index = 0;
	      index < 11;
	      index++ )
	{
		eCurrentIMStatus[index] = Test11IMStatus[EcuIdx][index];
		if ( Test11IMStatus[EcuIdx][index] == INCOMPLETE )
		{
			setrgb ( HIGHLIGHTED_TEXT );
		}
		else if ( Test11IMStatus[EcuIdx][index] == DISABLED )
		{
			setrgb ( RED_TEXT );
		}
		SetFieldText ( IM_READINESS_INDEX+index, szIM_Status[Test11IMStatus[EcuIdx][index]] );
		setrgb ( NORMAL_TEXT );
	}
}


/*******************************************************************************
**
**  Function:  RunDynamicTest11
**
**  Purpose:
**
*******************************************************************************/
STATUS RunDynamicTest11 ( BOOL          bDisplayCARBTimers,
                          unsigned long EngineStartTimestampMsecs )
{
	REQ_MSG        stReqMsg;
	PID           *pPid;
	BYTE           EcuIdx;
	STATUS         eRetVal = PASS;
	STATUS         eRetCode = PASS;

	BYTE           CurrentEcuIdx;
	unsigned int   EcuPageOffset = 0;
	unsigned int   EcuPage = 1;
	BOOL           bECUPageUpdate = FALSE;
	unsigned int   IptStatusFlags;           // Bit Map of ITP items completed for current EcuIdx
	unsigned int   IptId = 0;                // supported IPT data INF (8 or B), default 0 = no support

	BYTE           EcuDoneCount = 0;

	BOOL           bInf8Supported = FALSE;
	BOOL           bInfBSupported = FALSE;

	BYTE           SubTestStatusFlags = SUB_TEST_NORMAL;
	BYTE           LastTestStatusFlags = SUB_TEST_INITIAL; // set to force an update the first time

	// variables for CARB Timers
	unsigned long  LastCheckTimestampMsecs = 0;
	unsigned long  CurrentTimestampMsecs;
	unsigned short TestStartTimestampSecs;     // time the test started (in seconds)
	unsigned short LastCheckTimestampSecs = 0;
	unsigned short CheckDTCsTimerSecs = 0;     // # of seconds until DTCs are checked
	unsigned short IdleTimeSecs = 0;           // time at idle (in seconds, stops at 30)
	unsigned short AtSpeedTimeSecs = 0;        // time at speeds > 25mph (in seconds, stops at 300)
	unsigned short RPM = 0;                    // engine RPM (used if RUNTM is not supported)
	unsigned short SpeedMPH = 0;               // vehicle speed in MPH
	unsigned short SpeedKPH = 0;               // vehicle speed in KPH
	unsigned short RunTimeSecs = 0;            // engine run time (in seconds)
	BOOL           bRunTimeSupport;            // 1 = RUNTM PID supported
	unsigned int   TestState = 0xFF;
	unsigned int   TimeStatusFlags = 0;
	BOOL           bLoop;
	BOOL           bLogMessage;


	TestStartTimestampSecs = (unsigned short)(EngineStartTimestampMsecs / 1000);


	// determine PID support
	bRunTimeSupport = IsIDSupported ( ALLECUS, PIDREQUEST, 0x1F );

	if ( IsIDSupported ( ALLECUS, PIDREQUEST, 0x0C ) == FALSE &&
	     bRunTimeSupport == FALSE )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $01 PIDs $0C (RPM) and $1F (RUNTM) not supported\n" );
		bDisplayCARBTimers = FALSE;
	}

	// check for SID $09 INF support
	if ( IsIDSupported ( ALLECUS, INFREQUEST, INF_TYPE_IPT_GAS ) == TRUE )
	{
		bInf8Supported = TRUE;
	}

	if ( IsIDSupported ( ALLECUS, INFREQUEST, INF_TYPE_IPT_DIESEL ) == TRUE )
	{
		bInfBSupported = TRUE;
	}

	if ( bInf8Supported == FALSE &&
	     gbDiesel == FALSE &&
	     gModelYear >= 2010 &&
	     (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD ||
	      gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "INF $8 not supported (Required for MY 2010 and later Spark Ignition Vehicles)\n" );
	}
	else if ( bInfBSupported == FALSE &&
	          gbDiesel == TRUE &&
	          gModelYear >= 2010 &&
	          (gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD ||
	           gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD) )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "INF $B not supported (Required for MY 2010 and later Compression Ignition Vehicles)\n" );
	}

	// initialize static text elements based on INF support
	if ( bInf8Supported == TRUE && bInfBSupported == FALSE )
	{
		IptId = 0x08;
		init_screen ( _string_elements11_INF856, _num_string_elements11_INF856 );
	}

	else if ( bInf8Supported == FALSE && bInfBSupported == TRUE )
	{
		IptId = 0x0B;
		init_screen ( _string_elements11_INFB36, _num_string_elements11_INFB36 );
	}

	else if ( bInf8Supported == FALSE && bInfBSupported == FALSE )
	{
		// Verify that INF $8 or INF $B (IPT) is supported by at least one ECU for MY 2005 and later - OBD II
		// Verify that INF $8 or INF $B (IPT) is supported by at least one ECU - EOBD with IUMPR
		if ( ((gstUserInput.eComplianceType == US_OBDII || gstUserInput.eComplianceType == HD_OBD) &&
		      gModelYear >= 2005) ||
		     gstUserInput.eComplianceType == EOBD_WITH_IUMPR || gstUserInput.eComplianceType == HD_EOBD )
		{
			Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "SID $09 IPT (INF $08 or INF $0B) not supported\n" );
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "SID $09 IPT (INF $08 or INF $0B) not supported\n" );
		}

		if ( gbDiesel == FALSE )
		{
			init_screen ( _string_elements11_INF856, _num_string_elements11_INF856 );
		}
		else
		{
			init_screen ( _string_elements11_INFB36, _num_string_elements11_INFB36 );
		}
	}

	else if ( bInf8Supported == TRUE && bInfBSupported == TRUE )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $09 IPT (INF $08 and INF $0B) both supported\n" );

		if ( gbDiesel == FALSE )
		{
			IptId = 0x08;
			init_screen ( _string_elements11_INF856, _num_string_elements11_INF856 );
		}
		else
		{
			IptId = 0x0B;
			init_screen ( _string_elements11_INFB36, _num_string_elements11_INFB36 );
		}
	}


	// display CARB Timers, if required
	if ( bDisplayCARBTimers == TRUE )
	{
		short x, y;

		// add CARB Timer display text to the screen
		get_cursor_pos ( &x, &y );
		place_screen_text ( _string_elements_timers, _num_string_elements_timers );
		gotoxy ( x, y );
		SetFieldDec ( IDLE_TIMER, IdleTimeSecs );
		SetFieldDec ( SPEED_25_MPH_TIMER, AtSpeedTimeSecs );
		SetFieldDec ( TOTAL_DRIVE_TIMER, RunTimeSecs );
	}


	// save SID 1 PID $41
	SavePid41Data ( );


	// initialize screen
	for ( EcuIdx=0;
	      EcuIdx < gNumOfECUs &&
	      EcuIdx < MAX_ECUS_PER_PAGE;
	      EcuIdx++ )
	{
		SetFieldHex ( ECU_ID_INDEX+EcuIdx, GetEcuId ( EcuIdx ) );

		// If I/M Readiness not supported for the current ECU, mark it as done
		if ( IsIDSupported ( EcuIdx, PIDREQUEST, 0x01 ) == FALSE )
		{
			pTest11CurrentDisplayData[EcuIdx].Flags |= IMREADYDONE;
		}

		// If IPT not supported for the current ECU, mark it as done
		if ( IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_GAS ) == FALSE &&
		     IsIDSupported ( EcuIdx, INFREQUEST, INF_TYPE_IPT_DIESEL ) == FALSE )
		{
			pTest11CurrentDisplayData[EcuIdx].Flags |= IPTDONE;

			if ( gbDiesel == FALSE )
			{
				pTest11CurrentDisplayData[EcuIdx].NODI = 20;
				gstEcuSIDData[EcuIdx].pTest10_10_Ipt->NODI = 20;
			}
			else
			{
				pTest11CurrentDisplayData[EcuIdx].NODI = 18;
				gstEcuSIDData[EcuIdx].pTest10_10_Ipt->NODI = 18;
			}
		}

		// If I/M Readiness and IPT are done for the curnent ECU, mark the ECU as done
		if ( (pTest11CurrentDisplayData[EcuIdx].Flags & IMREADYDONE) != 0 &&
		     (pTest11CurrentDisplayData[EcuIdx].Flags & IPTDONE) != 0 )
		{
			pTest11CurrentDisplayData[EcuIdx].Flags |= ECUDONE;
			EcuDoneCount++;
			SetFieldText ( ECU_STATUS_INDEX+EcuIdx, "N/A" );
		}
	}
	SetFieldDec ( ECU_PAGE_INDEX, EcuPage );
	EcuPageOffset = 0;

	CurrentEcuIdx = 0;

	IptStatusFlags = 0xFFFFFFFF;   // by default all items completed
	EvaluateIpt ( CurrentEcuIdx, &IptStatusFlags, FALSE );

	SelectECU ( CurrentEcuIdx, -1, EcuPageOffset );
	DisplayEcuData ( CurrentEcuIdx, IptStatusFlags );


	// flush the STDIN stream of any user input before loop
	ClearKeyboardBuffer ( );

	CurrentTimestampMsecs = LastCheckTimestampMsecs = GetTickCount ( );

	gbSuspendLogOutput = TRUE;
	gbSuspendScreenOutput = TRUE;
	//-------------------------------------------
	// loop until test completes
	//-------------------------------------------
	for ( ; ; )
	{
		//-------------------------------------------
		// request SID 1 PID 1
		//-------------------------------------------
		stReqMsg.SID    = 0x01;
		stReqMsg.NumIds = 1;
		stReqMsg.ID[0]  = 0x01;
		eRetVal = RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE );

		bLogMessage = FALSE;

		if ( eRetVal == FAIL )
		{
			Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
			      "SID $01 PID $01 request\n" );
			DumpTransactionBuffer ( );
		}
		else
		{
			if ( eRetVal == ERRORS )
			{
				// early/late message, note it and keep going
				SubTestStatusFlags |= SUB_TEST_FAIL;
				bLogMessage = TRUE;
			}

			for ( EcuIdx = 0;
			      EcuIdx < gNumOfECUs;
			      EcuIdx++ )
			{
				if ( gstResponse[EcuIdx].PidSize > 0 )
				{
					if ( SavePid01Data ( EcuIdx ) == TRUE ||
					     LastTestStatusFlags == SUB_TEST_INITIAL )
					{
						bLogMessage = TRUE;

						pPid = (PID *)&gstResponse[EcuIdx].Pid[0];
						if ( IsIM_ReadinessComplete ( pPid ) == TRUE )
						{
							pTest11CurrentDisplayData[EcuIdx].Flags |= IMREADYDONE;
						}

						if ( EcuIdx == EcuPageOffset+CurrentEcuIdx )
						{
							UpdatePid01Display ( EcuIdx );
						}
					}
				}
			}

			if ( bLogMessage == TRUE )
			{
				LogLastTransaction ( );
			}
		}

		//-------------------------------------------
		// Get SID 9 IPT
		//-------------------------------------------
		if ( IptId != 0 )
		{
			stReqMsg.SID    = 0x09;
			stReqMsg.NumIds = 1;
			stReqMsg.ID[0]  = IptId;
			eRetVal = RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE );

			bLogMessage = FALSE;

			if ( eRetVal == FAIL )
			{
				Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
				      "SID $09 IPT request\n" );
				DumpTransactionBuffer ( );
			}
			else
			{
				if ( eRetVal == ERRORS )
				{
					// early/late message, note it and keep going
					SubTestStatusFlags |= SUB_TEST_FAIL;
					bLogMessage = TRUE;
				}

				for ( EcuIdx = 0;
				      EcuIdx < gNumOfECUs;
				      EcuIdx++ )
				{
					if ( GetIptData ( EcuIdx, &pTest11_5_Ipt[EcuIdx] ) == PASS )
					{
						if ( SaveIptData ( EcuIdx, &pTest11_5_Ipt[EcuIdx] ) == TRUE ||
						     LastTestStatusFlags == SUB_TEST_INITIAL )
						{
							bLogMessage = TRUE;
						}
					}
				}

				if ( bLogMessage == TRUE )
				{
					// something changed, update the display because EVAP from one ECU
					// could affect another ECU's display
					for ( EcuIdx = 0;
					      EcuIdx < gNumOfECUs;
					      EcuIdx++ )
					{
						IptStatusFlags = 0xFFFFFFFF;   // by default all items completed
						eRetVal = EvaluateIpt ( EcuIdx, &IptStatusFlags, FALSE );
						if ( (eRetVal & FAIL) == PASS )
						{
							pTest11CurrentDisplayData[EcuIdx].Flags |= IPTDONE;
							if ( (eRetVal & ERRORS) == ERRORS )
							{
								SubTestStatusFlags |= SUB_TEST_FAIL;
							}
						}

						if ( EcuIdx == EcuPageOffset+CurrentEcuIdx )
						{
							UpdateIptDisplay ( EcuIdx, IptStatusFlags, &pTest11_5_Ipt[EcuIdx] );
						}
					}

					LogLastTransaction ( );
				}
			}
		}


		if ( bDisplayCARBTimers == TRUE )
		{
			//-------------------------------------------
			// request RPM - SID 1 PID $0C
			//-------------------------------------------
			if ( bRunTimeSupport == FALSE )
			{
				stReqMsg.SID    = 0x01;
				stReqMsg.NumIds = 1;
				stReqMsg.ID[0]  = 0x0C;
				eRetVal = RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE );

				bLogMessage = FALSE;

				if ( eRetVal == FAIL )
				{
					Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "SID $01 PID $0C request\n" );
					DumpTransactionBuffer ( );
				}
				else
				{
					if ( eRetVal != PASS )
					{
						// cover the case where a response was early/late
						SubTestStatusFlags |= SUB_TEST_FAIL;
						bLogMessage = TRUE;
					}

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

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

								// convert from 1 cnt = 1/4 RPM to 1 cnt = 1 RPM
								RPM >>= 2;
								break;  // leave ECU for loop
							}
						}
					}

					if ( EcuIdx >= gNumOfECUs )
					{
						Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
						      "SID $01 PID $0C missing response\n" );
						SubTestStatusFlags |= SUB_TEST_FAIL;
						bLogMessage = TRUE;
					}

					if ( bLogMessage == TRUE )
					{
						LogLastTransaction ( );
					}
				}
			}

			//-------------------------------------------
			// request Speed - SID 1 PID $0D
			//-------------------------------------------
			stReqMsg.SID    = 0x01;
			stReqMsg.NumIds = 1;
			stReqMsg.ID[0]  = 0x0D;
			eRetVal = RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE );

			bLogMessage = FALSE;

			if ( eRetVal == FAIL )
			{
				Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
				      "SID $01 PID $0D request\n" );
				DumpTransactionBuffer ( );
			}
			else
			{
				if ( eRetVal != PASS )
				{
					// cover the case where a response was early/late
					SubTestStatusFlags |= SUB_TEST_FAIL;
					bLogMessage = TRUE;
				}

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

						if ( pPid->ID == 0x0D )
						{
							double dTemp = pPid->Data[0];

							SpeedKPH = pPid->Data[0];

							// convert from km/hr to mile/hr
							SpeedMPH = (unsigned short)( ((dTemp * 6214) / 10000) + 0.5 );
							break;  // leave ECU for loop
						}
					}
				}

				if ( EcuIdx >= gNumOfECUs )
				{
					Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "SID $01 PID $0D missing response\n" );
					SubTestStatusFlags |= SUB_TEST_FAIL;
					bLogMessage = TRUE;
				}

				if ( bLogMessage == TRUE )
				{
					LogLastTransaction ( );
				}
			}

			//-------------------------------------------
			// request engine RunTime - SID 1 PID $1F
			//-------------------------------------------
			if ( bRunTimeSupport == TRUE )
			{
				stReqMsg.SID    = 0x01;
				stReqMsg.NumIds = 1;
				stReqMsg.ID[0]  = 0x1F;
				eRetVal = RequestSid ( &stReqMsg, REQ_MSG_NO_PERIODIC_DISABLE );

				bLogMessage = FALSE;

				if ( eRetVal == FAIL )
				{
					Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "SID $01 PID $1F request\n" );
					DumpTransactionBuffer ( );
				}
				else
				{
					if ( eRetVal != PASS )
					{
						// cover the case where a response was early/late
						SubTestStatusFlags |= SUB_TEST_FAIL;
						bLogMessage = TRUE;
					}

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

							if ( pPid->ID == 0x1F )
							{
								RunTimeSecs = pPid->Data[0];
								RunTimeSecs = (RunTimeSecs << 8) | (pPid->Data[1]);    // 1 cnt = 1 sec
								break;  // leave ECU for loop
							}
						}
					}

					if ( EcuIdx >= gNumOfECUs )
					{
						Log ( FAILURE, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
						      "SID $01 PID $1F missing response\n" );
						SubTestStatusFlags |= SUB_TEST_FAIL;
						bLogMessage = TRUE;
					}

					if ( bLogMessage == TRUE )
					{
						LogLastTransaction ( );
					}
				}
			}
			else
			{
				RunTimeSecs = (unsigned short)(GetTickCount ( ) / 1000) - TestStartTimestampSecs;
			}


			SetFieldDec ( TOTAL_DRIVE_TIMER, RunTimeSecs );

			//-------------------------------------------
			// Determine phase of dynamic test
			// update screen
			//-------------------------------------------
			bLoop = TRUE;
			while ( bLoop )
			{
				bLoop = FALSE;
				switch ( TestState )
				{
					case 0xFF:   // First Time ONLY - covers the case were the engine has already been idling
					{
						LastCheckTimestampSecs = RunTimeSecs;

						if ( (bRunTimeSupport == TRUE) ? (RunTimeSecs > 0) : (RPM > 450) )
						{

							if ( SpeedMPH <= 1 )
							{
								TestState = 1;
								IdleTimeSecs = RunTimeSecs;
								bLoop = TRUE;
								break;
							}
						}

						// engine is not running or SpeedMPH >1... don't know if there was an idle
						// set-up to intentionally fall thru to case 0
						TestState = 0;
					}
					//  0xFF falls through

					case 0:     // wait until idle  (RunTimeSecs > 0 or RPM > 450)
					{
						if ( (bRunTimeSupport == TRUE) ? (RunTimeSecs > 0) : (RPM > 450) )
						{
							// check 600 seconds cumulative time
							if ( (TimeStatusFlags & CUMULATIVE_TIME) != CUMULATIVE_TIME &&
							     RunTimeSecs >= 600 )
							{
								TimeStatusFlags |= CUMULATIVE_TIME;
								SaveTransactionStart ( ); // treat as a seperate transaction to avoid duplication
								Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "Idle Time = %d;  Speed Time = %d;  Run Time = %d  *RUN TIME DONE*\n",
								      IdleTimeSecs, AtSpeedTimeSecs, RunTimeSecs );
								LogLastTransaction ( );
							}

							if ( SpeedMPH <= 1 &&
							     IdleTimeSecs < 30 )
							{
								TestState = 1;
								IdleTimeSecs = 0;
								bLoop = TRUE;
							}
							else if ( SpeedMPH >= 25 &&
							          AtSpeedTimeSecs < 300 )
							{
								TestState = 2;
								bLoop = TRUE;
							}
							else if ( TimeStatusFlags == (IDLE_TIME | ATSPEED_TIME | CUMULATIVE_TIME) )
							{
								TestState = 3;
								bLoop = TRUE;
							}
							else
							{
								LastCheckTimestampSecs = RunTimeSecs;
							}
						}
					}
					break;

					case 1:     // 30 seconds continuous time at idle
					{
						if ( SpeedMPH <= 1 &&
						     (bRunTimeSupport == FALSE) ? (RPM > 450) : 1 )
						{
							// check idle time
							IdleTimeSecs = min ( IdleTimeSecs + (RunTimeSecs - LastCheckTimestampSecs), 30 );
							LastCheckTimestampSecs = RunTimeSecs;

							SetFieldDec ( IDLE_TIMER, IdleTimeSecs );

							if ( IdleTimeSecs >= 30 )
							{
								TimeStatusFlags |= IDLE_TIME;
								TestState = 0;
								bLoop = TRUE;
								SaveTransactionStart ( ); // treat as a seperate transaction to avoid duplication
								Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "Idle Time = %d;  Speed Time = %d;  Run Time = %d  *IDLE DONE*\n",
								      IdleTimeSecs, AtSpeedTimeSecs, RunTimeSecs );
								LogLastTransaction ( );
							}

							// check 600 seconds cumulative time
							if ( (TimeStatusFlags & CUMULATIVE_TIME) != CUMULATIVE_TIME &&
							     RunTimeSecs >= 600 )
							{
								TimeStatusFlags |= CUMULATIVE_TIME;
								SaveTransactionStart ( ); // treat as a seperate transaction to avoid duplication
								Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "Idle Time = %d;  Speed Time = %d;  Run Time = %d  *RUN TIME DONE*\n",
								      IdleTimeSecs, AtSpeedTimeSecs, RunTimeSecs );
								LogLastTransaction ( );
							}
						}
						else
						{
							TestState = 0;
							bLoop = TRUE;
						}
					}
					break;

					case 2:     // 300 seconds cumulative time at SpeedMPH >= 25 MPH
					{
						if ( SpeedMPH >= 25 &&
						     (bRunTimeSupport == FALSE) ? (RPM > 450) : 1 )
						{
							// check at speed time
							AtSpeedTimeSecs = min ( AtSpeedTimeSecs + (RunTimeSecs - LastCheckTimestampSecs), 300 );
							LastCheckTimestampSecs = RunTimeSecs;

							SetFieldDec ( SPEED_25_MPH_TIMER, AtSpeedTimeSecs );

							if ( AtSpeedTimeSecs >= 300 )
							{
								TimeStatusFlags |= ATSPEED_TIME;
								TestState = 0;
								bLoop = TRUE;
								SaveTransactionStart ( ); // treat as a seperate transaction to avoid duplication
								Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "Idle Time = %d;  Speed Time = %d;  Run Time = %d  *AT SPEED DONE*\n",
								      IdleTimeSecs, AtSpeedTimeSecs, RunTimeSecs );
								LogLastTransaction ( );
							}

							// check 600 seconds cumulative time
							if ( (TimeStatusFlags & CUMULATIVE_TIME) != CUMULATIVE_TIME &&
							     RunTimeSecs >= 600 )
							{
								TimeStatusFlags |= CUMULATIVE_TIME;
								SaveTransactionStart ( ); // treat as a seperate transaction to avoid duplication
								Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
								      "Idle Time = %d;  Speed Time = %d;  Run Time = %d  *RUN TIME DONE*\n",
								      IdleTimeSecs, AtSpeedTimeSecs, RunTimeSecs );
								LogLastTransaction ( );
							}
						}
						else
						{
							TestState = 0;
							bLoop = TRUE;
						}
					}
					break;

					default:     // 'idle' and 'at speed' times done
					{

					}
					break;
				} // end switch (TestState)
			} // end while (bLoop)
		} // end if ( bDisplayCARBTimers == TRUE)


		//-------------------------------------------
		// Check for DTCs
		//-------------------------------------------
		if ( CheckDTCsTimerSecs <= 0 )
		{
			// initially clear the DTC flag
			SubTestStatusFlags &= (~SUB_TEST_DTC);

			eRetVal = IsDTCPending ( (REQ_MSG_NO_PERIODIC_DISABLE|REQ_MSG_ALLOW_NO_RESPONSE) );
			if ( eRetVal == PASS )
			{
				// log and flag the pending DTCs
				LogLastTransaction ( );
				SubTestStatusFlags |= SUB_TEST_DTC;
			}
			else if ( eRetVal == ERRORS )
			{
				// log the error
				LogLastTransaction ( );
			}

			eRetVal = IsDTCStored ( (REQ_MSG_NO_PERIODIC_DISABLE|REQ_MSG_ALLOW_NO_RESPONSE) );
			if ( eRetVal == PASS )
			{
				// log and flag the stored DTCs
				LogLastTransaction ( );
				SubTestStatusFlags |= SUB_TEST_DTC;
			}
			else if ( eRetVal == ERRORS )
			{
				// log the error
				LogLastTransaction ( );
			}

#ifdef _DEBUG
			CheckDTCsTimerSecs = 2;
#else
			CheckDTCsTimerSecs = 30;
#endif
		}


		// update on-screen test status
		if ( gbTestSubsectionFailed )
		{
			// some function logged a FAILURE
			SubTestStatusFlags |= SUB_TEST_FAIL;
		}

		if ( SubTestStatusFlags != LastTestStatusFlags )
		{
			if ( (SubTestStatusFlags & SUB_TEST_FAIL) == SUB_TEST_FAIL )
			{
				setrgb ( HIGHLIGHTED_TEXT );
				SetFieldText ( IPT_TESTSTATUS_INDEX, "FAILURE" );
				setrgb ( NORMAL_TEXT );
			}
			else
			{
				SetFieldText ( IPT_TESTSTATUS_INDEX, "Normal" );
			}

			if ( (SubTestStatusFlags & SUB_TEST_DTC) == SUB_TEST_DTC )
			{
				setrgb ( HIGHLIGHTED_TEXT );
				SetFieldText ( IPT_TESTSTATUS_INDEX + 1, "DTC Detected" );
				setrgb ( NORMAL_TEXT );
			}
			else
			{
				SetFieldText ( IPT_TESTSTATUS_INDEX + 1, "             " );
			}

			LastTestStatusFlags = SubTestStatusFlags;
		}

		//-------------------------------------------
		// Check if test is complete
		//-------------------------------------------
		for ( EcuIdx=0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			if ( (pTest11CurrentDisplayData[EcuIdx].Flags & ECUDONE) == 0 )
			{
				if ( (pTest11CurrentDisplayData[EcuIdx].Flags & IMREADYDONE) != 0 &&
				     (pTest11CurrentDisplayData[EcuIdx].Flags & IPTDONE) != 0 )
				{
					pTest11CurrentDisplayData[EcuIdx].Flags |= ECUDONE;
					if ( EcuIdx >= EcuPageOffset &&
					     EcuIdx < (EcuPageOffset+MAX_ECUS_PER_PAGE) )
					{
						SetFieldText ( ECU_STATUS_INDEX+(EcuIdx-EcuPageOffset), "Done" );
					}
					EcuDoneCount++;
				}
			}
		}

		if ( EcuDoneCount == gNumOfECUs )
		{
			if ( (SubTestStatusFlags & SUB_TEST_FAIL) == SUB_TEST_FAIL )
			{
				eRetCode =  FAIL;
			}
			else
			{
				eRetCode =  PASS;
				break;  // leave infinite for loop
			}
		}

		//-------------------------------------------
		// Check for num or ESC key, delay 1 second
		//-------------------------------------------
		do
		{
			if ( _kbhit ( ) != 0 )
			{
				char c = _getch ( );
				if ( c == 27 )                    // ESC key
				{
					gbSuspendScreenOutput = FALSE;
					gbSuspendLogOutput = FALSE;
					Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "Test 11 aborted by user\n\n" );
					eRetCode = ABORT;
				}

				else if ( c == 'F' || c == 'f')   // "FAIL" key
				{
					gbSuspendScreenOutput = FALSE;
					gbSuspendLogOutput = FALSE;
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "Test 11 failed by user\n\n" );
					eRetCode = FAIL;
				}

				else if ( c >='1' && c <= '8' )   // new ECU index
				{
					EcuIdx = (c - '1');         // zero-based index
					if ( EcuPageOffset+EcuIdx < gNumOfECUs &&
					     EcuIdx != CurrentEcuIdx )
					{
						IptStatusFlags = 0xFFFFFFFF;   // by default all items completed
						EvaluateIpt ( EcuPageOffset+EcuIdx, &IptStatusFlags, FALSE );

						SelectECU ( EcuIdx, CurrentEcuIdx, EcuPageOffset );
						DisplayEcuData ( EcuPageOffset+EcuIdx, IptStatusFlags );
						CurrentEcuIdx = EcuIdx;
					}
				}

				else
				{
					if ( c == 73 )  //PGUP
					{
						if ( EcuPage < MAX_ECU_PAGE &&
						     EcuPageOffset+MAX_ECUS_PER_PAGE < gNumOfECUs )
						{
							EcuPageOffset += MAX_ECUS_PER_PAGE;
							EcuPage++;
							bECUPageUpdate = TRUE;
						}
					}

					else if ( c == 81 )  //PGDN
					{
						if ( EcuPage > 1 )
						{
							EcuPageOffset -= MAX_ECUS_PER_PAGE;
							EcuPage--;
							bECUPageUpdate = TRUE;
						}
					}
				}

				if ( bECUPageUpdate == TRUE )
				{
					// Update ECU page number
					SetFieldDec ( ECU_PAGE_INDEX, EcuPage );
					bECUPageUpdate = FALSE;

					for ( EcuIdx=0;
					      EcuIdx < MAX_ECUS_PER_PAGE;
					      EcuIdx++ )
					{
						SetFieldHex ( ECU_ID_INDEX+EcuIdx, GetEcuId ( EcuPageOffset+EcuIdx ) );

						if ( IsIDSupported ( EcuPageOffset+EcuIdx, PIDREQUEST, 0x01 ) == FALSE )
						{
							pTest11CurrentDisplayData[EcuPageOffset+EcuIdx].Flags |= IMREADYDONE;
						}

						if ( IsIDSupported ( EcuPageOffset+EcuIdx, INFREQUEST, INF_TYPE_IPT_GAS ) == FALSE &&
						     IsIDSupported ( EcuPageOffset+EcuIdx, INFREQUEST, INF_TYPE_IPT_DIESEL ) == FALSE )
						{
							pTest11CurrentDisplayData[EcuPageOffset+EcuIdx].Flags |= IPTDONE;

							if ( gbDiesel == FALSE )
							{
								pTest11CurrentDisplayData[EcuPageOffset+EcuIdx].NODI = 20;
								gstEcuSIDData[EcuPageOffset+EcuIdx].pTest10_10_Ipt->NODI = 20;
							}
							else
							{
								pTest11CurrentDisplayData[EcuPageOffset+EcuIdx].NODI = 18;
								gstEcuSIDData[EcuPageOffset+EcuIdx].pTest10_10_Ipt->NODI = 18;
							}
						}

						if ( (pTest11CurrentDisplayData[EcuPageOffset+EcuIdx].Flags & ECUDONE) != 0 )
						{
							SetFieldText ( ECU_STATUS_INDEX+EcuIdx, "Done" );
						}
						else
						{
							SetFieldText ( ECU_STATUS_INDEX+EcuIdx, "    " );
						}
					}

					CurrentEcuIdx = 0;
					IptStatusFlags = 0xFFFFFFFF;   // by default all items completed
					EvaluateIpt ( EcuPageOffset+CurrentEcuIdx, &IptStatusFlags, FALSE );

					SelectECU ( CurrentEcuIdx, -1, EcuPageOffset );
					DisplayEcuData ( EcuPageOffset+CurrentEcuIdx, IptStatusFlags );
				}
			}

			CurrentTimestampMsecs = GetTickCount ( );

			Sleep ( min ( 1000 - (CurrentTimestampMsecs - LastCheckTimestampMsecs), 50 ) );

		} while ( CurrentTimestampMsecs - LastCheckTimestampMsecs < 1000 );

		LastCheckTimestampMsecs = CurrentTimestampMsecs;
		CheckDTCsTimerSecs--;

		if ( eRetCode != PASS )
		{
			break;  // leave infinite for loop
		}
	} // end for (;;)


	gbSuspendScreenOutput = FALSE;
	gbSuspendLogOutput = FALSE;
	PrintEcuData ( IptId );

	if ( bDisplayCARBTimers == TRUE )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Idle Time = %d;  Speed Time = %d;  Run Time = %d\n",
		      IdleTimeSecs, AtSpeedTimeSecs, RunTimeSecs );
	}

	if ( eRetCode == ABORT )
	{
		ABORT_RETURN;
	}
	return eRetCode;
}


/*******************************************************************************
**
**  Function:  PrintEcuData
**
**  Purpose:
**
*******************************************************************************/
void PrintEcuData ( unsigned int IptId )
{
	BYTE          EcuIdx;
	unsigned int  index;
	unsigned int  pindex;

	unsigned int   IptStatusFlags;           // Bit Map of ITP items completed for current EcuIdx



	Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
	      "On exit from Test 11.2 the following were the conditions:\n" );

	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
		      "ECU ID: %02X    Status: %s\n",
		      GetEcuId ( EcuIdx ),
		      (pTest11CurrentDisplayData[EcuIdx].Flags&ECUDONE) ? "Done" : "    " );


		// write IM Status
		pindex = IMSTATUS_ELEMENT_INDEX;
		Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
		      "%s\n",
		      _string_elements11_INF856[pindex++] );
		for ( index = 0;
		      index < 11;
		      index++, pindex++ )
		{
			if ( gbDiesel == TRUE )
			{
				Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
				      "%-25s  %s\n",
				      _string_elements11_INFB36[pindex].szLabel,
				      szIM_Status[Test11IMStatus[EcuIdx][index]] );
			}
			else
			{
				Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
				      "%-25s  %s\n",
				      _string_elements11_INF856[pindex].szLabel,
				      szIM_Status[Test11IMStatus[EcuIdx][index]] );
			}
		}

		if ( IptId == 0 )
		{
			Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
			      "No IUMPR data because SID $09 IPT (INF $08 or INF $0B) not supported.\n" );
		}
		else
		{
			// write rate based counter
			Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
			      "%-25s  Initial     Current\n", _string_elements11_INF856[pindex++] );
			for ( index = 0;
			      index < 2;
			      index++, pindex++ )
			{
				if ( gbDiesel == TRUE )
				{
					Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "%-25s  %-8d    %-8d\n",
					      _string_elements11_INFB36[pindex].szLabel,
					      gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index],
					      pTest11CurrentDisplayData[EcuIdx].Data[index] );
				}
				else
				{
					Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "%-25s  %-8d    %-8d\n",
					      _string_elements11_INF856[pindex].szLabel,
					      gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index],
					      pTest11CurrentDisplayData[EcuIdx].Data[index] );
				}
			}

			pindex = COUNTER_ELEMENT_INDEX;
			Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
			      "%-25s  N    D      N    D\n", " " );
			for ( ;
			      index < (unsigned)(pTest11CurrentDisplayData[EcuIdx].NODI);
			      index += 2, pindex++ )
			{
				if ( gbDiesel == TRUE )
				{
					Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "%-25s  %-4d %-4d   %-4d %-4d\n",
					      _string_elements11_INFB36[pindex].szLabel,
					      gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index],
					      gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index+1],
					      pTest11CurrentDisplayData[EcuIdx].Data[index],
					      pTest11CurrentDisplayData[EcuIdx].Data[index+1] );
				}
				else
				{
					Log ( INFORMATION, SCREENOUTPUTOFF, LOGOUTPUTON, NO_PROMPT,
					      "%-25s  %-4d %-4d   %-4d %-4d\n",
					      _string_elements11_INF856[pindex].szLabel,
					      gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index],
					      gstEcuSIDData[EcuIdx].pTest10_10_Ipt->Data[index+1],
					      pTest11CurrentDisplayData[EcuIdx].Data[index],
					      pTest11CurrentDisplayData[EcuIdx].Data[index+1] );
				}
			}

			if ( !(pTest11CurrentDisplayData[EcuIdx].Flags & ECUDONE) )
			{
				IptStatusFlags = 0xFFFFFFFF;   // by default all items completed
				EvaluateIpt ( EcuIdx, &IptStatusFlags, TRUE );
			}

			Log ( BLANK, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT, "\n" );

		}
	}
}


/*******************************************************************************
**
**  Function:  AllocateMemoryForTest11_PerformanceCounters
**
**  Purpose:
**
*******************************************************************************/
void AllocateMemoryForTest11_PerformanceCounters ( void )
{
	BYTE          EcuIdx;
	unsigned int  IMReadinessIndex;


	if ( (pTest11_Pid01 = (PID *) malloc ( sizeof ( PID ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for pTest11_Pid01.",
		      sizeof ( PID ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	memset ( pTest11_Pid01,
	         0x00,
	         sizeof ( PID ) * gNumOfECUsForAlloc );

	if ( (pPreviousPid1 = (PID *) malloc ( sizeof ( PID ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for pPreviousPid1.",
		      sizeof ( PID ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	memset ( pPreviousPid1,
	         0x00,
	         sizeof ( PID ) * gNumOfECUsForAlloc );

	if ( (pPid41 = (PID *) malloc ( sizeof ( PID ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for pPid41.",
		      sizeof ( PID ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	memset ( pPid41,
	         0xFF,
	         sizeof ( PID ) * gNumOfECUsForAlloc );

	if ( (pTest11_5_Ipt = (IPT *) malloc ( sizeof ( IPT ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for pTest11_5_Ipt.",
		      sizeof ( IPT ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	memset ( pTest11_5_Ipt,
	         0x00,
	         sizeof ( IPT ) * gNumOfECUsForAlloc );

	if ( (pTest11_11_Ipt = (IPT *) malloc ( sizeof ( IPT ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for pTest11_11_Ipt.",
		      sizeof ( IPT ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	memset ( pTest11_11_Ipt,
	         0x00,
	         sizeof ( IPT ) * gNumOfECUsForAlloc );

	if ( (pTest11CurrentDisplayData = (IPT *) malloc ( sizeof ( IPT ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for pTest11CurrentDisplayData.",
		      sizeof ( IPT ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	memset ( pTest11CurrentDisplayData,
	         0x00,
	         sizeof ( IPT ) * gNumOfECUsForAlloc );

	if ( (Test11IMStatus = (enum IM_Status **) malloc( sizeof ( enum IM_Status * ) * gNumOfECUsForAlloc )) == NULL )
	{
		Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
		      "Unable to allocate memory (%d bytes) for Test11IMStatus.",
		      sizeof ( enum IM_Status ) * gNumOfECUsForAlloc );
		exit ( FAIL );
	}
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		if ( (Test11IMStatus[EcuIdx] = (enum IM_Status *) malloc ( sizeof ( enum IM_Status ) * 11 )) == NULL )
		{
			Log ( ERROR_FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_PROMPT,
			      "Unable to allocate memory (%d bytes) for Test11IMStatus[%d].",
			      sizeof ( enum IM_Status ) * 11,
			      EcuIdx );
			exit ( FAIL );
		}
	}
	for ( IMReadinessIndex = 0;
	      IMReadinessIndex < 11;
	      IMReadinessIndex++ )
	{
		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			Test11IMStatus[EcuIdx][IMReadinessIndex] = NOTSUPPORTED;
		}
		eCurrentIMStatus[IMReadinessIndex] = INVALID;
	}
}


/*******************************************************************************
**
**  Function:  FreeMemoryForTest11_PerformanceCounters
**
**  Purpose:
**
*******************************************************************************/
void FreeMemoryForTest11_PerformanceCounters ( void )
{
	BYTE  EcuIdx;


	free ( pTest11_Pid01 );

	free ( pPreviousPid1 );

	free ( pPid41 );
	
	free( pTest11_5_Ipt );

	free ( pTest11_11_Ipt );

	free ( pTest11CurrentDisplayData );

	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		free ( Test11IMStatus[EcuIdx] );

		// free informantion leftover from Test 10
		free ( gstEcuSIDData[EcuIdx].pTest10_10_Ipt );
		free ( gstEcuSIDData[EcuIdx].pTest10_10_FEOCNTR );
		free ( gstEcuSIDData[EcuIdx].pIpt );
	}

	free ( Test11IMStatus );
}
