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

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


// Funtion prototypes
STATUS RequestFFIDData        ( BOOL *pbFFSupOnPendFault );
STATUS VerifyFFDTCinDTCList   ( void );
STATUS VerifyFFDTCinFFDTCList ( void );

// Variable prototypes
extern unsigned char DTCTypeCharacter[];


/*******************************************************************************
**
**  Function:  VerifyFFSupportAndData
**
**  Purpose:   Verify FF freeze frame support and data
**
*******************************************************************************/
STATUS VerifyFFSupportAndData ( void )
{
	STATUS eRetCode = PASS;

//	static unsigned long FreezeFramePendingDTC[MAX_ECUS] = {0};  // array of pending Freeze Frame DTCs
//	unsigned char        FreezeFrameDTC[MAX_ECUS][MAX_RESP_BUF_SIZE];  // array of the Freeze Frame data
	BOOL                 bFFSupOnPendFault;                      // Set if Freeze Frame stored on pending fault
//	BYTE                 FFDTCCount[MAX_ECUS];                   // the count of ECUs which report a Freeze Frame DTC
//	BYTE                 FFDTCSupportCount;                      // the count of ECUs which support SID $19 LEV $03

	unsigned long        InitialFailureCount = 0;


	// Initialize data
//	memset ( &FFDTCCount[0],
//	         0,
//	         sizeof ( FFDTCCount ) );
//	FFDTCSupportCount = 0;
	bFFSupOnPendFault = FALSE;
//	memset ( &FreezeFrameDTC[0][0],
//	         0,
//	         sizeof ( FreezeFrameDTC ) );

	InitialFailureCount = GetFailureCount ( );

	// Request SID $19 LEV $03 data
	if ( RequestFFIDData ( &bFFSupOnPendFault ) != PASS )
	{
		eRetCode = FAIL;
	}

//	// Request SID $19 LEV $04 support data
//	if ( RequestFFSupportData ( FreezeFrameDTC,
//	                            FFDTCCount ) != PASS )
//	{
//		eRetCode = FAIL;
//	}

	// Check if a DTC is stored
	// If FF stored on pending fault then verify that it is in list of pending DTCs
	if ( gbDTCStored    == TRUE ||
	     bFFSupOnPendFault == TRUE )  // If FF stored on pending fault
	{
		// Verify all Freeze Frame DTCs are in the list of stored DTCs
		if ( VerifyFFDTCinDTCList ( ) != PASS )
		{
			eRetCode = FAIL;
		}

//		// Verify that all SID $19 LEV $03 PID data is valid
//		if ( VerifyAllFFData ( &FreezeFrameDTC[0][0],
//		                       FFDTCSupportCount,
//		                       &FFDTCCount[0] ) != PASS )
//		{
//			eRetCode = FAIL;
//		}
//	}
//	else
//	{
//		// Verify that all SID $19 LEV $03 PID data is valid
//		if ( VerifyAllFFData ( &FreezeFrameDTC[0][0],
//		                       FFDTCSupportCount,
//		                       &FFDTCCount[0] ) != PASS )
//		{
//			eRetCode = FAIL;
//		}
	}

	// test 6.5.1 - save FF DTC to compare during next test phase (7.5.1)
	if ( geTestPhase == eTestPendingDTC )
	{
		BYTE  EcuIdx;

		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			gstResponse[EcuIdx].pFFDTCList->Size = gstResponse[EcuIdx].FFSize;
			memcpy ( &gstResponse[EcuIdx].pFFDTCList->Dtc[0],
			         &gstResponse[EcuIdx].FF[0],
			         MAX_RESP_BUF_SIZE );
		}
	}

	// test 7.5.1 - compare FF DTC to previous test phase (6.5.1)
	if ( geTestPhase == eTestConfirmedDTC )
	{
		// Verify all Freeze Frame DTCs are in the list of previous Freeze Frame DTCs
		if ( VerifyFFDTCinFFDTCList ( ) != PASS )
		{
			eRetCode = FAIL;
		}
//		BYTE  EcuIdx;
//
//		for ( EcuIdx = 0;
//		      EcuIdx < gNumOfECUs;
//		      EcuIdx++ )
//		{
//			if ( FreezeFramePendingDTC[EcuIdx] != 0 &&
//			     FreezeFramePendingDTC[EcuIdx] != (unsigned long)(FreezeFrameDTC[EcuIdx]) )
//			{
//				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, YES_NO_ALL_PROMPT,
//				      "ECU %X  Confirmed Freeze Frame DTC doesn't match Pending FF DTC\n",
//				      GetEcuId ( EcuIdx ));
//				eRetCode = FAIL;
//			}
//		}
	}

	// Try group support
