#ifndef BSP_DEV_METER_EM_VANGO_V93XX_H_
#define BSP_DEV_METER_EM_VANGO_V93XX_H_

/*
 * em_vango_vp3xx.h
 *
 *  Created on: 23/07/2021
 *      Author: alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
  ------------------------------------------------------------------------
      VangoTech Energy-meter AFE V93xx chips SPI API
      @sa http://www.vangotech.com/int/product.php?areas=0&bigs=10&smalls=15&id=36
 */



#include "hal/ssp_hal.h"
#include "sys/pt.h"
#include "OsTime.h"



#ifndef V93XX_API_SYNC

/// @brief Sync API provides blocking rd/wr operations.
///         v93xx_reset - still async
#define V93XX_API_SYNC 1

#endif

/////////////////////////////////////////////////////////////////////////////////

typedef uint8_t     V93XXAdr;

/// @brief строки V93XXAdr заканчиваются V93XX_END
typedef V93XXAdr*   V93XXAdrs;
typedef const V93XXAdr*   CV93XXAdrs;


#if V93XX_API_SYNC == 0

typedef PTResult V93XXResult;

#else

typedef DevResult V93XXResult;

#endif




enum    V93XXIOStatus {
    //< has power off, or in reset
    V93XXIO_OFFLINE,
    //< startup after poweron or reset
    V93XXIO_START,
    //< powered on, but not SPI ready, UART activates by default
    V93XXIO_ONLINE, V93XXIO_UART = V93XXIO_ONLINE,
    //< have negotiated for SPI comm
    V93XXIO_SPI,
};
typedef enum    V93XXIOStatus   V93XXIOStatus;


enum V93XXIOOperation {
    V93XXIO_NONE,
    V93XXIO_RESET,
    V93XXIO_RD,
    V93XXIO_WR,

    V93XXIO_WRVER,
    V93XXIO_VER_WR0,
    V93XXIO_VER_WR,
};

union EMDev_V93XXSpiStats{

    struct {
    unsigned    rd;
    unsigned    wr;
    unsigned    rd_retry;
    unsigned    wr_retry;
    unsigned    rd_fails;
    unsigned    wr_fails;
    };

    struct {
        unsigned    io[2];
        union {
            struct {
                unsigned    retry[2];
                unsigned    fails[2];
            };
            unsigned    err[4];
        };
    };

    unsigned    fields[6];
};
typedef union EMDev_V93XXSpiStats EMDev_V93XXSpiStats;



struct EMDev_V93XXSpi {
    SSP_IODevice    ssp;
    V93XXIOStatus   io_state;

    // read from SoC after SPI negotiated
    uint32_t        hw_ver;

    // active io task
    struct {
        struct pt   pt;

#ifndef V93XX_API_SYNC
        // timeout counter by [50us] tick
        int             to50us;
#else
        os_hrtime_t     last50us;
#endif

        // сигналер сообщения нужен для извещения о завершении транзакции.
        // TODO: жестко связано на contiki - запмнинается нитка запустившая сообщение
        // TODO: стоит это тоже в сообщение переложить?
        void*               msg_signal;

        enum V93XXIOOperation optask;

        //< adresses string
        CV93XXAdrs  addr;
        //< points to io read/write data
        uint32_t*   data;

        // @value < 0 - operation aborted
        int8_t      retry;      // generic operation retry

        uint8_t     retry_rd;
        uint8_t     retry_wr;

        PTResult    ok;
        SSPResult   sspok;

        union   {
            uint64_t    w8;
            uint8_t     raw[8];
        }           cmdcache;

        // для операции чтения выделю свой msg - чтобы дать ядру микросхемы время на доступ к читаемым данным
        //  надо добавить паузу между командой и телом принимаемого пакета. делаю это явно указав заголовок и
        //  тело в сообщении
        SSPMessage      rd_msg;

    } iotask;

    EMDev_V93XXSpiStats stats;

    // timeout used by reset
    os_timeout_t    to;
};
typedef struct EMDev_V93XXSpi EMDev_V93XXSpi;



///////////////////////////////////////////////////////////////////////////////////
///     application BSP support handles

// application should provide this handles
void v93xx_reset_on(EMDev_V93XXSpi* x);
void v93xx_reset_off(EMDev_V93XXSpi* x);

#if V93XX_API_SYNC == 0

// this invokes from ISR, for timeout 50us after SPI operation
void v93xx_start_timeout_50us(EMDev_V93XXSpi* x);

//< application timeout ISR for SPI io timeout should invoke this handle
void v93xx_on_timeout(EMDev_V93XXSpi* x);

bool v93xx_is_timeout(EMDev_V93XXSpi* x);

/// @brief singnaler on V93XXSpi request finished
/// @nore weak, app should override it
void v93xx_finished(EMDev_V93XXSpi* this);

#endif

//< app provides this notify handle, that driver infokes when Async-dev operation finished,
//      and v93xx_wait() ready
void on_v93xx_notify(EMDev_V93XXSpi* this);

///////////////////////////////////////////////////////////////////////////////////

void v93xx_init(EMDev_V93XXSpi* x);
void v93xx_connect(EMDev_V93XXSpi* x, SSP_IOPort*    _port);


// FIX: после включения питания надо дать ванге 200мс перед подачей ресета чтобы прочухаться.
//  иначе она сходит с ума.
enum { V93XX_POWERUP_TIMEOUT_MS = 200, };

