/**
 * \file    sys_pd_hook.c
 * \brief   
 * 
 * \par     Copyright (c) 2018 UWE Technologies Corp., Ltd. All Rights Reserved.
 * \author  James
 * \date    2018-08-31
 * \version 
 * 
 * \history 
 *  Date        Note
 *  2018-08-31  Original Creation
 * 
 */

#include "libc.h"
#include "drivers.h"
#include "sys_pd_config.h"
#include "usbpd.h"
#include "sys_pd_hook.h"
#include "sys_low_power.h"
#include "sys_gpio.h"
#include "sys_bat_intf.h"
#include "sys_pd_config.h"
#include "sys_qc_hook.h"
#if SYS_SMG_DISPLAY_ENABLED
#include "sys_smg_display.h"
#endif /* SYS_SMG_DISPLAY_ENABLED */


volatile SYS_PD_INFO_t g_sys_pd_info;

#if (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED)
volatile u32_t dpm_vbat_acum_val = 0;
#define SYS_NUM_OF_VBAT_SCALE				    4
#define SYS_NUM_OF_IBAT_SCALE_FOR_CHARGE		7
#define SYS_NUM_OF_IBAT_SCALE_FOR_DISCHARGE	    9
/* current curve diagram
 * max voltage is: 16.8V (168), see sys_bat_rated_charging_volt_get()
 * and the array defines voltage for capacity 75%, 50%, 25% when charging or discharging
 */

const u16_t const charge_curr_curve[][SYS_NUM_OF_VBAT_SCALE]={
    {16000,15200,14600,13500}, /* for small current, <200mA */
	{16000,15500,14800,14400}, /* for 1A, {volt for 80~60%, 60~40%, 40~20%} value 16000, means 16.0V.*/
	{16400,15900,15300,14800}, /* for 2A */
	{16400,16100,15300,14800}, /* for 3A */
	{16400,16200,15500,15000}, /* for 4A */
	{16700,16500,15900,15500}, /* for 5A */
	{16700,16500,16000,15700} /* for 6A */
	};
	
const u16_t const discharge_curr_curve[][SYS_NUM_OF_VBAT_SCALE]={
    {15900,15200,14600,13500}, /* for small current, <200mA */
	{15800,15100,14200,13600}, /* for 1A, {volt for 80~60%, 60~40%, 40~20%} value 15600, means 15.6V. */
	{15500,14800,13900,13300}, /* for 2A */
	{15100,14400,13600,12900}, /* for 3A */
	{14900,14100,13400,12800}, /* for 4A */
	{14600,13900,13100,12600}, /* for 5A */
	{14500,13700,12900,12400}, /* for 6A */
	{14100,13300,12600,12100}, /* for 7A */
	{13800,13100,12400,11900} /* for 8A */
	};
#endif

#if SYS_OVERTEMP_DECTION_ENABLED

/** NOTE: the unit of temperature voltage is 100uV 
    ÎÂ¶È	µçÑ¹(V)
    -10	    2.7931
    0	    2.5264
    45	    0.9996
    55	    0.7529
    60	    0.6505
*/

/** Temperature greater than 60C, disable charge and discharge */
#define DPM_TEMP_P60C_VOLT          (6505)

/** Temperature greater than 55C, disable charge
 *  Temperature lower than 55C, restore half power charge
 */
#define DPM_TEMP_P55C_VOLT          (7529)

/** Temperature greater than 45C, halve charge power
 *  Temperature lower than 45C, restore full power charge
 */
#define DPM_TEMP_P45C_VOLT          (9996)

/** Temperature greater than 0C, restore charge 
 *  Temperature lower than 0C, disable charge
 */
#define DPM_TEMP_0C_VOLT            (25264)

/** Temperature greater than -10C, restore discharge, but still disable charge
 *  Temperature lower than -10C, disable charge and discharge
 */
#define DPM_TEMP_M10C_VOLT          (27931)

#define DPM_TEMP_INVALID_VOLT       (32600)

#endif /* SYS_OVERTEMP_DECTION_ENABLED */



void sys_pd_sink_unattached_hook()
{
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Unattached Hook");
    }
#endif /* CLI_ENABLED */

    sys_bat_charge_enable(FALSE);
    sys_gpio_vbus_en_set(FALSE);
    sys_pd_power_policy_process(TRUE);
    sys_gpio_pd_qc_led_off();
#if SYS_OVERTEMP_DECTION_ENABLED
    g_sys_pd_info.charging_current_saved = 0;
#endif /* SYS_OVERTEMP_DECTION_ENABLED */
}

void sys_pd_sink_attachwait_hook()
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Attachwait Hook");
    }
#endif /* CLI_ENABLED */
}

void sys_pd_sink_attached_hook()
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Attached Hook");
    }
#endif /* CLI_ENABLED */
    sys_gpio_vbus_en_set(TRUE);
    sys_bat_charge_enable(TRUE);
    sys_pd_led_state_set(SYS_PD_LED_STATE_ON);
    sys_bat_state_set(SYS_BAT_STATE_CHARGE);
    sys_pd_power_policy_process(TRUE);
#if SYS_OVERTEMP_DECTION_ENABLED
    g_sys_pd_info.charging_current_saved = 0;
#endif /* SYS_OVERTEMP_DECTION_ENABLED */
}

status_t sys_pd_sink_transit_to_new_power_hook()
{
    if (dpm_current_pwr_mode_get())
        return S_ERROR;

    if (!dpm_src_obj_pos_get())
        return S_ERROR;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Transit To New Power Hook");
    }
#endif /* CLI_ENABLED */

    sys_bat_charge_enable(TRUE);
    sys_gpio_pd_qc_led_on();
#if SYS_OVERTEMP_DECTION_ENABLED
    g_sys_pd_info.charging_current_saved = 0;
#endif /* SYS_OVERTEMP_DECTION_ENABLED */

    return S_OK;
}

void sys_pd_source_unattached_hook()
{
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSrc Unattached Hook");
    }
#endif /* CLI_ENABLED */
    sys_bat_charge_enable(FALSE);
    sys_gpio_vbus_en_set(FALSE);
    sys_pd_power_policy_process(TRUE);
    sys_gpio_pd_qc_led_off();
#if SYS_OVERTEMP_DECTION_ENABLED
    g_sys_pd_info.charging_current_saved = 0;
#endif /* SYS_OVERTEMP_DECTION_ENABLED */
}

void sys_pd_source_attachwait_hook()
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSrc Attachwait Hook");
    }
#endif /* CLI_ENABLED */
}

void sys_pd_source_attached_hook()
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSrc Attached Hook");
    }
#endif /* CLI_ENABLED */
    sys_gpio_vbus_en_set(TRUE);
    if (!dpm_port_dead_battery_get())
    {
        sys_pd_led_state_set(SYS_PD_LED_STATE_ON);
    }
    else {
        sys_pd_led_state_set(SYS_PD_LED_STATE_FLASH_FAST);
    }
    sys_pd_power_policy_process(TRUE);
    sys_bat_state_set(SYS_BAT_STATE_DISCHARGE);
#if SYS_OVERTEMP_DECTION_ENABLED
    g_sys_pd_info.charging_current_saved = 0;
#endif /* SYS_OVERTEMP_DECTION_ENABLED */
}

status_t sys_pd_source_transit_to_new_power_hook(u32_t pos)
{
    u32_t current, voltage;

    if (!dpm_current_pwr_mode_get())
        return S_ERROR;

    if (pos >= CFG_MAX_PWR_CAP_NUM)
        return S_INVALID_PARAMS;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        printf("\nSrc Transit To New Power Hook(%u)\n",pos);
    }
#endif /* CLI_ENABLED */

    if (POWER_SUPPLY_TYPE_PPS == usbpd_cfg_port_src_pwr_supply_type_get(pos))
    {
        current = REQ_PPS_OPR_CURR_GET(dpm_current_rdo_get())*CURRENT_PPS_DIV;
        voltage = REQ_PPS_OUTPUT_VOLT_GET(dpm_current_rdo_get())*VOLTAGE_PPS_REQ_DIV + SYS_POWER_BANK_VOLTAGE_COMPENSATION;
    }
    else 
    {
        current = usbpd_cfg_port_src_fixed_pwr_curr_cap_get(pos)*CURRENT_DIV;
        voltage = usbpd_cfg_port_src_fixed_pwr_volt_cap_get(pos)*VOLTAGE_DIV + SYS_POWER_BANK_VOLTAGE_COMPENSATION;
    }

    if (current >= CURRENT_3000mA) 
    {
        current = SYS_POWER_BANK_DICCHARGE_CURRENT_COMPENSATION_RATIO * current + SYS_POWER_BANK_CURRENT_COMPENSATION;
    }
    else {
        current = SYS_POWER_BANK_DICCHARGE_CURRENT_COMPENSATION_RATIO2 * current + SYS_POWER_BANK_CURRENT_COMPENSATION_2;
    }

    sys_bat_discharge_vbus_ibus_set(voltage, current);

    sys_gpio_pd_qc_led_on();

    return S_OK;
}

bool_t sys_pd_vbus_source_en_get(void)
{
    return g_sys_pd_info.vbus_source_en;
}

void sys_pd_vbus_source_en_set(bool_t flg)
{
    g_sys_pd_info.vbus_source_en = flg;
    if (flg)
    {
        sys_bat_dis_foldback_set(TRUE);
        sys_bat_discharge_vbus_ibus_set(VSAFE_5V+SYS_POWER_BANK_VOLTAGE_COMPENSATION, CURRENT_5000mA);
    }
    else {
        sys_bat_dis_foldback_set(FALSE);
        if ((dpm_cc_state_get() < DPM_CC_UNATTACHED_SNK) || 
            (dpm_cc_state_get() > DPM_CC_ATTACHED_SNK) || 
            (now() > 6000000UL) || 
            (dpm_vbus_volt_get() < 2200) ||
            (pe_hard_reset_in_prog()))
        {
            sys_bat_discharge_vbus_ibus_set(0, 0);
        }
    }
}

bool_t sys_pd_vbus_discharge_en_get(void)
{
    return dpm_vbus_discharge_get();
}

void sys_pd_vbus_discharge_en_set(bool_t flg)
{
    dpm_vbus_discharge_set(flg);
}

bool_t sys_pd_cc1_vconn_en_get(void)
{
    return sys_gpio_vconn1_get();
}

void sys_pd_cc1_vconn_en_set(bool_t flg)
{
    sys_gpio_vconn1_set(flg);
}

bool_t sys_pd_cc2_vconn_en_get(void)
{
    return sys_gpio_vconn2_get();
}

void sys_pd_cc2_vconn_en_set(bool_t flg)
{
    sys_gpio_vconn2_set(flg);
}


void sys_pd_prs_started_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nPRS Started Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_prs_completed_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nPRS Completed Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_drs_started_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nDRS Started Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_drs_completed_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nDRS Completed Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_vcs_started_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nVCS Started Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_vcs_completed_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nVCS Completed Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_power_change_req_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nPower Change Req Hook");
    }
#endif /* CLI_ENABLED */

}

void sys_pd_prl_msg_received_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_3) 
    {
        drv_uart_puts("\nPRL Msg Recevied Hook");
    }
#endif /* CLI_ENABLED */
    g_sys_pd_info.rx_pkt_cnt++;
}

void sys_pd_prl_msg_sent_hook(u32_t arg)
{
    sys_lpm_activate();
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_3) 
    {
        drv_uart_puts("\nPRL Msg Sent Hook");
    }
#endif /* CLI_ENABLED */
    g_sys_pd_info.tx_pkt_cnt++;
}

void sys_pd_led_state_set(SYS_PD_LED_STATE_t state)
{
    g_sys_pd_info.led_state = state;
    if (state)
    {
        g_sys_pd_info.led_on_start_tick = g_sys_pd_info.continuous_timer_tick;
    }
    if (state == SYS_PD_LED_STATE_FLASH)
    {
        g_sys_pd_info.led_display_flash_interval = 10;
    }
    else if (state == SYS_PD_LED_STATE_FLASH_FAST)
    {
        g_sys_pd_info.led_display_flash_interval = 10;
    }
}