//	if ( FFDTCCount != 0 )
//	{
//		STATUS ret_code = VerifyGroupFreezeFrameSupport ( FreezeFrameDTC );
//		if ( ret_code != PASS )
//		{
//			bReturn = ret_code;
//		}
//
//		// Tests 6.x - 9.x only
//		if ( geTestPhase == eTestPendingDTC    || geTestPhase == eTestConfirmedDTC        ||
//		     geTestPhase == eTestFaultRepaired || geTestPhase == eTestNoFault3DriveCycle )
//		{
//			ret_code = VerifyGroupFreezeFrameResponse ( FreezeFrameDTC );
//			if ( ret_code != PASS )
//			{
//				bReturn = ret_code;
//			}
//		}
//	}

	if ( InitialFailureCount != GetFailureCount ( ) )
	{
		// There could have been early/late responses that weren't treated as FAIL
		// or the test failed earlier
		return FAIL;
	}
	else
	{
		return eRetCode;
	}

}


/*******************************************************************************
**
**  Function:  RequestFFSupportData
**
**  Purpose:   Verify that SID $19 LEV $04 returns a support record.
**             Continue requesting support PIDS thru highest supported group.
**
*******************************************************************************/
STATUS RequestFFSupportData ( unsigned char *pFreezeFrameDTC,
                              unsigned int   FFDTCCount )
{
	REQ_MSG       stReqMsg;
	BYTE          EcuIdx;
	STATUS        eRetCode = PASS;

	unsigned long IdIdx;
	unsigned long PIDSupportFlags;


	PIDSupportFlags = 0;  // Used to verify that if no PID support, failure may be flagged

	// Request SID $19 LEV $04 support data
	for ( IdIdx = 0x00;
	      IdIdx < 0x100;
	      IdIdx += 0x20 )
	{
		stReqMsg.SID     = 0x19;
		stReqMsg.NumIds  = 5;
		stReqMsg.u.ID[0] = 0x04;  // LEV: ReportDTCSnapshotRecordByDTCNumber
		stReqMsg.u.ID[1] = 0xFF;  // DTCMaskRecord.DTCHighByte
		stReqMsg.u.ID[2] = 0xFF;  // DTCMaskRecord.DTCMiddleByte
		stReqMsg.u.ID[3] = 0xFF;  // DTCMaskRecord.DTCLowByte
		stReqMsg.u.ID[4] = 0x00;  // DTCMaskRecord.DTCSnapshotRecordNumber

		if ( RequestSID ( &stReqMsg, REQ_MSG_ALLOW_NO_RESPONSE ) == FAIL )
		{
			// If there were any Freeze Frame DTCs, there must be a response to PID 0x00
			if ( (IdIdx == 0x00 && FFDTCCount != 0 ) ||
			     IdIdx != 0x00 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "No Response to SID $19 PID-Supported PID $%02X request\n",
				      IdIdx );
				return FAIL;
			}
		}

		for ( EcuIdx = 0;
		      EcuIdx < gNumOfECUs;
		      EcuIdx++ )
		{
			// If the next group is supported, request it
			if ( gstResponse[EcuIdx].FFSupport[IdIdx >> 5].SupBits[3] & 0x01 )
			{
				break;  // leave ECU for loop
			}
		}

		// If no ECUs support the next group, stop requests
		if ( EcuIdx >= gNumOfECUs )
		{
			break;  // leave support for loop
		}
	}


	// Flag error if ECU indicates no support
//	if ( VerifyFFSupportData ( pFreezeFrameDTC ) == FAIL )
//	{
//		eRetCode = FAIL;
//	}


	// Request next unsupported PID-support PID
	if ( IdIdx != 0xE0 )
	{
		stReqMsg.SID     = 0x19;
		stReqMsg.NumIds  = 2;
		stReqMsg.u.ID[1] = 0x04;
		stReqMsg.u.ID[0] = (unsigned char)(IdIdx += 0x20);

		if ( RequestSID ( &stReqMsg, REQ_MSG_NORMAL|REQ_MSG_IGNORE_NO_RESPONSE ) != FAIL )
		{
			for ( EcuIdx = 0;
			      EcuIdx < gNumOfECUs;
			      EcuIdx++ )
			{
				if ( gstResponse[EcuIdx].FFSize != 0 )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Unexpected response to unsupported SID $19 PID $%02X!\n",
					      GetEcuId ( EcuIdx ),
					      IdIdx );
					eRetCode = FAIL;
				}
			}
		}
	}


	// Verify ECU did not drop out
	if ( VerifyECUCommunication ( ) != PASS )
	{
		eRetCode = FAIL;
	}
	return eRetCode;
}


