#ifndef __bsp_ina228_H__
#define __bsp_ina228_H__

#include "stdint.h"
#include "math.h"
#include "reg_ina228.h"
#include "xf_frame.h"
#include "xh_i2c.h"

#define MSB_U16(val)                        (((val) & 0xFF00U) >> 8)
#define LSB_U16(val)                        ((val) & 0xFFU)

#define MAX_REG_ADDRESS                     (INA228_REG_DEVICE_ID)

// ADC量程上限(INA228与INA238相同) 单位: mV
#define INA2X8_ADC_RANGE0_MAX_MV            (163.84f)
#define INA2X8_ADC_RANGE1_MAX_MV            (40.96f)

/*  
    INA228计算公式
    SHUNT_CAL = 13107.2 x 10^6 x CURRENT_LSB x RSHUNT
    CURRENT_LSB = MAX_CURRENT / 2^19
    Current[A] = CURRENT_LSB x CURRENT
    Power[W] = 3.2 x CURRENT_LSB * POWER
*/
#define INA228_CURRENT_LSB_DIV              (524288)
// 必须为float字面量: 整数写法超出32位会成为long long, 运行时转float会引入64位库函数
#define INA228_SHUNT_CONSTANT               (13107.2e6f)
#define INA228_POWER_CONSTANT               (3.2f)
// INA228参数单位换算
#define INA228_VSHUNT_UNIT_NV_LSB_ADC0      (312.5f)
#define INA228_VSHUNT_UNIT_NV_LSB_ADC1      (78.125f)
#define INA228_VBUS_UNIT_UV_LSB             (195.3125f)
#define INA228_DIETEMP_UNIT_MC_LSB          (7.8125f)
#define INA228_SOVL_UNIT_UV_LSB             (1.25f)
#define INA228_SUVL_UNIT_UV_LSB             (1.25f)
#define INA228_BOVL_UNIT_MV_LSB             (3.125f)
#define INA228_BUVL_UNIT_MV_LSB             (3.125f)
#define INA228_TOL_UNIT_MC_LSB              (7.8125f)
#define INA228_POL_UNIT_W_LSB               (256.0f)

/*  
    INA238计算公式
    SHUNT_CAL = 819.2 x 10^6 x CURRENT_LSB x RSHUNT
    CURRENT_LSB = MAX_CURRENT / 2^15
    Current[A] = CURRENT_LSB x CURRENT
    Power[W] = 0.2 x CURRENT_LSB * POWER
*/
#define INA238_CURRENT_LSB_DIV              (32768)
#define INA238_SHUNT_CONSTANT               (819.2e6f)
#define INA238_POWER_CONSTANT               (0.2f)
// INA238参数单位换算
#define INA238_VSHUNT_UNIT_UV_LSB_ADC0      (5.0f)
#define INA238_VSHUNT_UNIT_UV_LSB_ADC1      (1.25f)
#define INA238_VBUS_UNIT_MV_LSB             (3.125f)
#define INA238_DIETEMP_UNIT_MC_LSB          (125.0f)
#define INA238_SOVL_UNIT_UV_LSB             (1.25f)
#define INA238_SUVL_UNIT_UV_LSB             (1.25f)
#define INA238_BOVL_UNIT_MV_LSB             (3.125f)
#define INA238_BUVL_UNIT_MV_LSB             (3.125f)
#define INA238_TOL_UNIT_MC_LSB              (125.0f)
// INA238的DIETEMP和TEMP_LIMIT: bit15~4为12位补码有效值, bit3~0保留为0
#define INA238_TEMP_SHIFT                   (4)
#define INA238_TOL_MAX                      (0x7FF)
#define INA238_POL_UNIT_W_LSB               (256.0f)

// DEVICE_ID寄存器: bit15~4为DIEID, bit3~0为芯片版本号REV_ID
#define INA2X8_DIE_ID_MASK                  (0xFFF0)

// UNKNOWN必须为0: 注册宏未初始化chip_type, 静态清零后即为未识别状态
typedef enum 
{
   CHIP_TYPE_UNKNOWN    = 0,
   CHIP_TYPE_INA228     = 1,
   CHIP_TYPE_INA238     = 2,
   CHIP_TYPE_MAX,
} chip_type_t;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t bit0_3     : 4;
        uint16_t adcrange   : 1;
        uint16_t tempconmp  : 1;
        uint16_t convdly    : 8;
        uint16_t rstacc     : 1;
        uint16_t rst        : 1;
    } bits;
} config_ut;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t avg        : 3;
        uint16_t vtct       : 3;
        uint16_t vshct      : 3;
        uint16_t vbusct     : 3;
        uint16_t mode       : 4;
    } bits;
} adc_config_ut;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t shunt_cal  : 15;
        uint16_t bit15      : 1;
    } bits;
} shunt_cal_ut;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t tempco     : 14;
        uint16_t bit15_16   : 2;
    } bits;
} shunt_tempco_ut;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t memstat    : 1;
        uint16_t cnvrf      : 1;
        uint16_t pol        : 1;
        uint16_t busul      : 1;

        uint16_t busol      : 1;
        uint16_t shntul     : 1;
        uint16_t shntol     : 1;
        uint16_t tmpol      : 1;

        uint16_t bit8       : 1;
        uint16_t mathof     : 1;
        uint16_t chargeof   : 1;
        uint16_t energyof   : 1;

        uint16_t apol       : 1;
        uint16_t slowalert  : 1;
        uint16_t cnvr       : 1;
        uint16_t alatch     : 1;
    } bits;
} diag_alrt_ut;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t bovl       : 15;
        uint16_t bit15      : 1;
    } bits;
} bovl_ut;

typedef union
{
    uint16_t all;
    struct
    {
        uint16_t buvl       : 15;
        uint16_t bit15      : 1;
    } bits;
} buvl_ut;

