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


/*******************************************************************************
**  Typedefs and function pointers for J2534 API
*******************************************************************************/
typedef long (CALLBACK* PTCONNECT)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long *);
typedef long (CALLBACK* PTDISCONNECT)(unsigned long);
typedef long (CALLBACK* PTREADMSGS)(unsigned long, void *, unsigned long *, unsigned long);
typedef long (CALLBACK* PTWRITEMSGS)(unsigned long, void *, unsigned long *, unsigned long);
typedef long (CALLBACK* PTSTARTPERIODICMSG)(unsigned long, void *, unsigned long *, unsigned long);
typedef long (CALLBACK* PTSTOPPERIODICMSG)(unsigned long, unsigned long);
typedef long (CALLBACK* PTSTARTMSGFILTER)(unsigned long, unsigned long, void *, void *, void *, unsigned long *);
typedef long (CALLBACK* PTSTOPMSGFILTER)(unsigned long, unsigned long);
typedef long (CALLBACK* PTSETPROGRAMMINGVOLTAGE)(unsigned long, unsigned long, unsigned long);
typedef long (CALLBACK* PTREADVERSION)(unsigned long, char *, char *, char *);
typedef long (CALLBACK* PTGETLASTERROR)(char *);
typedef long (CALLBACK* PTIOCTL)(unsigned long, unsigned long, void *, void *);

typedef long (CALLBACK* PTOPEN)(void *, unsigned long *);
typedef long (CALLBACK* PTCLOSE)(unsigned long);

extern PTCONNECT          PassThruConnect;
extern PTDISCONNECT       PassThruDisconnect;
extern PTREADMSGS         PassThruReadMsgs;
extern PTWRITEMSGS        PassThruWriteMsgs;
extern PTSTARTPERIODICMSG PassThruStartPeriodicMsg;
extern PTSTOPPERIODICMSG  PassThruStopPeriodicMsg;
extern PTSTARTMSGFILTER   PassThruStartMsgFilter;
extern PTSTOPMSGFILTER    PassThruStopMsgFilter;
extern PTSETPROGRAMMINGVOLTAGE PassThruSetProgrammingVoltage;
extern PTREADVERSION      PassThruReadVersion;
extern PTGETLASTERROR     PassThruGetLastError;
extern PTIOCTL            PassThruIoctl;
extern PTOPEN             PassThruOpen;
extern PTCLOSE            PassThruClose;


// maximum number of J2534 devices allowed
#define MAX_J2534_DEVICES        50


/*******************************************************************************
**  OBD Message and protocol definitions
*******************************************************************************/
// Maximum number of OBD ECUs and protocols
#define OBD_LEGACY_MAX_ECUS      8
#define MAX_ECUS                 239
#define OBD_MAX_PROTOCOLS        4  // the largest number of protocols possible
#define OBD_ZEV_MAX_PROTOCOLS    3  // the largest number of ZEV protocols possible

// OBD response indicator bit
#define OBD_RESPONSE_BIT         0x40

// Maximum number of bytes in ISO15765 frame
#define ISO15765_MAX_BYTES_PER_FRAME 7

// NAK Response ID and Codes
#define NAK                             0x7F
#define NAK_GENERAL_REJECT              0x10
#define NAK_SERVICE_NOT_SUPPORTED       0x11
#define NAK_SUBFUNCTION_NOT_SUPPORTED   0x12
#define NAK_INVALID_FORMAT              0x13
#define NAK_REPEAT_REQUEST              0x21
#define NAK_CONDITIONS_NOT_CORRECT      0x22
#define NAK_SEQUENCE_ERROR              0x24
#define NAK_ID_NOT_SUPPORTED            0x31
#define NAK_GENERAL_PROGRAMMING_FAILURE 0x72
#define NAK_RESPONSE_PENDING            0x78

// Tester node address
#define TESTER_NODE_ADDRESS        0xF1

// eProtocolTag list - the order of this list must match ProtocolInitData[] in InitOBDProtocolList.c
#define ISO15765_I                 0   // US OBD-II protocol
#define ISO15765_29_BIT_I          1   // US OBD-II protocol
#define ISO15765_CLASSIC_I         2   // US OBD-II protocol Classic j1979 services
#define ISO15765_CLASSIC_29_BIT_I  3   // US OBD-II protocol Classic j1979 services

#define ISO15765_ZEV               0   // US OBD-II protocol
#define ISO15765_29_BIT_ZEV        1   // US OBD-II protocol
#define DOIP_NDIS_I                2   // UDS on IP NDIS
#define DOIP_I                     3   // UDS on IP

#define CLASSIC_J1979_SERVICES     0x0001

#define MAX_PROTOCOL_NAME  46

// Protocol list structure
typedef struct
{
	unsigned long eProtocol;       // generic protocol (for J2534-1)
	unsigned long ChannelID;
	unsigned long eInitFlags;      // J2534-1 ConnectFlags
	unsigned long TesterPresentID;
	unsigned long FilterID;
	unsigned long FlowFilterID[MAX_ECUS];
	BYTE          HeaderSize;      // size of message header
	unsigned long BaudRate;        // link data rate
	unsigned long eProtocolTag;    // tag that uniquely identifies each protocol
	char Name[MAX_PROTOCOL_NAME];  // ASCII string for the protocol name
} PROTOCOL_LIST;


// RequestSID Flags
#define REQ_MSG_NORMAL                      0x00000000
#define REQ_MSG_RETURN_AFTER_ALL_RESPONSES  0x00000001
#define REQ_MSG_NO_PERIODIC_DISABLE         0x00000002
#define REQ_MSG_ALLOW_NO_RESPONSE           0x00000004
        // set   = no response returns PASS from RequestSID
        // unset = no response returns FAIL from RequestSID
#define REQ_MSG_IGNORE_NO_RESPONSE          0x00000008
        // set   = log WARNING on no response in RequestSID
        // unset = don't log WARNING on no response in RequestSID
