// +FHDR------------------------------------------------------------
//                 Copyright (c) 2022 SmartLogic.
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : msg_transfer_layer.c
// Author        : xianfeng.du
// Created On    : 2022-06-29
// Last Modified :
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------

#include <stddef.h>
#include <string.h>
#include "mem_sections.h"
#include "ucp_printf.h"
#include "pet_sm_mgt.h"
#include "msg_transfer_mem.h"
#include "msg_transfer_mbuffer.h"

static inline int8_t get_queue_id(uint16_t type_id, uint16_t cu_flag)
{
    int8_t que_id = -1;

    switch (type_id)
    {
        case CU_SPLIT:
            if (cu_flag == U_PLANE) {
                que_id = UCP4008_TRAFFIC_NR_eMBB_DATA;
            } else {
                que_id = UCP4008_TRAFFIC_NR_eMBB_CTRL;
            }
            break;
        case OAM:
            que_id = UCP4008_TRAFFIC_OAM;
            break;
        default:
            UCP_PRINT_ERROR("get_queue_id doesn't support transfer_type[%d] .",type_id);
            break;
    }

    return que_id;
}

static inline void get_queue_info(uint16_t inst_id, uint16_t que_id, uint32_t handle_id, queue_info_s* queue_info)
{
    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueCfg_t* pLocalQueueCfg = (MsgQueueCfg_t *)&pMsgQueueLocalMgt->localQueueCfg[inst_id][que_id];

    PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
    MsgQueueCfg_t* pCommonQueueCfg = pPetSmLocalMgt->pQueueCfg[inst_id][que_id];

    pLocalQueueCfg->handler.value = handle_id;
    pLocalQueueCfg->tx_queue.block_num = queue_info->tx_block_num;
    pLocalQueueCfg->tx_queue.block_size = queue_info->tx_block_size;
    pLocalQueueCfg->rx_queue.block_num = queue_info->rx_block_num;
    pLocalQueueCfg->rx_queue.block_size = queue_info->rx_block_size;
    pLocalQueueCfg->rx_queue.rx_callback = queue_info->rx_callback;
    memcpy((void *)&pCommonQueueCfg->handler, (void *)&pLocalQueueCfg->handler, sizeof(HandleId_t));
    memcpy((void *)&pCommonQueueCfg->tx_queue, (void *)&pLocalQueueCfg->rx_queue, sizeof(QueueCfg_t));
    memcpy((void *)&pCommonQueueCfg->rx_queue, (void *)&pLocalQueueCfg->tx_queue, sizeof(QueueCfg_t));

    msg_transfer_queue_setup(inst_id, que_id);

    return;
}

int32_t msg_transfer_init(uint16_t port_index, uint16_t transfer_type, uint16_t inst_id, const transfer_type_info_s* transfer_type_info)
{
    if (port_index >= MAX_PORT_NUM)
    {
        UCP_PRINT_ERROR("msg_transfer_init port_index[%d] error.",port_index);
        return FAILURE;
    }

    if (transfer_type > OAM)
    {
        UCP_PRINT_ERROR("msg_transfer_init transfer_type[%d] error.",transfer_type);
        return FAILURE;
    }

    if (inst_id >= MAX_INSTANCE_NUM)
    {
        UCP_PRINT_ERROR("msg_transfer_init inst_id[%d] error.",inst_id);
        return FAILURE;
    }

    uint16_t que_id;
    HandleId_t handler;

    handler.port_id = (uint8_t)port_index;
    handler.inst_id = (uint8_t)inst_id;
    handler.type_id = (uint8_t)transfer_type;

    switch (transfer_type)
    {
        case CU_SPLIT:
            que_id = UCP4008_TRAFFIC_NR_eMBB_DATA;
            get_queue_info(inst_id, que_id, handler.value, (queue_info_s *)&transfer_type_info->queue_uplane_info);

            que_id = UCP4008_TRAFFIC_NR_eMBB_CTRL;
            get_queue_info(inst_id, que_id, handler.value, (queue_info_s *)&transfer_type_info->queue_cplane_info);
            break;
        case OAM:
            que_id = UCP4008_TRAFFIC_OAM;
            get_queue_info(inst_id, que_id, handler.value, (queue_info_s *)&transfer_type_info->queue_cplane_info);
            break;
        default:
            UCP_PRINT_ERROR("msg_transfer_init doesn't support transfer_type[%d] .",transfer_type);
            //break;
        return FAILURE;
    }

    return (int32_t)handler.value;
}

int32_t msg_transfer_send_start(int32_t handle_id, uint16_t cu_flag)
{
    HandleId_t handler;
    handler.value= (uint32_t)handle_id;
    //uint8_t port_id = handler.port_id;
    uint8_t inst_id = handler.inst_id;
    uint8_t type_id = handler.type_id;

    int8_t que_id = get_queue_id(type_id, cu_flag);
    if (que_id < 0)
    {
        UCP_PRINT_ERROR("msg_transfer_send_start,UNINITIALIZED_QUEUE");
        return UNINITIALIZED_QUEUE;
    }
	msg_queue_dl_block_init(inst_id,que_id);

    return SUCCESS;
}


