/**
  *****************************************************************************
  * @file    sys_bat_intf.h
  * @author  Solution Team
  * @version V1.00
  * @date    28-February-2023
  * @brief   Battery interface
  *****************************************************************************
  * @attention 
  *  Copyright (c) 2017 - 2023 Unicmicro Co., Ltd. 
  *  All Rights Reserved. 
  *****************************************************************************
  */
 
#ifndef __SYS_BAT_INTF_H_
#define __SYS_BAT_INTF_H_


#include "sys_defs.h"
#include "libc.h"
#include "sc8815_reg_defs.h"
#include "drv_i2c.h"
#include "drv_timer.h"


#define SYS_BAT_PWR_CTRL_I2C        (DRV_I2C_ID_0)

/** Get register field */
#define SYS_BAT_REG_GET(reg)         drv_i2c_reg_get(SYS_BAT_PWR_CTRL_I2C,(u8_t)SYS_BAT_BASE_ADDR,(u8_t)reg)

/** Set register field */
#define SYS_BAT_REG_SET(reg,val)     drv_i2c_reg_set(SYS_BAT_PWR_CTRL_I2C,(u8_t)SYS_BAT_BASE_ADDR,(u8_t)reg,val)

/** Get register field */
#define SYS_BAT_REG_FIELD_GET(reg,field)   drv_i2c_reg_field_get2(SYS_BAT_PWR_CTRL_I2C,(u8_t)SYS_BAT_BASE_ADDR,(u8_t)reg,(u8_t)(reg##_##field),(u8_t)(reg##_##field##_FLDSET))

/** Set register field */
#define SYS_BAT_REG_FIELD_SET(reg,field,val) drv_i2c_reg_field_set2(SYS_BAT_PWR_CTRL_I2C,(u8_t)SYS_BAT_BASE_ADDR,(u8_t)reg,reg##_##field,reg##_##field##_FLDSET,(u8_t)reg##_##field##_FLDMSK,val)

/** Get register field with width */
#define SYS_BAT_REG_FIELD_GET2(reg,field,width)   drv_i2c_reg_field_get(SYS_BAT_PWR_CTRL_I2C,(u8_t)SYS_BAT_BASE_ADDR,(u8_t)reg,(u8_t)(reg##_##field),(u8_t)width)

/** Set register field with width */
#define SYS_BAT_REG_FIELD_SET2(reg,field,width,val)  drv_i2c_reg_field_set(SYS_BAT_PWR_CTRL_I2C, (u8_t)SYS_BAT_BASE_ADDR,(u8_t)reg,(u8_t)(reg##_##field),(u8_t)width,(u8_t)val)


// MAX CHARGE POWER (unit: mW)
#define SYS_BAT_MAX_CHARGE_POWER                    (100000UL)
#define SYS_BAT_MAX_CHARGE_VOLT                     (20000UL)

#define SYS_BAT_MAX_CHARGE_POWER_EPR                (140000UL)
#define SYS_BAT_MAX_CHARGE_VOLT_EPR                 (28000UL)

// MAX DISCHARGE POWER (unit: mW)
#define SYS_BAT_MAX_DISCHARGE_POWER                 (100000UL)

#define SYS_BAT_MAX_IBAT_CURRENT                    (12000)
#define SYS_BAT_MAX_IBUS_CURRENT                    (6000)
#define SYS_BAT_IBAT_CURRENT_150MA				    (150)
#define SYS_BAT_IBAT_CURRENT_0p2A				    (200)
#define SYS_BAT_IBAT_CURRENT_0p5A				    (500)
#define SYS_BAT_IBAT_CURRENT_1A					    (1000)


#define SYS_BAT_SC8815_CURRENT_MIN                  (300)

// VBUSREF_I, unit mV, VBUSREF_I_SET2=0b11
#define SYS_BAT_VBUSREF_I_SET_VAL_TO_REG(v)         ((((f32_t)(v))/25-4)/4)
#define SYS_BAT_VBUSREF_I_SET_REG_TO_VAL(v)         (((u16_t)(v)*4+1)*25)

#define SYS_BAT_VBUSREF_I_SET_VAL_TO_REG1(v)        ((v)<25?0:(((v)/25-1) >> 2))
#define SYS_BAT_VBUSREF_I_SET_VAL_TO_REG2(v)        ((v)<25?0:(((v)/25-1) & 0x3))