/*******************************************************************************
**
**  Function: RequestFFIDData
**
**  Purpose: Verify that SID $19 LEV $03 returns stored DTC.
**           Assuming SID $19 LEV $03 was supported by the controller,
**           data should be returned.
**
*******************************************************************************/
STATUS RequestFFIDData ( BOOL          *pbFFSupOnPendFault )
{
	REQ_MSG   stReqMsg;
	BYTE      EcuIdx;
	STATUS    eRetCode = PASS;

	BYTE      FFDTCCount = 0;         // Count of ECUs which respond to Freeze Frame Request with data
	BYTE      FFDTCSupportCount = 0;  // Count of ECUs which respond to Freeze Frame Request
	DTCASSR  *pFF;


	if ( gbPhysicalAddressing == FALSE )
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Request FFIDs (SID $19 LEV $03) Functionally Addressed\n" );
	}
	else
	{
		Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Request FFIDs (SID $19 LEV $03) Physically Addressed\n" );
	}


	// Request SID $19 LEV $03 data
	stReqMsg.SID     = 0x19;
	stReqMsg.NumIds  = 1;
	stReqMsg.u.ID[0] = 0x03;  // Subfunction (LEV): ReportSnapshotIdentification
	gbIgnoreUnsupported = TRUE;
	if ( (gbPhysicalAddressing == FALSE && RequestSID ( &stReqMsg, REQ_MSG_ALLOW_NO_RESPONSE ) != PASS) ||
	     (gbPhysicalAddressing == TRUE  && RequestSID_PhysicallyAddressed_All ( &stReqMsg, REQ_MSG_ALLOW_NO_RESPONSE ) != PASS) )
	{
		gbIgnoreUnsupported = FALSE;
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "SID $19 LEV $03 request error\n" );
		return FAIL;
	}
	gbIgnoreUnsupported = FALSE;

	// Check for freeze frame DTCs
	for ( EcuIdx = 0;
	      EcuIdx < gNumOfECUs;
	      EcuIdx++ )
	{
		// Clear Freeze Frame Array entry for this ECU
//		pFreezeFrameDTC[EcuIdx] = 0;

		// If there was a response by this ECU, Increment the count of ECUs which support Freeze Frame DTC
		if ( gstResponse[EcuIdx].bResponseReceived == TRUE )
		{
			FFDTCSupportCount++;
		}

		// Skip if no FFID data or no DTCs stored
		if ( gstResponse[EcuIdx].FFSize != 0 &&
		     (gstResponse[EcuIdx].FF[0] != 0 ||
		      gstResponse[EcuIdx].FF[1] != 0) )
		{
//			// Save the DTC
//			memcpy ( pFreezeFrameDTC,
//			         &gstResponse[EcuIdx].FF,
//			         gstResponse[EcuIdx].FFSize );

			pFF = (DTCASSR*)&gstResponse[EcuIdx].FF[0];
			FFDTCCount++;

			// Check if a DTC is not supposed to be present
			if ( gbDTCStored     == FALSE &&
			     gbDTCPending    == FALSE &&
			     gbDTCHistorical == FALSE )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  SID $19 LEV $03  FFDTC $%c%02X%02X stored\n",
				      GetEcuId ( EcuIdx ),
				      DTCTypeCharacter[(pFF->Dtc.HighByte & 0xC0 ) >> 6],  // 1st character (P, C, B, U)
				      pFF->Dtc.HighByte & 0x3F,                            // 2nd (0,1,2,3) and 3rd (0-F) characters
				      pFF->Dtc.MidByte );                                  // 4th and 5th (0-F) characters

				eRetCode = FAIL;
			}

			else if ( gbDTCPending == TRUE  &&
			          gbDTCStored  == FALSE )
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  SID $19 LEV $03  FFDTC $%c%02X%02X stored on pending fault\n",
				      GetEcuId ( EcuIdx ),
				      DTCTypeCharacter[(pFF->Dtc.HighByte & 0xC0) >> 6],  // 1st character (P, C, B, U)
				      pFF->Dtc.HighByte & 0x3F,                           // 2nd (0,1,2,3) and 3rd (0-F) characters
				      pFF->Dtc.MidByte );                                 // 4th and 5th (0-F) characters
				*pbFFSupOnPendFault = TRUE;
			}
			else
			{
				Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  SID $19 LEV $03 FFDTC $%c%02X%02X stored\n",
				      GetEcuId ( EcuIdx ),
				      DTCTypeCharacter[(pFF->Dtc.HighByte & 0xC0) >> 6],  // 1st character (P, C, B, U)
				      pFF->Dtc.HighByte & 0x3F,                           // 2nd (0,1,2,3) and 3rd (0-F) characters
				      pFF->Dtc.MidByte );                                 // 4th and 5th (0-F) characters
				*pbFFSupOnPendFault = TRUE;
			}
		}
		else
		{
			Log ( INFORMATION, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
			      "ECU %X  SID $19 LEV $03 indicates no FFDTC stored\n",
			      GetEcuId ( EcuIdx ) );
		}
	}

	// Test 5.11.1 - If all ECUs report Freeze Frame DTCs stored, it is a Failure
	if ( geTestPhase == eTestNoDTC && gTestSubsection == 11 &&
	     FFDTCCount != 0 &&
	     FFDTCCount == FFDTCSupportCount )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "All ECUs reported Freeze Frame DTCs stored\n" );
		eRetCode = FAIL;
	}

	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyFFDTCinDTCList
