/**
 * @file ad5934_driver.c
 * @brief Implementation of 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
 */

#include "ad5934_driver.h"

int16_t temperature_dut_samples[2][AD5934_TEMP_AVERAGES]={{0},{0}};
int16_t temperature_ref_samples[2][AD5934_TEMP_AVERAGES]={{0},{0}};
float temperature_display[AD5934_TEMP_AVERAGES] = {0};


int16_t ec_dut_samples[2][AD5934_EC_AVERAGES]={{0},{0}};
float ec_display[AD5934_EC_AVERAGES] = {0};

/******************************************************************************
* @brief Set an AD5934 internal register value.
*
* @param registerAddress - Address of AD5934 register. LB Byte Address when more than 1 byte
*
* @param registerValue - Value of data to be written in the register.
*
* @param numberOfBytes - Number of bytes to be written in the register
*
* @return None.
******************************************************************************/
void AD5934_SetRegisterValue(uint8_t registerAddress, uint32_t registerValue, uint8_t numberOfBytes)
{
	uint8_t writeData[2] = {0, 0};
	HAL_StatusTypeDef status;
	union Bytes2Long AD5934_reg;

	AD5934_reg.number = registerValue;

	for (uint8_t i = 0; i < numberOfBytes; i++)
	{
		writeData[0] = registerAddress - i;
		writeData[1] = AD5934_reg.bytes[i];
		status = HAL_I2C_Master_Transmit(&hi2c2, AD5934_I2C_ADDRESS, writeData, 2, 5);
	}

	return;

}

/******************************************************************************
* @brief Read an AD5934 internal register value.
*
* @param registerAddress - Address of AD5933 register.
*
* @param numberOfBytes - Number of bytes to be read from the register.
*
* @return Register value.
******************************************************************************/
uint32_t AD5934_GetRegisterValue(uint8_t registerAddress, uint8_t numberOfBytes)
{
    uint8_t readData[1]   = {0};
    uint8_t writeData[2]; //= {AD5934_ADDR_POINTER, registerAddress};
    union Bytes2Long AD5934_reg;
    HAL_StatusTypeDef status;

    if(numberOfBytes > 4)
    	return 0xFFFFFFFF; //Overflow

    AD5934_reg.number = 0;
    for (uint8_t i = 0; i < numberOfBytes; i++)
    {
    	writeData[0] = AD5934_ADDR_POINTER;
    	writeData[1] = registerAddress - i;
    	status = HAL_I2C_Master_Transmit(&hi2c2, AD5934_I2C_ADDRESS, writeData, 2, 5);

    	//HAL_Delay(1);
    	readData[0] = 0;
    	status = HAL_I2C_Master_Receive(&hi2c2, AD5934_I2C_ADDRESS, readData, 1, 5);
    	AD5934_reg.bytes[i]=readData[0];

    }

    /*
    AD5934_value.byte[0] = (uint16_t)(AD5934_reg.number & 0x0000FFFF) + 2048;
    AD5934_value.ints[1] = (uint16_t)((AD5934_reg.number & 0xFFFF0000)>>16) + 2048;
	*/

    return AD5934_reg.number;
}


/************************************************************************************
 * @brief Lê um registrador do AD5934 usando a abstração Mem_Read (mais segura).
 *
 * @param regAddr Endereço do registrador no AD5934.
 * @return uint32_t  Valor lido do registrador.
 ***********************************************************************************/
uint32_t AD5934_ReadRegister(uint8_t regAddr, uint8_t numberOfBytes)
{
	uint32_t registerValue = 0;
	uint8_t readData[4] = {0,0,0,0}; // Buffer para receber 16 bits (AD5934 usa regs de 16-bit)
	uint8_t writeData[2] = {AD5934_ADDR_POINTER,regAddr};
	HAL_StatusTypeDef status;

    //Limit buffer size to prevent stack overflow (AD5934 regs are max 4 bytes) */
    if (numberOfBytes > 4)
    {
    	return 0xFFFFFFFF;
    }

    status = HAL_I2C_Master_Transmit(&hi2c2, AD5934_I2C_ADDRESS, writeData, 2, 5);

	HAL_Delay(1);

    // Usamos Mem_Read que faz: START -> ADDR+W -> REG_ADDR -> REPEATED_START -> ADDR+R -> DATA -> STOP
    status = HAL_I2C_Mem_Read(&hi2c2, AD5934_I2C_ADDRESS, AD5934_BLOCK_READ, I2C_MEMADD_SIZE_8BIT, readData, numberOfBytes, 5);

    /* 5. Reconstruct value from Big-Endian buffer */
    for (uint8_t i = 0; i < numberOfBytes; i++)
    {
    	registerValue = (registerValue << 8) | readData[i];
    }

    return registerValue;

}

