/**
 * @file ad5934_driver.h
 * @brief Header file for AD5934 I2C impedance converter driver.
 *
 * This driver provides functions to configure and read from the AD5934
 * 16-bit, 200kHz I2C impedance converter. The device supports frequency sweep
 * measurements and provides magnitude and phase data.
 *
 * @note Based on AD5934 datasheet – Rev. E – October 2017
 */

#ifndef INC_AD5934_DRIVER_H_
#define INC_AD5934_DRIVER_H_

#include "stm32f1xx_hal.h"
#include "main.h"
#include <math.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/*****************************************************************************/
/******************* ADP5589 Registers Definitions ***************************/
/*****************************************************************************/
// AD5934 I2C Address
#define AD5934_I2C_ADDRESS     			(0x0D << 1)
// Registers Address
#define AD5934_CONTROL_REG_HB           0x80
#define AD5934_CONTROL_REG_LB           0x81
#define AD5934_START_FREQ_REG_HB        0x82
#define AD5934_START_FREQ_REG_MB        0x83
#define AD5934_START_FREQ_REG_LB        0x84
#define AD5934_FREQ_INCR_REG_HB         0x85
#define AD5934_FREQ_INCR_REG_MB         0x86
#define AD5934_FREQ_INCR_REG_LB         0x87
#define AD5934_NR_INCR_REG_HB           0x88
#define AD5934_NR_INCR_REG_LB           0x89
#define AD5934_NR_SETTLE_REG_HB         0x8A
#define AD5934_NR_SETTLE_REG_LB         0x8B
#define AD5934_STATUS_REG               0x8F
#define AD5934_TEMP_REG_HB              0x92
#define AD5934_TEMP_REG_LB              0x93
#define AD5934_REAL_REG_HB              0x94
#define AD5934_REAL_REG_LB              0x95
#define AD5934_IMG_REG_HB               0x96
#define AD5934_IMG_REG_LB               0x97

/*****************************************************************************/
/******************* ADP5589 Registers Bits **********************************/
/*****************************************************************************/
// Control Register High Bits 0x80
#define AD5934_CONTROL_FUNCTION(x)      ((x) << 4)
// AD5934_CONTROL_FUNCTION(x) options
#define AD5934_INIT_START_FREQ			0x01
#define AD5934_START_FREQ_SWEEP			0x02
#define AD5934_INCR_FREQ				0x03
#define AD5934_REPEAT_FREQ				0x04
#define AD5934_POWER_DOWN				0x0A
#define AD5934_STANDBY					0x0B

#define AD5934_RESERVED					0x08

#define AD5934_CONTROL_RANGE(x)			((x) << 1)
// AD5934_CONTROL_RANGE(x) options
#define AD5934_2Vpp_RANGE				0x00
#define AD5934_200mVpp_RANGE			0x01
#define AD5934_400mVpp_RANGE			0x02
#define AD5934_1Vpp_RANGE				0x03

#define AD5934_PGA_GAIN(x)				((x) << 0)
// AD5934_PGA_GAIN(x) options
#define AD5934_PGA_GAIN_X5				0x00
#define AD5934_PGA_GAIN_X1				0x01

// Control Register Low Bits 0x81
#define AD5934_RESET					(1 << 4)

#define AD5934_FUNCTION_NOP             0x0

// Status Register 0x8F
#define AD5934_STATUS_TEMP_VALID		1
#define AD5934_STATUS_DATA_VALID		(1 << 1)
#define AD5934_STATUS_SWEEP_DONE		(1 << 2)


