#include "bsp_ina228.h"

/**
 * @brief       集成电流传感器 INA228 & INA238
 * @author      yingbo.tang
 * @date        2026.10.02
 * @version     V1.3
 * @details		
 * 		V1.0	2025.07.27	首版INA228驱动开发；
 * 		V1.1	2025.09.06	增加INA238驱动自适应；
 * 		V1.2	2026.02.27	驱动接口增加I2C结果判定，避免I2C忙碌时刻返回异常值；
 * 		V1.3	2026.10.02	完善芯片识别与初始化失败处理, 修正CHARGE符号与INA238温度解析,
 * 		                    增加ADC量程自动选择, 优化ADC转换时间分配；
 */

// 寄存器地址长度
static const uint8_t ina228_reg_size[MAX_REG_ADDRESS + 1] = 
{
    2, 2, 2, 2, 3, 3, 2, 3,     \
    3, 5, 5, 2, 2, 2, 2, 2,     \
    2, 2, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 2, 2
};

// 寄存器地址长度
static const uint8_t ina238_reg_size[MAX_REG_ADDRESS + 1] = 
{
    2, 2, 2, 0, 2, 2, 2, 2,     \
    3, 0, 0, 2, 2, 2, 2, 2,     \
    2, 2, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 0, 0,     \
    0, 0, 0, 0, 0, 0, 2, 2
};

static uint32_t ina_bytes_to_u32(uint8_t *p_buf, uint8_t len)
{
    uint32_t val = 0U;

    if (len > 4U)	{len = 4U;}

	// 字段组合
    for (uint8_t i = 0; i < len; i++)
    {
        val = (val << 8) | p_buf[i];
    }

    return val;
}

/**
 * @brief       浮点值转寄存器无符号值
 * @param [in]  value               浮点值
 * @param [in]  max                 寄存器允许的最大值
 * @param [out] none
 * @retval      限幅[0, max]并四舍五入后的整数值
 */
static uint16_t ina_float_to_u16(float value, uint16_t max)
{
    // 先在float中限幅再转换, 避免超出整数范围时转换为未定义行为
    if (value <= 0.0f)
    {
        return 0U;
    }
    if (value >= (float)max)
    {
        return max;
    }

    return (uint16_t)(value + 0.5f);
}

/**
 * @brief       INA228向指定寄存器地址写入数据
 * @param [in]  p_bsp_ina228		INA228结构体指针
 * @param [in]  reg_addr            寄存器地址
 * @param [in]  value               写入数值
 * @param [out] none
 * @retval		返回结果			1-失败，0-成功
 */
static uint8_t ina228_write_reg(p_bsp_ina228_t p_bsp_ina228, uint8_t reg_addr, uint16_t value)
{
    uint8_t tx_buf[2] = {0};
    uint8_t i;

    tx_buf[0] = MSB_U16(value);
    tx_buf[1] = LSB_U16(value);

    // 写入寄存器固定长度为2, 失败最多重试3次
    for (i = 0; i < 3; i++)
    {
        xh_i2c_set_slave_addr(p_bsp_ina228->i2c_dev_id, p_bsp_ina228->dev_addr);
        if (xh_i2c_write(p_bsp_ina228->i2c_dev_id, tx_buf, reg_addr, 2) == 0U)
        {
            return 0U;
        }
    }

    return 1U;
}

/**
 * @brief       INA228向指定寄存器地址读取数据
 * @param [in]  p_bsp_ina228		INA228结构体指针
 * @param [in]  reg_addr			寄存器地址
 * @param [out] p_buf				INA228读取返回数据
 * @param [out] p_len				INA228读取返回值长度
 * @retval		返回结果			1-失败，0-成功
 */
