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

#include "log_server.h"
#include "spu_hw_queue.h"
#include "ape_csu.h"
#include "ucp_port.h"
#include "ucp_utility.h"
#include "ucp_printf.h"

SpuLogServerInfo_t gLogServerInfo;

static inline SpuLogServerInfo_t* get_log_server_info(void)
{
    return (SpuLogServerInfo_t *)&gLogServerInfo;
}

void spu_log_server_init(void)
{
    //int32_t core_id = get_core_id();
    uint32_t u8core_num = 0;
    SpuLogServerInfo_t* pLogServerInfo = get_log_server_info();

    pLogServerInfo->isrFlag = 0;
    pLogServerInfo->pingpong = 0;
    pLogServerInfo->serverBufSize = SPU_LOG_CLIENT_BUF_SIZE;
    pLogServerInfo->clientBufSize = SPU_LOG_CLIENT_BUF_SIZE;
    for (u8core_num = 0; u8core_num < MAX_NUM_SPU; u8core_num++)
    {
        pLogServerInfo->clientBufBase[u8core_num] = SPU_LOG_CLIENT_BUF_BASE + (u8core_num * SPU_LOG_CLIENT_BUF_DEPTH * SPU_LOG_CLIENT_BUF_SIZE);
    }

    uint32_t i,j;
    for (i=0; i<MAX_INSTANCE_NUM; i++) {
        for (j=0; j<SPU_LOG_SERVER_RING_SIZE; j++) {
            pLogServerInfo->idx[i][j] = 0;
            pLogServerInfo->serverBufBase[i][j] = SPU_LOG_SERVER_BUF_BASE + (j*SPU_LOG_SERVER_BUF_SIZE*SPU_LOG_SERVER_BUF_DEPTH) + \
                                                    (i*SPU_LOG_SERVER_RING_SIZE*SPU_LOG_SERVER_BUF_SIZE*SPU_LOG_SERVER_BUF_DEPTH);
        }
    }
    return;
}

static inline void spu_log_server_receive(void)
{
    SpuLogMsgInfo_t context;
    uint32_t   u32value = 0;
    //int32_t rev = ecs_hw_que_recv(ECS_RFM_SPU1_HW_QUEUE, &context.value);
    int32_t rev = ecs_hw_que_recv(ECS_RFM_SPU1_HW_QUEUE, &u32value);
    if (SUCCESS != rev) {
        return;
    }
    context.value = u32value;

    SpuLogServerInfo_t* pLogServerInfo = get_log_server_info();
    uint8_t  cell_id = context.cell_id;
    uint8_t  core_id = context.core_id;
    uint16_t buf_idx = context.buf_idx;
    uint16_t size = context.buf_size;
    uint32_t pingpong = pLogServerInfo->pingpong;
    uint32_t src_addr = pLogServerInfo->clientBufBase[core_id] + (buf_idx * pLogServerInfo->clientBufSize);
    //uint32_t dst_idx = pLogServerInfo->idx[cell_id][pingpong] & (SPU_LOG_SERVER_BUF_DEPTH-1);
    uint32_t dst_idx = pLogServerInfo->idx[cell_id][pingpong];
    if ((SPU_LOG_SERVER_BUF_DEPTH-1) <= dst_idx) {
        return;
    }
    uint32_t dst_addr = pLogServerInfo->serverBufBase[cell_id][pingpong] + \
                        (dst_idx * pLogServerInfo->serverBufSize);
    memcpy_ucp(dst_addr, src_addr, size);
    pLogServerInfo->idx[cell_id][pingpong]++;

    return;
}

static inline uint32_t spu_log_fill_msg_header(uint8_t inst_id, char* buf, uint32_t size)
{
    MsgTransferHeader_t header;
    header.numMsg = 1;
    header.cellIndex = inst_id;
    header.msgType = MSG_TRANSFER_LOG_MSG_TYPE;
    header.msgLen = size + sizeof(uint32_t);
    header.log_size = size;
    memcpy_ucp(buf, &header, sizeof(MsgTransferHeader_t));

    uint32_t dst_addr = (uint32_t)(buf + sizeof(MsgTransferHeader_t));
    return dst_addr;
}

static inline int32_t spu_log_send_msg(uint8_t inst_id, uint32_t src_addr, uint32_t size)
{
    if (0 == size) {
        return SUCCESS;
    }
    uint32_t len = size+sizeof(MsgTransferHeader_t);

    char* buf;
    uint32_t availableSize,offset;

    uint16_t cu_flag = C_PLANE;
    HandleId_t handler;
    handler.port_id = get_ucp_port_id();
    handler.inst_id = inst_id;
    handler.type_id = OAM;
    int32_t ret = msg_transfer_send_start(handler.value);
    ret = msg_transfer_alloc_msg(handler.value, cu_flag, len, &buf, &availableSize, &offset);
    if (SUCCESS != ret)
    {
        UCP_PRINT_ERROR("spu_log_send_msg ret[0x%08x]", ret);
        return ret;
    }

    uint32_t dst_addr = spu_log_fill_msg_header(inst_id, buf, size);
    /*if (0 == inst_id) {
        ape_csu_dma_1D_G2L_ch0ch1_transfer(src_addr, dst_addr, size, inst_id, 0);
    } else {
        ape_csu_dma_1D_G2L_ch2ch3_transfer(src_addr, dst_addr, size, inst_id, 0);
    }*/
    ape_csu_dma_1D_G2L_ch2ch3_transfer(src_addr, dst_addr, size, inst_id, 1);
    //spu_csu_dma_1D_transfer(src_addr, dst_addr, size);

    ret = msg_transfer_send_msg(handler.value, cu_flag, (uint8_t *)buf, offset, size);
    ret = msg_transfer_send_end(handler.value);

    return ret;
}

static inline void spu_log_server_send(void)
{
    SpuLogServerInfo_t* pLogServerInfo = get_log_server_info();
    if (1 == pLogServerInfo->isrFlag)
    {
        pLogServerInfo->isrFlag = 0;
        uint16_t pingpong = pLogServerInfo->pingpong;

        uint32_t src_addr,size;
        for (uint32_t cell_id=0; cell_id<MAX_INSTANCE_NUM; cell_id++)
        {
            src_addr = pLogServerInfo->serverBufBase[cell_id][pingpong];
            size = pLogServerInfo->idx[cell_id][pingpong] * pLogServerInfo->serverBufSize;
            spu_log_send_msg(cell_id, src_addr, size);
        }

        pLogServerInfo->pingpong = 1 - pLogServerInfo->pingpong;
        for (uint32_t cell_id=0; cell_id<MAX_INSTANCE_NUM; cell_id++)
        {
            pLogServerInfo->idx[cell_id][pLogServerInfo->pingpong] = 0;
        }
    }

    return;
}

void spu_log_server_proc(void)
{
    spu_log_server_receive();
    spu_log_server_send();
    return;
}

void spu_log_server_isr(void)
{
    SpuLogServerInfo_t* pLogServerInfo = get_log_server_info();
    pLogServerInfo->isrFlag = 1;
#if 0
    pLogServerInfo->pingpong = 1 - pLogServerInfo->pingpong;
    for (uint32_t cell_id=0; cell_id<MAX_INSTANCE_NUM; cell_id++)
    {
        pLogServerInfo->idx[cell_id][pLogServerInfo->pingpong] = 0;
    }
#endif

    return;
}


