/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright (c) 2016-2021, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include "pin_mux.h"
#include "board.h"
#include "fsl_afe.h"
#include "fsl_cmp.h"
#include "fsl_vref.h"
#include "fsl_qtmr.h"
#include "fsl_xbar.h"
#include "fsl_llwu.h"
#include "fsl_rcm.h"
#include "fsl_pmc.h"
#include "fsl_rnga.h"
#include "fsl_wdog.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "fsl_smc.h"

#include "Defines.h"
#include "EEPROMDriver.h"
#include "ComPortDriver.h"
#include "UserInterface.h"
#include "Timer.h"
#include "MeteringLPRT.h"
#include "MeteringInterface3Ph.h"
#include "Calibration3Ph.h"
#include "Application.h"
#include "RTCDriver.h"
#include "PowerModes.h"
#include "iic_config.h"
#include "IOControls.h"
#include "AppInterface.h"
#include "UpgradeFW.h"
#include "flash_FTFL.h"
#include "AppCommon.h"
#if defined(MBEDTLS_NXP_SSSAPI)
#include "sssapi_mbedtls.h"
#else
#include "ksdk_mbedtls.h"
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define WDOG_WCT_INSTRUCITON_COUNT (256U)

/*******************************************************************************
* Prototypes
******************************************************************************/
/** Structure defined for date */
stDate  g_stDate;

/** Structure defined for time */
stTime  g_stTime;

tSystemState SystemState=
{
  BUS_CLOCK,
  SYSTEM_CLOCK,
  POWERMODE_RUN
};

tMETERLIBLPRT3PH_DATA mlib3phdata;
tCalibPoint3Ph CalibPoint;
/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Initializes different module functions necessery for the meter function.
 */
void InitModules(void)
{
  uint32_t primaskValue = 0U;
  
  /* Disable interrupt before initializing the IP modules of the MCU */
  primaskValue = DisableGlobalIRQ();
  
  /* Setup MCU clock based on power modes */
  ClockModuleInit();
  /* Initialize a timer for sub-task/interrupt handler synchronization etc */
  GPTimerModuleInit();
  /* Initialize I2C module to drive EEPROM device */
  I2CModuleInit();
  /* Initialize RTC module for meter RTC and passive tampers configurations */
  RTCModuleInit();
  /* Now good to enable interrupts */
  EnableGlobalIRQ(primaskValue);   
  
  /* Initialize UART module */
  UartModuleInit();
  
  /* Intialize all metering specific MCU IPs */
  MeteringInit();
  /* Initialize display sequences */
  UserInterfaceInit();
  
  /* Enable MMCAU clock and initialize */
  CLOCK_EnableClock(kCLOCK_Cau0);
  CRYPTO_InitHardware();
  
  /* Setup flash driver structure for device and initialize variables. */
  InitializeFlash();
}

/*!
 * @brief Initializes LLWU unit for the meter.
 */
void LLWU_Init(void)
{
  llwu_external_pin_filter_mode_t mains_on, push_button;
  
  /* Enable Mains_On, PUSH button pin filters */ 
  mains_on.filterMode = kLLWU_PinFilterRisingEdge;
  mains_on.pinIndex = 14U;
  LLWU_SetPinFilterMode(LLWU, 1U, mains_on);        /* Mains_On */
  push_button.filterMode = kLLWU_PinFilterFallingEdge;
  push_button.pinIndex = 17U;
  LLWU_SetPinFilterMode(LLWU, 2U, push_button);        /* Push button */
  LLWU_ClearPinFilterFlag(LLWU, 14U);
  LLWU_ClearPinFilterFlag(LLWU, 17U);
}


/*!
 * @brief Checks if the meter woke up due to any LLWU event and serve it.
 */
void CheckForWakeupSources(void)
{
  if (LLWU_GetPinFilterFlag(LLWU, PBU_LLWU_PTE))
  {
    /* Wakeup through push button */
    /* Clear push button interrupt flag */
    PORT_ClearPinsInterruptFlags(PBU_PORT, (1U << PBU_PIN));
  }

  if (LLWU_GetPinFilterFlag(LLWU, MAINS_ON_LLWU_PTE))
  {
    /* Wakeup through mains on */
    /* Clear mains on interrupt flag */
    PORT_ClearPinsInterruptFlags(MAINS_ON_PORT, (1U << MAINS_ON_PIN));
  }
  
  return;
}

/*!
 * @brief Invokes init functions of the different tasks of metering applicaiton.
 */
void InitApplication(void)
{
  /* read meter energy recording type - Import or/and Export */
  NVReadIIC(METRECTYPE, (uint8 *)&mlib3phdata.MetRecordingType, 1);
}

/*!
 * @brief main application C entry point of metering application.
 */
void main(void)
{
  /* set SMC to allow entering in to VLLS modes for sleep */
  SMC_SetPowerModeProtection(SMC, kSMC_AllowPowerModeVlp|kSMC_AllowPowerModeVlls);
  
  if (kRCM_SourceWakeup & RCM_GetPreviousResetSources(RCM)) /* Wakeup from VLLS. */
  {
    PMC_ClearPeriphIOIsolationFlag(PMC);
    NVIC_ClearPendingIRQ(LLWU_IRQn);
  }
  
  RNGA_Init(RNG);
  RNGA_SetMode(RNG, kRNGA_ModeSleep);
  
  BOARD_InitBootPins();
  
  LLWU_Init();
 /* Check if the meter woke up from sleep mode and do the needful */
  CheckForWakeupSources();
  
  WDOGModuleInit();
         
  /* Initialize meter GPIO pins */
  AppGPIOInit();
  
  /* Initialize LCD module */
  LCDModuleInit();
  
  /* Initializing all the peripheral modules */
  InitModules(); 

  /* Do remaining application tasks specific init */
  InitApplication();
  
  /*
   Main while loop.
   Major Functions which are  executed are
   a)Measurement
   b)Communication
   c)UserInterface
   d)Application
   */
 
  /* Main loop */  
  for (;;)
  {
    /* MetDue is set to true every 1 second, but not during battery/single wire modes */
    if (mlib3phdata.MetDue == TRUE)
    {
      /* Do metering calculations */
      DoMetering3Ph();
      /* Calibration */
      if ((mlib3phdata.CalibState == CALIBSTATE_PROGRESS) || (mlib3phdata.CalibState == CALIBSTATE_NEU_PROGRESS))
      {
        DoCalibration3Ph(&CalibPoint);
      }
    }
    
    /* Read meter date-time */
    ReadDateAndTime();
    
    /* Check power status */
    DoPowerStatus();
    
    /* Do LCD display function */
    Display();
    
    /* Do communication tasks */
    Communication();
    
    /* Keep servicing the MCU WDOG for meter non-reset */
    WDOG_Refresh(WDOG);
  }
}


