/*
 * @file adm1176.c
 *
 *  @brief This file contains the function definition of hotswap ADM1176_CONTROL_CMDler ADM1176
 *
 *	@copyright Copyright 2024 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "adm1176.h"
#include "main.h"

extern I2C_HandleTypeDef hi2c1;
s_adm1176_drv_cb hsc_info;
s_adm1176_drv_cb hsc_ps1_sply;
s_adm1176_drv_cb hsc_ps2_sply;
s_adm1176_drv_cb hsc_es1_sply;
s_adm1176_drv_cb hsc_es2_sply;
s_adm1176_drv_cb hsc_es1_heat_sply;
s_adm1176_drv_cb hsc_es2_heat_sply;
s_adm1176_drv_cb hsc_io_brd_sply;
s_adm1176_drv_cb hsc_io_heat_coil_top1;
s_adm1176_drv_cb hsc_io_heat_coil_top2;
s_adm1176_drv_cb hsc_io_heat_coil_bot1;
s_adm1176_drv_cb hsc_io_heat_coil_bot2;

/*!
 *  @brief I2C read hook function for ADM1176 module
 */
uint8_t adm1176_i2c_read(void* intf_hdl, uint16_t slv_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
    I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef*)intf_hdl;
    int8_t sts = ADM1176_ERR;
    if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)slv_addr, &reg_addr, 1, 100) == HAL_OK)
    {
        HAL_Delay(1);
        if(HAL_I2C_Master_Receive(hi2c, (uint16_t)slv_addr, data, len, 100) == HAL_OK)
        {
            sts = ADM1176_SCS;
        }
        else
        {
            sts = ADM1176_E_COM_FAIL;
        }
    }
    else
    {
        sts = ADM1176_E_COM_FAIL;
    }
    return sts;
}

/*!
 *  @brief I2C write hook function for ADM1176 module
 */
uint8_t adm1176_i2c_write(void* intf_hdl, uint16_t slv_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
    I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef*)intf_hdl;
    int8_t sts = ADM1176_E_COM_FAIL;
    uint8_t data_send[3] = {0};
    data_send[0]=reg_addr;
    data_send[1]=data[0];
    if(len>1)
        data_send[2]=data[1];
    len++;
    if(data==NULL)
    {
        if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)slv_addr, data_send, len, 500)== HAL_OK)
        {
            sts = ADM1176_SCS;
        }
        else
        {
            sts = ADM1176_E_COM_FAIL;
        }
    }
    if(HAL_I2C_Master_Receive(hi2c, (uint16_t)slv_addr, data_send, len, 500) == HAL_OK)
    {
        sts = ADM1176_SCS;
    }
    else
    {
        sts = ADM1176_E_COM_FAIL;
    }
    return sts;
}

/*!
 * @brief This API is used to check null pointer
 */
static e_adm1176_err null_ptr_check(const s_adm1176_drv_cb_ptr dev)
{
    e_adm1176_err sts = ADM1176_ERR;
    if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL))
    {
        sts = NULL_PTR_ER;
    }
    else
    {
        sts = ADM1176_SCS;
    }
    return sts;
}

/*!
 *  @brief This API creates the ADM1176_CONTROL_CMD block memory and initialize the startup configurations for adm1176 instance.
 */
e_adm1176_err adm1176_init(s_adm1176_drv_cb_ptr adm1176_hdl)
{
    e_adm1176_err sts= ADM1176_ERR;
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS)
    {
        sts=NULL_PTR_ER;
    }
    return sts;
}

/*!
 *  @brief This API releases the ADM1176_CONTROL_CMD block memory for adm1176 instance
 */
e_adm1176_err adm1176_deinit(s_adm1176_drv_cb_ptr adm1176_hdl)
{
    e_adm1176_err sts= ADM1176_ERR;
    //free(adm1176_hdl);
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS)
    {
        sts=ADM1176_SCS;
    }
    else
    {
        sts=ADM1176_ERR;
    }
    return sts;
}

/*!
 *  @brief This API reads and returns the voltage in volts by pass by reference
 */
float adm1176_read_voltage(s_adm1176_drv_cb_ptr adm1176_hdl)
{
    e_adm1176_err sts= ADM1176_ERR;
    float voltage = 0;
    uint8_t volt_arr[2]={0};
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS)
    {
        sts=NULL_PTR_ER;
    }
    else
    {
        sts=adm1176_hdl->read(adm1176_hdl->intf_hdl, adm1176_hdl->slv_addr, ADM1176_VOLTAGE_READ_CMD, volt_arr,2);
        if(sts==ADM1176_SCS && volt_arr[0] != 0)
        {
            adm1176_hdl->rdbck_type=0;
            voltage= (volt_arr[0]<<4 | volt_arr[1]>>4);
            voltage=(V_FULL_SCALE/4096)*(voltage);
        }
        else
            voltage = 0;
    }
    return(voltage);
}

