/**
 * @file hv_vos_Log.c
 * @brief vos log source code
 * @details 
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20230301
 * @copyright Copyright(c),2023-3, Hiview Software. All rights reserved.
 * @par History: 
 * <table>
 * <tr><th>author                     <th>date           <th>description
 * <tr><td>HiView SoC Software Team   <td>20230301       <td>Create and first Version.
 * </table>
**/

#include "hv_vos_Types.h"
#include "hv_vos_Macro.h"
#include "hv_vos_Log.h"
#include "hv_vos_Time.h"
#include "hv_vos_Conn.h"
#include "hv_vos_Printf.h"
#include "hv_vos_Task.h"
#include "hv_chip_Config.h"
#include "hv_chip_Memory.h"
#include "hv_vos_Cache.h"

//#define HV_LOG_USR_BUFFER

#ifndef HV_LOG_BUF_SZ
#define HV_LOG_BUF_SZ 512
#endif
#ifdef HV_LOG_USR_BUFFER
#define HV_LOG_BUF_TEMP (4096*16)
#endif
UINT32 g_uiLogOutputLevel = HV_LOG_LEVEL_INFO;
//static UINT32 s_uiLogFlag = HV_LOG_SHOW_TIMESTAMP | HV_LOG_SHOW_LINE | HV_LOG_SHOW_FILENAME;
static UINT32 s_uiLogFlag = HV_LOG_SHOW_TIMESTAMP;

/* index for errlog in flash. */
static UINT32 s_uiLogIndex = 0;
/* index for totallog read in ddr. */
static UINT32 s_uiLogTotalReadIndex = 0;
/* index for totallog write in ddr. */
static UINT32 s_uiLogTotalWriteIndex = 0;
/* errlog buf in flash. */
static char *pLogSave = (char *)(HV_MEMORY_CONFIG_MONITOR_LOG_START);

#ifdef HV_LOG_USR_BUFFER
/* total log buf in ddr. */
static char LogBufTotal[HV_LOG_BUF_TEMP] = {0};
#endif
/*
"VERBOSE",
"INFO",
"WARN",
"ERROR",
"FATAL",
"ALLWAYS",
*/
static const char *log_str[] = {
    "V",
    "I",
    "W",
    "E",
    "F",
    "A",
};

/* Supported colors. */
#define CLR_NORMAL  "\x1B[0m"
#define CLR_RED     "\x1B[1;31m"
#define CLR_GREEN   "\x1B[1;32m"
#define CLR_YELLOW  "\x1B[1;33m"
#define CLR_BLUE    "\x1B[1;34m"
#define CLR_NAGENTA "\x1B[1;35m"
#define CLR_CYAN    "\x1B[1;36m"
#define CLR_WHITE   "\x1B[1;37m"
#define CLR_RESET   "\x1B[0m"

INLINE void Hv_Vos_LOG_Lock(void)
{
    return;
}

INLINE void Hv_Vos_LOG_Unlock(void)
{
    return;
}

static __attribute((__unused__)) const char *apLogColor[] = 
{
    CLR_NORMAL,
    CLR_GREEN,
    CLR_YELLOW,
    CLR_NAGENTA,
    CLR_RED,
    CLR_WHITE,
};

INLINE void LOG_OUTPUT(char *pLogFuf, int iLevel)
{
    UINT32 uiLength = 0;
    UINT32 iLoop    = 0;

    uiLength = strlen(pLogFuf);
#ifdef HV_LOG_USR_BUFFER
    Hv_Vos_TaskEnterCritical();
    for (iLoop=0; iLoop<uiLength; iLoop++)
    {
        LogBufTotal[s_uiLogTotalWriteIndex++ & (HV_LOG_BUF_TEMP - 1)] = pLogFuf[iLoop];
    }
    LogBufTotal[s_uiLogTotalWriteIndex++ & (HV_LOG_BUF_TEMP - 1)] = '\n';
    Hv_Vos_TaskExitCritical();
#else
    HV_PRINTF("%s\n", pLogFuf);
#endif
    if (iLevel > HV_LOG_LEVEL_WARN)
    {
        for (iLoop=0; iLoop<uiLength; iLoop++)
        {
            pLogSave[s_uiLogIndex++ & 0xfff] = pLogFuf[iLoop];
        }
        pLogSave[s_uiLogIndex++ & 0xfff] = '\n';
        Hv_Vos_InvalidAllDCache();
    }
    return;
}

void Hv_Vos_FlushLogBuf(void)
{
    UINT32 uiTempWriteIndex = s_uiLogTotalWriteIndex;
#ifdef HV_LOG_USR_BUFFER
    while ((s_uiLogTotalReadIndex < uiTempWriteIndex)
            || ((uiTempWriteIndex & BIT_31) != (s_uiLogTotalReadIndex & BIT_31)))
    Hv_Chip_DebugUartPutc(LogBufTotal[(s_uiLogTotalReadIndex++) & (HV_LOG_BUF_TEMP - 1)]);
#endif
    return;
}

void Hv_Vos_LOG_SetFlag(UINT32 uiFlag)
{
    s_uiLogFlag = uiFlag;
}

const char * Hv_Vos_ExactFilename(const char *path) 
{
    const char *p;

    p = strrchr(path, '/');
    if (p) 
    {
        return p + 1;
    } 
    else 
    {
        return path;
    }
}

static __attribute((__unused__)) void Hv_Vos_LOG_WriteImpl(int level, int raw, const char *func,
                                 int line,
                                 const char *fmt, va_list va)
{
    char log_buf[HV_LOG_BUF_SZ];
    char *p = log_buf;

    if (!raw)
    {
        //p += HV_SPRINTF(p, "[%s]", log_str[level]);
        if (s_uiLogFlag & HV_LOG_SHOW_TIMESTAMP)
        {
            p += HV_SPRINTF(p, "<%d>", Hv_Vos_GetTick());
        }
        if (s_uiLogFlag & HV_LOG_SHOW_TASK_ID)
        {
            p += HV_SPRINTF(p, "<task-%02d>", Hv_Vos_TASK_CurrentTaskId());
        }
        if (s_uiLogFlag & HV_LOG_SHOW_FUNCTION)
        {
            p += HV_SPRINTF(p, "<func-%s>", func);
        }
        if (s_uiLogFlag & HV_LOG_SHOW_LINE)
        {
            p += HV_SPRINTF(p, "<line-%d>", line);
        }
    }

    HV_VSPRINTF(p, fmt, va);
    LOG_OUTPUT(log_buf, level);
}

#ifdef HV_CONFIG_ENABLE_PRINT
void Hv_Vos_LOG_Write(int level, int raw, const char *func,
                      int line, const char *fmt, ...)
{
    va_list va;
    va_start(va, fmt);
    Hv_Vos_LOG_WriteImpl(level, raw, func, line, fmt, va);
    va_end(va);
}
#endif

void Hv_Vos_LOG_SetLevel(int level)
{
    g_uiLogOutputLevel = level;
}

void Hv_Vos_LOG_DumpBuffer(const char *func, int line,
                           const char *name, const void *buf, int buf_length)
{

    int i = 0;

    HV_PRINTF("%s[%d]=", name, buf_length);
    for (i = 0; i < buf_length; i ++)
    {
        if (buf_length >= 16 && i % 16 == 0)
        {
            HV_PRINTF("\n   %08X: ", i / 16 * 16);
        }
        HV_PRINTF("%02x ", ((unsigned char *)buf)[i]);
    }
    HV_PRINTF("\n");
}