// Values for frequency counts	 = 		(freq*2^27)/(1MHz/16)
#define AD5934_FREQ_4K882HZ				0x009FF92F	// 4.882kHz
#define AD5934_FREQ_3K761HZ				0x007B3D8E	// 3.761kHZ
#define AD5934_FREQ_2K599HZ				0x005529FE	// 2.599kHz
#define AD5934_FREQ_2K5HZ				0x0051EB86	// 2.5kHz
#define AD5934_FREQ_2K293HZ				0x004B2314	// 2.293kHz
#define AD5934_FREQ_2K018HZ				0x00422036	// 2.018kHz
#define AD5934_FREQ_1K953HZ				0x003FFEF3	// 1.953kHz
#define AD5934_FREQ_1K865HZ				0x003D1CC1	// 1.865kHz
#define AD5934_FREQ_1K590HZ				0x003419E3	// 1.59kHz
#define AD5934_FREQ_0HZ					0x00000000	// 0Hz
#define AD5934_STEP_FREQ_0				0x0000	// 0 passos
#define AD5934_SETTLING_TIME_23			0x0017	// 17 ciclos
#define AD5934_SETTLING_TIME_32			0x0020	// 32 ciclos
#define AD5934_SETTLING_TIME_48			0x0030	// 48 ciclos
#define AD5934_SETTLING_TIME_64			0x0040	// 64 ciclos
#define AD5934_SETTLING_TIME_90			0x0060	// 90 ciclos
#define AD5934_SETTLING_TIME_117		0x0075	// 117 ciclos
#define AD5934_SETTLING_TIME_160		0x00A0	// 160 ciclos
#define AD5934_SETTLING_TIME_191		0x00BF	// 191 ciclos


/*****************************************************************************/
/**************************** Command Codes **********************************/
/*****************************************************************************/
#define AD5934_BLOCK_WRITE				0xA0
#define AD5934_BLOCK_READ    			0xA1
#define AD5934_ADDR_POINTER 			0xB0

/*! ADG715 Registers */
#define ADG715_I2C_ADDRESS    			(0x48 << 1)

#define ADG715_SW1	    				0x01 //Rf = 150R
#define ADG715_SW2	    				0x02 //Rf = 1.5k
#define ADG715_SW3	    				0x04 //Rf = 6.2k

#define ADG715_SW4	    				0x08 //Rcal = 100R
#define ADG715_SW5	    				0x10 //Rcal = 1k
#define ADG715_SW6	    				0x20 //Rcal = 10k

#define ADG715_SW7	    				0x40 //RTD Input
#define ADG715_SW8	    				0x80 //CE Input

#define ADG715_SWOFF	    			0x00 //Dummy

/*****************************************************************************/
/**************************** General Defines ********************************/
/*****************************************************************************/

#define AD5934_LOW_GAIN_BASE			0x01
#define AD5934_MID_GAIN_BASE			0x02
#define AD5934_HIGH_GAIN_BASE			0x04
#define AD5934_REF100R_BASE				0x08
#define AD5934_REF1K_BASE				0x10
#define AD5934_REF10K_BASE				0x20
#define AD5934_RTD_BASE					0x40
#define AD5934_CE_BASE					0x80


#define AD5934_CH_DELTA					0x10

#define AD5934_GAIN_FACTOR_100R			100.0f
#define AD5934_GAIN_FACTOR_1K			1000.0f
#define AD5934_GAIN_FACTOR_10K			10000.0f

#define AD5934_EC_IN_SERIES_RESISTOR	100.0f

#define AD5934_EC_10MS					0.01f 	// Ref 100R
#define AD5934_EC_1MS					0.001f	// Ref 1K
#define AD5934_EC_0_1MS					0.0001f	// Ref 10k

#define AD5934_DRIFT_PT100				2.92f
#define AD5934_DRIFT_PT1000				0.42f

#define AD5934_GAIN_FACTOR_1413US		1413.0f
#define AD5934_GAIN_FACTOR_12880US		12880.0f

// Aproximação linear do coeficiente PT100/PT1000 (α), usada abaixo de 0°C
// R(T) ≈ R0 * (1 + ALPHA * T)  →  T ≈ (R/R0 - 1) / ALPHA
#define AD5934_RTD_ALPHA     			0.00385f   // ohms/ohm/°C, padrão IEC 60751
#define AD5934_RTD_A					3.9083e-3f
#define AD5934_RTD_B					(-5.775e-7f)

#define AD5934_TEMP_AVERAGES			16
#define AD5934_EC_AVERAGES				16

#define AD5934_EC_ALPHA_PER_C 			0.02f
#define AD5934_EC_TEMP_REF_C 			25.0f

