/*
* FileName:shell_cmd.c
* Author : qiuxf
* CreateTime: 18-8-7 14:09
* Description:
*/
/**
@file shell_cmd.c
@brief Shell cmd process
*/

/********************************************************************************************
Debug Switch Definition Section
********************************************************************************************/

/********************************************************************************************
Include File Section
********************************************************************************************/
#include "shell_mem.h"
#include "shell_char.h"
#include "shell_inode.h"
#include "shell_cmd.h"
#include "log_creat.h"
#include "log_manager_task.h"
#include "string.h"

/********************************************************************************************
Macro Definition Section
********************************************************************************************/								
#define COUNT_OF(x)                     (sizeof((x))/sizeof(x[0]))
#define MAX_SHELL_SND_BUF				(1024)

#define ROOT_COMMENT		"change author to root, format: root [passwd]"
#define EXIT_COMMENT		"change author to user, format: exit"
#define HELP_COMMENT		"list all command and comment"
#define LS_COMMENT			"list all file"
#define CAT_COMMENT			"read file, format: cat [option] [filename]"
#define ECHO_COMMENT		"write to file, format: echo [string] > [filename]"
#define SEEK_COMMENT		"seek file, format: seek [file] [offset]"
#define LOGCAT_COMMENT		"process log file, format :logcat [option]"
#define MW_COMMENT			"write data to memory, format : mw [option] [address] [data]"
#define MR_COMMENT			"read data from memory, format : mr [option] [address]"
#define ISR_COMMENT         "open isr time statistics : isr [o/c] open or  close"
#define TSK_COMMENT         "open task time statistics: tsk [o/c] open or close"
#define LOGCAT_ERROR			"Format Error, logcat <option> <pattern>"
#define LOGCAT_CMDERROR			"CMD ERR"
#define LOGCAT_CMD_C			"-clear"
#define LOGCAT_CMD_E			"-e"
#define LOGCAT_CMD_S			"-s"
#define LOGCAT_FILE_NAME		"klog"
#define LOGCAT_CMD_HELP			"-help"
#define LOGCAT_HELP		"/*logcat -audio :  power/panic/rpc/common/climate/vehicle/gw/gauge/notify/trip/safety/odo/bsw/hardware/periph)*/\r\n"	\
						"/*logcat -audio AUDIOSTM)*/"
#define OPEN_                           "o"
#define CLOSE_                           "c"

#define WRITE_AUTHOR_STR()		do{\
									if(xShellGetAuthor() == AUTHOR_ROOT)\
									{\
										vShellWriteRootHead();\
									}\
									else\
									{\
										vShellWriteUserHead();\
									}\
									}while(0)

#define INTERRUPTABLE()			(CTRL_INIT == xShellCtrlGet())
#define Ecarx_TimeDelay(t)
#define LOGCAT_MAX		30
#define MEMORY_FILE_NAME	"memory"
#define MW_ERROR			"format error, format mw [option] [addr] [data]"
#define MR_ERROR			"format error, format mr [option] [addr]"
#define	FORMAT_B			"-b"
#define FORMAT_H			"-h"
#define FORMAT_W			"-w"
#define CAT_FORMAT_ERROR	"Format Error, Format: cat [-h/-c] <filename>"
#define MAX_FILE_SIZE		(0xFFFF)
#define SINGLE_READ_SIZE	(64)
#define ECHO_FORMAT_ERROR	"Format Error, Format: echo <string> > <filename>"

/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
static uint8_t ucShellEcho(int32_t argc, const uint8_t **argv);
static uint8_t ucShellLogcat(int32_t argc, const uint8_t **argv);
const SHELL_CMD * pxShellGetCmdFromTbl(const uint8_t *cmd);
void vGetString(uint8_t *nameg,uint8_t *str, uint8_t length);
void vShellDoLogcatCyclic(void *p_arg, uint8_t *rslt,uint8_t counter);
void vShellDoLogcatCyclicEnd(void *p_arg,uint8_t counter);
int32_t lShellNewDoLogcat(int32_t argc, const uint8_t *option, const uint8_t *pattern,const uint8_t *name,uint8_t buffID);
int32_t lShellDoLogcat(int32_t argc, const uint8_t *option, const uint8_t *pattern);
static uint8_t ucShellLogcatGetCmd(int32_t argc, const uint8_t **argv);
static uint8_t ucShellLogcat(int32_t argc, const uint8_t **argv);
void vEchoBufferClear(void);