/******************************************************************************
* @brief Configure and Start the AD5934 frequency sweep parameters.
*
* @param None.
*
* @return None.
******************************************************************************/
void AD5934_Init(void)
{
	/************ Config Sweep******************/

	// Place AD5934 in reset
	AD5934_SetRegisterValue(AD5934_CONTROL_REG_LB, (AD5934_CONTROL_FUNCTION(AD5934_RESET)), 1);

	// Configure starting frequency
	AD5934_SetRegisterValue(AD5934_START_FREQ_REG_LB, AD5934_FREQ_2K5HZ, 3);

	// Configure frequency increment step
	AD5934_SetRegisterValue(AD5934_FREQ_INCR_REG_LB, AD5934_FREQ_0HZ, 3);

	// Configure number of steps
	AD5934_SetRegisterValue(AD5934_NR_INCR_REG_LB, AD5934_STEP_FREQ_0, 2);

	// Set 128 Settling Time
	AD5934_SetRegisterValue(AD5934_NR_SETTLE_REG_LB, AD5934_SETTLING_TIME_0S01,  2);

}

/******************************************************************************
* @brief Re-Start the AD5934 frequency sweep parameters.
*
* @param None.
*
* @return None.
******************************************************************************/
void AD5934_RestartSweep(void)
{
	// Place AD5934 in standby
	AD5934_SetRegisterValue(AD5934_CONTROL_REG_HB, (AD5934_CONTROL_FUNCTION(AD5934_STANDBY) | AD5934_CONTROL_RANGE(AD5934_400mVpp_RANGE) |  AD5934_PGA_GAIN(AD5934_PGA_GAIN_X1)), 1);

	// Initialize starting frequency, Start frequency sweep, standby
	AD5934_SetRegisterValue(AD5934_CONTROL_REG_HB, ((AD5934_CONTROL_FUNCTION(AD5934_INIT_START_FREQ)) | AD5934_CONTROL_RANGE(AD5934_400mVpp_RANGE) |  AD5934_PGA_GAIN(AD5934_PGA_GAIN_X1)), 1);

	// Disable Internal Reset State
	AD5934_SetRegisterValue(AD5934_CONTROL_REG_LB, AD5934_CONTROL_FUNCTION(AD5934_RESERVED), 1);

	// Configure Range Output, PGA gain andPlace AD5934 in sweep
	AD5934_SetRegisterValue(AD5934_CONTROL_REG_HB, (AD5934_CONTROL_FUNCTION(AD5934_START_FREQ_SWEEP) | AD5934_CONTROL_RANGE(AD5934_400mVpp_RANGE) |  AD5934_PGA_GAIN(AD5934_PGA_GAIN_X1)), 1);

	// Wait for data to be valid
	AD5934_Wait_For_Data_Valid();

	// Power Down
	AD5934_SetRegisterValue(AD5934_CONTROL_REG_HB, (AD5934_CONTROL_FUNCTION(AD5934_POWER_DOWN) | AD5934_CONTROL_RANGE(AD5934_400mVpp_RANGE) |  AD5934_PGA_GAIN(AD5934_PGA_GAIN_X1)), 1);

}


/******************************************************************************
* @brief Start the AD5934 frequency sweep parameters.
*
* @param:   channel = AD5934_CH_REF_100R, AD5934_CH_REF_1K, AD5934_CH_REF_10K, AD5934_CH_PT100, AD5934_CH_PT1000 or AD5934_CH_EC
*
* @return Real(int16) and Imaginary(int16) numbers into a int32.
******************************************************************************/
uint32_t AD5934_Sweep(void)
{
	int16_t real_value, imag_value;
	uint32_t value=0;

	// Restart Sweeping
	AD5934_RestartSweep();

	real_value = ((AD5934_GetRegisterValue(AD5934_REAL_REG_LB,2)));
	imag_value = ((AD5934_GetRegisterValue(AD5934_IMG_REG_LB,2)));

	// Get Real (16-bit)  and Imaginary (16-bit) values into an unsigned 32-bit
	value = ((((uint16_t)(imag_value))<<16) | ((uint16_t)(real_value)));

	return value;
}



