/**
 * \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_pd_config.h"
#if SYS_QUICK_CHARGE_ENABLED
#include "sys_qc_hook.h"
#endif /* SYS_QUICK_CHARGE_ENABLED */


volatile SYS_PD_INFO_t g_sys_pd_info;

void sys_pd_sink_unattached_hook()
{
#if SYS_QUICK_CHARGE_ENABLED
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        dpm_qc_enable_set(&g_usbc_qc_info, FALSE, FALSE);
        sys_gpio_uart0_enable_set(TRUE);
    }
    else {
        if (DRV_UART_ID_0 == drv_uart_default_get())
        {
            if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(TRUE);
        }
        else {
            sys_gpio_uart0_enable_set(TRUE);
        }
    }
#else
    if (DRV_UART_ID_0 == drv_uart_default_get())
    {
        if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(TRUE);
    }
    else {
        sys_gpio_uart0_enable_set(TRUE);
    }
#endif /* SYS_QUICK_CHARGE_ENABLED */

    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Unattached Hook");
    }
#if SYS_PWM_CTRL_VOLT_ENABLED
    if (usbpd_cfg_port_src_pwm_en_get())
    {
    	drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,FALSE);
    }
#endif /* #if SYS_PWM_CTRL_VOLT_ENABLED */
}

void sys_pd_sink_attachwait_hook()
{
    sys_lpm_activate();
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Attachwait Hook");
    }
}

void sys_pd_sink_attached_hook()
{
    sys_lpm_activate();
#if SYS_QUICK_CHARGE_ENABLED
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        sys_gpio_uart0_enable_set(FALSE);
        if (!dpm_port_dead_battery_get())
        {
            // No need to enable QC sink
            dpm_qc_enable_set(&g_usbc_qc_info, FALSE, FALSE);
        }
    }
    else {
        if (DRV_UART_ID_0 == drv_uart_default_get())
        {
            if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(FALSE);
        }
        else {
            sys_gpio_uart0_enable_set(FALSE);
        }
    }
#else
    if (DRV_UART_ID_0 == drv_uart_default_get())
    {
        if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(FALSE);
    }
    else {
        sys_gpio_uart0_enable_set(FALSE);
    }
#endif /* SYS_QUICK_CHARGE_ENABLED */

    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Attached Hook");
    }
#if SYS_PWM_CTRL_VOLT_ENABLED
    if (usbpd_cfg_port_src_pwm_en_get())
    {
    	drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,FALSE);
    }
#endif /* #if SYS_PWM_CTRL_VOLT_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 (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSink Transit To New Power Hook");
    }

    return S_OK;
}

void sys_pd_source_unattached_hook()
{
#if SYS_QUICK_CHARGE_ENABLED
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        dpm_qc_enable_set(&g_usbc_qc_info, FALSE, FALSE);
        sys_gpio_uart0_enable_set(TRUE);
    }
    else {
        if (DRV_UART_ID_0 == drv_uart_default_get())
        {
            if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(TRUE);
        }
        else {
            sys_gpio_uart0_enable_set(TRUE);
        }
    }
#else
    if (DRV_UART_ID_0 == drv_uart_default_get())
    {
        if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(TRUE);
    }
    else {
        sys_gpio_uart0_enable_set(TRUE);
    }
#endif /* SYS_QUICK_CHARGE_ENABLED */

    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSrc Unattached Hook");
    }
#if SYS_PWM_CTRL_VOLT_ENABLED
    if (usbpd_cfg_port_src_pwm_en_get())
    {
    	drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,FALSE);
    }
#endif /* #if SYS_PWM_CTRL_VOLT_ENABLED */
}

void sys_pd_source_attachwait_hook()
{
    sys_lpm_activate();
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSrc Attachwait Hook");
    }
}

void sys_pd_source_attached_hook()
{
#if SYS_QUICK_CHARGE_ENABLED
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        sys_gpio_uart0_enable_set(FALSE);
        if (!dpm_port_dead_battery_get())
        {
            dpm_qc_enable_set(&g_usbc_qc_info, TRUE, FALSE);
        }
    }
    else {
        if (DRV_UART_ID_0 == drv_uart_default_get())
        {
            if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(FALSE);
        }
        else {
            sys_gpio_uart0_enable_set(FALSE);
        }
    }
#else
    if (DRV_UART_ID_0 == drv_uart_default_get())
    {
        if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(FALSE);
    }
    else {
        sys_gpio_uart0_enable_set(FALSE);
    }
#endif /* SYS_QUICK_CHARGE_ENABLED */

    sys_lpm_activate();
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nSrc Attached Hook");
    }
    sys_pd_led_state_set(SYS_PD_LED_STATE_ON);

#if SYS_PWM_CTRL_VOLT_ENABLED
    if (usbpd_cfg_port_src_pwm_en_get())
    {
        drv_pwm_init_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,FALSE,usbpd_cfg_port_src_pwm_per_get());
        drv_pwm_duty_set2(SYS_PWM_INDEX_FOR_VOLT_CTRL, usbpd_cfg_port_src_fixed_pwr_pwm_duty_get(CFG_VOLTAGE_5V_IDX));
        drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,usbpd_cfg_port_src_pwm_en_get());
    }
