/*
 * Copyright (c) 2010-2016, Freescale Semiconductor, Inc.
 * Copyright (c) 2016-2021, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#ifndef __METERINGLPRT_H
#define __METERINGLPRT_H

#include "types.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/  
#define nBUFFERS 2
#define POWERTOENERGY      (74.56540444)
  
#define SAMPLES1500   1500U    /* 1500 samples per second */
#define SAMPLES3000   3000U    /* 3000 samples per second */
#define SAMPLES6000   6000U    /* 6000 samples per second */
  
#define LPRT_OK      0         /* All input parameters are OK, function output is valid */
#define LPRT_ERROR   1         /* Some of input parameters is not OK, function output is not valid */

  typedef enum
{
  CURRENT_PHASE,
  CURRENT_NEUTRAL,
  nCURRENTS
} CURRENTS;

typedef enum
{
  ACT_POWER,
  REACT_POWER,
  APP_POWER,
  nPOWERS
} POWERS;

typedef enum
{
  ACTI_ENERGY_1PH,
  REACTIACTI_ENERGY_1PH,
  REACTEACTI_ENERGY_1PH,
  APPI_ENERGY_1PH,
  ACTE_ENERGY_1PH,
  APPE_ENERGY_1PH,
  nENERGIES_1PH
} ENERGIES;

typedef enum
{
  V_R_PHASE,
  V_Y_PHASE,
  V_B_PHASE,
  nVPHASES
}VPHASES;

typedef enum
{
  I_R_PHASE,
  I_Y_PHASE,
  I_B_PHASE,
  I_N_PHASE,
  nIPHASES
}IPHASES;

typedef enum
{
  R_PHASEMASK = (1 << V_R_PHASE),
  Y_PHASEMASK = (1 << V_Y_PHASE),
  B_PHASEMASK = (1 << V_B_PHASE),
}PHASEMASKS;

typedef enum
{
  ACT_POWER_3PH,
  REACT_POWER_3PH,
  APP_POWER_3PH,
  nPOWERS_3PH
} POWERS_3PH;

typedef enum
  {
    ACTI_ENERGY_3PH,
    REACTIACTI_ENERGY_3PH,
    REACTEACTI_ENERGY_3PH,
    APPI_ENERGY_3PH,
    ACTE_ENERGY_3PH,
    REACTIACTE_ENERGY_3PH,
    REACTEACTE_ENERGY_3PH,
    APPE_ENERGY_3PH,
    nENERGIES_3PH
} ENERGIES_3PH;

typedef enum
{
  METREC_FWDED,
  METREC_NET,
} METRECTYPES;

typedef enum
{
  PHSEQ_FWD,
  PHSEQ_REV,
}PH_SEQ;

