#ifndef _METER_H_
#define _METER_H_

#include "user_config.h"
#include <stdint.h>
#include <ti/iqmath/include/IQmathLib.h>

//! \brief Size of voltage array (it must be a multiple of 2)
#define HAL_ADC_V_ARRAY_LENGTH      4
//! \brief Size of voltage array (it must be a multiple of 2)
#define HAL_ADC_I_ARRAY_LENGTH      4

//! Voltage Mask used for circular buffer
#define HAL_ADC_V_MASK              (HAL_ADC_V_ARRAY_LENGTH-1)
//! Current Mask used for circular buffer
#define HAL_ADC_I_MASK              (HAL_ADC_I_ARRAY_LENGTH-1)
#define EM_PHASE_LENGTH                     (1)
// Indexes for the Phase Array
#define EM_PH_A_IDX                         (0)

#define HAL_ADC_FREQ_4000_HZ        (4096)
#define HAL_ADC_FREQ_8000_HZ        (8192)
#define HAL_ADC_FREQ_16000_HZ       (16000)

#define PHASE_A_VOLTAGE_DC_ESTIMATE                 100
#define PHASE_A_VOLTAGE_SCALE_FACTOR                500
#define PHASE_A_CURRENT_DC_ESTIMATE                 0
#define PHASE_A_CURRENT_SCALE_FACTOR                50
#define DEFAULT_V_DC_ESTIMATE_A                         _IQ19(PHASE_A_VOLTAGE_DC_ESTIMATE)
#define DEFAULT_V_RMS_SCALE_FACTOR_A                    _IQ19(PHASE_A_VOLTAGE_SCALE_FACTOR)
#define DEFAULT_I_DC_ESTIMATE_A                         _IQ19(PHASE_A_CURRENT_DC_ESTIMATE)
#define DEFAULT_I_RMS_SCALE_FACTOR_A                    _IQ19(PHASE_A_CURRENT_SCALE_FACTOR)
//*****************************************************************************
//
// The following are values are used as mask for the phaseDataReady global
// variable to trigger the foreground process.
//
//*****************************************************************************
#define HAL_ADC_PHASE_NO_DATA_READY         0x00
#define HAL_ADC_PHASE_A_DATA_READY          0x01
#define HAL_ADC_PHASE_B_DATA_READY          0x02
#define HAL_ADC_PHASE_C_DATA_READY          0x04
#define HAL_ADC_PHASE_NEUTRAL_DATA_READY    0x40
#define HAL_ADC_PHASE_TOTAL_DATA_READY	    0x80

#define MAX_PER_SAMPLE_VOLTAGE_SLEW _IQ23(1)

