/**
  *****************************************************************************
  * @file    sys_ufcs_hook.c
  * @author  Solution Team
  * @version V1.00
  * @date    28-February-2023
  * @brief   UFCS hook definitions
  *****************************************************************************
  * @attention
  *  Copyright (c) 2017 - 2023 Unicmicro Co., Ltd.
  *  All Rights Reserved.
  *****************************************************************************
  */

#include "libc.h"
#include "drivers.h"
#include "ufcs.h"
#include "sys_ufcs_config.h"
#include "sys_ufcs_hook.h"
#include "sys_low_power.h"
#include "sys_gpio.h"
#include "usbpd.h"
#include "sys_bat_intf.h"
#include "sys_bc_qc_hook.h"

volatile SYS_UFCS_INFO_t g_sys_ufcs;
#if UFCS_DEBUG_ENABLED
extern const char * const dev_type_str[UFCS_DEV_TYPE_END];
#endif

/**
 * @description:    设备去识别回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_unidentified_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        printf("\n[%s]Unidentified Hook\n", dev_type_str[ufcs_cfg_dev_type_get(dev)]);
    }
#endif /* UFCS_DEBUG_ENABLED */
    g_sys_ufcs.sys_obj_pos = 0;
}

/**
 * @description:    设备已识别回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_identified_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        printf("\n[%s]Identified Hook\n", dev_type_str[ufcs_cfg_dev_type_get(dev)]);
    }
#endif /* UFCS_DEBUG_ENABLED */
    g_sys_ufcs.sys_obj_pos = 0;
}

/**
 * @description:    检测到硬件复位回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_hrst_detected_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        printf("\n[%s]HRST Detected Hook\n", dev_type_str[ufcs_cfg_dev_type_get(dev)]);
    }
#endif /* UFCS_DEBUG_ENABLED */
    g_sys_ufcs.sys_obj_pos = 0;
    sys_gpio_vbus_en_set(FALSE);
    sys_gpio_pmic_pstop_set(FALSE);
    sys_bat_dis_foldback_set(FALSE);
    sys_bat_discharge_vbus_ibus_set(SYS_BAT_SC8815_CURRENT_MIN, SYS_BAT_SC8815_CURRENT_MIN, IN_DIR);
    pe_error_recovery_directed_set(TRUE);
}

/**
 * @description:    硬件复位完成回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_hrst_completed_hook(u32_t dev_ptr)
{
#if SYS_UFCS_ENABLED
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        printf("\n[%s]HRST Completed Hook\n", dev_type_str[ufcs_cfg_dev_type_get(dev)]);
    }
#endif /* UFCS_DEBUG_ENABLED */
    g_sys_ufcs.sys_obj_pos = 0;
    if (usbpd_cfg_port_quick_charge_en_get())
    {
        g_usbc_qc_info.bc_qc_disable = FALSE;
        if (usbpd_cfg_port_quick_charge_ver_get() == DPM_QC_V2)
        {
            g_usbc_qc_info.qc_v3_disabled = TRUE;
        }
        else {
            g_usbc_qc_info.qc_v3_disabled = FALSE;
        }
    }
    else {
        g_usbc_qc_info.bc_qc_disable = TRUE;
    }
    if (!dpm_port_dead_battery_get())
    {
        bc_qc_enable_set(&g_usbc_qc_info, TRUE, FALSE);
    }
    else {
        drv_chip_dp0_dm0_short_set(TRUE);
    }
#endif
}

/**
 * @description:    设备切换新的输出能力回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @param pos       输出能力编号索引，取值范围：1~7
 * @return          返回0则切换成功，非零则切换失败
 */
status_t sys_ufcs_transit_to_new_power_hook(u32_t dev_ptr, u32_t pos)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        printf("\n[%s]New Power Hook: %u->%u\n",
            dev_type_str[ufcs_cfg_dev_type_get(dev)],
            g_sys_ufcs.sys_obj_pos, pos);
    }
