/*
 * Hal_Fls.c
 *
 *  Created on: 2022Äê4ÔÂ6ÈÕ
 *      Author: Zhengchao
 */
#include "Hal_Fls.h"
#include "math.h"
/* Application can used space */
const BlockInfo_t gs_astBlockNumB[] =
{
    {APP_B_START_ADDR, APP_B_END_ADDR},    /* Block logical B */
};

/* Application flash status, this status info should be saved into flash */
static tAppFlashStatus gs_stAppFlashStatus;

#define GetAppStatusPtr() (&gs_stAppFlashStatus)

static tAppDownloadType gs_stAppDownloadInfo = {APP_VECTOR_TABLE_OFFSET,0,0};

#define SetFlashEreaseStatus(bIsFlashEraseSuccessful) \
    do{\
        gs_stAppFlashStatus.isFlashErasedSuccessfull = bIsFlashEraseSuccessful;\
    }while(0u)

#define SetFlashProgramStatus(bIsFlashProgramSuccessful) \
    do{\
        gs_stAppFlashStatus.isFlashProgramSuccessfull = bIsFlashProgramSuccessful;\
    }while(0u)

#define SetAppUpdateControllerName(bControolerName) \
    do{\
        gs_stAppFlashStatus.controllerName = bControolerName;\
    }while(0u)

#define SaveAppResetHandlerAddr(resetHandlerAddr, resetHnadlerAddrLen) \
    do{\
        gs_stAppFlashStatus.appStartAddr = resetHandlerAddr;\
        gs_stAppFlashStatus.appStartAddrLen = resetHnadlerAddrLen;\
    }while(0u)


#define SaveAppStatusCrc(xCrc)\
    do{\
        gs_stAppFlashStatus.crc = xCrc;\
    }while(0u)

/* Create APP status CRC and save */
#define CreateAndSaveAppStatusCrc(o_pCrc) \
    do{\
        CreateAppStatusCrc(o_pCrc);\
        SaveAppStatusCrc(*o_pCrc);\
    }while(0u)

#define CreateAppStatusCrc(o_pCrc) CRC_HAL_CreatSoftwareCrc((uint8 *)&gs_stAppFlashStatus, sizeof(gs_stAppFlashStatus) - 4u, o_pCrc)

#define IsFlashEraseSuccessful() (gs_stAppFlashStatus.isFlashErasedSuccessfull)
#define IsFlashProgramSuccessful() (gs_stAppFlashStatus.isFlashProgramSuccessfull)


static void Hal_FlsSaveFingerPrint(const uint8 *i_pFingerPrint, const uint8 i_FingerPrintLen);


#define SetFlashStructStatus(bIsAppFlashStructValid) \
    do{\
        gs_stAppFlashStatus.isFlashStructValid = bIsAppFlashStructValid;\
    }while(0u)

#define SetDownloadAppLength(bAppLength) \
    do{\
    	gs_stAppDownloadInfo.appLength = bAppLength;\
    	gs_stAppFlashStatus.appLength = bAppLength;\
    }while(0u)

#define SetDownloadAppPackCRC(bAppReceivedCRC) \
    do{\
    	gs_stAppDownloadInfo.receivedCRC = bAppReceivedCRC;\
    }while(0u)



//#define SetAPPStatus(bIsFlashEraseSuccessful, bIsFlashProgramSuccessful, bIsAppFlashStructValid) \
//    do{\
//        SetFlashEreaseStatus(bIsFlashEraseSuccessful);\
//        SetFlashProgramStatus(bIsFlashProgramSuccessful);\
//        SetFlashStructStatus(bIsAppFlashStructValid);\
//    }while(0u)


MemIf_JobResultType Hal_FlsWrite(Fls_AddressType u32TargetAddress, uint8 * pSourceAddressPtr, Fls_LengthType u32Length, uint32 timeOutMs)
{
	MemIf_JobResultType ret = MEMIF_JOB_FAILED;
	if(TRUE == IsFlashEraseSuccessful())
	{
		Fls_Write(u32TargetAddress,pSourceAddressPtr,u32Length);
		do
		{
			Fls_MainFunction();
			vTaskDelay(pdMS_TO_TICKS(1));
			timeOutMs--;
		}while(MEMIF_IDLE != Fls_GetStatus() && timeOutMs>0);
		ret = Fls_GetJobResult();
	}
	return ret;
}