///////////////////////////////////////////////////////////////////////////////////

//< ожидание завершения текущей Async-операции для доступа к девайсу
PTResult v93xx_wait(EMDev_V93XXSpi* x);

//< обрыв выполнения текущей Async-операции
void v93xx_abort(EMDev_V93XXSpi* x);

//-------------------------------------------------------------------------------------------------
//< последовательность сброса и активация SPI интерфейса
//  перед подачей ресета ждет V93XX_RESET_TIMEOUT_MS
//  @note Async operation.
PTResult v93xx_reset(EMDev_V93XXSpi* x);


// назначить текущую нитку для сигналирования завершения таранзакции
void v93xx_signal_to_me(EMDev_V93XXSpi* x);
void v93xx_signal_disable(EMDev_V93XXSpi* x);


V93XXResult v93xx_rd(EMDev_V93XXSpi* x, uint32_t*   data, CV93XXAdrs seq);
V93XXResult v93xx_rd1(EMDev_V93XXSpi* x, uint32_t*   data, V93XXAdr adr);

/// @brief writes data to registers, verifyed writen content
V93XXResult v93xx_wr(EMDev_V93XXSpi* x, CV93XXAdrs seq, const uint32_t* data);
V93XXResult v93xx_wr1(EMDev_V93XXSpi* x, V93XXAdr adr, uint32_t data);

/// @brief plain write to device, without wrie verify
V93XXResult v93xx_send(EMDev_V93XXSpi* x, CV93XXAdrs seq, const uint32_t* data);
V93XXResult v93xx_send1(EMDev_V93XXSpi* x, V93XXAdr adr, uint32_t data);


/// @return mask of verifyable on write bits of register id
uint32_t    v93xx_reg_mask_ver(V93XXAdr id);

/// @brief ищет x в seq, возвращает индекс с головы строки
/// @return -1 - ненайдено
int v93xx_addr_idx(V93XXAdr x, CV93XXAdrs seq);


//////////////////////////////////////////////////////////////////////////////////////////////////////////////

enum V93XXAddrID{
    V93XX_ANA_CTRL0     = 0,
    V93XX_ANA_CTRL1     = 1,

    V93XX_DSP_CTRL0     = 2,
    V93XX_DSP_CTRL1     = 3,
    V93XX_DSP_CTRL2     = 4,
    V93XX_DSP_CTRL3     = 5,
    V93XX_DSP_CTRL4     = 6,
    V93XX_DSP_CTRL5     = 7,

    // Power
    V93XX_DSP_DAT_PA     = 0x08,
    V93XX_DSP_DAT_QA     = 0x09,
    V93XX_DSP_DAT_SA     = 0x0A,
    V93XX_DSP_DAT_PB     = 0x0B,
    V93XX_DSP_DAT_QB     = 0x0C,
    V93XX_DSP_DAT_SB     = 0x0D,

    // Power Average
    V93XX_DSP_DAT_PA1    = 0x13,
    V93XX_DSP_DAT_QA1    = 0x14,
    V93XX_DSP_DAT_SA1    = 0x15,
    V93XX_DSP_DAT_PB1    = 0x16,
    V93XX_DSP_DAT_QB1    = 0x17,
    V93XX_DSP_DAT_SB1    = 0x18,

    // RMS
    // instantaneous RMS
    V93XX_DSP_DAT_RMS0U     = 0x0E,
    V93XX_DSP_DAT_RMS0IA    = 0x0F,
    V93XX_DSP_DAT_RMS0IB    = 0x10,

    // average RMS
    V93XX_DSP_DAT_RMS1U     = 0x19,
    V93XX_DSP_DAT_RMS1IA    = 0x1A,
    V93XX_DSP_DAT_RMS1IB    = 0x1B,

    // average RMS for 10 or 12 cycles (chose by line frequency.)
    V93XX_DSP_DAT_RMSU_AVG  = 0x1E,
    V93XX_DSP_DAT_RMSIA_AVG = 0x1F,
    V93XX_DSP_DAT_RMSIB_AVG = 0x20,

    V93XX_DSP_DAT_FRQ       = 0x21,
    V93XX_DSP_DAT_DCU       = 0x22,     // U DC value
    V93XX_DSP_DAT_DCIA      = 0x23,     // IA DC value
    V93XX_DSP_DAT_DCIB      = 0x24,     // IB DC value

    V93XX_DSP_CFG_CALI_PA   = 0x25,
    V93XX_DSP_CFG_DC_PA     = 0x26,
    V93XX_DSP_CFG_CALI_QA   = 0x27,
    V93XX_DSP_CFG_DC_QA     = 0x28,
    V93XX_DSP_CFG_CALI_PB   = 0x29,
    V93XX_DSP_CFG_DC_PB     = 0x2A,
    V93XX_DSP_CFG_CALI_QB   = 0x2B,
    V93XX_DSP_CFG_DC_QB     = 0x2C,
    V93XX_DSP_CFG_CALI_RMSU = 0x2D,     // RMSU gain calibration
    V93XX_DSP_CFG_RMS_DCU   = 0x2E,     // RMSU DC offset
    V93XX_DSP_CFG_CALI_RMSIA= 0x2F,     // RMSU gain calibration
    V93XX_DSP_CFG_RMS_DCIA  = 0x30,     // RMSU DC offset
    V93XX_DSP_CFG_CALI_RMSIB= 0x31,     // RMSU gain calibration
    V93XX_DSP_CFG_RMS_DCIB  = 0x32,     // RMSU DC offset