#if (!SYS_POWER_POLICY_DISABLED)
void sys_pd_power_policy_process(bool_t change_asap)
{
    if (sys_bat_capacity_get() >= 50)
    {
        if (((pe_pd_connected_time_get()) && 
            ((u32_t)(now() - pe_pd_connected_time_get()) > 1000000UL)) || 
            (change_asap))
        {
            if (POWER_MODE_SOURCE == dpm_current_pwr_mode_get())
            {
                if (VBUS_CURR_HANDLING_CAP_5A == dpm_rx_vdm_ack_cable_vbus_curr_cap_get())
                {
                    if (POWER_PROFILE_100W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
                    {
                        sys_pd_cfg_src_power_profile_set(POWER_PROFILE_100W_FIXED);
                    }
                }
                else {
                    if (POWER_PROFILE_60W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
                    {
                        sys_pd_cfg_src_power_profile_set(POWER_PROFILE_60W_FIXED);
                    }
                }
            }
        }
        else if (!dpm_cable_detect_done_get()) 
        {
            if (POWER_PROFILE_60W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
            {
                sys_pd_cfg_src_power_profile_set(POWER_PROFILE_60W_FIXED);
            }
        }
    }
    else if (sys_bat_capacity_get() >= 20) 
    {
        if (((pe_pd_connected_time_get()) && 
            ((u32_t)(now() - pe_pd_connected_time_get()) > 1000000UL)) || 
            (change_asap))
        {
            if (POWER_MODE_SOURCE == dpm_current_pwr_mode_get())
            {
                if (g_sys_pd_info.usba_no_current_flow_flag)
                {
                    if (POWER_PROFILE_60W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
                    {
                        sys_pd_cfg_src_power_profile_set(POWER_PROFILE_60W_FIXED);
                    }
                }
                else {
                    if (POWER_PROFILE_45W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
                    {
                        sys_pd_cfg_src_power_profile_set(POWER_PROFILE_45W_FIXED);
                    }
                }
            }
            else {
				//
            }
        }
        else if (!dpm_cable_detect_done_get()) 
        {
            if (POWER_PROFILE_60W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
            {
                sys_pd_cfg_src_power_profile_set(POWER_PROFILE_60W_FIXED);
            }
        }
    }
    else
    {
        if (((pe_pd_connected_time_get()) && 
            ((u32_t)(now() - pe_pd_connected_time_get()) > 1000000UL)) || 
            (change_asap))
        {
            if (POWER_MODE_SOURCE == dpm_current_pwr_mode_get())
            {
                if (POWER_PROFILE_45W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
                {
                    sys_pd_cfg_src_power_profile_set(POWER_PROFILE_45W_FIXED);
                }
            }
            else {
				//
            }
        }
        else if (!dpm_cable_detect_done_get()) 
        {
            if (POWER_PROFILE_45W_FIXED != usbpd_cfg_port_src_fixed_pwr_prof_get())
            {
                sys_pd_cfg_src_power_profile_set(POWER_PROFILE_45W_FIXED);
            }
        }
    }

    // Change C1 power
    if (usbpd_cfg_port_src_fixed_pwr_prof_changed_flag_get()) 
    {
        if ((dpm_cable_detect_done_get()) && 
            (dpm_current_pwr_mode_get()) &&
            (pe_state_get() == PE_SRC_READY))
        {
#if 0  /* modified by James Gan - 2019-12-19 */
            if ((dpm_partner_prod_type_get() == UPD_PRODUCT_HUB)||
                (dpm_partner_prod_type_get() == UPD_PRODUCT_AMA))
            {
                dpm_source_cap_change_set(TRUE);
                dpm_hrst_due_to_no_current_flag_set(FALSE);
            }
            else {
                dpm_hard_reset_req_set(TRUE);
            }
#else
            dpm_source_cap_change_set(TRUE);
            dpm_hrst_due_to_no_current_flag_set(FALSE);
#endif /* #if 0 */
            pe_state_machine();
        }
        usbpd_cfg_port_src_fixed_pwr_prof_changed_flag_set(FALSE);
#if CLI_ENABLED
	    if (sys_cfg_dbg_get() >= SYS_DEBUG_LEVEL_2) printf("C1 pf=%bu, cap=%bu\n", usbpd_cfg_port_src_fixed_pwr_prof_get(), sys_bat_capacity_get());
#endif /* CLI_ENABLED */
    }
}
#endif /* (!SYS_POWER_POLICY_DISABLED) */

#if SYS_POWER_BANK_ENABLED

void sys_bat_vbat_update()
{
    #define SYS_VBAT_MAX_MISS_CNT       (30)
    static int vbat_val_miss_cnt = 0;

    // Battery i2c communication check
    sys_bat_current_vbat_val_set(sys_bat_vbat_fb_val_get());
    if ((I2C_BUS_ERROR == g_i2c_info[SYS_BAT_PWR_CTRL_I2C].last_status) || 
        (I2C_ARBITRATION_LOST == g_i2c_info[SYS_BAT_PWR_CTRL_I2C].last_status) || 
        (I2C_TIME_OUT == g_i2c_info[SYS_BAT_PWR_CTRL_I2C].last_status))
    {
        vbat_val_miss_cnt++;
        if (vbat_val_miss_cnt >= SYS_VBAT_MAX_MISS_CNT)
        {
#if CLI_ENABLED
			if (sys_cfg_dbg_get()) drv_uart_puts("I2C Fault");
#endif /* CLI_ENABLED */
#if SYS_CAPACITY_PARA_SAVE_TO_FLASH
        	sys_capacity_set(sys_bat_capacity_get());
			sys_capacity_para_save();
#endif
            dpm_cc_state_release();
            dpm_cc_state_init();
            drv_chip_reset();
        }
    }
    else {
        vbat_val_miss_cnt = 0;
    }
}


void sys_bat_capacity_check()
{
#if (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED)
	u8_t dpm_curr_idx = 0;
	u8_t dpm_curr_num = 0;
	u16_t (*p_curr_curve_arr)[SYS_NUM_OF_VBAT_SCALE];
	u8_t i = 0;
	u8_t indicator_curr;
#endif /* (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED) */

    if ((!dpm_cable_detect_done_get()))
    {
        if (g_sys_pd_info.usba_ibus_avg_val > SYS_USBA_IBUS_NO_CURRENT_FLOW_THR)
        {
            sys_bat_current_ibat_val_set(g_sys_pd_info.usba_ibus_avg_val + 67);
        }
        else {
            sys_bat_current_ibat_val_set(SYS_USBA_IBUS_NO_CURRENT_FLOW_THR + (rand() & 0x3));
        }
    }
    else {
        
        if (sys_bat_current_ibat_val_get() > 300)
        {
            if (sys_bat_charging_flag_get())
            {
                sys_bat_current_ibat_val_inc(90);
            }
            else {
                sys_bat_current_ibat_val_inc(180);
            }
        }
    }

#if SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED
    // Capacity update
    sys_bat_cap_update();
#endif /* SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED */

#if (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED)
    sys_bat_accum_vbat_val_inc(sys_bat_current_vbat_val_get());
#endif /* (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED) */
    sys_bat_accum_ibat_val_inc(sys_bat_current_ibat_val_get());
    sys_bat_accum_val_index_inc(1);

#if USBPD_DEBUG_ENABLED
	if (SYS_DEBUG_LEVEL_3 <= sys_cfg_dbg_get())
    {
        printf("i=%u,v=%u,accum:i=%u,v=%u,idx:%u\n", 
        	sys_bat_current_ibat_val_get(), sys_bat_current_vbat_val_get(),
        	sys_bat_accum_ibat_val_get(), sys_bat_accum_vbat_val_get(), 
        	sys_bat_accum_val_index_get());
	}
#endif

    if (sys_bat_accum_val_index_get() >= SYS_BAT_ACCUM_VAL_IDX_MAX)
    {
#if (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED)
        sys_bat_avg_vbat_val_set(sys_bat_accum_vbat_val_get() / sys_bat_accum_val_index_get());
        sys_bat_accum_vbat_val_set(0);
#endif /* (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED) */
        sys_bat_avg_ibat_val_set(sys_bat_accum_ibat_val_get() / sys_bat_accum_val_index_get());
        sys_bat_accum_ibat_val_set(0);
        sys_bat_accum_val_index_set(0);

#if (!SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED)  /* modified by James Gan - 2018-11-19 */

#if CLI_ENABLED
    	//if (sys_cfg_dbg_get())  printf("capacity check, ");
#endif /* CLI_ENABLED */
    	if (sys_bat_charging_flag_get())
    	{
    		dpm_curr_num = SYS_NUM_OF_IBAT_SCALE_FOR_CHARGE;
    		p_curr_curve_arr = &charge_curr_curve[0];
#if CLI_ENABLED
    		//if (sys_cfg_dbg_get()) printf("charge mode.\n");
#endif /* CLI_ENABLED */
    	}
        else
    	{
    		dpm_curr_num = SYS_NUM_OF_IBAT_SCALE_FOR_DISCHARGE;
    		p_curr_curve_arr = &discharge_curr_curve[0];
#if CLI_ENABLED
    		//if (sys_cfg_dbg_get()) printf("discharge mode.\n");
#endif /* CLI_ENABLED */
    	}

    	if (sys_bat_avg_ibat_val_get() < (SYS_BAT_IBAT_CURRENT_0p5A))
    	{
    		dpm_curr_idx = 0;
    	}
    	else
    	{
    		dpm_curr_idx = (sys_bat_avg_ibat_val_get() - SYS_BAT_IBAT_CURRENT_0p5A) / SYS_BAT_IBAT_CURRENT_1A + 1;
    		if (dpm_curr_num <= dpm_curr_idx) dpm_curr_idx = (dpm_curr_num - 1);
    	}

        // capacity 100%
    	if (sys_bat_avg_vbat_val_get() >= sys_bat_max_rated_charge_volt_get())
    	{
            i = 100;
    	}
        // 80% - 99%
        else if (sys_bat_avg_vbat_val_get() >= p_curr_curve_arr[dpm_curr_idx][0])
    	{
    		i = 80 + sys_bat_ocv_rate(p_curr_curve_arr[dpm_curr_idx][0], sys_bat_max_rated_charge_volt_get(), 20);
    	}
        // 60% - 79%
        else if (sys_bat_avg_vbat_val_get() >= p_curr_curve_arr[dpm_curr_idx][1])
    	{
    		i = 60 + sys_bat_ocv_rate(p_curr_curve_arr[dpm_curr_idx][1], p_curr_curve_arr[dpm_curr_idx][0], 20);
    	}
        // 40% - 59%
        else if (sys_bat_avg_vbat_val_get() >= p_curr_curve_arr[dpm_curr_idx][2])
    	{
    		i = 40 + sys_bat_ocv_rate(p_curr_curve_arr[dpm_curr_idx][2], p_curr_curve_arr[dpm_curr_idx][1], 20);
        }
        // 20% - 39%
        else if (sys_bat_avg_vbat_val_get() >= p_curr_curve_arr[dpm_curr_idx][3])
    	{
    		i = 20 + sys_bat_ocv_rate(p_curr_curve_arr[dpm_curr_idx][3], p_curr_curve_arr[dpm_curr_idx][2], 20);
    	}
        // 0% - 19%
        else if (sys_bat_avg_vbat_val_get() >= SYS_BAT_DEAD_VOLT)
    	{
    		i = sys_bat_ocv_rate(SYS_BAT_DEAD_VOLT, p_curr_curve_arr[dpm_curr_idx][3], 20);
    	}
        else if (sys_bat_avg_vbat_val_get() < SYS_BAT_DEAD_VOLT)
        {
            i = 0;
        }

    	if (sys_bat_charging_flag_get())
    	{
            if (i > g_sys_pd_info.bat_cap_indicator_pre_charge)
    		{
    			g_sys_pd_info.bat_cap_indicator_pre_charge = i;
    			indicator_curr = i;
    		}
            else
    		{
    			indicator_curr = g_sys_pd_info.bat_cap_indicator_pre_charge;
    		}
    	}
        else
    	{
    		if (i < g_sys_pd_info.bat_cap_indicator_pre_discharge)
    		{
    			g_sys_pd_info.bat_cap_indicator_pre_discharge = i;
    			indicator_curr = i;
    		}
            else
    		{
    			indicator_curr = g_sys_pd_info.bat_cap_indicator_pre_discharge;
    		}
    	}

        if (sys_bat_capacity_get() != indicator_curr)
        {
            sys_bat_capacity_set(indicator_curr);
        }

#endif /* #if SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED */

        if (sys_bat_capacity_get() <= 5)
        {
            if ((!dpm_port_dead_battery_get()) && (SYS_BAT_STATE_CHARGE != sys_bat_state_get()))
            {
                sys_pd_led_state_set(SYS_PD_LED_STATE_FLASH_FAST);
            }
        }

#if USBPD_DEBUG_ENABLED
    	if (SYS_DEBUG_LEVEL_3 == sys_cfg_dbg_get())
        {
#if SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED  /* modified by James Gan - 2018-12-23 */
            printf("ibat=%u,vbat=%u,soc=%u,cap=%u\n", 
            	sys_bat_current_ibat_val_get(), sys_bat_avg_vbat_val_get(),
                sys_bat_capacity_get(), sys_bat_cap_mws_get());
#else
            printf("ibat=%u,vbat=%u,cur=%u,i=%u,cur=%u,soc=%u\n", 
                sys_bat_avg_ibat_val_get(), sys_bat_avg_vbat_val_get(), dpm_curr_idx, 
                i, indicator_curr, sys_bat_capacity_get());
#endif /* #if SYS_BAT_CAP_INTEGRAL_METHOD_ENABLED */
    	}
#endif

        sys_pd_power_policy_process(FALSE);
    }
}


#if SYS_LED_ENABLED

#if (!SYS_SMG_DISPLAY_ENABLED)  /* modified by James Gan - 2019-12-06 */
void sys_pd_init_display()
{
    static u8_t u8_num = SYS_LED_NUM, u8_direction = 1;

#if 0 /*CLI_ENABLED*/
	if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_1) printf("Init..led %u\n", u8_num);
#endif
	sys_gpio_bat_cap_led_step_on(SYS_LED_NUM-u8_num);
	if (0 == (g_sys_pd_info.continuous_timer_tick % 3))
	{
		if (0 == u8_direction)
		{
			u8_num++;
			if (SYS_LED_NUM == u8_num) u8_direction = 1;
		}
		else {
			u8_num--;
			if (0 == u8_num) u8_direction = 0;
		}
	}
    if ((g_sys_pd_info.sys_initializing) && (0 == u8_num))
    {
        g_sys_pd_info.sys_initializing = FALSE;
        sys_bat_dis_foldback_set(FALSE);
        sys_bat_dis_term_set(FALSE);
        sys_bat_cap_cali();
    }
}
#else
void sys_pd_init_display()
{
    static u8_t u8_num = 8;

#if 0 /*CLI_ENABLED*/
	if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_1) printf("Init..led %u\n", u8_num);
#endif
	if (0 == (g_sys_pd_info.continuous_timer_tick % 3))
	{
        if (0 == (u8_num & 1))
        {
            sys_smg_display_data_set(188);
        }
        else {
            sys_smg_display_data_set(SMG_NC);
        }
	    u8_num--;
	}
    sys_smg_ctrl_on_set(TRUE);
    if ((g_sys_pd_info.sys_initializing) && (0 == u8_num))
    {
        g_sys_pd_info.sys_initializing = FALSE;
        sys_bat_dis_foldback_set(FALSE);
        sys_bat_dis_term_set(FALSE);
        sys_bat_cap_cali();
    }
}
#endif /* #if (!SYS_SMG_DISPLAY_ENABLED) */

void sys_pd_display_process(void)
{
    if (g_sys_pd_info.display_state)
    {
        if (g_sys_pd_info.sys_initializing)
    	{
    		return;
    	}

        if ((sys_pd_led_state_get() == SYS_PD_LED_STATE_FLASH) || 
            (sys_pd_led_state_get() == SYS_PD_LED_STATE_FLASH_FAST))
        {
#if (!SYS_SMG_DISPLAY_ENABLED)  /* modified by James Gan - 2019-11-25 */
            if ((!dpm_port_dead_battery_get()) && ((sys_bat_capacity_get() > 5)))
            {
                // turn on all LEDs
                sys_gpio_bat_cap_full_led_on();
            }
            else {
                sys_gpio_bat_cap_1st_led_on();
            }
#else
            if ((!dpm_port_dead_battery_get()) && ((sys_bat_capacity_get() > 5)))
            {
                sys_smg_display_data_set(188);
            }
            else {
                sys_smg_display_data_set(sys_bat_capacity_get());
            }
            sys_smg_ctrl_on_set(TRUE);
#endif /* #if (!SYS_SMG_DISPLAY_ENABLED) */
        }
        else {
#if (!SYS_SMG_DISPLAY_ENABLED)  /* modified by James Gan - 2019-11-25 */
#if (5==SYS_LED_NUM)  /* modified by James Gan - 2019-04-16 */
            if (sys_bat_capacity_get() >= 80)
            {
                if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                {
                    if ((!g_sys_pd_info.c2_cable_done_flag) && 
                        (g_sys_pd_info.usba_no_current_flow_flag) && 
                        (sys_bat_charging_full_tick_get()) && 
                        (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_full_tick_get()) &&
                        ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_full_tick_get()) > SYS_BAT_CHARGE_FULL_LED_DELAY))
                    {
#if SYS_LED_DISPLAY_DURATION_ENABLED
                        sys_gpio_bat_cap_led_off();
#else
                        sys_gpio_bat_cap_full_led_on();
#endif /* SYS_LED_DISPLAY_DURATION_ENABLED */
                        sys_bat_charging_full_flag_set(TRUE);
                    }
                    else if ((!g_sys_pd_info.c2_cable_done_flag) && 
                        (g_sys_pd_info.usba_no_current_flow_flag) && 
                        (sys_bat_charging_full_tick_get()) && 
                        (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_full_tick_get()) &&
                        ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_full_tick_get()) > SYS_BAT_CHARGE_FULL_DETETION_TIME))
                    {
                        sys_gpio_bat_cap_full_led_on();
                    }
                    else {
                        if (0 == (g_sys_pd_info.continuous_timer_tick % 10))
                        {
                            sys_gpio_bat_cap_4th_led_on();
                        }
                        else {
                            sys_gpio_bat_cap_full_led_on();
                        }
                    }
                }
                else {
                    sys_gpio_bat_cap_full_led_on();
                }
            }
            else if (sys_bat_capacity_get() >= 60)
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_3rd_led_on();
                }
                else {
                    sys_gpio_bat_cap_4th_led_on();
                }
            }
            else if (sys_bat_capacity_get() >= 40)
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_2nd_led_on();
                }
                else {
                    sys_gpio_bat_cap_3rd_led_on();
                }
            }
            else if (sys_bat_capacity_get() >= 20)
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_1st_led_on();
                }
                else {
                    sys_gpio_bat_cap_2nd_led_on();
                }
            }
            else
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_led_off();
                }
                else {
                    sys_gpio_bat_cap_1st_led_on();
                }
            }