#define	IIR_COEFF_MIN_FREQ		4900
#define	IIR_COEFF_MAX_FREQ		5100
#define	IIR_COEFF_TABLE_LEN		101
#define	IIR_COEFF_SHIFT			1
const _iq30 G_CONSTANT[IIR_COEFF_TABLE_LEN] ={
	0xC4BEE7BE, /* Freq 49.00 */
	0xC4BF6219, /* Freq 49.02 */
	0xC4BFDC74, /* Freq 49.04 */
	0xC4C056CE, /* Freq 49.06 */
	0xC4C0D126, /* Freq 49.08 */
	0xC4C14B7E, /* Freq 49.10 */
	0xC4C1C5D5, /* Freq 49.12 */
	0xC4C2402B, /* Freq 49.14 */
	0xC4C2BA81, /* Freq 49.16 */
	0xC4C334D5, /* Freq 49.18 */
	0xC4C3AF28, /* Freq 49.20 */
	0xC4C4297B, /* Freq 49.22 */
	0xC4C4A3CC, /* Freq 49.24 */
	0xC4C51E1D, /* Freq 49.26 */
	0xC4C5986C, /* Freq 49.28 */
	0xC4C612BB, /* Freq 49.30 */
	0xC4C68D09, /* Freq 49.32 */
	0xC4C70756, /* Freq 49.34 */
	0xC4C781A2, /* Freq 49.36 */
	0xC4C7FBED, /* Freq 49.38 */
	0xC4C87638, /* Freq 49.40 */
	0xC4C8F081, /* Freq 49.42 */
	0xC4C96AC9, /* Freq 49.44 */
	0xC4C9E511, /* Freq 49.46 */
	0xC4CA5F57, /* Freq 49.48 */
	0xC4CAD99D, /* Freq 49.50 */
	0xC4CB53E2, /* Freq 49.52 */
	0xC4CBCE26, /* Freq 49.54 */
	0xC4CC4869, /* Freq 49.56 */
	0xC4CCC2AB, /* Freq 49.58 */
	0xC4CD3CEC, /* Freq 49.60 */
	0xC4CDB72C, /* Freq 49.62 */
	0xC4CE316C, /* Freq 49.64 */
	0xC4CEABAA, /* Freq 49.66 */
	0xC4CF25E7, /* Freq 49.68 */
	0xC4CFA024, /* Freq 49.70 */
	0xC4D01A60, /* Freq 49.72 */
	0xC4D0949A, /* Freq 49.74 */
	0xC4D10ED4, /* Freq 49.76 */
	0xC4D1890D, /* Freq 49.78 */
	0xC4D20345, /* Freq 49.80 */
	0xC4D27D7D, /* Freq 49.82 */
	0xC4D2F7B3, /* Freq 49.84 */
	0xC4D371E8, /* Freq 49.86 */
	0xC4D3EC1C, /* Freq 49.88 */
	0xC4D46650, /* Freq 49.90 */
	0xC4D4E083, /* Freq 49.92 */
	0xC4D55AB4, /* Freq 49.94 */
	0xC4D5D4E5, /* Freq 49.96 */
	0xC4D64F15, /* Freq 49.98 */
	0xC4D6C944, /* Freq 50.00 */
	0xC4D74372, /* Freq 50.02 */
	0xC4D7BD9F, /* Freq 50.04 */
	0xC4D837CB, /* Freq 50.06 */
	0xC4D8B1F7, /* Freq 50.08 */
	0xC4D92C21, /* Freq 50.10 */
	0xC4D9A64B, /* Freq 50.12 */
	0xC4DA2073, /* Freq 50.14 */
	0xC4DA9A9B, /* Freq 50.16 */
	0xC4DB14C2, /* Freq 50.18 */
	0xC4DB8EE8, /* Freq 50.20 */
	0xC4DC090D, /* Freq 50.22 */
	0xC4DC8331, /* Freq 50.24 */
	0xC4DCFD54, /* Freq 50.26 */
	0xC4DD7776, /* Freq 50.28 */
	0xC4DDF197, /* Freq 50.30 */
	0xC4DE6BB8, /* Freq 50.32 */
	0xC4DEE5D7, /* Freq 50.34 */
	0xC4DF5FF6, /* Freq 50.36 */
	0xC4DFDA14, /* Freq 50.38 */
	0xC4E05431, /* Freq 50.40 */
	0xC4E0CE4C, /* Freq 50.42 */
	0xC4E14867, /* Freq 50.44 */
	0xC4E1C281, /* Freq 50.46 */
	0xC4E23C9B, /* Freq 50.48 */
	0xC4E2B6B3, /* Freq 50.50 */
	0xC4E330CA, /* Freq 50.52 */
	0xC4E3AAE1, /* Freq 50.54 */
	0xC4E424F6, /* Freq 50.56 */
	0xC4E49F0B, /* Freq 50.58 */
	0xC4E5191F, /* Freq 50.60 */
	0xC4E59332, /* Freq 50.62 */
	0xC4E60D43, /* Freq 50.64 */
	0xC4E68754, /* Freq 50.66 */
	0xC4E70165, /* Freq 50.68 */
	0xC4E77B74, /* Freq 50.70 */
	0xC4E7F582, /* Freq 50.72 */
	0xC4E86F8F, /* Freq 50.74 */
	0xC4E8E99C, /* Freq 50.76 */
	0xC4E963A8, /* Freq 50.78 */
	0xC4E9DDB2, /* Freq 50.80 */
	0xC4EA57BC, /* Freq 50.82 */
	0xC4EAD1C5, /* Freq 50.84 */
	0xC4EB4BCD, /* Freq 50.86 */
	0xC4EBC5D4, /* Freq 50.88 */
	0xC4EC3FDA, /* Freq 50.90 */
	0xC4ECB9DF, /* Freq 50.92 */
	0xC4ED33E4, /* Freq 50.94 */
	0xC4EDADE7, /* Freq 50.96 */
	0xC4EE27EA, /* Freq 50.98 */
	0xC4EEA1EB, /* Freq 51.00 */
};
#define EM_MAIN_NOMINAL_FREQ_HZ             (50)
#define EM_SAMPLING_FREQ_HZ                 (HAL_ADC_FREQ_4000_HZ)
#define EM_PHASE_IMP_PER_KWHR               (6400)
#define EM_PHASE_PULSE_DUR                  (20)
#define EM_TOTAL_PHASE_IMP_PER_KWHR         (6400)
#define EM_TOTAL_PHASE_PULSE_DUR            (20)
#define EM_PHASE_START_UP_POWER_mW          (0)
#define EM_TOTAL_START_UP_POWER_mW          (0)
#define EM_AGGREGATE_ENABLE                 (0)
#define EM_PULSE_ARRAY_LENGTH               (EM_PHASE_LENGTH+EM_AGGREGATE_ENABLE)

