/**
  *****************************************************************************
  * @file    sys_pd_hook.h
  * @author  Solution Team
  * @version V1.00
  * @date    28-February-2023
  * @brief   USBPD hook implimentation
  *****************************************************************************
  * @attention 
  *  Copyright (c) 2017 - 2023 Unicmicro Co., Ltd. 
  *  All Rights Reserved. 
  *****************************************************************************
  */
 
#ifndef __SYS_PD_HOOK_H_
#define __SYS_PD_HOOK_H_

#include "sys_defs.h"
#include "sys_gpio.h"
#include "prl_msg_defs.h"
#include "usbpd.h"
#include "drivers.h"


#pragma pack(1)

#if SYS_POWER_BANK_ENABLED
/** USB-A IBAT no current flow threshold, unit mA */
#define SYS_USBA_IBUS_NO_CURRENT_FLOW_THR       (70U)//(70U)//(50U)
#define SYS_USBA_IBUS_HAS_CURRENT_FLOW_THR      (120U)

#define SYS_USBC2_IBUS_NO_CURRENT_FLOW_THR       (120U)//(70U)//(50U)
#define SYS_USBC2_IBUS_HAS_CURRENT_FLOW_THR      (150U)

#define SYS_USBA_IBUS_ACCUM_VAL_IDX_MAX         (8U)
/** System USB-A connection timeout value, unit is 100 ms */
//#define SYS_USBA_CONNECTION_TIMEOUT             (30U)
#define SYS_USBA_CONNECTION_TIMEOUT             (300U)

#endif /* SYS_POWER_BANK_ENABLED */

/** System continuous timer timeout value, unit is millisecond */
#define SYS_CONTINUOUS_TIMER_TIMEOUT            (10U)
#define SYS_CONTINUOUS_TIMER_HOOK_NUM           (10)

#define SYS_WATT_HOUR_CONSTANT                  (0.0000002777777778f)
#define SYS_LONG_KEY_DOWN_DETECT_DURATION_MIN   (100000UL)      /* 100ms, system tick */
#define SYS_LONG_KEY_DOWN_DETECT_DURATION       (2000000UL)     /* 2s, system tick */
#define SYS_LONG_KEY_DOWN_DETECT_DURATION_COMP  (3000UL)        /* 3ms, system tick */

#define VRD_MIN_SNK_DEF_USB                     (0x136)
#define VRD_MAX_SNK_DEF_USB                     (0x2F5)
#define VRD_MIN_SNK_5V_1P5A                     (0x364)
#define VRD_MAX_SNK_5V_1P5A                     (0x59F)
#define VRD_MIN_SNK_5V_3A                       (0x659)
#define VRD_MAX_SNK_5V_3A                       (0x9E4)

// 0x355 = (0.6875) * 4096 / 3.3
// 0x454 = (0.6875+0x205) * 4096 / 3.3
#define VRD_SNK_CC_ZERO_VOLT_IND                (0x454)
#define VRD_SNK_CC_ZERO_VOLT_CNT                (1)

/** System OCP auto restore time, unit is 100 ms */
#define SYS_OCP_RESTORE_TIME                    (20U)
#if 0
extern volatile u8_t mcu_ctrl_state;
#endif
#define SYS_MCU_I2C_CTRL_EN                      (0U)

extern volatile u8_t dpm_ctrl_state;

typedef enum SYS_PD_LED_STATE_e
{
    SYS_PD_LED_STATE_OFF,
    SYS_PD_LED_STATE_ON,
    SYS_PD_LED_STATE_FLASH,
    SYS_PD_LED_STATE_FLASH_FAST,
    SYS_PD_LED_STATE_FLASH_INVALID
} SYS_PD_LED_STATE_t;

typedef struct SYS_MCU_CTR_STA_s
{
    u8_t discharge_en:1;
    u8_t charge_en:1;
    u8_t power_off:1;
    u8_t reserved:5;

}SYS_MCU_CTR_STA_t;