    // Phase Error Calibration Register. The register needs to be configurationverification and self-checking
    V93XX_DSP_CFG_PHC       = 0x33,

    V93XX_DSP_CFG_DCU       = 0x34,     // U DC calibation
    V93XX_DSP_CFG_DCIA      = 0x35,     // U DC calibation
    V93XX_DSP_CFG_DCIB      = 0x36,     // U DC calibation

    V93XX_TEMP              = 0x68,



    V93XX_DSP_CFG_BPF   = 0x37,
    V93XX_DSP_SWELL_THL = 0x57,
    V93XX_DSP_SWELL_THH = 0x58,

    V93XX_DSP_DIP_THL   = 0x59,
    V93XX_DSP_DIP_THH   = 0x5A,

    //Times records of voltage swell, half wave as a unit. 24bit effective.
    // Clears:     When write in anyvalue, can clear zero the counter value.
    V93XX_DAT_SWELL_CNT = 0x6A,

    // Times records of voltage dip, half wave as a unit. 24bit effective.
    // Clears:     When write in any value, can clear zero the counter value.
    V93XX_DAT_DIP_CNT   = 0x6B,


    //Software reset register.
    //Writing 0x4572beaf into this address would be happen software reset once.
    V93XX_SYS_SFTRST    = 0x6C,


    V93XX_SYS_INTSTS    = 0x72,
    V93XX_SYS_INTEN     = 0x73,
    V93XX_SYS_STS       = 0x74,
    V93XX_SYS_MISC      = 0x75,

    V93XX_IOCFGX0       = 0x7D,
    V93XX_IOCFGX1       = 0x7E,

    V93XX_VERSION       = 0x7F,

    //< это последний элемент последовательности CV93XXAdrs
    V93XX_NONE          = 0xff,
    V93XX_END           = V93XX_NONE,
};
typedef enum V93XXAddrID V93XXAddrID;



enum V93xxANACTL0Fields{

    //< input short circuit
    V93XX_ANA_CTRL0_SHORT_I     = 1u<< 11,
    V93XX_ANA_CTRL0_SHORT_V     = 1u<< 10,

    V93XX_ANA_CTRL0_DEFAULT     = V93XX_ANA_CTRL0_SHORT_I | V93XX_ANA_CTRL0_SHORT_V,

    //< To select the analog input for Channel IB
    V93XX_ANA_CTRL0_SELIB       = 1u<< 13,

    V93XX_ANA_CTRL0_SELIB_IBDIFF= 0,    //< differential IB input
    V93XX_ANA_CTRL0_SELIB_TEMP  = V93XX_ANA_CTRL0_SELIB,    //< internal temperature sensor

    //< To enable the increase 6.5M RC oscillator frequency by 1.2X.
    //  It needs to set to 1 when the line frequency equals to 60Hz.
    //      0: X1; 1: X1.2
    V93XX_ANA_CTRL0_RCHX1P2     = 1u << 18,

    V93XX_ANA_CTRL0_RESERVED_Msk= 0xfffbd3ful,
};

enum V93xxANACTL1Fields{
    V93XX_ANA_CTRL1_DEFAULT = 0,

    V93XX_ANA_CTRL1_RESERVED_Msk= 0x00bf860ul,
};


#define V93XX_DSP_CTRL0_CFG_CHANNEL(x, no)   V93XX_DSP_CTRL0_CFG_CHANNELID_##x = (no), \
                V93XX_DSP_CTRL0_CFG_CHANNEL_##x = (V93XX_DSP_CTRL0_CFG_CHANNELID_##x << V93XX_DSP_CTRL0_CFG_CHANNEL_Pos)

enum V93xxDSPCTL0Fields{
    V93XX_DSP_CTRL0_DEFAULT = 0,

    //< Double refresh time for Instantaneous power value and RMS value
    V93XX_DSP_CTRL0_CURDAT_RATE = 0x80000000u,
    //<  refresh time for instantaneous power value is 20mS and instantaneous RMS value is 10mS.
    V93XX_DSP_CTRL0_CURDAT_20MS = 0,
    //<  refresh time for instantaneous power value is 40mS and instantaneous RMS value is 20mS.
    V93XX_DSP_CTRL0_CURDAT_40MS = 1u<< 31,

    //< Source comes from the register value of DSP_DAT_FRQ
    V93XX_DSP_CTRL0_FRQ_SEL_Pos = 28,
    V93XX_DSP_CTRL0_FRQ_SEL_Msk = 0x3u << V93XX_DSP_CTRL0_FRQ_SEL_Pos,

    V93XX_DSP_CTRL0_FRQ_SEL_0   = 0,
    V93XX_DSP_CTRL0_FRQ_SEL_1   = 1u << V93XX_DSP_CTRL0_FRQ_SEL_Pos,
    V93XX_DSP_CTRL0_FRQ_SEL_2   = 2u << V93XX_DSP_CTRL0_FRQ_SEL_Pos,
    V93XX_DSP_CTRL0_FRQ_SEL_3   = 3u << V93XX_DSP_CTRL0_FRQ_SEL_Pos,