#define EM_PHASE_CONSTANT               	(3600 * 1e9 * EM_SAMPLING_FREQ_HZ / EM_PHASE_IMP_PER_KWHR)
#define EM_TOTAL_PHASE_CONSTANT             (3600 * 1e9 * EM_SAMPLING_FREQ_HZ / EM_TOTAL_PHASE_IMP_PER_KWHR)
#define EM_MAX_FREQ_COUNT                   (EM_SAMPLING_FREQ_HZ*256L/40)
#define EM_MIN_FREQ_COUNT                   (EM_SAMPLING_FREQ_HZ*256L/70)
 //! \brief This define can be used to mask the EM_System_Configuration->pulseGeneration
 //! variable . This is used by the EM_genPulseIndPhase() to generate pulses for Phase A
#define EM_PULSE_GEN_PHASE_NONE                             (0x00)
#define V_HISTORY_MASK                  (0x3F)

typedef int64_t EM_Power_t;
typedef uint64_t EM_Energy_t;
//! \brief Contains EM SW Lib Phase Calibration
//!
typedef struct _EM_Pulse_Settings_
{
	uint8_t activePulseGpioPort;
	//!< Each phase uses a GPIO port used to generate a pulse used for calibration
	//!< Possible options for each port:
	//!< - GPIO_PORT_P1
	//!< - GPIO_PORT_P2
	//!< - GPIO_PORT_P3
	//!< - GPIO_PORT_P4
	//!< - GPIO_PORT_P5
	//!< - GPIO_PORT_P6
	//!< - GPIO_PORT_P7
	//!< - GPIO_PORT_P8
	//!< - GPIO_PORT_P9
	uint8_t reactivePulseGpioPort;
	//!< Each phase uses a GPIO port used to generate a pulse used for calibration
	//!< Possible options for each port:
	//!< - GPIO_PORT_P1
	//!< - GPIO_PORT_P2
	//!< - GPIO_PORT_P3
	//!< - GPIO_PORT_P4
	//!< - GPIO_PORT_P5
	//!< - GPIO_PORT_P6
	//!< - GPIO_PORT_P7
	//!< - GPIO_PORT_P8
	//!< - GPIO_PORT_P9
	uint16_t activePulseGpioPin;
	//!< Each phase uses a GPIO pin used to generate a pulse used for calibration
	//!< Possible options for each pin:
	//!< - GPIO_PIN0
	//!< - GPIO_PIN1
	//!< - GPIO_PIN2
	//!< - GPIO_PIN3
	//!< - GPIO_PIN4
	//!< - GPIO_PIN5
	//!< - GPIO_PIN6
	//!< - GPIO_PIN7
	uint16_t reactivePulseGpioPin;
	//!< Each phase uses a GPIO pin used to generate a pulse used for calibration
	//!< Possible options for each pin:
	//!< - GPIO_PIN0
	//!< - GPIO_PIN1
	//!< - GPIO_PIN2
	//!< - GPIO_PIN3
	//!< - GPIO_PIN4
	//!< - GPIO_PIN5
	//!< - GPIO_PIN6
	//!< - GPIO_PIN7
    uint64_t activeEnergyCounter;
    //!< Ongoing Active Energy Sum
    uint16_t activeEnergyPulseRemaining;
    //!< Counter used to keep track of remaining ADC samples to keep pulse high
	uint64_t reactiveEnergyCounter;
	//!< Ongoing Reactive Energy Sum
    uint16_t reactiveEnergyPulseRemaining;
    //!< Counter used to keep track of remaining ADC samples to keep pulse high
} EM_Pulse_Settings;
typedef enum _EM_Phase_
{
	EM_Phase_A=0x01,
	//!< - Results requested for phase A
	EM_Phase_B=0x02,
	//!< - Results requested for phase B
	EM_Phase_C=0x04,
	//!< - Results requested for phase C
	EM_Phase_D=0x08,
	//!< - Results requested for phase D
	EM_Phase_E=0x10,
	//!< - Results requested for phase E
	EM_Phase_F=0x20,
	//!< - Results requested for phase F
	EM_Phase_Neutral=0x40
	//!< - Results requested for phase Neutral
} EM_Phase;


