//
// Created by dell on 24-12-3.
//

#include "ldc1612.h"

#ifdef LDC_DEBUG
    #include <stdio.h>
    #define LDC1612_DEBUG(fmt, ...) printf("[LDC1612] " fmt "\n", ##__VA_ARGS__)
#else
    #define LDC1612_DEBUG(fmt, ...)
#endif

/*!
    \brief      写入寄存器
    \param[in]  reg_addr: 寄存器地址
    \param[in]  value: 写入值
    \param[out] none
    \retval     i2c_result_t
*/
static i2c_result_t ldc1612_write_register(uint8_t reg_addr, uint16_t value) {
    uint8_t data[2];
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;

    return LDC1612_IIC_WRITE_16BITS(LDC1612_ADDR, reg_addr, data);
}

/*!
    \brief      读取寄存器
    \param[in]  reg_addr: 寄存器地址
    \param[out] value: 读取值指针
    \retval     i2c_status_t
*/
static i2c_result_t ldc1612_read_register(uint8_t reg_addr, uint16_t *value) {
    uint8_t data[2];
    i2c_result_t status;

    if (value == NULL) {
        return I2C_RESULT_INVALID_PARAM;
    }

    status = LDC1612_IIC_READ_16BITS(LDC1612_ADDR, reg_addr, data);
    if (status == I2C_RESULT_SUCCESS) {
        *value = ((uint16_t)data[0] << 8) | data[1];
    }

    return status;
}

/*!
    \brief      计算并获取频率分频值
    \param[in]  channel: 通道号
    \param[out] none
    \retval     计算得到的频率分频值
*/
static uint16_t ldc1612_calculate_freq_divider(uint8_t channel) {
    uint16_t value;
    uint16_t fin_div, freq_div;
    float sensor_freq;

    sensor_freq = 1 / (2 * 3.14 * sqrt(COIL_L_UH * COIL_C_PF * pow(10, -18))) * pow(10, -6);
    if (sensor_freq <= 8.75) {
        fin_div = LDC1612_FIN_DIV_1;
    } else if (sensor_freq <= 17.5) {
        fin_div = LDC1612_FIN_DIV_2;
    } else if (sensor_freq <= 35.0) {
        fin_div = LDC1612_FIN_DIV_4;
    } else {
        LDC1612_DEBUG("Error: Sensor frequency (%.2f MHz) exceeds maximum limit!", sensor_freq);
        return 0;
        
    }

/* 
    Fref为参考时钟频率，单位MHz，必须小于35MHz，如果输入时钟为外部时钟40MHz，则需要分频
    LDC1612_EXT_CLK_MHZ为外部时钟频率，单位MHz
    Fin为传感器谐振频率，单位MHz。
    必须满足：Fin < Fref / 4
    通常高精度应用，采用外部40MHz，2分频，Fin不应超5MHz。
*/
    if (LDC1612_EXT_CLK_MHZ >= 35)
    {
        freq_div = LDC1612_FREF_DIV_2;
    } else {
        freq_div = LDC1612_FREF_DIV_1;
    }

    if (sensor_freq >= (LDC1612_EXT_CLK_MHZ / freq_div) / 4)
    {
        LDC1612_DEBUG("Warning: Sensor frequency (%.2f MHz) is too high for the given reference clock (%.2f MHz)!\n", sensor_freq, (float)(LDC1612_EXT_CLK_MHZ / freq_div));
    }

    value = LDC1612_CLOCK_DIVIDER_GEN(fin_div, freq_div);
    
    return value;
}

uint16_t ldc1612_get_manufacturer_id(void) {
    uint8_t data[2] = {0};

    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, READ_MANUFACTURER_ID, data);
    return (data[0] << 8) | data[1];
}

uint16_t ldc1612_get_deveice_id(void) {
    uint8_t data[2] = {0};

    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, READ_DEVICE_ID, data);
    return (data[0] << 8) | data[1];
}

/** @brief reset sensor.

 * */
ldc1612_status_t ldc1612_reset_sensor(void) {
    i2c_result_t state = ldc1612_write_register(SENSOR_RESET_REG, LDC1612_RESET_DEV);
    return (state == I2C_RESULT_SUCCESS) ? LDC1612_STATUS_SUCCESS : LDC1612_STATUS_ERROR;
}

