/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright (c) 2016-2021, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include "Defines.h"
#include "fsl_smc.h"
#include "fsl_afe.h"
#include "fsl_lptmr.h"
#include "fsl_vref.h"
#include "fsl_pmc.h"
#include "fsl_slcd.h"
#include "EEPROMDriver.h"
#include "Application.h"
#include "PowerModes.h"
#include "IOControls.h"
#include "MeteringLPRT.h"
#include "Timer.h"
#include "MeteringInterface3Ph.h"
#include "ComPortDriver.h"
#include "UserInterface.h"
#include "Calibration3Ph.h"
#include "lcd.h"
#include "AppInterface.h"
#include "IOControls.h"
#include "clock_config.h"
#include "AppCommon.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
* Prototypes
******************************************************************************/
uint8 TurnLatchOff;
uint8 BattModeTimeout;
/*******************************************************************************
 * Code
 ******************************************************************************/

/*!
 * @brief This function monitors if there's a state of power supply change in the meter,
 * e.g., mains to battery or vice-versa. Initiates actions based on power state changes.
 */
void DoPowerStatus(void)
{
  uint8 PowerMode;
  
  PowerMode = SystemState.PowerMode;
  /* Read the latest status of the power supply - mains or battery */
  CheckPowerStatus();
  if ((TurnLatchOff == TRUE) && (BattModeTimeout == 0))
  {
    /* step 1: Latch off if bettery mode operation over. This may not turn off the meter if COPEN/MOPEN is done in the mean time */
    LATCH_OFF;
    /* step 2: So, go the sleep mode additionally */
    ShutDownGPIOs();
    ShutDownIPs();
    SLCD_StopDisplay(LCD);
    SIM->MISC_CTL   = 0x800F0000;
    GoToSleep();
  }
  if ((PowerMode == POWERMODE_RUN) && (SystemState.PowerMode == POWERMODE_BAT))
  {
    /* just entered POWERMODE_RUN to POWERMODE_BAT state */
    ShutDownGPIOs();
    ShutDownIPs();
    SLCD_StopDisplay(LCD);
    SIM->MISC_CTL   = 0x800F0000;
    
    SWReset(7);
  }
  
  /* If mains comes back */
  if ((PowerMode == POWERMODE_BAT) && (SystemState.PowerMode == POWERMODE_RUN))
  {
    SWReset(8);
  }
}

/*!
 * @brief Intializes MCU system, bus and flash clocks. 
 * PLL/FLL is also initilized based on power states meter or bandwidth requirement 
 * in meter processing.
 * Clocks are limited to meet power consumption(VA) rating of the meter as per meter tender requirements.
 * Mostly, the MCU is not run at highest possible frequencies.
 */
void ClockModuleInit(void)
{
  switch (SystemState.PowerMode)
  {
    case POWERMODE_RUN:
      
      /* Set system frequency and bus clock to be high clock mode */
      SystemState.BusClk = BUS_CLOCK;
      SystemState.SysClk = SYSTEM_CLOCK; 
      
      while (kSMC_PowerStateRun != SMC_GetPowerModeState(SMC))
        SMC_SetPowerModeRun(SMC);
      {
      }
      
      /* Initialize MCU clock source */
      BOARD_BootClockRUN();
      break;
 
    case POWERMODE_BAT:
      SystemState.BusClk = BATTERY_FREQ;
      SystemState.SysClk = BATTERY_FREQ_SYSTEM;  

      while (kSMC_PowerStateRun != SMC_GetPowerModeState(SMC))
        SMC_SetPowerModeRun(SMC);
      {
      }
      
      /* Initialize MCU clock source */
      BOARD_BootClockRUNBat();
    break;
  }

}

void ShutDownAndReset (void)
{
  ShutDownGPIOs();
  ShutDownIPs();
  SLCD_StopDisplay(LCD);
  SIM->MISC_CTL   = 0x800F0000;

  DisableGlobalIRQ();
  /* took care of all wakup reasons, can sleep now */
  GoToSleep();
}

/*!
 * @brief Disbales few MCU IP functions to reduce power consumption in the MCU 
 * and in the meter.
 */
void ShutDownIPs(void)
{
  pmc_bandgap_buffer_config_t pmConfig;
  
  CLOCK_DisablePll0();
  pmConfig.enable = false;
  pmConfig.enableInLowPowerMode = false;
  PMC_ConfigureBandgapBuffer(PMC, &pmConfig);
}

/*!
 * @brief Takes the MCU to sleep mode.
 */
void GoToSleep(void)
{
  smc_power_mode_vlls_config_t vlls_config;
  vlls_config.enablePorDetectInVlls0 = true;
  
  /* Check Mains On / PFAIL */
  if (GPIO_GET_MAINS_ON)
  {
    SWReset(5);
  }
  
  while (kSMC_PowerStateRun != SMC_GetPowerModeState(SMC))
        SMC_SetPowerModeRun(SMC);
  {
  }
  
  while (kSMC_PowerStateVlls != SMC_GetPowerModeState(SMC))
  {
    vlls_config.subMode = kSMC_StopSub0;
    SMC_PreEnterStopModes();
    SMC_SetPowerModeVlls(SMC, &vlls_config);
  }
}
