// +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 "mem_sections.h"
#include "ucp_tick.h"
#include "ucp_port.h"
#include "ucp_printf.h"
#include "ucp_utility.h"
#include "pet_sm_mgt.h"
#include "msg_transfer_mem.h"
#include "msg_transfer_mbuffer.h"
#include "spu_hw_queue.h"

#define SINGLE_MSG_TX

static ALWAYS_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;
}

int32_t msg_transfer_callback_register(uint16_t transfer_type, uint16_t inst_id, uint16_t cu_flag, msg_transfer_callback rx_callback)
{
    int8_t que_id = get_queue_id(transfer_type, cu_flag);
    if (que_id < 0) {
        return FAILURE;
    }

    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    pMsgQueueLocalMgt->localQueueCfg[inst_id][que_id].rx_queue.rx_callback = rx_callback;

    PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
    MsgQueueCfg_t* pCommonQueueCfg = pPetSmLocalMgt->pQueueCfg[inst_id][que_id];
    do_write(&pCommonQueueCfg->rx_queue.rx_callback,rx_callback);

    HandleId_t handler;
    handler.port_id = get_ucp_port_id();
    handler.inst_id = inst_id;
    handler.type_id = transfer_type;
    handler.rsv = 0;

    return (int32_t)handler.value;
}

int32_t msg_transfer_send_start(int32_t handle_id)
{
#ifdef UCP_TICK_ENABLE
	uint32_t clockBegin,clockEnd;
	int32_t  clockCnt;
	rdmcycle(&clockBegin);
#endif

#ifndef SINGLE_MSG_TX
	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_queue_ul_block_init(inst_id,UCP4008_TRAFFIC_NR_eMBB_DATA);
		msg_queue_ul_block_init(inst_id,UCP4008_TRAFFIC_NR_eMBB_CTRL);
	} else {
		msg_queue_ul_block_init(inst_id,UCP4008_TRAFFIC_OAM);
	}
#endif

#ifdef UCP_TICK_ENABLE
	rdmcycle(&clockEnd);
	clockCnt = clockEnd - clockBegin;
	debug_write(DBG_DDR_MSG_IDX(type_id,6),clockCnt);
	UCP_PRINT_TICK("msg_transfer_send_start,cycle:[0x%08x]",clockCnt);