#endif /* UFCS_DEBUG_ENABLED */
    g_sys_ufcs.sys_obj_pos = pos;
    if (UFCS_DEV_TYPE_SRC == ufcs_cfg_dev_type_get(dev))
    {
#if 0
        u32_t duty, volt;
        if (pos)
        {
            volt = ufcs_pe_rx_request_req_volt_get(dev) * UFCS_VOLTAGE_DIV;
            if (volt >= UFCS_VOLTAGE_5V)
            {
                u16_t dutyMin = (u16_t)(SYS_PPS_1_PWM_DUTY_MAX >> 16);
                u16_t dutyMax = (u16_t)(SYS_DEF_PWM_DUTY_5V >> 16);
                duty = PWM_VOLT_TO_DUTY_DEC(volt,UFCS_VOLTAGE_5V,SYS_DEF_PWM_DUTY_STEP_VOLT,dutyMin,dutyMax);
            }
            else {
                duty = SYS_DEF_USBA_PWM_VOLT_TO_DUTY_LESS5(volt);
                if (duty >= SYS_DEF_PWM_PER)
                    duty = SYS_DEF_PWM_PER - 1;
            }
            drv_pwm_duty_set(SYS_PWM_INDEX_FOR_VOLT_CTRL, duty, SYS_DEF_PWM_PER);
        }
        else {
            volt = UFCS_VOLTAGE_5V;
            duty = SYS_DEF_PWM_DUTY_5V;
            drv_pwm_duty_set2(SYS_PWM_INDEX_FOR_VOLT_CTRL, duty);
        }
        drv_pwm_en_set(SYS_PWM_INDEX_FOR_VOLT_CTRL, TRUE);
#if UFCS_DEBUG_ENABLED
        if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2) printf("\nUVBUS-Set(%u):%umV,Duty:%x\n", pos, volt, duty);
#endif /* UFCS_DEBUG_ENABLED */
#else
        u32_t volt,curr;
        if (pos)
        {
            volt = ufcs_pe_rx_request_req_volt_get(dev) * UFCS_VOLTAGE_DIV;
            curr = ufcs_pe_rx_request_req_curr_get(dev) * UFCS_CURRENT_DIV + 300;
        }
        else {
            volt = UFCS_VOLTAGE_5V;
            curr = SYS_DEF_PWM_DUTY_5V;
        }
        /*设置电压电流*/
        sys_bat_discharge_vbus_ibus_set(volt, curr, OUT_DIR);

#if UFCS_DEBUG_ENABLED
        if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_1) printf("\nUVBUS-Set(%u):%umV,IBUS:%u\n", pos, volt, curr);
#endif /* UFCS_DEBUG_ENABLED */
#endif
    }
    return S_OK;
}

/**
 * @description:    设备获取线路泄放开关状态回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return          TRUE：打开，FALSE：关闭
 */
bool_t sys_ufcs_vbus_discharge_en_get(u32_t dev_ptr)
{
    return g_sys_ufcs.discharge_en;
}

/**
 * @description:    设备获取线路泄放开关状态回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @param flg       TRUE：打开，FALSE：关闭
 * @return void
 */
void sys_ufcs_vbus_discharge_en_set(u32_t dev_ptr, bool_t flg)
{
    g_sys_ufcs.discharge_en = flg;
}

/**
 * @description:    设备获取供电线路电压值回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return          电压值，单位毫伏
 */
u32_t sys_ufcs_vbus_volt_get(u32_t dev_ptr)
{
    return (u32_t)(drv_adc_read_multi_avg(DRV_ADC_CHN_VBUS,4) * drv_flash_trim_ref_volt_get() * VBUS_ADC_CONSTANT) >> ADC_RSLT_REG_ADC_RSLT_WTH;
}

/**
 * @description:    设备获取供电线路电流值回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return          电流值，单位毫安
 */
u32_t sys_ufcs_ibus_current_get(u32_t dev_ptr)
{
#if 0
    return drv_adc_ibus_get(SYS_CURRENT_SENCE_SAMPLE_RESISTER);
#else
    return sys_bat_ibus_val_get();
#endif
}

/**
 * @description:    设备输出能力改变请求回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_power_change_req_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if SYS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        puts("\nPower Change Req Hook");
    }
#endif /* SYS_DEBUG_ENABLED */
}

/**
 * @description:    设备鉴权请求回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_verify_req_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if SYS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        puts("\nVerify Req Hook");
    }
#endif /* SYS_DEBUG_ENABLED */
}

/**
 * @description:    设备鉴权回应回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_verify_resp_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if SYS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        puts("\nVerify Response Hook");
    }
#endif /* SYS_DEBUG_ENABLED */
}

/**
 * @description:    UFCS设备空闲时回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_idle_loop_hook(u32_t dev_ptr)
{

}

/**
 * @description:    设备收到消息回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_prl_msg_received_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
    sys_lpm_activate();
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        puts("\nPRL Msg Recevied Hook");
    }
#endif /* UFCS_DEBUG_ENABLED */
    switch (dev->prl.rx_msg_type)
    {
        case UFCS_PRL_MSG_DET_CBL_INFO:
        case UFCS_PRL_MSG_START_CBL_DET:
        case UFCS_PRL_MSG_END_CBL_DET:
            ufcs_pe_unsupported_msg_received_set(dev,TRUE);
            break;
        default:
            break;
    }
}