#endif /* #if SYS_PWM_CTRL_VOLT_ENABLED */

}

status_t sys_pd_source_transit_to_new_power_hook(u32_t pos)
{
#if SYS_PWM_CTRL_VOLT_ENABLED
	u32_t duty;
#endif

    if (!dpm_current_pwr_mode_get())
        return S_ERROR;

    if (pos >= CFG_MAX_PWR_CAP_NUM)
        return S_INVALID_PARAMS;

#if SYS_QUICK_CHARGE_ENABLED
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        //dpm_qc_enable_set(&g_usbc_qc_info, FALSE, FALSE);
        dpm_qc_state_set(&g_usbc_qc_info, DPM_QC_DISABLED);
        if (DRV_UART_ID_0 == drv_uart_default_get())
        {
            if (SYS_DEBUG_LEVEL_OFF == sys_cfg_dbg_get()) sys_gpio_uart0_enable_set(FALSE);
        }
        else {
            sys_gpio_uart0_enable_set(FALSE);
        }
    }
#endif /* SYS_QUICK_CHARGE_ENABLED */

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

#if (SYS_PWM_CTRL_VOLT_ENABLED && SYS_PWM_STEP_CTRL_VOLT_ENABLED)
    if ((POWER_SUPPLY_TYPE_FIXED == usbpd_cfg_port_src_pwr_supply_type_get(pos)) && 
        (VOLTAGE_VAL(VOLTAGE_12V) < usbpd_cfg_port_src_fixed_pwr_volt_cap_get(pos)))
    {
        duty = drv_pwm_duty_get(SYS_PWM_INDEX_FOR_VOLT_CTRL);
        if (duty == usbpd_cfg_port_src_fixed_pwr_pwm_duty_get(CFG_VOLTAGE_5V_IDX))
        {
            drv_pwm_duty_set2(SYS_PWM_INDEX_FOR_VOLT_CTRL, usbpd_cfg_port_src_fixed_pwr_pwm_duty_get(sys_pd_cfg_src_fixed_power_profile_index_get(VOLTAGE_12V)));
            drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL, TRUE);
            rtc_delay_us(3000);
        }
    }
#endif /* (SYS_PWM_CTRL_VOLT_ENABLED && SYS_PWM_STEP_CTRL_VOLT_ENABLED) */

#if SYS_PWM_CTRL_VOLT_ENABLED
    if (POWER_SUPPLY_TYPE_PPS == usbpd_cfg_port_src_pwr_supply_type_get(pos))
    {
        duty = usbpd_cfg_port_src_pps_pwr_pwm_duty_get(pos, REQ_PPS_OUTPUT_VOLT_GET(dpm_current_rdo_get())*VOLTAGE_PPS_REQ_DIV);
#if USBPD_DEBUG_ENABLED
        if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) printf("\nVBUS-Set(%u):%umV,Duty:%x\n", pos, REQ_PPS_OUTPUT_VOLT_GET(dpm_current_rdo_get())*VOLTAGE_PPS_REQ_DIV,duty);
#endif /* USBPD_DEBUG_ENABLED */
    }
    else {
        duty = usbpd_cfg_port_src_fixed_pwr_pwm_duty_get(pos);
#if USBPD_DEBUG_ENABLED
        if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) printf("\nVBUS-Set(%u):Duty:%x\n", pos, duty);
#endif /* USBPD_DEBUG_ENABLED */
    }
    drv_pwm_duty_set2(SYS_PWM_INDEX_FOR_VOLT_CTRL, duty);
    drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL, TRUE);
#else

#endif /* #if SYS_PWM_CTRL_VOLT_ENABLED */
    return S_OK;
}

bool_t sys_pd_vbus_source_en_get(void)
{
    return sys_gpio_vbus_source_en_get();
}

void sys_pd_vbus_source_en_set(bool_t flg)
{
    g_sys_pd_info.vbus_source_en = flg;
#if SYS_PWM_CTRL_VOLT_ENABLED
    if (flg && usbpd_cfg_port_src_pwm_en_get())
    {
        //make sure the voltage is VSafe5V
        drv_pwm_duty_set2(SYS_PWM_INDEX_FOR_VOLT_CTRL, usbpd_cfg_port_src_fixed_pwr_pwm_duty_get(CFG_VOLTAGE_5V_IDX));
        drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,TRUE);
    }
#endif /* SYS_PWM_CTRL_VOLT_ENABLED */
    sys_gpio_vbus_source_en_set(flg);
}

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 (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_2) 
    {
        drv_uart_puts("\nPRS Started Hook");
    }

}

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

}

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

}

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

}

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

}

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

}

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

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