static uint8_t ina228_read_reg(p_bsp_ina228_t p_bsp_ina228, uint8_t reg_addr, uint8_t *p_buf, uint8_t *p_len)
{
    if ((p_bsp_ina228 == NULL)
    || (p_buf == NULL)
    || (p_len == NULL)
    || (reg_addr > MAX_REG_ADDRESS)
    || (p_bsp_ina228->chip_type == CHIP_TYPE_UNKNOWN))
    {
        return 1U;
    }

	/* 根据芯片型号查寄存器长度 */
    uint8_t reg_length = (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? 
						ina238_reg_size[reg_addr] : ina228_reg_size[reg_addr];

    /* 长度合法性检查（INA228最大5字节） */
    if ((reg_length == 0U) || (reg_length > 5U))
    {
        return 1U;
    }

	xh_i2c_set_slave_addr(p_bsp_ina228->i2c_dev_id, p_bsp_ina228->dev_addr);
    if (xh_i2c_read(p_bsp_ina228->i2c_dev_id, p_buf, reg_addr, reg_length) != 0U)
	{
		return 1U;
	}

	*p_len = reg_length;

    return 0U;
}

/**
 * @brief       芯片识别
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] none
 * @retval      返回结果            1-失败(chip_type置为CHIP_TYPE_UNKNOWN)，0-成功
 * @details     连续尝试3次, I2C读取失败的那次不参与判断;
 *              DEVICE_ID只比较DIEID(bit15~4), 忽略芯片版本号, 避免芯片改版后无法识别.
 */
static uint8_t bsp_chip_identify(p_bsp_ina228_t p_bsp_ina228)
{
    uint8_t rx_buf[2] = {0};
    uint16_t manufacturer_id;
    uint16_t device_id;
    uint8_t i;

    p_bsp_ina228->chip_type = CHIP_TYPE_UNKNOWN;

    for (i = 0; i < 3; i++)
    {
        xh_i2c_set_slave_addr(p_bsp_ina228->i2c_dev_id, p_bsp_ina228->dev_addr);
        if (xh_i2c_read(p_bsp_ina228->i2c_dev_id, rx_buf, INA228_REG_MANUFACTURER_ID, 2) != 0U)
        {
            continue;
        }
        manufacturer_id = (rx_buf[0] << 8) | rx_buf[1];

        xh_i2c_set_slave_addr(p_bsp_ina228->i2c_dev_id, p_bsp_ina228->dev_addr);
        if (xh_i2c_read(p_bsp_ina228->i2c_dev_id, rx_buf, INA228_REG_DEVICE_ID, 2) != 0U)
        {
            continue;
        }
        device_id = ((rx_buf[0] << 8) | rx_buf[1]) & INA2X8_DIE_ID_MASK;

        // 通过厂商和设备ID识别具体芯片
        if (manufacturer_id == INA228_DEF_MANUFACTURER_ID)
        {
            if (device_id == (INA228_DEF_DEVICE_ID & INA2X8_DIE_ID_MASK))
            {
                p_bsp_ina228->chip_type = CHIP_TYPE_INA228;
                return 0U;
            }
            else if (device_id == (INA238_DEF_DEVICE_ID & INA2X8_DIE_ID_MASK))
            {
                p_bsp_ina228->chip_type = CHIP_TYPE_INA238;
                return 0U;
            }
        }
    }

    return 1U;
}

/**
 * @brief       电流LSB计算
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] none            
 * @retval      none
 */
static void bsp_current_lsb_calcu(p_bsp_ina228_t p_bsp_ina228)
{
    float current_lsb;

    current_lsb = p_bsp_ina228->max_curr_ma / 1000.0f;
    current_lsb /= (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? INA238_CURRENT_LSB_DIV : INA228_CURRENT_LSB_DIV;

    p_bsp_ina228->current_lsb = current_lsb;
}

/**
 * @brief       计算满量程分流电压
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] none
 * @retval      最大电流在分流器上产生的电压 单位: mV
 */
static float ina_full_scale_shunt_mv(p_bsp_ina228_t p_bsp_ina228)
{
    // mA x mΩ / 1000 = mV
    return p_bsp_ina228->max_curr_ma * p_bsp_ina228->shunt_mohm / 1000.0f;
}

/**
 * @brief       INA228参数适配
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  first_init          首次初始化标志, 1-首次
 * @param [out] none            
 * @retval      none
 */
static void ina228_param_cfg(p_bsp_ina228_t p_bsp_ina228, uint8_t first_init)
{
    float value;
    uint16_t reg_val;

    // 配置寄存器
    p_bsp_ina228->reg_config.all = INA228_DEF_CONFIG;
    // 满量程分流电压不超过40.96mV时选小量程, 分辨率高4倍, 否则选163.84mV量程
    p_bsp_ina228->reg_config.bits.adcrange      = (ina_full_scale_shunt_mv(p_bsp_ina228) <= INA2X8_ADC_RANGE1_MAX_MV)
                                                ? 0x01 : 0x00;  // 0h = ±163.84mV 1h = ±40.96mV
    p_bsp_ina228->reg_config.bits.tempconmp     = 0x00;         // 0h = 禁用分流温度补偿 1h = 启用分流温度补偿
    p_bsp_ina228->reg_config.bits.convdly       = 0x00;         // 0h = 0s 1h = 2ms FFh = 510ms
    // 仅首次初始化清零ENERGY/CHARGE累计值, 过程中调用不清零, INA238该位为保留位, 不置位
    p_bsp_ina228->reg_config.bits.rstacc        = ((first_init != 0U) && (p_bsp_ina228->chip_type == CHIP_TYPE_INA228))
                                                ? 0x01 : 0x00;  // 0h = 正常运行 1h = Energy和Charge寄存器清除为默认值
    p_bsp_ina228->reg_config.bits.rst           = 0x00;         // 0h = 正常运行 1h = 系统复位将寄存器设置为默认值
    
    // ADC配置寄存器
    p_bsp_ina228->reg_adc_config.all = INA228_DEF_ADC_CONFIG;
    p_bsp_ina228->reg_adc_config.bits.avg       = 0x02;         // 0h = 1 1h = 4 2h = 16 3h = 64 4h = 128 5h = 256 6h = 512 7h = 1024
    p_bsp_ina228->reg_adc_config.bits.vtct      = 0x04;         // 0h = 50us 1h = 84us 2h = 150us 3h = 280us 4h = 540us 5h = 1052us 6h = 2074us 7h = 4120us
    p_bsp_ina228->reg_adc_config.bits.vshct     = 0x06;         // 0h = 50us 1h = 84us 2h = 150us 3h = 280us 4h = 540us 5h = 1052us 6h = 2074us 7h = 4120us
    p_bsp_ina228->reg_adc_config.bits.vbusct    = 0x04;         // 0h = 50us 1h = 84us 2h = 150us 3h = 280us 4h = 540us 5h = 1052us 6h = 2074us 7h = 4120us
    p_bsp_ina228->reg_adc_config.bits.mode      = 0x0F;         // Fh = 连续转换,总线电压分流电压和温度

    // 分流校准寄存器
    p_bsp_ina228->reg_shunt_cal.all = INA228_DEF_SHUNT_CAL;
    float shunt_constant = (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? INA238_SHUNT_CONSTANT : INA228_SHUNT_CONSTANT;
    value = p_bsp_ina228->current_lsb * shunt_constant * p_bsp_ina228->shunt_mohm / 1000.0f;
    value *= (p_bsp_ina228->reg_config.bits.adcrange == 0x01) ? 4.0f : 1.0f;
    p_bsp_ina228->reg_shunt_cal.bits.shunt_cal  = ina_float_to_u16(value, 0x7FFF);

    // 分流温度系数寄存器(未使用, INA238无该字段)
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA228)
    {
        p_bsp_ina228->reg_shunt_tempco.all = INA228_DEF_SHUNT_TEMPCO;
    }

    // 诊断标志和警报寄存器
    p_bsp_ina228->reg_diag_alert.all = INA228_DEF_DIAG_ALRT;
    p_bsp_ina228->reg_diag_alert.bits.alatch  = 0x00;           // 故障产生后是否锁存, 等待读取DIAG_ALRT后恢复 0h = 透明 1h = 锁存

    // 分流过压阈值寄存器
    p_bsp_ina228->reg_sovl = INA228_DEF_SOVL;
    value = p_bsp_ina228->shunt_dir ? p_bsp_ina228->chg_ocp_thresh : p_bsp_ina228->dsg_ocp_thresh;
    if (value != 0.0f)
    {
        value = fabsf(value) * p_bsp_ina228->shunt_mohm; 
        value /= (p_bsp_ina228->reg_config.bits.adcrange == 0x01) ? 1.0f : 4.0f;
        value /= (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? INA238_SOVL_UNIT_UV_LSB : INA228_SOVL_UNIT_UV_LSB;
        
        // 二进制补码正数, 最大0x7FFF
        p_bsp_ina228->reg_sovl = ina_float_to_u16(value, INA228_DEF_SOVL);
    }

    // 分流欠压阈值寄存器
    p_bsp_ina228->reg_suvl = INA228_DEF_SUVL;
    value = p_bsp_ina228->shunt_dir ? p_bsp_ina228->dsg_ocp_thresh : p_bsp_ina228->chg_ocp_thresh;
    if (value != 0.0f)
    {
        value = fabsf(value) * p_bsp_ina228->shunt_mohm; 
        value /= (p_bsp_ina228->reg_config.bits.adcrange == 0x01) ? 1.0f : 4.0f;
        value /= (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? INA238_SUVL_UNIT_UV_LSB : INA228_SUVL_UNIT_UV_LSB;

        // 二进制补码负数: 绝对值最大0x8000(-32768), 取反得到寄存器的无符号值
        reg_val = ina_float_to_u16(value, INA228_DEF_SUVL);
        p_bsp_ina228->reg_suvl = (uint16_t)(0U - (uint32_t)reg_val);
    }

    // 总线过压阈值寄存器
    p_bsp_ina228->reg_bovl.all = INA228_DEF_BOVL;
    if (p_bsp_ina228->bus_ovp_thresh > 0)
    {
        float bovl_lsb = (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? INA238_BOVL_UNIT_MV_LSB : INA228_BOVL_UNIT_MV_LSB;
        value = p_bsp_ina228->bus_ovp_thresh / bovl_lsb;
        p_bsp_ina228->reg_bovl.bits.bovl = ina_float_to_u16(value, 0x7FFF);
    }

    // 总线欠压阈值寄存器
    p_bsp_ina228->reg_buvl.all = INA228_DEF_BUVL;
    if (p_bsp_ina228->bus_uvp_thresh > 0)
    {
        float buvl_lsb = (p_bsp_ina228->chip_type == CHIP_TYPE_INA238) ? INA238_BUVL_UNIT_MV_LSB : INA228_BUVL_UNIT_MV_LSB;
        value = p_bsp_ina228->bus_uvp_thresh / buvl_lsb;
        p_bsp_ina228->reg_buvl.bits.buvl = ina_float_to_u16(value, 0x7FFF);
    }

    // 温度超限阈值寄存器
    p_bsp_ina228->reg_temp_limit = INA228_DEF_TEMP_LIMIT;
    if (p_bsp_ina228->dev_otp_thresh > 0)
    {
        if (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)
        {
            // 12位有效值在bit15~4, 先限幅再左移
            value = p_bsp_ina228->dev_otp_thresh * 1000.0f / INA238_TOL_UNIT_MC_LSB;
            p_bsp_ina228->reg_temp_limit = (uint16_t)(ina_float_to_u16(value, INA238_TOL_MAX) << INA238_TEMP_SHIFT);
        }
        else
        {
            value = p_bsp_ina228->dev_otp_thresh * 1000.0f / INA228_TOL_UNIT_MC_LSB;
            p_bsp_ina228->reg_temp_limit = ina_float_to_u16(value, INA228_DEF_TEMP_LIMIT);
        }
    }

    // 功率超限阈值寄存器
    p_bsp_ina228->reg_pwr_limit = INA228_DEF_PWR_LIMIT;
    if (p_bsp_ina228->over_pwr_thresh > 0)
    {
        float power_coeff = (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)   \
                        ? (INA238_POL_UNIT_W_LSB * INA238_POWER_CONSTANT)   \
                        : (INA228_POL_UNIT_W_LSB * INA228_POWER_CONSTANT);
        value = p_bsp_ina228->over_pwr_thresh / p_bsp_ina228->current_lsb / power_coeff;
        p_bsp_ina228->reg_pwr_limit = ina_float_to_u16(value, INA228_DEF_PWR_LIMIT);
    }
}

/**
 * @brief       INA228初始化
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] none            
 * @retval      none
 */
void ina228_init(p_bsp_ina228_t p_bsp_ina228)
{
    uint8_t first_init = 0U;
    uint8_t ret = 0U;
    float shunt_mv;

    if (p_bsp_ina228 == NULL)   {return;}

    // 芯片识别仅在首次初始化时执行, 识别失败后不再重试
    if (p_bsp_ina228->ident_done == 0U)
    {
        p_bsp_ina228->ident_done = 1U;
        first_init = 1U;
        (void)bsp_chip_identify(p_bsp_ina228);
    }

    // 识别失败不写任何配置, 之后所有读取接口均返回失败, 上层据此判断初始化失败
    if (p_bsp_ina228->chip_type == CHIP_TYPE_UNKNOWN)
    {
        return;
    }

    // 满量程分流电压超出ADC最大量程时电流读数会饱和失真, 参数非法(<=0)时无法计算, 均按初始化失败处理,
    // 过程中调用set_shunt_mohm/set_max_curr_ma触发时同样处理, 之后所有读取接口均返回失败
    shunt_mv = ina_full_scale_shunt_mv(p_bsp_ina228);
    if (!((shunt_mv > 0.0f) && (shunt_mv <= INA2X8_ADC_RANGE0_MAX_MV)))
    {
        p_bsp_ina228->chip_type = CHIP_TYPE_UNKNOWN;
        return;
    }

    // 每次初始化都重新计算CURRENT_LSB, 以便set_max_curr_ma生效
    bsp_current_lsb_calcu(p_bsp_ina228);

    // 参数初始化
    ina228_param_cfg(p_bsp_ina228, first_init);

    // 参数写入
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_CONFIG,       p_bsp_ina228->reg_config.all        );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_ADC_CONFIG,   p_bsp_ina228->reg_adc_config.all    );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_SHUNT_CAL,    p_bsp_ina228->reg_shunt_cal.all     );
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA228)
    {
        ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_SHUNT_TEMPCO, p_bsp_ina228->reg_shunt_tempco.all  );
    }
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_DIAG_ALRT,    p_bsp_ina228->reg_diag_alert.all    );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_SOVL,         p_bsp_ina228->reg_sovl              );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_SUVL,         p_bsp_ina228->reg_suvl              );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_BOVL,         p_bsp_ina228->reg_bovl.all          );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_BUVL,         p_bsp_ina228->reg_buvl.all          );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_TEMP_LIMIT,   p_bsp_ina228->reg_temp_limit        );
    ret |= ina228_write_reg(p_bsp_ina228, INA228_REG_PWR_LIMIT,    p_bsp_ina228->reg_pwr_limit         );

    // 首次初始化写入失败按初始化失败处理, 与识别失败一致, 之后所有读取接口均返回失败
    if ((ret != 0U) && (first_init != 0U))
    {
        p_bsp_ina228->chip_type = CHIP_TYPE_UNKNOWN;
    }
}