int32_t msg_transfer_alloc_msg(int32_t handle_id, uint16_t cu_flag, uint32_t bufSize, char** buf,  uint32_t* availableSize, uint32_t* offset)
{
    HandleId_t handler;
    handler.value= (uint32_t)handle_id;
    //uint8_t port_id = handler.port_id;
    uint8_t inst_id = handler.inst_id;
    uint8_t type_id = handler.type_id;
    int8_t que_id = get_queue_id(type_id, cu_flag);

    if (que_id < 0)
    {
        *(uint64_t *)buf = 0;
        *availableSize = 0;
        *offset = 0;
        UCP_PRINT_ERROR("msg_transfer_alloc_msg,UNINITIALIZED_QUEUE");
        return UNINITIALIZED_QUEUE;
    }

    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueLocalInfo_t* ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localDlQueue[inst_id][que_id];

    if (0 == ch->msgCnt)
    {
        msg_queue_dl_alloc_buf(inst_id,que_id);
    }
    *(uint64_t *)buf = ch->bufAddr + ch->offset;
    *availableSize = ch->availableSize;
    *offset = ch->offset;
    ch->msgCnt++;

    UCP_PRINT_LOG("msg_transfer_alloc_msg,buf:0x%lx,availableSize:0x%08x,offset:0x%08x", *(uint64_t *)buf, ch->availableSize, ch->offset);

    return SUCCESS;
}

int32_t msg_transfer_send_msg(int32_t handle_id, uint16_t cu_flag, uint8_t* msg_ptr, uint32_t offset, uint32_t msg_len)
{
    HandleId_t handler;
    handler.value= (uint32_t)handle_id;
    //uint8_t port_id = handler.port_id;
    uint8_t inst_id = handler.inst_id;
    uint8_t type_id = handler.type_id;
    int8_t que_id = get_queue_id(type_id, cu_flag);
    if (que_id < 0) {
        UCP_PRINT_ERROR("msg_transfer_alloc_msg,UNINITIALIZED_QUEUE");
        return UNINITIALIZED_QUEUE;
    }

    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueLocalInfo_t* ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localDlQueue[inst_id][que_id];
    ch->availableSize -= msg_len;
    ch->offset += msg_len;

    UCP_PRINT_LOG("msg_transfer_send_msg,buf:0x%lx,availableSize:0x%08x,offset:0x%08x", (ch->bufAddr+ch->offset), ch->availableSize, ch->offset);

    return SUCCESS;
}

int32_t msg_transfer_send_end(int32_t handle_id, uint16_t cu_flag)
{
    HandleId_t handler;
    handler.value= (uint32_t)handle_id;
    //uint8_t port_id = handler.port_id;	
    uint8_t inst_id = handler.inst_id;
    uint8_t type_id = handler.type_id;
	
    int8_t que_id = get_queue_id(type_id, cu_flag);
    if (que_id < 0)
    {
        UCP_PRINT_ERROR("msg_transfer_send_end,UNINITIALIZED_QUEUE");
        return UNINITIALIZED_QUEUE;
    }
	msg_queue_dl_put_buf(inst_id,que_id);

    return SUCCESS;
}

int32_t msg_transfer_receive(int32_t handle_id, uint16_t cu_flag, uint32_t offset, uint32_t len, uint8_t** msg_ptr)
{
    uint32_t handledLength = 0;
    int32_t remainedLength = 0;
    uint8_t *buf, *temp;
    MsgMemBufAttr_t* mbuf;

    HandleId_t handler;
    handler.value= (uint32_t)handle_id;
    //uint8_t port_id = handler.port_id;
    uint8_t inst_id = handler.inst_id;
    uint8_t type_id = handler.type_id;
    int8_t que_id = get_queue_id(type_id, cu_flag);
    if (que_id < 0)
    {
        return UNINITIALIZED_QUEUE;
    }

    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueCfg_t* pQueueCfg = (MsgQueueCfg_t *)&pMsgQueueLocalMgt->localQueueCfg[inst_id][que_id];

    buf = msg_queue_ul_get_buf(inst_id,que_id);
    if (buf == NULL)
    {
        return EMPTY_QUEUE;
    }

    //*msg_ptr = buf;
    mbuf = MSG_MBUF_ATTR(buf);
    remainedLength = mbuf->msgSize;
    temp = buf;
    do
    {
        handledLength = pQueueCfg->rx_queue.rx_callback((char *)temp, remainedLength);
        remainedLength -= handledLength;
        temp += handledLength;
    } while(remainedLength > 0);

    return SUCCESS;
}

int32_t msg_transfer_close(int32_t handle_id)
{
    HandleId_t handler;
    handler.value= (uint32_t)handle_id;
    //uint8_t port_id = handler.port_id;
    uint8_t inst_id = handler.inst_id;
    uint8_t type_id = handler.type_id;

    if (type_id == CU_SPLIT)
    {
        msg_transfer_queue_free(inst_id, UCP4008_TRAFFIC_NR_eMBB_DATA);
        msg_transfer_queue_free(inst_id, UCP4008_TRAFFIC_NR_eMBB_CTRL);
    }
    else
    {
        msg_transfer_queue_free(inst_id, UCP4008_TRAFFIC_OAM);
    }

    return SUCCESS;
}