/**
 * @description:    设备发送消息回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @return void
 */
void sys_ufcs_prl_msg_sent_hook(u32_t dev_ptr)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
    sys_lpm_activate();
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        puts("\nPRL Msg Sent Hook");
    }
#endif /* UFCS_DEBUG_ENABLED */
}

/**
 * @description:    设备发送或接收输出能力消息回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @param dir       消息的方向，发送或接收
 * @return void
 */
void sys_ufcs_msg_output_cap_hook(u32_t dev_ptr, UFCS_PRL_DIR_TYPE_t dir)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        if (dir == UFCS_PRL_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Output Hook:\n");
    }
#endif /* UFCS_DEBUG_ENABLED */
}

/**
 * @description:    设备发送或接收请求输出能力消息回调函数
 * @param dev_ptr   UFCS设备指针（UFCS_DEV_t *）
 * @param dir       消息的方向，发送或接收
 * @return void
 */
void sys_ufcs_msg_request_hook(u32_t dev_ptr, UFCS_PRL_DIR_TYPE_t dir)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)dev_ptr;
#if UFCS_DEBUG_ENABLED
    if (ufcs_cfg_dbg_get(dev) >= UFCS_DEBUG_LEVEL_2)
    {
        if (dir == UFCS_PRL_TX)
        {
            drv_uart_putstr("\nTX ");
        }
        else {
            drv_uart_putstr("\nRX ");
        }
        drv_uart_putstr("Request Hook:\n");
    }
#endif /* UFCS_DEBUG_ENABLED */
}

/**
 * @description:    UFCS设备回调函数初始化
 * @param void
 * @return void
 */
void sys_ufcs_hook_init(void)
{
    UFCS_DEV_t *dev = (UFCS_DEV_t *)&g_sys_ufcs.dev_ufcs_usbc;

    /* 把本地UFCS设备实例的地址赋值给全局数组 */
    gp_ufcs_dev_items[UFCS_DEV_ID_0] = (u32_t)&g_sys_ufcs.dev_ufcs_usbc;

    /* 清空设备UFCS信息 */
    memset((void *)&g_sys_ufcs, 0, sizeof(SYS_UFCS_INFO_t));

    /* 获取配置区地址 sizeof(SYS_CONFIG_t)=32,sizeof(USB_PD_CONFIG_t)=276,sizeof(UFCS_DEV_CFG_t)=72 */
    dev->cfg = (UFCS_DEV_CFG_t *)&g_sys_cfg_map[sizeof(SYS_CONFIG_t)+sizeof(USB_PD_CONFIG_t)];

    /* 加载UFCS在Flash中的配置 */
    sys_ufcs_cfg_load(dev);

    /* 标记UFCS正在初始化中 */
    g_sys_ufcs.sys_initializing = TRUE;

    /* 赋值回调函数 */
    dev->unidentified = sys_ufcs_unidentified_hook;
    dev->identified = sys_ufcs_identified_hook;

    dev->hard_reset_detected = sys_ufcs_hrst_detected_hook;
    dev->hard_reset_completed = sys_ufcs_hrst_completed_hook;
    dev->transit_to_new_power = sys_ufcs_transit_to_new_power_hook;

    dev->vbus_discharge_set = sys_ufcs_vbus_discharge_en_set;

    dev->vbus_discharge_get = sys_ufcs_vbus_discharge_en_get;
    dev->vbus_volt_get = sys_ufcs_vbus_volt_get;
    dev->ibus_current_get = sys_ufcs_ibus_current_get;

    dev->power_change_req = sys_ufcs_power_change_req_hook;
    dev->verify_req = sys_ufcs_verify_req_hook;
    dev->verify_resp = sys_ufcs_verify_resp_hook;

    dev->prl_msg_received = sys_ufcs_prl_msg_received_hook;
    dev->prl_msg_sent = sys_ufcs_prl_msg_sent_hook;
    dev->idle_loop_hook = sys_ufcs_idle_loop_hook;
    dev->msg_output_cap = sys_ufcs_msg_output_cap_hook;
    dev->msg_request = sys_ufcs_msg_request_hook;

    /* PHY相关初始化，必须在这里调用 */
    ufcs_phy_init(dev);
    ufcs_phy_tx_pin_set(dev, UART_TXD);
    ufcs_phy_rx_pin_set(dev, UART_RXD);

}