/**
 * @brief       INA228设置分流器阻值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               分流器阻值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_shunt_mohm(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->shunt_mohm = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置最大期望电流值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               最大期望电流值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_max_curr_ma(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->max_curr_ma = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置充电过流阈值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               充电过流阈值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_chg_ocp_thresh(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->chg_ocp_thresh = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置放电过流阈值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               放电过流阈值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_dsg_ocp_thresh(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->dsg_ocp_thresh = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置总线过压阈值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               总线过压阈值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_bus_ovp_thresh(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->bus_ovp_thresh = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置总线欠压阈值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               总线欠压阈值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_bus_uvp_thresh(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->bus_uvp_thresh = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置设备过温阈值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               设备过温阈值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_dev_otp_thresh(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->dev_otp_thresh = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228设置过功率阈值
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [in]  value               过功率阈值
 * @param [out] none            
 * @retval      none
 */
void ina228_set_over_pwr_thresh(p_bsp_ina228_t p_bsp_ina228, float value)
{
    if (p_bsp_ina228 == NULL)   {return;}

    p_bsp_ina228->over_pwr_thresh = value;
    ina228_init(p_bsp_ina228);
}

/**
 * @brief       INA228读取分流器电压
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				分流器电压值
 * @retval		返回结果			1-失败，0-成功         
 */
