#include <stdio.h>
#include <stdlib.h>
#include "driver/spi_master.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "ade7758.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_sys.h"



#define PIN_ADUM_EN 4  // ou o pino real conectado ao VE1 do ADUM1401


static const char *TAG = "ade7758";

// --- SPI internals ---
static spi_device_handle_t ade7758_spi_handle = NULL;
static spi_host_device_t spi_host = SPI2_HOST;  // default

static spi_transaction_t spi_transaction;

// --- Configuração SPI do dispositivo ---
static const uint8_t MODE = 2;
static const uint8_t ADDR_BITS = 7;
static const uint8_t CMD_BITS = 1;
static const uint8_t SPI_WRITE = 1;
static const uint8_t SPI_READ  = 0;
static const int BUS_SPEED_HZ  = 1000000;


static void adum1401_select(void) {
    gpio_set_level(PIN_ADUM_EN, 1);
    esp_rom_delay_us(2);  // curto delay para estabilização
}

static void adum1401_deselect(void) {
    esp_rom_delay_us(2);  // opcional: aguarde para evitar glitch
    gpio_set_level(PIN_ADUM_EN, 0);
}

// === Transações básicas ===

static esp_err_t transfer_byte(uint8_t reg_addr, uint8_t data, uint8_t command) {
    adum1401_select();

    spi_transaction.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
    spi_transaction.length = 8;
    spi_transaction.cmd = command;
    spi_transaction.addr = reg_addr;
    spi_transaction.tx_data[0] = data;

    esp_err_t err = spi_device_transmit(ade7758_spi_handle, &spi_transaction);

    adum1401_deselect();
    return err;
}


static esp_err_t transfer_bytes(uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t len, uint8_t command) {
    if (len < 1) len = 1;

    spi_transaction_t t = {
        .flags = 0,
        .length = 8 * len,
        .cmd = command,
        .addr = reg_addr,
        .tx_buffer = tx_buf,
        .rx_buffer = rx_buf
    };

    adum1401_select();
    esp_err_t err = spi_device_transmit(ade7758_spi_handle, &t);
    adum1401_deselect();
    return err;
}


// === Interface pública ===

esp_err_t Init(spi_host_device_t host, int pin_miso, int pin_mosi, int pin_sclk) {
    // Essa função não inicializa o barramento SPI
    // Apenas armazena os parâmetros
    spi_host = host;
    return ESP_OK;
}

esp_err_t InitSpi(int cs_gpio) {
    spi_device_interface_config_t devcfg = {
        .command_bits = CMD_BITS,
        .address_bits = ADDR_BITS,
        .mode = MODE,
        .clock_speed_hz = BUS_SPEED_HZ,
        .spics_io_num = cs_gpio,
        .queue_size = 5,
    };

    gpio_config_t io_conf = {
        .pin_bit_mask = BIT64(PIN_ADUM_EN),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&io_conf);
    gpio_set_level(PIN_ADUM_EN, 0);  // inicialmente desativado


    return spi_bus_add_device(spi_host, &devcfg, &ade7758_spi_handle);
}

spi_device_handle_t GetHandle(void) {
    return ade7758_spi_handle;
}

// === Registro de acesso ===

uint8_t ReadRegister(uint8_t reg_addr, uint8_t command) {
    transfer_byte(reg_addr, 0, command);
    return spi_transaction.rx_data[0];
}

esp_err_t WriteRegister(uint8_t reg_addr, uint8_t data, uint8_t command) {
    return transfer_byte(reg_addr, data, command);
}

esp_err_t WriteRegisterMultipleBytes(uint8_t reg, uint8_t *data, uint8_t count, uint8_t command) {
    return transfer_bytes(reg, data, NULL, count, command);
}

esp_err_t ReadRegisterMultipleBytes(uint8_t reg, uint8_t *buf, uint8_t count, uint8_t command) {
    return transfer_bytes(reg, NULL, buf, count, command);
}

// === Leitura e escrita de tamanho fixo ===

esp_err_t write8(uint8_t reg, uint8_t value) {
    return WriteRegister(reg, value, SPI_WRITE);
}

esp_err_t write16(uint8_t reg, uint32_t value) {
    uint8_t buf[2] = {
        (value >> 8) & 0xFF,
        (value >> 0) & 0xFF
    };
    return WriteRegisterMultipleBytes(reg, buf, 2, SPI_WRITE);
}

esp_err_t write24(uint8_t reg, uint32_t value) {
    uint8_t buf[3] = {
        (value >> 16) & 0xFF,
        (value >> 8) & 0xFF,
        (value >> 0) & 0xFF
    };
    return WriteRegisterMultipleBytes(reg, buf, 3, SPI_WRITE);
}