/*!
 *  @brief This API writes the slave address from i2c
 */
e_adm1176_err adm1176_self_test(s_adm1176_drv_cb_ptr adm1176_hdl )
{
    e_adm1176_err sts =ADM1176_ERR;
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS)
    {
        sts=NULL_PTR_ER;
    }
    else
    {
        sts=adm1176_hdl->write(adm1176_hdl->intf_hdl, adm1176_hdl->slv_addr,0,NULL,0);
        if (sts ==ADM1176_SCS)
        {
            sts = ADM1176_SCS;
        }
        else
        {
            sts = ADM1176_ERR;
        }
    }
    return sts;
}
/*!
 *  @brief This API reads and returns the current by pass by reference
 */
float adm1176_read_current(s_adm1176_drv_cb_ptr adm1176_hdl)
{
    e_adm1176_err sts= ADM1176_ERR;
    float current = 0;
    uint8_t curr_arr[2]={0};
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS)
    {
        sts=NULL_PTR_ER;
    }
    else
    {
        sts=adm1176_hdl->read(adm1176_hdl->intf_hdl, adm1176_hdl->slv_addr,ADM1176_CURRENT_READ_CMD,curr_arr,2);
        if(sts==ADM1176_SCS && curr_arr[0] != 0)
        {
            adm1176_hdl->rdbck_type=0;
            current= (curr_arr[0]<<4 | curr_arr[1]>>4);
            current = ((((I_FULL_SCALE)/4096.0)*(current))/SENSE_RESISTOR)/1000.0;
        }
        else
        {
            current = 0;
        }
    }
    return(current);
}

/*!
 *  @brief This API turn on/off hotswapping operations manually.
 */
e_adm1176_err adm1176_hotswap_control(s_adm1176_drv_cb_ptr adm1176_hdl, uint8_t on_off)
{
    e_adm1176_err sts= ADM1176_ERR;
    uint8_t data = 0;
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS)
    {
        sts=NULL_PTR_ER;
    }
    else
    {
        if(adm1176_hdl->hot_swp_sts!=on_off)
        {
            sts=adm1176_hdl->write(adm1176_hdl->intf_hdl, adm1176_hdl->slv_addr,ADM1176_CONTROL_CMD,&data,1);
            if(sts==ADM1176_SCS)
            {
                adm1176_hdl->hot_swp_sts=on_off;
            }
        }
        else
        {
            sts=ADM1176_ERR;
        }
    }
    return (sts);
}

/*!
 *  @brief This API reads and stores the status byte
 */
e_adm1176_err adm1176_get_sts(s_adm1176_drv_cb_ptr adm1176_hdl,uint8_t *sts)
{
    e_adm1176_err err_sts = ADM1176_ERR;
    uint8_t cmd = ADM1176_STATUS_RD_CMD;
    err_sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS || sts==NULL)
    {
        err_sts=NULL_PTR_ER;
    }
    else
    {
        adm1176_hdl->rdbck_type=1;
        err_sts=adm1176_hdl->read(adm1176_hdl->intf_hdl, adm1176_hdl->slv_addr,cmd,sts,1);

    }
    return err_sts;
}

/*!
 *  @brief This API reads and stores the hotswap status
 */
e_adm1176_err adm1176_get_hotswap_sts(s_adm1176_drv_cb_ptr adm1176_hdl, uint8_t *hotswap_sts)
{
    uint8_t var = 0;
    e_adm1176_err sts = ADM1176_ERR;
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS || hotswap_sts==NULL)
    {
        sts=NULL_PTR_ER;
    }
    else
    {
        sts=adm1176_get_sts(adm1176_hdl, &var);
        if(sts==ADM1176_SCS)
        {
            adm1176_hdl->over_curr_sts=(0x01 & (var));
            adm1176_hdl->hot_swp_sts=(0x10 & (var));
            *hotswap_sts = (uint8_t)adm1176_hdl->hot_swp_sts;
        }
    }
    return (sts);
}

/*!
 *  @brief This API reads and stores the overcurrent status
 */
