/*
 * 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 "defines.h"
#include "fsl_qtmr.h"
#include "fsl_lptmr.h"
#include "fsl_adc16.h"
#include "math.h"
#include "Application.h"
#include "MeteringLPRT.h"
#include "Calibration3Ph.h"
#include "MeteringInterface3Ph.h"
#include "AppCommon.h"
#ifdef DOFUNDAMENTAL
#include "Fundamental3Ph.h"
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define TMR2callback                             TMR2_IRQHandler
#define DoPulsing3Ph                             LPTMR0_LPTMR1_IRQHandler
#define SARADCCallback                           ADC0_IRQHandler
/*******************************************************************************
* Prototypes
******************************************************************************/
uint8  OnActCounts;
uint8  NumFreqCycles;
uint8  OnReactCounts;
uint8  PhaseSequence;
uint16 LastTmrVal;  
uint16 ThisTmrVal;
uint32 FreqAccumPer;

uint8 PhMask;
uint8 ChlsDone;
uint16 VSamps;

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief This timer callback function accumates the active(and reactive if required)
 * energies calculated fron each metering cycle(1 sec) and compares the cumulative 
 * value with a threshold. If it exceeds the threshold value, turns on the 
 * LED for a duration. In electonic merters, this pulse is equivalent to 
 * 1 cycle rotation of disc in older electro-mechanical energy meters.
 */
void DoPulsing3Ph(void)
{
  LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
  /* Pulsing */
  ActAccumulator   += mlib3phdata.MetEnergyCounts[0];
  ReactAccumulator += mlib3phdata.MetEnergyCounts[1];
  if (ActAccumulator >= CALIBLED_COMPARE)
  {
    ActAccumulator -= CALIBLED_COMPARE;
    ON_KWH_LED();
    OnActCounts = ONCOUNTS;
  }
  if (ReactAccumulator >= CALIBLED_COMPARE)
  {
    ReactAccumulator -= CALIBLED_COMPARE;
    ON_KVARH_LED();
    OnReactCounts = ONCOUNTS;
  }
  if (OnActCounts > 0)
  {
    OnActCounts--;
  }
  else
  {
    OFF_KWH_LED();
  }

  if (OnReactCounts > 0)
  {
    OnReactCounts--;
  }
  else
  {
    OFF_KVARH_LED();
  }
}


void SARADCCallback(void)
{
  if ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) && (ADC0->SC1[0] & ADC_SC1_AIEN_MASK))
  {
    VSamps = (uint16)ADC16_GetChannelConversionValue(ADC0, 0U);
    /* read the SD-AFE current channel sample */
    mlib3phdata.ISamps[0] = RPHASE_AFE_CH_RR; 
    mlib3phdata.IOfstSum[0] += mlib3phdata.ISamps[0];
    mlib3phdata.ISamps[0] -= mlib3phdata.IOffsets[0]; // Previous offset
    
    /* read the SAR voltage channel sample */
    mlib3phdata.VOfstSum[0] += VSamps;
    mlib3phdata.VSampsS[0] = VSamps - mlib3phdata.VOffsets[0];
    ProcSamples3Ph(0);
  }
  if ((ADC0->SC1[1] & ADC_SC1_COCO_MASK) && (ADC0->SC1[1] & ADC_SC1_AIEN_MASK))
  {
    VSamps = (uint16)ADC16_GetChannelConversionValue(ADC0, 1U);
    /* read the SD-AFE current channel sample */
    mlib3phdata.ISamps[1] = YPHASE_AFE_CH_RR; 
    mlib3phdata.IOfstSum[1] += mlib3phdata.ISamps[1];
    mlib3phdata.ISamps[1] -= mlib3phdata.IOffsets[1]; // Previous offset
    
    /* read the SD-AFE neutral current channel sample */
    mlib3phdata.ISamps[3] = NEUTRAL_AFE_CH_RR;
    mlib3phdata.IOfstSum[3] += mlib3phdata.ISamps[3];
    mlib3phdata.ISamps[3] -= mlib3phdata.IOffsets[3]; // Previous offset
    
    /* read the SAR voltage channel sample */
    mlib3phdata.VOfstSum[1] += VSamps;
    mlib3phdata.VSampsS[1] = VSamps - mlib3phdata.VOffsets[1];
    ProcSamples3Ph(1);
  }
  if ((ADC0->SC1[2] & ADC_SC1_COCO_MASK) && (ADC0->SC1[2] & ADC_SC1_AIEN_MASK))
  {
    VSamps = (uint16)ADC16_GetChannelConversionValue(ADC0, 2U);
    /* read the SD-AFE current channel sample */
    mlib3phdata.ISamps[2] = BPHASE_AFE_CH_RR; 
    mlib3phdata.IOfstSum[2] += mlib3phdata.ISamps[2];
    mlib3phdata.ISamps[2] -= mlib3phdata.IOffsets[2]; // Previous offset
    
    /* read the SAR voltage channel sample */
    mlib3phdata.VOfstSum[2] += VSamps;
    mlib3phdata.VSampsS[2] = VSamps - mlib3phdata.VOffsets[2];
    
    ProcSamples3Ph(2);
    DoPower3Ph();
  }
  
  SDK_ISR_EXIT_BARRIER;  
}

/*!
 * @brief This timer callback function calculates the frequency of the meter.
 */
void TMR2callback(void)
{
  uint16 TmrCounts;
  float freq;
  
  /* Clear interrupt flag.*/
  QTMR_ClearStatusFlags(TMR2, kQTMR_EdgeFlag);
  
  SyncVChl &= 0x03;
  /* stamp a signature to indicate CMP o/p triggerred the timer, so a voltage is applied to the current channel with CMP */
  Syncing = 0xAAAA;

  if ((mlib3phdata.VSampsS[1] < 0) && (mlib3phdata.VSampsS[2] > 0))
  {
    PhaseSequence = PHSEQ_FWD;
  }
  else
  {
    PhaseSequence = PHSEQ_REV;
  }

  /* If valid period, accumulate for 50 cycles */
  /* Read TMR Count Value */
  ThisTmrVal = QTMR_GetCurrentTimerCount(TMR2);
  TmrCounts = 0x10000 + ThisTmrVal - LastTmrVal;
  LastTmrVal = ThisTmrVal;
  FreqAccumPer += TmrCounts;
  if (TmrCounts > 20000)
  {
    NumFreqCycles++;
  }

  /* If period accumulation cycles crossed */
  if (NumFreqCycles >= PERIOD_ACCUMULATION_CYCLES)
  {
    /* Time to compute frequency */
    freq = (float)FreqAccumPer/NumFreqCycles;

    NumFreqCycles = 0;
    FreqAccumPer = 0;
    
    /* Frequency conversion to real value */
    freq = (TMR_CNTS_50HZ/freq)*50.0;
    mlib3phdata.Frequency = freq * CalibStruct3Ph.FrequencyCoeff;
  }
  SDK_ISR_EXIT_BARRIER;
}