#define REQ_MSG_PHYSICALLY_ADDRESSED        0x00000100
        // set   = use address in passed structure to address RequestSID message
        // unset = use functional address to address RequestSID message


/*******************************************************************************
**  User Input definitions
*******************************************************************************/
// User prompt type definitions
typedef enum
{
	NO_PROMPT=0,
	ENTER_PROMPT=1,
	YES_NO_PROMPT=2,
	YES_NO_ALL_PROMPT=3,
	QUIT_CONTINUE_PROMPT=4,
	CUSTOM_PROMPT=5,
	COMMENT_PROMPT=6
} PROMPTTYPE;

// User log entry type definitions
typedef enum
{
	USER_ERROR=1,
	FAILURE=2,
	WARNING=3,
	INFORMATION=4,
	PROMPT=5,
	SUBSECTION_BEGIN=6,
	SUBSECTION_PASSED_RESULT=7,
	SUBSECTION_FAILED_RESULT=8,
	SUBSECTION_INCOMPLETE_RESULT=9,
	SECTION_PASSED_RESULT=10,
	SECTION_FAILED_RESULT=11,
	SECTION_INCOMPLETE_RESULT=12,
	BLANK=13,
	NETWORK=14,
	ERROR_FAILURE=15,
	RESULTS=16,
	COMMENT=17,
	J2534_FAILURE=20
} LOGTYPE;

// Screen Output type definitions
typedef enum
{
	SCREENOUTPUTON=TRUE,
	SCREENOUTPUTOFF=FALSE
} SCREENOUTPUT;

// Logfile Output type definitions
typedef enum
{
	LOGOUTPUTON=TRUE,
	LOGOUTPUTOFF=FALSE
} LOGOUTPUT;

// energy type definitions
typedef enum
{
	ENERGY_UNKNOWN=0,
	ICE=1,
	ZEV=2
} ENERGYTYPE;

// fuel type definitions
typedef enum
{
	FUEL_UNKNOWN=0,
	GASOLINE=1,
	DIESEL=2,
	CNGH2=4,
	OTHER=8
} FUELTYPE;

// power type definitions
typedef enum
{
	POWER_UNKNOWN=0,
	BATTERY=1,
	FUELCELL=2,
	PHEVG=3,
	PHEVD=4
} POWERTYPE;

// Powertrain type definitions
typedef enum
{
	PWRTRN_UNKNOWN=0,
	CONV=1,
	SS=2,
	HEV=3,
	PHEV = 4,
	ELEC = 5
} PWRTRNTYPE;

// vehicle type definitions
typedef enum
{
	VEHICLE_UNKNOWN=0,
	LD=1,
	MD=2,
	MDDC=3,
	HD=4
} VEHICLETYPE;

// Compliance test type definitions
typedef enum
{
	UNKNOWN=0,
	US_OBDII=1,
	HD_OBD=2,
	EOBD=3,
	EOBD_NO_IUMPR=4,
	HD_EOBD=5,
	CNOBD=6,
	IOBD_NO_IUMPR=7,
	HD_IOBD_NO_IUMPR=8,
	OBDBr_NO_IUMPR=9,
	OBDBr_WITH_IUMPR=10,
	US_ZEV=11
} COMPLIANCETYPE;

typedef enum
{
	USOBD=1,
	EUOBD=2,
	EUOBD_250K=3
} SCANTABLETYPE;

typedef enum
{
	TEST_NONE=0,
	STATIC_TESTS=1,
	DYNAMIC_TESTS=2,
	ZEV_TESTS=3,
	VEHICLE_REPORT=4,
} TEST_SECTION;

typedef enum
{
	eTestNone=0,
	eTestNoDTC=5,
	eTestPendingDTC=6,
	eTestConfirmedDTC=7,
	eTestFaultRepaired=8,
	eTestNoFault3DriveCycle=9,
	eTestInUseCounters=10,
	eTestPerformanceCounters=11,
	eTestZEV=12
} TEST_PHASE;


// List of message defines - ORDER MUST MATCH gDisplayStrings in j1699.c
#define DSPSTR_PRMPT_MODEL_YEAR      0
#define DSPSTR_PRMPT_ENG_CERT_YEAR   1
#define DSPSTR_PRMPT_OBD_ECU         2
#define DSPSTR_PRMPT_ENERGY_TYPE     3
#define DSPSTR_PRMPT_FUEL_TYPE       4
#define DSPSTR_PRMPT_POWER_TYPE      5
#define DSPSTR_PRMPT_PWRTRN_TYPE     6
#define DSPSTR_STMT_COMPLIANCE_TYPE  7
#define DSPSTR_PRMPT_VEH_TYPE        8
#define DSPSTR_PRMPT_ISO15765_TYPE   9
#define DSPSTR_RSLT_TOT_USR_ERROR    10
#define DSPSTR_RSLT_TOT_J2534_FAIL   11
#define DSPSTR_RSLT_TOT_WARN         12
#define DSPSTR_RSLT_TOT_FAIL         13
#define DSPSTR_RSLT_TOT_COMMENTS     14

#define DSPSTR_TOTAL                 15


// maximum length for a log filename
#define MAX_LOGFILENAME          80


// LogMsg Flags
#define LOG_NORMAL_MSG           0
#define LOG_REQ_MSG              1

// logging related maximums
#define MAX_LOG_STRING_SIZE     12416    // max. size of a single log entry
#define MAX_MESSAGE_LOG_SIZE     4096    // max. number of message bytes in a single log entry

// Function return value definitions (sometimes treated as bit map, DO NOT CHANGE VALUES!)
typedef enum
{
	PASS=0x00,
	FAIL=0x02,
	ABORT=0x04,
	ERRORS=0x08,
	RETRY=0x10,
	CTRL_C=0x20,
	EXIT=0x40
} STATUS;

// Macros
#define ABORT_RETURN   {gbTestAborted = TRUE;gbTestSectionAborted = TRUE;return ABORT;}


