/*********************************************************************************
**										 **
** Name			:   Dataflash.c	                                         **
**										 **
** Description	:								 **
**										 **
** 										 **
** Organization	:  Sun Mobility Pvt Ltd                             		 **
**										 **
** Revision		:   1.00 						 **
**********************************************************************************
** Revision History								 **
**  Rev      Date         By                  	Reason for Change 		 **
**------------------------------------------------------------------------------**
**  1.00     22-11-2024   Tushar Shetty		Base Version			                **
**										                                        **
*********************************************************************************/

/*********************************************************************************
**                     I N C L U D E  F I L E S
*********************************************************************************/
#include	"DataFlash.h"
#include    "ti_msp_dl_config.h"
/*********************************************************************************
**                          F U N C T I O N S
*********************************************************************************/

/*********************************************************************************
**   I N T E R N A L   M A C R O   A N D   T Y P E   D E F I N I T I O N S
*********************************************************************************/
typedef union MemoryParam_Tag
{
	struct
	{
	    uint8_t   Byte0;
	    uint8_t   Byte1;
	    uint8_t   Byte2;
	    uint8_t   Byte3;
	}Bytes;
	uint32_t Word;   
}MemoryParam;

/*********************************************************************************
**      I N T E R N A L   F U N C T I O N   P R O T O T Y P E S
*********************************************************************************/

/*********************************************************************************
**                   		V A R I A B L E S
**********************************************************************************/
uint32_t  	    gUI32_DataBuffer[SECTOR_MEM_SIZE /(MEM_BYTES_PER_ONCE/2)];


/*********************************************************************************
** Name			:	SM_Dataflash_Init				                            **
** Description	:		Number of Wait Cycles during flash operation	        **
** Inputs		:	None						                                **
** Outputs		:							                                    **
** Returns		:	None						                                **
*********************************************************************************/
void SM_Dataflash_Init(void)
{
	
}
/*********************************************************************************
** Name			:	SM_Flash_Read					**
** Description	:								**
** Inputs		:	None						**
** Outputs		:							**
** Returns		:	None						**
*********************************************************************************/
void SM_Flash_Read(uint32_t lUI32_StartWordAddress,uint32_t *lUI32_Data,uint16_t lUI16_NoOfWords)
{
	
    volatile    uint32_t   lUI32_DataFlashAddrress = lUI32_StartWordAddress;
                uint16_t   lUI16_FlashCounterIndex=0U; 
    for(lUI16_FlashCounterIndex=0; lUI16_FlashCounterIndex<lUI16_NoOfWords;lUI16_FlashCounterIndex++)
    {
        /*Reading the Data Flash directly from the memory by assigning address*/
        *lUI32_Data =(*(volatile unsigned int*)lUI32_DataFlashAddrress);
         /*Address incremented by 4.*/
        lUI32_DataFlashAddrress = lUI32_DataFlashAddrress + 4;
        /* Data Read array increment.*/
        lUI32_Data = lUI32_Data + 1;
    }
}

/*************************************************************************************
** Name			:	SM_Flash_Write					                                **
** Description	:	Writes the Data Buffer of uint32 to the Data Flash   			**
** Inputs		:	lUI32_StartWordAddress: Start Memory address    				**
**				 lUI16_NoOfWords: Number of Words to be written                     **
                 lUI32_Data: Data Buffer to be written                              **    
** Outputs		:							                                        **
** Returns		:	lUI_8FlashWriteStatus						                    **
*************************************************************************************/