typedef struct _bsp_ina228_t
{
    void * const i2c_dev_id;            // I2C设备驱动ID
    uint8_t dev_addr;                   // 设备地址(必须写)
    uint8_t shunt_dir;                  // 分流器方向(写0默认放电时IN+为高电位, 写1为放电时IN+为低电位)
    float   shunt_mohm;                 // 分流器电阻值(必须写) 单位: mΩ, 与max_curr_ma乘积须在(0, 163840]内, 否则初始化失败
    float   max_curr_ma;                // 采样量程最大电流(必须写) 单位: mA
    float   chg_ocp_thresh;             // 充电过流阈值(写0默认无保护) 单位: mA
    float   dsg_ocp_thresh;             // 放电过流阈值(写0默认无保护) 单位: mA
    float   bus_ovp_thresh;             // 总线过压阈值(写0默认无保护) 单位: mV
    float   bus_uvp_thresh;             // 总线欠压阈值(写0默认无保护) 单位: mV
    float   dev_otp_thresh;             // 过温阈值(写0默认无保护) 单位: degC
    float   over_pwr_thresh;            // 过功率阈值(写0默认无保护) 单位: W

    config_ut reg_config;               // 配置寄存器
    adc_config_ut reg_adc_config;       // ADC配置寄存器
    shunt_cal_ut reg_shunt_cal;         // 分流校准寄存器
    shunt_tempco_ut reg_shunt_tempco;   // 分流温度系数寄存器
    diag_alrt_ut reg_diag_alert;        // 诊断标志和警报寄存器
    uint16_t reg_sovl;                  // 分流过压阈值寄存器
    uint16_t reg_suvl;                  // 分流欠压阈值寄存器
    bovl_ut reg_bovl;                   // 总压过压阈值寄存器
    buvl_ut reg_buvl;                   // 总压欠压阈值寄存器
    uint16_t reg_temp_limit;            // 温度高于上限阈值寄存器
    uint16_t reg_pwr_limit;             // 功率高于上限阈值寄存器

    float   current_lsb;                // 最大电流 / 2^19(INA228) 或 / 2^15(INA238) 单位: A/LSB
    chip_type_t chip_type;              // 芯片类型, 识别失败为CHIP_TYPE_UNKNOWN, 此时所有读写接口均返回失败
    uint8_t     ident_done;             // 芯片识别已执行标志, 仅首次初始化识别一次, 失败后不再重试
} bsp_ina228_t, *p_bsp_ina228_t;

#define REG_XH_BSP_INA228_WEAK() XH_INA228_WEAK_FUNC_DEF(ina228,p_bsp_ina228_t)
#define REG_XH_BSP_INA228(dev_id, prio, i2c_dev_id, dev_addr, shunt_dir, shunt_mohm, max_curr_ma,           \
        chg_ocp_thresh, dsg_ocp_thresh, bus_ovp_thresh, bus_uvp_thresh, dev_otp_thresh, over_pwr_thresh)    \
        bsp_ina228_t  _##dev_id =                                                                           \
        {                                                                                                   \
            XH_PTR_TYPE_DEV(i2c_dev_id),                                                                    \
            dev_addr,                                                                                       \
            shunt_dir,                                                                                      \
            shunt_mohm,                                                                                     \
            max_curr_ma,                                                                                    \
            chg_ocp_thresh,                                                                                 \
            dsg_ocp_thresh,                                                                                 \
            bus_ovp_thresh,                                                                                 \
            bus_uvp_thresh,                                                                                 \
            dev_otp_thresh,                                                                                 \
            over_pwr_thresh                                                                                 \
        };                                                                                                  \
        XH_REG_INA228_DRV_NEW(dev_id, &_##dev_id, prio, DEV_AUTO_INIT, ina228_init, NULL, ina228)

/* 初始化 */
extern void ina228_init(p_bsp_ina228_t p_bsp_ina228);

/* 设置分流器阻值 */
extern void ina228_set_shunt_mohm(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置最大期望电流值 */  
extern void ina228_set_max_curr_ma(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置充电过流阈值 */
extern void ina228_set_chg_ocp_thresh(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置放电过流阈值 */
extern void ina228_set_dsg_ocp_thresh(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置总线过压阈值 */
extern void ina228_set_bus_ovp_thresh(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置总线欠压阈值 */
extern void ina228_set_bus_uvp_thresh(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置设备过温阈值 */
extern void ina228_set_dev_otp_thresh(p_bsp_ina228_t p_bsp_ina228, float value);
/* 设置过功率阈值 */
extern void ina228_set_over_pwr_thresh(p_bsp_ina228_t p_bsp_ina228, float value);

/* 获取分流器电压值 */
extern uint8_t ina228_get_vshunt_mv(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取总线电压值 */
extern uint8_t ina228_get_vbus_mv(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取设备温度值 */
extern uint8_t ina228_get_dietemp_c(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取电流值 */
extern uint8_t ina228_get_current_ma(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取功率值 */
extern uint8_t ina228_get_power_w(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取电能值 */
extern uint8_t ina228_get_energy_j(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取电荷值 */
extern uint8_t ina228_get_charge_c(p_bsp_ina228_t p_bsp_ina228, float *p_data);
/* 获取诊断标志和警报 */
extern uint8_t ina228_get_diag_alrt(p_bsp_ina228_t p_bsp_ina228, uint16_t *p_data);
/* 获取制造商ID */
extern uint8_t ina228_get_manu_id(p_bsp_ina228_t p_bsp_ina228, uint16_t *p_data);
/* 获取器件ID */
extern uint8_t ina228_get_device_id(p_bsp_ina228_t p_bsp_ina228, uint16_t *p_data);

#endif //__bsp_ina228_H__