uint8_t ina228_get_vshunt_mv(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_VSHUNT, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

    float data;
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)
    {
        // 二进制补码, 有符号
        data = (value > 0x7FFF) ? ((float)value - 0x10000) : ((float)value);
        // uV转换为mV
        if (p_bsp_ina228->reg_config.bits.adcrange == 0x01)
        {
            data = (float)((data * INA238_VSHUNT_UNIT_UV_LSB_ADC1) / 1000.0f);
        }
        else
        {
            data = (float)((data * INA238_VSHUNT_UNIT_UV_LSB_ADC0) / 1000.0f);
        }
    }
    else
    {
        // bit4 ~ bit23有效值, bit0 ~ bit3保留为0
        value = value >> 4;
        // 二进制补码, 有符号
        data = (value > 0x7FFFF) ? ((float)value - 0x100000) : ((float)value);
        // nV转换为mV
        if (p_bsp_ina228->reg_config.bits.adcrange == 0x01)
        {
            data = (float)((data * INA228_VSHUNT_UNIT_NV_LSB_ADC1) / 1000000.0f);
        }
        else
        {
            data = (float)((data * INA228_VSHUNT_UNIT_NV_LSB_ADC0) / 1000000.0f);
        }
    }

    if (p_bsp_ina228->shunt_dir == 0)
    {
        data = data * (-1.0f);
    }

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取总线电压
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				总线电压值
 * @retval		返回结果			1-失败，0-成功
 */
