#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "spu_log.h"
#include "spu_shell.h"

#define SPU_LOG_INNER_MAX_SIZE  (64)


/**************************************************/
/* 对内接口 */

#ifdef SPU_LOG_TEST_FLAG
typedef struct SPU_LOG_DBG_INFO
{
    uint32_t u32spu_log_output_cnt;
    uint32_t u32spu_log_output_level_low;
    uint32_t u32spu_log_output_oversize1;
    uint32_t u32spu_log_output_oversize2;
    uint32_t u32spu_log_output_send_err;
    uint32_t u32spu_log_output_send_ok;
    uint32_t u32spu_sendlog_par_err;
    uint32_t u32spu_sendlog_oversize;
    uint32_t u32spu_sendlog_send_err;
    uint32_t u32spu_sendlog_send_ok;
    uint32_t u32spu_sendlog_print_par_err;
    uint32_t u32spu_sendlog_print_oversize;
    uint32_t u32spu_sendlog_print_send_err;
    uint32_t u32spu_sendlog_print_send_ok;
}spu_log_dbg_info_t;

spu_log_dbg_info_t gstspu_log_dbg;
#endif

uint8_t  gu8osp_print_level = 0;

/* 平台Log打印级别初始化 */
void spu_log_init(uint8_t level)
{
    gu8osp_print_level = level;//LOG_ERROR; //LOG_DEBUG;
#ifdef SPU_LOG_TEST_FLAG
    memset(&gstspu_log_dbg, 0, sizeof(gstspu_log_dbg));
#endif

    return ;
}

/* 设置平台Log打印级别 */
uint8_t spu_log_level_set(spu_log_level_e emlog_level)
{
    if (LOG_TICK < emlog_level)
    {
        return 1;
    }
    
    gu8osp_print_level = emlog_level;

    UCP_PRINT_LOG("spu_log_level_set gu8osp_print_level %u", gu8osp_print_level);

    return 0;
}

/* 获取平台Log打印级别 */
uint8_t spu_log_level_get(void)
{
    UCP_PRINT_LOG("spu_log_level_get gu8osp_print_level %u", gu8osp_print_level);

    return gu8osp_print_level;
}

uint32_t spu_vsprint_log(char *dst, const char *fmt, ...)
{
    uint32_t u32str_len  = 0;
    va_list  st_va_list;
    va_start(st_va_list, fmt);
    u32str_len = vsprintf(dst, fmt, st_va_list);
    va_end(st_va_list);
    return u32str_len;
}

/* 平台打印输出函数 */
void spu_log_output(uint8_t level, const char *fmt, ...)
{
    int32_t  i32core_id = get_core_id();
    int32_t  i32ret = 0;
    uint32_t u32str_len  = 0;
    va_list  st_va_list;
    __LOG static int8_t i8str[SPU_LOG_INNER_MAX_SIZE*2]    = {0};
    uint8_t  u8offset = SPU_SW_MSG_INFO_SIZE;
    spu_sw_msg_info_t   stsw_msg_info;

    uint8_t *pu8_addr  = NULL;
    uint16_t u16_index = 0;
    SpuLogMsgInfo_t stlog_msg_info;

#ifdef UCP_TICK_ENABLE
    uint32_t u32clock_begin;
    uint32_t u32clock_end;
    int32_t  i32clock_cnt;
    rdmcycle(&u32clock_begin);
#endif

#ifdef SPU_LOG_TEST_FLAG
    ++gstspu_log_dbg.u32spu_log_output_cnt;
#endif

    if (level > gu8osp_print_level)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_log_output_level_low;
#endif
        return;
    }

    u32str_len = strlen(fmt);
    if(u32str_len > SPU_LOG_INNER_MAX_SIZE)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_log_output_oversize1;
#endif
        return;
    }

    va_start(st_va_list, fmt);
    u32str_len = vsprintf((char *)i8str, fmt, st_va_list);
    va_end(st_va_list);

    if (u32str_len > SPU_LOG_INNER_MAX_SIZE)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_log_output_oversize2;
