/*
 * Copyright (c) 2021, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include "common.h"
#include "fsl_wdog.h"
#include "fsl_flash.h"
#include "Defines.h"
#include "UpgradeFW.h"
#include "flash_FTFL.h"
#include "EEPROMDriver.h"
#include "EEPROMAddrs.h"
#include "MeteringInterface3Ph.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define SIZE_OF_PROG_BUFF		0x300
#define FW_BUFFER_LEN   128 
/*******************************************************************************
* Prototypes
******************************************************************************/
uint8  fw_buffer_bl[FW_BUFFER_LEN];
uint8  *fw_buffer_ptr;
uint32 remaining_bytes;
uint32 flash_start_address;
uint32 binDesc[(MAX_DESC*8)/4];
uint32 source_address;

/*******************************************************************************
 * Code
 ******************************************************************************/
/* 
 Description: Application downloader routine.
 Returns: -1 if unsuccessful, 2 if successful.
 */ 
uint16 ActivateApp(uint32* dest_start_address)
{
  int32 ret_status = -1;
  uint8 locresult=0;
  uint32 length, this_size, zDesc;
  uint8 i,j;
  uint32_t primaskValue = 0U;
  
  /* read no. of descriptors */
  memcpy((uint8 *)&zDesc, (uint8 *)FlashMemFOTAStartAddr, 4);
  /* Check if no of descriptors are not huge no.! */
  if(zDesc > MAX_DESC)
  {
    return -1;
  }
  
  /* read the bin descriptors now, each descriptors 8 bytes long */
  memcpy((uint8 *)binDesc, (uint8 *)(FlashMemFOTAStartAddr+4), zDesc*8);
  /* process binary descriptors */
  for (i=0; i<zDesc; i++)
  {
    /* 1. TBD - check if binDesc[] address values are integral multiple of FLASH_SECTOR_SIZE */
    
    /* 2. Erase flash sectors for each bin descriptors */
    primaskValue = DisableGlobalIRQ();
    /* 
    * Desciptors [4 bytes address, 4 bytes size].
    * Rounding off the size for multiple of FLASH_SECTOR_SIZE is required and done here.
    */
    locresult=EraseSectors(binDesc[2*i], (((binDesc[2*i+1]-1)/FLASH_SECTOR_SIZE)+1)*FLASH_SECTOR_SIZE);
    EnableGlobalIRQ(primaskValue); 
    if(locresult!=0)
    {
      return -1;
    }
    
    /* 3. Write from Stored binary to Executable in place flash area */
    source_address = FlashMemFOTAStartAddr + 4 +( zDesc*8);     /* the beginning of binaries here */
    /* adding sizes of previous binaries (i) in actual. j<i should exclude '0'th binary size */
    for(j=0; j<i; j++)
    {
      source_address += binDesc[(2*j)+1];
    }
    
    flash_start_address = binDesc[2*i];
    length = remaining_bytes = binDesc[(2*i)+1];
    
    fw_buffer_ptr = fw_buffer_bl;
    while(remaining_bytes)
    {
      this_size = (remaining_bytes>FW_BUFFER_LEN)?FW_BUFFER_LEN:remaining_bytes;
      fw_buffer_ptr = (uint8 *)(source_address + length - remaining_bytes);
      primaskValue = DisableGlobalIRQ();
      FLASH_Program(&s_flashDriver, (uint32)(flash_start_address + length - remaining_bytes),(uint8_t*)fw_buffer_ptr, this_size);
      EnableGlobalIRQ(primaskValue); 
      
      remaining_bytes -= this_size;
      /* keep servicing the WDOG */
      WDOG_Refresh(WDOG);
    }
  }
  
  ret_status = 1;
  
  return ret_status;
}