uint8_t SM_Flash_Write(uint32_t lUI32_StartWordAddress, uint32_t *lUI32_Data,uint16_t lUI16_NoOfWords)
{
  	            uint16_t    lUI16_NoofWordsIndex = 0U;
    volatile    uint32_t    lUI32_WriteFlashAddress = lUI32_StartWordAddress;
                uint8_t     lUI8_WriteErrorType = ERROR_FAIL;
                uint8_t     lUI8_WriteCmdStatus=0U; 
                uint16_t    lUI16_WriteTimeout=0U;

    for( lUI16_NoofWordsIndex = lUI16_NoOfWords;lUI16_NoofWordsIndex > 0; lUI16_NoofWordsIndex--)
    {
        lUI16_WriteTimeout=0;
        DL_FlashCTL_unprotectSector(
        FLASHCTL, lUI32_WriteFlashAddress, DL_FLASHCTL_REGION_SELECT_MAIN);      
        /*8 Byte Data Flash At a Time.*/
        lUI8_WriteCmdStatus=DL_FlashCTL_programMemoryFromRAM64WithECCGenerated( FLASHCTL,lUI32_WriteFlashAddress,lUI32_Data);
        while(lUI8_WriteCmdStatus==DL_FLASHCTL_COMMAND_STATUS_IN_PROGRESS && lUI16_WriteTimeout++<6400);    
        if( lUI8_WriteCmdStatus == DL_FLASHCTL_COMMAND_STATUS_PASSED)         
        {    
            lUI8_WriteCmdStatus=DL_FlashCTL_readVerifyFromRAM64WithECCGenerated( FLASHCTL,lUI32_WriteFlashAddress,lUI32_Data);
            if (lUI8_WriteCmdStatus != DL_FLASHCTL_COMMAND_STATUS_PASSED) 
            {
                /* If command did not pass, set error flag. */
                lUI8_WriteErrorType = ERROR_FAIL;
                break;
            }
            else
            {
               /*Flash Written Status */
                lUI8_WriteErrorType = NO_ERROR;
            }    
			
        }
        else 
        {
            /* If command did not pass, set error flag */
            lUI8_WriteErrorType = ERROR_FAIL;
            break;
        }

        /*DataFlash Address increment by length of 2 words(8 Bytes)*/
        lUI32_WriteFlashAddress = lUI32_WriteFlashAddress + 8;
        /*Write Array increment by 2 words(8 Bytes)*/
        lUI32_Data = lUI32_Data + 2;
    }
    return lUI8_WriteErrorType;
}
/*********************************************************************************
** Name			:	SM_Flash_Erase					                            **
** Description	:	Sector(1KB) Erase in the Data Flash							**
** Inputs		:		lUI32_SectorStartAddress: Memory address to write the 	**
**				data from the memory				                            **
**				lUI16_NoOfSectors: Number of Sectors to Erased                  **
** Outputs		:						                                        **
** Returns		:	lUI_8FlashEraseStatus: Flash Error Status				    **
*********************************************************************************/
uint8_t SM_Flash_Erase(uint32_t lUI32_SectorStartAddress,uint16_t lUI16_NoOfSectors)
{
    volatile    uint32_t    lUI32_SectorStartAdd = lUI32_SectorStartAddress;
                uint16_t    lUI16_BlockNoIndex = 0U;
                uint8_t     lUI8_ErrorType = ERROR_FAIL;
                uint8_t     lUI8_EraseCmdStatus=0U; 
                uint16_t    lUI16_EraseTimeout=0U;
    DL_FlashCTL_executeClearStatus(FLASHCTL);
    for(lUI16_BlockNoIndex =lUI16_NoOfSectors; lUI16_BlockNoIndex>0;lUI16_BlockNoIndex--)
    {
        /*Unprotect the Particular Sector Befor Erase Operation*/
        DL_FlashCTL_unprotectSector(
        FLASHCTL, lUI32_SectorStartAdd, DL_FLASHCTL_REGION_SELECT_MAIN);  
        lUI16_EraseTimeout=0;     
        /*Erase the Particular Data Flash Sector*/   
        lUI8_EraseCmdStatus=DL_FlashCTL_eraseMemoryFromRAM(FLASHCTL, lUI32_SectorStartAdd, DL_FLASHCTL_COMMAND_SIZE_SECTOR);
        while(lUI8_EraseCmdStatus==DL_FLASHCTL_COMMAND_STATUS_IN_PROGRESS && lUI16_EraseTimeout++<6400);  
        if (lUI8_EraseCmdStatus== DL_FLASHCTL_COMMAND_STATUS_PASSED) 
        {
           lUI8_ErrorType = NO_ERROR;
        }
        else 
        {   
            /* If command did not pass, set error flag */
            lUI8_ErrorType = ERROR_FAIL;
            break;
        }
    	/*Increment the Sector Address By 1KB*/
    	lUI32_SectorStartAdd = lUI32_SectorStartAdd + SECTOR_MEM_SIZE;
             
    }
    return lUI8_ErrorType;
}
/*********************************************************************************************
** Name			:	SM_Flash_Blankcheck					                                    **
** Description	:	Memory Blank Check at a particular address	                            **  
					in the Data Flash	                                                    **
** Inputs		:	lUI32_StartWordAddress: Memory address to check for blank the memory    **
**				    lUI16_NoOfWords: Number of Words to be checked for Blank                **
** Outputs		:							                                                **
** Returns		:	FlashBankCheckStatus: whether memory is blank or not 	                **
*********************************************************************************************/