ldc1612_status_t ldc1612_init(void) {
    i2c_result_t i2c_status;
    uint16_t manufacturer_id, device_id;

    /* reset LDC1612 sensor */
    i2c_status = ldc1612_reset_sensor();
    if (i2c_status != I2C_RESULT_SUCCESS) {
        return LDC1612_STATUS_ERROR;
    }

    delay_ms(100);

    manufacturer_id = ldc1612_get_manufacturer_id();
    device_id = ldc1612_get_deveice_id();

    if (manufacturer_id != 0x5449 || device_id != 0x3055) {
        return LDC1612_STATUS_ERROR;
    }

    return LDC1612_STATUS_SUCCESS;
}

/*!
    \brief      配置单通道模式
    \param[in]  channel: 通道号 (0或1)
    \param[out] none
    \retval     ldc1612_status_t
*/
ldc1612_status_t ldc1612_config_single_channel(uint8_t channel) {
    i2c_result_t status;

    if (channel > 1) {
        return LDC1612_STATUS_INVALID_PARAM;
    }

    /* 配置顺序严格按照TI官方文档要求 */
    
    /* Step 1: 确保传感器处于睡眠模式 - 配置前必须 */
    status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
    if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR;
    delay_ms(10);

    /* Step 2: 配置频率分频 - 必须在其他配置之前 */
    uint16_t freq_divider = ldc1612_calculate_freq_divider(channel);
    ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider);
    delay_ms(5);

    /* Step 3: 配置LC稳定时间 - 影响测量精度 */
    ldc1612_write_register(SET_SETTLECOUNT_REG_START + channel, LDC1612_SETTLECOUNT_CH0);

    /* Step 4: 配置转换时间 - 影响测量速度和精度 */
    ldc1612_write_register(SET_CONVERSION_TIME_REG_START + channel, LDC1612_RCOUNT_TIME_CH0);

    /* Step 5: 配置转换偏移 */
    ldc1612_write_register(SET_CONVERSION_OFFSET_REG_START + channel, SET_CONVERSION_OFFSET_CH0);

    /* Step 6: 配置驱动电流 - 影响传感器灵敏度 */
    ldc1612_write_register(SET_DRIVER_CURRENT_REG + channel, LDC1612_DRIVE_CURRENT);

    /* Step 7: 配置多路复用器 - 设置通道选择和滤波 */
    // ldc1612_configure_mux_register(LDC1612_MUX_AUTOSCAN_DISABLE, LDC1612_MUX_RR_SEQUENCE_0, LDC1612_MUX_FILTER_ALL_LOW, LDC1612_MUX_FILTER_NONE);
    ldc1612_write_register(MUX_CONFIG_REG, LDC1612_MUX_CONFIG);

    /* Step 8: 配置错误输出 */
    ldc1612_write_register(ERROR_CONFIG_REG, LDC1612_ERROR_CONFIG_DEFAULT);

    /* Step 9: 最后启动传感器 - 必须最后一步 */
    status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0);
    if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR;
    
    /* Step 10: 等待传感器稳定 */
    delay_ms(50);

    return LDC1612_STATUS_SUCCESS;
}

/** @brief read the raw channel result from register.
    @param channel LDC1612 has total two channels.
    @param result raw data
 * */
uint32_t ldc1612_get_raw_channel_result(uint8_t channel) {
    uint32_t raw_value = 0;
    uint8_t value[2] = {0};

    /* Read MSW */
    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, CONVERSION_RESULT_REG_START + (channel * 2), value);
    raw_value |= (uint32_t)(((uint16_t)value[0] << 8) | value[1]) << 16;

    /* Read LSW */
    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, CONVERSION_RESULT_REG_START + 1 + (channel * 2), value);
    raw_value |= (uint32_t)(((uint16_t)value[0] << 8) | value[1]);

    
    uint32_t calibration_value = raw_value & 0x0FFFFFFF;
    if (calibration_value == 0x0FFFFFFF) {
        return 0xF0000000; /* No coil */
    }
    if (LDC1612_ERROR_CONFIG_DEFAULT & 0xF800) {
        uint8_t error_code = (uint8_t)(raw_value >> 24);
        if (error_code & 0x80) return 0x80000000; /* Under range */
        if (error_code & 0x40) return 0x40000000; /* Over range */
        if (error_code & 0x20) return 0x20000000; /* Watchdog */
        if (error_code & 0x10) return 0x10000000; /* Amplitude error */
    }
    
    return raw_value;
}


