/******************************************************************************/
/* Component Name   ICU-M Interface Library (ICUMIF)                          */
/******************************************************************************/
/* Product      : ICU-M Firmware                                              */
/******************************************************************************/
/*******************************************************************************
* Copyright(C) 2021-2023 Renesas Electronics Corporation.                       
*                                                                               
*          RENESAS ELECTRONICS CONFIDENTIAL AND PROPRIETARY                     
*                                                                               
* These instructions, statements, and programs are the confidential information 
* of Renesas Electronics Corporation. They must be used and modified solely for 
* the purpose for which it was furnished by Renesas Electronics Corporation.    
* All part of them must not be reproduced nor disclosed to others in any form,  
* without the prior written permission of Renesas Electronics Corporation.      
*******************************************************************************/

/**************************************************************************************/
/* Header files                                                                       */
/**************************************************************************************/
#include "r_icumif_api.h"
#include "r_icumif_pub.h"
#include "icum_d_comm_pe_pub.h"

#include "r_icumif.h"

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0001]:[ICUMFW_UD_L_IF_0001]
* Function name: R_ICUMIF_Init
* Description  : Initialize the ICU-M interface library
* Arguments    : uint32_t       *p_request_queue : Pointer to service request queue
* Return Value : int32_t Library initialization result
*                   0               : Successful
*                   Negative values : Parameter error
***************************************************************************************/
int32_t R_ICUMIF_Init(uint32_t *p_request_queue)
{
    int32_t     ret_val = R_ICUMIF_ER_OK;
    uint32_t    call_comm_ret;

    /* 1. address check using Cluster RAM area check function */
    call_comm_ret = D_COMM_PE_CheckMemorySharedRAM((uint32_t)((uintptr_t)p_request_queue), (uint32_t)sizeof(uint32_t) * (uint32_t)TOTAL_QUEUE_LENGTH);
    if (ER_OK == call_comm_ret)
    {
        /* 2. Parameter alignment check */
        if (0U != ((uint32_t)((uintptr_t)p_request_queue) & ALIGNMENT_4BYTE_CHECK_PATTERN))
        {
            ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
        }
        else
        {
            /* 3. Execute COMM(PE) driver initialization to initialize service queue */
            call_comm_ret = D_COMM_PE_Init(p_request_queue);

            /* 4. According to result of COMM (PE) driver initialization process, */
            /*    execute respective corresponding processes                      */
            if (ER_D_COMM_PARAM_NOT_G_RAM == call_comm_ret)
            {
                /* 4-1. Parameters other than shared RAM area, process is terminated */
                ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
            }
            else if (ER_D_COMM_QUE_NOT_ACCESS == call_comm_ret)
            {
                /* 4-2. */
                ret_val = R_ICUMIF_ER_SOFTWARE_ERROR;
            }
            else
            {
                /* 5. Execute interrupt enable process to enable interrupts from ICUP */
                D_COMM_SetInterruptEnable();
            }
        }
    }
    else if (ER_D_COMM_ALIGN_NG == call_comm_ret)
    {
        ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
    }
    else
    {
        /* 6. */
        ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
    }

    /* 7. */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0002]:[ICUMFW_UD_L_IF_0002]