//! \brief Selects appropriate EM Sensor for the corresponding channel
//!
typedef enum _EM_Current_Sensor_
{
	EM_Phase_Sensor_CT=0,
	//!< Current Transformer (CT) 
	EM_Phase_Sensor_Shunt=1,
	//!< Shunt
    EM_Phase_Sensor_RC=2,
    //!< Rogowski Coil (RC)
} EM_Current_Sensor;
//! \brief Contains EM SW Lib System Configuration
//!
typedef struct _EM_Phase_Configuration_
{
	_iq23 *currentSamplePtr;    //change from int32_t to _iq23
	//!< Pointer to the current sample
	_iq23 *voltageSamplePtr;  //change from int16_t to _iq23
	//!< Pointer to the voltage sample
	EM_Current_Sensor currentSensor;
	//!< Sensor connected to the current (I) channel
	uint16_t phaseResultsSupported;
	//!< Register used to read what results will be calculated for this phase
	//!< Note: This is a Read-Only register. 
	//!< Possible mask values are:
    //!< - EM_PHASE_RESULT_CALC_VRMS
    //!< - EM_PHASE_RESULT_CALC_IRMS
    //!< - EM_PHASE_RESULT_CALC_V_PEAK
    //!< - EM_PHASE_RESULT_CALC_I_PEAK
    //!< - EM_PHASE_RESULT_CALC_POWER_FACTOR
    //!< - EM_PHASE_RESULT_CALC_FREQ
	//!< - EM_PHASE_RESULT_CALC_ACTIVE_POWER
	//!< - EM_PHASE_RESULT_CALC_REACTIVE_POWER
	//!< - EM_PHASE_RESULT_CALC_APPARENT_POWER
	//!< - EM_PHASE_RESULT_CALC_ACTIVE_ENERGY
	//!< - EM_PHASE_RESULT_CALC_REACTIVE_ENERGY
	//!< - EM_PHASE_RESULT_CALC_APPARENT_ENERGY
	EM_Phase_Calibration *phaseCalibPtr;
	//!< Pointer to EM_Phase_Calibration struct
} EM_Phase_Configuration;