// VBUSREF_E, unit mV, VBUSREF_E_SET2=0b11
#define SYS_BAT_VBUSREF_E_SET_VAL_TO_REG1(v)        ((v)<31.4?0:((u32_t)((v)/31.4-1) >> 2))
#define SYS_BAT_VBUSREF_E_SET_VAL_TO_REG2(v)        ((v)<31.4?0:((u32_t)((v)/31.4-1) & 0x3))
#define SYS_BAT_VBUSREF_E_SET_REG_TO_VAL(v)         ((u32_t)31.4*(4*(v)+1))


/* IBUS, unit mA
 * IBUS_LIM (A) = ((IBUS_LIM_SET +1) / 256) * IBUS_RATIO * 10Ohm / RS1
 * 23.4375 = 256 / 6000
 */
#define SYS_BAT_IBUS_LIM_VAL_TO_REG(v)              ((v)<23.4375?0:(((double)(v))/23.4375-1))
#define SYS_BAT_IBUS_LIM_REG_TO_VAL(v)              ((((double)(v))+1)*23.4375)


// IBAT, unit mA
#define SYS_BAT_IBAT_LIM_VAL_TO_REG(v)              (((f32_t)(v))/12000U*256-1)
#define SYS_BAT_IBAT_LIM_REG_TO_VAL(v)              ((((f32_t)(v))+1)/256*12000U)


// VINREG, unit mV
#define SYS_BAT_VINREG_VAL_TO_REG(v)                (((u16_t)(v)/100-1))
#define SYS_BAT_VINREG_REG_TO_VAL(reg)              (((u16_t)(reg)+1)*100)


// VBUS_FB_VALUE, unit mV
#define SYS_BAT_VBUS_FB_REG_TO_VAL(reg1,reg2)       (((u16_t)(reg1)*4+(reg2)+1)*25)


// VBAT_FB_VALUE, unit mV
#define SYS_BAT_VBAT_FB_REG_TO_VAL(reg1,reg2)       (((u16_t)(reg1)*4+(reg2)+1)*25)


// IBUS_VALUE, unit mV
#define SYS_BAT_IBUS_REG_TO_VAL(reg1,reg2)          (((u16_t)(reg1)*4+(reg2)+1)*10)


// IBAT_VALUE, unit mV
#define SYS_BAT_IBAT_REG_TO_VAL(reg1,reg2)          (((u16_t)(reg1)*4+(reg2)+1)*20)


// ADIN_VALUE, unit mV
#define SYS_BAT_ADIN_REG_TO_VAL(reg1,reg2)          (((u16_t)(reg1)*4+(reg2)+1)*2)


#define SYS_BAT_CHARGING_EFFICIENCY                 (0.95)
#define SYS_BAT_DISCHARGING_EFFICIENCY              (0.92)


//#define SYS_BAT_1S                                  0
//#define SYS_BAT_2S                                  1
//#define SYS_BAT_3S                                  2
//#define SYS_BAT_4S                                  3

#define SYS_BAT_CNT                                 SYS_BAT_4S

/** 
Battery voltage setting per cell, only valid for internal VBAT voltage setting
000: 4.1V
001: 4.2V (default)
010: 4.25V
011: 4.3V
100: 4.35V
101: 4.4V
110: 4.45V
111: 4.5V
 */
#define SYS_BAT_DEF_CELL_VOLT                       (0x1)

/** Battery voltage per cell, unit in millivolt */
#define SYS_BAT_CELL_VOLT                           (4200U)
#define SYS_BAT_VIN_VOLT                            (4500U)

#define SYS_BAT_MAX_VOLT                            (21000U)

#define SYS_BAT_MAX_VOLT_EX                         (25200U)

#define SYS_BAT_DEAD_VOLT_4S                        (12000U)
#define SYS_BAT_DEAD_VOLT_5S                        (15000U)
#define SYS_BAT_DEAD_VOLT_6S                        (19000U)
#define SYS_BAT_DEAD_VOLT_7S                        (21000U)
#define SYS_BAT_DEAD_VOLT_UNDER_4S                   (9000U)
#define SYS_BAT_INVALID_VOLT                        (25)