/******************************************************************************
* @brief Get Reference Resistance on Board.
*
* @param channel - AD5934_CH_PT100 or AD5934_CH_PT1000.
*
* @return impedance.
******************************************************************************/
float AD5934_Get_Ref_Resistance(void)
{
	uint8_t i;
	uint32_t sample;
	int32_t ref_sum[2];
	float real_ref,imag_ref, real_dut, mag_ref;

	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7) == GPIO_PIN_SET) // OFF = PT1000, ON = PT100, PA7 has internal pull-up and switch connects to GND
		ADG715_Update(AD5934_CH_REF100R_LOW_GAIN); // Set the Reference Resistor on board in the Analog Mux
	else
		ADG715_Update(AD5934_CH_REF1K_MID_GAIN); // Set the Reference Resistor on board in the Analog Mux


	sample = AD5934_Sweep(); // Get Reference Resistor Values from ADC

	// Move values in the vectors
	for (i = (AD5934_TEMP_AVERAGES-1); i > 0; i--)
	{
		temperature_ref_samples[0][i] = temperature_ref_samples[0][i-1]; //real
		temperature_ref_samples[1][i] = temperature_ref_samples[1][i-1]; //imag
	}

	// Read real and imaginary data
	temperature_ref_samples[0][0] = (int16_t)(sample & 0x0000FFFF); //real
	//temperature_ref_samples[1][0]  = 0xFFFF-(((sample & 0xFFFF0000)>>16)); //imag
	temperature_ref_samples[1][0]  = (int16_t)((sample & 0xFFFF0000)>>16); //imag

	// Sum values in the vectors
	for (i = 0, ref_sum[0]=0, ref_sum[1]=0; i < AD5934_TEMP_AVERAGES; i++)
	{
		ref_sum[0] += (int32_t)temperature_ref_samples[0][i]; //real
		ref_sum[1] += (int32_t)temperature_ref_samples[1][i]; //imag
	}

	real_ref = ((float)ref_sum[0])/((float)AD5934_TEMP_AVERAGES);
	imag_ref = ((float)ref_sum[1])/((float)AD5934_TEMP_AVERAGES);

	// Calculate gain factor impedance
	mag_ref = sqrtf((real_ref * real_ref) + (imag_ref * imag_ref));

	return mag_ref;
}