uint8_t ina228_get_vbus_mv(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_VBUS, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

    float data;
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)
    {
        // 二进制补码, 有符号
        data = (value > 0x7FFF) ? ((float)value - 0x10000) : ((float)value);
        // 转换为mV
        data = data * INA238_VBUS_UNIT_MV_LSB;
    }
    else
    {
        // bit4 ~ bit23有效值, bit0 ~ bit3保留为0
        value = value >> 4;
        // 二进制补码, 有符号
        data = (value > 0x7FFFF) ? ((float)value - 0x100000) : ((float)value);
        // uV转换为mV
        data = (data * INA228_VBUS_UNIT_UV_LSB) / 1000.0f;
    }

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取温度
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				温度值
 * @retval		返回结果			1-失败，0-成功         
 */
uint8_t ina228_get_dietemp_c(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_DIETEMP, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

    float data;
    // 二进制补码, 有符号
    if (value > 0x7FFF)
    {
        data = (float)value - 0x10000;
    }
    else
    {
        data = (float)value;
    }

    // mC转换为C
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)
    {
        // 12位有效值在bit15~4, bit3~0恒为0, 16位有符号值除以16即为精确的12位补码值
        data = data / (float)(1U << INA238_TEMP_SHIFT);
        data = (data * INA238_DIETEMP_UNIT_MC_LSB) / 1000.0f;
    }
    else
    {
        data = (data * INA228_DIETEMP_UNIT_MC_LSB) / 1000.0f;
    }

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取电流
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				电流值
 * @retval		返回结果			1-失败，0-成功         
 */