uint8_t SM_Flash_Blankcheck(uint32_t lUI32_StartWordAddress,uint16_t lUI16_NoOfWords)
{	
                uint16_t    lUI16_NoofWordsIndex = 0U;
    volatile    uint32_t    lUI32_BlankCheckFlashAddress = lUI32_StartWordAddress;
                uint8_t     lUI8_FlashBankCheckStatus = ERROR_FAIL;
                uint8_t     lUI8_BlankCheckCmdStatus=0U; 
                uint16_t    lUI16_BlankCheckTimeout=0U;

    for(lUI16_NoofWordsIndex = lUI16_NoOfWords;lUI16_NoofWordsIndex>0; lUI16_NoofWordsIndex--)
    {
        lUI16_BlankCheckTimeout=0;
        lUI8_BlankCheckCmdStatus=DL_FlashCTL_blankVerifyFromRAM(FLASHCTL,lUI32_BlankCheckFlashAddress);
        while(lUI8_BlankCheckCmdStatus==DL_FLASHCTL_COMMAND_STATUS_IN_PROGRESS && lUI16_BlankCheckTimeout++<6400);       
        /*Blank Check a particular word memory */
        if(lUI8_BlankCheckCmdStatus == DL_FLASHCTL_COMMAND_STATUS_PASSED)
        {
            lUI8_FlashBankCheckStatus = NO_ERROR;
        }
        else 
        {
            lUI8_FlashBankCheckStatus = ERROR_FAIL;
            break;
        }
        lUI32_BlankCheckFlashAddress = lUI32_BlankCheckFlashAddress + 4;
    }
    return lUI8_FlashBankCheckStatus;
	
   
}
/*************************************************************************************
** Name			:	SM_Flash_ReadVerify					                            **
** Description	:	Compares the Data Buffer to the data stored in a Flash Memory   **
** Inputs		:lUI32_StartWordAddress: Start Memory address  **				    **
**				 lUI16_NoOfWords: Number of Words to be checked for Read Verify     **
                 lUI32_Data: Data Buffer to be compared with                        **    
** Outputs		:							                                        **
** Returns		:	lUI_8FlashReadVerifyStatus						                **
**************************************************************************************/