DECLARATION_MUTEX ( log_mutex_output );

/********************************************************************************************
Const Global Variable Definition Section
********************************************************************************************/


/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/


/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/

//QM_DATA static uint8_t s_aucCmdSndBuf[MAX_SHELL_SND_BUF];
static uint8_t s_aucFileReadWriteBuf[256];
static uint8_t s_aucFileWriteBuf[256];
static uint8_t s_aucWriteLognNme[30]={0};

/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/
static struct logcat_context
{
	int32_t fd;
	int32_t argc;
	const uint8_t *pattern;
	const uint8_t *option;
} log_context;

static const SHELL_CMD s_xShellCmdTbl[] =
{     /*help*/
	{(const uint8_t *)"echo",  (const uint8_t *)ECHO_COMMENT,     AUTHOR_USER, ucShellEcho},
	{(const uint8_t *)"logcat", (const uint8_t *)LOGCAT_COMMENT, AUTHOR_USER,		ucShellLogcat}
};


/********************************************************************************************
Function Definition Section
********************************************************************************************/


/**
 * pxShellGetCmdFromTbl
 * Author qiuxf
 * @param cmd  cmd
 * @return cmd proc struct
 */
const SHELL_CMD * pxShellGetCmdFromTbl(const uint8_t *cmd)
{
    const SHELL_CMD *tmp = SAF_NULL;
	uint32_t TblSize = COUNT_OF(s_xShellCmdTbl);
    uint32_t i = 0;

    if((strlen((const char *)cmd) + 1) > SHELL_MAX_ARGV_LEN)
    {
        tmp = SAF_NULL;
    }
    else
    {       
        for(i = 0; i < TblSize; i++)
        {
            if(0 == strncmp((const char *)s_xShellCmdTbl[i].cmd, (const char *)cmd, SHELL_MAX_ARGV_LEN))
            {
                tmp = &s_xShellCmdTbl[i];
                break;
            }
        }
    }
    return tmp;
}

/**
 * ucShellHelp
 * Author qiuxf
 * @param argc  count of arg
 * @param argv arg list
 * @return boolean
 */
uint8_t ucShellCmdIsExistence(uint8_t *strcmd)
{
	uint8_t ret = SAF_FALSE;
	
	for(uint8_t i = 0; i < (sizeof(s_xShellCmdTbl)/sizeof(SHELL_CMD)); i++)
	{
		if(SAF_NULL != s_xShellCmdTbl[i].cmd && strcmd != SAF_NULL)
		{
			if(0 == strncmp((char *)s_xShellCmdTbl[i].cmd, (char *)strcmd, strlen((char *)s_xShellCmdTbl[i].cmd)))
			{
				ret = SAF_TRUE;
				break;
			}
		}
	}
	
	return ret;
}
static uint8_t ucShellEcho(int32_t argc, const uint8_t **argv)
{
	//uint8_t ret = SAF_FALSE;
	const uint8_t *namep = SAF_NULL;
	const uint8_t *str = SAF_NULL;

	if(3 != argc)
	{
		printk("%s\r\n", ECHO_FORMAT_ERROR);
	}
	else
	{
		if(0 != strncmp((const char *)argv[1], ">", strlen((const char *)">")))
		{
			printk("%s\r\n", ECHO_FORMAT_ERROR);
		}
		else
		{
			str = argv[0];
			namep = argv[2];
#if 0
			if(fd < 0)
			{
				printk("%s open error, code: %d\r\n", namep, fd);
			}
			else
#endif
			{
				memset(s_aucFileReadWriteBuf, 0, sizeof(s_aucFileReadWriteBuf));
				memcpy(s_aucFileReadWriteBuf, (void *)str, strlen((const char *)str));
				memset(s_aucFileWriteBuf,0,sizeof(s_aucFileWriteBuf));
				memcpy(s_aucFileWriteBuf, (void *)str, strlen((const char *)str));
				if(namep != SAF_NULL)
				{
					memset(s_aucWriteLognNme, 0, sizeof(s_aucWriteLognNme));
					memcpy(s_aucWriteLognNme, namep, strlen((const char *)namep));
				}
			}
		}
	}
	WRITE_AUTHOR_STR();
    return SAF_FALSE;
}