    //<  accumulation value for line frequency test value  of 16 cycles (the default update time is 320ms
    V93XX_DSP_CTRL0_FRQ_SEL_16CYC   = V93XX_DSP_CTRL0_FRQ_SEL_0,
    //<  accumulation value for line frequency test value  of 1 cycle (the default update time is 20ms
    V93XX_DSP_CTRL0_FRQ_SEL_1CYC    = V93XX_DSP_CTRL0_FRQ_SEL_1,
    //<  accumulation value for line frequency test value  of 64 cycles (the default update time is 1280ms
    V93XX_DSP_CTRL0_FRQ_SEL_64CYC   = V93XX_DSP_CTRL0_FRQ_SEL_2,


    //< Source select for Apparent power calculation
    V93XX_DSP_CTRL0_S_MODE         = 1u << 24,
    V93XX_DSP_CTRL0_S_RMS           = 0,            //<
    V93XX_DSP_CTRL0_S_P             = V93XX_DSP_CTRL0_S_MODE,  //<  by power value

    V93XX_DSP_CTRL0_CFG_CHANNEL_Pos = 20,
    V93XX_DSP_CTRL0_CFG_CHANNEL_Msk = 0xfu << V93XX_DSP_CTRL0_CFG_CHANNEL_Pos,

    V93XX_DSP_CTRL0_CFG_CHANNEL(AFPBFP, 0),    //<  channel 1, fundamental active power A; channel 2, fundamental active power B
    V93XX_DSP_CTRL0_CFG_CHANNEL(AFPVF , 1),    //<  channel 1, fundamental active power A; channel 2, fundamental voltage RMS
    V93XX_DSP_CTRL0_CFG_CHANNEL(AFPAFI, 2),    //<  channel 1, fundamental active power A; channel 2, fundamental current RMS A
    V93XX_DSP_CTRL0_CFG_CHANNEL(AFPBFI, 3),    //<  channel 1, fundamental active power A; channel 2, fundamental current RMS B
    V93XX_DSP_CTRL0_CFG_CHANNEL(BFPVF , 4),    //<  channel 1, fundamental active power B; channel 2, fundamental voltage RMS
    V93XX_DSP_CTRL0_CFG_CHANNEL(BFPAFI, 5),    //<  channel 1, fundamental active power B; channel 2, fundamental current RMS A
    V93XX_DSP_CTRL0_CFG_CHANNEL(BFPBFI, 6),    //<  channel 1, fundamental active power B; channel 2, fundamental current RMS B
    V93XX_DSP_CTRL0_CFG_CHANNEL(VFAFI , 7),    //<  channel 1, fundamental voltage RMS; channel 2, fundamental current RMS A
    V93XX_DSP_CTRL0_CFG_CHANNEL(VFBFI , 8),    //<  channel 1, fundamental voltage RMS; channel 2, fundamental current RMS B
    V93XX_DSP_CTRL0_CFG_CHANNEL(AFIBFI, 9),    //<  channel 1, fundamental current RMS A; channel 2, fundamental current RMS B

                // 10~15: the same as configured 0


    //< To select mode for Reactive power B
    V93XX_DSP_CTRL0_QB_MODE         = 1u << 19,
    V93XX_DSP_CTRL0_QB_TOTAL        = 0,
    V93XX_DSP_CTRL0_QB_FUND         = V93XX_DSP_CTRL0_QB_MODE,  //<  fundamental wave

    //< To select mode for Reactive power A
    V93XX_DSP_CTRL0_QA_MODE         = 1u << 18,
    V93XX_DSP_CTRL0_QA_TOTAL        = 0,
    V93XX_DSP_CTRL0_QA_FUND         = V93XX_DSP_CTRL0_QA_MODE,  //<  fundamental wave


    V93XX_DSP_CTRL0_PQ_HPFSEL       = 1u << 17,     //< Calculate total power whether pass highpass filter
    V93XX_DSP_CTRL0_FUND_HPFSEL     = 1u << 16,     //< Calculate fundamental data whether pass highpass filter
    V93XX_DSP_CTRL0_RMSU_HPFSEL     = 1u << 15,     //< alculate voltage RMS data whether pass highpass filter
    V93XX_DSP_CTRL0_RMSIA_HPFSEL    = 1u << 14,     //< alculate current IA RMS data whether pass highpass filter
    V93XX_DSP_CTRL0_RMSIB_HPFSEL    = 1u << 13,     //< alculate current IB RMS data whether pass highpass filter

    V93XX_DSP_CTRL0_AVGRMS_RATE_Pos = 10,
    V93XX_DSP_CTRL0_AVGRMS_RATE_Msk = 3u << V93XX_DSP_CTRL0_AVGRMS_RATE_Pos,

    V93XX_DSP_CTRL0_AVGRMS_40MS     = 0,
    V93XX_DSP_CTRL0_AVGRMS_80MS     = 1u << V93XX_DSP_CTRL0_AVGRMS_RATE_Pos,
    V93XX_DSP_CTRL0_AVGRMS_320MS    = 2u << V93XX_DSP_CTRL0_AVGRMS_RATE_Pos,
    V93XX_DSP_CTRL0_AVGRMS_640MS    = 3u << V93XX_DSP_CTRL0_AVGRMS_RATE_Pos,


    V93XX_DSP_CTRL0_AVGPQ_RATE_Pos  = 8,
    V93XX_DSP_CTRL0_AVGPQ_RATE_Msk  = 3u << V93XX_DSP_CTRL0_AVGPQ_RATE_Pos,