// Drive Cycle completion flags
#define IDLE_TIME           0x01
#define ATSPEED_TIME        0x02
#define CUMULATIVE_TIME     0x04
#define FEO_TIME            0x08


// Dynamic Test display maximums
#define MAX_ECUS_PER_PAGE        8
#define MAX_ECU_PAGE             30 // MAX_ECUS / MAX_ECUS_PER_PAGE rounded up


// DID type enumeration
#define NUM_ID_SUP_TYPES 6
// values here must match offsets for the appropriate string in SID[] and IDTypeString[]
typedef enum
{
	PIDREQUEST=0,    // SID $22 $F400-F4FF
	PF5REQUEST=1,    // SID $22 $F500-F5FF
	FFREQUEST=2,
	MIDREQUEST=3,    // SID $22 $F600-F6FF
	RIDREQUEST=4,
	INFREQUEST=5     // SID $22 $F800-F8FF
} IDTYPE;

#define ALLECUS 0xFF
#define ALREADYLOADED 0xFFFF

// SID 22 INFoTypes
#define INF_TYPE_VIN_COUNT      0xF801
#define INF_TYPE_VIN            0xF802
#define INF_TYPE_CALID_COUNT    0xF803
#define INF_TYPE_CALID          0xF804
#define INF_TYPE_CVN_COUNT      0xF805
#define INF_TYPE_CVN            0xF806
#define INF_TYPE_IPT_COUNT      0xF807
#define INF_TYPE_IPT_GAS        0xF808
#define INF_TYPE_ECUNAME_COUNT  0xF809
#define INF_TYPE_ECUNAME        0xF80A
#define INF_TYPE_IPT_DIESEL     0xF80B
#define INF_TYPE_ESN_COUNT      0xF80C
#define INF_TYPE_ESN            0xF80D
#define INF_TYPE_EROTAN_COUNT   0xF80E
#define INF_TYPE_EROTAN         0xF80F
#define INF_TYPE_PROTID         0xF810
#define INF_TYPE_GTR            0xF811
#define INF_TYPE_FEOCNTR        0xF812
#define INF_TYPE_TG_EFN         0xF813
#define INF_TYPE_EVAP_DIST      0xF814
#define INF_TYPE_MTRCYCLE       0xF815
#define INF_TYPE_ER_IT          0xF816
#define INF_TYPE_DT_FC          0xF817
#define INF_TYPE_PKE_EOE        0xF818
#define INF_TYPE_PSA            0xF819
#define INF_TYPE_PHEVDD         0xF81A
#define INF_TYPE_PHEVFD         0xF81B
#define INF_TYPE_PHEVGD         0xF81C
#define INF_TYPE_AAF1OCCVD      0xF81D
#define INF_TYPE_AAF2OCCVD      0xF81E
#define INF_TYPE_AAF3OCCVD      0xF81F
#define INF_TYPE_DSOMOCCVD      0xF821
#define INF_TYPE_RTSSCOCCVD     0xF822
#define INF_TYPE_DCTOCCVD       0xF823
#define INF_TYPE_APTWUFOCCVD    0xF824
#define INF_TYPE_OCCT1VD        0xF825
#define INF_TYPE_OCCT2VD        0xF826
#define INF_TYPE_OCCT3VD        0xF827
#define INF_TYPE_OCCT4VD        0xF828
#define INF_TYPE_OCCT5VD        0xF829
#define INF_TYPE_EDSMD          0xF82A

#define INF_TYPE_HDGHGA100HD1   0xF841
#define INF_TYPE_HDGHGA100HD2   0xF842
#define INF_TYPE_HDGHGS100HD1   0xF843
#define INF_TYPE_HDGHGS100HD2   0xF844
#define INF_TYPE_HDGHGLD1       0xF845
#define INF_TYPE_HDGHGLD2       0xF846
#define INF_TYPE_HDGHGPSAD      0xF847
#define INF_TYPE_HDGHGPHEVVD    0xF848
#define INF_TYPE_HDGHGPHEVFD    0xF849
#define INF_TYPE_HDGHGPHEVGD    0xF850
#define INF_TYPE_HDGHGATSS      0xF851
#define INF_TYPE_HDGHGATAES     0xF852
#define INF_TYPE_HDGHGATWHR     0xF853
#define INF_TYPE_HDGHGAT1AT2    0xF854
#define INF_TYPE_HDGHGAT3AT4    0xF855
#define INF_TYPE_HDGHGAT5AT6    0xF856
#define INF_TYPE_HDGHGAT7AT8    0xF857
#define INF_TYPE_HDGHGAT9AT10   0xF858
#define INF_TYPE_HDGHGAT11AT12  0xF859
#define INF_TYPE_HDGHGAT13AT14  0xF85A
#define INF_TYPE_HDGHGAT15AT16  0xF85B

#define INF_TYPE_NOx100HMEOA    0xF861
#define INF_TYPE_NOx100HMTA     0xF862
#define INF_TYPE_NOx100HEOEA    0xF863
#define INF_TYPE_NOx100HDTA     0xF864
#define INF_TYPE_NOx100HERTA    0xF865
#define INF_TYPE_NOx100HVFCA    0xF866
#define INF_TYPE_NOx100HMEOS    0xF867
#define INF_TYPE_NOx100HMTS     0xF868
#define INF_TYPE_NOx100HEOES    0xF869
#define INF_TYPE_NOx100HDTS     0xF86A
#define INF_TYPE_NOx100HERTS    0xF86B
#define INF_TYPE_NOx100HVFCS    0xF86C
#define INF_TYPE_NOxVMEOL       0xF86D
#define INF_TYPE_NOxVMTL        0xF86E
#define INF_TYPE_NOxVEOEL       0xF86F
#define INF_TYPE_NOxVDTL        0xF870
#define INF_TYPE_NOxVERTL       0xF871
#define INF_TYPE_NOxVVFCL       0xF872
#define INF_TYPE_NOxEAEOEL      0xF873
#define INF_TYPE_NOxEADTL       0xF874
#define INF_TYPE_NOxEAERTL      0xF875
#define INF_TYPE_NOxEAVFCL      0xF876
#define INF_TYPE_NOxPMRVD       0xF877
#define INF_TYPE_ER             0xF878
#define INF_TYPE_MAD            0xF879