#define SYS_BAT_ACCUM_VAL_IDX_MAX                   (5)

typedef enum BAT_SET_MODE_s
{
    internal,
    external,
}BAT_SET_MODE_t;

typedef enum PORT_PWR_DIR_s
{
    IN_DIR,
    OUT_DIR,
}PORT_PWR_DIR_t;

typedef enum BAT_CELL_SET_s
{
    SYS_BAT_1S,
    SYS_BAT_2S,
    SYS_BAT_3S,
    SYS_BAT_4S,
    SYS_BAT_5S,
    SYS_BAT_6S,
    SYS_BAT_7S,
}BAT_CELL_SET_t;

void sys_bat_init(void);

u16_t sys_bat_vbus_fb_val_get();
u16_t sys_bat_vbat_fb_val_get();
u16_t sys_bat_ibus_val_get();
u16_t sys_bat_ibat_val_get();
u16_t sys_bat_adin_val_get();

void sys_bat_discharge_vbus_ibus_set(u32_t vbus, u32_t ibus, bool_t dir);
void sys_bat_ibus_set(u32_t ibus);
void sys_bat_charge_enable(bool_t en);
void sys_bat_charge_current_update();

#if 1
#define sys_bat_dis_foldback_set(flg)               (SYS_BAT_REG_FIELD_SET(CTRL3_SET_REG,DIS_SHORTFOLDBACK,flg))
#else
#define sys_bat_dis_foldback_set(flg)
#endif

#if 1
#define sys_bat_dis_term_set(flg)                   (SYS_BAT_REG_FIELD_SET(CTRL1_SET_REG,DIS_TERM,flg))
#else
#define sys_bat_dis_term_set(flg)
#endif


#define  SYS_BAT_CHARGE_FULL_DETETION_TIME      (600)   /* unit is 100ms, 60s */
#define  SYS_BAT_CHARGE_FULL_LED_DELAY          (1000)  /* unit is 100ms, default to 100-60 = 40s */


typedef enum SYS_BAT_STATE_e
{
    SYS_BAT_STATE_IDLE,
    SYS_BAT_STATE_CHARGE,
    SYS_BAT_STATE_DISCHARGE,
    SYS_BAT_STATE_DEAD_BATTERY,
    SYS_BAT_STATE_INVALID
} SYS_BAT_STATE_t;


typedef struct SYS_BAT_INFO_s
{
    u32_t max_rated_charge_volt:16;
    u32_t charging_current_reach_peak:1;
    u32_t charging:1;
    u32_t charging_pre:1;
    u32_t charging_full:1;
    u32_t capacity:7;
    u32_t dead_bat_check_cnt:2;
    u32_t state:3;

    u32_t rated_charging_volt:16;
    u32_t rated_charging_current:16;

    u32_t current_vbat_val:16;
    u32_t current_ibat_val:16;

    u32_t avg_vbat_val:16;
    u32_t avg_ibat_val:16;

    u32_t accum_vbat_val:24;
    u32_t status_reg:8; //for store SC881X status reg

    u32_t accum_ibat_val:24;
    u32_t accum_val_index:8;

    u32_t charging_start_tick;
    u32_t charging_full_tick;

}SYS_BAT_INFO_t;

extern volatile SYS_BAT_INFO_t g_sys_bat_info;

#define sys_bat_info_ptr_get()          (&(g_sys_bat_info))

#define sys_bat_max_rated_charge_volt_set(v) \
    do { \
        g_sys_bat_info.max_rated_charge_volt = v; \
    } while(0)

#define sys_bat_max_rated_charge_volt_get() \
    (g_sys_bat_info.max_rated_charge_volt)

#define sys_bat_charging_current_reach_peak_flag_set(v) \
    do { \
        g_sys_bat_info.charging_current_reach_peak = v; \
    } while(0)

#define sys_bat_charging_current_reach_peak_flag_get() \
    (g_sys_bat_info.charging_current_reach_peak)


#define sys_bat_charging_flag_set(v) \
    do { \
        g_sys_bat_info.charging = v; \
    } while(0)

#define sys_bat_charging_flag_get() \
    (g_sys_bat_info.charging)