    V93XX_DSP_CTRL0_AVGPQ_40MS      = 0,
    V93XX_DSP_CTRL0_AVGPQ_80MS      = 1u << V93XX_DSP_CTRL0_AVGPQ_RATE_Pos,
    V93XX_DSP_CTRL0_AVGPQ_320MS     = 2u << V93XX_DSP_CTRL0_AVGPQ_RATE_Pos,
    V93XX_DSP_CTRL0_AVGPQ_640MS     = 3u << V93XX_DSP_CTRL0_AVGPQ_RATE_Pos,


    V93XX_DSP_CTRL0_MODE_Pos    = 4,
    V93XX_DSP_CTRL0_MODE_Msk    = 0xfu << V93XX_DSP_CTRL0_MODE_Pos,

    V93XX_DSP_CTRL0_MODE0       = 0,    //< 128 sampling points per cycle by DSP at 6.5536MHz system clock
    V93XX_DSP_CTRL0_MODE1       = 1,    //<  64 sampling points per cycle by DSP at 6.5536MHz system clock
    V93XX_DSP_CTRL0_MODE2       = 2,    //<  32 sampling points per cycle by DSP at 6.5536MHz system clock
    V93XX_DSP_CTRL0_MODE6       = 6,    //<  64 sampling points per cycle by DSP at 3.2768MHz system cloc
    V93XX_DSP_CTRL0_MODE7       = 7,    //<  32 sampling points per cycle by DSP at 3.2768MHz system cloc

    // (supported only up to 2 channelsinstantaneous current RMS calculation.)
    V93XX_DSP_CTRL0_MODE8       = 8,    //<  32 sampling points per cycle by DSP at 819.2KHz system clock
    V93XX_DSP_CTRL0_MODE9       = 9,    //<  16 sampling points per cycle by DSP at 409.6KHz system clock


    V93XX_DSP_CTRL0_GRID_FRQ    = 0x8,
    V93XX_DSP_CTRL0_GRID_50HZ   = 0,
    V93XX_DSP_CTRL0_GRID_60HZ   = V93XX_DSP_CTRL0_GRID_FRQ,

    V93XX_DSP_CTRL0_ADCUEN      = 4,    // To enable the voltage channel (including ADC and DSP)
    V93XX_DSP_CTRL0_ADCIBEN     = 2,    // To enable the voltage channel (including ADC and DSP)
    V93XX_DSP_CTRL0_ADCIAEN     = 1,    // To enable the current channel A (including ADC and DSP)

    V93XX_DSP_CTRL0_RESERVED_Msk = 0x40000000ul,
};

enum V93xxDSPCTL1Fields{
    V93XX_DSP_CTRL1_DEFAULT = 0,

    V93XX_DSP_CTRL1_RESERVED_Msk = 0x7f000800ul,
};

enum V93xxDSPCTL2Fields{
    V93XX_DSP_CTRL2_DEFAULT = 0,
};

enum V93xxDSPCTL3Fields{
    V93XX_DSP_CTRL3_DEFAULT = 0,
};

enum V93xxDSPCTL4Fields{
    V93XX_DSP_CTRL4_DEFAULT = 0,

    V93XX_DSP_CTRL4_RESERVED_Msk = 0x0000fc08ul,
};

enum V93xxDSPCTL5Fields{
    V93XX_DSP_CTRL5_DEFAULT = 0,

    V93XX_DSP_CTRL5_WAVE_ADDR_CLR   = 1u << 31, //< Reset reading the address of waveform storage, write 1 to reset.

    // The operating mode of waveform storage:
    V93XX_DSP_CTRL5_WAVE_MEM_MODE   = 3u << 28,
    //<storage by manual, full then stop. This time is the single storage.
    V93XX_DSP_CTRL5_WAVE_MEM_MODE_SINGLE_MANUAL = 0,
    //<storage by manual, trigger or manual stop. This time is the cyclic storage.
    V93XX_DSP_CTRL5_WAVE_MEM_MODE_CYCLE_MANUAL  = 1u<<28,
    //<storage by trigger, full then stop. This time is  the single storage.
    V93XX_DSP_CTRL5_WAVE_MEM_MODE_SINGLE_STOP   = 2u<<28,
    V93XX_DSP_CTRL5_WAVE_MEM_MODE_OFF           = 3u<<28,   //< disable

    V93XX_DSP_CTRL5_WAVE_MEM_EN     = 1u << 29,         //< Waveform storage to trigger manual switch

    V93XX_DSP_CTRL5_U_DIP_TRIG      = 1u << 27,         //< event trigger for the voltage dip
    V93XX_DSP_CTRL5_U_SWELL_TRIG    = 1u << 26,         //< event trigger for the voltage swell

    V93XX_DSP_CTRL5_IB_LC_TRIG    = 1u << 25,           //< event trigger for the IB under-current
    V93XX_DSP_CTRL5_IB_OC_TRIG    = 1u << 24,           //< Event trigger for the IB over-current
    V93XX_DSP_CTRL5_IA_LC_TRIG    = 1u << 23,           //< event trigger for the IA under-current
    V93XX_DSP_CTRL5_IA_OC_TRIG    = 1u << 22,           //< Event trigger for the IA over-current

    V93XX_DSP_CTRL5_U_LV_TRIG     = 1u << 21,           //< Event trigger for Under-voltage
    V93XX_DSP_CTRL5_U_OV_TRIG     = 1u << 20,           //< Event trigger for Over-voltage

    V93XX_DSP_CTRL5_RESERVED_Msk = 0x00008800ul,
};