/*! Metering library data structure definition - 1PH METER                    */
typedef struct
{
  float     Vrms;                /*!< Calculated RMS value of the voltage */
  float     Irms[nCURRENTS];     /*!< Calculated RMS currents - Phase and neutral */
  float     VrmsNoFudge;         /*!< RMS value of voltage w/o compensation */
  float IrmsNoFudge[nCURRENTS];  /*!< RMS value of currents w/o compensation */
  float     PFMetImax;           /*!< Calculated Power factor value during forced Imax condition */
  float ActPowers[nCURRENTS];    /*!< Calculated active power */
  float ActPowersNoFudge[nCURRENTS]; /*!< Calculated active power value w/o compensation */
  float ReactPowers[nCURRENTS];  /*!< Calculated reactive power */
  float AppPowers[nCURRENTS];    /*!< Calculated apparent power */
  float AppPowersNoFudge[nCURRENTS]; /*!< Calculated apparent power w/o compensation */
  float PowerFactors[nCURRENTS]; /*!< Calculated power factor */
  float  Frequency;              /*!< Calculated frequency */
  uint16 nSamples;               /*!< No of voltage/current samples per second - application to load */
  uint8  MetDue;                 /*!< Indicates metrology processing is due for a second */
  uint8  MetOnImax;              /*!< Indication to do metering with Imax condition - application to load */
  int8   ISigns[nCURRENTS];      /*!< Forward/reverse sign of currents, 1 = forward, -1 = reverse */
  uint8  ReactSampleIndex;       /*!< Reactive sample index - internal */
  uint8  CurToUse;               /*!< Indicates which current has higher value - Phase/neutral */
  uint16 nSamps;                 /*!< Indicates current sample index ~ [0-(nSamples-1)] */
  int32 VOffset;                 /*!< Calculated Voltage offset */
  int32 *pVQCycleSamps;          /*!< 90 degree phase shifted voltage samples buffer pointer - internal */
  int32  IOfstSum[nCURRENTS];    /*!< Current offset sum - internal */
  int32  IOffsets[nCURRENTS];    /*!< Calculated current offsets */
  int32  VSampsS;                /*!< Offset compensated voltage sample */
  int32  VOfstSum;               /*!< Voltage offset sum - internal */
  uint64 VrmsSums[nBUFFERS];     /*!< Square sums of the voltage samples - internal */
  uint64 IrmsSums[nBUFFERS][nCURRENTS]; /*!< Square sums of the current samples - internal */
  uint64 RelaySenseSums[nBUFFERS]; /*!< Square sums of the relay sense voltage samples - internal */
  int32  VRelayOfstSum;          /*!< Relay sense voltage offset sum - internal */
  int32  VRelayOffset;           /*!< Calculated relay voltage offset */
  float IBasic;                  /*!< Basic currnet of the meter - application to load */
  float IMax;                    /*!< Maximum current rating of the meter - application to load */
  float VHystHigh;               /*!< High threshold value of voltage to enable gain for the current measurement - application to load */
  float VHystLow;                /*!< Low threshold value of voltage to disable gain for the current measurement - application to load */
  float MaxPower;                /*!< Maximum value of calculated power to restrict power/energy count calculation - application to load */
  int32  ISamps[nCURRENTS];      /*!< Offset compensated current samples */
  float PhAngles[2];             /*!< Calculated Phase angle */
  uint8 MetRecordingType;        /*!< Power/energy recording type METREC_FWDED/METREC_NET */
  uint8  WBuffer;                /*!< Buffer index of voltage/current samples buffers for a second period */
  uint8  FirstTime;              /*!< internal use */
  uint8 IsGainEnabled;           /*!< Returns current gain is status. TRUE = enabled, FALSE = disabled */
  uint8 LastGainStatus;          /*!< Related to current gain status - internal */
  uint8  IncEnerPtrs[3];         /*!< Indicated energy pointer types active, reactive and apparent - internal */
  uint32 MetEnergyCounts[3];     /*!< Calculated energy counts for 50 periods */
  uint64 MetEnergySecCounts[3];  /*!< Calculated energy counts 1 second */
  uint8  DoFundamental;          /*!< Indicate whether fundamental frequency calculation to be done - application to load */
  uint8  fSampNo;                /*!< Used for fundamental frequency related calculations - internal */
  uint8  CalibState;             /*!< Holds calibration state CALIBSTATE_IDLE, CALIBSTATE_PROGRESS, CALIBSTATE_COMPLETE */
} tMETERLIBLPRT1PH_DATA;

