/*
 * @file exo_io_al_i2c_common.c
 *
 * @brief This file contains abstracted function definition for I2C interface
 *
 * @copyright Copyright 2023 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 <stdio.h>
#include <unistd.h>
#include "exo_io_al_i2c_common.h"
#include "exo_hal_io_al_common.h"
#include "exo_ahw_al_common.h"
#include "exo_common.h"
#ifndef LINUX_TEMP_PORT
#include "exo_io_al_stm32f7xx_i2c.h"
#else
#include "exo_io_al_linux_i2c.h"
#endif

#ifndef LINUX_TEMP_PORT
#include "exo_io_al_stm32f7xx_i2c.h"
#endif


#define IOAL_I2C_TX_CPLT_CB		io_hal_i2c_tx_complete_cb		///< I2C1 TX complete callback event
#define IOAL_I2C_RX_CPLT_CB		io_hal_i2c_rx_complete_cb		///< I2C1 RX complete callback event
#define IOAL_I2C_ABORT_CPLT_CB		io_hal_i2c_abort_complete_cb		///< I2C1 Abort complete callback event
#define IOAL_I2C_LISTEN_CPLT_CB		io_hal_i2c_listen_complete_cb		///< I2C1 Listen complete callback event
#define IOAL_I2C_ERROR_CB		io_hal_i2c_error_cb			///< I2C1 Error complete callback event


extern void *intf_inst_hdle_ptr[MAX_IO_INST_ID];


/**
 * @brief This API initializes the control block memory
  * and do the basic configurations for I2C
 */
hal_ret_sts io_hal_i2c_init(ioal_i2c_hdle *ioal_hi2c, io_inst_id inst_id)
{
#ifdef LINUX_TEMP_PORT
    DEBUG_CPRINT(("\n EXO IO AL I2C Initialise"));
    usleep(100000);
#endif
	hal_ret_sts sts = HAL_IO_INIT_INVALID_INSTANCE;
        if(ioal_hi2c != NULL)
        {
            switch(inst_id)
            {
                case IOAL_INST_I2C1:
                    if(HAL_SCS == io_hal_common_i2c1_init(ioal_hi2c))
                    {
                        intf_inst_hdle_ptr[IOAL_INST_I2C1] = ioal_hi2c;
                        io_hal_i2c1_cb_init(ioal_hi2c);
                    }
                    else
                    {
                        sts = HAL_IO_INIT_ERR;
                    }
                    break;
                case IOAL_INST_I2C2:
                    if(HAL_SCS == io_hal_common_i2c2_init(ioal_hi2c))
                    {
                        intf_inst_hdle_ptr[IOAL_INST_I2C2] = ioal_hi2c;
                        io_hal_i2c2_cb_init(ioal_hi2c);
                    }
                    else
                    {
                        sts = HAL_IO_INIT_ERR;
                    }
                    break;

                case IOAL_INST_I2C3:
                    if(HAL_SCS == io_hal_common_i2c3_init(ioal_hi2c))
                    {
                        intf_inst_hdle_ptr[IOAL_INST_I2C3] = ioal_hi2c;
                        io_hal_i2c3_cb_init(ioal_hi2c);
                    }
                    else
                    {
                        sts = HAL_IO_INIT_ERR;
                    }
                    break;

                case IOAL_INST_I2C4:
                    if(HAL_SCS == io_hal_common_i2c4_init(ioal_hi2c))
                    {
                        intf_inst_hdle_ptr[IOAL_INST_I2C4] = ioal_hi2c;
                        io_hal_i2c4_cb_init(ioal_hi2c);
                    }
                    else
                    {
                        sts = HAL_IO_INIT_ERR;
                    }
                    break;
                default:
                    sts = HAL_IO_INIT_INVALID_INSTANCE;
                    break;
            }
        }
        else
        {
            sts = HAL_IO_INVLD_ARG;
        }
#ifdef LINUX_TEMP_PORT
    DEBUG_CPRINT(("\n EXO IO AL I2C Initialisation completed successfully"));
#endif
    return sts;
}

/**
 * @brief This function de-initialize the i2c
 */
hal_ret_sts io_hal_i2c_deinit(ioal_i2c_hdle *hi2c)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	hi2c->intf_gen_info.state = IO_BUSY_STATE;
	if(HAL_SCS == io_hal_common_i2c_deinit(hi2c))
	{
		ret_sts = HAL_SCS;
		hi2c->intf_gen_info.state = IO_ERR_STATE;
	}
	else
	{
		ret_sts = HAL_IO_TX_ERR;
		hi2c->intf_gen_info.state = IO_FREE_STATE;
	}
	return ret_sts;
}