**
**  Purpose:   Verify the DTC in the freeze frame is in the list of stored DTCs.
**
*******************************************************************************/
STATUS VerifyFFDTCinDTCList ( void )
{
	STATUS         eRetCode = PASS;

	BYTE           FFEcuIdx;
	unsigned long  FFDTCIdx;
	unsigned long  FFDTC;
	unsigned long  FFDTCCount = 0;
	DTCASSR  *pFFDTC;

	BYTE           DTCEcuIdx;
	unsigned long  DTCIdx;
	unsigned long  StrdDTC;
	unsigned long  StrdDTCCount = 0;
	DTCASVR  *pDTC;

	unsigned long  MtchdDTCCount = 0;
	BOOL           bMtchdDTC = FALSE;


	// Count all DTCs for all ECUs
	for ( DTCEcuIdx = 0;
	      DTCEcuIdx < gNumOfECUs;
	      DTCEcuIdx++ )
	{
		// Count all Stored DTCs
		if ( gstResponse[DTCEcuIdx].pDTCList->Size != 0 )
		{
			for ( DTCIdx = 0;
			      DTCIdx < gstResponse[DTCEcuIdx].pDTCList->Size;
			      DTCIdx += sizeof ( DTCASVR ) )
			{
				pDTC = (DTCASVR *)(&gstResponse[DTCEcuIdx].pDTCList->Dtc[DTCIdx]);
				StrdDTC = (pDTC->Record.Dtc.HighByte << 8) + pDTC->Record.Dtc.MidByte;
				if ( StrdDTC != 0x0000 )
				{
					StrdDTCCount++;
				}
			}
		}

		// Count all Freeze Frames
		for ( FFDTCIdx = 0;
		      FFDTCIdx < gstResponse[DTCEcuIdx].FFSize;
		      FFDTCIdx += sizeof ( DTCASSR ) )
		{
			pFFDTC = (DTCASSR *)(&gstResponse[DTCEcuIdx].FF[0]);
			FFDTC = (pFFDTC->Dtc.HighByte << 8) + pFFDTC->Dtc.MidByte;
			if ( FFDTC != 0x0000  )
			{
				FFDTCCount++;
			}
		}
	}


	// Verify each Freeze DTCs is in the list of Confirmed or Pending DTCs
	for ( FFEcuIdx = 0;
	      FFEcuIdx < gNumOfECUs;
	      FFEcuIdx++ )
	{
		for ( FFDTCIdx = 0;
		      FFDTCIdx < gstResponse[FFEcuIdx].FFSize;
		      FFDTCIdx += sizeof ( DTCASSR ) )
		{
			bMtchdDTC = FALSE;

			pFFDTC = (DTCASSR *)(&gstResponse[FFEcuIdx].FF[FFDTCIdx]);
			FFDTC = (pFFDTC->Dtc.HighByte << 8) + pFFDTC->Dtc.MidByte;
			if ( FFDTC != 0x0000 )
			{
				for ( DTCEcuIdx = 0;
				      DTCEcuIdx < gNumOfECUs;
				      DTCEcuIdx++ )
				{
					for ( DTCIdx = 0;
					      DTCIdx < gstResponse[DTCEcuIdx].pDTCList->Size;
					      DTCIdx += sizeof ( DTCASVR ) )
					{
						pDTC = (DTCASVR*)(&gstResponse[DTCEcuIdx].pDTCList->Dtc[DTCIdx]);
						StrdDTC = (pDTC->Record.Dtc.HighByte << 8) + pDTC->Record.Dtc.MidByte;
						if ( StrdDTC != 0x0000 )
						{
							if ( FFDTC == StrdDTC )
							{
								bMtchdDTC = TRUE;
								MtchdDTCCount++;
								break;  // leave DTC index for loop
							}
						}
					}  // end for DTC Index < DTC Size
	
					if ( bMtchdDTC == TRUE )
					{
						break;  // leave DTC ECU for loop
					}
				}  // end for DTC ECU
	
				if ( !bMtchdDTC )
				{
					Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
					      "ECU %X  Freeze Frame DTC $%c%02X%02X not found in list of stored or pending DTCs on any ECU\n",
					      GetEcuId (FFEcuIdx),
					      DTCTypeCharacter[(pFFDTC->Dtc.HighByte & 0xC0) >> 6],  // 1st character (P, C, B, U)
					      pFFDTC->Dtc.HighByte & 0x3F,                           // 2nd (0,1,2,3) and 3rd (0-F) characters
					      pFFDTC->Dtc.MidByte );                                 // 4th and 5th (0-F) characters
					eRetCode = FAIL;
				}
			}  // end FFDTC != 0x0000
		}  // end for FFDTC index < FFSize
	}  // end for FF ECU


	if ( StrdDTCCount !=0  &&
	     MtchdDTCCount == 0 )
	{
		Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
		      "Stored DTC with no Freeze Frame DTC on any ECU\n" );
		eRetCode = FAIL;
	}


	return eRetCode;
}