* Function name: R_ICUMIF_ServiceRequest
* Description  : Requests ICU-M to execute the service
* Arguments    : r_icumif_isd_t *p_ISD : Pointer to ISD where request parameter is set
* Return Value : int32_t Service execution request result
*                   0               : Successful
*                   Negative values : Parameter error, Interface library uninitialized
***************************************************************************************/
int32_t R_ICUMIF_ServiceRequest(r_icumif_isd_t *p_ISD)
{
    int32_t     ret_val = R_ICUMIF_ER_OK;
    uint32_t    call_comm_ret;

    /* 1. address check using Cluster RAM area check function */
    call_comm_ret = D_COMM_PE_CheckMemorySharedRAM((uint32_t)((uintptr_t)p_ISD), (uint32_t)sizeof(r_icumif_isd_t));
    if (ER_OK == call_comm_ret)
    {
        /* 2. Parameter alignment check */
        if (0U != ((uint32_t)((uintptr_t)p_ISD) & ALIGNMENT_4BYTE_CHECK_PATTERN))
        {
            ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
        }
        else
        {
            /* 3-1. Set ID of service request PE */
            p_ISD->requester_id = (r_icumif_requester_id_t)GET_MY_PEID;

            /* 3-2. Set channel of service execution response interrupt */
            p_ISD->host_int_ch = ICUM_COMM_ICH_FM_SERV_RESPONSE;

            /* 3-3. Set initial state to service processing state */
            p_ISD->service_result = SERV_NEW_REQUEST;

            /* 4. In order to check whether area indicated by p_ISD exists in RAM, */
            /*    it checks whether service processing state is SERV_NEW_REQUEST   */
            if (SERV_NEW_REQUEST != p_ISD->service_result)
            {
                /* Not SERV_NEW_REQUEST, process is terminated */
                ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
            }
            else
            {
                /* 5. Execute interrupt issue process to issue service execution req interrupt */
                call_comm_ret = D_COMM_TriggerInterruptToICUP(ICUM_COMM_ICH_TO_SERV_REQUEST, p_ISD);

                /* 6. According to result of interrupt issue process, */
                /*    execute respective corresponding processes      */
                switch (call_comm_ret)
                {
                    case ER_OK:
                        /* 6-1. Do nothing */
                        break;
                    case ER_D_COMM_QUE_FULL:
                        /* 6-2. */
                        p_ISD->req_res_status = R_ICUMIF_REQRES_PE_RES_DEQUE;
                        p_ISD->service_result = SERV_REQUEST_QUEUE_FULL;
                        ret_val = R_ICUMIF_ER_REQ_QUEUE_FULL;
                        break;
                    case ER_D_COMM_QUE_NOT_INIT:
                        /* 6-3. */
                        ret_val = R_ICUMIF_ER_IF_LIB_NOT_INIT;
                        break;
                    case ER_PARAM:
                    case ER_D_COMM_QUE_NOT_ACCESS:
                    default:
                        /* 6-4. */
                        ret_val = R_ICUMIF_ER_SOFTWARE_ERROR;
                        break;
                }
            }
        }
    }
    else if (ER_D_COMM_ALIGN_NG == call_comm_ret)
    {
        ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
    }
    else
    {
        /* 7. */
        ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
    }

    /* 8. */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0003]:[ICUMFW_UD_L_IF_0003]