/**
 * @brief This function get the i2c error code
 */
uint32 io_hal_i2c_get_err(ioal_i2c_hdle *hi2c)
{
	return io_hal_common_i2c_get_err(hi2c);
}

/**
 * @brief This API initializes the I2C1 callback events
 */
void io_hal_i2c1_cb_init(ioal_i2c_hdle *hi2c1)
{
	hi2c1->i2c_mst_tx_cplt_cb = IOAL_I2C_TX_CPLT_CB;
	hi2c1->i2c_mst_rx_cplt_cb = IOAL_I2C_RX_CPLT_CB;
	hi2c1->i2c_abort_cplt_cb = IOAL_I2C_ABORT_CPLT_CB;
	hi2c1->i2c_listen_cplt_cb = IOAL_I2C_LISTEN_CPLT_CB;
	hi2c1->i2c_error_cb = IOAL_I2C_ERROR_CB;

}

/**
 * @brief This API initializes the I2C2 callback events
 */
void io_hal_i2c2_cb_init(ioal_i2c_hdle *hi2c2)
{
	hi2c2->i2c_mst_tx_cplt_cb = IOAL_I2C_TX_CPLT_CB;
	hi2c2->i2c_mst_rx_cplt_cb = IOAL_I2C_RX_CPLT_CB;
	hi2c2->i2c_abort_cplt_cb = IOAL_I2C_ABORT_CPLT_CB;
	hi2c2->i2c_listen_cplt_cb = IOAL_I2C_LISTEN_CPLT_CB;
	hi2c2->i2c_error_cb = IOAL_I2C_ERROR_CB;

}

/**
 * @brief This API initializes the I2C3 callback events
 */
void io_hal_i2c3_cb_init(ioal_i2c_hdle *hi2c3)
{
	hi2c3->i2c_mst_tx_cplt_cb = IOAL_I2C_TX_CPLT_CB;
	hi2c3->i2c_mst_rx_cplt_cb = IOAL_I2C_RX_CPLT_CB;
	hi2c3->i2c_abort_cplt_cb = IOAL_I2C_ABORT_CPLT_CB;
	hi2c3->i2c_listen_cplt_cb = IOAL_I2C_LISTEN_CPLT_CB;
	hi2c3->i2c_error_cb = IOAL_I2C_ERROR_CB;

}

/**
 * @brief This API initializes the I2C4 callback events
 */
void io_hal_i2c4_cb_init(ioal_i2c_hdle *hi2c4)
{
	hi2c4->i2c_mst_tx_cplt_cb = IOAL_I2C_TX_CPLT_CB;
	hi2c4->i2c_mst_rx_cplt_cb = IOAL_I2C_RX_CPLT_CB;
	hi2c4->i2c_abort_cplt_cb = IOAL_I2C_ABORT_CPLT_CB;
	hi2c4->i2c_listen_cplt_cb = IOAL_I2C_LISTEN_CPLT_CB;
	hi2c4->i2c_error_cb = IOAL_I2C_ERROR_CB;
}

/**
 * @brief This API transmits data in master mode.
 */