uint8_t read8(uint8_t reg) {
    uint8_t buf[1];
    ReadRegisterMultipleBytes(reg, buf, 1, SPI_READ);
    return buf[0];
}

uint32_t read16(uint8_t reg) {
    uint8_t buf[2];
    ReadRegisterMultipleBytes(reg, buf, 2, SPI_READ);
    return (buf[0] << 8) | buf[1];
}

uint32_t read24(uint8_t reg) {
    uint8_t buf[3];
    ReadRegisterMultipleBytes(reg, buf, 3, SPI_READ);
    return (buf[0] << 16) | (buf[1] << 8) | buf[2];
}

esp_err_t readBlockData(uint8_t reg, uint8_t *buf, int len) {
    return ReadRegisterMultipleBytes(reg, buf, len, SPI_READ);
}


/*****************************
 *
 *     public functions
 *
 *****************************/

/**
 * In general:
 * @params:  void
 * @return: register content (measure) of the proper type depending on register width
 */

unsigned char getVersion()
{
    return read8(VERSION);
}

/** === setOpMode / getOpMode ===
 OPERATIONAL MODE REGISTER (0x13)
The general configuration of the ADE7758 is defined by writing to the OPMODE register.
Table 18 summarizes the functionality of each bit in the OPMODE register.

Bit Location		Bit Mnemonic		Default Value		Description
0					DISHPF				0					The HPFs in all current channel inputs are disabled when this bit is set.
1					DISLPF				0					The LPFs after the watt and VAR multipliers are disabled when this bit is set.
2					DISCF				1					The frequency outputs APCF and VARCF are disabled when this bit is set.
3 to 5				DISMOD				0					By setting these bits, ADE7758�s ADCs can be turned off. In normal operation, these bits should be left at Logic 0.
                                                            DISMOD[2:0]				Description
                                                            0	0	0				Normal operation.
                                                            1	0	0				Redirect the voltage inputs to the signal paths for the current channels and the current inputs to the signal paths for the voltage channels.
                                                            0	0	1				Switch off only the current channel ADCs.
                                                            1	0	1				Switch off current channel ADCs and redirect the current input signals to the voltage channel signal paths.
                                                            0	1	0				Switch off only the voltage channel ADCs.
                                                            1	1	0				Switch off voltage channel ADCs and redirect the voltage input signals to the current channel signal paths.
                                                            0	1	1				Put the ADE7758 in sleep mode.
                                                            1	1	1				Put the ADE7758 in power-down mode (reduces AIDD to 1 mA typ).
6					SWRST				0					Software Chip Reset. A data transfer to the ADE7758 should not take place for at least 18 �s after a software reset.
7					RESERVED			0					This should be left at 0.

*/

void setOpMode(uint8_t m)
{
    write8(OPMODE, m);
}
uint8_t getOpMode()
{
    return read8(OPMODE);
}

/** === setMMode / getMMode ===
MEASUREMENT MODE REGISTER (0x14)
The configuration of the PERIOD and peak measurements made by the ADE7758 is defined by writing to the MMODE register.
Table 19 summarizes the functionality of each bit in the MMODE register.

Bit Location		Bit Mnemonic		Default Value		Description
0 to 1				FREQSEL				0					These bits are used to select the source of the measurement of the voltage line frequency.
                                                            FREQSEL1		FREQSEL0		Source
                                                            0				0				Phase A
                                                            0				1				Phase B
                                                            1				0				Phase C
                                                            1				1				Reserved
2 to 4				PEAKSEL				7					These bits select the phases used for the voltage and current peak registers.
                                                            Setting Bit 2 switches the IPEAK and VPEAK registers to hold the absolute values
                                                            of the largest current and voltage waveform (over a fixed number of half-line cycles)
                                                            from Phase A. The number of half-line cycles is determined by the content of the
                                                            LINECYC register. At the end of the LINECYC number of half-line cycles, the content
                                                            of the registers is replaced with the new peak values. Similarly, setting Bit 3 turns
                                                            on the peak detection for Phase B, and Bit 4 for Phase C. Note that if more than one
                                                            bit is set, the VPEAK and IPEAK registers can hold values from two different phases, that is,
                                                            the voltage and current peak are independently processed (see the Peak Current Detection section).
5 to 7				PKIRQSEL			7					These bits select the phases used for the peak interrupt detection.
                                                            Setting Bit 5 switches on the monitoring of the absolute current and voltage waveform to Phase A.
                                                            Similarly, setting Bit 6 turns on the waveform detection for Phase B, and Bit 7 for Phase C.
                                                            Note that more than one bit can be set for detection on multiple phases.
                                                            If the absolute values of the voltage or current waveform samples in the selected phases exceeds
                                                            the preset level specified in the VPINTLVL or IPINTLVL registers the corresponding bit(s) in the
                                                            STATUS registers are set (see the Peak Current Detection section).

*/

