#include <stdlib.h>
#include <string.h>
#include "spu_shell.h"
#include "ucp_printf.h"
#include "spu_log.h"
#include "ucp_drv_common.h"
#include "ucp_utility.h"
#include "typedef.h"
#include "phy_para.h"
#include "spu_version.h"

OSP_CMD_RTN gastCmdRtnTblExt[MAX_EXT_CMD_NUM];

int ospCmdRtnExtNum =0;
uint32_t gu32_osp_shell_task_cnt = 0;
uint32_t gu32_osp_shell_task_rev = 0;
char seps[]=" ,\t\n\"";
uint32_t g_core_id = 0;
uint32_t SHELL_CMD_NUM_EXT = 0;

static uint32_t argval[10]  =  {0};
static char argchar[10][32] = {0};
static char shellOut[64]     ={0};


OSP_CMD_RTN ospCmdRtnTbl[] =
{
    {"recmd_ape", (OSP_FUNCPTR)spu_shell_wrapper, (OSP_FUNCPTR)spu_reget_cmd},
    {"intr_ape",  (OSP_FUNCPTR)spu_shell_wrapper, (OSP_FUNCPTR)spu_csu_int_cnt},
};

int  SHELL_CMD_NUM = SHELL_NELEMENTS(ospCmdRtnTbl);
static int nCmdField;
static int maxCmdField=10;
static char *g_parg[32]={0};


void *spu_find_sym(char * addr)
{
    return addr;
}

int spu_isdigit( int ch )
{

    return (unsigned int)(ch - '0') < 10u;

}


void spu_insert_cmd_ext(char *name, OSP_FUNCPTR pfunc, char *desc, uint32_t argnum)
{
    uint8_t  u8str_len = 0;
    uint32_t num        = 0;
    uint32_t i          = 0;
    OSP_CMD_RTN *tlb    = NULL;
    OSP_CMD_EXT stCmdExt;

    if ((name == NULL) || pfunc == NULL)
    {    
        UCP_PRINT_ERROR("osp_insert_cmd_ext name:%p pfunc:%p\r\n", name, pfunc);
        return;
    }

    for (i = 0; i < MAX_EXT_CMD_NUM; i++)
    {
        if (strcmp(gastCmdRtnTblExt[i].cmd, name) == 0)
        {
            UCP_PRINT_ERROR("osp_insert_cmd_ext i:%u cmd:%s has exist name:%s\r\n", i, gastCmdRtnTblExt[i].cmd, name);
            return;
        }
    }
    
    tlb = gastCmdRtnTblExt;
    num = SHELL_CMD_NUM_EXT;
    if(num >= MAX_EXT_CMD_NUM)
    {
        UCP_PRINT_ERROR("osp_insert_cmd_ext num:%u beyond MAX_EXT_CMD_NUM:%d\r\n", num, MAX_EXT_CMD_NUM);
        return;
    }

    u8str_len = strlen(name);
    if(u8str_len > 12)
    {
        UCP_PRINT_ERROR("osp_insert_cmd_ext u8str_len:%u beyond 12\r\n", u8str_len);
        return;
    }

    memcpy_ucp(tlb[num].cmd, name, u8str_len + 1);
    tlb[num].wrapper = (OSP_FUNCPTR)spu_shell_wrapper;
    tlb[num].routine = pfunc;
    tlb[num].argnum          = argnum;

    memcpy_ucp(stCmdExt.cmd, name, u8str_len + 1);
    stCmdExt.argnum    = argnum;

    SHELL_CMD_NUM_EXT++; 
    stCmdExt.num    = SHELL_CMD_NUM_EXT;

    UCP_PRINT_LOG("osp_insert_cmd_ext name:%s num:%u argnum:%u\r\n", stCmdExt.cmd, stCmdExt.num, stCmdExt.argnum);

    spu_shellinfo_to_arm((char *)&stCmdExt, sizeof(OSP_CMD_EXT), UCP4008_OSP_SHELL_REG);
    
    return;

}