/******************************************************************************
* @brief Calculate Temperature.
*
* @param channel - Magnitude of the Reference Resistor.
*
* @return impedance.
******************************************************************************/
float AD5934_GetTemperature(float mag_ref)
{
	uint8_t i, ch_ref;
	uint32_t sample;
	int32_t dut_sum[2];
	float real_dut, imag_dut, ratio, discriminant, mag_dut, ratio_mag, impedance_dut, temperature_sum, gain_factor, temp_result;

	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7) == GPIO_PIN_SET) // OFF = PT1000, ON = PT100, PA7 has internal pull-up and switch connects to GND
	{
		ch_ref = AD5934_CH_RTD_LOW_GAIN; //PT100
		gain_factor = AD5934_GAIN_FACTOR_100R;
	}
	else
	{
		ch_ref = AD5934_CH_RTD_MID_GAIN; //PT1000
		gain_factor = AD5934_GAIN_FACTOR_1K;
	}

	ADG715_Update(ch_ref);

	sample = AD5934_Sweep(); // Get PT100/PT1000 Values from ADC

	for (i = (AD5934_TEMP_AVERAGES-1); i > 0; i--)
	{
		temperature_dut_samples[0][i] = temperature_dut_samples[0][i-1]; //real
		temperature_dut_samples[1][i] = temperature_dut_samples[1][i-1]; //imag
	}

	// Read real and imaginary data
	temperature_dut_samples[0][0] = (int16_t)(sample & 0x0000FFFF); //real
	//temperature_dut_samples[0][1]  = 0xFFFF-(((sample & 0xFFFF0000)>>16)); //imag
	temperature_dut_samples[1][0]  = (int16_t)((sample & 0xFFFF0000)>>16); //imag

	for (i = 0, dut_sum[0]=0, dut_sum[1]=0; i < AD5934_TEMP_AVERAGES; i++)
	{
		dut_sum[0] += (int32_t)temperature_dut_samples[0][i]; //real
		dut_sum[1] += (int32_t)temperature_dut_samples[1][i]; //imag
	}

	real_dut = ((float)dut_sum[0])/((float)AD5934_TEMP_AVERAGES);
	imag_dut = ((float)dut_sum[1])/((float)AD5934_TEMP_AVERAGES);

	// Calculate magnitude
	mag_dut = sqrtf((real_dut * real_dut) + (imag_dut * imag_dut));

	//for (i = (AD5934_TEMP_AVERAGES-1); i > 0; i--)
		//temperature_display[i] = temperature_display[i-1];

	ratio_mag = mag_ref / mag_dut;

	if(ch_ref==AD5934_CH_REF100R_LOW_GAIN) // only for PT100
		impedance_dut = AD5934_Linear_Correction(gain_factor * ratio_mag);
	else
		impedance_dut = gain_factor * ratio_mag;

	// Calculate impedance ratio with the Reference Resistor
	ratio = impedance_dut / gain_factor;

	// Calculate impedance discriminant with the ratio
	discriminant = (AD5934_RTD_A*AD5934_RTD_A)-(4.0f * AD5934_RTD_B * (1.0f - ratio));

	//temp_result = (-AD5934_RTD_A + sqrtf(discriminant)/(2.0f * AD5934_RTD_B));

	return (AD5934_Round_Float_Precision(((-AD5934_RTD_A + sqrtf(discriminant))/(2.0f * AD5934_RTD_B)),2));
	//return (AD5934_Round_Float_Precision(temp_result,1));

	// Calculate new temperature with the discriminant
	//temperature_display[0] = (-AD5934_RTD_A + sqrtf(discriminant))/(2.0f * AD5934_RTD_B);

	// Sum of all temperatures
	// for (i = 0, temperature_sum=0.0f; i < AD5934_TEMP_AVERAGES; i++)
		// temperature_sum += temperature_display[i];

	// Is the temperature stable?
	//if(temperature_display[0]>0.0f && (abs(temperature_display[0]-temperature_display[AD5934_TEMP_AVERAGES-1])/temperature_display[0])<0.1f)
		//return(AD5934_Round_Float_Precision(temperature_sum/((float)AD5934_TEMP_AVERAGES),1)); // Sum / number of averages
	//else
		//return 0.0f;	//instable values return always 0
}


/**
 * @brief Calculates impedance and converts it to conductivity using a 2-point
 * temperature-compensated model.
 *
 * @param temperature_dut The current temperature of the DUT (Device Under Test).
 * @return float Calculated conductivity in uS/cm.
 */
float AD5934_GetImpedance(float temperature_dut)
{
    uint8_t i, ec_gain;
    uint32_t sample_dut;
    int32_t dut_sum[2] = {0, 0};
    float real_avg, imag_avg, mag_dut, slope, target_cond;

    /* 1. Hardware Setup: Gain Selection (PA6) */
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == GPIO_PIN_SET)
        ec_gain = AD5934_CH_EC_HIGH_GAIN;
    else
        ec_gain = AD5934_CH_EC_MID_GAIN;

    if((ec_gain != flash_data.EC10mS_EC5mS_switch) && (main_state != STATE_PH4_DRY_EC_CALIBRATION || main_state != STATE_PH7_WET_EC_CALIBRATION))
    	return -1.0f; // Fatal error because the gain used in calibration is different

    ADG715_Update(ec_gain);
    //HAL_Delay(5);

    /* 2. Data Acquisition */
    sample_dut = AD5934_Sweep();

    // Shift buffer for moving average
    for (i = (AD5934_EC_AVERAGES - 1); i > 0; i--)
    {
        ec_dut_samples[0][i] = ec_dut_samples[0][i-1];
        ec_dut_samples[1][i] = ec_dut_samples[1][i-1];
    }


    // Deconstruct 32-bit sample into Real and Imaginary components
    ec_dut_samples[0][0] = (float)(int16_t)(sample_dut & 0xFFFF);
    ec_dut_samples[1][0] = (float)(int16_t)((sample_dut >> 16) & 0xFFFF);


    /* 3. Compute Averages */
    for (i = 0; i < AD5934_EC_AVERAGES; i++)
    {
        dut_sum[0] += (int32_t)ec_dut_samples[0][i];
        dut_sum[1] += (int32_t)ec_dut_samples[1][i];
    }

    real_avg = (float)dut_sum[0] / (float)AD5934_EC_AVERAGES;
    imag_avg = (float)dut_sum[1] / (float)AD5934_EC_AVERAGES;

    /* 4. Magnitude Calculation */
    mag_dut = sqrtf((real_avg * real_avg) + (imag_avg * imag_avg));

    /* 5. Calibration Logic Implementation */

    // Mode: CALIBRATION SETUP (User is defining the reference magnitude)
    if(main_state == STATE_PH4_DRY_EC_CALIBRATION || main_state == STATE_PH7_WET_EC_CALIBRATION)
    {
        return mag_dut;
    }
    // Mode: MEASUREMENT (Applying temperature compensation)
    else if(flash_data.ec0_mag != flash_data.ec1413_mag)
	{
		slope = (AD5934_GAIN_FACTOR_1413US/(flash_data.ec1413_mag-flash_data.ec0_mag));

		return(AD5934_GAIN_FACTOR_1413US + (AD5934_EC_Compensate_To_25C(mag_dut,temperature_dut) - flash_data.ec1413_mag) * slope);
	}
    else
        return 0.0f; // Calibration error fallback

}