MemIf_JobResultType Hal_FlsRead(Fls_AddressType u32TargetAddress, uint8 * pSourceAddressPtr, Fls_LengthType u32Length, uint32 timeOutMs)
{
	MemIf_JobResultType ret = MEMIF_JOB_FAILED;
	Fls_Read(u32TargetAddress,pSourceAddressPtr,u32Length);
	while(MEMIF_IDLE != Fls_GetStatus() && timeOutMs>0)
	{
		Fls_MainFunction();
		vTaskDelay(pdMS_TO_TICKS(1));
		timeOutMs--;
	}
	ret = Fls_GetJobResult();
	return ret;
}

MemIf_JobResultType Hal_FlsErase(Fls_AddressType u32TargetAddress, uint32 eraseInternalLength, uint32 timeOutMs)
{
	MemIf_JobResultType ret = MEMIF_JOB_FAILED;
	Fls_LengthType u32Length = 0;
	if(eraseInternalLength > NUMBER_OF_INTERNAL_SECTOR * INTERNAL_SECTOR_SIZE)
	{
		u32Length = NUMBER_OF_INTERNAL_SECTOR * INTERNAL_SECTOR_SIZE;
	}
	else
	{
		u32Length = ceil((double)(eraseInternalLength/(double)(INTERNAL_SECTOR_SIZE))) * INTERNAL_SECTOR_SIZE;
	}

	Fls_Erase(u32TargetAddress,u32Length);
	do
	{
		Fls_MainFunction();
		vTaskDelay(pdMS_TO_TICKS(1));
		timeOutMs--;
	}while(MEMIF_IDLE != Fls_GetStatus() && timeOutMs>0);
	ret = Fls_GetJobResult();
	if(ret == MEMIF_JOB_OK)
	{
		SetFlashEreaseStatus(TRUE);
	}
	else
	{
		SetFlashEreaseStatus(FALSE);
	}
	return ret;
}


void Hal_SetAppInfo(uint32 appLength, uint32 appReceviedCRC,ControllerType controllerName)
{
	SetDownloadAppLength(appLength);
	SetDownloadAppPackCRC(appReceviedCRC);
	SetAppUpdateControllerName(controllerName);
	uint32 fingerPrint = 0x5555;
	Hal_FlsSaveFingerPrint(&fingerPrint, 2); //save finger print
}


/* Save FingerPrint */
static void Hal_FlsSaveFingerPrint(const uint8 *i_pFingerPrint, const uint8 i_FingerPrintLen)
{
    uint8 FingerPrintLen = 0u;
//    tCrc crc = 0u;
//    ASSERT(NULL_PTR == i_pFingerPrint);

    if (i_FingerPrintLen > FL_FINGER_PRINT_LENGTH)
    {
        FingerPrintLen = FL_FINGER_PRINT_LENGTH;
    }
    else
    {
        FingerPrintLen = (uint8)i_FingerPrintLen;
    }

    memcpy((void *) gs_stAppFlashStatus.aFingerPrint, (const void *) i_pFingerPrint,
               FingerPrintLen);
//    CreateAndSaveAppStatusCrc(&crc);
}

/* Get storage reset handler information */
static uint32 Hal_FlsGetStorageRestHandlerAddr(void)
{
    return APP_VECTOR_TABLE_OFFSET + RESET_HANDLER_OFFSET;
}

/* Get reset handler addr length */
static uint32 Hal_FlsGetResetHandlerLen(void)
{
    return RESET_HANDLER_ADDR_LEN;
}