enum V93xxDSPCFG_BPFFields{
    V93XX_DSP_CFG_BPF_DEFAULT   = 0,
    V93XX_DSP_CFG_BPF_MODE0     = 0x806764B6,
    V93XX_DSP_CFG_BPF_MODE1     = V93XX_DSP_CFG_BPF_MODE0,
    V93XX_DSP_CFG_BPF_MODE2     = V93XX_DSP_CFG_BPF_MODE0,

    V93XX_DSP_CFG_BPF_MODE6     = 0x80DD7A8C,
    V93XX_DSP_CFG_BPF_MODE7     = V93XX_DSP_CFG_BPF_MODE6,

    V93XX_DSP_CFG_BPF_MODE8     = 0x82B465F0,
};



enum V93XXSYS_SFTRSTFields{

    // Writing 0x4572beaf into this address would be happen software reset once.
    V93XX_SYS_SFTRST_RESET  = 0x4572beaf,
};



enum V93xxSYSINTSTSFields{

    V93XX_SYS_INT_UDIP      = 1u<< 27,      //< Flag bit for the voltage dip
    V93XX_SYS_INT_USWELL    = 1u<< 26,      //< Flag bit for the voltage swell
    V93XX_SYS_INT_IBLC      = 1u<< 25,      //< Flag bit for the IB under-current
    V93XX_SYS_INT_IBOC      = 1u<< 24,      //< Flag bit for the IB over-current
    V93XX_SYS_INT_IALC      = 1u<< 23,      //< Flag bit for the IA under-current
    V93XX_SYS_INT_IAOC      = 1u<< 22,      //< Flag bit for the IA over-current
    V93XX_SYS_INT_ULV       = 1u<< 21,      //< Flag bit for the U under-voltage
    V93XX_SYS_INT_UOV       = 1u<< 20,      //< Flag bit for the U ober-voltage

    V93XX_SYS_INT_SPIERR    = 1u<< 19,      //< Flag bit for the SPI communication error
    V93XX_SYS_INT_UARTERR   = 1u<< 16,      //< Flag bit for the UART communication error
    V93XX_SYS_INT_DMA_FINISH= 1u<< 15,      //< Flag bit for active waveform uploading finished
    V93XX_SYS_INT_CKERR     = 1u<< 14,      //< Flag bit for checksum error
    V93XX_SYS_INT_HSE_FAIL  = 1u<< 13,      //< Flag bit for CTI external input clock error has happened
    V93XX_SYS_INT_REF_ERR   = 1u<< 12,      //< Flag bit for reference error happened
    V93XX_SYS_INT_BIST_ERR  = 1u<< 11,      //< Flag bit for BIST error happened

    /// it could to select the channel IA or IB by bit20 of metering control register
    /// (Table 2-19 Metering Control Register 2 (0x03,DSP_CTRL1)),
    ///  and to select the direction of zerocrossing by bit19~bit18 of metering control register (0x03,DSP_CTRL1)
    V93XX_SYS_INT_ISIGN     = 1u<< 10,      //< current zero-crossing,

    /// , it could to select the direction of zero-crossing by bit19~bit18 of DSP_CTRL1
    V93XX_SYS_INT_USIGN     = 1u<< 9,       //< voltage zero-crossing,

    V93XX_SYS_INT_CURRMS_UPD    = 1u<< 5,       //< instantaneous RMS data updating
    V93XX_SYS_INT_AVGRMS_UPD    = 1u<< 4,       //< average RMS data updating
    V93XX_SYS_INT_CURPWR_UPD    = 1u<< 3,       //< instantaneous power data updating
    V93XX_SYS_INT_AVGPWR_UPD    = 1u<< 2,       //< average power data updating

    V93XX_SYS_INT_PDN           = 1u<< 1,       //< power down event

    ///  This bit will clear automatically when starts to phase measurement.
    V93XX_SYS_INT_PHS_UPD       = 1u,           //< Phase measurement finished

    V93XX_SYS_INT_UPD   =   V93XX_SYS_INT_CURRMS_UPD | V93XX_SYS_INT_CURPWR_UPD
                        | V93XX_SYS_INT_AVGRMS_UPD | V93XX_SYS_INT_AVGPWR_UPD
                        | V93XX_SYS_INT_PHS_UPD
                        ,
};

enum V93xxSYSSTSFields{

    V93XX_SYS_STS_UDIP      = 1u<< 30,      //< Flag bit for the voltage dip
    V93XX_SYS_STS_USWELL    = 1u<< 29,      //< Flag bit for the voltage swell
    V93XX_SYS_STS_IBLC      = 1u<< 28,      //< Flag bit for the IB under-current
    V93XX_SYS_STS_IBOC      = 1u<< 27,      //< Flag bit for the IB over-current
    V93XX_SYS_STS_IALC      = 1u<< 26,      //< Flag bit for the IA under-current
    V93XX_SYS_STS_IAOC      = 1u<< 25,      //< Flag bit for the IA over-current
    V93XX_SYS_STS_ULV       = 1u<< 24,      //< Flag bit for the U under-voltage
    V93XX_SYS_STS_UOV       = 1u<< 23,      //< Flag bit for the U ober-voltage

    V93XX_SYS_STS_RST_Pos       = 23,      //< Flag bit for the U ober-voltage
    V93XX_SYS_STS_RST_Msk       = 7u<< V93XX_SYS_STS_RST_Pos,