#else // 4 LEDs
            if (sys_bat_capacity_get() >= 75)
            {
                if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                {
                    if ((!g_sys_pd_info.c2_cable_done_flag) && 
                        (g_sys_pd_info.usba_no_current_flow_flag) && 
                        (sys_bat_charging_full_tick_get()) && 
                        (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_full_tick_get()) &&
                        ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_full_tick_get()) > SYS_BAT_CHARGE_FULL_LED_DELAY))
                    {
#if SYS_LED_DISPLAY_DURATION_ENABLED
                        sys_gpio_bat_cap_led_off();
#else
                        sys_gpio_bat_cap_full_led_on();
#endif /* SYS_LED_DISPLAY_DURATION_ENABLED */
                        sys_bat_charging_full_flag_set(TRUE);
                    }
                    else if ((!g_sys_pd_info.c2_cable_done_flag) && 
                        (g_sys_pd_info.usba_no_current_flow_flag) && 
                        (sys_bat_charging_full_tick_get()) && 
                        (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_full_tick_get()) &&
                        ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_full_tick_get()) > SYS_BAT_CHARGE_FULL_DETETION_TIME))
                    {
                        sys_gpio_bat_cap_full_led_on();
                    }
                    else {
                        if (0 == (g_sys_pd_info.continuous_timer_tick % 10))
                        {
                            sys_gpio_bat_cap_3rd_led_on();
                        }
                        else {
                            sys_gpio_bat_cap_full_led_on();
                        }
                    }
                }
                else {
                    sys_gpio_bat_cap_full_led_on();
                }
            }
            else if (sys_bat_capacity_get() >= 50)
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_2nd_led_on();
                }
                else {
                    sys_gpio_bat_cap_3rd_led_on();
                }
            }
            else if (sys_bat_capacity_get() >= 25)
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_1st_led_on();
                }
                else {
                    sys_gpio_bat_cap_2nd_led_on();
                }
            }
            else
            {
                if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_gpio_bat_cap_led_off();
                }
                else {
                    sys_gpio_bat_cap_1st_led_on();
                }
            }
#endif /* #if (5==SYS_LED_NUM) */
#else
            if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
            {
                if ((g_sys_pd_info.led_on_start_tick) && 
                    (g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.led_on_start_tick) && 
                    ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.led_on_start_tick) > 10))
                {
                    sys_smg_display_data_set(sys_bat_capacity_get());
                    if ((!g_sys_pd_info.c2_cable_done_flag) && 
                        (g_sys_pd_info.usba_no_current_flow_flag) && 
                        (sys_bat_capacity_get() == 100) && 
                        (sys_bat_charging_full_tick_get()) && 
                        (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_full_tick_get()) &&
                        ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_full_tick_get()) > SYS_BAT_CHARGE_FULL_LED_DELAY))
                    {
#if SYS_LED_DISPLAY_DURATION_ENABLED
                        sys_smg_display_data_set(SMG_NC);
                        sys_smg_ctrl_on_set(TRUE);
#else
                        sys_smg_ctrl_on_set(TRUE);
#endif /* SYS_LED_DISPLAY_DURATION_ENABLED */
                        sys_bat_charging_full_flag_set(TRUE);
                    }
                    else if ((!g_sys_pd_info.c2_cable_done_flag) && 
                        (g_sys_pd_info.usba_no_current_flow_flag) && 
                        (sys_bat_capacity_get() == 100) && 
                        (sys_bat_charging_full_tick_get()) && 
                        (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_full_tick_get()) &&
                        ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_full_tick_get()) > SYS_BAT_CHARGE_FULL_DETETION_TIME))
                    {
                        sys_smg_ctrl_on_set(TRUE);
                    }
                    else {
                        if (0 == (g_sys_pd_info.continuous_timer_tick % 10))
                        {
                            sys_smg_display_data_set(SMG_UNITS_DIGIT_OFF + sys_bat_capacity_get());
                            sys_smg_ctrl_on_set(TRUE);
                        }
                        else {
                            sys_smg_ctrl_on_set(TRUE);
                        }
                    }
                }
                else {
                    sys_smg_display_data_set(188);
                    sys_smg_ctrl_on_set(TRUE);
                }
            }
            else {
                sys_smg_display_data_set(sys_bat_capacity_get());
                if ((g_sys_pd_info.prevent_auto_poweroff) &&
                    (0 == (g_sys_pd_info.continuous_timer_tick % 10)))
                {
                    sys_smg_display_data_set(SMG_X);
                }
                sys_smg_ctrl_on_set(TRUE);
            }
#endif /* #if (!SYS_SMG_DISPLAY_ENABLED) */
        }
    }
    else {
#if SYS_SMG_DISPLAY_ENABLED  /* modified by James Gan - 2019-11-25 */
        sys_smg_display_data_set(SMG_NC);
        sys_smg_ctrl_on_set(TRUE);
#else
        // turn off all LEDs
        sys_gpio_bat_cap_led_off();
#endif /* #if SYS_SMG_DISPLAY_ENABLED */
    }
}

void sys_pd_display_state_machine(void)
{
    // Digit display control
#if SYS_LED_DISPLAY_DURATION_ENABLED
    if ((g_sys_pd_info.led_on_start_tick) && 
        (g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.led_on_start_tick) &&
        (((!dpm_port_dead_battery_get()) && ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.led_on_start_tick) > SYS_LED_DISPLAY_DURATION)) || 
         ((dpm_port_dead_battery_get()) && ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.led_on_start_tick) > SYS_LED_DISPLAY_DURATION_SHORT))) && 
        (dpm_port_state_get() != DPM_PORT_STATE_CHARGE))
    {
        g_sys_pd_info.display_state = FALSE;
        sys_pd_led_state_set(SYS_PD_LED_STATE_OFF);
    }
    else 
#else
    if ((g_sys_pd_info.led_on_start_tick) && 
        (g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.led_on_start_tick) &&
        ((dpm_port_dead_battery_get()) && ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.led_on_start_tick) > SYS_LED_DISPLAY_DURATION_SHORT)) && 
        (dpm_port_state_get() != DPM_PORT_STATE_CHARGE))
    {
        g_sys_pd_info.display_state = FALSE;
        sys_pd_led_state_set(SYS_PD_LED_STATE_OFF);
    }
    else 
#endif /* SYS_LED_DISPLAY_DURATION_ENABLED */
    {
        switch (sys_pd_led_state_get())
        {
            case SYS_PD_LED_STATE_FLASH_FAST:
            case SYS_PD_LED_STATE_FLASH:
                if (0 == (g_sys_pd_info.continuous_timer_tick % g_sys_pd_info.led_display_flash_interval))
                {
                    g_sys_pd_info.display_state = FALSE;
                }
                else {
                    g_sys_pd_info.display_state = TRUE;
                }
                break;
            case SYS_PD_LED_STATE_ON:
                if ((g_sys_pd_info.prevent_auto_poweroff) && 
                    (dpm_port_state_get() != DPM_PORT_STATE_CHARGE))
                {
                    if (0 == (g_sys_pd_info.continuous_timer_tick % 30))
                    {
                        g_sys_pd_info.display_state = FALSE;
                    }
                    else {
                        g_sys_pd_info.display_state = TRUE;
                    }
                }
                else {
                    g_sys_pd_info.display_state = TRUE;
                }
                break;
            case SYS_PD_LED_STATE_OFF:
            default:
                g_sys_pd_info.display_state = FALSE;
                break;
        }
    }
}

void sys_pd_display_flash_manually(u8_t cnt, u8_t fast)
{
    sys_pd_led_state_set(SYS_PD_LED_STATE_FLASH);
    // flash n times
    g_sys_pd_info.display_state = TRUE;
    sys_pd_display_process();
    cnt = cnt * 2 - 1;
    do
    {
        // delay about 500ms
        if (!fast)
        {
            rtc_delay_us(300000);
        }
        rtc_delay_us(200000);
        g_sys_pd_info.display_state = !g_sys_pd_info.display_state;
        sys_pd_display_process();
        cnt--;
    } while(cnt > 0);
    rtc_delay_us(200000);
}

#else

#define sys_pd_display_flash_manually(cnt,fast)

#endif /* SYS_LED_ENABLED */

u32_t sys_usba_vbus_get()
{
    return drv_adc_read_multi_avg(SYS_USBA_VBUS_ADC_ID, 3) * drv_flash_trim_ref_volt_get() * SYS_USBA_VBUS_ADC_CONSTANT / ADC_REF_DIVISOR;
}

