
/**
@file shell_char.c
@brief Include char process function.
*/

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


/********************************************************************************************
Include File Section
********************************************************************************************/

#include "shell_mem.h"
#include "shell_char.h"
#include "shell_core.h"
//#include "cirq_buffer.h"
#include "ecarx_queue.h"
//#include "Ecarx_Timer.h"
//#include "Uart.h"
#include "main.h"
#include "shell_port.h"
//#include "config.h"
#include "shell_cmd.h"
#include "string.h"
/********************************************************************************************
Macro Definition Section
********************************************************************************************/
/*ASCII defination*/
#define RECORENUM                       (10)
#define CHAR_BACK_SPACE                 '\b'
#define CHAR_ENTER                      '\r'
#define CHAR_CHANGE_LINE                '\n'
#define CHAR_SPACE                      ' '
#define CHAR_UPDOWNHEAD					'['
#define CHAR_CTRL_START                 (0)
#define CHAR_ETX                        (3)     /*ctrl + c*/
#define CHAR_EOT                        (4)     /*ctrl + d*/
#define CHAR_SUB                        (26)    /*ctrl + z*/
#define CHAR_CTRL_END                   (31)
#define PRINTK_BUF_SIZE					(512)
/*constatic string*/
#define NEW_LINE						"\r\n"
#define ROOT_STR                        "root:>"
#define USER_STR                        "user:>"
#define PASS_WD                         "beyond"
#define PASS_WD_ERROR                   "password error\r\n"
#define ARGV_TO_LONG                    "max size of argv is 30\r\n"
#define ARGC_TO_MORE                    "MAX size of argv is 10\r\n"
#define CMD_INVALID                     "Invalid instruction\r\n"
#define UART_PASSWORD_SIZE	8

#define SHELL_SND_MSG_CONST()           do{;}while(0)
/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
void vShellCtrlSet(CTRL_CMD cmd);
CTRL_CMD xShellCtrlGet(void);
void vShellCtrlProcess(uint8_t recv);
void vShellWriteRootHead(void);
void vShellWriteUserHead(void);
boolean xShellPasswdCheck(const uint8_t *passwd);
void vShellClearMsgBuf(void);
SHELL_MSG_GROUP * pxShellGetMsgGroup(void);
static uint8_t ucShellNeedWriteback(char c);
static uint8_t ucShellDoCreateMessage(SHELL_BUF *pbuf, SHELL_MSG_GROUP *pmsg);
static uint8_t ucShellCreateArgFromRecvBuf(SHELL_BUF *pbuf, SHELL_MSG_GROUP *pmsg);
void vShellWriteBack(uint8_t c,uint8_t *singlechar);
void vShellDeleteWriteString(uint8_t cmdlength);
void vShellWriteString(uint8_t *pStr,uint16_t length);
void vShellKeyUp(void);
void vShellKeyDown(void);
uint8_t ucShellChangeLine(void);
void vShellCmdRecord(void);
void vShellBackSpace(uint8_t c,uint8_t *singlechar);
void vShellOtherCharacter(uint8_t c);
uint8_t ucShellCharIntProc(uint8_t c);


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

/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/
//uint64_t g_xUartPasswordFlash = UART_PASSWORD_FF;
//uint8_t g_axUartPasswordData[UART_PASSWORD_SIZE]={0};
/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/
static SHELL_BUF s_xShellRecvBuf;
static SHELL_MSG_GROUP s_xShellMsgGrp;
static CTRL_CMD s_xCtrlCmdBuf = CTRL_INIT;
//QM_DATA static uint8_t s_ucPrintBuf[PRINTK_BUF_SIZE];
static ShellCmdRecord_t s_xCmdRecord = {0};
/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/

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


/*
 * printk
 * Author qiuxf
 * @param cmd control cmd
 * @return none
 */