/**
 * @brief Monitora o status com TIMEOUT para evitar travamento do sistema.
 */
void AD5934_Wait_For_Data_Valid(void)
{
    uint32_t  timeout_counter = 0;
    const uint32_t MAX_TIMEOUT = 10000; // Limite de tentativas
    uint8_t status;

    while (1)
    {
        status = (uint8_t)AD5934_GetRegisterValue(AD5934_STATUS_REG, 1);

        if ((status & AD5934_STATUS_DATA_VALID) != 0)
        {
            break; // Sucesso!
        }

        timeout_counter++;
        if (timeout_counter >= MAX_TIMEOUT)
        {
            // TRATAMENTO DE ERRO: O sistema não travou, mas o chip falhou.
            break;
        }

        HAL_Delay(1); // Pequeno delay para não sobrecarregar o barramento I2C
    }
}



/**
 * @brief Reduz a precisão decimal de um float através de truncamento.
 *
 * @param valor O valor float original.
 * @param casas_decimais Quantidade de casas que devem permanecer após a vírgula.
 * @return float O valor com as casas decimais excedentes removidas.
 */
float AD5934_Round_Float_Precision(float value, uint8_t number_of_decimals)
{
    float multiply = 1.0f;

    for (uint8_t i = 0; i < number_of_decimals; i++)
    	multiply *= 10.0f;

    return roundf(value * multiply) / multiply;
}


/**
 * @brief Performs a linear transformation optimized to match the provided dataset.
 *
 * This function implements a linear regression model: y = mx + c
 * Derived from least squares fitting of the input/output pairs:
 * m (slope) ≈ 1.02236
 * c (offset) ≈ -2.1163
 *
 * The implementation is branchless (no conditionals) to ensure constant
 * execution time (O(1)) and prevent pipeline stalls in ARM Cortex-M3.
 *
 * @param input_val The raw float value from sensor/ADC.
 * @return float The transformed value following the requested trend.
 */
float AD5934_Linear_Correction(float raw_value)
{
    /* Pre-calculated constants from regression analysis */
    const float slope = 1.02281f;
    const float offset = (-2.1409f);

    /* Single FPU instruction (if FPU available) or optimized software float mul/add */
    return (raw_value * slope) + offset;
}


/**
 * @brief Temperature compensation with drift equal to 2%
 * @param admittance raw in uS/cm
 * @param temperature_celsius Temperature in degrees Celsius
 * @return admittance compensated
 */
float AD5934_EC_Compensate_To_25C(float ec_raw_uScm, float temp_C)
{

	float factor = 1.0f + AD5934_EC_ALPHA_PER_C * (temp_C - AD5934_EC_TEMP_REF_C);

	if (factor < 0.1f)
		factor = 0.1f;

	return (ec_raw_uScm / factor);
}