#endif

	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)
{
#ifdef UCP_TICK_ENABLE
	uint32_t clockBegin,clockEnd;
	int32_t  clockCnt;
	rdmcycle(&clockBegin);
#endif

	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) {
		*(uint32_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->localUlQueue[inst_id][que_id];
	uint8_t* msg_buf;
	uint16_t buf_id;

#ifndef SINGLE_MSG_TX
	if (bufSize > ch->availableSize) {
		UCP_PRINT_ERROR("msg_transfer_alloc_msg,OUT_OF_BLOCK_MEMORY");
		return OUT_OF_BLOCK_MEMORY;
	}

	if (0 == ch->msgCnt) {
		msg_buf = msg_queue_ul_alloc_buf(inst_id,que_id,&buf_id);
		ch->idx = buf_id;
		ch->bufAddr = (uint32_t)msg_buf;
	}
	ch->msgCnt++;
	*offset = ch->offset;
	*availableSize = ch->availableSize;
	*(uint32_t *)buf = ch->bufAddr + ch->offset;
	UCP_PRINT_LOG("msg_transfer_alloc_msg,buf:0x%08x,availableSize:0x%08x,offset:0x%08x", *(uint32_t *)buf, ch->availableSize, ch->offset);
#else
	int32_t availableLength = ch->bufSize - MSG_MBUF_HEAD_SIZE;
	if(0 >= availableLength) {
		return UNINITIALIZED_QUEUE;
	}

	*availableSize = availableLength;
	if (bufSize > availableLength) {
		UCP_PRINT_ERROR("msg_transfer_alloc_msg,OUT_OF_BLOCK_MEMORY");
		return OUT_OF_BLOCK_MEMORY;
	}

	msg_buf = msg_queue_ul_alloc_buf(inst_id,que_id,&buf_id);
	if(NULL == msg_buf){
		return UNINITIALIZED_QUEUE;
	}
	*(uint32_t *)buf = (uint32_t)msg_buf;
	*offset = buf_id;//redefine offset to buf_id
#endif

#ifdef UCP_TICK_ENABLE
	rdmcycle(&clockEnd);
	clockCnt = clockEnd - clockBegin;
	debug_write(DBG_DDR_MSG_IDX(type_id,7),clockCnt);
	UCP_PRINT_TICK("msg_transfer_send_start,cycle:[0x%08x]",clockCnt);
#endif
	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)
{
#ifdef UCP_TICK_ENABLE
	uint32_t clockBegin,clockEnd;
	int32_t  clockCnt;
	rdmcycle(&clockBegin);
#endif

	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->localUlQueue[inst_id][que_id];
#ifndef SINGLE_MSG_TX
	ch->availableSize -= msg_len;
	ch->offset += msg_len;
	UCP_PRINT_LOG("msg_transfer_send_msg,buf:0x%08x,availableSize:0x%08x,offset:0x%08x", (ch->bufAddr+ch->offset), ch->availableSize, ch->offset);
	int32_t ret = SUCCESS;
#else
	uint16_t idx = (uint16_t)offset;//redefine offset to buf_id
    MsgMemBufAttr_t *mbuf = (MsgMemBufAttr_t *)get_mbuf_ptr(ch->bufBase, ch->bufSize, idx);
    do_write(&mbuf->msgSize, msg_len);
	__ucps2_synch(0);
	
    uint32_t value = (inst_id << 24) + (que_id << 16) + idx;
    int32_t ret = ecs_hw_que_send(ECS_RFM_SPU0_HW_QUEUE, value);
#endif

#ifdef UCP_TICK_ENABLE
	rdmcycle(&clockEnd);
	clockCnt = clockEnd - clockBegin;
	debug_write(DBG_DDR_MSG_IDX(type_id,8),clockCnt);
	UCP_PRINT_TICK("msg_transfer_send_start,cycle:[0x%08x]",clockCnt);
#endif

	return ret;
}

int32_t msg_transfer_send_end(int32_t handle_id)
{
#ifdef UCP_TICK_ENABLE
	uint32_t clockBegin,clockEnd;
	int32_t  clockCnt;
	rdmcycle(&clockBegin);
#endif

#ifndef SINGLE_MSG_TX
	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_queue_ul_put_buf(inst_id,UCP4008_TRAFFIC_NR_eMBB_DATA);
		msg_queue_ul_put_buf(inst_id,UCP4008_TRAFFIC_NR_eMBB_CTRL);
	} else {
		msg_queue_ul_put_buf(inst_id,UCP4008_TRAFFIC_OAM);
	}
#endif

#ifdef UCP_TICK_ENABLE
	rdmcycle(&clockEnd);
	clockCnt = clockEnd - clockBegin;
	debug_write(DBG_DDR_MSG_IDX(type_id,9),clockCnt);
	UCP_PRINT_TICK("msg_transfer_end,cycle:[0x%08x]",clockCnt);
#endif

	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)
{
#ifdef UCP_TICK_ENABLE
	uint32_t clockBegin,clockEnd;
	int32_t  clockCnt;
	rdmcycle(&clockBegin);
#endif

	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 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_dl_get_buf(inst_id,que_id);
	if (buf == NULL) {
		return EMPTY_QUEUE;
	}

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

#ifdef UCP_TICK_ENABLE
	rdmcycle(&clockEnd);
	clockCnt = clockEnd - clockBegin;
	debug_write(DBG_DDR_MSG_IDX(type_id,10),clockCnt);
	UCP_PRINT_TICK("msg_transfer_end,cycle:[0x%08x]",clockCnt);
#endif

	return SUCCESS;
}

int32_t msg_transfer_close(int32_t handle_id)
{
	return SUCCESS;
}