/*! Metering library data structure definition - 3PH METER                    */
typedef struct
{
  float Vrms[nVPHASES];                 /*!< Calculated RMS value of the voltages */
  float Irms[nIPHASES];                 /*!< Calculated RMS currents */
  float VrmsNoFudge[nIPHASES];          /*!< RMS value of voltages w/o compensation */
  float IrmsNoFudge[nIPHASES];          /*!< RMS value of currents w/o compensation */
  float Frequency;                      /*!< Calculated frequency */
  uint16 nSamples;                      /*!< No of voltage/current samples per second - application to load */
  uint8  ReactSampleIndex;              /*!< Reactive sample index - internal */
  int16  *pVQCycleSamps[nVPHASES];      /*!< 90 degree phase shifted voltage samples buffer pointer - internal */
  uint64 VrmsSums[2][nVPHASES];         /*!< Square sums of the voltage samples - internal */
  uint64 IrmsSums[2][nIPHASES];         /*!< Square sums of the current samples - internal */
  uint8  MetDue;                        /*!< Indicates metrology processing is due for a second */
  uint8  MetOnImax;                     /*!< Indication to do metering with Imax condition - application to load */
  int16  VSampsS[nVPHASES];             /*!< Offset compensated voltage samples */
  uint32 VOfstSum[nVPHASES];            /*!< Voltage offset sums - internal */
  int32 IOfstSum[nIPHASES];             /*!< Current offset sums - internal */
  int32 IOffsets[nIPHASES];             /*!< Calculated current offsets */
  uint16 VOffsets[nVPHASES];            /*!< Calculated Voltage offsets */
  int32 ISamps[nIPHASES];               /*!< Offset compensated current samples */
  int8  ISigns[nVPHASES];               /*!< Forward/reverse sign of currents, 1 = forward, -1 = reverse */
  float ActPowers[nVPHASES];            /*!< Calculated active power values */
  float ReactPowers[nVPHASES];          /*!< Calculated reactive power values */
  float AppPowers[nVPHASES];            /*!< Calculated apparent power values */
  float PhPowerFactors[nVPHASES];       /*!< Calculated power factor values of three-phases */
  float PowerFactor;                    /*!< Calculated total power factor */
  float Powers[nPOWERS_3PH];            /*!< Calculated powers values per second */
  float PhAngles[nVPHASES];             /*!< Calculated Phase angles */
  float AppPowersNoFudge[nVPHASES];     /*!< Calculated apparent power values w/o compensation */
  float ActPowerNoFudge;                /*!< Calculated total active power value w/o compensation */
  float AppPowerNoFudge;                /*!< Calculated total apparent power value w/o compensation */
  float PhPFNoFudge[nIPHASES];          /*!< Calculated power factors w/o compensation */
  float PFMetImax;                      /*!< Calculated Power factor value during forced Imax condition */
  float IBasic;                         /*!< Basic currents of the meter - application to load */
  float IMax;                           /*!< Maximum current rating of the meter - application to load */
  float  MinIMagThreshold;
  float MaxPower;                       /*!< Maximum value of calculated power to restrict power/energy count calculation - application to load */
  uint8 MetRecordingType;               /*!< Power/energy recording type METREC_FWDED/METREC_NET */     
  uint8  WBuffer;                       /*!< Buffer index of voltage/current samples buffers for a second period */
  uint8  nZCurs;                        /*!< internal */
  uint8  FirstCycle;                    /*!< internal */
  uint8  IncEnerPtrs[3];                /*!< Indicated energy pointer types active, reactive and apparent - internal */
  uint32 MetEnergyCounts[3];            /*!< Calculated energy counts for 50 periods */
  uint64 MetEnergySecCounts[3];         /*!< Calculated energy counts 1 second */
  uint8  DoFundamental;                 /*!< Indicate whether fundamental frequency calculation to be done - application to load */
  uint8 CalibState;                     /*!< Holds calibration state CALIBSTATE_IDLE, CALIBSTATE_PROGRESS, CALIBSTATE_COMPLETE */
} tMETERLIBLPRT3PH_DATA;

/*******************************************************************************
* Prototypes
******************************************************************************/
extern tMETERLIBLPRT1PH_DATA *pmlib1phdata;
extern float VFundamental1Ph;
extern float IFundamental1Ph[nCURRENTS];
extern float VTHD1Ph;
extern float ITHD1Ph[nCURRENTS];

extern float Vrelaysense;