#if 0
int32_t Shell_printk(const uint8_t *format, ...)
{
	/* Attention:
	 * This API is discarded, please use struct LOG_CATEGORY outputs the log,
	 * For more detail, see the example in the file log.h.
	 */
	return 0;
}
#endif
/*
 * printk
 * Author qiuxf
 * @param cmd control cmd
 * @return none
 */


/*
 * print critical information
 * Author qiuxf
 * @param cmd control cmd
 * @return none
 */

/*
 * vShellCtrlSet
 * Author qiuxf
 * @param cmd control cmd
 * @return none
 */
void vShellCtrlSet(CTRL_CMD cmd)
{
	s_xCtrlCmdBuf = cmd;
}

/**
 * xShellCtrlGet
 * Author qiuxf
 * @param none
 * @return control command
 */
CTRL_CMD xShellCtrlGet(void)
{
	return s_xCtrlCmdBuf;
}
/**
 * xShellCtrlGet
 * Author qiuxf
 * @param none
 * @return control command
 */
void vShellCtrlProcess(uint8_t recv)
{
	if(CHAR_ETX == recv)
	{
		s_xCtrlCmdBuf = CTRL_C;
	}
	else if(CHAR_EOT == recv)
	{
		s_xCtrlCmdBuf = CTRL_D;
	}
	else if(CHAR_SUB == recv)
	{
		s_xCtrlCmdBuf = CTRL_Z;
	}
	else
	{
		; /*do nothing*/
	}
}
/**
 * Shell_WriteRootStr
 * Author qiuxf
 * @param none
 * @return none
 */
void vShellWriteRootHead(void)
{
    UART_WRITE_STR(ROOT_STR);
}
/**
 * vShellWriteUserHead
 * Author qiuxf
 * @param none
 * @return none
 */
void vShellWriteUserHead(void)
{
    UART_WRITE_STR(USER_STR);
}

/**
 * vShellWriteUserHead
 * Author qiuxf
 * @param none
 * @return none
 */
#if 0
boolean xShellPasswdCheck(const uint8_t *passwd)
{
	int32_t ret = SAF_FALSE;
	
	if(passwd != SAF_NULL)
	{
		/*8 byte size if input char judge '\0',if if input HEX should judge '\r''\n'*/
		if((memcmp(passwd,g_axUartPasswordData,UART_PASSWORD_SIZE) == 0) &&((passwd[8] == '\0') ||(passwd[8] == '\r') || (passwd[8] == '\n')))
		{
			//Shell_Printk("password_input = %s\r\n",passwd);	
			ret = SAF_TRUE;
		}

	}
	return ret;
}
#endif
/**
 * vShellClearMsgBuf
 * Author qiuxf
 * @param none
 * @return none
 */
void vShellClearMsgBuf(void)
{
    memset(&s_xShellMsgGrp, 0, sizeof(s_xShellMsgGrp));
}

SHELL_MSG_GROUP * pxShellGetMsgGroup(void)
{
    return &s_xShellMsgGrp;
}
/**
 * ucShellNeedWriteback
 * Author qiuxf
 * @param c       input char
 * @return none
 */
static uint8_t ucShellNeedWriteback(char c)
{
    /*control char need not writeback*/
	uint8_t ret = SAF_FALSE;
	if(('\a' < c) && (c <= '\r'))
	{
		ret = SAF_TRUE;
	}
    else if(c <= CHAR_CTRL_END)
    {
        ret = SAF_FALSE;
    }
    else
    {
        ret = SAF_TRUE;
    }
	return ret;
}

/**
 * ucShellDoCreateMessage
 * Author qiuxf
 * @param input_c       input char
 * @return none
 */
 