uint8_t ina228_get_current_ma(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_CURRENT, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

    float data;
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)
    {
        // 二进制补码, 有符号
        data = (value > 0x7FFF) ? ((float)value - 0x10000) : ((float)value);
        // 转换为mA
        data = data * p_bsp_ina228->current_lsb * 1000.0f;  
    }
    else
    {
        // bit4 ~ bit23有效值, bit0 ~ bit3保留为0
        value = value >> 4;
        // 二进制补码, 有符号
        data = (value > 0x7FFFF) ? ((float)value - 0x100000) : ((float)value);
        // 转换为mA
        data = data * p_bsp_ina228->current_lsb * 1000.0f;  
    }

    if (p_bsp_ina228->shunt_dir == 0)
    {
        data = data * (-1.0f);
    }

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取功率
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				功率值
 * @retval		返回结果			1-失败，0-成功
 */
uint8_t ina228_get_power_w(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_POWER, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

	float data;
    if (p_bsp_ina228->chip_type == CHIP_TYPE_INA238)
    {
        data = (float)(value * p_bsp_ina228->current_lsb * INA238_POWER_CONSTANT);
    }
    else
    {
        data = (float)(value * p_bsp_ina228->current_lsb * INA228_POWER_CONSTANT);
    }

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取电能
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				电能值, 单位: J (Wh = J / 3600)
 * @retval		返回结果			1-失败，0-成功
 * @details
 *      1. 累计值, 非瞬时值: 芯片每次转换后由硬件自动累加 功率 x 时间, 读取不清零;
 *         上电、CONFIG.RST、CONFIG.RSTACC 时清零;
 *      2. 无符号, 只增不减: 累加的 POWER 寄存器为无符号数(始终为正),
 *         充电和放电都会使其增加, 表示总吞吐能量而非净能量, 无法区分充放电方向;
 *         如需分别统计充电/放电能量, 需软件按电流方向自行积分;
 *      3. 寄存器为40位, 换算: Energy[J] = ENERGY x 16 x 3.2 x CURRENT_LSB;
 *         溢出时 DIAG_ALRT.ENERGYOF 置1;
 *      4. INA238无该寄存器, 返回失败.
 */
uint8_t ina228_get_energy_j(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_ENERGY, rx_buf, &len) != 0)
	{
		return 1U;
	}

    // 无符号; 为避免引入64位运算, 40位拆为 高16位(bit39~24) x 2^24 + 低24位(bit23~0),
    // 原始计数 < 2^24 时精确, 超出后受float 24位有效位限制丢失低位, 相对误差约 6e-8,
    uint32_t hi = ina_bytes_to_u32(&rx_buf[0], 2);
    uint32_t lo = ina_bytes_to_u32(&rx_buf[2], 3);

	float data = ((float)hi * 16777216.0f + (float)lo)
               * p_bsp_ina228->current_lsb * INA228_POWER_CONSTANT * 16.0f;

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取电荷
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				电荷值, 单位: C (Ah = C / 3600)
 * @retval		返回结果			1-失败，0-成功
 * @details
 *      1. 累计值, 非瞬时值: 芯片每次转换后由硬件自动累加 电流 x 时间, 读取不清零;
 *         上电、CONFIG.RST、CONFIG.RSTACC 时清零;
 *      2. 有符号(二进制补码), 表示净电荷: 累加带符号的 CURRENT,
 *         结果 = 流入 - 流出, 可为负; 输出正负方向与 ina228_get_current_ma 一致(受 shunt_dir 影响);
 *         例: 先充10Ah再放3Ah, 结果为净7Ah;
 *      3. 寄存器为40位, 换算: Charge[C] = CHARGE x CURRENT_LSB;
 *         溢出时 DIAG_ALRT.CHARGEOF 置1;
 *      4. INA238无该寄存器, 返回失败.
 */