* Function name: R_ICUMIF_ServiceResponse
* Description  : Acquires ISD from service response queue for self PE
* Arguments    : None
* Return Value : int32_t Service response reception process result
*                   0               : Successful
*                   Negative values : Interface library uninitialized
***************************************************************************************/
int32_t R_ICUMIF_ServiceResponse(void)
{
    int32_t         ret_val = R_ICUMIF_ER_OK;
    uint32_t        call_comm_ret;
    uint32_t        call_comm_ret_isd;
    uint32_t        exist_isd = 1U;
    r_icumif_isd_t  *p_isd;

    /* Repeat process until there is no ISD in service response queue for self PE */
    while (1U == exist_isd)
    {
        /* 1. Acquires ISD from service response queue for self PE */
        call_comm_ret = D_COMM_GetResponseISD(&p_isd);

        /* 2. According to result of acquires ISD,       */
        /*    execute respective corresponding processes */
        switch (call_comm_ret)
        {
            case ER_OK:
            case ER_D_COMM_EXIST_ISD:
                /* 3-1. address check using Cluster RAM area check function */
                call_comm_ret_isd = D_COMM_PE_CheckMemorySharedRAM((uint32_t)((uintptr_t)p_isd), (uint32_t)sizeof(r_icumif_isd_t));
                if (ER_OK == call_comm_ret_isd)
                {
                    /* 3-1-1. For detect that ICU-M could not update ISD,          */
                    /*          check value of service process state in acquired ISD */
                    if (SERV_NEW_REQUEST == p_isd->service_result)
                    {
                        /* 3-1-1-1. ICU-M could not update ISD */
                        p_isd->service_result = SERV_ISD_NOT_ACCESSIBLE;
                    }
                    else
                    {
                        /* 3-1-1-2. */
                        /* do nothing */
                    }

                    /* 3-1-2. */
                    if (NULL != p_isd->ptr.p_callbackfunc)
                    {
                        /* 3-1-2-1. If there is registration of callback function, */
                        /*            calling callback function                      */
                        p_isd->ptr.p_callbackfunc(p_isd);
                    }
                    else
                    {
                        /* 3-1-2-2. */
                        /* do nothing */
                    }
                    if (ER_OK == call_comm_ret)
                    {
                        exist_isd = 0U;
                    }
                    else
                    {
                        /* do nothing */
                    }
                }
                else if (ER_D_COMM_ALIGN_NG == call_comm_ret_isd)
                {
                    ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
                    exist_isd = 0U;
                }
                else
                {
                    ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
                    exist_isd = 0U;
                }
                break;
            case ER_D_COMM_NO_ISD:
                /* 3-2. No ISD in service response queue, exit from loop process */
                exist_isd = 0U;
                break;
            case ER_D_COMM_QUE_NOT_INIT:
                /* 3-3. Interface library not initialized */
                ret_val = R_ICUMIF_ER_IF_LIB_NOT_INIT;
                exist_isd = 0U;
                break;
            case ER_D_COMM_QUE_NOT_ACCESS:
            default:
                /* 3-4. Software error */
                ret_val = R_ICUMIF_ER_SOFTWARE_ERROR;
                exist_isd = 0U;
                break;
        }
    }

    /* 4. Return the service response reception process result */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0004]:[ICUMFW_UD_L_IF_0004]
* Function name: R_ICUMIF_IsServiceCompleted
* Description  : Check state of service execution requested to ICU-M
* Arguments    : r_icumif_isd_t *p_ISD : Pointer to ISD that service execution requested
* Return Value : int32_t Service execution state
*                   0            : Service running
*                   Other than 0 : Service execution completion
***************************************************************************************/
int32_t R_ICUMIF_IsServiceCompleted(r_icumif_isd_t *p_ISD)
{
    int32_t ret_val;
    uint8_t mem_check = ICUM_COMM_MEMCHECK_OK;
    uint32_t call_comm_ret;

    /* 1. address check using Cluster RAM area check function */
    call_comm_ret = D_COMM_PE_CheckMemorySharedRAM((uint32_t)((uintptr_t)p_ISD), (uint32_t)sizeof(r_icumif_isd_t));
    if (ER_OK == call_comm_ret)
    {
        /* 2. Parameter alignment check */
        if (0U != ((uint32_t)((uintptr_t)p_ISD) & ALIGNMENT_4BYTE_CHECK_PATTERN))
        {
            ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
        }
        else
        {
            if ((p_ISD->service_id == SERVICE_01_AES_CMAC) &&
                ((uint32_t)p_ISD->service_priority == R_ICUMIF_SERV_PRIORITY_HIGHEST))
            {
                /* Do nothing */
            }
            else
            {
                (void)D_COMM_GetICUMemCheckErrInfo(&mem_check);
            }

            if (ICUM_COMM_MEMCHECK_OK == (uint32_t)mem_check)
            {
                /* 3. Check service request / response queue transition state in ISD */
                ret_val = R_ICUMIF_RTN_SERV_RUNNING;

                /* 4. Service execution completion */
                switch ((uint32_t)p_ISD->req_res_status)
                {
                    case R_ICUMIF_REQRES_ICUM_RES_ENQUE:
                        if ((uint32_t)p_ISD->res_nointerrupt == R_ICUMIF_REQRES_NOINTERRPUT)
                        {
                            ret_val = R_ICUMIF_RTN_SERV_COMPLETION;
                        }
                        else
                        {
                            /* Do nothing */
                        }
                        break;
                    case R_ICUMIF_REQRES_PE_RES_DEQUE:
                        /* 4-1. Check value of service process state in ISD */
                        if (SERV_REQUEST > p_ISD->service_result)
                        {
                            /* 4-1-1. Service execution completion */
                            ret_val = R_ICUMIF_RTN_SERV_COMPLETION;
                        }
                        else
                        {
                            /* Do nothing */
                        }
                        break;
                    case R_ICUMIF_REQRES_PE_REQ_ENQUE:
                        if ((uint32_t)p_ISD->req_nointerrupt == R_ICUMIF_REQRES_NOINTERRPUT)
                        {
                            ret_val = R_ICUMIF_RTN_SERV_COMPLETION;
                        }
                        else
                        {
                            /* Do nothing */
                        }
                        break;
                    case R_ICUMIF_REQRES_ICUM_REQ_DEQUE:
                        /* 4-2. Service running */
                        /* Initial value */
                        break;
                    default:
                        /* 4-3. */
                        ret_val = R_ICUMIF_ER_SOFTWARE_ERROR;
                        break;
                }
            }
            else
            {
                ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
            }
        }
    }
    else if (ER_D_COMM_ALIGN_NG == call_comm_ret)
    {
        ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
    }
    else
    {
        /* 5. */
        ret_val = R_ICUMIF_ER_ADDR_NOT_G_RAM;
    }

    /* 6. */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0005]:[ICUMFW_UD_L_IF_0005]