typedef struct SYS_PD_INFO_s
{
    sys_tick_t current_time;
    drv_timer_t continuous_timer;
    u32_t continuous_timer_fast_tick;
    u32_t continuous_timer_tick;
    // 32 bits: pd continuous_timer_tick
    u32_t ocp_start_tick;

    // 
    u32_t ovp_start_tick;
    
    u32_t vbus_current:16;
    u32_t ibus_current:16;
    
    u32_t vbus_set_volt:16;
    u32_t ibus_set_curr:16;
    
    u32_t rated_vbus:16,
          rated_ibus:16;
    UPD_EXT_MSG_GET_MFR_INFO_t rx_get_mfr_info;

    u32_t vbus_source_en:1;
    u32_t sys_initializing:1;
    u32_t led_state:4;
    u32_t led_display_flash_interval:5;
    u32_t c2_cable_done_flag:1;
    u32_t display_state:1;
    u32_t invalid_bat_sta_ref:1;
    u32_t invalid_bat_cap_ref:1;
    u32_t previous_profile:8;
    u32_t reserved1:9;

    u32_t led_on_start_tick;

    u32_t snk_request_current_state:1,  /** snk request current state */
          snk_request_last_state:1,     /** snk request last state */
          snk_request_is_need:1,        /** snk request is need flag */
          snk_request_auto_is_need:1,   /** auto snk request is need flag */
          snk_request_auto_pps:1,       /** auto snk request PPS flag */
          auto_epr_request_flg:1,
          snk_request_pps_in_epr_mode:1,
          snk_request_pps_index_in_epr_mode:4,
          snk_request_epr_after_pps:1,
          snk_request_epr_index_after_pps:4,
          reserved2:16;

    u32_t rx_pkt_cnt;

    u32_t tx_pkt_cnt;

#if SYS_POWER_BANK_ENABLED
    u32_t c1_current_pwr;

    // 32 bits
    u32_t usba_ibus_accum_val:24;
    u32_t usba_ibus_accum_val_idx:8;
    //32 bits
    u32_t usbc2_ibus_accum_val:24;
    u32_t usbc2_ibus_accum_val_idx:8;
    // 32 bits
    u32_t usba_vbus_val:16,
          usbc2_vbus_val:16;

     u32_t usba2_vbus_val:16;
     u32_t usbc2_ibus_avg_val:16;
            
    // 32 bits
    u32_t usba_ibus_avg_val:16;
    u32_t usba_no_current_flow_flag:1;
    u32_t usba_no_current_flow_last_flag:1;
    u32_t usba1_power_on_flag:1;
    u32_t usba1_qc_en_flag:1;
    u32_t usba1_indet_flag:1;
    u32_t usba1_indet_current_flag:1;
    u32_t usba1_indet_pre_flag:1;
    u32_t usba2_power_on_flag:1;
    u32_t usba2_qc_en_flag:1;
    u32_t usba2_indet_flag:1;
    u32_t usba2_indet_current_flag:1;
    u32_t usba2_indet_pre_flag:1;
    u32_t usba_ocp_flag:1;
    u32_t usbc2_no_current_flow_flag:1;
    u32_t usbc2_no_current_flow_last_flag:1;
    u32_t usbc_src_current_ocp_flg:1;
    
    // 32 bits: pd continuous_timer_tick
    u32_t usba1_disconnected_tick;

    // 32 bits: pd continuous_timer_tick
    u32_t usba2_disconnected_tick;

    // 32 bits: pd continuous_timer_tick
    u32_t usba_no_current_start_tick;
    //
    u32_t usbc2_no_current_start_tick;
    // 32 bits
    u32_t bat_cap_indicator_pre_charge:7;
    u32_t bat_cap_indicator_pre_discharge:7;
    u32_t power_check_current_state:1;
    u32_t power_check_last_state:1;
    u32_t key_down_cnt:2;
    u32_t prevent_auto_poweroff:1;
    u32_t prevent_auto_poweroff_last_state:1;
    u32_t power_down_detect_current_state:1;
    u32_t power_down_detect_last_state:1;
    u32_t usbc_curr_1p6a_vol_chang_flag:1;
    u32_t usbc_curr_2p4a_vol_chang_flag:1;
    u32_t usbc_curr_3p2a_vol_chang_flag:1;
    u32_t usbc_curr_4a_vol_chang_flag:1;
    u32_t usbc_curr_0p8a_vol_chang_flag:1;
    u32_t usbc_curr_u0p6a_vol_chang_flag:1;
    u32_t usbc_power_ctrl_en:1;
    u32_t i2c_int_flag:1;
    u32_t reserved4:2;

    // 32 bits: pd continuous_timer_tick
    u32_t double_click_1st_hit_tick;

    // 32 bits: pd continuous_timer_tick
    u32_t low_current_mode_start_tick;

    // 64 bits: system time
    sys_tick_t power_down_detect_start_time;

    // 32 bits: pd continuous_timer_tick
    u32_t auto_power_down_last_tick;

    u32_t p60c_otp_flag:1,
          p60c_otp_pre_flag:1,
          p55c_otp_flag:1,
          p55c_otp_pre_flag:1,
          p45c_otp_flag:1,
          p45c_otp_pre_flag:1,
          p0c_otp_flag:1,
          p0c_otp_pre_flag:1,
          m10c_otp_flag:1,
          m10c_otp_pre_flag:1,
          ntc_test_flag:1,
          ntc_volt:17,
          ocp_restore_cnt:4;
    u32_t charging_current_saved:16,
          p40c_otp_flag:1,
          p40c_otp_pre_flag:1,
          reserved6:14;

#endif /* SYS_POWER_BANK_ENABLED */
    SYS_MCU_CTR_STA_t mcu_state;
    SYS_MCU_CTR_STA_t mcu_state_pre;


} SYS_PD_INFO_t;