void setMMode(uint8_t m)
{
    write8(MMODE, m);
}
uint8_t getMMode(void)
{
    return read8(MMODE);
}

/** === setWavMode / getWavMode ===
WAVEFORM MODE REGISTER (0x15)
The waveform sampling mode of the ADE7758 is defined by writing to the WAVMODE register.
Table 20 summarizes the functionality of each bit in the WAVMODE register.

Bit Location		Bit Mnemonic		Default Value 		Description
0 to 1				PHSEL				0					These bits are used to select the phase of the waveform sample.
                                                            PHSEL[1:0]				Source
                                                            0	0					Phase A
                                                            0	1					Phase B
                                                            1	0					Phase C
                                                            1	1					Reserved
2 to 4				WAVSEL				0					These bits are used to select the type of waveform.
                                                            WAVSEL[2:0]				Source
                                                            0	0	0				Current
                                                            0	0	1				Voltage
                                                            0	1	0				Active Power Multiplier Output
                                                            0	1	1				Reactive Power Multiplier Output
                                                            1	0	0				VA Multiplier Output
                                                            -Others-				Reserved
5 to 6				DTRT				0					These bits are used to select the data rate.
                                                            DTRT[1:0]				Update Rate
                                                            0	0					26.04 kSPS (CLKIN/3/128)
                                                            0	1					13.02 kSPS (CLKIN/3/256)
                                                            1	0					6.51 kSPS (CLKIN/3/512)
                                                            1	1					3.25 kSPS (CLKIN/3/1024)
7					VACF				0					Setting this bit to Logic 1 switches the VARCF output pin to an output
                                                            frequency that is proportional to the total apparent power (VA).
                                                            In the default state, Logic 0, the VARCF pin outputs a frequency proportional
                                                            to the total reactive power (VAR).
*/

void setWavMode(uint8_t m)
{
    write8(WAVMODE, m);
}
uint8_t getWavMode()
{
    return read8(WAVMODE);
}

/** === setCompMode / getCompMode ===

COMPUTATIONAL MODE REGISTER (0x16)
The computational method of the ADE7758 is defined by writing to the COMPMODE register.

Bit Location	Bit Mnemonic	Default Value		Description
0 to 1			CONSEL			0					These bits are used to select the input to the energy accumulation registers.
                                                    CONSEL[1:0] = 11 is reserved. IA, IB, and IC are IA, IB, and IC phase shifted by �90�, respectively.
                                                    Registers		CONSEL[1, 0] = 00		CONSEL[1, 0] = 01			CONSEL[1, 0] = 10
                                                    AWATTHR			VA � IA					VA � (IA � IB)				VA � (IA�IB)
                                                    BWATTHR			VB � IB					0							0
                                                    CWATTHR			VC � IC					VC � (IC � IB)				VC � IC

                                                    AVARHR			VA � IA					VA � (IA � IB)				VA � (IA�IB)
                                                    BVARHR			VB � IB					0							0
                                                    CVARHR			VC � IC					VC � (IC � IB)				VC � IC

                                                    AVAHR			VARMS � IARMS			VARMS � IARMS				VARMS � ARMS
                                                    BVAHR			VBRMS � IBRMS			(VARMS + VCRMS)/2 � IBRMS	VARMS � IBRMS
                                                    CVAHR			VCRMS � ICRMS			VCRMS � ICRMS				VCRMS � ICRMS

2 to 4			TERMSEL			7					These bits are used to select the phases to be included in the APCF and VARCF pulse outputs.
                                                    Setting Bit 2 selects Phase A (the inputs to AWATTHR and AVARHR registers) to be included.
                                                    Bit 3 and Bit 4 are for Phase B and Phase C, respectively.
                                                    Setting all three bits enables the sum of all three phases to be included in the frequency outputs
                                                    (see the Active Power Frequency Output and the Reactive Power Frequency Output sections).

5				ABS				0					Setting this bit places the APCF output pin in absolute only mode.
                                                    Namely, the APCF output frequency is proportional to the sum of the absolute values of the watt-hour
                                                    accumulation registers (AWATTHR, BWATTHR, and CWATTHR).
                                                    Note that this bit only affects the APCF pin and has no effect on the content of the corresponding
                                                    registers.

6				SAVAR			0					Setting this bit places the VARCF output pin in the signed adjusted mode.
                                                    Namely, the VARCF output frequency is proportional to the sign-adjusted sum of the VAR-hour accumulation
                                                    registers (AVARHR, BVARHR, and CVARHR).
                                                    The sign of the VAR is determined from the sign of the watt calculation from the corresponding phase,
                                                    that is, the sign of the VAR is flipped if the sign of the watt is negative, and if the watt is positive,
                                                    there is no change to the sign of the VAR.
                                                    Note that this bit only affects the VARCF pin and has no effect on the content of the corresponding
                                                    registers.

7				NOLOAD			0					Setting this bit activates the no-load threshold in the ADE7758.
*/