#define AD5934_EC_1413US_PT100_DEFAULT	3111	// magnitude
#define AD5934_EC_1413US_PT1000_DEFAULT	2970	// magnitude


//Mux Set to Read...
#define AD5934_ID_RTD       	      	0
#define AD5934_ID_EC    	    	    1
#define AD5934_ID_REF_100R_LOWGAIN     	2
#define AD5934_ID_REF_100R_MIDGAIN    	3
#define AD5934_ID_REF_1K_MIDGAIN       	4
#define AD5934_ID_REF_1K_HIGHGAIN      	5
#define AD5934_ID_REF_10K_HIGHGAIN		6

/*****************************************************************************/
/**************************** Filtering  Defines *****************************/
/*****************************************************************************/
#define AD5934_TIME_PER_SWEEP        	10  // 60 ms entre o início de cada sweep
#define AD5934_SYNC_MUX_SETTLING    	40   // 10 ms to wait before read after change ADG715 channels

#define AD5934_BURST_SIZE      			1	// Number of Repeated Sweeps on the same channel before change the Mux
#define AD5934_TRIM_COUNT      			0
#define AD5934_HISTORY_SIZE    			16
#define AD5934_IIR_ALPHA       			0.10f

#define AD5934_REF_FLOAT_SCALE_MIN		1850.0f
#define AD5934_REF_FLOAT_SCALE_MAX		2450.0f
#define AD5934_REF_OUT_SCALE_MIN		0
#define AD5934_REF_OUT_SCALE_MAX		4095

//#define AD5934_RTD_FLOAT_SCALE_MIN		1850.0f
//#define AD5934_RTD_FLOAT_SCALE_MAX		2450.0f
#define AD5934_RTD_FLOAT_SCALE_MIN		(-10.0f)
#define AD5934_RTD_FLOAT_SCALE_MAX		60.0f
#define AD5934_RTD_OUT_SCALE_MIN		70
#define AD5934_RTD_OUT_SCALE_MAX		800

#define AD5934_EC5_FLOAT_SCALE_MIN		0.0f
#define AD5934_EC5_FLOAT_SCALE_MAX		5.5f
#define AD5934_EC5_OUT_SCALE_MIN		0
#define AD5934_EC5_OUT_SCALE_MAX		4095

#define AD5934_EC10_FLOAT_SCALE_MIN		0.0f
#define AD5934_EC10_FLOAT_SCALE_MAX		15.0f
#define AD5934_EC10_OUT_SCALE_MIN		0
#define AD5934_EC10_OUT_SCALE_MAX		4095



union Bytes2Int
{
	uint8_t bytes[2];
	uint16_t number;
};

union Bytes2Long
{
	uint8_t bytes[4];
	uint32_t number;
};

union Short2Long
{
	uint16_t ints[2];
	uint32_t number;
};

typedef enum {
    AD5934_CH_REF100R_LOW_GAIN = 0,
    AD5934_CH_REF100R_MID_GAIN,
    AD5934_CH_REF100R_HIGH_GAIN,

    AD5934_CH_REF1K_LOW_GAIN,
    AD5934_CH_REF1K_MID_GAIN,
    AD5934_CH_REF1K_HIGH_GAIN,

    AD5934_CH_REF10K_LOW_GAIN,
    AD5934_CH_REF10K_MID_GAIN,
    AD5934_CH_REF10K_HIGH_GAIN,

    AD5934_CH_RTD_LOW_GAIN,
    AD5934_CH_RTD_MID_GAIN,
    AD5934_CH_RTD_HIGH_GAIN,

    AD5934_CH_EC_LOW_GAIN,
    AD5934_CH_EC_MID_GAIN,
    AD5934_CH_EC_HIGH_GAIN,

    AD5934_CH_MAX // Guarda automaticamente o número total de canais (15)
} AD5934_Channel_t;


typedef enum {
    AD5934_IDLE,
    AD5934_WAIT_MUX,
    AD5934_START_CONVERSION,
    AD5934_WAIT_CONVERSION,
    AD5934_READ_DATA,
    AD5934_WAIT_NEXT_SWEEP,
    AD5934_SWITCH_MUX
} AD5934_State_t;