void spu_reget_cmd()
{
    uint32_t i        = 0;
    OSP_CMD_EXT stCmdExt;

    for (i = 0; i < SHELL_CMD_NUM_EXT; i++)
    {        
        UCP_PRINT_LOG("spu_reget_cmd i:%u cmd:%s\r\n", i, gastCmdRtnTblExt[i].cmd);        
        memcpy_ucp(stCmdExt.cmd, gastCmdRtnTblExt[i].cmd, strlen(gastCmdRtnTblExt[i].cmd) + 1);
        stCmdExt.argnum = gastCmdRtnTblExt[i].argnum;
        stCmdExt.num    = SHELL_CMD_NUM_EXT;

        spu_shellinfo_to_arm((char *)&stCmdExt, sizeof(OSP_CMD_EXT), UCP4008_OSP_SHELL_REG);
    }

    return;

}

void spu_set_log_level(uint8_t ucLevel)
{    
    if(ucLevel > LOG_TICK)
    {
        #ifdef LOG_SWITCH
        UCP_PRINT_ERROR("spu_set_log_level ucLevel:%u\n", ucLevel);
        #endif
        return;
    }
    
    //debug_write(DBG_DDR_COMMON_IDX(get_core_id(), 159), ucLevel);
    spu_log_init(ucLevel);

    return;
}


int spu_shell_init(void)
{
    g_core_id = get_core_id();

    spu_insert_cmd_ext("csu_ape", (OSP_FUNCPTR)spu_csu_stop_cfg, "cfg csu info", 2);
    spu_insert_cmd_ext("level_ape", (OSP_FUNCPTR)spu_log_level_set, "cfg ape print level", 1);
    spu_insert_cmd_ext("slevel_ape", (OSP_FUNCPTR)spu_log_level_get, "get ape print level", 0);
    /* 注册版本信息 */
    if (11 == g_core_id) {
        spu_insert_cmd_ext("ver_spu", (OSP_FUNCPTR)spu_show_version, "show spu soft version", 0);
    }

    return 0;
}


/******************************************************************************
* set_out_str - print string to console
* input:
*    out : output string
* return
*    none
*/

void set_out_str(char *out)
{
	//UCP_PRINT_LOG("%s", out);
}

int spu_shell_symo(char **arg, int len)
{
    int i;
    OSP_FUNCPTR func;

    unsigned long func_ret;

    for(i = 0; i < len; i++)
    {
        if((arg[i][0] == '0') && ((arg[i][1] == 'x') || (arg[i][1] == 'X')))
        {
            argval[i] = (uint32_t)strtoul(arg[i], (char **)NULL, 16);
        }
        else if(spu_isdigit(arg[i][0]))
        {
            argval[i] = (uint32_t)strtoul(arg[i], (char **)NULL, 10);
        }
        else
        {
            return -1;
        }
    }

    func = spu_find_sym((char *)argval[0]);
       
    if(func)
    {
        func_ret = func(argval[1], argval[2], argval[3], argval[4], 
            argval[5], argval[6], argval[7], argval[8], argval[9]);

        return 0;
    }

    return -1;
}



int spu_shell_wrapper(char **arg, int len, OSP_FUNCPTR func)
{
    int i;
    int ret;

    for(i = 0; i < len; i++)
    {
        if((arg[i][0] == '0') && ((arg[i][1] == 'x') || (arg[i][1] == 'X')))
        {
        
            argval[i] = strtoul(arg[i], (char **)NULL, 16);
        }
        else if(spu_isdigit(arg[i][0]))
        {
            argval[i] = strtoul(arg[i], (char **)NULL, 10);
        }
        else
        {
            strcpy(argchar[i], arg[i]);
            argval[i] = (long)argchar[i];
        }
    }

    ret = func(argval[0], argval[1], argval[2], argval[3], argval[4], 
        argval[5], argval[6], argval[7], argval[8], argval[9]);

    return ret;
}