typedef struct _EM_Metrology_
{
    int16_t sampleCount;
    //!< Number of samples being accumulated in the block of processed
    //!< signals being gathered used for the oneDivSC calculation.
    int64_t actPowDotProd;
    //!< Accumulated multiplication of the phase corrected current and voltage (I.V)
    //!< used for the active power calculation.
    int64_t reactPowDotProd;
    //!< Accumulated multiplication of the phase corrected current and voltage 90 (I.V90)
    //!< used for the reactive power calculation.
    int64_t vDotProd;  //change from int16_t vDotProd[3]
    //!< Accumulated squares of the phase corrected voltage (V.V). These are used to
    //!< calculate the RMS voltage, and the power factor. We need separate accumulation
    //!< for each current sensor, as we accumulate the phase corrected voltage which matches
    //!< the current sensor's phase shift.
    int64_t iDotProd;
    //!< Accumulated squares of the phase corrected current (I.I). These are used to
    //!< calculate the RMS current, and the power factor. We need separate accumulation
    //!< for each current sensor, as we accumulate the phase corrected voltage which matches
    //!< the current sensor's phase shift.
    uint16_t cycleSampleCount;
    //!< This is a count of the number of samples to date in the current mains cycle. This
    //!< is used to calculate the mainPeriod.
    _iq30 reactPowGConst;
    //!< G Constant used for the IIR filter to calculate Reactive Power
    uint32_t mainPeriod;
    //!< This a running average of the length of a mains cycle. (samples/cycle * 256)
    uint32_t prevMainPeriod;
    //!< This a running average of the length of a mains cycle. (samples/cycle * 256)
    _iq30 oneDivSC;
    //!< Constant used to calculate the VRMS,IRMS, power and energy values (1/sample_count)
    uint16_t prevSampleCount;
    //!< Stores the prev sample count used to calculate oneDivSC. This is used to avoid
    //!< calculating 1/SC each cycle.
    uint8_t cycleCount;
    //!< Number of zero crossings. Once this number has reached the # of nominal freq.
    //!< For example for 50.2 Hz, once it reaches 50 cycles then the foreground is triggered.
} EM_Metrology;
typedef enum _EM_message_code_
{

	EM_message_code_no_error=0,
	//!< This message code is returned when no error was detected while 
	//!< invoking the API.

	// 1-20 reserved for system configuration messages
    EM_message_code_pulseArray_error=1,
    //!< This error is returned if pulseArrayLength is greater than 0
    //!< and pulseArray is 0
	EM_message_code_indPhaseMeter_error=2,
    //!< This error is returned if pulseArrayLength is greater than 0
	//!< and indPhaseMeterConstant is 0
	EM_message_code_indPhasePulseDuration_error=3,
    //!< This error is returned if pulseArrayLength is greater than 0
    //!< and indPhasePulseDuration is 0
    EM_message_code_totalPhaseMeter_error=4,
    //!< This error is returned if pulseArrayLength is greater than 0,
    //!< totalPhaseMeterConstant is 0 and the pulseGeneration has
    //!< the EM_PULSE_GEN_PHASE_AGGREGATE flag set
    EM_message_code_totalPhasePulseDuration_error=5,
    //!< This error is returned if pulseArrayLength is greater than 0
    //!< and totalPhasePulseDuration is 0 and the pulseGeneration has
    //!< the EM_PULSE_GEN_PHASE_AGGREGATE flag set

	// 21-40 reserved for algorithm configuration messages
    EM_message_code_samplingFrequency_error=21,
    //!< This error is returned if the sampling frequency is not greater than 0
    EM_message_code_reactPowLength_error=22,
    //!< This error is returned if the reactPowIIRTable ptr is null and
    //!< the reactPowIIRLength variable is greater than 0
    EM_message_code_reactPowIIRTable_error=23,
    //!< This error is returned if the reactPowIIRLength is greater than 0
    //!< and the reactPowIIRTable ptr is equal to 0
	
	// 41-59 reserved for meter configuration messages
    EM_message_code_phaseLength_error=41,
    //!< This error is returned if the phaseLength is equal to 0
    EM_message_code_phaseConfig_error=41,
    //!< This error is returned if the phaseConfigPtr is equal to 0

	// 60-249 reserved for calibration messages
	EM_message_code_calibrate_invalidPhase_error=81,
	//!< This error is returned if the phase number is invalid

	//240-255 error
	EM_message_code_error_occurred=255
	//!< This is a generic error this is error that is returned if an unhandled
	//!< error occurs
} EM_message_code;
typedef struct _EM_Phase_BG_Results_
{
    int32_t vDCEstimate;
    //!< DC Estimate for Voltage
    int64_t iDCEstimate;
    //!< DC Estimate for Current
    int16_t reactPowPrevV90;
    //!< Previous V90 voltage used for the IIR filter in the reactive power calculation.
    _iq23 vPrevSample; //change to _iq23
    //!< Previous Voltage sample used for the IIR filter in the reactive power calculation.
    int32_t rogowskiPrevI90;
    //!< Previous I90 current used for the IIR filter in the Rogowski ADC current calculation.
    int32_t iPrevSample;
    //!< Previous Current sample used for the IIR filter in the Rogowski ADC current calculation.
}EM_Phase_BG_Results;