* Function name: R_ICUMIF_GetStatus
* Description  : Acquire address value of status information of ICU-M Firmware
* Arguments    : None
* Return Value : r_icumif_sts_t * Address value of ICU-M Firmware status information
***************************************************************************************/
r_icumif_sts_t *R_ICUMIF_GetStatus(void)
{
    r_icumif_sts_t  *p_status;

    /* 1. Acquire address value of status information of ICU-M Firmware */
    p_status = D_COMM_GetICUStatusAddr();

    /* 2. */
    return (p_status);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0008]:[ICUMFW_UD_L_IF_0008]
* Function name: R_ICUMIF_SetSystemCallBackFunc
* Description  : Register the function to call back when receiving system interrupt
* Arguments    : R_ICUMIF_CB_REGIST_t *p_regist_info : Pointer to registration info
* Return Value : int32_t Callback registration result
*                   0               : Successful
*                   Negative values : Parameter error
***************************************************************************************/
int32_t R_ICUMIF_SetSystemCallBackFunc(R_ICUMIF_CB_REGIST_t *p_regist_info)
{
    int32_t             ret_val = R_ICUMIF_ER_OK;
    uint32_t            call_comm_ret;
    alignment_check_t   prm_ptr;

    /* 1. Parameter alignment check ( p_regist_info ) */
    if (0U != ((uint32_t)((uintptr_t)p_regist_info) & ALIGNMENT_4BYTE_CHECK_PATTERN))
    {
        ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
    }
    else
    {
        /* 2. Parameter alignment check ( callback function address ) */
        prm_ptr.p_align_check = p_regist_info->p_func_addr;
        if (0U != (prm_ptr.val_align_check & ALIGNMENT_2BYTE_CHECK_PATTERN))
        {
            ret_val = R_ICUMIF_ER_PARAM_ALIGNMENT;
        }
        else
        {
            /* 3. Register the function to call back */
            call_comm_ret = D_COMM_SetSystemCallBackFunc(p_regist_info);

            /* 4. According to result of callback function regist process, */
            /*    execute respective corresponding processes               */
            switch (call_comm_ret)
            {
                case ER_OK:
                    /* 4-1. Do nothing */
                    break;
                default:
                    /* 4-2. Software error */
                    ret_val = R_ICUMIF_ER_SOFTWARE_ERROR;
                    break;
            }
        }
    }

    /* 5. Return callback registration result */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_L_IF_0010]:[ICUMFW_UD_L_IF_0010]
* Function name: R_ICUMIF_IRQ_Handler
* Description  : Execute interrupt process of ICUP --> PE (INTICUP)
* Arguments    : None
* Return Value : None
***************************************************************************************/
void R_ICUMIF_IRQ_Handler(void)
{
    D_COMM_IRQ_Handler();
}