#if 1
char *my_strtok ( char *str, const char *delimiters )
{
	
	static char * s_mem = SAF_NULL;
	char *s;
	char const * delim;
	uint8_t stat = 1;
	char *t;

	if( delimiters == SAF_NULL)
	{
		return SAF_NULL;
	}
	if( str == SAF_NULL && s_mem == SAF_NULL) 
	{
		return SAF_NULL;
	}

	if(str != SAF_NULL) 
	{
		s = str;
	}
	else 
	{
		s = s_mem;
	}

	while(stat)
	{
		delim = delimiters;
		while( *delim && *s != *delim)
		{
			delim++;
		}
		
		if(*delim)
		{
			s++;
		}
		else 
		{
			stat=0; 
		}
	}
	s_mem = s;
	while( *s)
	{
		delim = delimiters;
		while( *delim && *s != *delim)
		{
			delim++;
		}
		
		if(*delim)
		{
			*s = '\0';
			t = s_mem;
			s_mem = s+1;
			return t;
		}
		s++;
	}
 
	t = s_mem;
	s_mem = SAF_NULL; 
	return t;
}
#endif
static uint8_t ucShellDoCreateMessage(SHELL_BUF *pbuf, SHELL_MSG_GROUP *pmsg)
{
    char *ptmp = my_strtok((char *)&pbuf->DataBuf[0], (const char *)" ");
    uint8_t ret = SAF_FALSE;
	
    while(ptmp)
    {
        if(pmsg->argc >= SHELL_MAX_ARGC)
        {
            UART_WRITE_STR(ARGC_TO_MORE);
            ret = SAF_FALSE;
            break;
        }
        else
        {
            ;
        }
        if((strlen(ptmp) + 1) <= SHELL_MAX_ARGV_LEN)
        {
            memset(pmsg->argv[pmsg->argc], 0, SHELL_MAX_ARGV_LEN);
            strncpy((char *)pmsg->argv[pmsg->argc], ptmp, SHELL_MAX_ARGV_LEN);
            pmsg->argc++;			
            ptmp = my_strtok(SAF_NULL, (const char *)" ");
			ret = SAF_TRUE;
			if(pmsg->argc == 1)
			{
				ret = ucShellCmdIsExistence(&pmsg->argv[0][0]);
				if(SAF_FALSE == ret)
				{
					UART_WRITE_STR(CMD_INVALID);
					break;
				}
			}
        }
        else
        {
            UART_WRITE_STR(ARGV_TO_LONG);
            ret = SAF_FALSE;
            break;
        }
    }
    return ret;
}

/**
 * Shell_CreateMsgFromRecvBuf
 * Author qiuxf
 * @param input_c       input char
 * @return none
 */
static uint8_t ucShellCreateArgFromRecvBuf(SHELL_BUF *pbuf, SHELL_MSG_GROUP *pmsg)
{
    uint8_t ret = SAF_TRUE;

    if(SAF_NULL == pmsg)
    {
        ret = SAF_FALSE;
    }
	else
	{
		if(0 == pbuf->buf_pt)
		{
			/*only '\n' has been reveived*/
			if(AUTHOR_USER == xShellGetAuthor())
			{
				UART_WRITE_STR(USER_STR);
			}
			else
			{
				UART_WRITE_STR(ROOT_STR);
			}
			ret = SAF_FALSE;
		}
		else
		{
			ret = ucShellDoCreateMessage(pbuf, pmsg);
		}
	}
    return ret;
}

void vShellWriteBack(uint8_t c,uint8_t *singlechar)
{
	if((c == '\r')||(c == '\n'))
	{                
		UART_WRITE_STR(NEW_LINE);             
	}
	else if(c == '\b')
	{
		;
	}
	else
	{
		singlechar[0] = c;
		UART_WRITE_STR(singlechar);
	}
}

void vShellDeleteWriteString(uint8_t cmdlength)
{
	uint8_t singlechar[4] = {0};
	for(uint8_t i = 0; i < cmdlength; i++)
	{
		singlechar[0] = CHAR_BACK_SPACE;
		singlechar[1] = ' ';
		singlechar[2] = CHAR_BACK_SPACE;
		UART_WRITE_STR((char *)singlechar);
	}
}