typedef struct {
    float    burst[AD5934_BURST_SIZE];
    uint8_t  burst_index;
    float    history[AD5934_HISTORY_SIZE];
    uint8_t  history_index;
    uint8_t  history_count;
    float    iir_state;
    uint8_t  iir_initialized;
    float    filtered_value;
    uint8_t  value_valid;
} AD5934_filter_t;

typedef struct {
    float buffer[AD5934_HISTORY_SIZE];
    float sum;
    uint8_t index;
    uint8_t count;      // quantas amostras já foram inseridas (até encher o buffer)
    float average;
} AD5934_AvgFilter_t;

static const uint8_t ADG715_Channel_Map[AD5934_CH_MAX] = {
    [AD5934_CH_REF100R_LOW_GAIN]   = (ADG715_SW1 | ADG715_SW4),
    [AD5934_CH_REF100R_MID_GAIN]   = (ADG715_SW2 | ADG715_SW4),
    [AD5934_CH_REF100R_HIGH_GAIN]  = (ADG715_SW3 | ADG715_SW4),

    [AD5934_CH_REF1K_LOW_GAIN]     = (ADG715_SW1 | ADG715_SW5),
    [AD5934_CH_REF1K_MID_GAIN]     = (ADG715_SW2 | ADG715_SW5),
    [AD5934_CH_REF1K_HIGH_GAIN]    = (ADG715_SW3 | ADG715_SW5),

    [AD5934_CH_REF10K_LOW_GAIN]    = (ADG715_SW1 | ADG715_SW6),
    [AD5934_CH_REF10K_MID_GAIN]    = (ADG715_SW2 | ADG715_SW6),
    [AD5934_CH_REF10K_HIGH_GAIN]   = (ADG715_SW3 | ADG715_SW6),

    [AD5934_CH_RTD_LOW_GAIN]       = (ADG715_SW1 | ADG715_SW7),
    [AD5934_CH_RTD_MID_GAIN]       = (ADG715_SW2 | ADG715_SW7),
    [AD5934_CH_RTD_HIGH_GAIN]      = (ADG715_SW3 | ADG715_SW7),

    [AD5934_CH_EC_LOW_GAIN]        = (ADG715_SW1 | ADG715_SW8),
    [AD5934_CH_EC_MID_GAIN]        = (ADG715_SW2 | ADG715_SW8),
    [AD5934_CH_EC_HIGH_GAIN]       = (ADG715_SW3 | ADG715_SW8)
};

static const float AD5934_Scale_Float_Min[AD5934_CH_MAX] = {
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_REF_FLOAT_SCALE_MIN,
	AD5934_RTD_FLOAT_SCALE_MIN,
	AD5934_RTD_FLOAT_SCALE_MIN,
	AD5934_RTD_FLOAT_SCALE_MIN,
	AD5934_EC10_FLOAT_SCALE_MIN,
	AD5934_EC10_FLOAT_SCALE_MIN,
	AD5934_EC5_FLOAT_SCALE_MIN
};

static const float AD5934_Scale_Float_Max[AD5934_CH_MAX] = {
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_REF_FLOAT_SCALE_MAX,
	AD5934_RTD_FLOAT_SCALE_MAX,
	AD5934_RTD_FLOAT_SCALE_MAX,
	AD5934_RTD_FLOAT_SCALE_MAX,
	AD5934_EC10_FLOAT_SCALE_MAX,
	AD5934_EC10_FLOAT_SCALE_MAX,
	AD5934_EC5_FLOAT_SCALE_MAX
};

static const uint16_t AD5934_Scale_Out_Min[AD5934_CH_MAX] = {
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_REF_OUT_SCALE_MIN,
	AD5934_RTD_OUT_SCALE_MIN,
	AD5934_RTD_OUT_SCALE_MIN,
	AD5934_RTD_OUT_SCALE_MIN,
	AD5934_EC10_OUT_SCALE_MIN,
	AD5934_EC10_OUT_SCALE_MIN,
	AD5934_EC5_OUT_SCALE_MIN
};