void setCompMode(uint8_t m)
{
    write8(COMPMODE, m);
}
uint8_t getCompMode(void)
{
    return read8(COMPMODE);
}

/** === setLcycMode / getLcycMode ===

LINE CYCLE ACCUMULATION MODE REGISTER (0x17)
The functionalities involved the line-cycle accumulation mode in the ADE7758 are defined by writing to the LCYCMODE register.

Bit Location	Bit Mnemonic	Default Value		Description

0				LWATT			0					Setting this bit places the watt-hour accumulation registers
                                                    (AWATTHR, BWATTHR, and CWATTHR registers) into line-cycle accumulation mode.
1				LVAR			0					Setting this bit places the VAR-hour accumulation registers (AVARHR, BVARHR, and CVARHR registers)
                                                    into line-cycle accumulation mode.
2				LVA				0					Setting this bit places the VA-hour accumulation registers (AVAHR, BVAHR, and CVAHR registers)
                                                    into line-cycle accumulation mode.
3 to 5			ZXSEL			7					These bits select the phases used for counting the number of zero crossings in the line-cycle
                                                    accumulation mode. Bit 3, Bit 4, and Bit 5 select Phase A, Phase B, and Phase C, respectively.
                                                    More than one phase can be selected for the zero-crossing detection,
                                                    and the accumulation time is shortened accordingly.
6				RSTREAD			1					Setting this bit enables the read-with-reset for all the WATTHR, VARHR, and VAHR registers for all three
                                                    phases, that is, a read to those registers resets the registers to 0 after the content of the registers
                                                    have been read. This bit should be set to Logic 0 when the LWATT, LVAR, or LVA bits are set to Logic 1.
7				FREQSEL			0					Setting this bit causes the FREQ (0x10) register to display the period, instead of the frequency of the
                                                    line input.
*/

void setLcycMode(uint8_t m)
{
    write8(LCYCMODE, m);
}
uint8_t getLcycMode(void)
{
    return read8(LCYCMODE);
}

/** === gainSetup ===
 GAIN REGISTER (0x23)
The PGA configuration of the ADE7758 is defined by writing to the GAIN register.
Table 18 summarizes the functionality of each bit in the GAIN register.

Bit Location		Bit Mnemonic		Default Value		Description
0 to 1				PGA1				0					Current GAIN
                                                            PGA1[1:0]			Description
                                                            0	0				x1
                                                            0	1				x2
                                                            1	0				x4
                                                            1	1				RESERVED
2					----				RESERVED			Reserved.
3 to 4				SCALE				0					Current input full-scale select
                                                            SCALE[1:0]			Description
                                                            0	0				0.5v
                                                            0	1				0.25v
                                                            1	0				0.125v
                                                            1	1				Reserved
5 to 6				PGA2				0					Voltage GAIN
                                                            PGA2[1:0]			Description
                                                            0	0				x1
                                                            0	1				x2
                                                            1	0				x4
                                                            1	1				RESERVED
7					INTEGRATOR			0					This bit enables the integrator on the current chanel when set.
*/

void gainSetup(uint8_t integrator, uint8_t scale, uint8_t PGA2, uint8_t PGA1)
{
    char pgas = (integrator << 7) | (PGA2 << 5) | (scale << 3) | (PGA1);
    write8(GAIN, pgas); // write GAIN register, format is |3 bits PGA2 gain|2 bits full scale|3 bits PGA1 gain
}

void setupDivs(uint8_t Watt_div, uint8_t VAR_div, uint8_t VA_div)
{
    write8(WDIV, Watt_div);
    write8(VARDIV, VAR_div);
    write8(VADIV, VA_div);
}