/******************************************************************************
* get_cmd_arg - split command to params,then save to array arg
* input:
*    cmd : pointer to command
* return
*    params number
*/
int get_cmd_arg(char *cmd)
{
    char *token;

    nCmdField = 0;

    token = strtok(cmd, seps);    

    while (token != NULL)
    {   
        if (nCmdField >= maxCmdField)
        {
            return -1;
        }
        g_parg[nCmdField] = token;
        token = strtok(NULL, seps);
        nCmdField++;
    }

    return nCmdField;
}


int match_cmd(int num,  OSP_CMD_RTN*tlb)
{
    int i;
//    int ret;
    if((0 == num) || (NULL == tlb))
        return -1;

    for (i = 0; i < num; i++)
    {
        if (strcmp(tlb[i].cmd, g_parg[0]) == 0)
        {        
            //ret = (*tlb[i].wrapper)(&g_parg[1], nCmdField-1, tlb[i].routine);
            spu_shell_wrapper(&g_parg[1], nCmdField-1, tlb[i].routine);
            set_out_str(shellOut);
            return (0);
        }
    }
    return -1;
}
/****************************************************************************** 
* exec_cmd - execute command
* input:
*    none
* return
*    OSP_OK,or
*    OSP_ERROR(fail)
*/
int exec_cmd(void)
{
    int ret;
    int num;
    OSP_CMD_RTN* tlb;
    
    if (nCmdField > 0)
    {
        num = SHELL_CMD_NUM;
        tlb = ospCmdRtnTbl;
        ret = match_cmd(num, tlb);
        if(!ret)
        {
            return ret;
        }
        
        num = SHELL_CMD_NUM_EXT;
        tlb = gastCmdRtnTblExt;
        ret = match_cmd(num, tlb);
        if(!ret)
        {
            return ret;
        }
        
        ret = spu_shell_symo(&g_parg[0], nCmdField);

        return ret;

    }
    
    return (-1);
}

void spu_csu_int_cnt(void)
{
    char pbuf[2048];    
    uint32_t len      = 0;
    uint32_t ulNum    = 0;
    uint32_t ulCnt    = 0;    
	int32_t apeId     = get_core_id();
    stCoreInt* apeCoreIntInfo = (stCoreInt*)APE_INT_INFO_ADDR + APE_INT_MAXNUM*apeId;

    len = sprintf(pbuf,"\n\r%-8s%-16s%-8s%-16s\n\r","CoreId", "Inttype", "Intnum",  "IntCnt");

    ulNum = do_read_volatile(&(apeCoreIntInfo[APE_INT_TX_SLOT].intNum));
    ulCnt = do_read_volatile(&(apeCoreIntInfo[APE_INT_TX_SLOT].intCnt));
    len +=sprintf(pbuf +len,"%-8u%-16s%-8u%u\n\r", apeId, "APE_INT_TX_SLOT", ulNum, ulCnt);

    ulNum = do_read_volatile(&(apeCoreIntInfo[APE_INT_RX_SLOT].intNum));
    ulCnt = do_read_volatile(&(apeCoreIntInfo[APE_INT_RX_SLOT].intCnt));
    len +=sprintf(pbuf +len,"%-8u%-16s%-8u%u\n\r", apeId, "APE_INT_RX_SLOT", ulNum, ulCnt);

    ulNum = do_read_volatile(&(apeCoreIntInfo[APE_INT_STC_0US].intNum));
    ulCnt = do_read_volatile(&(apeCoreIntInfo[APE_INT_STC_0US].intCnt));
    len +=sprintf(pbuf +len,"%-8u%-16s%-8u%u\n\r", apeId, "APE_INT_STC_0US", ulNum, ulCnt);

    ulNum = do_read_volatile(&(apeCoreIntInfo[APE_INT_STC].intNum));
    ulCnt = do_read_volatile(&(apeCoreIntInfo[APE_INT_STC].intCnt));
    len +=sprintf(pbuf +len,"%-8u%-16s%-8u%u\n\r", apeId, "APE_INT_STC", ulNum, ulCnt);

    spu_shellinfo_to_arm(pbuf, len, UCP4008_OSP_SHELL);

    return;
}