#define sys_bat_charging_pre_flag_set(v) \
    do { \
        g_sys_bat_info.charging_pre = v; \
    } while(0)

#define sys_bat_charging_pre_flag_get() \
    (g_sys_bat_info.charging_pre)


#define sys_bat_charging_full_flag_set(v) \
    do { \
        g_sys_bat_info.charging_full = v; \
    } while(0)

#define sys_bat_charging_full_flag_get() \
    (g_sys_bat_info.charging_full)


#define sys_bat_capacity_set(v) \
    do { \
        g_sys_bat_info.capacity = v; \
    } while(0)

#define sys_bat_capacity_get() \
    (g_sys_bat_info.capacity)


#define sys_bat_rated_charging_volt_set(v) \
    do { \
        g_sys_bat_info.rated_charging_volt = v; \
    } while(0)

#define sys_bat_rated_charging_volt_get() \
    (g_sys_bat_info.rated_charging_volt)

#define sys_bat_rated_charging_current_set(v) \
    do { \
        g_sys_bat_info.rated_charging_current = v; \
    } while(0)

#define sys_bat_rated_charging_current_get() \
    (g_sys_bat_info.rated_charging_current)


#define sys_bat_accum_val_index_set(v) \
    do { \
        g_sys_bat_info.accum_val_index = v; \
    } while(0)

#define sys_bat_accum_val_index_inc(x) \
    do { \
        g_sys_bat_info.accum_val_index += x; \
    } while(0)

#define sys_bat_accum_val_index_get() \
    (g_sys_bat_info.accum_val_index)


#define sys_bat_dead_check_cnt_set(v) \
    do { \
        g_sys_bat_info.dead_bat_check_cnt = v; \
    } while(0)

#define sys_bat_dead_check_cnt_inc(x) \
    do { \
        g_sys_bat_info.dead_bat_check_cnt += x; \
    } while(0)

#define sys_bat_dead_check_cnt_get() \
    (g_sys_bat_info.dead_bat_check_cnt)


#define sys_bat_state_set(v) \
    do { \
        g_sys_bat_info.state = v; \
    } while(0)

#define sys_bat_state_get() \
    (g_sys_bat_info.state)


#define sys_bat_current_vbat_val_set(v) \
    do { \
        g_sys_bat_info.current_vbat_val = v; \
    } while(0)

#define sys_bat_current_vbat_val_inc(v) \
    do { \
        g_sys_bat_info.current_vbat_val += v; \
    } while(0)

#define sys_bat_current_vbat_val_dec(v) \
    do { \
        g_sys_bat_info.current_vbat_val -= v; \
    } while(0)

#define sys_bat_current_vbat_val_get() \
    (g_sys_bat_info.current_vbat_val)


#define sys_bat_current_ibat_val_set(v) \
    do { \
        g_sys_bat_info.current_ibat_val = v; \
    } while(0)

#define sys_bat_current_ibat_val_inc(v) \
    do { \
        g_sys_bat_info.current_ibat_val += v; \
    } while(0)

#define sys_bat_current_ibat_val_dec(v) \
    do { \
        g_sys_bat_info.current_ibat_val -= v; \
    } while(0)

#define sys_bat_current_ibat_val_get() \
    (g_sys_bat_info.current_ibat_val)


#define sys_bat_avg_vbat_val_set(v) \
    do { \
        g_sys_bat_info.avg_vbat_val = v; \
    } while(0)

#define sys_bat_avg_vbat_val_get() \
    (g_sys_bat_info.avg_vbat_val)


#define sys_bat_avg_ibat_val_set(v) \
    do { \
        g_sys_bat_info.avg_ibat_val = v; \
    } while(0)

#define sys_bat_avg_ibat_val_get() \
    (g_sys_bat_info.avg_ibat_val)


#define sys_bat_accum_vbat_val_set(v) \
    do { \
        g_sys_bat_info.accum_vbat_val = v; \
    } while(0)

#define sys_bat_accum_vbat_val_inc(v) \
    do { \
        g_sys_bat_info.accum_vbat_val += v; \
    } while(0)

#define sys_bat_accum_vbat_val_get() \
    (g_sys_bat_info.accum_vbat_val)


#define sys_bat_accum_ibat_val_set(v) \
    do { \
        g_sys_bat_info.accum_ibat_val = v; \
    } while(0)