/** === getMaskInterrupts / setMaskInterrupts
MASK REGISTER (0x18)
When an interrupt event occurs in the ADE7758, the IRQ logic output goes active low if the mask bit for this event is Logic 1 in the MASK register.
The IRQ logic output is reset to its default collector open state when the RSTATUS register is read.
describes the function of each bit in the interrupt mask register.

Bit Location	Interrupt Flag		Default Value		Description
0				AEHF				0					Enables an interrupt when there is a change in Bit 14 of any one of the three WATTHR registers,
                                                        that is, the WATTHR register is half full.
1				REHF				0					Enables an interrupt when there is a change in Bit 14 of any one of the three VARHR registers,
                                                        that is, the VARHR register is half full.
2				VAEHF				0					Enables an interrupt when there is a 0 to 1 transition in the MSB of any one of the three VAHR
                                                        registers, that is, the VAHR register is half full.
3				SAGA				0					Enables an interrupt when there is a SAG on the line voltage of the Phase A.
4				SAGB				0					Enables an interrupt when there is a SAG on the line voltage of the Phase B.
5				SAGC				0					Enables an interrupt when there is a SAG on the line voltage of the Phase C.
6				ZXTOA				0					Enables an interrupt when there is a zero-crossing timeout detection on Phase A.
7				ZXTOB				0					Enables an interrupt when there is a zero-crossing timeout detection on Phase B.
8				ZXTOC				0					Enables an interrupt when there is a zero-crossing timeout detection on Phase C.
9				ZXA					0					Enables an interrupt when there is a zero crossing in the voltage channel of Phase A
                                                        (see the Zero-Crossing Detection section).
10				ZXB					0					Enables an interrupt when there is a zero crossing in the voltage channel of Phase B
                                                        (see the Zero-Crossing Detection section).
11				ZXC					0					Enables an interrupt when there is a zero crossing in the voltage channel of Phase C
                                                        (see the Zero-Crossing Detection section).
12				LENERGY				0					Enables an interrupt when the energy accumulations over LINECYC are finished.
13				RESERVED			0					Reserved.
14				PKV					0					Enables an interrupt when the voltage input selected in the MMODE register is above
                                                        the value in the VPINTLVL register.
15				PKI					0					Enables an interrupt when the current input selected in the MMODE register is above the
                                                        value in the IPINTLVL register.
16				WFSM				0					Enables an interrupt when data is present in the WAVEMODE register.
17				REVPAP				0					Enables an interrupt when there is a sign change in the watt calculation among any one of
                                                        the phases specified by the TERMSEL bits in the COMPMODE register.
18				REVPRP				0					Enables an interrupt when there is a sign change in the VAR calculation among any one of
                                                        the phases specified by the TERMSEL bits in the COMPMODE register.
19				SEQERR				0					Enables an interrupt when the zero crossing from Phase A is followed not by the zero crossing
                                                        of Phase C but with that of Phase B.
*/
uint32_t getMaskInterrupts(void)
{
    return read24(MASK);
}
void setMaskInterrupts(uint32_t m)
{
    write24(MASK, m);
}
/**	getStatus / resetStatus
INTERRUPT STATUS REGISTER (0x19)/RESET INTERRUPT STATUS REGISTER (0x1A)
The interrupt status register is used to determine the source of an interrupt event.
When an interrupt event occurs in the ADE7758, the corresponding flag in the interrupt status register is set.
The IRQ pin goes active low if the corresponding bit in the interrupt mask register is set.
When the MCU services the interrupt, it must first carry out a read from the interrupt status register to determine the source of the interrupt.
All the interrupts in the interrupt status register stay at their logic high state after an event occurs.
The state of the interrupt bit in the interrupt status register is reset to its default value once the reset interrupt status register is read.

Bit Location	Interrupt Flag		Default Value		Event Description
0				AEHF				0					Indicates that an interrupt was caused by a change in Bit 14 among any one of the three
                                                        WATTHR registers, that is, the WATTHR register is half full.
1				REHF				0					Indicates that an interrupt was caused by a change in Bit 14 among any one of the three
                                                        VARHR registers, that is, the VARHR register is half full.
2				VAEHF				0					Indicates that an interrupt was caused by a 0 to 1 transition in Bit 15 among any one of the three
                                                        VAHR registers, that is, the VAHR register is half full.
3				SAGA				0					Indicates that an interrupt was caused by a SAG on the line voltage of the Phase A.
4				SAGB				0					Indicates that an interrupt was caused by a SAG on the line voltage of the Phase B.
5				SAGC				0					Indicates that an interrupt was caused by a SAG on the line voltage of the Phase C.
6				ZXTOA				0					Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase A.
7				ZXTOB				0					Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase B.
8				ZXTOC				0					Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase C.
9				ZXA					0					Indicates a detection of a rising edge zero crossing in the voltage channel of Phase A.
10				ZXB					0					Indicates a detection of a rising edge zero crossing in the voltage channel of Phase B.
11				ZXC					0					Indicates a detection of a rising edge zero crossing in the voltage channel of Phase C.
12				LENERGY				0					In line energy accumulation, indicates the end of an integration over an integer number of
                                                        half- line cycles (LINECYC). See the Calibration section.
13				RESET				1					Indicates that the 5 V power supply is below 4 V. Enables a software reset of the ADE7758
                                                        and sets the registers back to their default values. This bit in the STATUS or RSTATUS register
                                                        is logic high for only one clock cycle after a reset event.
14				PKV					0					Indicates that an interrupt was caused when the selected voltage input is above the value in the
                                                        VPINTLVL register.
15				PKI					0					Indicates that an interrupt was caused when the selected current input is above the value
                                                        in the IPINTLVL register.
16				WFSM				0					Indicates that new data is present in the waveform register.
17				REVPAP				0					Indicates that an interrupt was caused by a sign change in the watt calculation among any
                                                        one of the phases specified by the TERMSEL bits in the COMPMODE register.
18				REVPRP				0					Indicates that an interrupt was caused by a sign change in the VAR calculation among any
                                                        one of the phases specified by the TERMSEL bits in the COMPMODE register.
19				SEQERR				0					Indicates that an interrupt was caused by a zero crossing from Phase A
                                                        followed not by the zero crossing of Phase C but by that of Phase B.
*/