#define INF_TYPE_IPD_UDS        0xF882
#define INF_TYPE_DCSERS         0xF883
#define INF_TYPE_DCSERS_EWMA    0xF884


// OBD message response data structures
#define MAX_NUM_SUP_BYTES       8     // $Fx00, $Fx20, $Fx40, $Fx60, $Fx80, $FxA0, $FxC0, $FxE0
#define MAX_RESP_BUF_SIZE       2048
#define MAX_RESP_STR_SIZE       MAX_RESP_BUF_SIZE * 5
#define MAX_PID_RESP_SIZE       41

#define MAX_NUM_DTCFF            1024   // number of DTCs which have Freeze Frame data

#define MAX_DTCEXTDATA_COUNT     1024   // number of DTCs (4 bytes: HB,MB,LB,Status) which can fit in a 4k message
#define MAX_DTCIUMPR_COUNT       MAX_DTCEXTDATA_COUNT   // number of DTCs which support IUMPR (ExtData $91)
#define MAX_DTCTESTRESULT_COUNT  MAX_DTCEXTDATA_COUNT   // number of DTCs which support TestResults (ExtData $92)
#define MAX_DTCSMAD_COUNT        MAX_DTCEXTDATA_COUNT   // number of DTCs which support SMAD  (ExtData $93)
#define MAX_DTCRG_COUNT          MAX_DTCEXTDATA_COUNT   // number of DTCs which support Readiness Groups

#define MAX_DTCTESTRESULT_NUM    20     // maximum number of Test Results per DTC
#define DTCASTRSIZE              4      // number of bytes in DTCASTR (DTC High byte, Middle byte, Low byte, Status)

// DTC Status State definitions
#define DTC_STATE_NO_FAULT               1   // Test 5, 10, 11
#define DTC_STATE_INDUCE_FAULT           2   // Test 6
#define DTC_STATE_CONTINUE_FAULT         3   // Test 7
#define DTC_STATE_REPAIR_1DC_FAULT       4   // Test 8
#define DTC_STATE_REPAIR_3DC_FAULT       5   // Test 9.2, 9.3, 9.5
#define DTC_STATE_SET_PERM_FAULT         6   // Test 9.8, 9.9
#define DTC_STATE_REPAIR_PERM_FAULT      7   // Test 9.13
#define DTC_STATE_REPAIR_1DC_PERM_FAULT  8   // Test 9.15
#define DTC_STATE_ERASE_PERM_FAULT       9   // Test 9.18
#define DTC_STATE_ZEV_PEND_FAULT         10  // Test 12.8
#define DTC_STATE_ZEV_CONF_FAULT         11  // Test 12.9
#define DTC_STATE_ZEV_REPAIR_1DC_FAULT   12  // Test 12.10

// DTC Status byte definitions
#define DTC_STATUS_TEST_FAILED                                0x01
#define DTC_STATUS_TEST_FAILED_THIS_OPERATIONAL_CYCLE         0x02
#define DTC_STATUS_PENDING_DTC                                0x04
#define DTC_STATUS_CONFIRMED_DTC                              0x08
#define DTC_STATUS_TEST_NOT_COMPLETED_SINCE_LAST_CLEAR        0x10
#define DTC_STATUS_TEST_FAILED_SINCE_LAST_CLEAR               0x20
#define DTC_STATUS_TEST_NOT_COMPLETED_THIS_OPERATIONAL_CYCLE  0x40
#define DTC_STATUS_WARNING_INDICATOR_REQUESTED                0x80

#define MAX_REQ_BUF_SIZE        6


typedef struct
{
	BYTE PIDMSB;
	BYTE PIDLSB;
	BYTE Data[MAX_PID_RESP_SIZE];
} PID;

typedef struct
{
	BYTE MIDMSB;
	BYTE MIDLSB;
	BYTE SDTID;
	BYTE UASID;
	BYTE TVHI;
	BYTE TVLO;
	BYTE MINTLHI;
	BYTE MINTLLO;
	BYTE MAXTLHI;
	BYTE MAXTLLO;
} MID;

typedef struct
{
	BYTE INFMSB;
	BYTE INFLSB;
	BYTE Data[MAX_RESP_BUF_SIZE];
} INF;

typedef struct
{
	BYTE ID;
	BYTE SupBits[4];
} ID_SUPPORT;

typedef struct
{
	BYTE ID;
	BYTE FrameNumber;
	BYTE SupBits[4];
} FF_SUPPORT;

typedef struct
{
	BOOL DTCSupported;
	BYTE DTCStatus;
	BYTE DTCSeverity;
	BYTE DTCFormat;
	WORD DTCSize;           // number of bytes in array ConfDTC or PendDTC
} DTC_HEADER;

typedef struct
{
	WORD Size;
	BYTE Dtc[MAX_RESP_BUF_SIZE];
} DTC_LIST;

typedef struct
{
	BYTE HighByte;
	BYTE MidByte;
	BYTE LowByte;
} DTC;  // structure for DTC Record

typedef struct
{
	DTC  Dtc;
	BYTE Status;
} DTCASTR;  // DTC AND STATUS RECORD, structure for Subfunc $04, $06, $0A, $10m, $1A, $42, $55, $56

typedef struct
{
	BYTE   Severity;
	DTCASTR Record;
} DTCASVR;  // DTC AND SEVERITY RECORD, structure for ConfDTC and PendDTC data Subfunc $42 FGID $04 and $08

typedef struct
{
	DTC  Dtc;
	BYTE RecNum;
} DTCASSR;  // DTC AND SNAPSHOT Record, structure for Subfunc $03

typedef struct
{
	BYTE RecNum;
	BYTE NumOfIdents;
} SNAPSHOTRECORD;  //structure for Subfunc $04