#pragma pack()

extern volatile SYS_PD_INFO_t g_sys_pd_info;

#define SYS_NTC_ADC_ID                          (DRV_ADC_CHN_8)

#define sys_mcu_int_get()                       (g_sys_pd_info.i2c_int_flag)

#define sys_mcu_int_en_set(flg) \
    do { \
        g_sys_pd_info.i2c_int_flag = flg; \
    } while(0)
    
/** \brief Get LED state
 */
#define sys_pd_led_state_get()      (g_sys_pd_info.led_state)

/** \brief Set LED state
 *
 * \param state     defined by SYS_PD_LED_STATE_t
 */
void sys_pd_led_state_set(SYS_PD_LED_STATE_t state);
#if SYS_USBA_ENABLED

/** \brief Get USB-A1 VBUS value
 *
 * \return VBUS value
 */
u32_t sys_usba1_vbus_get();

/** \brief Get USB-A2 VBUS value
 *
 * \return VBUS value
 */
u32_t sys_usba2_vbus_get();

/** \brief Set USB-A VBUS value
 *
 * \param volt      VBUS value
 * \return TRUE - Success, FALSE - Failure
 */
bool_t sys_usba_vbus_set(u32_t volt);

/** \brief Get USB-A IBUS value
 *
 * \return IBUS value
 */
#define sys_usba_ibus_get() drv_adc_ibus_get(SYS_CURRENT_SENCE_SAMPLE_RESISTER)

/** \brief USB-A initialization
 */
void sys_usba_init();
#else
#define sys_usba1_vbus_get()            (0)
#define sys_usba2_vbus_get()            (0)
#define sys_usba_ibus_get()             (0)
#define sys_usba_restore()
#define sys_usba_init()
#define sys_usba_vbus_set(volt)
#endif
#if SYS_POWER_POLICY_DISABLED
#define sys_pd_power_policy_process(change_asap)
#else
void sys_pd_power_policy_process(bool_t change_asap);
#endif


/** \brief Configuration channel(CC) hook when in Unattached.SNK
 */
void sys_pd_sink_unattached_hook();

/** \brief CC hook when in AttachWait.SNK
 */
void sys_pd_sink_attachwait_hook();

/** \brief CC hook when in Attached.SNK
 */
void sys_pd_sink_attached_hook();

/** \brief PD hook while sink mode require new power transition
 *
 * \return              see the error code of status_t
 */
status_t sys_pd_sink_transit_to_new_power_hook();

/** \brief CC hook when in Unattached.SRC
 *
 */