static const uint16_t AD5934_Scale_Out_Max[AD5934_CH_MAX] = {
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_REF_OUT_SCALE_MAX,
	AD5934_RTD_OUT_SCALE_MAX,
	AD5934_RTD_OUT_SCALE_MAX,
	AD5934_RTD_OUT_SCALE_MAX,
	AD5934_EC10_OUT_SCALE_MAX,
	AD5934_EC10_OUT_SCALE_MAX,
	AD5934_EC5_OUT_SCALE_MAX
};


extern I2C_HandleTypeDef hi2c2;

extern volatile AD5934_State_t ad5934_state;
extern volatile uint32_t g_ms_counter; // Increment each 1ms Timer
extern volatile uint32_t state_timer;

extern uint8_t current_mux_channel;
extern uint8_t sweep_count; // Count how many sweeps done at the same channel now (0 a 7)
extern uint8_t is_new_channel;
extern uint8_t current_ec_mux;
extern uint8_t current_rtd_mux;
extern uint8_t current_ref_mux;

extern AD5934_filter_t g_rtd_filter, g_ec_filter, g_ref_100R_LowGain_filter, g_ref_100R_MidGain_filter,  g_ref_1K_MidGain_filter, g_ref_1K_HighGain_filter, g_ref_10K_HighGain_filter;

extern uint8_t is_startup;

/*****************************************************************************/
/************************ Functions Declarations *****************************/
/*****************************************************************************/
void AD5934_SetRegisterValue(uint8_t registerAddress, uint32_t registerValue, uint8_t numberOfBytes);

uint32_t AD5934_GetRegisterValue(uint8_t registerAddress, uint8_t numberOfBytes);

uint32_t AD5934_ReadRegister(uint8_t regAddr, uint8_t numberOfBytes);

void AD5934_Init(void);

void AD5934_RestartSweep(void);

void AD5934_Repeat_Sweep(void);

void AD5934_StopSweep(void);

float AD5934_Get_Ref_Resistance(void);

float AD5934_Calculate_Temperature(float mag_ref_pt100, float mag_ref_pt1000, float mag_dut);

float AD5934_EC_Compensate_Magnitude_To_25C(float mag_dut, float temperature_dut);

float AD5934_EC_Calibrate_Temperature(float temp_C);

float AD5934_GetMagnitude(void);

float AD5934_GetImpedance(float mag_ref, float mag_dut);

float AD5934_GetAdmittance(float mag_ref_10mS_MidGain, float mag_ref_1mS_MidGain, float mag_ref_1mS_HighGain, float mag_ref_0_1mS_HighGain, float mag_dut);

uint32_t AD5934_Get_Real_Imag_Numbers(void);

uint16_t AD5934_Compress_To_IntScale(float value, uint8_t scale);

float AD5934_Round_Float_Precision(float value, uint8_t number_of_decimals);

float AD5934_Linear_Correction(float raw_value);

void AD5934_MovingAvg_Init(AD5934_AvgFilter_t *filt);

void AD5934_MovingAvg_Process(AD5934_AvgFilter_t *filt, float new_sample);

void AD5934_Process_System(void);

void AD5934_Sort_Array(float *v, uint8_t n);

float AD5934_Trimmed_Mean(float *buffer, uint8_t n, uint8_t trim);

float AD5934_History_Average(const float *hist, uint8_t n);

void AD5934_Process_Sample(AD5934_filter_t *ch, float raw);

void AD5934_RTD_NewSample(float raw);

void AD5934_EC_NewSample(float raw);

void AD5934_Reference_100R_LowGain_NewSample(float raw);

void AD5934_Reference_100R_MidGain_NewSample(float raw);

void AD5934_Reference_1K_MidGain_NewSample(float raw);

void AD5934_Reference_1K_HighGain_NewSample(float raw);

void AD5934_Reference_10K_HighGain_NewSample(float raw);

void ADG715_SetRegisterValue(char value);

void ADG715_ResetChannels(void);

void ADG715_SetChannels(AD5934_Channel_t channel);

#ifdef __cplusplus
}
#endif

#endif /* INC_AD5934_DRIVER_H_ */