typedef struct _EM_Total_Results_
{
	EM_Power_t activePower;
	//!< Total Active Power since system initialization (uW)
	EM_Power_t reactivePower;
	//!< Total Reactive Power since system initialization (uVAr)
	EM_Power_t apparentPower;
	//!< Total Apparent Power since system initialization (uVA)
    EM_Energy_t activeEnergy;
    //!< Total Active Energy consumed since system initialization (uWh)
    EM_Energy_t reactiveEnergy;
    //!< Total Reactive Energy consumed since system initialization (uVArh)
    EM_Energy_t apparentEnergy;
    //!< Total Apparent Energy consumed since system initialization (UVAh)
} EM_Total_Results;
typedef struct _EM_Phase_Results_
{
    uint32_t VRMS;
    //!< VRMS for previous frame (mV)
    uint32_t IRMS;
    //!< IRMS for previous frame (uA)
    uint32_t vPeak;
    //!< VPeak since system initialization (mV)
    uint32_t iPeak;
    //!< IPeak since system initialization (uA)
    int32_t powerFactor;
    //!< Power Factor calculated when the EM_powerFactor
    uint16_t frequency;
    //!< The Frequency is stored in 0.01Hz steps. A 16 bit unsigned number supports the range
    //!< 0.01Hz to 655.35Hz, which is clearly more than we will ever need for the fundamental.
    EM_Power_t activePower;
	//!< Active Power for previous frame (uW)
	EM_Power_t reactivePower;
	//!< Reactive Power for previous frame (uVAr)
	EM_Power_t apparentPower;
	//!< Apparent Power for previous frame (uVA)
	EM_Energy_t activeEnergy;
	//!< Active Energy for previous frame (uWh)
	EM_Energy_t reactiveEnergy;
	//!< Reactive Energy for previous frame (uVArh)
	EM_Energy_t apparentEnergy;
	//!< Apparent Energy for previous frame (uVAh)
	EM_Phase phaseID;
	//!< Present Phase ID Name
} EM_Phase_Results;
typedef struct _EM_SW_Lib_Result_Handle_
{
	EM_Total_Results *emTotalResult;
	//!< Pointer to EM_Total_Results struct
	EM_Phase_Results *phaseResults;
	//!< Pointer to EM_Phase_Result struct buffer
	EM_Phase_BG_Results *phaseBGResults;
	//!<  Pointer to the EM_Phase_BG_Results struct buffer
	EM_Metrology **phaseMetrologyPing;
	//!< Pointer to EM_Metrology struct Ping buffer
    EM_Metrology **phaseMetrologyPong;
    //!< Pointer to EM_Metrology struct Pong buffer
	uint8_t phaseResultsSupportedLen;
	//!< Length of the phaseResultsSupportedPtr buffer
} EM_SW_Lib_Result_Handle;

typedef struct _EM_Meter_Configuration_
{
	EM_Phase_Configuration *phaseConfigPtr;
	//!< Pointer to the EM_Phase_Configuration struct buffer
	uint8_t phaseLength;
	//!< Length of the emPhasePtr buffer
	uint8_t *meterPW;
	//~< Pointer to meter password string
} EM_Meter_Configuration;
//! \brief Contains EM SW Lib Algorithm Configuration
//!
typedef struct _EM_Algorithm_Configuration_
{
    EM_Power_t residualPowerCutoff;
	//!< Residual Power Cutoff per each phase. This threshold is used as the minimum 
	//!< value of power to store. Power values below this value will not be stored.
    EM_Power_t totalResidualPowerCutoff;
	//!< Residual Power Cutoff for the sum of all the phases. If the sum of all phase  
	//!< power values is below this value, the total power value will not be updated.
	uint8_t mainNomFreq;
	//!< Nominal Freq value for the system (Hz)
    _iq29 sqrtTwoConst;
    //!< Square of 2 constant used for Vpeak and Ipeak calculations
    _iq30 energyCalcConst;
    //!< One dividing by (3600 x sampling frequency)
    uint16_t freqSampling;
    //!< Sampling Frequency (Hz)
    uint16_t reactPowIIRMinFreq;
    //!< Min Frequency for the IIR coefficient table
    uint8_t reactPowIIRShift;
    //!< Number of shifts required to calculated index for IIR table
    uint16_t reactPowIIRLength;
    //!< Length of the IIR coefficient table
    _iq30 *reactPowIIRTable;
} EM_Algorithm_Configuration;

typedef struct _EM_System_Configuration_
{
	EM_Pulse_Settings *pulseArray;
	//!< Pointer to the location where the pulse configuration is stored 
	//!< (one for each phase)
	//uint8_t pulseArrayLength;
	//!< Length of the pulseArray configuration
	uint64_t indPhaseMeterConstant;
	//!< Number of pulses for each / kWH (active energy) or number of pulses 
	//!< for each / kVarh (reactive energy) for each phase
	uint16_t indPhasePulseDuration;
	//!< Pulse duration in ADC counts for each active / reactive energy
	uint64_t totalPhaseMeterConstant;
	//!< Number of pulses for each / kWH for the cumulative total active
	//!< energy or number of pulses for each / kVarh for the cumulative
	//!< reactive energy
	uint16_t totalPhasePulseDuration;
	//!< Pulse duration in ADC counts for the cumulative total of active
	//!< / reactive energy
	uint8_t pulseGeneration;
    //!< Register used to enable / disable the phase pulse flag:
    //!< - EM_PULSE_GEN_PHASE_A
	//!< - EM_PULSE_GEN_PHASE_B
	//!< - EM_PULSE_GEN_PHASE_C
	//!< - EM_PULSE_GEN_PHASE_D
	//!< - EM_PULSE_GEN_PHASE_E
	//!< - EM_PULSE_GEN_PHASE_F
	//!< - EM_PULSE_GEN_PHASE_NEUTRAL
	//!< - EM_PULSE_GEN_PHASE_AGGREGATE
} EM_System_Configuration;
typedef struct _EM_SW_Lib_Config_Handle_
{
	EM_System_Configuration *systemConfig;
	//!< Pointer to EM_System_Configuration struct
	EM_Algorithm_Configuration *algorithmConfig;
	//!< Pointer to EM_Algorithm_Configuration struct
	EM_Meter_Configuration *meterConfig;
	//!< Pointer to EM_Meter_Configuration struct
} EM_SW_Lib_Config_Handle;