typedef struct
{
	WORD DataID;
	BYTE Data;
} SNAPSHOTRECORDDATA;  //structure for Subfunc $04

typedef struct
{
	BYTE PIDMSB;
	BYTE PIDLSB;
	BYTE FrameNumber;
	BYTE Data[41];
} FREEZEFRAMEDATA;

typedef struct
{
	DTCASTR  Record;
	WORD     CompCounts;  // Numerator
	WORD     CondCounts;  // Denominator
	BYTE     RGID;        // Readiness Group Identifier
}DTCIUMPR;

typedef struct
{
	WORD     UnitScaling;  // Unit And Scaling ID
	WORD     TestValue;    // Test Value
	WORD     MinTstLmt;    // Min. Test Limit
	WORD     MaxTstLmt;    // Max. Test Limit
}TestResult;

typedef struct
{
	DTCASTR     Record;
	BYTE        NumTstRslts;  // Number of test results
	TestResult  Result[MAX_DTCTESTRESULT_NUM];  // array of test result structures
}DTCTestResult;

typedef struct
{
	DTCASTR  Record;
	BYTE     NumCounts;    // Monitor Activity Numerator Counts
	float    ActRatio;     // Stored Monitor Activity Ratio
	BYTE     RGID;         // Readiness Group Identifier
}DTCSMAD;

typedef struct
{
	DTCASTR  Record;
	BYTE     RGID;    // Readiness Group Identifier
}DTCREADINESSGROUP;


#define MAX_READINESS_GROUP_ID 0x14
#define MAX_READINESS_GROUPS   0x15


#define  IMRDATAVALID      0x0001
#define  IPDDATAVALID      0x0002
#define  IUMPRDATAVALID    0x0004
#define  SMADDATAVALID     0x0008
#define  IMREADYDONE       0x0010
#define  IPDDONE           0x0020
#define  IUMPRDONE         0x0040
#define  SMADDONE          0x0080
#define  ECUDONE           0x8000
#define  IMRDATANOTVALID   0xFFFE
#define  IPDDATANOTVALID   0xFFFD
#define  IUMPRDATANOTVALID 0xFFFB
#define  SMADDATANOTVALID  0xFFF7
#define  IMREADYNOTDONE    0xFFEF
#define  IPDNOTDONE        0xFFDF
#define  IUMPRNOTDONE      0xFFBF
#define  SMADNOTDONE       0xFF7F
#define  ECUNOTDONE        0x7FFF


#define IPD_OBDCOND_INDEX    0  //
#define IPD_IGNCNTR_INDEX    1  //


#define  ECUNAME_BUFFER_SIZE 18
#define  TGEFN_BUFFER_SIZE   13
#define  VIN_BUFFER_SIZE     18  // 17 charters + NULL
#define  CVN_BUFFER_SIZE     16  // $XX $XX $XX $XX + NULL
#define  CALID_BUFFER_SIZE   17  // 123456789ABCDEF0 + NULL