static boolean Hal_GetAPPFlsInfo(uint32 *o_pAppInfoStartAddr, uint32 *o_pBlockSize)
{
    boolean result = FALSE;

	*o_pAppInfoStartAddr = gs_astBlockNumB[0u].xBlockStartLogicalAddr;
	*o_pBlockSize = gs_astBlockNumB[0u].xBlockEndLogicalAddr - gs_astBlockNumB[0u].xBlockStartLogicalAddr;
	result = TRUE;

    return result;
}



/* Flash check sum */
static uint8 FlashChecksum(void)
{
    uint32 xCountCrc = 0u;
    CRC_HAL_CreatSoftwareCrc((const uint8 *)(gs_stAppDownloadInfo.appVectoTableStartAddr + APP_FLAST_START_PHY_ADDR), gs_stAppDownloadInfo.appLength, &xCountCrc);

    if(gs_stAppDownloadInfo.receivedCRC == xCountCrc)
    {
    	return TRUE;
    }
    else
    {
    	return FALSE;
    }
}

static void Hal_FlsGetResetHandlerInfo(uint32 *o_pResetHandlerOffset, uint32 *o_pResetHandlerLength)
{
    if(NULL_PTR != o_pResetHandlerOffset && NULL_PTR != o_pResetHandlerLength)
    {
    	*o_pResetHandlerOffset = Hal_FlsGetStorageRestHandlerAddr();
    	*o_pResetHandlerLength = Hal_FlsGetResetHandlerLen();
    }
}


void Hal_FlsGetAppVectorTableStartAddr(uint32 *appVectorTableStartAddr)
{
	*appVectorTableStartAddr = gs_stAppDownloadInfo.appVectoTableStartAddr;
}



static uint8 Hal_FlsWriteFlashAppInfo(void)
{

	uint8 result = FALSE;
	MemIf_JobResultType flsRet = MEMIF_JOB_FAILED;

	tAppFlashStatus *pAppStatusPtr = NULL_PTR;
	uint32 appInfoStartAddr = 0u;
	uint32 appInfoLen = 0u;

	uint32 resetHandlerOffset = 0u;
	uint32 resetHandlerLength = 0u;

	uint32 resetHandleLogicalAddr = 0u;
	uint8 resetHandleAddrTemp[RESET_HANDLER_ADDR_LEN];
	uint32 resetHandlePhyAddr = 0u;

	uint32 crc = 0u;

	/* Write data information in flash */
	pAppStatusPtr = GetAppStatusPtr();

	Hal_GetAPPFlsInfo(&appInfoStartAddr, &appInfoLen);

	Hal_FlsGetResetHandlerInfo(&resetHandlerOffset,&resetHandlerLength);

	resetHandleLogicalAddr = appInfoStartAddr + resetHandlerOffset;

	Hal_FlsRead(resetHandleLogicalAddr,resetHandleAddrTemp,RESET_HANDLER_ADDR_LEN,500);

	for(uint8 i=0; i<RESET_HANDLER_ADDR_LEN;i++)
	{
		resetHandlePhyAddr |= (resetHandleAddrTemp[i]<<(8*i));
	}


	SaveAppResetHandlerAddr(resetHandlePhyAddr, resetHandlerLength);


	CreateAndSaveAppStatusCrc(&crc);

	if(pAppStatusPtr != NULL_PTR)
	{
		 flsRet = Hal_FlsWrite(appInfoStartAddr,(uint8 *)pAppStatusPtr,sizeof(tAppFlashStatus),500);
	}
	if(flsRet == MEMIF_JOB_OK)
	{
		result = TRUE;
	}
	else
	{
		result = FALSE;
	}
	return result;

}

uint8 Hal_FlsCheckIsTransferSucceed(void)
{
	uint8 ret = FALSE;
	if(TRUE == FlashChecksum())
	{
		SetFlashProgramStatus(TRUE);
		ret = TRUE;
	}
	else
	{
		SetFlashProgramStatus(FALSE);
		ret = FALSE;
	}

	SetFlashStructStatus(TRUE);
	Hal_FlsWriteFlashAppInfo();

	Hal_SetAppInfo(0,0xFFFFFFFF,CONTROLLER_SELF);
	SetFlashEreaseStatus(FALSE);

	return ret;
}