/* Arrays to store SD24 conversion results */
_iq23 phAVSamples[HAL_ADC_V_ARRAY_LENGTH];// change from int16_t to _iq23
_iq23 phAISamples[HAL_ADC_I_ARRAY_LENGTH];// change from int32_t to _iq23
// Index variables to read SD24_B results
volatile uint8_t phAWriteVIdx=0;
volatile uint8_t phAWriteIIdx=0;
extern EM_Phase_Calibration g_emPhaseCalibration[1];

EM_Phase_Configuration emPhaseConfiguration[EM_PHASE_LENGTH] =
{
    {
        .phaseResultsSupported = 0x0FFF,
        .phaseCalibPtr = &g_emPhaseCalibration[EM_PH_A_IDX],
        .currentSensor = EM_Phase_Sensor_Shunt
    },
};
EM_Total_Results emTotalResult = {0};
EM_Phase_Results emPhaseResult[EM_PHASE_LENGTH] =
{
    {
        .phaseID = EM_Phase_A
    },
};
EM_Phase_BG_Results emPhaseBackground[EM_PHASE_LENGTH] = {0};
EM_Metrology emMetrologyPing[EM_PHASE_LENGTH] = {0};

EM_Metrology emMetrologyPong[EM_PHASE_LENGTH] = {0};

EM_Metrology *emMetrologyPingArray[EM_PHASE_LENGTH] =
{
    &emMetrologyPing[0]
};
EM_Metrology *emMetrologyPongArray[EM_PHASE_LENGTH] =
{
    &emMetrologyPong[0]
};
EM_SW_Lib_Result_Handle gEmSWResult =
{
    .emTotalResult = &emTotalResult,
    .phaseResults = &emPhaseResult[0],
	.phaseBGResults = &emPhaseBackground[0],
    .phaseMetrologyPing = emMetrologyPingArray,
	.phaseMetrologyPong = emMetrologyPongArray,
    .phaseResultsSupportedLen = EM_PHASE_LENGTH,
};
EM_Algorithm_Configuration emAlgorithmConfig =
{
    .residualPowerCutoff = EM_PHASE_START_UP_POWER_mW,
    .totalResidualPowerCutoff = EM_TOTAL_START_UP_POWER_mW,
    .mainNomFreq = EM_MAIN_NOMINAL_FREQ_HZ,
	.freqSampling = EM_SAMPLING_FREQ_HZ,
	.reactPowIIRLength = IIR_COEFF_TABLE_LEN,
	.reactPowIIRMinFreq = IIR_COEFF_MIN_FREQ,
	.reactPowIIRShift = IIR_COEFF_SHIFT,
	.reactPowIIRTable = (_iq30 *) G_CONSTANT
};
EM_Meter_Configuration emMeterConfig =
{
    .phaseConfigPtr = emPhaseConfiguration,
    .phaseLength = EM_PHASE_LENGTH,
};

EM_Pulse_Settings emPulseSetting[EM_PULSE_ARRAY_LENGTH] =
{
    //PHASE_A
    {
        .activeEnergyCounter = 0,
        .reactiveEnergyCounter = 0,
    },
};

EM_System_Configuration emSystemConfig =
{
    .pulseArray = emPulseSetting,
   // .pulseArrayLength = EM_PULSE_ARRAY_LENGTH,//garygao
    .indPhaseMeterConstant = EM_PHASE_CONSTANT,
    .indPhasePulseDuration = EM_PHASE_PULSE_DUR,
    .totalPhaseMeterConstant = EM_TOTAL_PHASE_CONSTANT,
    .totalPhasePulseDuration = EM_TOTAL_PHASE_PULSE_DUR,
    .pulseGeneration=(EM_PULSE_GEN_PHASE_NONE)
};