bool_t sys_usba_vbus_set(u32_t volt)
{
    if ((VOLTAGE_12V < volt) || (VOLTAGE_5V > volt))
        return FALSE;

    sync_enter_critical();

    if (g_sys_pd_info.usba_vbus_pwm_cali_offset_is_minus)
    {
        if (VOLTAGE_5V == volt)
        {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_DUTY_5V-g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
        else if (VOLTAGE_9V == volt)
        {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_DUTY_9V-g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
        else if (VOLTAGE_12V == volt)
        {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_DUTY_12V-g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
        else {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_VOLT_TO_DUTY(volt)-g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
    }
    else {
        if (VOLTAGE_5V == volt)
        {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_DUTY_5V+g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
        else if (VOLTAGE_9V == volt)
        {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_DUTY_9V+g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
        else if (VOLTAGE_12V == volt)
        {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_DUTY_12V+g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
        else {
            drv_pwm_duty_set(SYS_USBA_PWM_ID, SYS_DEF_USBA_PWM_VOLT_TO_DUTY(volt)+g_sys_pd_info.usba_vbus_pwm_cali_offset, SYS_DEF_USBA_PWM_PER);
        }
    }
    drv_pwm_en_set(SYS_USBA_PWM_ID, TRUE);

#if SYS_QUICK_CHARGE_ENABLED
    g_usba1_qc_info.vbus_volt = volt;
    g_usba2_qc_info.vbus_volt = volt;
#endif /* SYS_QUICK_CHARGE_ENABLED */

    sync_exit_critical();

    return TRUE;
}

void sys_usba_init()
{
    if (usbpd_cfg_port_usba_volt_calibration_en_get())
    {
        // calibrate the USBA PWM offset
        u32_t usba_vbus = sys_usba_vbus_get();
        if ((usba_vbus > VOLTAGE_5V) && ((usba_vbus - VOLTAGE_5V) > 200U))
        {
            g_sys_pd_info.usba_vbus_pwm_cali_offset = (usba_vbus-VOLTAGE_5V)/SYS_DEF_USBA_PWM_DUTY_STEP_VOLT;
            g_sys_pd_info.usba_vbus_pwm_cali_offset_is_minus = 0;
            sys_usba_vbus_set(VOLTAGE_5V);
        }
        else if ((usba_vbus < VOLTAGE_5V) && ((VOLTAGE_5V - usba_vbus) > 200U))
        {
            g_sys_pd_info.usba_vbus_pwm_cali_offset = (VOLTAGE_5V-usba_vbus)/SYS_DEF_USBA_PWM_DUTY_STEP_VOLT;
            g_sys_pd_info.usba_vbus_pwm_cali_offset_is_minus = 1;
            sys_usba_vbus_set(VOLTAGE_5V);
        }
#if CLI_ENABLED
    	if (sys_cfg_dbg_get()) 
        {
            printf("\nUSBA VBUS: %u, calibration:%s%u\n",usba_vbus,
                g_sys_pd_info.usba_vbus_pwm_cali_offset_is_minus?"-":" ",
                g_sys_pd_info.usba_vbus_pwm_cali_offset);
    	}
#endif /* CLI_ENABLED */
    }


    // read status reg
    sys_bat_status_reg_set(SYS_BAT_REG_GET(STATUS_REG));

    if (sys_gpio_usba1_insert_detect_get())
    {
        sys_gpio_usba1_power_on_set(TRUE);
        delay(500);
        sys_gpio_usba1_power_on_set(FALSE);
    }
    if (sys_gpio_usba2_insert_detect_get())
    {
        sys_gpio_usba2_power_on_set(TRUE);
        delay(500);
        sys_gpio_usba2_power_on_set(FALSE);
    }

    // read status reg again
    sys_bat_status_reg_set(SYS_BAT_REG_GET(STATUS_REG));
    
    g_sys_pd_info.usba1_indet_current_flag = sys_gpio_usba1_insert_detect_get();
    if (g_sys_pd_info.usba1_indet_current_flag)
    {
        g_sys_pd_info.usba1_indet_flag = g_sys_pd_info.usba1_indet_current_flag;
        sys_gpio_usba1_insert_detect_clear();
        sys_gpio_usba1_power_on_set(TRUE);
        g_sys_pd_info.usba_no_current_flow_flag = FALSE;
        g_sys_pd_info.usba1_disconnected_tick = 0;
        g_sys_pd_info.usba_no_current_start_tick = 0;
        if (g_sys_pd_info.usba2_qc_en_flag)
        {
            // disable a2 QC
            g_sys_pd_info.usba2_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
            dpm_qc_enable_set(&g_usba2_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
        }
#if CLI_ENABLED
		if (sys_cfg_dbg_get()) drv_uart_puts("A1 indet init");
#endif /* CLI_ENABLED */
    }

    g_sys_pd_info.usba2_indet_current_flag = sys_gpio_usba2_insert_detect_get();
    if (g_sys_pd_info.usba2_indet_current_flag)
    {
        g_sys_pd_info.usba2_indet_flag = g_sys_pd_info.usba2_indet_current_flag;
        sys_gpio_usba2_insert_detect_clear();
        sys_gpio_usba2_power_on_set(TRUE);
        g_sys_pd_info.usba_no_current_flow_flag = FALSE;
        g_sys_pd_info.usba2_disconnected_tick = 0;
        g_sys_pd_info.usba_no_current_start_tick = 0;
        if (g_sys_pd_info.usba1_qc_en_flag)
        {
            // disable a1 QC
            g_sys_pd_info.usba1_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
            dpm_qc_enable_set(&g_usba1_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
        }
#if CLI_ENABLED
		if (sys_cfg_dbg_get()) drv_uart_puts("A2 indet init");
#endif /* CLI_ENABLED */
    }
}

void sys_usba_restore()
{
    if ((g_sys_pd_info.usba2_indet_flag) && (g_sys_pd_info.usba1_indet_flag))
    {
        sys_usba_vbus_set(VOLTAGE_5V);
        sys_gpio_usba1_power_on_set(TRUE);
        sys_gpio_usba2_power_on_set(TRUE);
        g_sys_pd_info.usba_no_current_flow_flag = FALSE;
        g_sys_pd_info.usba1_disconnected_tick = 0;
        g_sys_pd_info.usba2_disconnected_tick = 0;
        g_sys_pd_info.usba_no_current_start_tick = 0;
#if CLI_ENABLED
    	if (sys_cfg_dbg_get()) printf("Restore: A1/A2 On\n");
#endif /* CLI_ENABLED */
    }
    else if (g_sys_pd_info.usba1_indet_flag)
    {
        sys_usba_vbus_set(VOLTAGE_5V);
        sys_gpio_usba1_power_on_set(TRUE);
        // Enable QC;
        g_sys_pd_info.usba1_qc_en_flag = TRUE;
#if SYS_QUICK_CHARGE_ENABLED
        if (usbpd_cfg_port_quick_charge_en_get())
        {
            dpm_qc_enable_set(&g_usba1_qc_info, TRUE, FALSE);
        }
#endif /* SYS_QUICK_CHARGE_ENABLED */
        g_sys_pd_info.usba_no_current_flow_flag = FALSE;
        g_sys_pd_info.usba1_disconnected_tick = 0;
        g_sys_pd_info.usba_no_current_start_tick = 0;
#if CLI_ENABLED
    	if (sys_cfg_dbg_get()) printf("Restore: A1 On\n");
#endif /* CLI_ENABLED */
    }
    else if (g_sys_pd_info.usba2_indet_flag)
    {
        sys_usba_vbus_set(VOLTAGE_5V);
        sys_gpio_usba2_power_on_set(TRUE);
        // Enable QC;
        g_sys_pd_info.usba2_qc_en_flag = TRUE;
#if SYS_QUICK_CHARGE_ENABLED
        if (usbpd_cfg_port_quick_charge_en_get())
        {
            dpm_qc_enable_set(&g_usba2_qc_info, TRUE, FALSE);
        }
#endif /* SYS_QUICK_CHARGE_ENABLED */
        g_sys_pd_info.usba_no_current_flow_flag = FALSE;
        g_sys_pd_info.usba2_disconnected_tick = 0;
        g_sys_pd_info.usba_no_current_start_tick = 0;
#if CLI_ENABLED
    	if (sys_cfg_dbg_get()) printf("Restore: A2 On\n");
#endif /* CLI_ENABLED */
    }
}

#endif /* SYS_POWER_BANK_ENABLED */

void sys_pd_idle_hook(u32_t arg)
{
    g_sys_pd_info.current_time = now();

    sys_tick_t start_time = now();

    if ((drv_timer_stopped(&(g_sys_pd_info.continuous_timer))) && 
        (!(drv_timer_expired(&(g_sys_pd_info.continuous_timer)))))
    {
        drv_timer_start(SYS_CONTINUOUS_TIMER_TIMEOUT, &(g_sys_pd_info.continuous_timer), NULL);
    }

    g_sys_pd_info.power_check_current_state = sys_gpio_power_check_detect();
    if (g_sys_pd_info.power_check_current_state)
    {
        if (g_sys_pd_info.power_check_current_state != g_sys_pd_info.power_check_last_state)
        {
            g_sys_pd_info.power_check_last_state = g_sys_pd_info.power_check_current_state;
#if CLI_ENABLED
            if (sys_cfg_dbg_get())
            {
                printf("\nPWR_CHK detected\n");
            }
#endif

#if SYS_POWER_KEY_DOUBLE_CLICK_CTRL
			g_sys_pd_info.key_down_cnt++;
#if CLI_ENABLED
			if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_2) printf("PWR_CHK det,%u\n", g_sys_pd_info.key_down_cnt);
#endif
#endif
        }
    }
    else {
#if SYS_POWER_KEY_DOUBLE_CLICK_CTRL
		if(1 == g_sys_pd_info.key_down_cnt)
		{
			if(0 == g_sys_pd_info.double_click_1st_hit_tick)
			{
				//printf ("wait another K-down,%u\n", g_sys_pd_info.key_down_cnt);
				g_sys_pd_info.double_click_1st_hit_tick = g_sys_pd_info.continuous_timer_tick;
			}
            else if ((g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.double_click_1st_hit_tick) && 
			    ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.double_click_1st_hit_tick) >= 8))
			{
				g_sys_pd_info.double_click_1st_hit_tick = 0;
				g_sys_pd_info.key_down_cnt = 0;
				//printf ("d-click time o,%u\n", g_sys_pd_info.key_down_cnt);
			}
		}
        else if ((1 < g_sys_pd_info.key_down_cnt) && g_sys_pd_info.double_click_1st_hit_tick && 
		    (g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.double_click_1st_hit_tick) && 
		    ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.double_click_1st_hit_tick) < 8))
		{
            if (g_sys_pd_info.prevent_auto_poweroff)
            {
                g_sys_pd_info.prevent_auto_poweroff = FALSE;
                g_sys_pd_info.low_current_mode_start_tick = 0;
                sys_hub_ctrl_set(FALSE);
                sys_gpio_hub_led_off();
            }
            else {
                sys_hub_ctrl_set(TRUE);
                sys_gpio_hub_led_on();
                g_sys_pd_info.prevent_auto_poweroff = TRUE;
                if (!g_sys_pd_info.low_current_mode_start_tick)
                {
                    g_sys_pd_info.low_current_mode_start_tick = g_sys_pd_info.continuous_timer_tick;
                }
            }
			g_sys_pd_info.double_click_1st_hit_tick = 0;
			g_sys_pd_info.key_down_cnt = 0;
		}
        else
		{
			g_sys_pd_info.double_click_1st_hit_tick = 0;
			g_sys_pd_info.key_down_cnt = 0;
		}
#endif
        g_sys_pd_info.power_check_last_state = FALSE;
    }

    //handler QC state machine
#if SYS_QUICK_CHARGE_ENABLED
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        if (g_sys_pd_info.usba1_qc_en_flag)
        {
            dpm_qc_state_machine(&g_usba1_qc_info);
        }
        if (g_sys_pd_info.usba2_qc_en_flag)
        {
            dpm_qc_state_machine(&g_usba2_qc_info);
        }
    }
#endif /* SYS_QUICK_CHARGE_ENABLED */

    // handle system process here per 100ms
    if (drv_timer_expired(&(g_sys_pd_info.continuous_timer)))
    {
        g_sys_pd_info.continuous_timer_tick++;

        if (g_sys_pd_info.sys_initializing)
	    {
#if SYS_LED_ENABLED  /* modified by James Gan - 2019-11-22 */
            sys_pd_init_display();
#else
            // after system init 1.6 seconds, we need to enable short foldback feature
            if (16 <= g_sys_pd_info.continuous_timer_tick)
            {
                g_sys_pd_info.sys_initializing = FALSE;
                sys_bat_dis_foldback_set(FALSE);
                sys_bat_dis_term_set(FALSE);
                sys_bat_cap_cali();
            }
#endif /* #if SYS_LED_ENABLED */
        }
        else {
            // read status reg
            sys_bat_status_reg_set(SYS_BAT_REG_GET(STATUS_REG));

            // C1 over current check
            if (dpm_source_ocp_flag_get() && dpm_vbus_source_en_get())
            {
                dpm_vbus_source_en_set(FALSE);
                sys_gpio_pd_qc_led_off();
                sys_pd_led_state_set(SYS_PD_LED_STATE_FLASH_FAST);
#if CLI_ENABLED
    			if (sys_cfg_dbg_get()) printf("OCP: %umV\n",dpm_vbus_volt_get());
#endif /* CLI_ENABLED */
            }

#if SYS_POWER_BANK_ENABLED
            sys_bat_vbat_update();

            // Dead battery checking
            if ((!sys_bat_charging_flag_get()) && 
                (!pe_prs_in_prog_get()) && 
                (!dpm_port_dead_battery_get()) && 
                (((sys_bat_current_vbat_val_get() > SYS_BAT_INVALID_VOLT) && (sys_bat_current_vbat_val_get() <= SYS_BAT_DEAD_VOLT))))
            {
                sys_bat_dead_check_cnt_inc(1);
                if (sys_bat_dead_check_cnt_get() >= SYS_POWER_BANK_CHECK_DEAD_BATTERY_CNT)
                {
                    dpm_port_dead_battery_set(TRUE);
                    
#if CLI_ENABLED
    				if (sys_cfg_dbg_get()) printf("Dead Bat:%umV\n",sys_bat_current_vbat_val_get());
#endif /* CLI_ENABLED */
                    
                    if (DPM_CC_ATTACHED_SRC == dpm_cc_state_get())
                    {
                        dpm_vbus_source_en_set(FALSE);
                    }

                    // disable USB-A
                    sys_usba_vbus_set(VOLTAGE_5V);
                    sys_gpio_usba1_power_on_set(FALSE);
                    sys_gpio_usba2_power_on_set(FALSE);

                    //Need to flash battery cap LEDs to notice dead battery
                    sys_gpio_pd_qc_led_off();
                    sys_bat_state_set(SYS_BAT_STATE_DEAD_BATTERY);
                    sys_pd_led_state_set(SYS_PD_LED_STATE_FLASH_FAST);
                    sys_bat_dead_check_cnt_set(0);
                }
            }

            // process every 200ms
            if (0 == (g_sys_pd_info.continuous_timer_tick & 0x1))
            {
                // get ibat value
                g_sys_bat_info.current_ibat_val = sys_bat_ibat_val_get();

                g_sys_pd_info.vbus_current = sys_bat_vbus_fb_val_get();
                g_sys_pd_info.ibus_current = sys_bat_ibus_val_get();

                {
                    // C1 power
                    g_sys_pd_info.c1_current_pwr = g_sys_pd_info.vbus_current * g_sys_pd_info.ibus_current;

                    if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                    {
                        // A port power
                        u32_t usba_pwr = 0;
                        if (g_sys_pd_info.usba_ibus_avg_val > SYS_USBA_IBUS_HAS_CURRENT_FLOW_THR)
                        {
                            usba_pwr = g_sys_pd_info.usba_ibus_avg_val + 50;
                            usba_pwr = usba_pwr * sys_usba_vbus_get() / SYS_BAT_DISCHARGING_EFFICIENCY;
                        }

                        // available charge power 
                        g_sys_pd_info.c1_current_pwr *= SYS_BAT_CHARGING_EFFICIENCY;

                        if (g_sys_pd_info.c1_current_pwr > usba_pwr)
                        {
                            sys_bat_charging_flag_set(TRUE);
                            if (sys_bat_charging_flag_get() != sys_bat_charging_pre_flag_get())
                            {
                                sys_bat_charging_pre_flag_set(sys_bat_charging_flag_get());
                        		g_sys_pd_info.bat_cap_indicator_pre_charge = 0;
                        		g_sys_pd_info.bat_cap_indicator_pre_discharge = 100;
                            }
                            sys_bat_state_set(SYS_BAT_STATE_CHARGE);
                        }
                        else {
                            sys_bat_charging_flag_set(FALSE);
                            if (sys_bat_charging_flag_get() != sys_bat_charging_pre_flag_get())
                            {
                                sys_bat_charging_pre_flag_set(sys_bat_charging_flag_get());
                        		g_sys_pd_info.bat_cap_indicator_pre_charge = 0;
                        		g_sys_pd_info.bat_cap_indicator_pre_discharge = 100;
                                sys_bat_charging_full_flag_set(FALSE);
                                sys_bat_charging_full_tick_set(0);
                            }
                            sys_bat_state_set(SYS_BAT_STATE_DISCHARGE);
                            sys_bat_current_ibat_val_set((usba_pwr - g_sys_pd_info.c1_current_pwr) / sys_bat_current_vbat_val_get());
                        }
                    }
                    else {
                        sys_bat_charging_flag_set(FALSE);
                        if (sys_bat_charging_flag_get() != sys_bat_charging_pre_flag_get())
                        {
                    		g_sys_pd_info.bat_cap_indicator_pre_charge = 0;
                    		g_sys_pd_info.bat_cap_indicator_pre_discharge = 100;
                            sys_bat_charging_pre_flag_set(sys_bat_charging_flag_get());
                        }
                        if ((g_sys_pd_info.usba_ibus_avg_val > SYS_USBA_IBUS_HAS_CURRENT_FLOW_THR) || 
                            (dpm_port_state_get() == DPM_PORT_STATE_DISCHARGE))
                        {
                            sys_bat_state_set(SYS_BAT_STATE_DISCHARGE);
                        }
                        else if ((g_sys_pd_info.usba_ibus_avg_val <= SYS_USBA_IBUS_NO_CURRENT_FLOW_THR) && 
                            (dpm_port_state_get() == DPM_PORT_STATE_IDLE))
                        {
                            sys_bat_state_set(SYS_BAT_STATE_IDLE);
                        }
                    }

#if SYS_POWER_SOURCE_NO_CURRENT_HRST
                    if ((dpm_cable_detect_done_get()) && 
                        (dpm_current_pwr_mode_get()) && 
                        (pe_pd_connected_time_get()) && 
                        ((u32_t)(now() - pe_pd_connected_time_get()) > 3000000UL) &&
                        (!dpm_hrst_due_to_no_current_flag_get()) && 
                        (POWER_PROFILE_30W_FIXED <= usbpd_cfg_port_src_fixed_pwr_prof_get()) && 
                        (dpm_src_obj_pos_get() > 1) && 
                        (10 < g_sys_pd_info.ibus_current) && (g_sys_pd_info.ibus_current < 150))
                    {
                        dpm_hrst_due_to_no_current_flag_set(TRUE);
                        dpm_hard_reset_req_set(TRUE);
#if CLI_ENABLED
                        if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_1)
                        {
                            printf ("Need to hrst due to no current.\n");
                        }
#endif
                    }
#endif /* SYS_POWER_SOURCE_NO_CURRENT_HRST */
                }

                // check capacity
                sys_bat_capacity_check();

                g_sys_pd_info.usba_ibus_accum_val += sys_usba_ibus_get();
                g_sys_pd_info.usba_ibus_accum_val_idx++;

                // power down detection 
#if SYS_POWER_BANK_POWER_DOWN_DETECT
                g_sys_pd_info.power_down_detect_current_state = g_sys_pd_info.power_check_current_state;
                if (g_sys_pd_info.power_down_detect_current_state)
                {
                    if (g_sys_pd_info.power_down_detect_current_state != g_sys_pd_info.power_down_detect_last_state)
                    {
                        g_sys_pd_info.power_down_detect_last_state = g_sys_pd_info.power_down_detect_current_state;
                        g_sys_pd_info.power_down_detect_start_time = g_sys_pd_info.current_time;
                        g_sys_pd_info.auto_power_down_last_tick = 0;
                        if (dpm_port_dead_battery_get() && (!sys_bat_charging_flag_get()))
                        {
                            sys_bat_state_set(SYS_BAT_STATE_DEAD_BATTERY);
                            sys_pd_led_state_set(SYS_PD_LED_STATE_FLASH_FAST);
                        }
                        else {
                            sys_pd_led_state_set(SYS_PD_LED_STATE_ON);
                        }
                        if (sys_bat_charging_full_tick_get() && (g_sys_pd_info.continuous_timer_tick > SYS_BAT_CHARGE_FULL_DETETION_TIME))
                        {
                            sys_bat_charging_full_tick_set(g_sys_pd_info.continuous_timer_tick - SYS_BAT_CHARGE_FULL_DETETION_TIME);
                        }
#if SYS_OVERTEMP_DECTION_ENABLED
                        if ((!dpm_port_dead_battery_get()) && (!g_sys_pd_info.p60c_otp_flag) && (!g_sys_pd_info.m10c_otp_flag))
#else
                        if (!dpm_port_dead_battery_get())
#endif
                        {
                            // restore OCP
                            if (g_sys_pd_info.usba_no_current_flow_flag && g_sys_pd_info.usba_ocp_flag)
                            {
                                g_sys_pd_info.usba_ocp_flag = FALSE;
#if CLI_ENABLED
                				if (sys_cfg_dbg_get()) printf("Restore USB when no OCP\n");
#endif /* CLI_ENABLED */
                                sys_usba_restore();
                            }
                            if (dpm_source_ocp_flag_get())
                            {
#if CLI_ENABLED
                				if (sys_cfg_dbg_get()) printf("Restore C1 when no OCP\n");
#endif /* CLI_ENABLED */
                                dpm_source_ocp_flag_set(FALSE);
                                if (dpm_cable_detect_done_get() && 
                                    pe_pd_connected_get())
                                {
                                    dpm_hard_reset_req_set(TRUE);
                                    pe_state_machine();
                                }
                            }
                        }
                    }
                    if ((dpm_port_state_get() != DPM_PORT_STATE_CHARGE) && 
                        (g_sys_pd_info.power_down_detect_last_state) && 
                        (g_sys_pd_info.power_down_detect_start_time) && 
                        (g_sys_pd_info.current_time > g_sys_pd_info.power_down_detect_start_time) && 
                        ((g_sys_pd_info.current_time - g_sys_pd_info.power_down_detect_start_time) > SYS_POWER_BANK_POWER_DOWN_DETECT_DURATION))
                    {
                        g_sys_pd_info.power_down_detect_last_state = FALSE;
#if CLI_ENABLED
    					if (sys_cfg_dbg_get()) printf("Off\n");
#endif /* CLI_ENABLED */
#if SYS_CAPACITY_PARA_SAVE_TO_FLASH
                        sys_capacity_set(sys_bat_capacity_get());
                        sys_capacity_reset_flag_set(FALSE);
    					sys_capacity_para_save();
#endif
                        if (dpm_port_dead_battery_get())
                        {
                            dpm_port_dead_battery_set(FALSE);
                            sys_bat_state_set(SYS_BAT_STATE_IDLE);
                        }
                        sys_pd_display_flash_manually(3,FALSE);
                        sys_pd_led_state_set(SYS_PD_LED_STATE_OFF);
                        while (sys_gpio_power_check_detect())
                        {
                            if ((now() - g_sys_pd_info.power_down_detect_start_time) > SYS_POWER_BANK_POWER_DOWN_DETECT_DURATION_UL)
                            {
                                sys_pd_display_flash_manually(3,TRUE);
                            }
                        }
                        if ((now() - g_sys_pd_info.power_down_detect_start_time) > SYS_POWER_BANK_POWER_DOWN_DETECT_DURATION_UL)
                        {
                            sys_cfg_erase();
                            sys_capacity_para_erase();
                        }
                        // disable USB-A
                        sys_usba_vbus_set(VOLTAGE_5V);
                        sys_gpio_usba1_power_on_set(FALSE);
                        sys_gpio_usba2_power_on_set(FALSE);
                        dpm_cc_state_release();
                        dpm_cc_state_init();
                        dpm_rp_rd_clear();
                        //sys_cmd_port_disable_set(TRUE);
                        rtc_delay_us(1000000UL);
                        sys_gpio_power_on_set(OFF);
                    }
                }
                else {
                    g_sys_pd_info.power_down_detect_last_state = 0;
                    g_sys_pd_info.power_down_detect_start_time = 0;
                }
#endif

#if (0) /*SYS_POWER_KEY_DOUBLE_CLICK_CTRL*/
                g_sys_pd_info.prevent_auto_poweroff_last_state = g_sys_pd_info.prevent_auto_poweroff;
                if (g_sys_pd_info.power_key_current_state & SYS_POWER_KEY_DOUBLE_CLICK_CHECKED)
                {
                    if (!dpm_port_dead_battery_get())
                    {
                        g_sys_pd_info.prevent_auto_poweroff = TRUE;
                    }
                    if (!g_sys_pd_info.low_current_mode_start_tick)
                    {
                        g_sys_pd_info.low_current_mode_start_tick = g_sys_pd_info.continuous_timer_tick;
                    }
                }
                else {
                    g_sys_pd_info.prevent_auto_poweroff = FALSE;
                    g_sys_pd_info.low_current_mode_start_tick = 0;
                }
#endif /* SYS_POWER_KEY_DOUBLE_CLICK_CTRL */

                // usb-a current check
                if (g_sys_pd_info.usba_ibus_accum_val_idx >= SYS_USBA_IBUS_ACCUM_VAL_IDX_MAX)
                {
                    g_sys_pd_info.usba_ibus_avg_val = g_sys_pd_info.usba_ibus_accum_val / g_sys_pd_info.usba_ibus_accum_val_idx;
    				g_sys_pd_info.usba_ibus_accum_val = 0;
                    g_sys_pd_info.usba_ibus_accum_val_idx = 0;

                    g_sys_pd_info.usba_no_current_flow_last_flag = g_sys_pd_info.usba_no_current_flow_flag;
                    if (g_sys_pd_info.usba_ibus_avg_val <= SYS_USBA_IBUS_NO_CURRENT_FLOW_THR)
                    {
                        g_sys_pd_info.usba_no_current_flow_flag = TRUE;
                    }
                    else if (g_sys_pd_info.usba_ibus_avg_val >= SYS_USBA_IBUS_HAS_CURRENT_FLOW_THR)
                    {
                        g_sys_pd_info.usba_no_current_flow_flag = FALSE;
                    }
                    if (g_sys_pd_info.usba_no_current_flow_last_flag != g_sys_pd_info.usba_no_current_flow_flag)
                    {
                        if (!g_sys_pd_info.usba_no_current_flow_flag)
                        {
                            sys_bat_dis_term_set(TRUE);
                            sys_pd_led_state_set(SYS_PD_LED_STATE_ON);
                            g_sys_pd_info.usba_no_current_start_tick = 0;
                        }
                        else {
                            if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE))
                            {
                                sys_bat_dis_term_set(FALSE);
                                if (sys_bat_charging_full_tick_get() && (g_sys_pd_info.continuous_timer_tick > SYS_BAT_CHARGE_FULL_DETETION_TIME))
                                {
                                    sys_bat_charging_full_tick_set(g_sys_pd_info.continuous_timer_tick - SYS_BAT_CHARGE_FULL_DETETION_TIME);
                                }
                                sys_pd_led_state_set(SYS_PD_LED_STATE_ON);
                            }
                            g_sys_pd_info.usba_no_current_start_tick = g_sys_pd_info.continuous_timer_tick;
                        }
                    }
                    
                    // auto power off
#if SYS_POWER_BANK_AUTO_POWER_DOWN_EN
                    if (usbpd_cfg_port_auto_power_down_get() && (!dpm_port_dead_battery_get()))
                    {
#if SYS_POWER_KEY_DOUBLE_CLICK_CTRL  /* modified by James Gan - 2019-01-15 */
        				if ((!dpm_cable_detect_done_get()) && 
                            (((FALSE == g_sys_pd_info.prevent_auto_poweroff) && (g_sys_pd_info.usba_no_current_flow_flag)) || 
                             (g_sys_pd_info.prevent_auto_poweroff && g_sys_pd_info.low_current_mode_start_tick &&
                             (g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.low_current_mode_start_tick) && 
                             ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.low_current_mode_start_tick) > SYS_LOW_CURRENT_MODE_FORCE_POWER_OFF_TIME))))
#else
        				if ((g_sys_pd_info.usba_no_current_flow_flag) && 
                            (!dpm_cable_detect_done_get()))
#endif /* #if SYS_POWER_KEY_DOUBLE_CLICK_CTRL */
                        {
                            if (!g_sys_pd_info.auto_power_down_last_tick)
                            {
                                g_sys_pd_info.auto_power_down_last_tick = g_sys_pd_info.continuous_timer_tick;
                            }

                            if (g_sys_pd_info.auto_power_down_last_tick && 
                                (g_sys_pd_info.continuous_timer_tick > g_sys_pd_info.auto_power_down_last_tick))
                            {
                                if ((!dpm_port_dead_battery_get()) && 
                                    ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.auto_power_down_last_tick) >= SYS_POWER_BANK_IDLE_DETECT_DURATION))
                                {
                                    sys_pd_led_state_set(SYS_PD_LED_STATE_OFF);
                                }

                                if ((g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.auto_power_down_last_tick) >= SYS_POWER_BANK_AUTO_POWER_DOWN_DELAY)
                                {
                                    g_sys_pd_info.usba_no_current_flow_last_flag = FALSE;
#if CLI_ENABLED
        							if (sys_cfg_dbg_get()) printf("Auto off\n");
#endif /* CLI_ENABLED */
                                    // flash 3 times
#if SYS_CAPACITY_PARA_SAVE_TO_FLASH
        							sys_capacity_set(sys_bat_capacity_get());
                                    sys_capacity_reset_flag_set(FALSE);
        					        sys_capacity_para_save();
#endif
                                    if (dpm_port_dead_battery_get())
                                    {
                                        dpm_port_dead_battery_set(FALSE);
                                        sys_bat_state_set(SYS_BAT_STATE_IDLE);
                                    }
                                    sys_pd_display_flash_manually(3,FALSE);
                                    //sys_pd_led_state_set(SYS_PD_LED_STATE_OFF);
                                    //sys_cmd_port_disable_set(TRUE);
                                    // disable USB-A
                                    sys_usba_vbus_set(VOLTAGE_5V);
                                    sys_gpio_usba1_power_on_set(FALSE);
                                    sys_gpio_usba2_power_on_set(FALSE);
                                    rtc_delay_us(1000000UL);
                                    sys_gpio_power_on_set(OFF);
                                }
                            }
                        }
                        else {
                            g_sys_pd_info.auto_power_down_last_tick = 0;
                        }
                    }
#endif
                }

                // dead battery
                if (dpm_port_dead_battery_get())
                {
                    if (!pe_prs_in_prog_get())
                    {
                        /* Enable charging in non-PD mode, and clear dead battery flag */
                        if ((((PE_SNK_READY == pe_state_get()) && 
                            (1 <= dpm_rx_src_cap_num_get()) && 
                            (dpm_rx_src_cap_max_power_get() >= DEFAULT_MIN_PD_POWER)) || 
                            ((DPM_CC_ATTACHED_SNK == dpm_cc_state_get()) && 
                            ((g_pe_info.hard_reset_cnt > N_HARD_RESET_CNT)))))
                        {
                            if ((PE_SNK_READY == pe_state_get()) && (1 == dpm_rx_src_cap_num_get()) && 
                                (((UPD_DATA_MSG_SOURCE_CAP_FIXED_SUPPLY_t *)dpm_rx_src_cap_object_get(CFG_VOLTAGE_5V_IDX))->dual_role_pwr) && 
                                (((UPD_DATA_MSG_SOURCE_CAP_FIXED_SUPPLY_t *)dpm_rx_src_cap_object_get(CFG_VOLTAGE_5V_IDX))->usb_comm_cap))
                            {
#if CLI_ENABLED
                        		if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_2) printf("NC\n");
#endif /* CLI_ENABLED */
                            }
                            else {
#if CLI_ENABLED
    					        if (sys_cfg_dbg_get()) printf("Dead exit:%umV\n", sys_bat_current_vbat_val_get());
#endif /* CLI_ENABLED */
                                dpm_port_dead_battery_set(FALSE);
                                sys_usba_restore();
                                if (sys_pd_led_state_get() == SYS_PD_LED_STATE_FLASH_FAST)
                                {
                                    sys_bat_state_set(SYS_BAT_STATE_CHARGE);
                                    sys_pd_led_state_set(SYS_PD_LED_STATE_ON);
                                }
                            }
                        }
                    }
                }
            }