#endif
        return ;
    }

    pu8_addr = spu_log_client_mem_alloc(&u16_index);
    memcpy_ucp((pu8_addr+u8offset), i8str, u32str_len);
    __ucps2_synch(0);

    stsw_msg_info.u8Head[0]  = SPU_SW_MSG_INFO_HEAD1;
    stsw_msg_info.u8Head[1]  = SPU_SW_MSG_INFO_HEAD2;
    stsw_msg_info.u16DataLen = u32str_len;
    stsw_msg_info.u8PktType  = PKT_TYPE_PLATFORM_LOG;
    stsw_msg_info.u8CoreId   = (uint8_t)i32core_id;
    stsw_msg_info.u16Tail    = 0;
    memcpy_ucp(pu8_addr, (void *)&stsw_msg_info, u8offset);
    __ucps2_synch(0);

    stlog_msg_info.cell_id = 0;
    stlog_msg_info.core_id = i32core_id;
    stlog_msg_info.buf_idx = u16_index;
    stlog_msg_info.buf_size = (u32str_len + u8offset);

    i32ret = ecs_hw_que_send(ECS_RFM_SPU1_HW_QUEUE, stlog_msg_info.value);
    if (0 != i32ret)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_log_output_send_err;
#endif
    }
    else
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_log_output_send_ok;
#endif
    }

#ifdef SPU_LOG_TEST_FLAG
    debug_write(DBG_DDR_COMMON_IDX(i32core_id, 80), gstspu_log_dbg.u32spu_log_output_send_ok);
    //debug_write(DBG_DDR_COMMON_IDX(i32core_id, 81), gstspu_log_dbg.u32spu_log_output_cnt);
    //debug_write(DBG_DDR_COMMON_IDX(i32core_id, 82), gstspu_log_dbg.u32spu_log_output_level_low);
    //debug_write(DBG_DDR_COMMON_IDX(i32core_id, 83), gstspu_log_dbg.u32spu_log_output_oversize2);
    //debug_write(DBG_DDR_COMMON_IDX(i32core_id, 84), gstspu_log_dbg.u32spu_log_output_send_err);
#endif
#ifdef UCP_TICK_ENABLE
    rdmcycle(&u32clock_end);
    i32clock_cnt = u32clock_end - u32clock_begin;
    debug_write(DBG_DDR_MSG_IDX(i32core_id, 101), i32clock_cnt);
#endif

    return;
}

/**************************************************/
/* 对外接口 */
/* 对外调试信息输出接口(字符串) */
void osp_sendLog(int level, char* pbuf, int size, int cell_id)
{
    spu_sw_msg_info_t stsw_msg_info;
    SpuLogMsgInfo_t   stlog_msg_info;
    int32_t  i32core_id = get_core_id();
    int32_t  i32ret = 0;
    uint8_t  u8offset = SPU_SW_MSG_INFO_SIZE;
    uint8_t *pu8_addr  = NULL;
    uint16_t u16_index = 0;

#ifdef UCP_TICK_ENABLE
    uint32_t u32clock_begin;
    uint32_t u32clock_end;
    int32_t  i32clock_cnt;
    rdmcycle(&u32clock_begin);
#endif

    if (NULL == pbuf)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_par_err;
#endif
        return ;
    }

    if ((size+u8offset) > SPU_LOG_CLIENT_BUF_SIZE)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_oversize;
#endif
        return ;
    }

    pu8_addr = spu_log_client_mem_alloc(&u16_index);
    memcpy_ucp((pu8_addr+u8offset), pbuf, size);

    stsw_msg_info.u8Head[0]  = SPU_SW_MSG_INFO_HEAD1;
    stsw_msg_info.u8Head[1]  = SPU_SW_MSG_INFO_HEAD2;
    stsw_msg_info.u16DataLen = size;
    stsw_msg_info.u8PktType  = PKT_TYPE_STR_LOG;
    stsw_msg_info.u8CoreId   = (uint8_t)i32core_id;
    stsw_msg_info.u16Tail    = 0;
    memcpy_ucp(pu8_addr, (void *)&stsw_msg_info, u8offset);
    __ucps2_synch(0);

    stlog_msg_info.cell_id = cell_id;
    stlog_msg_info.core_id = i32core_id;
    stlog_msg_info.buf_idx = u16_index;
    stlog_msg_info.buf_size = (size + u8offset);

    i32ret = ecs_hw_que_send(ECS_RFM_SPU1_HW_QUEUE, stlog_msg_info.value);
    if (0 != i32ret)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_send_err;
#endif
    }
    else
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_send_ok;
#endif
    }

#ifdef UCP_TICK_ENABLE
    rdmcycle(&u32clock_end);
    i32clock_cnt = u32clock_end - u32clock_begin;
    debug_write(DBG_DDR_MSG_IDX(i32core_id, 102), i32clock_cnt);