e_adm1176_err adm1176_get_overcurrent_sts(s_adm1176_drv_cb_ptr adm1176_hdl, uint8_t *under_vlt_sts)
{
    uint8_t var = 0;
    e_adm1176_err sts = ADM1176_ERR;
    sts=null_ptr_check(adm1176_hdl);
    if(sts!=ADM1176_SCS ||under_vlt_sts==NULL)
    {
        sts=NULL_PTR_ER;
    }
    else
    {
        sts=adm1176_get_sts(adm1176_hdl, &var);
        if(sts==ADM1176_SCS)
        {
            adm1176_hdl->over_curr_sts=(0x01 & (var));
            adm1176_hdl->hot_swp_sts=(0x10 & (var));
            *under_vlt_sts = (uint8_t)adm1176_hdl->over_curr_sts;
        }
    }
    return (sts);
}

/*!
 *  @brief This API init payload board hotswap controller
 */
void ps_hsc_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case HSC_ADM1176_PS_1:
    {
        hsc_info.intf_hdl = &hi2c1;
        hsc_info.slv_addr = 0x80;
        hsc_info.write = adm1176_i2c_write;
        hsc_info.read =  adm1176_i2c_read;
    }
    break;

    default:
        break;
    }
}

/*!
 *  @brief This API init power board hotswap controller
 */
void pwr_brd_hsc_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case HSC_ADM1176_PS_1_IN_SUPPLY:
    {
        hsc_ps1_sply.intf_hdl = &hi2c1;
        hsc_ps1_sply.slv_addr = 0x94;
        hsc_ps1_sply.write = adm1176_i2c_write;
        hsc_ps1_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_PS_2_IN_SUPPLY:
    {
        hsc_ps2_sply.intf_hdl = &hi2c1;
        hsc_ps2_sply.slv_addr = 0x9C;
        hsc_ps2_sply.write = adm1176_i2c_write;
        hsc_ps2_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_EDGE_1_IN_SUPPLY:
    {
        hsc_es1_sply.intf_hdl = &hi2c1;
        hsc_es1_sply.slv_addr = 0x90;
        //hsc_es1_sply.slv_addr = 0x9E;
        hsc_es1_sply.write = adm1176_i2c_write;
        hsc_es1_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_EDGE_1_HEAT_COIL:
    {
        hsc_es1_heat_sply.intf_hdl = &hi2c1;
        hsc_es1_heat_sply.slv_addr = 0x8A;
        hsc_es1_heat_sply.write = adm1176_i2c_write;
        hsc_es1_heat_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_EDGE_2_IN_SUPPLY:
    {
        hsc_es2_sply.intf_hdl = &hi2c1;
        //hsc_es2_sply.slv_addr = 0x8E;
        hsc_es2_sply.slv_addr = 0xEC;
        hsc_es2_sply.write = adm1176_i2c_write;
        hsc_es2_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_EDGE_2_HEAT_COIL:
    {
        hsc_es2_heat_sply.intf_hdl = &hi2c1;
        hsc_es2_heat_sply.slv_addr = 0x8C;
        hsc_es2_heat_sply.write = adm1176_i2c_write;
        hsc_es2_heat_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_IO_BRD_IN_SUPPLY:
    {
        hsc_io_brd_sply.intf_hdl = &hi2c1;
        hsc_io_brd_sply.slv_addr = 0x98;
        hsc_io_brd_sply.write = adm1176_i2c_write;
        hsc_io_brd_sply.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_IO_BRD_HEAT_COIL_TOP_1:
    {
        hsc_io_heat_coil_top1.intf_hdl = &hi2c1;
        hsc_io_heat_coil_top1.slv_addr = 0x9A;
        hsc_io_heat_coil_top1.write = adm1176_i2c_write;
        hsc_io_heat_coil_top1.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_IO_BRD_HEAT_COIL_TOP_2:
    {
        hsc_io_heat_coil_top2.intf_hdl = &hi2c1;
        hsc_io_heat_coil_top2.slv_addr = 0x96;
        hsc_io_heat_coil_top2.write = adm1176_i2c_write;
        hsc_io_heat_coil_top2.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_IO_BRD_HEAT_COIL_BOTTOM_1:
    {
        hsc_io_heat_coil_bot1.intf_hdl = &hi2c1;
        hsc_io_heat_coil_bot1.slv_addr = 0xF8;
        hsc_io_heat_coil_bot1.write = adm1176_i2c_write;
        hsc_io_heat_coil_bot1.read =  adm1176_i2c_read;
    }
    break;

    case HSC_ADM1176_IO_BRD_HEAT_COIL_BOTTOM_2:
    {
        hsc_io_heat_coil_bot2.intf_hdl = &hi2c1;
        hsc_io_heat_coil_bot2.slv_addr = 0xC0;
        //hsc_io_heat_coil_bot2.slv_addr = 0x70;
        hsc_io_heat_coil_bot2.write = adm1176_i2c_write;
        hsc_io_heat_coil_bot2.read =  adm1176_i2c_read;
    }
    break;

    default:
        break;
    }
}