void vGetString(uint8_t *nameg,uint8_t *str, uint8_t length)
{
	Log_Buffer_Param* log_cfg;
	
	if(g_pxLogCfg->log_cfg != SAF_NULL)
	{
				
		for(uint8_t i =0;i< g_ucLogNum;i++)
		{
			
			log_cfg = &g_pxLogCfg->log_cfg[i];	
			
			if((log_cfg->logname !=SAF_NULL) && (nameg !=SAF_NULL) && (str != SAF_NULL))
			{
				if((strlen((const char *)log_cfg->logname) == strlen((const char *)nameg)) && (0 == strncmp((const char *)nameg, (const char *)log_cfg->logname, strlen((const char *)log_cfg->logname))) && \
				(strlen((const char *)s_aucFileWriteBuf)!=0) && (strlen((const char *)s_aucWriteLognNme) !=0))
				{
					if((strlen((const char *)nameg)== strlen((const char *)s_aucWriteLognNme)) && (0 == strncmp((const char *)nameg,(const char *)s_aucWriteLognNme, strlen((const char *)nameg))))
					{
						if((strlen((const char *)s_aucFileWriteBuf) < SHELL_MAX_ARGV_LEN) && (strlen((const char *)s_aucFileWriteBuf) < length))
						{
							memcpy(str,s_aucFileWriteBuf, strlen((const char *)s_aucFileWriteBuf));
						}
						else if((SHELL_MAX_ARGV_LEN >= length) && (strlen((const char *)s_aucFileWriteBuf) >=  length))
						{
							memcpy(str,s_aucFileWriteBuf, length - 1);
						}
						else 
						{
							if((SHELL_MAX_ARGV_LEN < length) && (strlen((const char *)s_aucFileWriteBuf) >=  SHELL_MAX_ARGV_LEN))
							{
								memcpy(str,s_aucFileWriteBuf, SHELL_MAX_ARGV_LEN - 1);
							}
						}
//
					}
				}
			}
			
			//printf("vGetStringend  %d****\n", i);
		}
	}	

}
					


/**
 * vShellDoLogcatCyclic
 * Author qiuxf
 * @param argc  count of arg
 * @param argv arg list
 * @return boolean
 */
void vShellDoLogcatCyclic(void *p_arg, uint8_t *rslt,uint8_t counter)
{
	int32_t fd = 0;
	int32_t argc = 0;
	uint32_t read_size = 0;
	// const uint8_t *pattern = SAF_NULL;
	// const uint8_t *option = SAF_NULL;
	struct logcat_context *context = SAF_NULL;
	if(SAF_NULL == p_arg)
	{
		*rslt = SAF_FALSE;
	}
	else
	{
		context = (struct logcat_context *)p_arg;
		fd = context->fd;
		argc = context->argc;
		// pattern = context->pattern;
		// option = context->option;
		memset(s_aucFileReadWriteBuf, 0, sizeof(s_aucFileReadWriteBuf));
		read_size = ulShellRead(fd, s_aucFileReadWriteBuf, sizeof(s_aucFileReadWriteBuf) - 1,counter);	/*read single line*/
		//	if(read_size > 0)
		while(read_size > 0)
		{
			if(1 == argc)/*logcat -audio*/
			{
				//MUTEX_TAKE (log_mutex_output,SAFETYOS_MAX_DELAY );							
				printk("%s", (uint8_t *)&s_aucFileReadWriteBuf[0]);
				//MUTEX_GIVE ( log_mutex_output );
			}
			else
			{

			}
			memset(s_aucFileReadWriteBuf, 0, sizeof(s_aucFileReadWriteBuf));
			read_size = ulShellRead(fd, s_aucFileReadWriteBuf, sizeof(s_aucFileReadWriteBuf) - 1,counter);	/*read single line*/
		}
		*rslt = SAF_TRUE;
	}
}

/**
 * vShellDoLogcatCyclicEnd
 * Author qiuxf
 * @param p_arg
 * @return none
 */
void vShellDoLogcatCyclicEnd(void *p_arg,uint8_t counter)
{
	int32_t fd = 0;

	if(SAF_NULL != p_arg)
	{
		fd = ((struct logcat_context *)p_arg)->fd;
		lShellClose(fd,counter);
	}
}