typedef struct
{
	// This ECU's Network Communication Information
	BYTE            Header[4];
	DWORD           RespId;                      // ID of the response from the ECU
	DWORD           ReqId;                       // ID to send a request to the ECU
	BYTE            IPv4Address[4];              // IPv4 address associated with this ECU
	BYTE            IPv6Address[16];             // IPv6 address assicuates with this ECU
	BOOL            bResponseReceived;           // used to check for multiple responses
	BOOL            bLinkActive;
	BOOL            bNAKReceived;                // set if this ECU recieved a NAK on the latest request
	BYTE            NAKCode;                     // NAK code on the latest request
	BOOL            bFFReceived;                 // set if this ECU recieved a First Frame of the latest response
	
	// This ECU's Network Communication Timing Information
	unsigned long   ResponseTimeExtensionMsecs;
	unsigned long   ResponsePendingDelayTimeMsecs;
	unsigned long   AggregateResponseTimeMsecs;  // Total Accumulated Response Time for this ECU
	unsigned long   AggregateResponses;          // Total number of responses from this ECU
	unsigned long   LongestResponsesTimeMsecs;   // Longest response time from this ECU
	unsigned long   RespTimeOutofRange;          // Count of response times outside expected range
	unsigned long   RespTimeTooLate;             // Count of response times too long
	unsigned long   RespTimeTooSoon;             // Count of response times too short

	// This ECU's ID Support And Data
	BYTE            PIDSupportSize;                 // number of entries in $F4xx Support array
	ID_SUPPORT      PIDSupport[MAX_NUM_SUP_BYTES];  // $F400 support array

	BYTE            PF5SupportSize;                 // number of entries in $F5xx Support array
	ID_SUPPORT      PF5Support[MAX_NUM_SUP_BYTES];  // $F500 support array
	
	WORD            PIDSize;                        // number of bytes in array PID
	BYTE            PID[246];                       // 6 * largest PID (81 - 41 bytes)

	BYTE            MIDSupportSize;
	ID_SUPPORT      MIDSupport[MAX_NUM_SUP_BYTES];
	WORD            MIDSize;            // number of bytes in array MID
	BYTE            MID[MAX_RESP_BUF_SIZE];

	BYTE            TIDSupportSize;
	ID_SUPPORT      TIDSupport[4];
	WORD            TIDSize;            // number of bytes in array TID
	BYTE            TID[MAX_RESP_BUF_SIZE];
	
	BYTE            RIDSupportSize;
	BYTE            RIDSupport[7];
	WORD            RIDSize;            // number of bytes in array RID
	BYTE            RID[MAX_RESP_BUF_SIZE];

	BYTE            INFSupportSize;
	ID_SUPPORT      INFSupport[MAX_NUM_SUP_BYTES];
	WORD            INFSize;            // number of bytes in array INF
	BYTE            INF[MAX_RESP_BUF_SIZE];

	BYTE            CompareSupportSize;
	ID_SUPPORT      CompareSupport[MAX_NUM_SUP_BYTES];

	// This ECU's DTC Data
	WORD            ClrDTCSize;
	BYTE            ClrDTC[8];

	DTC_HEADER      PendDTCHeader;
	BYTE            PendDTC[MAX_RESP_BUF_SIZE];

	DTC_HEADER      ConfDTCHeader;
	BYTE            ConfDTC[MAX_RESP_BUF_SIZE];

	BOOL            bPermDTCSupported;
	BYTE            PermDTCStatus;
	BYTE            PermDTCFormat;
	WORD            PermDTCSize;         // number of bytes in array PermDTC
	BYTE            PermDTC[MAX_RESP_BUF_SIZE];

	BYTE            FFSupportSize;
	FF_SUPPORT      FFSupport[MAX_NUM_SUP_BYTES];
	WORD            FFSize;             // number of bytes in array FF
	BYTE            FF[MAX_RESP_BUF_SIZE];

	DTC_LIST       *pDTCList;
	DTC_LIST       *pFFDTCList;

	BOOL            bIPDSupported;
	WORD            IPD[2];
	WORD            IPD_Test10_10[2];
	WORD            IPD_Test11_7[2];
	WORD            IPD_Test11_12[2];
	WORD            IPD_Test11_CurrentDisplayData[2];
	BYTE            IPDStatusFlags;

	BOOL            bDTCIUMPRSupported;
	BYTE            DTCIUMPRStatus;
	WORD            DTCIUMPRCount;
	DTCIUMPR        DTCIUMPRList[MAX_DTCIUMPR_COUNT];        // this ECU's list of DTCs which support IUMPR and last IUMPR response
	WORD            DTCIUMPR_RGTotalCount;
	WORD            DTCIUMPR_RGListCount[MAX_READINESS_GROUPS];
	WORD            DTCIUMPR_RGIncdCount[MAX_READINESS_GROUPS];
	DTCIUMPR        DTCIUMPR_RGList[MAX_DTCIUMPR_COUNT];     // this ECU's list of DTCs which support IUMPR with Readiness Group and last IUMPR response
	DTCIUMPR        DTCIUMPR_Test10_10[MAX_DTCIUMPR_COUNT];  // this ECU's IUMPR response in Test 10.10
	DTCIUMPR        DTCIUMPR_Test11_7[MAX_DTCIUMPR_COUNT];   // this ECU's IUMPR response in Test 11.5
	DTCIUMPR        DTCIUMPR_Test11_12[MAX_DTCIUMPR_COUNT];  // this ECU's IUMPR response in Test 11.11
	DTCIUMPR        DTCIUMPR_Test11_CurrentDisplayData[MAX_DTCIUMPR_COUNT];
	DTCIUMPR        DTCIUMPRCurrent;                         // this ECU's last IUMPR response

	BOOL            bDTCTestResultSupported;
	BYTE            DTCTestResultStatus;
	WORD            DTCTestResultCount;
	DTCTestResult   DTCTestResultList[MAX_DTCTESTRESULT_COUNT];        // this ECU's list of DTCs which support TestResult and last TestResult response
	DTCTestResult   DTCTestResult_Test10_10[MAX_DTCTESTRESULT_COUNT];  // this ECU's TestResult response in Test 10.10
	DTCTestResult   DTCTestResult_Test11_6[MAX_DTCTESTRESULT_COUNT];   // this ECU's TestResult response in Test 11.5
	DTCTestResult   DTCTestResult_Test11_11[MAX_DTCTESTRESULT_COUNT];  // this ECU's TestResult response in Test 11.11
	DTCTestResult   DTCTestResult_Test11_CurrentDisplayData[MAX_DTCTESTRESULT_COUNT];
	DTCTestResult   DTCTestResultCurrent;                              // this ECU's last TestResult response

	BOOL            bDTCSMADSupported;
	BYTE            DTCSMADStatus;
	WORD            DTCSMADCount;
	DTCSMAD         DTCSMADList[MAX_DTCSMAD_COUNT];          // this ECU's list of DTCs which support SMAD and last SMAD response
	WORD            DTCSMAD_RGTotalCount;
	WORD            DTCSMAD_RGListCount[MAX_READINESS_GROUPS];
	WORD            DTCSMAD_RGIncdCount[MAX_READINESS_GROUPS];
	DTCSMAD         DTCSMAD_RGList[MAX_DTCSMAD_COUNT];     // this ECU's list of DTCs which support SMAD with Readiness Group and last SMAD response
	DTCSMAD         DTCSMAD_Test10_10[MAX_DTCSMAD_COUNT];    // this ECU's SMAD response in Test 10.10
	DTCSMAD         DTCSMAD_Test11_7[MAX_DTCSMAD_COUNT];     // this ECU's SMAD response in Test 11.5
	DTCSMAD         DTCSMAD_Test11_12[MAX_DTCSMAD_COUNT];    // this ECU's SMAD response in Test 11.11
	DTCSMAD         DTCSMAD_Test11_CurrentDisplayData[MAX_DTCSMAD_COUNT];
	DTCSMAD         DTCSMADCurrent;                          // this ECU's last SMAD response

	BOOL            bDTCReadinessGroupSupported;
	BYTE            DTCReadinessGroupStatus[MAX_READINESS_GROUPS];
	WORD            DTCReadinessGroupCount;
	WORD            DTCReadinessGroupListCount[MAX_READINESS_GROUPS];
	DTCREADINESSGROUP  DTCReadinessGroupList[MAX_DTCRG_COUNT];        // this ECU's list of DTCs which support each Readiness Group
	DTCREADINESSGROUP  DTCReadinessGroupCurrent[MAX_DTCRG_COUNT];     // this ECU's last Readiness Group response
	WORD            DTCReadinessGroupCurrentCount;                    // the number of Readiness Group data records in last response
	DWORD           DTCReadinessGroupStatusFlags[2];                  // DTCReadinessGroupStatusFlags[0] IUMPR RG completion flags
	                                                                  // DTCReadinessGroupStatusFlags[1] SMAD RG completion flags
	
	WORD            StatusFlags;                                      // application flags. set 1 when done, valid

	
	// This ECU's saved response Information
	BOOL            bVINValid;                               // set if this ECU has a valid VIN
	BYTE            VINString[VIN_BUFFER_SIZE];              // this ECU's VIN response
	BYTE            ECUName_String[ECUNAME_BUFFER_SIZE];     // this ECU's Name String
	BYTE            TGEFN_String[TGEFN_BUFFER_SIZE];         // this ECU's TG/EFN string
	WORD            CVNCount;                                // the number of CVN's in this ECU's response
	BYTE           *pCVNString;                              // this ECU's CVN response
	WORD            CALIDCount;                              // the number of CALID's in this ECU's response
	BYTE           *pCALIDString;                            // this ECU's CALID response
	WORD            ODB_Compliance_Level;                    // this ECU's OBD Compliance Level response
	BYTE            ProtocolID;                              // this ECU's Protocol Id response
	PID             PID51;                                   // this ECU's last PID $F451 response
	PID             PIDF501;                                 // this ECU's last PID $F501 response
	INF            *pFEOCNTR;                                // this ECU's last FEOCNTR response
	INF            *pTest10_10_FEOCNTR;                      // this ECU's FEOCNTR response in Test 10.10
	INF             MAD;                                     // this ECU's last MAD ($F879) response
} ECU_DATA;