hal_ret_sts io_hal_i2c_transmit(ioal_i2c_hdle *hi2c, uint16 addr, uint8 *pdata, uint16 size, uint32 timeout)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    hi2c->intf_gen_info.state = IO_BUSY_STATE;
    if(hi2c != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_transmit(hi2c,addr,pdata,size,200))
        {
            ret_sts = HAL_SCS;
            hi2c->intf_gen_info.state = IO_FREE_STATE;
        }
        else
        {
            ret_sts = HAL_IO_TX_ERR;
            hi2c->intf_gen_info.state = IO_FREE_STATE;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API receives data in master mode.
 */
hal_ret_sts io_hal_i2c_receive(ioal_i2c_hdle *hi2c, uint16 addr, uint8 *pdata, uint16 size, uint32 timeout)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    hi2c->intf_gen_info.state = IO_BUSY_STATE;
    if(hi2c != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_receive(hi2c,addr,pdata,size,timeout))
        {
            ret_sts = HAL_SCS;
            hi2c->intf_gen_info.state = IO_FREE_STATE;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
            hi2c->intf_gen_info.state = IO_FREE_STATE;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

#ifndef LINUX_TEMP_PORT
/**
 * @brief This API transmit data in master mode with Interrupt
 */
hal_ret_sts io_hal_i2c_transmit_it(ioal_i2c_hdle *hi2c,  ahw_al_gen_info* ahw_info, uint16 addr, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    hi2c->intf_gen_info.state = IO_BUSY_STATE;
    hi2c->app_callbacks=ahw_info->intr_hdl.io_cb_list.i2c_callbacks;
    hi2c->cb_context=ahw_info->intr_hdl.cb_context;
    if(hi2c != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_transmit_it(hi2c,addr,pdata,size))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API receive data in master mode with Interrupt
 */
hal_ret_sts io_hal_i2c_receive_it(ioal_i2c_hdle *hi2c,  ahw_al_gen_info* ahw_info, uint16 addr, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    hi2c->intf_gen_info.state = IO_BUSY_STATE;
    hi2c->app_callbacks=ahw_info->intr_hdl.io_cb_list.i2c_callbacks;
    hi2c->cb_context=ahw_info->intr_hdl.cb_context;
    if(hi2c != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_receive_it(hi2c,addr,pdata,size))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API transmit data in master mode with DMA
 */
hal_ret_sts io_hal_i2c_transmit_dma(ioal_i2c_hdle *hi2c, ahw_al_gen_info* ahw_info, uint16 addr, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    hi2c->intf_gen_info.state = IO_BUSY_STATE;
    hi2c->app_callbacks=ahw_info->intr_hdl.io_cb_list.i2c_callbacks;
    hi2c->cb_context=ahw_info->intr_hdl.cb_context;
    if(hi2c != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_transmit_dma(hi2c,addr,pdata,size))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API receive data in master mode with DMA
 */
hal_ret_sts io_hal_i2c_receive_dma(ioal_i2c_hdle *hi2c, ahw_al_gen_info* ahw_info, uint16 addr, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    hi2c->intf_gen_info.state = IO_BUSY_STATE;
    hi2c->app_callbacks=ahw_info->intr_hdl.io_cb_list.i2c_callbacks;
    hi2c->cb_context=ahw_info->intr_hdl.cb_context;
    if(hi2c != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_receive_dma(hi2c,addr,pdata,size))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API checks if device is ready for communication.
 */
hal_ret_sts io_hal_i2c_is_device_ready(ioal_i2c_hdle *hi2c, uint16 addr, uint32 trials, uint32 timeout)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(hi2c != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_is_device_ready(hi2c,addr,trials,timeout))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_TX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API enable the Address listen mode with interrupt.
 */
hal_ret_sts io_hal_i2c_enablelisten_it(ioal_i2c_hdle *hi2c)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(hi2c != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_enablelisten_it(hi2c))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_TX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/**
 * @brief This API abort a master I2C with interrupt.
 */
hal_ret_sts io_hal_i2c_abort_it(ioal_i2c_hdle *hi2c, uint16 addr)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(hi2c != NULL)
    {
        if(HAL_SCS == io_hal_common_i2c_abort_it(hi2c, addr))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_TX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}
#endif

void io_hal_i2c_tx_complete_cb(ioal_i2c_hdle *hi2c)
{
    hi2c->intf_gen_info.state = IO_FREE_STATE;
    hi2c->app_callbacks.i2c_mst_tx_cplt_cb(hi2c);
}
void io_hal_i2c_rx_complete_cb(ioal_i2c_hdle *hi2c)
{
    hi2c->intf_gen_info.state = IO_FREE_STATE;
    hi2c->app_callbacks.i2c_mst_rx_cplt_cb(hi2c);
}
void io_hal_i2c_listen_complete_cb(ioal_i2c_hdle *hi2c)
{
    hi2c->intf_gen_info.state = IO_FREE_STATE;
    hi2c->app_callbacks.i2c_listen_cplt_cb(hi2c);
}
void io_hal_i2c_abort_complete_cb(ioal_i2c_hdle *hi2c)
{
    hi2c->intf_gen_info.state = IO_FREE_STATE;
    hi2c->app_callbacks.i2c_abort_cplt_cb(hi2c);
}
void io_hal_i2c_error_cb(ioal_i2c_hdle *hi2c)
{
    hi2c->intf_gen_info.state = IO_FREE_STATE;
  //  hi2c->app_callbacks.i2c_error_cb(hi2c);
}