    V93XX_SYS_STS_RST_POWERON   = 1u<< V93XX_SYS_STS_RST_Pos,   //< power on reset
    V93XX_SYS_STS_RST_RES       = 2u<< V93XX_SYS_STS_RST_Pos,
    V93XX_SYS_STS_RST_RX        = 3u<< V93XX_SYS_STS_RST_Pos,   //<  RX low-level voltage reset
    V93XX_SYS_STS_RST_SW        = 4u<< V93XX_SYS_STS_RST_Pos,   //<  software reset


    V93XX_SYS_STS_CRP_OUT2      = 1u<< 19,      //< Status bit for power-creep detection for energy accumulator 2
    V93XX_SYS_STS_CRP_OUT1      = 1u<< 18,      //< Status bit for power-creep detection for energy accumulator 1
    V93XX_SYS_STS_SBCREEP       = 1u<< 17,      //< Status bit for no-load detection for apparent power Channel B
    V93XX_SYS_STS_QBCREEP       = 1u<< 16,      //< Status bit for no-load detection for reactive power Channel B
    V93XX_SYS_STS_PBCREEP       = 1u<< 15,      //< Status bit for no-load detection for active power Channel B
    V93XX_SYS_STS_SACREEP       = 1u<< 14,      //< Status bit for no-load detection for apparent power Channel A
    V93XX_SYS_STS_QACREEP       = 1u<< 13,      //< Status bit for no-load detection for reactive power Channel A
    V93XX_SYS_STS_PACREEP       = 1u<< 12,      //< Status bit for no-load detection for active power Channel A

    ///  Sign bit for active power Channel B. Under the powercreep detection, no refresh the flag bit.
    V93XX_SYS_STS_QBSIGN        = 1u<< 11,
    V93XX_SYS_STS_PBSIGN        = 1u<< 10,
    V93XX_SYS_STS_QASIGN        = 1u<< 9,
    V93XX_SYS_STS_PASIGN        = 1u<< 8,

    V93XX_SYS_STS_QB_NEG        = V93XX_SYS_STS_QBSIGN,
    V93XX_SYS_STS_PB_NEG        = V93XX_SYS_STS_PBSIGN,
    V93XX_SYS_STS_QA_NEG        = V93XX_SYS_STS_QASIGN,
    V93XX_SYS_STS_PA_NEG        = V93XX_SYS_STS_PASIGN,

    V93XX_SYS_STS_HSE_FAIL      = 1u<< 6,      //< Flag bit for CTI external input clock error has happened
    V93XX_SYS_STS_BIST_ERR      = 1u<< 5,      //< Flag bit for BIST error happened

    V93XX_SYS_STS_RAMINITIAL    = 1u<< 4,      //< Status bit for RAM initialization finished

    ///  This bit will clear automatically when starts to phase measurement.
    V93XX_SYS_STS_PHS_UPD       = 1u<< 3,       //< Phase measurement finished

    V93XX_SYS_STS_PDN           = 1u<< 2,       //< power down event

    V93XX_SYS_STS_REF_ERR      = 1u<< 1,        //< Status bit for the reference of ADC whether electric leaking.
    V93XX_SYS_STS_REF_LEAK     = V93XX_SYS_INT_REF_ERR, //< Status bit for the reference of ADC whether electric leaking.

    /// Status bit for Checksum. Checksum calculation adress range: 0x0~0x7, 0x25~0x3A, 0x55~0x60
    V93XX_SYS_STS_CKERR         = 1,            //< checksum erro
};


enum V93xxSYS_MISCFields{
    V93XX_SYS_MISC_DEFAULT   = 0,

    V93XX_SYS_MISC_CK_EGY_DIS   = 1u<< 4,  //< When checksum has error, force the energy accumulator and CF output to disable.
    V93XX_SYS_MISC_PD_EGY_DIS   = 1u<< 3,  //< When power-down has error, force the energy accumulator and CF output to disable.

    V93XX_SYS_MISC_INTPOL       = 1u<< 2, //< Reverse output on Interrupted pin:
    V93XX_SYS_MISC_INT_POS      = 0,                        //interrupt pin triggered by high-level voltage
    V93XX_SYS_MISC_INT_NEG      = V93XX_SYS_MISC_INTPOL,    //interrupt pin triggered by low-level voltage

    /* To enable baud rate self-adapting for UART. It suggests enabling before changing system CLK.
     *  0: disable Baud rate self-adapting function.Baud rate self-adapting only for first time
     *      communication.
     *  1: enable Baud rate self-adapting function. Baud rate self-adapting for every time
     *      communication.
     */
    V93XX_SYS_MISC_UARTAUTOEN   = 1u,

    V93XX_SYS_MISC_WR_Msk       = 0x1ful,
};

enum V93xxSYS_INTENFields{
    V93XX_SYS_INTEN_RESERVED_Msk    = 0xf0060000ul,
};


#define V93XXPINCFG( b53, b20) ( ((b53) << 3) | (b20) )

#define V93XXIOCFG( p0,p1,p2,p3)    ( ((p3)<<24) | ((p2)<<16) | ((p1)<<8) | (p0))
//  PxCFG
enum V93xxIOCFGX0_PinCfg{
    V93XX_PINCFG_HIZ            = 0,
    V93XX_PINCFG_ZC             = 1,     //< Current zero-crossing interruption
    V93XX_PINCFG_ZV             = 2,     //< Voltage zero-crossing interruption
    V93XX_PINCFG_ZC3            = 3,     //< Current zero-crossing interruption
    V93XX_PINCFG_ZV4            = 4,     //< Voltage zero-crossing interruption
    V93XX_PINCFG_1TYPE          = 5,    //< 1sttype interruption