// Service ID (Mode) request structure
typedef struct
{
	DWORD    ReqEcuID;                       // ID of the requested ECU (Physical Address)
	DWORD    RespEcuID;                      // ID of the ECU response (Physical Address)
	BOOL     bPhysicallyAddressed;
	BYTE     SID;
	BYTE     NumIds;
	union
	{
		BYTE  ID[6];
		WORD  DID[3];
	} u;
	BYTE           Data[MAX_REQ_BUF_SIZE];
} REQ_MSG;

#define MAX_CODE_STR_LEN  10

typedef struct
{
	ENERGYTYPE     eEnergyType;
	FUELTYPE       eFuelType;
	POWERTYPE      ePowerType;
	PWRTRNTYPE     ePwrTrnType;
	VEHICLETYPE    eVehicleType;
	COMPLIANCETYPE eComplianceType; // type of compliance being tested for
	SCANTABLETYPE  eScanTable;      // table of permutations used for OBD protocol scans
	BYTE           MaxProtocols;    // maximum number of OBD protocols
	BYTE           NumDCToSetMIL;   // count of drive cycles (either "two" or "three" ) with fault to set MIL
} USER_INPUT;


// Global function prototypes
// j1699.c
char * substring ( char       *str,
                   const char *substr );  // returns loc. of 'substr' in 'str'
unsigned long GetFailureCount ( void );   // returns global failure count
void   ClearKeyboardBuffer  ( void );
// end j1699.c
STATUS ClearCodes ( void );
// ConnectOBDProtocol.c
STATUS ConnectOBDProtocol ( void );
STATUS StartPeriodicMsg ( void );
STATUS StopPeriodicMsg ( BOOL bLogError );
// end ConnectOBDProtocol.c
// DetermineOBDProtocol.c
STATUS DetermineOBDProtocol ( void );
unsigned long GetEcuId ( BYTE EcuIdx );
// end DetermineOBDProtocol.c
STATUS DisconnectOBDProtocol ( void );
// IDSupport.c
STATUS RequestIDSupportData ( IDTYPE IdType,
                              BOOL   bVerifyECUCommunication );
STATUS RequestGroupPIDSupportData ( IDTYPE IdType );
STATUS VerifyIDSupportData ( IDTYPE IdType );
void   CopyIDSupport    ( IDTYPE  IdType );        // Type of PID support array
void   RestoreIDSupport ( IDTYPE  IdType );        // Type of PID support array
STATUS CompareIDSupport ( BYTE    EcuIdx,          // The index of the current ECU
                          IDTYPE  IdType,          // Type of PID support array
                          BOOL    bGroup );        // Flag indicating if this is a group PID Support response
BOOL   IsIDSupported    ( BYTE    EcuIdx,
                          IDTYPE  IdType,
                          WORD    PidIdx );
// end IDSupport.c
STATUS IsDTCPending ( unsigned long Flags );
STATUS IsDTCStored  ( unsigned long Flags );
void   LogMsg ( PASSTHRU_MSG *,
                unsigned long);
char   Log ( LOGTYPE      eLogType,
             SCREENOUTPUT ScreenOutput,
             LOGOUTPUT    LogOutput,
             PROMPTTYPE   ePromptType,
             const char  *LogString, ... );
STATUS RequestSID ( REQ_MSG      *pstReqMsg,
                    unsigned long Flags);
STATUS RequestSID_PhysicallyAddressed_All ( REQ_MSG      *pstReqMsg,
                                            unsigned long Flags);
STATUS RequestSID_PhysicallyAddressed_Single ( REQ_MSG      *pstReqMsg,
                                               unsigned long Flags,
                                               unsigned long EcuId );

void   StopTest ( STATUS     ExitStatus,
                  TEST_PHASE eTestPhase );

STATUS Test5_NoDTC ( void );
STATUS Test6_PendingDTC ( void );
STATUS Test7_ConfirmedDTC ( void );
STATUS Test8_FaultRepaired ( void );
STATUS Test9_NoFaultsAfter3DriveCycles ( void );
STATUS Test9_7to17_PermanentCodes ( void );
STATUS Test10_InUseCounters ( BOOL *pbReEnterTest );
STATUS Test11_PerformanceCounters ( BOOL *pbReEnterTest );
STATUS Test12_ZEV ( void );

