#include "Non_volatile_Memorys.h"
#include "EEPROM_24Cxx_Remap.h"
typedef union
{
	struct
	{
		uint8_t Flag[4];
	} Sig;
	uint8_t Data[4];
} NVMInitUnion;

const NVMInitUnion NVMDefaultInit =
	{
		"TYW",
};

const NVMODOUnion NVMDefaultODO =
	{
		0,
		0,
		0,
		0,
};

const uint8_t NVMDefault_Zero[16] =
	{
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,

};
/*const uint8_t NVMDTCDefaultValue[37] =
{
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
	0x00,
}; */

NVMInitUnion NVMInit;
NVMODOUnion NVMODO;
NVMTRIPUnion NVMTRIP;

#pragma ghs section bss = ".myNonInitArea"	    
#pragma alignvar(8)
uint8_t u8NVMMaintenance[16];
#pragma alignvar(8)
uint8_t u8MileODORelated[16];
 #pragma ghs section bss = default
uint8_t u8MileSnapshotRelated[20][16];



typedef struct
{
	uint8_t *pData;
	const uint8_t *pDefaultValue;
	uint8_t Len;
	uint8_t DataType;
	uint16_t Addr;
} NVMDataAttributeTableStruct;

uint8_t NVMEEPROMFault;
#define NVM_EEPROM_FAULT NVMEEPROMFault

typedef struct
{
	uint8_t u8NVMEnable;
	uint8_t Req[NVM_TOTAL_DATA_NUM];
	uint8_t Current;
} NVMUpdateCtrlStruct;