uint32_t getStatus(void)
{
    return read24(STATUS);
}

uint32_t resetStatus(void)
{
    return read24(RSTATUS);
}

/** === getAIRMS ===
 * Phase A Current RMS Value
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with the data (24 bits unsigned).
 */
int32_t getAIRMS(void)
{
    long lastupdate = 0;
    resetStatus();               // Clear all interrupts
    while (!(getStatus() & ZXA)) // wait Zero-Crossing
    {                            // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // breack;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    return read24(AIRMS);
}

/** === getBIRMS ===
 * Phase B Current RMS Value
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with the data (24 bits unsigned).
 */

int32_t getBIRMS(void)
{
    long lastupdate = 0;
    resetStatus();               // Clear all interrupts
    while (!(getStatus() & ZXB)) // wait Zero-Crossing
    {                            // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // breack;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    return read24(BIRMS);
}
/** === getCIRMS ===
 * Phase C Current RMS Value
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with the data (24 bits unsigned).
 */
int32_t getCIRMS(void)
{
    long lastupdate = 0;
    resetStatus();               // Clear all interrupts
    while (!(getStatus() & ZXC)) // wait Zero-Crossing
    {                            // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // breack;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    return read24(CIRMS);
}

/** === getAVRMS ===
 * Phase A RMS Value (Voltage Channel).
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with the data (24 bits unsigned).
 */

int32_t getAVRMS(void)
{
    long lastupdate = 0;
    resetStatus();               // Clear all interrupts
    while (!(getStatus() & ZXA)) // wait Zero-Crossing
    {                            // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // breack;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    return read24(AVRMS);
}

/** === getBVRMS ===
 * Phase B RMS Value (Voltage Channel).
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with the data (24 bits unsigned).
 */

int32_t getBVRMS(void)
{
    long lastupdate = 0;
    resetStatus();               // Clear all interrupts
    while (!(getStatus() & ZXB)) // wait Zero-Crossing
    {                            // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // breack;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    return read24(BVRMS);
}

/** === getCVRMS ===
 * Phase C RMS Value (Voltage Channel).
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with the data (24 bits unsigned).
 */

int32_t getCVRMS(void)
{
    long lastupdate = 0;
    resetStatus();               // Clear all interrupts
    while (!(getStatus() & ZXC)) // wait Zero-Crossing
    {                            // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // break;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    return read24(CVRMS);
}

/** === vrms ===
 * Returns the mean of last 20 readings of RMS voltage. Also supress first reading to avoid
 * corrupted data.
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with RMS voltage value
 */

uint32_t avrms(void)
{
    uint8_t i = 0;
    uint32_t v = 0;
    if (getAVRMS())
    { // Ignore first reading to avoid garbage
        for (i = 0; i < 10; ++i)
        {
            v += getAVRMS();
        }
        return v / 10;
    }
    else
    {
        return 0;
    }
}
uint32_t bvrms()
{
    uint8_t i = 0;
    uint32_t v = 0;
    if (getBVRMS())
    { // Ignore first reading to avoid garbage
        for (i = 0; i < 10; ++i)
        {
            v += getBVRMS();
        }
        return v / 10;
    }
    else
    {
        return 0;
    }
}
uint32_t cvrms()
{
    uint8_t i = 0;
    uint32_t v = 0;
    if (getCVRMS())
    { // Ignore first reading to avoid garbage
        for (i = 0; i < 10; ++i)
        {
            v += getCVRMS();
        }
        return v / 10;
    }
    else
    {
        return 0;
    }
}

/** === irms ===
 * Returns the mean of last 20 readings of RMS current. Also supress first reading to avoid
 * corrupted data.
 * To minimize noise, synchronize the reading of the rms register with the zero crossing
 * of the voltage input and take the average of a number of readings.
 * @param none
 * @return long with RMS current value in hundreds of [mA], ie. 6709=67[mA]
 */

uint32_t airms()
{
    char n = 0;
    long i = 0;
    if (getAIRMS())
    { // Ignore first reading to avoid garbage
        for (n = 0; n < 10; ++n)
        {
            i += getAIRMS();
        }
        return i / 10;
    }
    else
    {
        return 0;
    }
}
uint32_t birms()
{
    char n = 0;
    long i = 0;
    if (getBIRMS())
    { // Ignore first reading to avoid garbage
        for (n = 0; n < 10; ++n)
        {
            i += getBIRMS();
        }
        return i / 10;
    }
    else
    {
        return 0;
    }
}
int32_t cirms()
{
    char n = 0;
    int32_t i = 0;
    if (getCIRMS())
    { // Ignore first reading to avoid garbage
        for (n = 0; n < 10; ++n)
        {
            i += getCIRMS();
        }
        return i / 10;
    }
    else
    {
        return 0;
    }
}

/** === getFreq ===
 * Period of the Phase selected in MMode.
 * @param none
 * @return int with the data (12 bits unsigned).
 */

int32_t getFreq(void)
{
    return read16(FREQ);
}

/** setLineCyc: sets the number of cycles required for the accumulations.
 **/

void setLineCyc(uint32_t d)
{
    write16(LINECYC, d);
}

/** === setCurrentOffset / getCurrentOffset ===
 * @param none
 * @return int with the data (12 bits 2-complement signed).
 */

int32_t getACurrentOffset()
{
    int32_t data;
    data = ((int32_t)(read16(AIRMSOS) << 20) >> 20);
    return data;
}
int32_t getBCurrentOffset()
{
    int32_t data;
    data = ((int32_t)(read16(BIRMSOS) << 20) >> 20);
    return data;
}
int32_t getCCurrentOffset()
{
    int32_t data;
    data = ((int32_t)(read16(CIRMSOS) << 20) >> 20);
    return data;
}
void setACurrentOffset(int32_t o)
{
    write16(AIRMSOS, o);
}
void setBCurrentOffset(int32_t o)
{
    write16(BIRMSOS, o);
}
void setCCurrentOffset(int32_t o)
{
    write16(CIRMSOS, o);
}

void setAWattOffset(int32_t o)
{
    write16(AWATTOS, o);
}
void setBWattOffset(int32_t o)
{
    write16(BWATTOS, o);
}
void setCWattOffset(int32_t o)
{
    write16(CWATTOS, o);
}

void setAVAROffset(int32_t o)
{
    write16(AVAROS, o);
}
void setBVAROffset(int32_t o)
{
    write16(BVAROS, o);
}
void setCVAROffset(int32_t o)
{
    write16(CVAROS, o);
}
/** === setVoltageOffset / getVoltageOffset ===
 * @param none
 * @return int with the data (12 bits 2-complement signed).
 */

int32_t getAVoltageOffset()
{
    int32_t data;
    data = ((int32_t)(read16(AVRMSOS) << 20) >> 20);
    return data;
}
int32_t getBVoltageOffset()
{
    int32_t data;
    data = ((int32_t)(read16(BVRMSOS) << 20) >> 20);
    return data;
}
int32_t getCVoltageOffset()
{
    int32_t data;
    data = ((int32_t)(read16(CVRMSOS) << 20) >> 20);
    return data;
}
void setAVoltageOffset(int32_t o)
{
    write16(AVRMSOS, o);
}
void setBVoltageOffset(int32_t o)
{
    write16(BVRMSOS, o);
}
void setCVoltageOffset(int32_t o)
{
    write16(CVRMSOS, o);
}

/** === setZeroCrossingTimeout / getZeroCrossingTimeout ===
 * Zero-Crossing Timeout. If no zero crossings are detected
 * on Channel 2 within a time period specified by this 12-bit register,
 * the interrupt request line (IRQ) is activated
 * @param none
 * @return int with the data (12 bits unsigned).
 */

void setZeroCrossingTimeout(int32_t d)
{
    write16(ZXTOUT, d);
}
int32_t getZeroCrossingTimeout()
{
    return read16(ZXTOUT);
}

/** === setPotLine(Phase) ===
Set the conditions for Line accumulation in the selected phase.
Then wait for the interruption and return the phase number when it occurs.
If it does not happen for more than 1.5 seconds, it returns a 0.
**/

uint8_t setPotLine(uint8_t Phase, uint32_t Cycles)
{
    long lastupdate = 0;
    char m = 0;
    switch (Phase)
    {
    case PHASE_A:
        m = (LWATT | LVAR | LVA | ZXSEL_A);
        break;
    case PHASE_B:
        m = (LWATT | LVAR | LVA | ZXSEL_B);
        break;
    case PHASE_C:
        m = (LWATT | LVAR | LVA | ZXSEL_C);
        break;
    }
    setLcycMode(0);
    setLcycMode(m);
    resetStatus();
    setLineCyc(Cycles);
    lastupdate = 0;
    while (!(getStatus() & LENERGY)) // wait to terminar de acumular
    {                                // wait for the selected interrupt to occur
        lastupdate++;
        if (lastupdate > 20)
        {
            return 0; // breack;
        }
        vTaskDelay(pdMS_TO_TICKS(20));
    }

    return Phase;
}

/** === getWatt(phase) / getVar(phase) / getVa(phase) ===
Devuelve los valores de la potencia requerida de la fase seleccionada.
Utilizar antes setPotLine(phase) para generar los valores.
**/

int32_t getWatt(uint8_t Phase)
{
    int32_t temp = 0;
    switch (Phase)
    {
    case PHASE_A:
        temp = read16(AWATTHR);
        break;
    case PHASE_B:
        temp = read16(BWATTHR);
        break;
    case PHASE_C:
        temp = read16(CWATTHR);
        break;
    }
    return temp;
}
int32_t getVar(uint8_t Phase)
{
    int32_t temp = 0;
    switch (Phase)
    {
    case PHASE_A:
        temp = read16(AVARHR);
        break;
    case PHASE_B:
        temp = read16(BVARHR);
        break;
    case PHASE_C:
        temp = read16(CVARHR);
        break;
    }
    return temp;
}
int32_t getVa(uint8_t Phase)
{
    int32_t temp = 0;
    switch (Phase)
    {
    case PHASE_A:
        temp = read16(AVAHR);
        break;
    case PHASE_B:
        temp = read16(BVAHR);
        break;
    case PHASE_C:
        temp = read16(CVAHR);
        break;
    }
    return temp;
}
void setAPCFDEN(int32_t d)
{
    write16(APCFDEN, d);
}
int32_t getAPCFDEN(void)
{
    int32_t data;
    data = ((int32_t)(read16(APCFDEN) << 20) >> 20);
    return data;
}
void setAPCFNUM(int32_t d)
{
    write16(APCFNUM, d);
}
int32_t getAPCFNUM(void)
{
    int32_t data;
    data = ((int32_t)(read16(APCFNUM) << 20) >> 20);
    return data;
}
void setVARCFNUM(int32_t d)
{
    write16(VARCFNUM, d);
}
int32_t getVARCFNUM(void)
{
    int32_t data;
    data = ((int32_t)(read16(VARCFNUM) << 20) >> 20);
    return data;
}
void setVARCFDEN(int32_t d)
{
    write16(VARCFDEN, d);
}
int32_t getVARCFDEN(void)
{
    int32_t data;
    data = ((int32_t)(read16(VARCFDEN) << 20) >> 20);
    return data;
}
void setAWG(int32_t d)
{
    write16(AWG, d);
}
int32_t getAWG()
{
    return ((read16(AWG)) << 4) >> 4;
}
void setBWG(int32_t d)
{
    write16(BWG, d);
}
void setCWG(int32_t d)
{
    write16(CWG, d);
}
void setAVARG(int32_t d)
{
    write16(AVARG, d);
}
int32_t getAVARG()
{
    return ((read16(AVARG)) << 4) >> 4;
}
void setBVARG(int32_t d)
{
    write16(BVARG, d);
}
int32_t getBVARG()
{
    return ((read16(BVARG)) << 4) >> 4;
}
void setCVARG(int32_t d)
{
    write16(CVARG, d);
}
int32_t getCVARG()
{
    return ((read16(CVARG)) << 4) >> 4;
}
void setAVAG(int32_t d)
{
    write16(AVAG, d);
}
void setBVAG(int32_t d)
{
    write16(BVAG, d);
}
void setCVAG(int32_t d)
{
    write16(CVAG, d);
}