STATUS VerifyRIDSupportAndData ( void );
STATUS VerifyPIDBurstSupport ( void );
// VerifyPIDSupportAndData.c
STATUS VerifyPIDSupportAndData ( BOOL bEngineDontCare );
STATUS VerifyIM_Ready ( void );
// end VerifyPIDSupportAndData.c
STATUS VerifyPendingDTCData ( BYTE State );
STATUS VerifyConfirmedDTCData ( BYTE State );
STATUS VerifyDTCFFData ( void );
STATUS VerifyECUCommunication ( void );
STATUS VerifyMILData ( void );
STATUS VerifyMIDSupportAndResults ( void );
STATUS VerifyO2TestResults ( void );
STATUS VerifyPermanentDTCData ( BYTE State );
STATUS VerifyDeprecatedServices ( unsigned int ID );
STATUS VerifyReservedServices ( void );
STATUS VerifyINFSupportAndData ( void );
STATUS VerifyVehicleState ( BOOL ucEngineRunning,
                            BOOL ucHybrid );


// Global variables
extern FILE           *gTempLogFileHandle;
extern FILE           *gLogFileHandle;

extern char            gLogFileNameString[MAX_LOGFILENAME];
extern int             gModelYear;                        // integer version of model year entered by the user
extern int             gVINModelYear;                     // integer version of model year entered by the user (used for VIN checks)
extern char            gUserMakeString[80];               // make of vehicle entered by the user
extern char            gUserModelString[80];              // model of vehicle entered by the user
extern BYTE            gUserNumOfECUs;                    // number of ECUs entered by the user
extern BYTE            gUserNumOfECUsReprgm;              // number of reprogrammable ECUs entered by the user
extern BYTE            gNumOfECUsForAlloc;                // number of ECUs used for memory allocation
extern USER_INPUT      gstUserInput;                      // structure for user selected compliance test information
extern char           *gEnergyTypeStrings[3];             // strings that represent the user selected energy type
extern char           *gFuelTypeStrings[5];               // strings that represent the user selected fuel type
extern char           *gPwrTrnTypeStrings[5];             // strings that represent the user selected powertrain type
extern char           *gVehicleTypeStrings[5];            // strings that represent the user selected vehicle type
extern char           *gComplianceTestTypeStrings[12];    // strings that represent the user selected compliance test
extern char           *gDisplayStrings[DSPSTR_TOTAL];     // strings used for display/logging
extern BOOL            gbHybrid;                          // set by the user if this is a hybrid vehicle
extern BOOL            gbPlugIn;                          // set by the user if this is a plug-in vehicle
extern BOOL            gbDynoCert;                        // set by the user if this is a Dyno Certified vehicle
extern BOOL            gbIgnoreUnsupported;               // set if a response to an unsupported PID should not Log a warning

extern BOOL            gbDirectEthernet;
extern boolean         bDHCP_Server_On;
extern BOOL            gbProtocolDetermined;              // set if a OBD protocol found
extern unsigned long   gRequestDelayTimeMsecs;
extern unsigned short  gProtocolIdx;                      // index of the OBD protocol being used
extern PROTOCOL_LIST   gstProtocolList[OBD_MAX_PROTOCOLS];
extern BYTE            gNumOfECUs;                        // number of responding ECUs
extern BYTE            gNumOfECUsResp;                    // number of responding ECUs
extern BOOL            gbSuspendScreenOutput;
extern BOOL            gbSuspendLogOutput;
extern BOOL            gbIgnoreFailureLogging;
extern ECU_DATA       *gstResponse;                       // pointer to the data from the latest response

extern BYTE            gReverseOrderStateArray[MAX_ECUS];  // state of reverse order request
#define NOT_REVERSE_ORDER              0x00  // not reverse order
#define REVERSE_ORDER_REQUESTED        0x01  // reverse order requested, no response yet
#define REVERSE_ORDER_RESPONSE         0x02  // first reverse order response received, SupportSize cleared
#define REVERSE_ORDER_GROUP_REQUESTED  0x04  // reverse order group requested, no response yet
#define REVERSE_ORDER_GROUP_RESPONSE1  0x08  // first reverse order group response received, $EO and $C0 and SupportSize cleared
#define REVERSE_ORDER_GROUP_RESPONSE2  0x10  // second reverse order group response received, $A0-$00 cleared

extern unsigned long   gDeviceID;               // global storage for J2534-1 Device ID
extern TEST_PHASE      geTestPhase;             // The current Test Phase
extern BYTE            gTestSubsection;         // The test subsection (to be used in conjunction with geTestPhase)
extern BOOL            gbDetermineProtocol;     // set if in DetermineProtocol function
extern BOOL            gbVerifyLink;            // set if in VerifyECUCommunication function
extern BOOL            gbPhysicalAddressing;    // set if requests should be sent physically addressed
extern BOOL            gbAllECUResetCompleted;  // set if Response Data has been reset for all ECU's (physically addressing only)
extern BOOL            gbSkipPA;                // set if skiping physical addressing (TESTING ONLY)

extern BOOL            gbEngineRunning;         // set if engine should be running
extern BOOL            gbPSA;                   // set if engine should be running
extern BOOL            gbEngineWarm;            // set if engine should be warm
extern BOOL            gbDTCPending;            // set if a DTC should be pending
extern BOOL            gbDTCStored;             // set if a DTC should be stored
extern BOOL            gbDTCHistorical;
extern BOOL            gbDTCPermanent;          // set if a DTC should be permanent

extern BOOL            gbTestSectionAborted;    // set if a test section (Static/Dynamic) was aborted,
                                                // clear only before the Static test and before Dynamic tests
extern BOOL            gbTestSectionFailed;     // set if a test (static/dynamic) failed,
                                                // clear only at the beginning of the Static or Dynamic test
extern BOOL            gbTestSubsectionFailed;  // set if a test subsection failed,
                                                // clear before each subsection (ie test 5.10, test 7.4, etc)
extern BOOL            gbTestAborted;           // set if any test was aborted,
                                                // clear only before running Static and Dynamic tests
extern BOOL            gbTestFailed;            // set if any test failed,
                                                // clear only before running Static and Dynamic tests

extern char            gVINString[VIN_BUFFER_SIZE];
extern char            gVIDString[VIN_BUFFER_SIZE];

extern BYTE            DTCTypeCharacter[];