/*******************************************************************************
**
**  Function:  VerifyFFDTCinFFDTCList
**
**  Purpose:   Verify the DTC in the freeze frame is in the list of previous freeze frame DTCs.
**
*******************************************************************************/
STATUS VerifyFFDTCinFFDTCList ( void )
{
	STATUS         eRetCode = PASS;

	BYTE           FFEcuIdx;
	unsigned long  FFDTCIdx;
	unsigned long  FFDTC;
	unsigned long  FFDTCCount = 0;
	DTCASSR   *pFFDTC;

	unsigned long  DTCIdx;
	unsigned long  StrdDTC;
	unsigned long  StrdDTCCount = 0;
	DTCASSR   *pDTC;

	unsigned long  MtchdDTCCount = 0;
	BOOL           bMtchdDTC = FALSE;


	// Verify each Freeze Frame DTC is in the list of previous freeze frame DTCs
	for ( FFEcuIdx = 0;
	      FFEcuIdx < gNumOfECUs;
	      FFEcuIdx++ )
	{
		for ( FFDTCIdx = 0;
		      FFDTCIdx < gstResponse[FFEcuIdx].FFSize;
		      FFDTCIdx += sizeof ( DTCASSR ) )
		{
			bMtchdDTC = FALSE;

			pFFDTC = (DTCASSR *)(&gstResponse[FFEcuIdx].FF[FFDTCIdx]);
			FFDTC = (pFFDTC->Dtc.HighByte << 8) + pFFDTC->Dtc.MidByte;
			if ( FFDTC != 0x0000 )
			{
				for ( DTCIdx = 0;
				      DTCIdx < gstResponse[FFEcuIdx].pFFDTCList->Size;
				      DTCIdx += sizeof ( DTCASSR ) )
				{
					pDTC = (DTCASSR*)(&gstResponse[FFEcuIdx].pFFDTCList->Dtc[DTCIdx]);
					StrdDTC = (pDTC->Dtc.HighByte << 8) + pDTC->Dtc.MidByte;
					if ( StrdDTC != 0x0000 )
					{
						if ( FFDTC == StrdDTC )
						{
							bMtchdDTC = TRUE;
							MtchdDTCCount++;
							break;  // leave DTC index for loop
						}
					}
				}  // end for DTC Index < DTC Size
	
				if ( bMtchdDTC == TRUE )
				{
					break;  // leave DTC ECU for loop
				}
			}  // end FFDTC != 0x0000
	
			if ( !bMtchdDTC && FFDTC != 0x0000 )
			{
				Log ( FAILURE, SCREENOUTPUTON, LOGOUTPUTON, NO_PROMPT,
				      "ECU %X  Freeze Frame DTC $%c%02X%02X not found in list of previous Freeze Frame DTCs on this ECU\n",
				      GetEcuId (FFEcuIdx),
				      DTCTypeCharacter[(pFFDTC->Dtc.HighByte & 0xC0) >> 6],  // 1st character (P, C, B, U)
				      pFFDTC->Dtc.HighByte & 0x3F,                           // 2nd (0,1,2,3) and 3rd (0-F) characters
				      pFFDTC->Dtc.MidByte );                                 // 4th and 5th (0-F) characters
				eRetCode = FAIL;
			}

		}  // end for FFDTC index < FFSize
	}  // end for FF ECU

	return eRetCode;
}
