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

#include "ldc1612.h"

/** @brief set conversion interval time.
    @param channel LDC1612 has total two channels.
    @param result The value to be set.
 * */
void ldc1612_set_conversion_time(uint8_t channel, uint16_t result) {
    uint8_t data[2] = {0};
    data[0] = (result >> 8) & 0xFF;
    data[1] = result & 0xFF;
    i2c_write_16bits(LDC1612_ADDR, SET_CONVERSION_TIME_REG_START + channel, data);
}

/** @brief set conversion offset.
    @param channel LDC1612 has total two channels.
    @param result The value to be set.
 * */
void ldc1612_set_conversion_offset(uint8_t channel, uint16_t result) {
    uint8_t data[2] = {0};
    data[0] = (result >> 8) & 0xFF;
    data[1] = result & 0xFF;
    i2c_write_16bits(LDC1612_ADDR, SET_CONVERSION_OFFSET_REG_START + channel, data);
}

/** @brief Before conversion,wait LC sensor stabilize for a short time.
    @param channel LDC1612 has total two channels.
    @param result The value to be set.
 * */
void ldc1612_set_LC_stabilize_time(uint8_t channel, uint16_t result) {
    uint8_t data[2] = {0};
    data[0] = (result >> 8) & 0xFF;
    data[1] = result & 0xFF;
    i2c_write_16bits(LDC1612_ADDR, SET_LC_STABILIZE_REG_START + channel, data);
}

/** @brief set input frequency divide and fref divide.
    @param channel LDC1612 has total two channels.
    @param FIN_DIV FIN input divide
    @param FREF_DIV fref,reference frequency of sensor.
 * */
void ldc1612_set_freq_divide(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);

    fin_div = (uint16_t) (sensor_freq / 8.75 + 1);

    if (fin_div * 4 < 40) {
        freq_div = 2;
    } else {
        freq_div = 4;
    }

    value = fin_div << 12;
    value |= freq_div;
    // printf("\tvalue: 0x%x\r\n", value);

    uint8_t data[2] = {0};
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;
    // printf("\tFIN_DIV: %d, FREF_DIV: %d\r\n", fin_div, freq_div);

    i2c_write_16bits(LDC1612_ADDR, SET_FREQ_REG_START + channel, data);
}

/** @brief Error output config.
    @param result The value to be set.
 * */
void ldc1612_set_error_config(uint16_t value) {
    uint8_t data[2] = {0};
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;

    i2c_write_16bits(LDC1612_ADDR, ERROR_CONFIG_REG, data);
}

/** @brief mux  config.
    @param result The value to be set.
 * */
void ldc1612_set_mux_config(uint16_t value) {
    uint8_t data[2] = {0};
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;

    i2c_write_16bits(LDC1612_ADDR, MUL_CONFIG_REG, data);
}

/** @brief reset sensor.

 * */
void ldc1612_reset_sensor(void) {
    uint8_t data[2] = {0};
    data[0] = 0x80;
    data[1] = 0x00;
    i2c_write_16bits(LDC1612_ADDR, SENSOR_RESET_REG, data);
}

/** @brief set drive current of sensor.
    @param result The value to be set.
 * */
void ldc1612_set_drive_current(uint8_t channel, uint16_t value) {
    uint8_t data[2] = {0};
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;

    i2c_write_16bits(LDC1612_ADDR, SET_DRIVER_CURRENT_REG + channel, data);
}

/** @brief Main config part of sensor.Contains select channel、start conversion、sleep mode、sensor activation mode、INT pin disable ..
    @param result The value to be set.
 * */
void ldc1612_set_sensor_config(uint16_t value) {
    uint8_t data[2] = {0};
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;

    i2c_write_16bits(LDC1612_ADDR, SENSOR_CONFIG_REG, data);
}

void ldc1612_single_ch0_config(void) {
    ldc1612_set_freq_divide(CHANNEL_0); //0x14 --0x1002

    ldc1612_set_LC_stabilize_time(CHANNEL_0, LC_STABILIZE_TIME_CH0); //0x10 --0x001E

    ldc1612_set_conversion_time(CHANNEL_0, LDC1612_CONVERSION_TIME_CH0); //0x08 --0x0546

    ldc1612_set_error_config(LDC1612_ERROR_CONFIG); //0x19 --0x0000)

    ldc1612_set_drive_current(CHANNEL_0, LDC1612_DRIVE_CURRENT); //0x1E --0x9000

    ldc1612_set_mux_config(LDC1612_MUX_CONFIG); //0x1B --0x020C

    ldc1612_set_sensor_config(LDC1612_SENSOR_CONFIG); //0x1A --0x1601
}

void ldc1612_iic_get_sensor_infomation(void) {
    uint8_t data[2] = {0};
    // ldc1612_iic_read_16bits(READ_MANUFACTURER_ID, data);
    i2c_read_16bits(LDC1612_ADDR, READ_MANUFACTURER_ID, data);
    printf("\tManufacturer: 0x%x", (data[0] << 8) | data[1]);
    // ldc1612_iic_read_16bits(READ_DEVICE_ID, data);
    i2c_read_16bits(LDC1612_ADDR, READ_DEVICE_ID, data);
    printf("\tDevice: 0x%x", (data[0] << 8) | data[1]);
}

uint16_t ldc1612_get_manufacturer_id(void) {
    uint8_t data[2] = {0};
    i2c_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};
    i2c_read_16bits(LDC1612_ADDR, READ_DEVICE_ID, data);
    return (data[0] << 8) | data[1];
}

/** @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};

    // ldc1612_iic_read_16bits(CONVERTION_RESULT_REG_START + channel, value);
    i2c_read_16bits(LDC1612_ADDR, CONVERTION_RESULT_REG_START + channel, value);
    raw_value |= (uint32_t) ((value[0] << 8) | value[1]) << 16;
    // ldc1612_iic_read_16bits(CONVERTION_RESULT_REG_START + channel + 1, value);
    i2c_read_16bits(LDC1612_ADDR, CONVERTION_RESULT_REG_START + channel + 1, value);
    raw_value |= (uint32_t) ((value[0] << 8) | value[1]);
    return ldc1612_parse_raw_result(raw_value);
}

/** @brief parse the data which read from data register.
    @param channel LDC1612 has total two channels.
    @param raw_result the raw data which read from data register,it contains error codes and sensor value;
 * */
uint32_t ldc1612_parse_raw_result(uint32_t raw_result) {
    uint32_t calibration_value = 0;
    uint8_t error_code = 0;

    calibration_value = raw_result & 0x0FFFFFFF;
    if (0xFFFFFFF == calibration_value) {
        return 0xF0000000;
        // ERR_NC-No coil detected!!!
    }

    error_code = raw_result >> 24;

    if (error_code & 0x80) {
        return 0x80000000;
        // ERR_UR-Under range error!!!
    }
    if (error_code & 0x40) {
        return 0x40000000;
        // ERR_OR-Over range error!!!
    }
    if (error_code & 0x20) {
        return 0x20000000;
        // ERR_WD-Watch dog timeout error!!!
    }
    if (error_code & 0x10) {
        return 0x10000000;
        // ERR_AE-error!!!
    }

    return raw_result;
}