#if SYS_OVERTEMP_DECTION_ENABLED
            if ((g_sys_pd_info.continuous_timer_tick & 3) == 0)
            {
                if (!g_sys_pd_info.ntc_test_flag)
                {
                    g_sys_pd_info.ntc_volt = drv_adc_read_multi_avg(SYS_NTC_ADC_ID,5) * drv_flash_trim_ref_volt_get() * 10 / ADC_REF_DIVISOR;
                }
                g_sys_pd_info.p60c_otp_pre_flag = g_sys_pd_info.p60c_otp_flag;
                g_sys_pd_info.p55c_otp_pre_flag = g_sys_pd_info.p55c_otp_flag;
                g_sys_pd_info.p45c_otp_pre_flag = g_sys_pd_info.p45c_otp_flag;
                g_sys_pd_info.p0c_otp_pre_flag = g_sys_pd_info.p0c_otp_flag;
                g_sys_pd_info.m10c_otp_pre_flag = g_sys_pd_info.m10c_otp_flag;
                if (g_sys_pd_info.ntc_volt < DPM_TEMP_INVALID_VOLT)
                {
                    /** Temperature greater than 60C, disable charge and discharge */
                    if (g_sys_pd_info.ntc_volt <= DPM_TEMP_P60C_VOLT)
                    {
                        if (!g_sys_pd_info.p60c_otp_flag)
                        {
                            g_sys_pd_info.p60c_otp_flag = TRUE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("DCHG:OTP 60C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                        {
                            if (!g_sys_pd_info.charging_current_saved)
                            {
                                g_sys_pd_info.charging_current_saved = sys_bat_rated_charging_current_get();
                            }
                            sys_bat_rated_charging_current_set(0);
                            sys_bat_ibus_set(0);
                        }

#if SYS_QUICK_CHARGE_ENABLED
                        if (usbpd_cfg_port_quick_charge_en_get())
                        {
                            dpm_qc_enable_set(&g_usbc_qc_info, FALSE, FALSE);
                        }
#endif
                        if (dpm_vbus_source_en_get())
                        {
                            dpm_vbus_source_en_set(FALSE);
                        }
                        sys_gpio_usba1_power_on_set(FALSE);
                        sys_gpio_usba2_power_on_set(FALSE);
                        sys_gpio_pd_qc_led_off();
                    }
                    else if (g_sys_pd_info.ntc_volt <= DPM_TEMP_P55C_VOLT) /** Temperature greater than 55C, disable charge */
                    {
                        if (!g_sys_pd_info.p55c_otp_flag)
                        {
                            g_sys_pd_info.p55c_otp_flag = TRUE;
#if CLI_ENABLED
        				    if (sys_cfg_dbg_get()) printf("DCHG:OTP 60-55C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }

                        if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                        {
                            if (!g_sys_pd_info.charging_current_saved)
                            {
                                g_sys_pd_info.charging_current_saved = sys_bat_rated_charging_current_get();
                            }
                            sys_bat_rated_charging_current_set(0);
                            sys_bat_ibus_set(0);
                        }
                    }
                    else if (g_sys_pd_info.ntc_volt <= DPM_TEMP_P45C_VOLT) /** Temperature greater than 45C, halve charge power */
                    {
                        if (g_sys_pd_info.p60c_otp_flag)
                        {
                            g_sys_pd_info.p60c_otp_flag = FALSE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("DCHG:OTR 60C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (g_sys_pd_info.m10c_otp_flag)
                        {
                            g_sys_pd_info.m10c_otp_flag = FALSE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("DCHG:OTR -10C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (!g_sys_pd_info.p45c_otp_flag)
                        {
                            g_sys_pd_info.p45c_otp_flag = TRUE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("CHG:OTP 45C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                        {
                            if (!g_sys_pd_info.charging_current_saved)
                            {
                                g_sys_pd_info.charging_current_saved = sys_bat_rated_charging_current_get();
                                sys_bat_rated_charging_current_set((sys_bat_rated_charging_current_get() >> 1));
                                sys_bat_ibus_set(sys_bat_rated_charging_current_get());
                            }
                        }
                    }
                    else if (g_sys_pd_info.ntc_volt <= DPM_TEMP_0C_VOLT)
                    {
                        if (g_sys_pd_info.p60c_otp_flag)
                        {
                            g_sys_pd_info.p60c_otp_flag = FALSE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("DCHG:OTR 60C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (g_sys_pd_info.m10c_otp_flag)
                        {
                            g_sys_pd_info.m10c_otp_flag = FALSE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("DCHG:OTR -10C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (g_sys_pd_info.p45c_otp_flag)
                        {
                            g_sys_pd_info.p45c_otp_flag = FALSE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("CHG:OTR 0-45C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if ((dpm_port_state_get() == DPM_PORT_STATE_CHARGE) && 
                            (g_sys_pd_info.charging_current_saved))
                        {
                            sys_bat_rated_charging_current_set(g_sys_pd_info.charging_current_saved);
                            sys_bat_ibus_set(g_sys_pd_info.charging_current_saved);
                            g_sys_pd_info.charging_current_saved = 0;
                        }
                    }
                    else if (g_sys_pd_info.ntc_volt <= DPM_TEMP_M10C_VOLT)
                    {
                        if (!g_sys_pd_info.p0c_otp_flag)
                        {
                            g_sys_pd_info.p0c_otp_flag = TRUE;
#if CLI_ENABLED
        				    if (sys_cfg_dbg_get()) printf("CHG:OTP -10-0C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }

                        if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                        {
                            if (!g_sys_pd_info.charging_current_saved)
                            {
                                g_sys_pd_info.charging_current_saved = sys_bat_rated_charging_current_get();
                            }
                            sys_bat_rated_charging_current_set(0);
                            sys_bat_ibus_set(0);
                        }
                    }
                    else if (g_sys_pd_info.ntc_volt > DPM_TEMP_M10C_VOLT)
                    {
                        if (!g_sys_pd_info.m10c_otp_flag)
                        {
                            g_sys_pd_info.m10c_otp_flag = TRUE;
#if CLI_ENABLED
            				if (sys_cfg_dbg_get()) printf("DCHG:OTP -10C(%u)\n",g_sys_pd_info.ntc_volt);
#endif /* CLI_ENABLED */
                        }
                        if (dpm_port_state_get() == DPM_PORT_STATE_CHARGE)
                        {
                            if (!g_sys_pd_info.charging_current_saved)
                            {
                                g_sys_pd_info.charging_current_saved = sys_bat_rated_charging_current_get();
                            }
                            sys_bat_rated_charging_current_set(0);
                            sys_bat_ibus_set(0);
                        }

#if SYS_QUICK_CHARGE_ENABLED
                        if (usbpd_cfg_port_quick_charge_en_get())
                        {
                            dpm_qc_enable_set(&g_usbc_qc_info, FALSE, FALSE);
                        }
#endif
                        if (dpm_vbus_source_en_get())
                        {
                            dpm_vbus_source_en_set(FALSE);
                        }
                        sys_gpio_usba1_power_on_set(FALSE);
                        sys_gpio_usba2_power_on_set(FALSE);
                        sys_gpio_pd_qc_led_off();
                    }

                    // retore 
                    if ((((g_sys_pd_info.p60c_otp_pre_flag)&& (!g_sys_pd_info.p60c_otp_flag)) || 
                        ((g_sys_pd_info.m10c_otp_pre_flag)&& (!g_sys_pd_info.m10c_otp_flag))) && 
                        (!dpm_port_dead_battery_get()))
                    {
                        sys_usba_restore();
                        if ((dpm_cable_detect_done_get()) && 
                            (dpm_current_pwr_mode_get()))
                        {
                            if (pe_pd_connected_get())
                            {
                                dpm_hard_reset_req_set(TRUE);
                                pe_state_machine();
                            }
                            else {
                                dpm_vbus_source_en_set(TRUE);
#if SYS_QUICK_CHARGE_ENABLED
                                if (usbpd_cfg_port_quick_charge_en_get())
                                {
                                    dpm_qc_enable_set(&g_usbc_qc_info, TRUE, FALSE);
                                }
#endif
                            }
                        }
                    }
                }
            }
#endif /* SYS_OVERTEMP_DECTION_ENABLED */

            // Current compensation every 500ms
            if ((g_sys_pd_info.continuous_timer_tick % 5) == 0)
            {
                if (dpm_cable_detect_done_get())
                {
                    if (POWER_MODE_SINK == dpm_current_pwr_mode_get() && 
                        (!pe_prs_in_prog_get()))
                    {
                        // need to draw current flow smoothly
                        sys_bat_charge_current_update();
                    }
#if SYS_VOLTAGE_COMPENSATION_ENABLED
                    else if (dpm_current_pwr_mode_get() && 
                        (!dpm_port_dead_battery_get()) && 
                        pe_pd_connected_get() && 
                        (!pe_prs_in_prog_get()) && 
                        (dpm_src_obj_pos_get() > 0) && 
                        (POWER_SUPPLY_TYPE_FIXED == usbpd_cfg_port_src_pwr_supply_type_get((dpm_src_obj_pos_get()-1))))
                    {
                        u32_t vbus_cfg = usbpd_cfg_port_src_fixed_pwr_volt_cap_get((dpm_src_obj_pos_get()-1))*VOLTAGE_DIV + SYS_POWER_BANK_VOLTAGE_COMPENSATION;
                        u32_t ibus_cfg = usbpd_cfg_port_src_fixed_pwr_curr_cap_get((dpm_src_obj_pos_get()-1))*CURRENT_DIV + SYS_POWER_BANK_CURRENT_COMPENSATION;
                        if (g_sys_pd_info.ibus_current >= 4000)
                        {
                            sys_bat_discharge_vbus_ibus_set(vbus_cfg+500U,ibus_cfg);
                        }
                        else if (g_sys_pd_info.ibus_current >= 3200)
                        {
                            sys_bat_discharge_vbus_ibus_set(vbus_cfg+400U,ibus_cfg);
                        }
                        else if (g_sys_pd_info.ibus_current >= 2400)
                        {
                            sys_bat_discharge_vbus_ibus_set(vbus_cfg+300U,ibus_cfg);
                        }
                        else if (g_sys_pd_info.ibus_current >= 1600)
                        {
                            sys_bat_discharge_vbus_ibus_set(vbus_cfg+200U,ibus_cfg);
                        }
                        else if (g_sys_pd_info.ibus_current >= 800)
                        {
                            sys_bat_discharge_vbus_ibus_set(vbus_cfg+100U,ibus_cfg);
                        }
                        else
                        {
                        	sys_bat_discharge_vbus_ibus_set(vbus_cfg,ibus_cfg);
        				}
                    }
#endif /* SYS_VOLTAGE_COMPENSATION_ENABLED */
                }

                // handle digit or led display
                sys_pd_display_state_machine();
    	        sys_pd_display_process();
            }

            // Check the capacity every 800 ms 
            if (0 == (g_sys_pd_info.continuous_timer_tick & 0x7))
            {
#if SYS_SMG_DISPLAY_ENABLED  /* modified by James Gan - 2019-11-25 */
                if ((dpm_cable_detect_done_get()) && 
                    (sys_bat_charging_flag_get()) && 
                    (!dpm_current_pwr_mode_get()) && 
                    (sys_bat_capacity_get() >= 100) && 
                    (sys_bat_avg_ibat_val_get() < 300) && 
                    (sys_bat_charging_start_tick_get() > 0) &&
                    (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_start_tick_get()) && 
                    ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_start_tick_get()) > SYS_BAT_CHARGE_FULL_DETETION_TIME) && 
                    (!sys_bat_charging_full_tick_get()))
                {
                    sys_bat_charging_full_tick_set(g_sys_pd_info.continuous_timer_tick);
                }
#else
                if ((dpm_cable_detect_done_get()) && 
                    (sys_bat_charging_flag_get()) && 
                    (!dpm_current_pwr_mode_get()) && 
                    (sys_bat_capacity_get() >= 90) && 
                    (sys_bat_avg_ibat_val_get() < 300) && 
                    (sys_bat_charging_start_tick_get() > 0) &&
                    (g_sys_pd_info.continuous_timer_tick > sys_bat_charging_start_tick_get()) && 
                    ((g_sys_pd_info.continuous_timer_tick - sys_bat_charging_start_tick_get()) > SYS_BAT_CHARGE_FULL_DETETION_TIME) && 
                    (!sys_bat_charging_full_tick_get()))
                {
                    sys_bat_charging_full_tick_set(g_sys_pd_info.continuous_timer_tick);
                }
#endif /* #if SYS_SMG_DISPLAY_ENABLED */
            }

            // usb-a insert detection
            {
#if SYS_OVERTEMP_DECTION_ENABLED
            	if ((!g_sys_pd_info.p60c_otp_flag) &&
                    (!g_sys_pd_info.m10c_otp_flag) && 
                    (!dpm_port_dead_battery_get()))
#else
                if (!dpm_port_dead_battery_get())
#endif
                {
                    if (g_sys_pd_info.prevent_auto_poweroff)
                    {
                        if (g_sys_pd_info.prevent_auto_poweroff_last_state != g_sys_pd_info.prevent_auto_poweroff)
                        {
                            g_sys_pd_info.prevent_auto_poweroff_last_state = g_sys_pd_info.prevent_auto_poweroff;

                            sys_usba_vbus_set(VOLTAGE_5V);
                            // disable QC
                            g_sys_pd_info.usba1_qc_en_flag = FALSE;
                            g_sys_pd_info.usba2_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
                            dpm_qc_enable_set(&g_usba1_qc_info, FALSE, FALSE);
                            dpm_qc_enable_set(&g_usba2_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
#if CLI_ENABLED
            	            if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_1) printf("DCHG LI\n");
#endif /* CLI_ENABLED */
                            if (!g_sys_pd_info.usba_ocp_flag)
                            {
                                if (!sys_gpio_usba1_power_on_get())
                                {
                                    sys_gpio_usba1_power_on_set(TRUE);
                                    g_sys_pd_info.usba_no_current_flow_flag = FALSE;
                                    g_sys_pd_info.usba1_disconnected_tick = 0;
                                    g_sys_pd_info.usba_no_current_start_tick = 0;
#if CLI_ENABLED
                        			if (sys_cfg_dbg_get()) printf("A1 On\n");
#endif /* CLI_ENABLED */
                                }
                                if (!sys_gpio_usba2_power_on_get())
                                {
                                    sys_gpio_usba2_power_on_set(TRUE);
                                    g_sys_pd_info.usba_no_current_flow_flag = FALSE;
                                    g_sys_pd_info.usba2_disconnected_tick = 0;
                                    g_sys_pd_info.usba_no_current_start_tick = 0;
#if CLI_ENABLED
                        			if (sys_cfg_dbg_get()) printf("A2 On\n");
#endif /* CLI_ENABLED */
                                }
                            }
                        }
                    }
                    else {
                        g_sys_pd_info.prevent_auto_poweroff_last_state = FALSE;
                    }

                    g_sys_pd_info.usba_vbus_val = sys_usba_vbus_get();
                    if ((!g_sys_pd_info.usba_ocp_flag) && (!(g_sys_pd_info.prevent_auto_poweroff)))
                    {
                        g_sys_pd_info.usba1_indet_pre_flag = g_sys_pd_info.usba1_indet_current_flag;
                        g_sys_pd_info.usba1_indet_current_flag = sys_gpio_usba1_insert_detect_get();
                        if (g_sys_pd_info.usba1_indet_current_flag)
                        {
                            if ((g_sys_pd_info.usba1_indet_current_flag != g_sys_pd_info.usba1_indet_pre_flag) &&
                                (g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.usba1_disconnected_tick > 4))
                            {
                                g_sys_pd_info.usba1_indet_flag = g_sys_pd_info.usba1_indet_current_flag;
                                sys_gpio_usba1_insert_detect_clear();
                                sys_usba_vbus_set(VOLTAGE_5V);
                                sys_gpio_usba1_power_on_set(TRUE);
                                g_sys_pd_info.usba_no_current_flow_flag = FALSE;
                                g_sys_pd_info.usba1_disconnected_tick = 0;
                                g_sys_pd_info.usba_no_current_start_tick = 0;
                                if (g_sys_pd_info.usba2_qc_en_flag)
                                {
                                    // disable a2 QC
                                    g_sys_pd_info.usba2_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
                                    dpm_qc_enable_set(&g_usba2_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
                                }
                                else {
                                    // Enable a1 QC
                                    g_sys_pd_info.usba1_qc_en_flag = TRUE;
#if SYS_QUICK_CHARGE_ENABLED
                                    if (usbpd_cfg_port_quick_charge_en_get())
                                    {
                                        dpm_qc_enable_set(&g_usba1_qc_info, TRUE, FALSE);
                                    }
#endif /* SYS_QUICK_CHARGE_ENABLED */
                                }
#if CLI_ENABLED
                    			if (sys_cfg_dbg_get()) drv_uart_puts("A1 indet");
#endif /* CLI_ENABLED */
                            }
                        }

                        g_sys_pd_info.usba2_indet_pre_flag = g_sys_pd_info.usba2_indet_current_flag;
                        g_sys_pd_info.usba2_indet_current_flag = sys_gpio_usba2_insert_detect_get();
                        if (g_sys_pd_info.usba2_indet_current_flag)
                        {
                            if ((g_sys_pd_info.usba2_indet_current_flag != g_sys_pd_info.usba2_indet_pre_flag) &&
                                (g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.usba2_disconnected_tick > 4))
                            {
                                g_sys_pd_info.usba2_indet_flag = g_sys_pd_info.usba2_indet_current_flag;
                                sys_gpio_usba2_insert_detect_clear();
                                sys_usba_vbus_set(VOLTAGE_5V);
                                sys_gpio_usba2_power_on_set(TRUE);
                                g_sys_pd_info.usba_no_current_flow_flag = FALSE;
                                g_sys_pd_info.usba2_disconnected_tick = 0;
                                g_sys_pd_info.usba_no_current_start_tick = 0;
                                if (g_sys_pd_info.usba1_qc_en_flag)
                                {
                                    // disable a1 QC
                                    g_sys_pd_info.usba1_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
                                    dpm_qc_enable_set(&g_usba1_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
                                }
                                else {
                                    // Enable a2 QC
                                    g_sys_pd_info.usba2_qc_en_flag = TRUE;
#if SYS_QUICK_CHARGE_ENABLED
                                    if (usbpd_cfg_port_quick_charge_en_get())
                                    {
                                        dpm_qc_enable_set(&g_usba2_qc_info, TRUE, FALSE);
                                    }
#endif /* SYS_QUICK_CHARGE_ENABLED */
                                }
#if CLI_ENABLED
                    			if (sys_cfg_dbg_get()) drv_uart_puts("A2 indet");
#endif /* CLI_ENABLED */
                            }
                        }

                        if (((g_sys_pd_info.usba1_indet_flag) || (g_sys_pd_info.usba2_indet_flag)) && 
                            (g_sys_pd_info.usba_no_current_flow_flag) && 
                            (g_sys_pd_info.usba_no_current_start_tick) && 
                            (g_sys_pd_info.continuous_timer_tick - g_sys_pd_info.usba_no_current_start_tick > SYS_USBA_CONNECTION_TIMEOUT))
                        {
                            sys_usba_vbus_set(VOLTAGE_5V);
                            if (g_sys_pd_info.usba1_indet_flag)
                            {
                                g_sys_pd_info.usba1_indet_flag = FALSE;
                                if (g_sys_pd_info.usba1_qc_en_flag)
                                {
                                    g_sys_pd_info.usba1_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
                                    dpm_qc_enable_set(&g_usba1_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
                                }
                                sys_gpio_usba1_power_on_set(FALSE);
                                g_sys_pd_info.usba1_disconnected_tick = g_sys_pd_info.continuous_timer_tick;
                            }
                            if (g_sys_pd_info.usba2_indet_flag)
                            {
                                g_sys_pd_info.usba2_indet_flag = FALSE;
                                if (g_sys_pd_info.usba2_qc_en_flag)
                                {
                                    g_sys_pd_info.usba2_qc_en_flag = FALSE;
#if SYS_QUICK_CHARGE_ENABLED
                                    dpm_qc_enable_set(&g_usba2_qc_info, FALSE, FALSE);
#endif /* SYS_QUICK_CHARGE_ENABLED */
                                }
                                g_sys_pd_info.usba2_disconnected_tick = g_sys_pd_info.continuous_timer_tick;
                                sys_gpio_usba2_power_on_set(FALSE);
                            }
#if CLI_ENABLED
                			if (sys_cfg_dbg_get()) drv_uart_puts("USB-A Off");
#endif /* CLI_ENABLED */
                        }
                    }

                    if ((sys_gpio_usba1_power_on_get() || sys_gpio_usba2_power_on_get()) && 
                        (g_sys_pd_info.usba_vbus_val < VSAFE_5V_DISCONNECT))
                    {
                        g_sys_pd_info.usba_ocp_flag = TRUE;
                        sys_usba_vbus_set(VOLTAGE_5V);
                        sys_gpio_usba1_power_on_set(FALSE);
                        sys_gpio_usba2_power_on_set(FALSE);
                        g_sys_pd_info.usba1_disconnected_tick = g_sys_pd_info.continuous_timer_tick;
                        g_sys_pd_info.usba2_disconnected_tick = g_sys_pd_info.continuous_timer_tick;
#if CLI_ENABLED
            			if (sys_cfg_dbg_get()) printf("USB-A OCP, Power Off\n");
#endif /* CLI_ENABLED */
                    }
                }
            }

#endif /* SYS_POWER_BANK_ENABLED */

            // C1 VBUS check
            if ((!usbpd_cfg_capture_mode_get()) && 
                (usbpd_cfg_port_vbus_check_get()) && 
                (!dpm_cable_detect_done_get()) && 
                (dpm_vbus_volt_get() > 6000U) && 
                ((u32_t)(now() - dpm_cc_connection_changed_time_get()) > 600000UL) && 
                (!pe_error_recovery_directed_get()))
            {
#if USBPD_DEBUG_ENABLED
        		if (usbpd_cfg_dbg_get()) drv_uart_puts("VBUS > 6V, No connection");
#endif /* CLI_ENABLED */
                pe_error_recovery_directed_set(TRUE);
            }

        }

        // restart timer
        sys_tick_t current_time = now();
        u32_t duration = (u32_t)(current_time - start_time) / 1000;
        if (duration >= SYS_CONTINUOUS_TIMER_TIMEOUT)
        {
            // no need to restart timer and keep the timeout flag for next run
        }
        else {
            drv_timer_start(SYS_CONTINUOUS_TIMER_TIMEOUT-duration, &(g_sys_pd_info.continuous_timer), NULL);
        }
    }
}

void sys_pd_vdm_disc_ident_ack_received_hook(u32_t arg)
{
#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nVDM DISC IDENT ACK Hook");
    }
#endif /* CLI_ENABLED */

    // Change power policy here
    if (MSG_SOP_TYPE_SOPP == dpm_msg_sop_type_get())
    {
        sys_pd_power_policy_process(TRUE);
    }
}


void sys_pd_prl_msg_vdm_attention_hook(UPD_DATA_MSG_VDM_ATTENTION_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("VDM Attention Hook:\n");
    }
#endif /* CLI_ENABLED */
}


void sys_pd_prl_msg_vdm_unstructured_hook(u8_t *p_msg, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_msg)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Unstructured VDM Hook:\n");
    }
#endif /* CLI_ENABLED */
    if (PRL_MSG_DIR_RX == dir)
    {
        pe_unsupported_msg_received_set(TRUE);
    }
}

void sys_pd_prl_msg_alert_hook(UPD_DATA_MSG_ALERT_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_puts("Alert Hook:");
        printf(" %-24s: %02X\n", "Type", p_info->type);
        if (p_info->type > 0)
        {
            if (p_info->type & UPD_ALERT_TYPE_RSVD1)
            {
                drv_uart_puts("  Bit0: Reserved");
            }
            if (p_info->type & UPD_ALERT_TYPE_BAT_STA_CHG)
            {
                drv_uart_puts("  Bit1: Battery Status Change");
            }
            if (p_info->type & UPD_ALERT_TYPE_OCP)
            {
                drv_uart_puts("  Bit2: Over-Current Protection");
            }
            if (p_info->type & UPD_ALERT_TYPE_OTP)
            {
                drv_uart_puts("  Bit3: Over-Temperature Protection");
            }
            if (p_info->type & UPD_ALERT_TYPE_OPR_COND_CHG)
            {
                drv_uart_puts("  Bit4: Operating Condition Change");
            }
            if (p_info->type & UPD_ALERT_TYPE_SRC_INPT_CHG)
            {
                drv_uart_puts("  Bit5: Source Input Change");
            }
            if (p_info->type & UPD_ALERT_TYPE_OVP)
            {
                drv_uart_puts("  Bit6: Over-Voltage Protection");
            }
            if (p_info->type & UPD_ALERT_TYPE_RSVD2)
            {
                drv_uart_puts("  Bit7: Reserved");
            }
        }

        printf(" %-24s: %02X\n %-24s: %02X\n", 
            "Fixed Batteries", p_info->fixed_batteries,
            "Hot Swappable Batteries", p_info->hot_swappable_batteries);
    }
#endif /* CLI_ENABLED */
}

void sys_pd_prl_msg_get_country_info_hook(UPD_DATA_MSG_GET_COUNTRY_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        printf("Get Country Info Hook:\n %-24s: %c%c\n", 
            "Country Code", p_info->alpha_2_code_1, p_info->alpha_2_code_2);
    }
#endif /* CLI_ENABLED */
}

void sys_pd_prl_msg_battery_status_hook(UPD_DATA_MSG_BATTERY_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        printf("Battery Status Hook:\n %-24s: %02X\n %-24s: %u\n", 
            "Info", p_info->info,
            "Capacity", p_info->present_capacity);
    }
#endif /* CLI_ENABLED */
    if (dir == PRL_MSG_DIR_TX)
    {
        if (g_sys_pd_info.invalid_bat_sta_ref)
        {
            p_info->info = 1; // Invalid Battery reference
            p_info->present_capacity = 0xFFFF;
            p_info->resv = 0;
            g_sys_pd_info.invalid_bat_sta_ref = 0;
        }        
    }
    else {

    }
}

void sys_pd_prl_msg_ext_src_cap_hook(UPD_EXT_MSG_SRC_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        printf("Extended Source Capability Hook:\n %-24s: %02X\n %-24s: %u\n", 
            "Batteries", p_info->batteries,
            "PDP", p_info->src_pdp);
        printf("Configuration:\n %-24s: %02X\n %-24s: %u\n", 
            "Batteries", usbpd_cfg_port_battery_num_get(),
            "PDP", usbpd_cfg_port_src_pdp_get());
    }
#endif /* CLI_ENABLED */
}

void sys_pd_prl_msg_ext_status_hook(UPD_EXT_MSG_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Status Hook:\n");
    }
#endif /* CLI_ENABLED */
}

void sys_pd_prl_msg_ext_get_bat_cap_hook(UPD_EXT_MSG_GET_BAT_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Get Battery Capability Hook:\n");
    }
#endif /* CLI_ENABLED */
    if (dir == PRL_MSG_DIR_TX)
    {
        
    }
    else {
        if (p_info->bat_cap_ref > 0)
        {
            g_sys_pd_info.invalid_bat_cap_ref = 1;
        }
    }
}

void sys_pd_prl_msg_ext_get_bat_status_hook(UPD_EXT_MSG_GET_BAT_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Get Battery Status Hook:\n");
    }
#endif /* CLI_ENABLED */
    if (dir == PRL_MSG_DIR_TX)
    {
        
    }
    else {
        if (p_info->bat_status_ref > 0)
        {
            g_sys_pd_info.invalid_bat_sta_ref = 1;
        }
    }
}

void sys_pd_prl_msg_ext_bat_cap_hook(UPD_EXT_MSG_BAT_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Battery Capability Hook:\n");
    }
#endif /* CLI_ENABLED */
    if (dir == PRL_MSG_DIR_TX)
    {
        if (g_sys_pd_info.invalid_bat_cap_ref)
        {
            p_info->type = 1; // Invalid Battery reference
            p_info->design_capacity = 0xFFFF;
            g_sys_pd_info.invalid_bat_cap_ref = 0;
        }
    }
    else {
        
    }
}


void sys_pd_prl_msg_ext_get_mfr_info_hook(UPD_EXT_MSG_GET_MFR_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Get Manufacturer Info Hook:\n");
        if (1 == p_info->mfr_info_target)
        {
            printf(" Battery Reference: %u\n", p_info->mfr_info_ref);
        }
    }
#endif /* CLI_ENABLED */

    if (dir == PRL_MSG_DIR_RX)
    {
        g_sys_pd_info.rx_get_mfr_info.mfr_info_target = p_info->mfr_info_target;
        g_sys_pd_info.rx_get_mfr_info.mfr_info_ref = p_info->mfr_info_ref;
    }
}