void spu_csu_stop_cfg(uint8_t ucstop, uint8_t ucadvance)
{    
    if(ucstop > 1)
    {
        UCP_PRINT_EMPTY("spu_csu_stop_cfg ucstop:%u ucadvance:%u\n", ucstop, ucadvance);
        return;
    }
    
	do_write(CSU_STOP_CMD_ADDR, ucstop);
	
	//do_write(CSU_ADVANCE_US_ADDR, ucadvance);
	do_write(CSU_TX_ADVANCE_SAMPLE, ucadvance);
    
    return;
}

void spu_shellinfo_to_arm(char* pbuf, int ulLen, uint8_t u8PktType)
{    
    spu_sw_msg_info_t stMsgHead;
    uint16_t u16offset       = SPU_SW_MSG_INFO_SIZE;
    int32_t  i32core_id      = get_core_id();
    uint8_t  ret             = 0;
    int8_t   *pi8buf         = NULL;
    uint8_t  u8shell_index   = i32core_id + 24;
    
    if (NULL == pbuf)
    {
        UCP_PRINT_EMPTY("ERROR:osp msg start ret:%u\n", ret);
        return;
    }

    pi8buf = spu_sw_mem_malloc(u8shell_index);
    if (NULL == pi8buf)
    {
        UCP_PRINT_EMPTY("osp_shellinfo_to_arm call spu_sw_mem_malloc return null\n");
        return ;
    }            
    
    memcpy_ucp(pi8buf, pbuf, ulLen);


    stMsgHead.u8PktType    = u8PktType;
    stMsgHead.u16DataLen   = ulLen+SPU_SW_MSG_INFO_SIZE;
    stMsgHead.u8CoreId     = (uint8_t)i32core_id;

    spu_sw_msg_info_t * pstsw_msg_info = (spu_sw_msg_info_t *)(pi8buf - u16offset);
    memcpy_ucp((void *)pstsw_msg_info, (void *)&stMsgHead, u16offset);

    ret = spu_sw_enque(u8shell_index, pi8buf);
    if (0 == ret)
    {        
        UCP_PRINT_EMPTY("osp_shellinfo_to_arm ret:%u\n", ret);
        return ;
    }

    return;
}


void spu_shell_proc(spu_sw_msg_info_t *pMsg)
{    
    int32_t ret;

    if (NULL == pMsg)
    {
        return;
    }
    
    /*arm 发过来的shell消息*/
    if(UCP4008_OSP_SHELL == pMsg->u8PktType)
    {    
        ret = get_cmd_arg((char *)pMsg->i8Data); 
        if(-1 == ret)
            return ;
        ret = exec_cmd();
        //set_prompt();
    }    
   
    return;

}

void spu_shell_task(void)
{
    uint8_t u8loop              = g_core_id + 12;
    spu_sw_msg_info_t *psw_msg  = NULL;

    debug_write(DBG_DDR_COMMON_IDX(g_core_id, 20), ++gu32_osp_shell_task_cnt);
    
    /* 从软队列里取出 */
    if(0 == spu_sw_deque(u8loop, (uint32_t **)&psw_msg))
    {
        debug_write(DBG_DDR_COMMON_IDX(g_core_id, 21), psw_msg);
        debug_write(DBG_DDR_COMMON_IDX(g_core_id, 22), &psw_msg);
        debug_write(DBG_DDR_COMMON_IDX(g_core_id, 23), ++gu32_osp_shell_task_rev);
        spu_shell_proc(psw_msg);
    }

    return;
}




