/*
 * Copyright (c) 2010-2016, Freescale Semiconductor, Inc.
 * Copyright (c) 2016-2021, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include "common.h"
#include "fsl_rcm.h"
#include "fsl_smc.h"
#include "fsl_pmc.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "boot_loader.h"
#include "lcd.h"
#include "Application.h"
#include "PowerModes.h"
#include "EEPROMAddrs.h"
#include "EEPROMDriver.h"
#include "iic_config.h"
#include "Timer.h"
#include "AppCommon.h"
#include "ActivateApp.h"

#define SYSTEM_RESET    6

/*******************************************************************************
* Prototypes
******************************************************************************/
uint32 LLWUStatus;

uint32 recv_timeout_flag = NO_TIMEOUT;
uint8  BattModeTimeout;
stImageTransfer blImageTransfer;

tSystemState SystemState = 
{
  BUS_CLOCK,
  SYSTEM_CLOCK,
  POWERMODE_RUN,
};

/* LATCH */
const port_pin_config_t latch_port_config = {
  /* Internal pull-up resistor is enabled */
  kPORT_PullUp,
  /* Fast slew rate is configured */
  kPORT_FastSlewRate,
  /* Open drain is disabled */
  kPORT_OpenDrainDisable,
  /* Pin is configured as GPIO */
  kPORT_MuxAsGpio,
  /* Pin Control Register fields [15:0] are not locked */
  kPORT_UnlockRegister};

/* Define the init structure for the latch pin */
gpio_pin_config_t latch_gpio_config = {
  kGPIO_DigitalOutput,
  0,
};

/*******************************************************************************
 * Code
 ******************************************************************************/
void JumpToApplication(uint32_t stackPointer, uint32_t applicationAddress)
{
  /* Static variables are needed as we need to ensure the values we are using are not stored on the previous stack */
  static uint32_t s_stackPointer = 0;
  s_stackPointer = stackPointer;
  static volatile void (*farewellBootloader)(void) = 0;
  farewellBootloader = (volatile void (*)(void))applicationAddress;


  /* Set the VTOR to the application vector table address */
  SCB->VTOR = stackPointer;


  /* Set stack pointers to the application stack pointer */
  __set_MSP(s_stackPointer);
  __set_PSP(s_stackPointer);

  /* Jump to the application */
  farewellBootloader();
}

#ifdef LCD_ON_BOOT
void DisplayBoot(void)
{
  LCDInit();
  LCDClear();

  /* "BL9600" */
  LCD->WF8B[13] = 0x80;
  LCD->WF8B[14] = 0x40;
  LCD->WF8B[15] = 0x20;
  LCD->WF8B[16] = 0x10;
  LCD->WF8B[17] = 0x08;
  LCD->WF8B[18] = 0x04;
  LCD->WF8B[16] = 0x02;
  LCD->WF8B[15] = 0x01;
  LCD->WF8B[23] = 0x7C;
  LCD->WF8B[24] = 0x64;
  LCD->WF8B[25] = 0x7A;
  LCD->WF8B[26] = 0x28;
}
#endif

void main (void)
{
  int16 ret_status=0;
  uint8 BootState;
  uint32 app_addr;
  uint32_t primaskValue = 0U;
  
  if (kRCM_SourceWakeup & RCM_GetPreviousResetSources(RCM)) /* Wakeup from VLLS. */
  {
    PMC_ClearPeriphIOIsolationFlag(PMC);
    NVIC_ClearPendingIRQ(LLWU_IRQn);
  }
  
  BootState = (IRTC_BbRam[0] == 0xBA)?2:1;
  
  do
  {
    switch(BootState)
    {
    case 1:
      /* Disable interrupt before initializing the IP modules of the MCU */
      primaskValue = DisableGlobalIRQ();
      /* jump to applicaton */
      
      //SCB->VTOR=((uint32_t)APP_RESET_VECTOR);
      JumpToApplication(*((unsigned int*)APP_RESET_VECTOR), *((unsigned int*)(APP_RESET_VECTOR+4)));
      break;
      
    case 2:
      BOARD_InitBootPins();
      
      while (kSMC_PowerStateRun != SMC_GetPowerModeState(SMC))
        SMC_SetPowerModeRun(SMC);
      {
      }
      
      /* Initialize MCU clock source */
      BOARD_BootClockRUN();
      
      PORT_SetPinConfig(LATCH_PORT, LATCH_PIN, &latch_port_config);
      GPIO_PinInit(LATCH_GPIO, LATCH_PIN, &latch_gpio_config);
      LATCH_ON;
      
      /* Disable interrupt before initializing the IP modules of the MCU */
      primaskValue = DisableGlobalIRQ();
      
      /* Setup flash driver structure for device and initialize variables. */
      InitializeFlash();
      
#ifdef LCD_ON_BOOT
      DisplayBoot();
#endif
      
      /* Now good to enable interrupts */
      EnableGlobalIRQ(primaskValue); 
      
      ret_status = ActivateApp(&app_addr);
      
      primaskValue = DisableGlobalIRQ();
      /* Initialize I2C module to drive EEPROM device */
      I2CModuleInit();
      GPTimerModuleInit();
      EnableGlobalIRQ(primaskValue); 
      
      NVReadIIC(ImageTrnfInfoAddr, (void *)&blImageTransfer, sizeof(blImageTransfer));
      if(ret_status != (-1))
      {
        blImageTransfer.ImageTransferStatus = E_IMAGE_TS_ACTIVATION_SUCCESSFUL;
        /* disable */
        IRTC_SetWriteProtection(RTC, false);
        IRTC_BbRam[0] = 0x00;       /* disbaled */
      }
      else
      {
        blImageTransfer.ImageTransferStatus = E_IMAGE_TS_ACTIVATION_FAILED;
      }
      NVWriteIIC(ImageTrnfInfoAddr, (void *)&blImageTransfer, sizeof(blImageTransfer));
      
      /* Force to go undefined boot state, so that it does SystemReset. */
      BootState = SYSTEM_RESET;
      break;
    
    default: 
      /* Reset if any wanted BootState */
#ifdef LCD_ON_BOOT
      LCDClear();
#endif
      NVIC_SystemReset();
      break;
    }
  }while (1);
  
}