void vShellWriteString(uint8_t *pStr, uint16_t length)
{	
	(void)length;
	if(pStr != SAF_NULL)
	{
		UART_WRITE_STR((const char *)pStr);
	}
}

void vShellKeyUp(void)
{
	uint8_t cmdindex = s_xCmdRecord.cmdindex;
	if(cmdindex > 0 && cmdindex!=255)
	{
		memset(s_xShellRecvBuf.DataBuf, 0, sizeof(s_xShellRecvBuf.DataBuf));
		memcpy(&s_xShellRecvBuf,&s_xCmdRecord.cmdbuf[cmdindex],sizeof(SHELL_BUF));
		s_xCmdRecord.cmdindex--;
	}
	else
	{
		memset(s_xShellRecvBuf.DataBuf, 0, sizeof(s_xShellRecvBuf.DataBuf));
		memcpy(&s_xShellRecvBuf,&s_xCmdRecord.cmdbuf[0],sizeof(SHELL_BUF));
	}
	vShellDeleteWriteString(s_xCmdRecord.curcmdlength);
	vShellWriteString(s_xShellRecvBuf.DataBuf,s_xShellRecvBuf.buf_pt);
	s_xCmdRecord.curcmdlength = s_xShellRecvBuf.buf_pt;
}

void vShellKeyDown(void)
{
	uint8_t cmdindex = s_xCmdRecord.cmdindex + 1;
	if(cmdindex < s_xCmdRecord.cmdnum)
	{
		memset(s_xShellRecvBuf.DataBuf, 0, sizeof(s_xShellRecvBuf.DataBuf));
		memcpy(&s_xShellRecvBuf,&s_xCmdRecord.cmdbuf[cmdindex],sizeof(SHELL_BUF));
		s_xCmdRecord.cmdindex = s_xCmdRecord.cmdindex + 1;
	}
	else
	{
		memset(s_xShellRecvBuf.DataBuf, 0, sizeof(s_xShellRecvBuf.DataBuf));
		memcpy(&s_xShellRecvBuf,&s_xCmdRecord.cmdbuf[4],sizeof(SHELL_BUF));
		s_xCmdRecord.cmdindex = s_xCmdRecord.cmdnum - 1;
	}
	vShellDeleteWriteString(s_xCmdRecord.curcmdlength);
	vShellWriteString((uint8_t *)&s_xShellRecvBuf.DataBuf,s_xShellRecvBuf.buf_pt);
	s_xCmdRecord.curcmdlength = s_xShellRecvBuf.buf_pt;
}



uint8_t ucShellChangeLine()
{
	uint8_t ret = SAF_FALSE;
	s_xCmdRecord.curcmdlength = 0;
	if(SAF_TRUE == ucShellCreateArgFromRecvBuf(&s_xShellRecvBuf, &s_xShellMsgGrp))
	{
		ret = SAF_TRUE;
	}
	else
	{
		vShellClearMsgBuf();
	}
	/*Clear buf*/
	s_xShellRecvBuf.buf_pt = 0;
	memset(s_xShellRecvBuf.DataBuf, 0, sizeof(s_xShellRecvBuf.DataBuf));
	return ret;
}
void vShellCmdRecord()
{
	uint8_t cmdnum = 0;
	cmdnum = s_xCmdRecord.cmdnum;
	SHELL_BUF tempbuf[SHELL_MAX_CMD] = {0};

	if((0 != strncmp((const char *)&s_xCmdRecord.cmdbuf[cmdnum-1],(const char *)&s_xShellRecvBuf,sizeof(SHELL_BUF))) && (s_xShellRecvBuf.buf_pt > 0))
	{
		if(SHELL_MAX_CMD > cmdnum)
		{
			memset(&s_xCmdRecord.cmdbuf[cmdnum],0,SHELL_RECV_SIZE);
			memcpy(&s_xCmdRecord.cmdbuf[cmdnum],&s_xShellRecvBuf,sizeof(SHELL_BUF));
			s_xCmdRecord.cmdnum++;
		}
		else
		{
			memset(tempbuf,0,(5*sizeof(SHELL_BUF)));
			memcpy(tempbuf,&s_xCmdRecord.cmdbuf[1],(4*sizeof(SHELL_BUF)));
			memset(&s_xCmdRecord,0,sizeof(ShellCmdRecord_t));
			memcpy(&s_xCmdRecord.cmdbuf[0],tempbuf,(4*sizeof(SHELL_BUF)));
			memcpy(&s_xCmdRecord.cmdbuf[4],&s_xShellRecvBuf,sizeof(SHELL_BUF));
			s_xCmdRecord.cmdnum = 5;	
		}
	}
	s_xCmdRecord.cmdindex = s_xCmdRecord.cmdnum - 1;
}