void sys_pd_prl_msg_ext_mfr_info_hook(UPD_EXT_MSG_MFR_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Manufacturer Info Hook:\n");
        printf(" %-24s: %u\n", "VID", p_info->vid);
        printf(" %-24s: %u\n", "PID", p_info->pid);
        printf(" %-24s: %s\n", "String", p_info->mfr_str);
    }
#endif /* CLI_ENABLED */

    if (dir == PRL_MSG_DIR_TX)
    {
        if ((g_sys_pd_info.rx_get_mfr_info.mfr_info_target != 0) || 
            (g_sys_pd_info.rx_get_mfr_info.mfr_info_ref != 0))
        {
            memset((char *)p_info->mfr_str, 0, UPD_EXT_MSG_MFR_MAX_STRING_LEN);
            strcpy((char *)p_info->mfr_str, "Not Supported");
        }
    }
}


void sys_pd_prl_msg_ext_secur_req_hook(UPD_EXT_MSG_SECURITY_REQ_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    
}

void sys_pd_prl_msg_ext_secur_resp_hook(UPD_EXT_MSG_SECURITY_RESP_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    
}


void sys_pd_prl_msg_ext_fw_up_req_hook(void *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    
}

void sys_pd_prl_msg_ext_fw_up_resp_hook(void *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    
}