void sys_pd_source_unattached_hook();

/** \brief CC hook when in AttachWait.SRC
 *
 */
void sys_pd_source_attachwait_hook();

/** \brief CC hook when in Attached.SRC
 *
 */
void sys_pd_source_attached_hook();

/** \brief PD hook while source require new power transition
 *
 * \param pos           the position of source capabilities
 * \return              see the error code of status_t
 */
status_t sys_pd_source_transit_to_new_power_hook(u32_t pos);

/** \brief CC or PD hook when get PD VBUS source enable status
 *
 * \return              0: disabled, 1: enabled
 */
bool_t sys_pd_vbus_source_en_get(void);

/** \brief CC or PD hook when enable or disable PD VBUS sourcing
 *
 * \param flg           0: disable, 1: enable
 */
void sys_pd_vbus_source_en_set(bool_t flg);

/** \brief CC or PD hook when get PD VBUS source enable discharge
 *
 * \return              0: disabled, 1: enabled
 */
bool_t sys_pd_vbus_discharge_en_get(void);

/** \brief CC or PD hook when enable or disable PD VBUS discharge
 *
 * \param flg           0: disable, 1: enable
 */
void sys_pd_vbus_discharge_en_set(bool_t flg);

/** \brief CC or PD hook when get PD CC1 VCONN source enable status
 *
 * \return              0: disabled, 1: enabled
 */
bool_t sys_pd_cc1_vconn_en_get(void);

/** \brief CC or PD hook when enable or disable PD CC1 VCONN sourcing
 *
 * \param flg           0: disable, 1: enable
 */
void sys_pd_cc1_vconn_en_set(bool_t flg);

/** \brief CC or PD hook when get PD CC2 VCONN source enable status
 *
 * \return              0: disabled, 1: enabled
 */
bool_t sys_pd_cc2_vconn_en_get(void);


/** \brief PD hook when power role swap started
 *
 * \param arg           unused argument
 */
void sys_pd_prs_started_hook(u32_t arg);

/** \brief PD hook when power role swap completed
 *
 * \param arg           unused argument
 */
void sys_pd_prs_completed_hook(u32_t arg);


/** \brief PD hook when data role swap started
 *
 * \param arg           unused argument
 */
void sys_pd_drs_started_hook(u32_t arg);

/** \brief PD hook when data role swap completed
 *
 * \param arg           unused argument
 */
void sys_pd_drs_completed_hook(u32_t arg);


/** \brief PD hook when vconn source swap started
 *
 * \param arg           unused argument
 */
void sys_pd_vcs_started_hook(u32_t arg);

/** \brief PD hook when vconn source swap completed
 *
 * \param arg           unused argument
 */
void sys_pd_vcs_completed_hook(u32_t arg);

/** \brief PD power profile change request hook
 *
 * \param arg           unused argument
 */
void sys_pd_power_change_req_hook(u32_t arg);

/** \brief PD hook when message received
 *
 * \param arg           unused argument
 */
void sys_pd_prl_msg_received_hook(u32_t arg);

/** \brief PD hook when message sent
 *
 * \param arg           unused argument
 */
void sys_pd_prl_msg_sent_hook(u32_t arg);

/** \brief PD task IDLE hook when task is IDLE
 *
 * \param arg           unused argument
 */
void sys_pd_idle_hook(u32_t arg);

/** \brief PD hook when VDM discover identity response ack is received
 *
 * \param arg           unused argument
 */
void sys_pd_vdm_disc_ident_ack_received_hook(u32_t arg);

/** \brief PD hook when received or transmited VDM Attention message
 *
 * \param p_info        Pointer to PD UPD_DATA_MSG_VDM_ATTENTION_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_vdm_attention_hook(UPD_DATA_MSG_VDM_ATTENTION_t *p_info, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited Unstructured VDM message
 *
 * \param p_msg         Pointer to PD message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_vdm_unstructured_hook(u8_t *p_msg, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited alert message
 *
 * \param p_info        Pointer to PD UPD_DATA_MSG_ALERT_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_alert_hook(UPD_DATA_MSG_ALERT_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received get country info message
 *
 * \param p_info        Pointer to PD UPD_DATA_MSG_GET_COUNTRY_INFO_t message
 */