uint8_t SM_Flash_ReadVerify(uint32_t lUI32_StartWordAddress,uint32_t *lUI32_Data,uint16_t lUI16_NoOfWords)
{
	
                uint16_t    lUI16_TotalNoofWords = 0;
    volatile    uint32_t    lUI32_ReadVerifyFlashAddress = lUI32_StartWordAddress;
                uint8_t     lUI8_FlashReadVerifyStatus = ERROR_FAIL;
                uint8_t     lUI8_ReadVerifyCmdStatus=0U; 
                uint16_t    lUI16_ReadVerifyTimeout=0U;

    /*As we read 2 words(8 Bytes) at a time*/
    lUI16_TotalNoofWords = (lUI16_NoOfWords/2);

    for( lUI16_TotalNoofWords = lUI16_NoOfWords;lUI16_TotalNoofWords > 0; lUI16_TotalNoofWords--)
    {
        lUI16_ReadVerifyTimeout=0;
        /* Read Verify Memory Address with the Data*/
        lUI8_ReadVerifyCmdStatus=DL_FlashCTL_readVerifyFromRAM64WithECCGenerated(FLASHCTL,lUI32_ReadVerifyFlashAddress,lUI32_Data);
        while(lUI8_ReadVerifyCmdStatus==DL_FLASHCTL_COMMAND_STATUS_IN_PROGRESS && lUI16_ReadVerifyTimeout++<6400); 
        if(lUI8_ReadVerifyCmdStatus  == DL_FLASHCTL_COMMAND_STATUS_PASSED)
        {    
            lUI8_FlashReadVerifyStatus = NO_ERROR;
        }
        else
        {
            lUI8_FlashReadVerifyStatus=ERROR_FAIL;
            break;
        }

        lUI32_ReadVerifyFlashAddress = lUI32_ReadVerifyFlashAddress + 8;
        lUI32_Data = lUI32_Data + 2;
    }

    return  lUI8_FlashReadVerifyStatus;
}

/*********************************************************************************
** Name			:	EEPROM_Read      				                            **
** Description		:	To Read the data from the EEPROM		                **
** Inputs		:	lUI32_PageNumber: Memory address to Read the 	            **
**				 data from the memory				                            **
**				laUI8_Data: Array to update the read data from 	                **
**				the memory					                                    **
** Outputs		:							                                    **
** Returns		:	None						                                **
*********************************************************************************/
void EEPROM_Read(uint32_t lUI32_PageNumber,uint8_t *laUI8_Data)
{
	            uint32_t  	    lUI32_Index1 =0;
                uint8_t   	    lUI8_Index2 =0;                
	            uint32_t  	    lUI32_DataBuffer[MAX_DATA_BYTES_128 / (MEM_BYTES_PER_ONCE/2)];
                uint16_t        lUI16_DataFlashSectorNum = 0, lUI16_DataFlashPageNum = 0;
                uint16_t        lUI16_Page = 0;
                MemoryParam     lstr_ReadData;
	volatile    uint32_t        lUI32_ReadStartWordAddress=0;    
    volatile    uint16_t        lUI16_ReadNoOfWords=0;

    /*Get the Page Number from the Memory Address*/
    lUI16_Page = (uint16_t) (lUI32_PageNumber / MAX_DATA_BYTES_128);
    /*Get the Sector Number from the Page Number*/
	lUI16_DataFlashSectorNum = lUI16_Page / 8;
    /*Get the Page Number of a Particular Sector*/
    lUI16_DataFlashPageNum = lUI16_Page % 8;
    
    lUI32_ReadStartWordAddress=(DATAFLASH_BASE_ADDRESS + (lUI16_DataFlashSectorNum * SECTOR_MEM_SIZE)+(lUI16_DataFlashPageNum*MAX_DATA_BYTES_128));

    lUI16_ReadNoOfWords=(MAX_DATA_BYTES_128 /(MEM_BYTES_PER_ONCE/2));

	SM_Flash_Read(lUI32_ReadStartWordAddress,lUI32_DataBuffer,lUI16_ReadNoOfWords);
	

	for(lUI32_Index1 = 0, lUI8_Index2 = 0; lUI8_Index2 < lUI16_ReadNoOfWords; lUI8_Index2++)
    {
        	
		lstr_ReadData.Word = lUI32_DataBuffer[lUI8_Index2];
        laUI8_Data[lUI32_Index1+0u] =lstr_ReadData.Bytes.Byte0;
		laUI8_Data[lUI32_Index1+1u] =lstr_ReadData.Bytes.Byte1;
		laUI8_Data[lUI32_Index1+2u] =lstr_ReadData.Bytes.Byte2;
		laUI8_Data[lUI32_Index1+3u] =lstr_ReadData.Bytes.Byte3;
		lUI32_Index1 = lUI32_Index1 + 4u;
    }
    
}