extern tMETERLIBLPRT3PH_DATA *pmlib3phdata;
extern float VFundamental3Ph[nVPHASES];
extern float IFundamental3Ph[nVPHASES];
extern float VTHD3Ph[nVPHASES];
extern float ITHD3Ph[nVPHASES];

/***************************************************************************//*!
 * @brief   Does the RMS and power calculation per voltage and current samples. 
 *          Also, does the offset calculations. Once this function finished all 
 *          samples processing for 50 periods (50 Hz signal), 
 *          tMETERLIBLPRT3PH_DATA -> MetDue is set to 'TRUE' value.
 * @note    The @ref DoPower1Ph function must be called after 1 set of voltage,
 *          current samples are received.
 ******************************************************************************/
extern void DoPower1Ph(void);

/***************************************************************************//*!
 * @brief   Re-calculates non-billing parameters once every second or 50 
 *          sinusoidal wave periods.
 * @note    The @ref DoMetering1Ph function must be called after 
 *          tMETERLIBLPRT1PH_DATA -> MetDue is set to 'TRUE' value. This 
 *          function internally clears tMETERLIBLPRT1PH_DATA -> MetDue to 
 *          'FALSE'.
 ******************************************************************************/
extern void DoMetering1Ph(void);

/***************************************************************************//*!
 * @brief   Initializes tMETERLIBLPRT1PH_DATA meteting structure object with 
 *          few application specific parameters. Typically to be called once 
 *          application run cycle.
 * @param   nSamples     No of voltage/current samples per second 
 *          - application to load.
 * @param   samplesForOffset   No of samples per second to be used for offset 
 *          calculation.
 * @param   pFreqDependentPhErr   Application defined Frequency dependent phase 
 *          correction values.
 * @param   doFundamental Application defined initialization if metering library 
 *          should perform fundamental calculation related tasks.
 * @note    The @ref MeterLibLPRT1Ph_InitParams function must be called 
 *          typically once in application initialization cycle.
 ******************************************************************************/
extern uint8 MeterLibLPRT1Ph_InitParams(tMETERLIBLPRT1PH_DATA *mlib,  
                                       uint16 nSamples, uint16 samplesForOffset, 
                                       float *pFreqDependentPhErr, uint8 doFundamental);

/* Callbacks/hooks exported by metrology library */
/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to further correct the phase angle to fine tune power calculation.
 * @param   currenttoUse Current phase number CURRENT_PHASE or CURRENT_NEUTRAL.
 * @note    The @ref CorrectAppPhAngle1Ph is called from DoMetering1Ph().
 ******************************************************************************/
extern void CorrectAppPhAngle1Ph(uint8 currenttoUse);

/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to tune up non-billing parameters as per application need - for 
 *          example to clear leakage current and related parameters.
 * @note    The @ref FudgeParameters1Ph is called from DoMetering1Ph().
 ******************************************************************************/
extern void FudgeParameters1Ph(void);

/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to check current phase voltage and indicate the metering library 
 *          to switch to low power mode measurements of non-billing parameters  
 *          through tMETERLIBLPRT1PH_DATA -> IsGainEnabled parameter.
 * @note    The @ref ChkVolLvl is called from DoMetering1Ph().
 ******************************************************************************/
extern void ChkVolLvl(void);

/***************************************************************************//*!
 * @brief   This function is called from metering library during calibration 
 *          phase only to calculate calibration coefficients during low power 
 *          operation and current gain is disabled. Application should also call
 *          this function in the context of ChkVolLvl() if the current RMS 
 *          voltage is higher than tMETERLIBLPRT1PH_DATA -> VHystLow.
 * @note    The @ref DisableGain is called from DoMetering1Ph().
 ******************************************************************************/
extern void DisableGain(void);