void ldc1612_drvie_current_detect(uint8_t channel) {
    uint8_t data[2] = {0};
    uint16_t init_value = 0 , drive_current = 0;

    ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
    delay_ms(10);
    
    uint16_t freq_divider = ldc1612_calculate_freq_divider(channel);
    ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider);
    delay_ms(5);

    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SENSOR_CONFIG_REG, data);
    // ldc1612_set_sensor_config(LDC1612_SLEEP_MODE);
    ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
    delay_ms(10);
    ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0);
    delay_ms(10);
    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SET_DRIVER_CURRENT_REG, data);

    init_value = (((data[0] << 8) | data[1]) >> 6) & 0x1F;
    drive_current = (init_value << 11) | 0x0000;
    LDC1612_DEBUG("init value: 0x%x\tdrive current: 0x%x\n", init_value, drive_current);
}

/** @brief Get sensor status register
    @return Status register value
 * */
uint16_t ldc1612_get_sensor_status(void) {
    uint8_t data[2] = {0};
    LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SENSOR_STATUS_REG, data);
    return (data[0] << 8) | data[1];
}

/** @brief Check if data is ready for specific channel
    @param channel Channel to check (0 or 1)
    @return true if data is ready, false otherwise
 * */
bool ldc1612_is_data_ready(uint8_t channel) {
    uint16_t status = ldc1612_get_sensor_status();
    if (channel == 0) {
        return (status & 0x0040) != 0; // DRDY_0 bit
    } else if (channel == 1) {
        return (status & 0x0080) != 0; // DRDY_1 bit
    }
    return false;
}

/*!
    \brief      检查并记录LDC1612的状态和错误
    \param[in]  none
    \param[out] none
    \retval     读取到的原始状态寄存器值
*/
uint16_t ldc1612_check_status_and_log_errors(void) {
    uint16_t status;
    i2c_result_t i2c_status = ldc1612_read_register(SENSOR_STATUS_REG, &status);

    if (i2c_status != I2C_RESULT_SUCCESS) {
        LDC1612_DEBUG("Failed to read STATUS register!");
        return 0;
    }

    LDC1612_DEBUG("--- LDC1612 Status Check (Value: 0x%04X) ---", status);

    // 检查数据就绪状态
    if (status & LDC1612_STATUS_DRDY) {
        LDC1612_DEBUG("  [OK] Data is ready.");
    }
    if (status & LDC1612_STATUS_UNREAD_CH0) {
        LDC1612_DEBUG("  [INFO] Channel 0 has unread data.");
    }
    if (status & LDC1612_STATUS_UNREAD_CH1) {
        LDC1612_DEBUG("  [INFO] Channel 1 has unread data.");
    }

    // 检查是否有任何错误标志
    if ((status & 0x3F00) == 0) { // 检查所有错误位的掩码
        LDC1612_DEBUG("  [OK] No errors detected.");
    } else {
        uint8_t err_chan = (status & LDC1612_STATUS_ERR_CHAN_MASK) >> 14;
        LDC1612_DEBUG("  [ERROR] An error occurred on Channel %d.", err_chan);

        if (status & LDC1612_STATUS_ERR_UR) {
            LDC1612_DEBUG("    - Underflow Error: Conversion result is less than OFFSET.");
        }
        if (status & LDC1612_STATUS_ERR_OR) {
            LDC1612_DEBUG("    - Overflow Error: Conversion result is at maximum.");
        }
        if (status & LDC1612_STATUS_ERR_WD) {
            LDC1612_DEBUG("    - Watchdog Timeout: Sensor failed to complete conversion in time.");
        }
        if (status & LDC1612_STATUS_ERR_AHE) {
            LDC1612_DEBUG("    - Amplitude High Error: Sensor oscillation amplitude > 1.8V.");
        }
        if (status & LDC1612_STATUS_ERR_ALE) {
            LDC1612_DEBUG("    - Amplitude Low Error: Sensor oscillation amplitude < 1.2V.");
        }
        if (status & LDC1612_STATUS_ERR_ZC) {
            LDC1612_DEBUG("    - Zero-Count Error: Reference count is zero, check clock.");
        }
    }
    LDC1612_DEBUG("-------------------------------------------------");

    // 读取STATUS寄存器会自动清除错误标志，但不会清除DRDY和UNREADCONV标志
    return status;
}