#define sys_bat_accum_ibat_val_inc(v) \
    do { \
        g_sys_bat_info.accum_ibat_val += v; \
    } while(0)

#define sys_bat_accum_ibat_val_get() \
    (g_sys_bat_info.accum_ibat_val)


#define sys_bat_charging_start_tick_set(v) \
    do { \
        g_sys_bat_info.charging_start_tick = v; \
    } while(0)

#define sys_bat_charging_start_tick_get() \
    (g_sys_bat_info.charging_start_tick)


#define sys_bat_charging_full_tick_set(v) \
    do { \
        g_sys_bat_info.charging_full_tick = v; \
    } while(0)

#define sys_bat_charging_full_tick_get() \
    (g_sys_bat_info.charging_full_tick)


#define sys_bat_status_reg_set(v) \
    do { \
        g_sys_bat_info.status_reg = v; \
    } while(0)

#define sys_bat_status_reg_get() \
    (g_sys_bat_info.status_reg)




#define SYS_BAT_SAVING_CAP_DIFF        (20)

u32_t sys_bat_ocv_rate(u32_t ocv_min, u32_t ocv_max, u8_t scale);
#if SYS_CAPACITY_PARA_SAVE_TO_FLASH
u32_t sys_bat_cap_saved_check(u32_t soc);
#else
#define sys_bat_cap_saved_check(soc)         (soc)
#endif

/** \brief Battery capacity calibration
 */
void sys_bat_cap_cali(void);

#if SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED

#define SYS_BAT_CAP_FULL_CHECK_TIMEOUT   (60000)

//#define SYS_BAT_DEF_RATED_CAP_WS           (331200000UL) //(92000*3600)
//#define SYS_BAT_DEF_RATED_CAP_WS         (342000000UL) //(95000*3600)
//#define SYS_BAT_DEF_RATED_CAP_WS         (256500000UL) //(71250*3600)
#define SYS_BAT_DEF_RATED_CAP_WS           (370800000UL) //(103000*3600)
#define SYS_BAT_DEF_SAMP_INTERVAL        (200U)

typedef struct SYS_BAT_CAP_INFO_s
{
    u32_t interval:16;      // sampling interval, unit is millisecond
    u32_t reserved:16;      // reserved
    u32_t vbat_last:16;     // last sampling vbat
    u32_t ibat_last:16;     // last sampling ibat
    u32_t cap_mws_rated;    // rated capacity: watt second 95*3600
    u32_t cap_mws_dt;       // current capacity: watt second
    u32_t cap_mws;          // accumulated capacity: watt second
    drv_timer_t cap_timer;  // capacity timer for calculating
} SYS_BAT_CAP_INFO_t;

extern volatile SYS_BAT_CAP_INFO_t g_sys_bat_cap;


#define sys_bat_cap_mws_rated_get()         (g_sys_bat_cap.cap_mws_rated)
#define sys_bat_cap_mws_rated_set(v)        (g_sys_bat_cap.cap_mws_rated = v)
#define sys_bat_cap_mws_get()               (g_sys_bat_cap.cap_mws)
#define sys_bat_cap_mws_set(v)              (g_sys_bat_cap.cap_mws = v)
#define sys_bat_vbat_last_get()             (g_sys_bat_cap.vbat_last)
#define sys_bat_vbat_last_set(v)            (g_sys_bat_cap.vbat_last = v)
#define sys_bat_ibat_last_get()             (g_sys_bat_cap.ibat_last)
#define sys_bat_ibat_last_set(v)            (g_sys_bat_cap.ibat_last = v)
#define sys_bat_ibat_current_get()          (g_sys_bat_cap.ibat_current)
#define sys_bat_ibat_current_set(v)         (g_sys_bat_cap.ibat_current = v)
#define sys_bat_samp_interval_get()         (g_sys_bat_cap.interval)
#define sys_bat_samp_interval_set(v)        (g_sys_bat_cap.interval = v)

/** \brief Battery capacity update, call period should be 
 *         equal to g_sys_bat_cap.interval
 */
void sys_bat_cap_update(void);

#endif /* #if SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED */


#endif /* #ifndef __SYS_BAT_INTF_H_ */