/***************************************************************************//*!
 * @brief   This function is called from metering library during calibration 
 *          phase only to calculate calibration coefficients after low power 
 *          operation and current gain is enabled. Application should also call
 *          this function in the context of ChkVolLvl() if the current RMS 
 *          voltage is higher than tMETERLIBLPRT1PH_DATA -> VHystHigh.
 * @note    The @ref EnableGain is called from DoMetering1Ph().
 ******************************************************************************/
extern void EnableGain(void);

/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to save CalibStruct1Ph data structure object - once after the 
 *          calibration is done.
 * @note    The @ref CalibMemwrite1Ph is called whenever calibration is 
 *          performed.
 ******************************************************************************/
extern void CalibMemwrite1Ph(void);

/***************************************************************************//*!
 * @brief   This function Process three-phase each phase voltage, current 
 *          samples for a phase.
 * @param   channel     phase number of three-phases.
 * @note    The @ref ProcSamples3Ph function must be called after voltage, 
 *          current samples are received for any phase.
 ******************************************************************************/
extern void ProcSamples3Ph(uint8 channel);

/***************************************************************************//*!
 * @brief   Does the RMS and power calculation per voltage and current samples. 
 *          Also, does the offset calculations. Once this function finished all 
 *          samples processing for 50 periods (50 Hz signal), 
 *          tMETERLIBLPRT3PH_DATA -> MetDue is set to 'TRUE' value.
 * @note    The @ref DoPower3Ph function must be called once after all of 
 *          voltage, current samples are received.
 ******************************************************************************/
extern void DoPower3Ph(void);

/***************************************************************************//*!
 * @brief   Re-calculates non-billing parameters once every second or 50 
 *          sinusoidal wave periods.
 * @note    The @ref DoMetering3Ph function must be called after 
 *          tMETERLIBLPRT3PH_DATA -> MetDue is set to 'TRUE' value. This 
 *          function internally clears tMETERLIBLPRT3PH_DATA -> MetDue to 
 *          'FALSE'.
 ******************************************************************************/
extern void DoMetering3Ph(void);

/***************************************************************************//*!
 * @brief   Initializes tMETERLIBLPRT3PH_DATA meteting structure object with 
 *          few application specific parameters. Typically to be called once 
 *          applicaiton run cycle.
 * @param   nSamples     No of voltage/current samples per second 
 *          - application to load.
 * @param   samplesForOffset   No of samples per second to be used for offset 
 *          calculation.
 * @param   pFreqDependentPhErr   Application defined Frequency dependent phase 
 *          correction values.
 * @param   doFundamental Application defined initialization if metering library 
 *          should perform fundamental calculation related tasks.
 * @note    The @ref MeterLibLPRT3Ph_InitParams function must be called 
 *          typically once in application initialization cycle.
 ******************************************************************************/
extern uint8 MeterLibLPRT3Ph_InitParams(tMETERLIBLPRT3PH_DATA *mlib,  
                                       uint16 nSamples, uint16 samplesForOffset, 
                                       float *pFreqDependentPhErr, uint8 doFundamental);

/* Callbacks/hooks exported by metrology library */
/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to tune up non-billing parameters as per applicaiton need - for 
 *          example to clear leakage current and related parameters.
 * @note    The @ref FudgeParameters3Ph is called from DoMetering3Ph().
 ******************************************************************************/
extern void FudgeParameters3Ph(void);

/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to further correct the phase angle to fine tune power calculation.
 * @note    The @ref CorrectAppPhAngle3Ph is called from DoMetering1Ph().
 ******************************************************************************/
extern void CorrectAppPhAngle3Ph(uint32 phase);

/***************************************************************************//*!
 * @brief   This function is called from metering library to allow application 
 *          to save CalibStruct3Ph data structure object - once after the 
 *          calibration is done.
 * @note    The @ref CalibMemwrite3Ph is called whenever calibration is 
 *          performed.
 ******************************************************************************/
extern void CalibMemwrite3Ph(void);

#ifdef __cplusplus
}

#endif
#endif /* __METERING3PH_H */