uint8_t ina228_get_charge_c(p_bsp_ina228_t p_bsp_ina228, float *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_CHARGE, rx_buf, &len) != 0)
	{
		return 1U;
	}

    // 二进制补码, 有符号; 为避免引入64位运算, 40位拆为 高16位(bit39~24, 有符号) x 2^24 + 低24位(bit23~0, 无符号),
    // |原始计数| < 2^24 时精确, 超出后受float 24位有效位限制丢失低位, 相对误差约 6e-8,
    int32_t  hi = (int32_t)ina_bytes_to_u32(&rx_buf[0], 2);
    uint32_t lo = ina_bytes_to_u32(&rx_buf[2], 3);
    if (hi > 0x7FFF)
    {
        hi -= 0x10000;
    }

    float data = ((float)hi * 16777216.0f + (float)lo) * p_bsp_ina228->current_lsb;

    if (p_bsp_ina228->shunt_dir == 0)
    {
        data = data * (-1.0f);
    }

	*p_data = data;

    return 0U;
}

/**
 * @brief       INA228读取诊断标志和警报
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				诊断标志值
 * @retval		返回结果			1-失败，0-成功
 */
uint8_t ina228_get_diag_alrt(p_bsp_ina228_t p_bsp_ina228, uint16_t *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_DIAG_ALRT, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

	*p_data = (uint16_t)value;

    return 0U;
}

/**
 * @brief       INA228读取制造商ID
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				制造商ID值
 * @retval		返回结果			1-失败，0-成功
 */
uint8_t ina228_get_manu_id(p_bsp_ina228_t p_bsp_ina228, uint16_t *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_MANUFACTURER_ID, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

	*p_data = (uint16_t)value;

    return 0U;
}

/**
 * @brief       INA228读取器件ID
 * @param [in]  p_bsp_ina228        INA228结构体指针
 * @param [out] p_data				器件ID值
 * @retval		返回结果			1-失败，0-成功
 */
uint8_t ina228_get_device_id(p_bsp_ina228_t p_bsp_ina228, uint16_t *p_data)
{
    if ((p_bsp_ina228 == NULL) || (p_data == NULL))
    {
        return 1U;
    }

	uint8_t rx_buf[5] = {0};
	uint8_t len;
	if (ina228_read_reg(p_bsp_ina228, INA228_REG_DEVICE_ID, rx_buf, &len) != 0)
	{
		return 1U;
	}

	uint32_t value = ina_bytes_to_u32(rx_buf, len);

	*p_data = (uint16_t)value;

    return 0U;
}