void sys_pd_prl_msg_sent_hook(u32_t arg)
{
    sys_lpm_activate();
    if (usbpd_cfg_dbg_get() >= USBPD_DEBUG_LEVEL_3) 
    {
        drv_uart_puts("\nPRL Msg Sent Hook");
    }
    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;
    }
}


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);
    }


    //handler QC state machine
#if SYS_QUICK_CHARGE_ENABLED
    if ((usbpd_cfg_port_quick_charge_en_get()) && 
        (!pe_pd_connected_get()) &&
        (DPM_QC_DISABLED != dpm_qc_state_get(&g_usbc_qc_info)))
    {
        dpm_qc_state_machine(&g_usbc_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.continuous_timer_tick > 25) && 
            (drv_gpio_en_get(UART_RXD)) &&
            ((!dpm_cable_detect_done_get()) ||
             (sys_cfg_dbg_get())))
        {
            sys_gpio_uart0_enable();
        }

        // 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()) &&
        (VBUS_CURR_HANDLING_CAP_5A == dpm_rx_vdm_ack_cable_vbus_curr_cap_get()))
    {
        
    }
}

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

    if (dir == PRL_MSG_DIR_RX)
    {
        int cap_pos = dpm_src_obj_pos_get();
        u32_t volt, current;
        UPD_DATA_MSG_SOURCE_CAP_FIXED_SUPPLY_t *p_src_cap_fixed = (UPD_DATA_MSG_SOURCE_CAP_FIXED_SUPPLY_t *)dpm_rx_src_cap_object_get(cap_pos-1);
        if (POWER_SUPPLY_TYPE_BATTERY == p_src_cap_fixed->supply_type)
        {
            UPD_DATA_MSG_SOURCE_CAP_BATTERY_SUPPLY_t *p_src_cap_battery = (UPD_DATA_MSG_SOURCE_CAP_BATTERY_SUPPLY_t *)dpm_rx_src_cap_object_get(cap_pos-1);
            volt = p_src_cap_battery->max_volt * VOLTAGE_DIV;
            current = (u32_t)(p_src_cap_battery->max_allow_pwr) * POWER_DIV * 1000 / volt;
        }
        else if (POWER_SUPPLY_TYPE_VARIABLE == p_src_cap_fixed->supply_type)
        {
            UPD_DATA_MSG_SOURCE_CAP_VARIABLE_SUPPLY_t *p_src_cap_vari = (UPD_DATA_MSG_SOURCE_CAP_VARIABLE_SUPPLY_t *)dpm_rx_src_cap_object_get(cap_pos-1);
            volt = p_src_cap_vari->max_volt * VOLTAGE_DIV;
            current = p_src_cap_vari->max_curr * CURRENT_DIV;
        }
        else if (POWER_SUPPLY_TYPE_PPS == p_src_cap_fixed->supply_type)
		{
			UPD_DATA_MSG_SOURCE_CAP_PPS_APDU_t *p_cap_pps = (UPD_DATA_MSG_SOURCE_CAP_PPS_APDU_t *)dpm_rx_src_cap_object_get(cap_pos-1);
			volt = MAX_VOLT_GET(p_cap_pps) * VOLTAGE_PPS_DIV;
			current = MAX_CURR_GET(p_cap_pps) * CURRENT_PPS_DIV;
		}
        else {
            volt = p_src_cap_fixed->volt * VOLTAGE_DIV;
            current = p_src_cap_fixed->max_curr * CURRENT_DIV;
        }
#if CLI_ENABLED
        if (sys_cfg_dbg_get() > SYS_DEBUG_LEVEL_1) printf("RX SRC CAP, POS:%u,V:%u,A:%u\n",cap_pos,volt,current);
#endif /* CLI_ENABLED */
    }
}

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

#if 0  /* deleted by James Gan - 2020-05-08 */
    if (dir == PRL_MSG_DIR_TX)
    {
        drv_uart_putstr("\nTX ");
    }
    else {
        drv_uart_putstr("\nRX ");
    }
#endif /* #if 0 */
}

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_PWM_CTRL_VOLT_ENABLED
    if (usbpd_cfg_port_src_pwm_en_get())
    {
        if (POWER_ROLE_SINK == usbpd_cfg_port_def_pr_get())
        {
            drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,FALSE);
        }
        else {
            drv_pwm_init_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,FALSE,usbpd_cfg_port_src_pwm_per_get());
            drv_pwm_duty_set2(SYS_PWM_INDEX_FOR_VOLT_CTRL, usbpd_cfg_port_src_fixed_pwr_pwm_duty_get(CFG_VOLTAGE_5V_IDX));
            drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL,usbpd_cfg_port_src_pwm_en_get());
        }
    }
#endif /* SYS_PWM_CTRL_VOLT_ENABLED */

#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(source_capabilities, (v_func_args_ptr_t)sys_pd_prl_msg_src_cap_hook);
    usbpd_prl_msg_hook_set(request, (v_func_args_ptr_t)sys_pd_prl_msg_req_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);
}