/*

*lShellNewDoLogcat
*add for power audio swc rpc
*logcat output alone

*/
int32_t lShellNewDoLogcat(int32_t argc, const uint8_t *option, const uint8_t *pattern,const uint8_t *name,uint8_t buffID)
{
	int32_t fd = 0;
	int32_t ret = 0;

	(void)option;
	(void)pattern;
	SHELL_CYCLIC_TASKLET tasklet;

	fd = lShellOpen(name, F_READ_MASK | F_IOCTL_MASK,buffID);
	if(fd < 0)
	{
		printk("%s open error , code : %d", name, fd);
		ret = -1;
	}
	else
	{
		// if(SAF_NULL != pattern)
		// {			
		// 	memset(s_aucPatternBuf, 0, sizeof(s_aucPatternBuf));
		// 	strncpy((char *)s_aucPatternBuf, (const char *)pattern, sizeof(s_aucPatternBuf));
		// }
		// if(SAF_NULL != option)
		// {
		// 	memset(s_aucOptionBuf, 0, sizeof(s_aucOptionBuf));
		// 	strncpy((char *)s_aucOptionBuf, (const char *)option, sizeof(s_aucOptionBuf));
		// }
		log_context.argc = argc;
		log_context.fd = fd;
		// log_context.pattern = s_aucPatternBuf;
		// log_context.option = s_aucOptionBuf;

		tasklet.p_arg = (void *)&log_context;
		tasklet.proc = vShellDoLogcatCyclic;
		tasklet.endproc = vShellDoLogcatCyclicEnd;
		xShellCyclicTaskletSet(&tasklet,buffID);
	}
	return ret;
}
/**
 * lShellDoLogcat
 * Author qiuxf
 * @param argc  count of arg
 * @param argv arg list
 * @return boolean
 */
/**
 * ucShellLogcat
 * Author qiuxf
 * @param argc  count of arg
 * @param argv arg list
 * @return boolean
 */
static uint8_t ucShellLogcatGetCmd(int32_t argc, const uint8_t **argv)
{
	uint8_t ret = SAF_FALSE;
	int32_t file_ret = 0;
	uint8_t cmplen = 0;
	Log_Buffer_Param* log_cfg;

	if(g_pxLogCfg->log_cfg != SAF_NULL)
	{	
		for(uint8_t i = 0; i < g_ucLogNum; i++)
		{			
			log_cfg = &g_pxLogCfg->log_cfg[i];	
			if((log_cfg->logname != SAF_NULL) && (log_cfg->logcmd != SAF_NULL))
			{					
				if(strlen((const char *)log_cfg->logcmd) > strlen((const char *)argv[0]) )
				{
					cmplen = strlen((const char *)log_cfg->logcmd);
				}
				else
				{
					cmplen = strlen((const char *)argv[0]);
				}
				if((strlen((const char *)log_cfg->logcmd) == strlen((const char *)argv[0])) && (0 == strncmp((const char *)argv[0], (const char *)log_cfg->logcmd, cmplen)))
				{
					if(SAF_FALSE == log_cfg->isvalid)
					{
						printk("The %s buffer size is abnormal. [%d]\r\n",log_cfg->logname,*(log_cfg->buffsize));
					}
					file_ret = lShellNewDoLogcat(argc , argv[0], SAF_NULL,log_cfg->logname,i);
					if(0 == file_ret)
					{
						ret = SAF_TRUE;
					}
					break;					
				}
			}
			else
			{
				printk("%s\r\n", LOGCAT_CMDERROR);
				break;
			}
		}
	}
	return ret;
}


static uint8_t ucShellLogcat(int32_t argc, const uint8_t **argv)
{
	uint8_t ret = SAF_FALSE;
	//int32_t file_ret = 0;
	uint8_t logBuffValidNum = 0;
	Log_Buffer_Param* log_cfg;

	if(1 == argc)
	{
		if(g_pxLogCfg->log_cfg != SAF_NULL)
		{
			for (uint8_t count = 0; count < g_ucLogNum; count++)
			{
				log_cfg = &g_pxLogCfg->log_cfg[count];
				if(SAF_TRUE == log_cfg->isvalid)
				{
					logBuffValidNum++;
				}
			}
		}
		if( logBuffValidNum > 0 )
		{
			ret = ucShellLogcatGetCmd(argc, argv);
		}
		else
		{
			printk("[LOG]The total size of the requested cache buffer exceeds the limit!\r\n");
		}			
	}
	if(ret == SAF_FALSE)
	{
		printk("%s\r\n", LOGCAT_ERROR);
	}
	return ret;
}

void vEchoBufferClear()
{
	memset(s_aucFileWriteBuf,0,sizeof(s_aucFileWriteBuf));
}


