/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright (c) 2016-2021, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include "Defines.h"
#include "UserInterface.h"
#include "Application.h"
#include "fsl_wdog.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "ComPortDriver.h"
#include "PowerModes.h"
#include "Timer.h"
#include "EEPROMDriver.h"
#include "MeteringLPRT.h"
#include "MeteringInterface3Ph.h"
#include "IOControls.h"
#include "UpgradeFW.h"
#include "AppCommon.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define GPIOEventHandler    PTx_IRQHandler
/*******************************************************************************
* Prototypes
******************************************************************************/
uint8  UpDetected;
uint8  DownDetected;
uint8  UpScrollDebouncer;
uint8  DownScrollDebouncer;
uint8  MainsOn;
/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Initializes few GPIO pins in the meter, to check whether meter is 
 * powered up from mains supply or through battery, and do the necessery settings.
 */
void AppGPIOInit(void)
{
  /* 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 output latch pin */
  gpio_pin_config_t latch_gpio_config = {
    kGPIO_DigitalOutput,
    0,
  };
  PORT_SetPinConfig(LATCH_PORT, LATCH_PIN, &latch_port_config);
  GPIO_PinInit(LATCH_GPIO, LATCH_PIN, &latch_gpio_config);
  LATCH_OFF;
  
  /* kWh Led */
  const port_pin_config_t kwh_led_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 output kWh LED pin */
  gpio_pin_config_t kwh_led_gpio_config = {
    kGPIO_DigitalOutput,
    0,
  };
  PORT_SetPinConfig(KWH_LED_PORT, KWH_LED_PIN, &kwh_led_port_config);
  GPIO_PinInit(KWH_LED_GPIO, KWH_LED_PIN, &kwh_led_gpio_config);
  OFF_KWH_LED();
  
  /* kVArh Led */
  const port_pin_config_t kvarh_led_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 output LED pin */
  gpio_pin_config_t kvarh_led_gpio_config = {
    kGPIO_DigitalOutput,
    0,
  };
  PORT_SetPinConfig(KVARH_LED_PORT, KVARH_LED_PIN, &kvarh_led_port_config);
  GPIO_PinInit(KVARH_LED_GPIO, KVARH_LED_PIN, &kvarh_led_gpio_config);
  OFF_KVARH_LED();
  
  /* Down scroll */
  const port_pin_config_t push_button_down_port_config = {
    /* Internal pull-up resistor is enabled */
    kPORT_PullDisable,
    /* Fast slew rate is configured */
    kPORT_SlowSlewRate,
    /* Open drain is disabled */
    kPORT_OpenDrainEnable,
    /* Pin is configured as GPIO */
    kPORT_MuxAsGpio,
    /* Pin Control Register fields [15:0] are not locked */
    kPORT_UnlockRegister};
  
  /* Define the init structure for the output LED pin */
  gpio_pin_config_t push_button_down_gpio_config = {
    kGPIO_DigitalInput,
    0,
  };
  PORT_SetPinConfig(PBD_PORT, PBD_PIN, &push_button_down_port_config);
  GPIO_PinInit(PBD_GPIO, PBD_PIN, &push_button_down_gpio_config);
  
  /* Up scroll */
  const port_pin_config_t push_button_up_port_config = {
    /* Internal pull-up resistor is enabled */
    kPORT_PullDisable,
    /* 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 output LED pin */
  gpio_pin_config_t push_button_up_gpio_config = {
    kGPIO_DigitalInput,
    0,
  };
  PORT_SetPinConfig(PBU_PORT, PBU_PIN, &push_button_up_port_config);
  PORT_SetPinInterruptConfig(PBU_PORT, PBU_PIN, kPORT_InterruptFallingEdge);
  GPIO_PinInit(PBU_GPIO, PBU_PIN, &push_button_up_gpio_config);
  
  /*  Magnet */
  const port_pin_config_t magnet_port_config = {
    /* Internal pull-up resistor is enabled */
    kPORT_PullUp,
    /* Slow slew rate is configured */
    kPORT_SlowSlewRate,
    /* 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 magnet pin */
  gpio_pin_config_t magnet_gpio_config = {
    kGPIO_DigitalInput,
    0,
  };
  PORT_SetPinConfig(MAG_PORT, MAG_PIN, &magnet_port_config);
  GPIO_PinInit(MAG_GPIO, MAG_PIN, &magnet_gpio_config);
  
  /* Reset PTE1) : By Default it is configured as Reset */
  const port_pin_config_t reset_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 Reset pin */
  gpio_pin_config_t reset_gpio_config = {
    kGPIO_DigitalOutput,
    1,
  };
  PORT_SetPinConfig(PORTE, 1U, &reset_port_config);
  GPIO_PinInit(GPIOE, 1U, &reset_gpio_config);
  
  /* Mains availability */
  const port_pin_config_t mains_on_port_config = {
    /* Internal pull-up resistor is disabled */
    kPORT_PullDisable,
    /* Slow slew rate is configured */
    kPORT_SlowSlewRate,
    /* Open drain is enabled */
    kPORT_OpenDrainEnable,
    /* Pin is configured as GPIO */
    kPORT_MuxAsGpio,
    /* Pin Control Register fields [15:0] are not locked */
    kPORT_UnlockRegister};
  
  /* Define the init structure for the mains on pin */
  gpio_pin_config_t mains_on_gpio_config = {
    kGPIO_DigitalInput,
    0,
  };
  PORT_SetPinConfig(MAINS_ON_PORT, MAINS_ON_PIN, &mains_on_port_config);
  GPIO_PinInit(MAINS_ON_GPIO, MAINS_ON_PIN, &mains_on_gpio_config);

  /* I2C pins */
  const port_pin_config_t i2c_sda_port_config = {
    /* Internal pull-up resistor is disabled */
    kPORT_PullDisable,
    /* Slow slew rate is configured */
    kPORT_SlowSlewRate,
    /* 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 i2c sda pin */
  gpio_pin_config_t i2c_sda_gpio_config = {
    kGPIO_DigitalOutput,
    1U,
  };
  
  const port_pin_config_t i2c_scl_port_config = {
    /* Internal pull-up resistor is disabled */
    kPORT_PullDisable,
    /* Slow slew rate is configured */
    kPORT_SlowSlewRate,
    /* 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 i2c scl pin */
  gpio_pin_config_t i2c_scl_gpio_config = {
    kGPIO_DigitalOutput,
    1U,
  };
  
  PORT_SetPinConfig(SCL_PORT, SCL_PIN, &i2c_sda_port_config);
  GPIO_PinInit(SCL_GPIO, SCL_PIN, &i2c_sda_gpio_config);
  PORT_SetPinConfig(SDA_PORT, SDA_PIN, &i2c_scl_port_config);
  GPIO_PinInit(SDA_GPIO, SDA_PIN, &i2c_scl_gpio_config);

  
#ifdef RELAYONBOARD
  /* Relay pins */
  const port_pin_config_t relay_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 relay gpio pin */
  gpio_pin_config_t relay_gpio_config = {
    kGPIO_DigitalOutput,
    0,
  };
  
  PORT_SetPinConfig(RELAY_OPEN_PORT, RELAY_OPEN_PIN, &relay_port_config);
  PORT_SetPinConfig(RELAY_CLOSE_PORT, RELAY_CLOSE_PIN, &relay_port_config);
  GPIO_PinInit(RELAY_OPEN_GPIO, RELAY_OPEN_PIN, &relay_gpio_config);
  GPIO_PinInit(RELAY_CLOSE_GPIO, RELAY_CLOSE_PIN, &relay_gpio_config);
  CloseRelay();
#endif
  
  CheckPowerStatus();
  
  if (SystemState.PowerMode == POWERMODE_BAT)
  {
    if (GPIO_GET_PBU == PBU_ACTIVE_LEVEL)
    {
      LATCH_ON;
      BattModeTimeout = BattModeTO;
    }
    else
    {
      ShutDownGPIOs();
      SIM->MISC_CTL   = 0x800F0000;
      GoToSleep();
    }
  }
}

/*!
 * @brief Drive gpio pins to close the relay.
 */
void CloseRelay(void)
{
  RELAY_CLOSE_HI;
  RELAY_OPEN_LO;
  SDK_DelayAtLeastUs((RELAY_PULSE_HIGH_TIME_MS * 1000), SYSTEM_CLOCK);
  RELAY_CLOSE_LO;
}

/*!
 * @brief Drive gpio pins to open the relay.
 */
void OpenRelay(void)
{
  RELAY_OPEN_HI;
  RELAY_CLOSE_LO;
  SDK_DelayAtLeastUs((RELAY_PULSE_HIGH_TIME_MS * 1000), SYSTEM_CLOCK);
  RELAY_OPEN_LO;
}

/*!
 * @brief Initialization routine for load connection through relay.
 */
void InitConnectDisconnect(void)
{
  uint16 DisConSign;
  
  NVReadIIC(DiscnCtrlSignAddr, (uint8 *)&DisConSign, 2);
  if(DisConSign!= DISCONCTRL_SIGN)
  {
    /* Connect */
    CloseRelay();
    
    DisConSign = DISCONCTRL_SIGN;
    NVWriteIIC(DiscnCtrlSignAddr, (uint8 *)&DisConSign, 2);
  }
}

/*!
 * @brief Disables GPIO functions to default reset low-power state of the MCU, 
 * to reduce power consumption in the meter.
 */
void ShutDownGPIOs(void)
{
  /* disable pin functions, except Mains_ON/PFAIL and Push Button - which are left as wakeup sources */
  /* Also leave SWD GPIO pins if you want debugging enabled */
  const port_pin_config_t shutdown_port_config = {
    /* Internal pull-up resistor is disabled */
    kPORT_PullDisable,
    /* Fast slew rate is configured */
    kPORT_FastSlewRate,
    /* Open drain is disabled */
    kPORT_OpenDrainDisable,
    /* Pin function disabled or analog */
    kPORT_PinDisabledOrAnalog,
    /* Pin Control Register fields [15:0] are not locked */
    kPORT_UnlockRegister};

  PORT_SetMultiplePinsConfig(PORTA, 0xBF, &shutdown_port_config);       /* PTA6 is mains on */
  PORT_SetMultiplePinsConfig(PORTB, 0xFD, &shutdown_port_config);       /* PTB1 is up scroll */
  PORT_SetMultiplePinsConfig(PORTC, 0xFE, &shutdown_port_config);
  PORT_SetMultiplePinsConfig(PORTD, 0xFF, &shutdown_port_config);
  PORT_SetMultiplePinsConfig(PORTE, 0x3D, &shutdown_port_config);
  PORT_SetMultiplePinsConfig(PORTF, 0xFF, &shutdown_port_config);
  PORT_SetMultiplePinsConfig(PORTG, 0xFF, &shutdown_port_config);
  PORT_SetMultiplePinsConfig(PORTH, 0xFF, &shutdown_port_config);
  PORT_SetMultiplePinsConfig(PORTI, 0x0F, &shutdown_port_config);
}
  
/*!
 * @brief Routine to check if the meter is powered of the AC mains or the battery.
 */
void CheckPowerStatus(void)
{
  if (GPIO_GET_MAINS_ON)
  {
    MainsOn = TRUE;
    SystemState.PowerMode = POWERMODE_RUN;
  }
  else
  {
    MainsOn = FALSE;
    SystemState.PowerMode = POWERMODE_BAT;
  }
}