void sys_pd_prl_msg_ext_pps_status_hook(UPD_EXT_MSG_PPS_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended PPS Status Hook:\n");
    }
#endif /* CLI_ENABLED */
}


void sys_pd_prl_msg_ext_country_info_hook(UPD_EXT_MSG_COUNTRY_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Country Info Hook:\n");
    }
#endif /* CLI_ENABLED */
}

void sys_pd_prl_msg_ext_country_codes_hook(UPD_EXT_MSG_COUNTRY_CODES_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Country Codes Hook:\n");
    }
#endif /* CLI_ENABLED */
}


void sys_pd_prl_msg_ext_snk_cap_hook(UPD_EXT_MSG_SNK_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir)
{
    if (!p_info)
        return;

#if CLI_ENABLED
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        if (dir == PRL_MSG_DIR_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Extended Sink Capability Hook:\n");
    }
#endif /* CLI_ENABLED */
}


void sys_pd_hook_init()
{
    memset((void *)&g_sys_pd_info, 0, sizeof(SYS_PD_INFO_t));

    g_sys_pd_info.sys_initializing = TRUE;

    sys_pd_led_state_set(SYS_PD_LED_STATE_ON);

#if SYS_QUICK_CHARGE_ENABLED
    sys_qc_init();
#endif

    usbpd_cc_hook_set(snk,unattached, sys_pd_sink_unattached_hook);
    usbpd_cc_hook_set(snk,attachwait, sys_pd_sink_attachwait_hook);
    usbpd_cc_hook_set(snk,attached, sys_pd_sink_attached_hook);
    usbpd_cc_hook_set(src,unattached, sys_pd_source_unattached_hook);
    usbpd_cc_hook_set(src,attachwait, sys_pd_source_attachwait_hook);
    usbpd_cc_hook_set(src,attached, sys_pd_source_attached_hook);

    usbpd_snk_transit_to_new_power_hook_set(sys_pd_sink_transit_to_new_power_hook);
    usbpd_src_transit_to_new_power_hook_set(sys_pd_source_transit_to_new_power_hook);

    usbpd_hook_set(src_vbus_en, sys_pd_vbus_source_en_set);
    usbpd_hook_set(discharge_en, sys_pd_vbus_discharge_en_set);
    usbpd_hook_set(cc1_vconn_en, sys_pd_cc1_vconn_en_set);
    usbpd_hook_set(cc2_vconn_en, sys_pd_cc2_vconn_en_set);

    usbpd_hook_with_return_set(src_vbus_en, sys_pd_vbus_source_en_get);
    usbpd_hook_with_return_set(discharge_en, sys_pd_vbus_discharge_en_get);
    usbpd_hook_with_return_set(cc1_vconn_en, sys_pd_cc1_vconn_en_get);
    usbpd_hook_with_return_set(cc2_vconn_en, sys_pd_cc2_vconn_en_get);
    
    usbpd_event_hook_set(prs_started, sys_pd_prs_started_hook);
    usbpd_event_hook_set(prs_completed, sys_pd_prs_completed_hook);
    usbpd_event_hook_set(drs_started, sys_pd_drs_started_hook);
    usbpd_event_hook_set(drs_completed, sys_pd_drs_completed_hook);
    usbpd_event_hook_set(vcs_started, sys_pd_vcs_started_hook);
    usbpd_event_hook_set(vcs_completed, sys_pd_vcs_completed_hook);
    usbpd_event_hook_set(power_change_req, sys_pd_power_change_req_hook);
    usbpd_event_hook_set(idle, sys_pd_idle_hook);
    usbpd_event_hook_set(vdm_disc_ident_ack_received, sys_pd_vdm_disc_ident_ack_received_hook);
    usbpd_event_hook_set(prl_msg_received, sys_pd_prl_msg_received_hook);
    usbpd_event_hook_set(prl_msg_sent, sys_pd_prl_msg_sent_hook);

    usbpd_prl_msg_hook_set(vdm_attention, (v_func_args_ptr_t)sys_pd_prl_msg_vdm_attention_hook);
    usbpd_prl_msg_hook_set(vdm_unstructured, (v_func_args_ptr_t)sys_pd_prl_msg_vdm_unstructured_hook);

    usbpd_prl_msg_hook_set(alert, (v_func_args_ptr_t)sys_pd_prl_msg_alert_hook);
    usbpd_prl_msg_hook_set(get_country_info, (v_func_args_ptr_t)sys_pd_prl_msg_get_country_info_hook);
    usbpd_prl_msg_hook_set(battery_status, (v_func_args_ptr_t)sys_pd_prl_msg_battery_status_hook);
    usbpd_prl_msg_hook_set(ext_src_cap, (v_func_args_ptr_t)sys_pd_prl_msg_ext_src_cap_hook);
    usbpd_prl_msg_hook_set(ext_status, (v_func_args_ptr_t)sys_pd_prl_msg_ext_status_hook);
    usbpd_prl_msg_hook_set(ext_get_bat_cap, (v_func_args_ptr_t)sys_pd_prl_msg_ext_get_bat_cap_hook);
    usbpd_prl_msg_hook_set(ext_get_bat_status, (v_func_args_ptr_t)sys_pd_prl_msg_ext_get_bat_status_hook);
    usbpd_prl_msg_hook_set(ext_bat_cap, (v_func_args_ptr_t)sys_pd_prl_msg_ext_bat_cap_hook);
    usbpd_prl_msg_hook_set(ext_get_mfr_info, (v_func_args_ptr_t)sys_pd_prl_msg_ext_get_mfr_info_hook);
    usbpd_prl_msg_hook_set(ext_mfr_info, (v_func_args_ptr_t)sys_pd_prl_msg_ext_mfr_info_hook);
    usbpd_prl_msg_hook_set(ext_secur_req, (v_func_args_ptr_t)sys_pd_prl_msg_ext_secur_req_hook);
    usbpd_prl_msg_hook_set(ext_secur_resp, (v_func_args_ptr_t)sys_pd_prl_msg_ext_secur_resp_hook);
    usbpd_prl_msg_hook_set(ext_fw_up_req, (v_func_args_ptr_t)sys_pd_prl_msg_ext_fw_up_req_hook);
    usbpd_prl_msg_hook_set(ext_fw_up_resp, (v_func_args_ptr_t)sys_pd_prl_msg_ext_fw_up_resp_hook);
    usbpd_prl_msg_hook_set(ext_pps_status, (v_func_args_ptr_t)sys_pd_prl_msg_ext_pps_status_hook);
    usbpd_prl_msg_hook_set(ext_country_info, (v_func_args_ptr_t)sys_pd_prl_msg_ext_country_info_hook);
    usbpd_prl_msg_hook_set(ext_country_codes, (v_func_args_ptr_t)sys_pd_prl_msg_ext_country_codes_hook);
    usbpd_prl_msg_hook_set(ext_snk_cap, (v_func_args_ptr_t)sys_pd_prl_msg_ext_snk_cap_hook);
}