/**
 * @brief Calibrates EC sensor reading to 25°C reference point
 * @param temp_C Temperature of the liquid in Celsius
 * @return Temperature-compensated Correction factor value at 25°C reference
 */
float AD5934_EC_Calibrate_Temperature(float temp_C)
{
	// Calibration data points for standard solution (1413 uS/cm)
    const float temps[] = {5, 10, 15, 18, 20, 22, 25, 30, 35, 40, 45, 50};
    const float conductivities[] = {893, 1018, 1149, 1225, 1278, 1329, 1413, 1552, 1691, 1843, 1988, 2145};

    // Find the two nearest temperature points for interpolation
    int32_t temp_index = -1;
    for (int i = 0; i < 12; i++)
    {
        if (temps[i] >= temp_C)
        {
            temp_index = i;
            break;
        }
    }

    // Handle boundary cases
    if (temp_index == -1) {
        // Temperature higher than max point (50°C)
        temp_index = 10;
    } else if (temp_index == 0) {
        // Temperature lower than min point (5°C)
        temp_index = 0;
    }

    // Interpolate conductivity at measured temperature
    float temp1 = temps[temp_index - 1];
    float temp2 = temps[temp_index];
    float cond1 = conductivities[temp_index - 1];
    float cond2 = conductivities[temp_index];

    // Linear interpolation to get conductivity at measured temperature
    float interpolated_cond = cond1 + (cond2 - cond1) * (temp_C - temp1) / (temp2 - temp1);

    // Return real conductivity at the temperature
    return(interpolated_cond/1413.0f);
}


/**
 * @brief Calibrate AD5934 using dry probe and standard solution
 *
 * @param dry_probe_real Raw real value from dry probe measurement
 * @param dry_probe_imag Raw imaginary value from dry probe measurement
 * @param standard_real Raw real value from 1413 uS/cm standard solution
 * @param standard_imag Raw imaginary value from 1413 uS/cm standard solution
 * @return float Calibration factor for converting raw readings to admittance
 */
float AD5934_Calibrate(float dry_probe_real, float dry_probe_imag, float standard_real, float standard_imag)
{
    // Calculate magnitude of dry probe reading
    float dry_magnitude = sqrtf(dry_probe_real * dry_probe_real + dry_probe_imag * dry_probe_imag);

    // Calculate magnitude of standard solution reading
    float standard_magnitude = sqrtf(standard_real * standard_real + standard_imag * standard_imag);

    // Calculate calibration factor based on known standard (1413 uS/cm)
    // This assumes the standard provides a known conductance value
    float calibration_factor = 1413.0f / standard_magnitude;

    return calibration_factor;
}

/*****************************************************************************
 * ADG715
*****************************************************************************
 * @brief Writes data into a register.
 *
 * @param value - Data value to write.
 *
 * @return None.
*******************************************************************************/

void ADG715_SetRegisterValue(char value)
{
	uint8_t  writeData[1]	= {value};
	HAL_StatusTypeDef status;

	status = HAL_I2C_Master_Transmit(&hi2c2, ADG715_I2C_ADDRESS, writeData, 1, 1);

	return;
}

void ADG715_SetChannels(uint8_t ch1, uint8_t ch2)
{
	ADG715_SetRegisterValue(ch1+ch2);
}

void ADG715_ResetChannels(void)
{
	ADG715_SetRegisterValue(0);
}

/******************************************************************************
* @brief Update Channels on the ADG715 and stop-start AD5934.
*
* @param: channel = AD5934_CH_REF_100R, AD5934_CH_REF_1K, AD5934_CH_REF_10K, AD5934_CH_PT100, AD5934_CH_PT1000, AD5934_CH_EC, ...
*
* @return none.
******************************************************************************/
void ADG715_Update(AD5934_Channel_t channel)
{
    // Garante que o índice recebido não ultrapassa os limites do vetor
    if (channel >= AD5934_CH_MAX)
        return;

    // Envia o byte combinado via I2C (Make-before-break nativo por barramento)
    ADG715_SetRegisterValue(ADG715_Channel_Map[channel]);

    // Gestão inteligente do delay de acomodação
    if (channel >= AD5934_CH_EC_LOW_GAIN)
        HAL_Delay(20); // Canais de Condutividade Elétrica (CE) necessitam de maior estabilização química
    else
        HAL_Delay(10); // Resistores puros e RTD estabilizam mais rapidamente

}