void vShellBackSpace(uint8_t c,uint8_t *singlechar)
{
	if(s_xShellRecvBuf.buf_pt > 0)
	{
		singlechar[0] = c;
		singlechar[1] = ' ';
		singlechar[2] = c;
		UART_WRITE_STR(singlechar);		/*write back*/

		s_xShellRecvBuf.DataBuf[s_xShellRecvBuf.buf_pt - 1] = 0;
		s_xShellRecvBuf.buf_pt--;
	}
	else
	{
		; /*no data no process*/
	}

	return;
}

void vShellOtherCharacter(uint8_t c)
{
	if(s_xShellRecvBuf.buf_pt < SHELL_MAX_ARGV_LEN)
	{
		s_xShellRecvBuf.DataBuf[s_xShellRecvBuf.buf_pt] = c;
		s_xShellRecvBuf.buf_pt++;
	}
	else
	{
		s_xShellRecvBuf.buf_pt = 0;
		memset(s_xShellRecvBuf.DataBuf, 0, sizeof(s_xShellRecvBuf.DataBuf));
	}
}
/**
 * ucShellCharIntProc
 * Author qiuxf
 * @param input_c       input char
 * @return none
 */
uint8_t ucShellCharIntProc(uint8_t c)
{
    SHELL_STATE status = xShellGetStatus();
	uint8_t singlechar[4] = {0};
	uint8_t ret = SAF_FALSE;
	memset(singlechar, 0, sizeof(singlechar));
    if(SHELL_BUSY != status)
    {
        if(SAF_TRUE == ucShellNeedWriteback(c))
        {
            /*write back received char*/
			vShellWriteBack(c,singlechar);
            /*not control char*/
            if((c == CHAR_CHANGE_LINE) || (c == CHAR_ENTER))
            {
                /*receive command*/
				vShellCmdRecord();
                ret = ucShellChangeLine();
            }
            else if(CHAR_BACK_SPACE == c)
            {
				vShellBackSpace(c,singlechar);
            }
            else
            {
                vShellOtherCharacter(c);
            }
        }
        else
        {
            ;/* control char process*/
        }
    }
    else
    {
		/*shell busy only proc control char*/
    	vShellCtrlProcess((uint8_t)c);
    }
    return ret;
}

#if 0
void Shell_Uart_Password_Check(void)
{	
	g_xUartPasswordFlash = (*((uint64_t*)JTAG_PWD_ADDR));
	
	memcpy(g_axUartPasswordData,(char*)JTAG_PWD_ADDR,UART_PASSWORD_SIZE);
	
	//Shell_Printk("g_xUartPasswordFlash = %016llx\r\n",g_xUartPasswordFlash);
	//Shell_Printk("%s\r\n",g_axUartPasswordData);
	if((UART_PASSWORD_FF == g_xUartPasswordFlash)||(UART_PASSWORD_00 == g_xUartPasswordFlash))
	{
		vShellSetAuthor(AUTHOR_ROOT);
	}
	else
	{
		vShellSetAuthor(AUTHOR_USER);//need input password
	}
}
#endif