#endif
    return ;
}

/* 对外调试信息输出接口(二进制) */
void osp_sendLog_print(int level, char* pbuf, int size, int cell_id)
{
    spu_sw_msg_info_t stsw_msg_info;
    SpuLogMsgInfo_t   stlog_msg_info;
    int32_t  i32core_id = get_core_id();
    int32_t  i32ret = 0;
    uint8_t  u8offset = SPU_SW_MSG_INFO_SIZE;
    uint8_t *pu8_addr  = NULL;
    uint16_t u16_index = 0;

#ifdef UCP_TICK_ENABLE
    uint32_t u32clock_begin;
    uint32_t u32clock_end;
    int32_t  i32clock_cnt;
    rdmcycle(&u32clock_begin);
#endif

    if (NULL == pbuf)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_print_par_err;
#endif
        return ;
    }

    if ((size+u8offset) > SPU_LOG_CLIENT_BUF_SIZE)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_print_oversize;
#endif
        return ;
    }

    pu8_addr = spu_log_client_mem_alloc(&u16_index);
    memcpy_ucp((pu8_addr+u8offset), pbuf, size);

    stsw_msg_info.u8Head[0]  = SPU_SW_MSG_INFO_HEAD1;
    stsw_msg_info.u8Head[1]  = SPU_SW_MSG_INFO_HEAD2;
    stsw_msg_info.u16DataLen = (uint16_t)size;
    stsw_msg_info.u8PktType  = PKT_TYPE_BIN_LOG;
    stsw_msg_info.u8CoreId   = (uint8_t)i32core_id;
    memcpy_ucp(pu8_addr, (void *)&stsw_msg_info, u8offset);
    __ucps2_synch(0);

    stlog_msg_info.cell_id = cell_id;
    stlog_msg_info.core_id = i32core_id;
    stlog_msg_info.buf_idx = u16_index;
    stlog_msg_info.buf_size = (size + u8offset);

    i32ret = ecs_hw_que_send(ECS_RFM_SPU1_HW_QUEUE, stlog_msg_info.value);
    if (0 != i32ret)
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_print_send_err;
#endif
    }
    else
    {
#ifdef SPU_LOG_TEST_FLAG
        ++gstspu_log_dbg.u32spu_sendlog_print_send_ok;
#endif
    }

#ifdef UCP_TICK_ENABLE
    rdmcycle(&u32clock_end);
    i32clock_cnt = u32clock_end - u32clock_begin;
    debug_write(DBG_DDR_COMMON_IDX(i32core_id, 103), i32clock_cnt);
#endif
}

#ifdef PCIE_BACKHAUL
#include "../../../pet_rfm_spu0/driver/inc/ucp_pcie_traffic.h"
#define LOGBUFSIZE      (256)
char tmp_buf[LOGBUFSIZE] = {0};

void com_debug_log(const char *fmt, ...)
{
    PcieEpMemBarStruct_t*   	pUcpMemBar = (PcieEpMemBarStruct_t *)0x08740000;//pMemSection->baseAddr;
    //uint32_t core_id = get_core_id();
    uint32_t count = 0;
    uint32_t i     = 0;

    va_list args;
    va_start(args,fmt);
    while(1)
    {
        count++;
        if(do_read((void *)&pUcpMemBar->command[PCI_ENDPOINT_UCPEP_EP_ED]) == 0)
        {
            vsnprintf(tmp_buf, LOGBUFSIZE, fmt, args);            
            //ape_csu_dma_1D_L2G_ch2ch3_transfer((uint64_t)((uint32_t)(tmp_buf-0x100000)), pUcpMemBar->log_buf, 1024, inst_id, 1);
            //memcpy_ucp(pUcpMemBar->log_buf, tmp_buf, 1024);
            for(i=0;i<LOGBUFSIZE;i++)
            {
                do_write_byte((char *)(&pUcpMemBar->log_buf[i]), tmp_buf[i]);
            }
            do_write((uint32_t*)&pUcpMemBar->command[PCI_ENDPOINT_UCPEP_EP_ED],  1);
            //do_write(((uint32_t*)(&APC_CSU_DMAZSTEPL0) + (apeId<<6) + (i<<3)), 4096);
            break;
        }
        else
        {
#if 1
            if(count > 1000)
            {
                break;
            }
#endif
            ucp_nop(100);
        }
    }
    va_end(args);
}
#endif