void sys_pd_prl_msg_get_country_info_hook(UPD_DATA_MSG_GET_COUNTRY_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received battery status message
 *
 * \param p_info        Pointer to PD UPD_DATA_MSG_BATTERY_STATUS_t message
 */
void sys_pd_prl_msg_battery_status_hook(UPD_DATA_MSG_BATTERY_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/*  == Extended message hook ==  */

/** \brief PD hook when received or transmited extended source capability message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_SRC_CAP_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_src_cap_hook(UPD_EXT_MSG_SRC_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited extended status message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_STATUS_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_status_hook(UPD_EXT_MSG_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited extended get battery capability message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_GET_BAT_CAP_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
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);

/** \brief PD hook when received or transmited extended get battery status message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_GET_BAT_STATUS_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
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);

/** \brief PD hook when received or transmited extended battery capability message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_BAT_CAP_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_bat_cap_hook(UPD_EXT_MSG_BAT_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received or transmited extended get manufacturer information message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_GET_MFR_INFO_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
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);

/** \brief PD hook when received or transmited extended manufacturer information message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_MFR_INFO_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_mfr_info_hook(UPD_EXT_MSG_MFR_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received or transmited extended security request message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_SECURITY_REQ_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_secur_req_hook(UPD_EXT_MSG_SECURITY_REQ_t *p_info, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited extended security response message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_SECURITY_RESP_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_secur_resp_hook(UPD_EXT_MSG_SECURITY_RESP_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received or transmited extended firmware upgrade request message
 *
 * \param p_info        Pointer to PD firmware upgrade request message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_fw_up_req_hook(void *p_info, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited extended firmware upgrade response message
 *
 * \param p_info        Pointer to PD firmware upgrade response message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_fw_up_resp_hook(void *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received or transmited extended PPS status message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_PPS_STATUS_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_pps_status_hook(UPD_EXT_MSG_PPS_STATUS_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received or transmited extended country info message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_COUNTRY_INFO_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_country_info_hook(UPD_EXT_MSG_COUNTRY_INFO_t *p_info, PRL_MSG_DIR_TYPE_t dir);

/** \brief PD hook when received or transmited extended country codes message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_COUNTRY_CODES_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_country_codes_hook(UPD_EXT_MSG_COUNTRY_CODES_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook when received or transmited extended sink capability message
 *
 * \param p_info        Pointer to PD UPD_EXT_MSG_SNK_CAP_t message
 * \param dir           The hook call from receiving or transmiting, 0: rx, 1: tx
 */
void sys_pd_prl_msg_ext_snk_cap_hook(UPD_EXT_MSG_SNK_CAP_t *p_info, PRL_MSG_DIR_TYPE_t dir);


/** \brief PD hook initialization, need to be called in system init
 *
 */
void sys_pd_hook_init();

bool_t sys_usbc_vbus_get();

void power_key_event_detect();

void sys_qc_machine_entrence();

void sys_init_config();

void sys_usbc_vbus_ovp_hanler();

void sys_deadbattery_protection();

void detect_current_direction();

void pd_hard_reset_need_check();

void powerkey_event_hander();

void chip_auto_power_off();

void sys_ntc_temp_protection();

void usbc_volt_adjust();

void dead_battery_exit_checkout();

void battery_charging_isfull();

void sys_small_current_mode();
#if SYS_USBA_ENABLED

void sys_usba_indet_detect();
void usba_current_check();

void sys_usba_unload();

void sys_usba_ocp_protection();
#else
#define sys_usba_indet_detect()
#define usba_current_check()
#define sys_usba_unload()
#define sys_usba_ocp_protection()
#endif
void sys_usbc_vbus_check();
void sys_usbc_ibus_ocp();
void sys_mcu_charge_discharge_ctrl();
void sys_gpio_i2c_int_handler();
bool_t sys_pd_ibus_over_check();

bool_t sys_new_power_level_req();

#endif /* #ifndef __SYS_PD_HOOK_H_ */