NVMUpdateCtrlStruct NVMUpdateCtrl;
//uint8_t aaaa[37];
const NVMDataAttributeTableStruct NVMDataAttributeTable[] =
	{

		{NVMInit.Data, NVMDefaultInit.Data, 4, EEPROM_HIREL_DATA_TYPE, 0x0000},
		{NVMODO.Data, NVMDefaultODO.Data, 8, EEPROM_HIREL_DATA_TYPE, 0x0001},

		{/* 		 */ u8NVMMaintenance, NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0000},

		{/*			 */ u8MileODORelated, NVMDefault_Zero, 8, EEPROM_NORMAL_DATA_TYPE, 0x0020}, //
		{/*			 */ &u8MileODORelated[8], NVMDefault_Zero, 8, EEPROM_NORMAL_DATA_TYPE, 0x0028}, //

		{/*			 */ &u8MileSnapshotRelated[0][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x0040},  //
		{/*			 */ &u8MileSnapshotRelated[1][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x0050},  //
		{/*			 */ &u8MileSnapshotRelated[2][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x0060},  //
		{/*			 */ &u8MileSnapshotRelated[3][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x0070},  //
		{/*			 */ &u8MileSnapshotRelated[4][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x0080},  //
		{/*			 */ &u8MileSnapshotRelated[5][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x0090},  //
		{/*			 */ &u8MileSnapshotRelated[6][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x00A0},  //
		{/*			 */ &u8MileSnapshotRelated[7][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x00B0},  //
		{/*			 */ &u8MileSnapshotRelated[8][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x00C0},  //
		{/*			 */ &u8MileSnapshotRelated[9][0], NVMDefault_Zero,     16, EEPROM_NORMAL_DATA_TYPE, 0x00D0},  //
		{/*			 */ &u8MileSnapshotRelated[10][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x00E0}, //
		{/*			 */ &u8MileSnapshotRelated[11][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x00F0}, //
		{/*			 */ &u8MileSnapshotRelated[12][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0100}, //
		{/*			 */ &u8MileSnapshotRelated[13][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0110}, //
		{/*			 */ &u8MileSnapshotRelated[14][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0120}, //
		{/*			 */ &u8MileSnapshotRelated[15][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0130}, //
		{/*			 */ &u8MileSnapshotRelated[16][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0140}, //
		{/*			 */ &u8MileSnapshotRelated[17][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0150}, //
		{/*			 */ &u8MileSnapshotRelated[18][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0160}, //
		{/*			 */ &u8MileSnapshotRelated[19][0], NVMDefault_Zero,    16, EEPROM_NORMAL_DATA_TYPE, 0x0170}, //
		
		//{			 &DiagDtc[0].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0180},
		//{			 &DiagDtc[0].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0190},
		//{			 &DiagDtc[0].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x01A0}, //
		//{			 &DiagDtc[1].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x01B0},
		//{			 &DiagDtc[1].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x01C0},
		//{			 &DiagDtc[1].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x01D0}, //
		//{			 &DiagDtc[2].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x01E0},
		//{			 &DiagDtc[2].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x01F0},
		//{			 &DiagDtc[2].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x0200}, //
		//{			 &DiagDtc[3].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0210},
		//{			 &DiagDtc[3].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0220},
		//{			 &DiagDtc[3].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x0230}, //
		//{			 &DiagDtc[4].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0240},
		//{			 &DiagDtc[4].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0250},
		//{			 &DiagDtc[4].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x0260}, //
		//{			 &DiagDtc[5].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0270},
		//{			 &DiagDtc[5].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0280},
		//{			 &DiagDtc[5].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x0290}, //
		//{			 &DiagDtc[6].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x02A0},
		//{			 &DiagDtc[6].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x02B0},
		//{			 &DiagDtc[6].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x02C0}, //
		//{			 &DiagDtc[7].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x02D0},
		//{			 &DiagDtc[7].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x02E0},
		//{			 &DiagDtc[7].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x02F0}, //
		//{			 &DiagDtc[8].Status.Flag      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0300},
		//{			 &DiagDtc[8].ExtendData.ExLMonth      , NVMDefault_Zero, 16, EEPROM_NORMAL_DATA_TYPE, 0x0310},
		//{			 &DiagDtc[8].SnapShotInfo.FirstOccurOdometer_L                  , NVMDefault_Zero, 5, EEPROM_NORMAL_DATA_TYPE, 0x0320}, //
};

void NVM_Init(void)
{
	uint8_t i;
	uint8_t j;

	uint8_t *pData;
 const 	uint8_t *pDefaultValue;
	uint8_t Len;

#if NVM_USE_EEPROM

	uint8_t Type;
	uint16_t Addr;

	uint8_t InitStatus;
	EEPROMAccessStatusEnum Status;

	NVMUpdateCtrl.u8NVMEnable = 0;
	NVMUpdateCtrl.Current = 0xFF;
	for (i = 0; i < NVM_TOTAL_DATA_NUM; i++)
		NVMUpdateCtrl.Req[i] = 0;

	pData = NVMDataAttributeTable[NVM_INIT_DATA].pData;
	Len = NVMDataAttributeTable[NVM_INIT_DATA].Len;
	Type = NVMDataAttributeTable[NVM_INIT_DATA].DataType;
	Addr = NVMDataAttributeTable[NVM_INIT_DATA].Addr;

	Status = EEPROM_Startup_Data_Read(Type, Addr, pData, Len);

	if (Status == EEPROM_DATA_OK)
	{
		NVM_EEPROM_FAULT = 0;
		InitStatus = 1;
	}
	else if (Status == EEPROM_DATA_PARTIAL_LOST)
	{
		NVM_EEPROM_FAULT = 0;
		InitStatus = 1;
		NVM_Data_Update(NVM_INIT_DATA);
	}
	else if (Status == EEPROM_DATA_LOST)
	{
		NVM_EEPROM_FAULT = 0;
		InitStatus = 0;
	}
	else
	{
		NVM_EEPROM_FAULT = 1;
		InitStatus = 0;
	}

	if (InitStatus)
	{
		i = 0;
		pDefaultValue = NVMDataAttributeTable[NVM_INIT_DATA].pDefaultValue;

		while (i < Len)
		{
			if (pData[i] != pDefaultValue[i])
			{
				InitStatus = 0;
				break;
			}

			i++;
		}
	}

	if (InitStatus)
	{

		if (NVM_TOTAL_DATA_NUM > 1)
		{
			for (i = 1; i < NVM_TOTAL_DATA_NUM; i++)
			{
				pData = NVMDataAttributeTable[i].pData;
				Len = NVMDataAttributeTable[i].Len;
				Type = NVMDataAttributeTable[i].DataType;
				Addr = NVMDataAttributeTable[i].Addr;

				Status = EEPROM_Startup_Data_Read(Type, Addr, pData, Len);

				if (Status == EEPROM_DATA_PARTIAL_LOST)
				{
					NVM_Data_Update(i);
				}
				else if (Status != EEPROM_DATA_OK)
				{
					pDefaultValue = NVMDataAttributeTable[i].pDefaultValue;

					for (j = 0; j < Len; j++)
						pData[j] = pDefaultValue[j];

					NVM_Data_Update(i);
				}
			}
		}
	}
	else
	{
		for (i = 0; i < NVM_TOTAL_DATA_NUM; i++)
		{
			pData = NVMDataAttributeTable[i].pData;
			pDefaultValue = NVMDataAttributeTable[i].pDefaultValue;
			Len = NVMDataAttributeTable[i].Len;

			for (j = 0; j < Len; j++)
				pData[j] = pDefaultValue[j];

			NVM_Data_Update(i);
		}
	}

#else

	NVM_EEPROM_FAULT = 0;

	for (i = 0; i < NVM_TOTAL_DATA_NUM; i++)
	{
		pData = NVMDataAttributeTable[i].pData;
		pDefaultValue = NVMDataAttributeTable[i].pDefaultValue;
		Len = NVMDataAttributeTable[i].Len;

		for (j = 0; j < Len; j++)
			pData[j] = pDefaultValue[j];
	}

#endif
}

void NVM_Data_Update(uint8_t DataName)
{
#if NVM_USE_EEPROM

	if (NVM_EEPROM_FAULT == 0)
	{
		if (DataName < NVM_TOTAL_DATA_NUM)
		{
			NVMUpdateCtrl.Req[DataName] = 1;
			NVMUpdateCtrl.u8NVMEnable = 1;
		}
	}

#endif
}

void NVM_Data_Update_Service(void)
{
#if NVM_USE_EEPROM
	uint8_t i;
	uint8_t *pData;
	uint8_t Len;
	uint8_t Type;
	uint16_t Addr;

	EEPROMAccessStatusEnum Status;

	if (NVMUpdateCtrl.u8NVMEnable)
	{
		if (NVMUpdateCtrl.Current < NVM_TOTAL_DATA_NUM)
		{
			Status = EEPROM_Get_Data_Write_Status();

			if (Status == EEPROM_DATA_OK)
				NVMUpdateCtrl.Req[NVMUpdateCtrl.Current] = 0;
			else if (Status == EEPROM_MEMORY_BUSY)
				return;
		}

		NVMUpdateCtrl.Current = 0xFF;

		i = NVM_TOTAL_DATA_NUM;

		while (i)
		{
			i--;

			if (NVMUpdateCtrl.Req[i])
			{
				pData = NVMDataAttributeTable[i].pData;
				Len = NVMDataAttributeTable[i].Len;
				Type = NVMDataAttributeTable[i].DataType;
				Addr = NVMDataAttributeTable[i].Addr;

				Status = EEPROM_Data_Write(Type, Addr, pData, Len);

				if (Status == EEPROM_DATA_OK)
					NVMUpdateCtrl.Current = i;

				return;
			}
		}

		NVMUpdateCtrl.u8NVMEnable = 0;
	}

#endif
}
void Delay_Ms(uint8_t Time)
{
	// uint16_t Delay = Time;
	// Delay *= 1000 / API_INT_CYCLE;
	// Delay += API_ROLLING_COUNTER;
	// while (Delay != API_ROLLING_COUNTER);
}