EM_SW_Lib_Config_Handle gEmSWConfig =
{
	.systemConfig = &emSystemConfig,
	.algorithmConfig = &emAlgorithmConfig,
	.meterConfig = &emMeterConfig,
};

uint16_t HAL_ADC_maxFreqCount = EM_MAX_FREQ_COUNT;
uint16_t HAL_ADC_minFreqCount = EM_MIN_FREQ_COUNT;

uint16_t *EMSWLIB_EM_HAL_ADC_maxFreqCount =  &HAL_ADC_maxFreqCount;
uint16_t *EMSWLIB_EM_HAL_ADC_minFreqCount =  &HAL_ADC_minFreqCount;


extern void EM_perSampleProc(
        EM_Metrology *metro,
        EM_Phase_Configuration *phase,
        EM_Phase_BG_Results *bgData);

void EM_calcReactivePowerMultAcc(EM_Metrology *metro,
                                 EM_Phase_Configuration *phase,
                                 EM_Phase_BG_Results *bgData);

void EM_perDataChunk(EM_SW_Lib_Config_Handle *config,
                     EM_SW_Lib_Result_Handle *result,
                     uint16_t phaseIdx);                            
void EM_foregroundProc(uint8_t *resultStatus);
void EM_processForegroundData(uint8_t phaseIdx);
void EM_updateOneDivSC(EM_Metrology *metro);
void EM_calcFreqPeriod(EM_Metrology *metro,
                       EM_Phase_Configuration *phase,
                       EM_Phase_BG_Results *bgData);
void EM_calcFreq(EM_Metrology *metro, EM_Phase_Results *result,
                 EM_Algorithm_Configuration *algo);  
void EM_updateReactPowConst(EM_Metrology *metro, EM_Phase_Results *result,
                            EM_Algorithm_Configuration *algo);

void EM_calcVRMSDivSqrt(EM_Metrology *metro, EM_Phase_Configuration *phase,
                        EM_Phase_Results *result);
void EM_calcIRMSDivSqrt(EM_Metrology *metro, EM_Phase_Configuration *phase,
                        EM_Phase_Results *result);                  
uint64_t isqrt64(uint64_t h);   
void EM_calcActivePowerDiv(EM_Metrology *metro, EM_Phase_Configuration *phase,
                           EM_Phase_Results *result,
                           EM_Algorithm_Configuration *algo);   
uint64_t mul64u_64_q30(uint32_t *x, uint32_t y); 
uint64_t mul64_64_q30(uint32_t *x, uint32_t y); 
void EM_calcReactivePowerDiv(EM_Metrology *metro, EM_Phase_Configuration *phase,
                             EM_Phase_Results *result,
                             EM_Algorithm_Configuration *algo); 
void EM_calcApparentPower(EM_Phase_Results *result);  

EM_message_code EM_configureEnergyMeasurement(
        EM_SW_Lib_Config_Handle *config,
        EM_SW_Lib_Result_Handle *result);
EM_message_code EM_initReactPowGConstant(EM_SW_Lib_Config_Handle *config,
                                         EM_SW_Lib_Result_Handle *result);  
EM_message_code EM_initOneDivSC(EM_SW_Lib_Config_Handle *config,
                                EM_SW_Lib_Result_Handle *result); 
void EM_clearMetrology(EM_Metrology *metro);  
void EM_calcPowerFactor(EM_Phase_Results *result);  
void UART_writeBuffer(uint8_t *pData, uint8_t ui8Cnt);                            
// int32_t EM_currentDCFilter(int64_t p, int32_t x);                            
// int16_t EM_voltageDCFilter(int32_t p, int16_t x);                                                                             
// Variable used to trigger foreground process
volatile uint8_t phaseDataReady;
uint8_t gemResultStatus;
volatile int16_t gADCOffset;
int64_t V_dc_estimate;
int64_t I_dc_estimate;
volatile uint8_t datasendflag = 0;
extern int64_t int64mpy(int32_t Input1, int32_t Input2);
uint8_t calcCRC8(uint8_t *pData, uint16_t len);
uint8_t Crc8( uint8_t inCrc, uint8_t inData );
__STATIC_INLINE _iq23 metrology_dcFilter(int64_t *p, _iq23 x)
{
    *p += ( (int64_t) (x - ( (int32_t) (*p >> 16) )) ) << 2;
     x -= ( (int32_t) (*p >> 16) );

    return x;
}

#endif