    V93XX_PINCFG_WAVE_REFRESH   =  V93XXPINCFG(1, 0),
    V93XX_PINCFG_INSTRMS_REFRESH=  V93XXPINCFG(1, 1),
    V93XX_PINCFG_AVGRMS_REFRESH =  V93XXPINCFG(1, 2),
    V93XX_PINCFG_INSTP_REFRESH  =  V93XXPINCFG(1, 3),
    V93XX_PINCFG_AVGP_REFRESH   =  V93XXPINCFG(1, 4),

    V93XX_PINCFG_IBLC           =  V93XXPINCFG(2, 0),
    V93XX_PINCFG_IBOC           =  V93XXPINCFG(2, 1),
    V93XX_PINCFG_IALC           =  V93XXPINCFG(2, 2),
    V93XX_PINCFG_IAOC           =  V93XXPINCFG(2, 3),
    V93XX_PINCFG_ULV            =  V93XXPINCFG(2, 4),
    V93XX_PINCFG_UOV            =  V93XXPINCFG(2, 5),
    V93XX_PINCFG_VDIP           =  V93XXPINCFG(2, 6),
    V93XX_PINCFG_VSWELL         =  V93XXPINCFG(2, 7),

    V93XX_PINCFG_REFERR         =  V93XXPINCFG(3, 0),
    V93XX_PINCFG_HSEERR         =  V93XXPINCFG(3, 1),
    V93XX_PINCFG_SPIERR         =  V93XXPINCFG(3, 2),
    V93XX_PINCFG_UARTERR        =  V93XXPINCFG(3, 3),
    V93XX_PINCFG_PDN            =  V93XXPINCFG(3, 4),
    V93XX_PINCFG_CKERR          =  V93XXPINCFG(3, 5),
    V93XX_PINCFG_PHS_UPD        =  V93XXPINCFG(3, 6),
    V93XX_PINCFG_RAMERR         =  V93XXPINCFG(3, 7),

    V93XX_PINCFG_4TYPE1         =  V93XXPINCFG(4, 0),   //< 1st type interruption
    V93XX_PINCFG_4TYPE2         =  V93XXPINCFG(4, 1),   //< 2st type interruption
    V93XX_PINCFG_4TYPE3         =  V93XXPINCFG(4, 2),   //< 3st type interruption
    V93XX_PINCFG_4TYPE4         =  V93XXPINCFG(4, 3),   //< 4st type interruption

    V93XX_PINCFG_5TYPE1         =  V93XXPINCFG(5, 0),   //< 1st type interruption
    V93XX_PINCFG_TYPE12         =  V93XXPINCFG(5, 1),   //< 1st type interruption
    V93XX_PINCFG_TYPE13         =  V93XXPINCFG(5, 2),   //< 1st type interruption
    V93XX_PINCFG_TYPE14         =  V93XXPINCFG(5, 3),   //< 1st type interruption
    V93XX_PINCFG_TYPE23         =  V93XXPINCFG(5, 4),   //< 1st type interruption
    V93XX_PINCFG_TYPE24         =  V93XXPINCFG(5, 5),   //< 1st type interruption
    V93XX_PINCFG_TYPE34         =  V93XXPINCFG(5, 6),   //< 1st type interruption
    V93XX_PINCFG_ALL            =  V93XXPINCFG(5, 7),   //< 1st type interruption

    V93XX_PINCFG_TYPE123        =  V93XXPINCFG(6, 0),   //< 1st type interruption
    V93XX_PINCFG_TYPE124        =  V93XXPINCFG(6, 1),   //< 1st type interruption
    V93XX_PINCFG_TYPE134        =  V93XXPINCFG(6, 2),   //< 1st type interruption
    V93XX_PINCFG_TYPE234        =  V93XXPINCFG(6, 3),   //< 1st type interruption
    V93XX_PINCFG_6ALL           =  V93XXPINCFG(6, 7),   //< 1st type interruption

    // modificator for above V93XX_PINCFG_xxx
    /// Bit[5:0] can be configured arbitrary value
    V93XX_PINCFG_CF1            =  2u<<6,   //< CF1 output.
    V93XX_PINCFG_CF2            =  1u<<6,   //< CF2 output
    V93XX_PINCFG_PENRG          =  3u<<6,   //< Actively energy accumulation data uploads
};

union V93xxIOCFGX0Reg{
    uint32_t    raw;
    struct {
        uint8_t p0cfg;
        uint8_t p1cfg;
        uint8_t p2cfg;
        uint8_t p3cfg;
    };
};

union V93xxIOCFGX1Reg{
    uint32_t    raw;
    struct {
        uint8_t p4cfg;
        uint8_t p5cfg;
        uint8_t p6cfg;
    };
};


enum V93XXDSPFRQFields{
    /*
     *  Grid frequency = wave_cnt*freq_const/DSP_DAT_FRQ
     * */
    //  Frequency constant
    V93XXDSPFRQ_SCALE_DSP8  = 1600, // DSP mode 8
    V93XXDSPFRQ_SCALE_DSP67 = 3200, // DSP mode 6,7
    V93XXDSPFRQ_SCALE_DSP012= 6400, // DSP mode 0,1,2
};




#endif /* BSP_DEV_METER_EM_VANGO_V93XX_H_ */