/*************************************************************************************
** Name			:	EEPROM_Write     				                                **
** Description	:	To write the data to the memory			                        **
** Inputs		:	lUI32_PageNumber: Memory address to write the 	                **
**				    data from the memory				                            **
**				    laUI8_Data: Array of data to be writtent to the                 **
**				    memory						                                    **
** Outputs		:							                                        **
** Returns		:	None						                                    **
*************************************************************************************/

uint8_t EEPROM_Write(uint32_t lUI32_PageNumber,uint8_t *laUI8_Data)
{
	            uint16_t    	lUI16_Index1=0;
                uint16_t    	lUI16_Index2=0;
                uint16_t        lUI16_DataFlashSectorNum = 0,lUI16_DataFlashPageNum = 0;
                uint16_t        lUI16_Page = 0;
                uint8_t	        lUI8_DataWrittenStatus = false;
    volatile    uint32_t        lUI32_StartWordAddress=0;    
    volatile    uint16_t        lUI16_NoOfWords=0;
	            MemoryParam     lstr_WriteData;

    /*Get the Page Number from the Memory Address*/
    lUI16_Page = (uint16_t) (lUI32_PageNumber / MAX_DATA_BYTES_128);
    /*Get the Sector Number from the Page Number*/
	lUI16_DataFlashSectorNum = lUI16_Page / 8;
    /*Get the Page Number of a Particular Sector*/
    lUI16_DataFlashPageNum = lUI16_Page % 8;

    lUI32_StartWordAddress=(DATAFLASH_BASE_ADDRESS + (lUI16_DataFlashSectorNum * SECTOR_MEM_SIZE));

    lUI16_NoOfWords=(MAX_DATA_BYTES_128 /MEM_BYTES_PER_ONCE);
	/*Read entire Sector and store in the Buffer of 1KB*/ 
    SM_Flash_Read(lUI32_StartWordAddress,gUI32_DataBuffer,(SECTOR_MEM_SIZE /MEM_BYTES_PER_ONCE)*2);

	for(lUI16_Index1 = 0, lUI16_Index2 = 0; lUI16_Index2 < (lUI16_NoOfWords*2); lUI16_Index2++)
	{
		lstr_WriteData.Bytes.Byte0 = laUI8_Data[lUI16_Index1];
		lstr_WriteData.Bytes.Byte1 = laUI8_Data[lUI16_Index1+1];
		lstr_WriteData.Bytes.Byte2 = laUI8_Data[lUI16_Index1+2];
		lstr_WriteData.Bytes.Byte3 = laUI8_Data[lUI16_Index1+3];
        gUI32_DataBuffer[((lUI16_DataFlashPageNum*MAX_DATA_BYTES_128)/(MEM_BYTES_PER_ONCE/2))+lUI16_Index2] = lstr_WriteData.Word; 
		lUI16_Index1 = lUI16_Index1 + 4;
	}  
    /* Erase the Entire Sector of 1KB*/    
	lUI8_DataWrittenStatus=SM_Flash_Erase(lUI32_StartWordAddress,(uint16_t)(SECTOR_MEM_SIZE / SECTOR_MEM_SIZE));
    if(lUI8_DataWrittenStatus==NO_ERROR)
    {
        /* Write the Sector with the Updated Data*/
        lUI8_DataWrittenStatus=SM_Flash_Write(lUI32_StartWordAddress,gUI32_DataBuffer,(uint16_t)(SECTOR_MEM_SIZE / MEM_BYTES_PER_ONCE));  
        if(lUI8_DataWrittenStatus == NO_ERROR)
        {
            /*Check the memory whether it is blank or not*/
            lUI8_DataWrittenStatus = SM_Flash_Blankcheck((DATAFLASH_BASE_ADDRESS+(lUI16_Page*MAX_DATA_BYTES_128)),(uint16_t)(lUI16_NoOfWords));
        }
        else
        {
            /*Nothing*/
        }      
    }
    else
    {
        /*Nothing*/
    }
    return (lUI8_DataWrittenStatus==NO_ERROR?0x01:0x00);  
}

