/*
 * @file exo_io_al_uart_common.c
 *
 * @brief This file contains abstracted function definition for UART 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_uart_common.h"
#include "exo_hal_io_al_common.h"
#include "exo_common.h"
#ifndef LINUX_TEMP_PORT
#include "exo_io_al_stm32f7xx_uart.h"
#else
#include "exo_io_al_linux_uart.h"
#endif

#define IOAL_UART_TX_CPLT_CB		io_hal_uart_tx_cmplt_cb		///< UART TX complete callback event
#define IOAL_UART_RX_CPLT_CB		io_hal_uart_rx_cmplt_cb		///< UART RX complete callback event
#define IOAL_UART_ABORT_CPLT_CB		io_hal_uart_abort_cmplt_cb	///< UART Abort complete callback event
#define IOAL_UART_ABORT_TX_CPLT_CB	io_hal_uart_abort_tx_cmplt_cb	///< UART Abort TX complete callback event
#define IOAL_UART_ABORT_RX_CPLT_CB	io_hal_uart_abort_rx_cmplt_cb	///< UART Abort RX complete callback event
#define IOAL_UART_ERROR_CB		io_hal_uart_error_cb	        ///< UART error 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 UART interface
 */
hal_ret_sts io_hal_uart_init(ioal_uart_hdle *ioal_huart, io_inst_id inst_id)
{
#ifdef LINUX_TEMP_PORT
    DEBUG_CPRINT(("\n EXO IO AL UART Initialise"));
    usleep(100000);
#endif
    hal_ret_sts sts=HAL_IO_INIT_ERR;
    if(ioal_huart != NULL)
    {
        switch(inst_id)
        {
            case IOAL_INST_UART1:
                if(HAL_SCS == io_hal_common_uart1_init(ioal_huart))
                {
                    intf_inst_hdle_ptr[IOAL_INST_UART1] = ioal_huart;
                    io_hal_uart1_cb_init(ioal_huart);
                    sts=HAL_SCS;
                }
                else
                {
                    sts = HAL_IO_INIT_ERR;
                }
                break;
            case IOAL_INST_UART4:
                if(HAL_SCS == io_hal_common_uart4_init(ioal_huart))
                {
                    intf_inst_hdle_ptr[IOAL_INST_UART4] = ioal_huart;
                    io_hal_uart4_cb_init(ioal_huart);
                    sts=HAL_SCS;

                }
                else
                {

                    sts = HAL_IO_INIT_ERR;
                }
                break;

            case IOAL_INST_UART5:
                if(HAL_SCS == io_hal_common_uart5_init(ioal_huart))
                {
                    intf_inst_hdle_ptr[IOAL_INST_UART5] = ioal_huart;
                    io_hal_uart5_cb_init(ioal_huart);
                    sts=HAL_SCS;

                }
                else
                {

                    sts = HAL_IO_INIT_ERR;
                }

                break;
            case IOAL_INST_UART6:
                if(HAL_SCS == io_hal_common_uart6_init(ioal_huart))
                {
                    intf_inst_hdle_ptr[IOAL_INST_UART6] = ioal_huart;
                    io_hal_uart6_cb_init(ioal_huart);
                    sts=HAL_SCS;
                }
                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 UART Initialisation completed successfully"));
#endif
    return sts;
}

/*
 * @brief This API initialize the callback events for UART6
 */
void io_hal_uart6_cb_init(ioal_uart_hdle *huart6)
{
    huart6->tx_cplt_cb = IOAL_UART_TX_CPLT_CB;
    huart6->rx_cplt_cb = IOAL_UART_RX_CPLT_CB;
    huart6->abort_cplt_cb = IOAL_UART_ABORT_CPLT_CB;
    huart6->abort_tx_cplt_cb = IOAL_UART_ABORT_TX_CPLT_CB;
    huart6->abort_rx_cplt_cb = IOAL_UART_ABORT_RX_CPLT_CB;
    huart6->error_cb = IOAL_UART_ERROR_CB;

}


/*
 * @brief This API initialize the callback events for UART1
 */
void io_hal_uart1_cb_init(ioal_uart_hdle *huart1)
{
    huart1->tx_cplt_cb = IOAL_UART_TX_CPLT_CB;
    huart1->rx_cplt_cb = IOAL_UART_RX_CPLT_CB;
    huart1->abort_cplt_cb = IOAL_UART_ABORT_CPLT_CB;
    huart1->abort_tx_cplt_cb = IOAL_UART_ABORT_TX_CPLT_CB;
    huart1->abort_rx_cplt_cb = IOAL_UART_ABORT_RX_CPLT_CB;
    huart1->error_cb = IOAL_UART_ERROR_CB;
}

/*
 * @brief This API initialize the callback events for UART4
 */
void io_hal_uart4_cb_init(ioal_uart_hdle *huart4)
{
    huart4->tx_cplt_cb = IOAL_UART_TX_CPLT_CB;
    huart4->rx_cplt_cb = IOAL_UART_RX_CPLT_CB;
    huart4->abort_cplt_cb = IOAL_UART_ABORT_CPLT_CB;
    huart4->abort_tx_cplt_cb = IOAL_UART_ABORT_TX_CPLT_CB;
    huart4->abort_rx_cplt_cb = IOAL_UART_ABORT_RX_CPLT_CB;
    huart4->error_cb = IOAL_UART_ERROR_CB;
}

/*
 * @brief This API initialize the callback events for UART5
 */
void io_hal_uart5_cb_init(ioal_uart_hdle *huart5)
{
    huart5->tx_cplt_cb = IOAL_UART_TX_CPLT_CB;
    huart5->rx_cplt_cb = IOAL_UART_RX_CPLT_CB;
    huart5->abort_cplt_cb = IOAL_UART_ABORT_CPLT_CB;
    huart5->abort_tx_cplt_cb = IOAL_UART_ABORT_TX_CPLT_CB;
    huart5->abort_rx_cplt_cb = IOAL_UART_ABORT_RX_CPLT_CB;
    huart5->error_cb = IOAL_UART_ERROR_CB;

}

/*
 * @brief This API transmit the data in UART interface with blocking mode
 */
hal_ret_sts io_hal_uart_transmit(ioal_uart_hdle *huart, uint8 *pdata, uint16 size, uint32 timeout)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_transmit(huart,pdata,size,timeout))
        {
            ret_sts = HAL_SCS;
            huart->intf_gen_info.state = IO_FREE_STATE;
        }
        else
        {
            ret_sts = HAL_IO_TX_ERR;
            huart->intf_gen_info.state = IO_FREE_STATE;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API receive the data in UART interface with blocking mode
 */
hal_ret_sts io_hal_uart_receive(ioal_uart_hdle *huart, uint8 *pdata, uint16 size, uint32 timeout)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_receive(huart,pdata,size,timeout))
        {
            ret_sts = HAL_SCS;
            huart->intf_gen_info.state = IO_FREE_STATE;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
            huart->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 the data with interrupt mode
 */
hal_ret_sts io_hal_uart_transmit_it(ioal_uart_hdle *huart, ahw_al_gen_info* ahw_info, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    huart->app_callbacks=ahw_info->intr_hdl.io_cb_list.uart_callbacks;
    huart->cb_context=ahw_info->intr_hdl.cb_context;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_transmit_it(huart,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 the data with interrupt mode
 */
hal_ret_sts io_hal_uart_receive_it(ioal_uart_hdle *huart, ahw_al_gen_info* ahw_info, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    huart->app_callbacks=ahw_info->intr_hdl.io_cb_list.uart_callbacks;
    huart->cb_context=ahw_info->intr_hdl.cb_context;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_receive_it(huart,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 the data in UART interface with DMA mode
 */
hal_ret_sts io_hal_uart_transmit_dma(ioal_uart_hdle *huart, ahw_al_gen_info* ahw_info, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    huart->app_callbacks=ahw_info->intr_hdl.io_cb_list.uart_callbacks;
    huart->cb_context=ahw_info->intr_hdl.cb_context;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_transmit_dma(huart,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 the data in UART interface in DMA mode
 */
hal_ret_sts io_hal_uart_receive_dma(ioal_uart_hdle *huart, ahw_al_gen_info* ahw_info, uint8 *pdata, uint16 size)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    huart->app_callbacks=ahw_info->intr_hdl.io_cb_list.uart_callbacks;
    huart->cb_context=ahw_info->intr_hdl.cb_context;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_receive_dma(huart,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 pause the transmission of data in DMA mode
 */
hal_ret_sts io_hal_uart_dma_pause(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_dma_pause(huart))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

hal_ret_sts io_hal_uart_dma_receive_to_idle(ioal_uart_hdle *huart ,  ahw_al_gen_info* ahw_info,uint8 *pdata, uint16 size )
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    huart->app_callbacks=ahw_info->intr_hdl.io_cb_list.uart_callbacks;
    huart->cb_context=ahw_info->intr_hdl.cb_context;
    if(huart != NULL && pdata != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_dma_receive_to_idle(huart ,pdata ,size))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

hal_ret_sts io_hal_uart_get_rx_event_type(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_get_rx_event_type(huart))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API resume the transmission of data in DMA mode
 */
hal_ret_sts io_hal_uart_dma_resume(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_dma_resume(huart))
        {
            ret_sts = HAL_SCS;
        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API stop the transmission of data in DMA mode
 */
hal_ret_sts io_hal_uart_dma_stop(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_dma_stop(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API abort the transmission of data
 */
hal_ret_sts io_hal_uart_abort(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_abort(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API abort the ongoing transmit of data
 */
hal_ret_sts io_hal_uart_abort_transmit(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_abort_transmit(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API abort the receive of data
 */
hal_ret_sts io_hal_uart_abort_receive(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_abort_receive(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API abort transmission of data with interrupt mode
 */
hal_ret_sts io_hal_uart_abort_it(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_abort_it(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API abort the transmission of data with interrupt mode
 */
hal_ret_sts io_hal_uart_abort_transmit_it(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_abort_transmit_it(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API abort the receive of data with interrupt mode
 */
hal_ret_sts io_hal_uart_abort_receive_it(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_abort_receive_it(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}


/*
 * @brief This API configures the receive timeout
 */
hal_ret_sts io_hal_uart_receive_timeout_config(ioal_uart_hdle *huart,uint32 timeout)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_receive_timeout_config(huart,timeout))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

/*
 * @brief This API This API enables the receive timeout
 */
hal_ret_sts io_hal_uart_receive_timeout_enable(ioal_uart_hdle *huart)
{
    hal_ret_sts ret_sts = HAL_MAX_ERR;
    if(huart != NULL)
    {
        if(HAL_SCS == io_hal_common_uart_receive_timeout_enable(huart))
        {
            ret_sts = HAL_SCS;

        }
        else
        {
            ret_sts = HAL_IO_RX_ERR;
        }
    }
    else
    {
        ret_sts = HAL_IO_INVLD_ARG;
    }
    return ret_sts;
}

#endif

/*
 * @brief This API to get UART state
 */
ioal_uart_state io_hal_uart_get_state(ioal_uart_hdle *huart)
{
	ioal_uart_state uart_sts = IOAL_UART_STATE_MAX;
    huart->intf_gen_info.state = IO_BUSY_STATE;
    uart_sts = io_hal_common_uart_get_state(huart);
    huart->intf_gen_info.state = IO_FREE_STATE;
    return uart_sts;
}

/**
 * @brief UART call back api
 */
void io_hal_uart_tx_cmplt_cb(ioal_uart_hdle *huart)
{
    huart->intf_gen_info.state = IO_FREE_STATE;
    if(huart->app_callbacks.uart_tx_cplt_cb != NULL){
    huart->app_callbacks.uart_tx_cplt_cb(huart);
    }
}
void io_hal_uart_rx_cmplt_cb(ioal_uart_hdle *huart)
{
    huart->intf_gen_info.state = IO_FREE_STATE;
    if(huart->app_callbacks.uart_rx_cplt_cb != NULL){
    huart->app_callbacks.uart_rx_cplt_cb(huart);
    }
}
void io_hal_uart_abort_cmplt_cb(ioal_uart_hdle *huart)
{
    huart->intf_gen_info.state = IO_FREE_STATE;
    huart->app_callbacks.uart_abort_cplt_cb(huart);
}
void io_hal_uart_abort_tx_cmplt_cb(ioal_uart_hdle *huart)
{
    huart->intf_gen_info.state = IO_FREE_STATE;
    huart->app_callbacks.uart_abort_tx_cplt_cb(huart);
}
void io_hal_uart_abort_rx_cmplt_cb(ioal_uart_hdle *huart)
{
    huart->intf_gen_info.state = IO_FREE_STATE;
    huart->app_callbacks.uart_abort_rx_cplt_cb(huart);
}
void io_hal_uart_error_cb(ioal_uart_hdle *huart)
{
    huart->intf_gen_info.state = IO_FREE_STATE;
   if( huart->app_callbacks.uart_error_cb !=NULL)
   {
	   huart->app_callbacks.uart_error_cb(huart);
   }
}

