
#define	_IN_CONSOLE_C
#include "console.h"
#include "serial.h"
#include "trigger.h"
#include "cpuid.h"

//---------------------------------------------------------------------------------------------

int g_useQueue = 1;		// = 0, 不使用队列输出，同步等待串口发送完成。= 1，使用队列输入输出

//---------------------------------------------------------------------------------------------
void SetConsoleOutType(int type)
{
	if (type != 0)
	{
		g_useQueue = 1;
	}
	else
	{
		g_useQueue = 0;
	}
}

//---------------------------------------------------------------------------------------------

int	SendData(u8 * pDatBuf, int len)
{
	if (g_useQueue == 1)
	{
#if (CONSOLE_PORT == COMM_USART1)
		return Usart1SendData(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART2)
		return Usart2SendData(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART3)
		return Usart3SendData(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART4)
		return Usart4SendData(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART5)
		return Usart5SendData(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART6)
		return Usart6SendData(pDatBuf, len);
#else
		return 0;
#endif
	}
	else
	{
#if (CONSOLE_PORT == COMM_USART1)
		return Usart1SendDataSync(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART2)
		return Usart2SendDataSync(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART3)
		return Usart3SendDataSync(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART4)
		return Usart4SendDataSync(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART5)
		return Usart5SendDataSync(pDatBuf, len);
#elif (CONSOLE_PORT == COMM_USART6)
		return Usart6SendDataSync(pDatBuf, len);
#else
		return 0;
#endif
	}
}

int ResvData(u8 * pDat, int expectLen)
{
	if (g_useQueue == 1)
	{
#if (CONSOLE_PORT == COMM_USART1)
		return Usart1GetData(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART2)
		return Usart2GetData(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART3)
		return Usart3GetData(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART4)
		return Usart4GetData(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART5)
		return Usart5GetData(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART6)
		return Usart6GetData(pDat, expectLen);
#else
		return 0;
#endif
	}
	else
	{
#if (CONSOLE_PORT == COMM_USART1)
		return Usart1GetDataSync(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART2)
		return Usart2GetDataSync(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART3)
		return Usart3GetDataSync(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART4)
		return Usart4GetDataSync(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART5)
		return Usart5GetDataSync(pDat, expectLen);
#elif (CONSOLE_PORT == COMM_USART6)
		return Usart6GetDataSync(pDat, expectLen);
#else
		return 0;
#endif
	}
}

// 串口选择
#if (CONSOLE_PORT == COMM_USART1)

#define	INIT_USART		InitUsart1

#elif (CONSOLE_PORT == COMM_USART2)

#define	INIT_USART		InitUsart2

#elif (CONSOLE_PORT == COMM_USART3)

#define	INIT_USART		InitUsart3

#elif (CONSOLE_PORT == COMM_USART4)

#define	INIT_USART		InitUsart4

#elif (CONSOLE_PORT == COMM_USART5)

#define	INIT_USART		InitUsart5

#elif (CONSOLE_PORT == COMM_USART6)

#define	INIT_USART		InitUsart6

#else

#endif

//---------------------------------------------------------------------------------------------

// 输入输出支持

#include <stdio.h>
#include <string.h>

#if defined ( __CC_ARM   )

#pragma import(__use_no_semihosting_swi)

//标准库需要的支持函数

struct __FILE
{
	int handle;
};

FILE __stdout;
FILE __stdin;

// 重定义 fputc 函数
int fputc(int ch, FILE *f)
{
	u8 c = (u8)ch;
	SendData(&c, 1);
	return ch; 
}

// 重定义 fgetc 函数
int fgetc(FILE *f)
{
    int ch;
	u8 c;

	ch = ResvData(&c, 1);
	if (ch == 1)
	{
#if (0)			// 回显
		SendData(&c, 1);
#endif
		return c;
	}

	return -1;
}

int ferror(FILE *f)
{
  // 添加代码
  return EOF;
}


void _ttywrch(int ch)
{
	u8 c = (u8)ch;
	SendData(&c, 1);
}

void _sys_exit(int return_code)
{
	while (1);
}

#define	GETCHAR	getchar
#define	PUTCHAR	putchar

#elif defined   (  __GNUC__  )

int __io_putchar(int ch)
{
	u8 c;
	c = ch;
  SendData(&c, 1);
  return ch;
}

int __io_getchar(void)
{
    int ch;
	u8 c;

	ch = ResvData(&c, 1);
	if (ch == 1)
	{
		ch = (int)c;
		return ch;
	}
	return 0;
}

int _read(int file, char *ptr, int len)
{
	int rslt;
	rslt = ResvData((u8*)ptr, len);
	return rslt;
}

int _write(int file, char *ptr, int len)
{
	SendData((u8*)ptr, len);
	return len;
}

#define	PUTCHAR	__io_putchar
#define	GETCHAR	__io_getchar

#endif


int PutChar(int ch)
{
	return PUTCHAR(ch);
}
int GetChar(void)
{
	return GETCHAR();
}


//---------------------------------------------------------------------------------------------


typedef struct
{
	int pause;					// 暂停
	int newCmd;					// 新命令标志
	int cmdExec;				// 命令执行标志
	int cancel;					// 请求退出执行标志
	char command[MAX_CMD_LINE];	// 命令行内容

	int cmdInCtrl;				// 控制命令状态
	int cmdPointer;				// 命令行指针
	int cmdLen;					// 命令长度
	char cmdBuf[MAX_CMD_LINE];	// 命令行缓存
}CmdLine;

CmdLine g_cmdLine;


//---------------------------------------------------------------------------------------------
int IsNewCommand(void)
{
	return g_cmdLine.newCmd;
}

int LockExecAndGetCmdStr(char*pBuf)
{
	int len;
	EnterCritical();
	len = g_cmdLine.cmdLen;
	g_cmdLine.cmdExec = 1;
	g_cmdLine.newCmd = 0;
	ExitCritical();

	memcpy(pBuf, g_cmdLine.command, len);

	return len;
}

void UnlockExec(void)
{
	g_cmdLine.cmdExec = 0;
}

void SetPauseStatus(int sta)
{
	if (sta != 0)
	{
		g_cmdLine.pause = 1;
	}
	else
	{
		g_cmdLine.pause = 0;
	}
}

//---------------------------------------------------------------------------------------------
// 循环队列保存历史命令

#define	HISTORY_CMD_NUM		10		// 历史命令存储个数

char g_cmdHistory[HISTORY_CMD_NUM][MAX_CMD_LINE];
int g_cmdHisIdx = 0;	// 历史命令指针
int g_cmdHisNum = 0;	// 历史命令个数
int g_cmdHisSer = -1;	// 历史命令遍历

int g_cursorNum = 0;	// 20220412

void InitHistory(void)
{
	g_cmdHisIdx = 0;	// 历史命令指针
	g_cmdHisNum = 0;	// 历史命令个数
	g_cmdHisSer = -1;	// 历史命令遍历

	g_cursorNum = 0;

	memset(g_cmdHistory, 0, HISTORY_CMD_NUM*MAX_CMD_LINE);
}

void AddNewCmdToHistory(char * pCmd)
{
	if (pCmd != NULL)
	{
		// 判断当前命令是否已经存放在历史命令中,如果已存放,将其提取到队列尾部
		for (int i = 0; i < g_cmdHisNum; i++)
		{
			if (strcmp(&(g_cmdHistory[i][0]), pCmd) == 0)	// 已存放
			{
				int temp1, temp2;
				int count;
				// 计算提取到队列尾部所需次数
				if (i >= g_cmdHisIdx)
				{
					count = g_cmdHisNum - (i - g_cmdHisIdx);
				}
				else
				{
					count = g_cmdHisIdx - i;
				}
				count--;
				// 提取过程
				for (int j = 0; j < count; j++)
				{
					temp1 = i + j;
					temp2 = temp1 + 1;
					if (temp1 >= g_cmdHisNum)
					{
						temp1 -= g_cmdHisNum;
					}
					if (temp2 >= g_cmdHisNum)
					{
						temp2 -= g_cmdHisNum;
					}
					memset(&(g_cmdHistory[temp1][0]), 0, MAX_CMD_LINE);
					strcpy(&(g_cmdHistory[temp1][0]), &(g_cmdHistory[temp2][0]));
					if (j == (count - 1))
					{
						memset(&(g_cmdHistory[temp2][0]), 0, MAX_CMD_LINE);
						strcpy(&(g_cmdHistory[temp2][0]), pCmd);
					}
				}

				return;
			}
		}

		if (g_cmdHisIdx >= HISTORY_CMD_NUM)
		{
			g_cmdHisIdx = 0;
		}
		memset(&(g_cmdHistory[g_cmdHisIdx][0]), 0, MAX_CMD_LINE);
		strcpy(&(g_cmdHistory[g_cmdHisIdx][0]), pCmd);
		g_cmdHisIdx++;
		if (g_cmdHisNum < HISTORY_CMD_NUM)
		{
			g_cmdHisNum++;
		}
	}
}

// 上光标处理
void UpCursorProc(void)
{
	if (g_cursorNum > 0)
	{
		g_cursorNum--;
	}
	else
	{
		return;
	}

	g_cmdHisSer--;
	if (g_cmdHisSer < 0)
	{
		g_cmdHisSer = g_cmdHisNum - 1;
	}

	if (1)
	{
		// 输出退格,清空所有
		while (g_cmdLine.cmdPointer != 0)
		{
			PUTCHAR(0x08);		// 输出退格
			PUTCHAR(' ');		// 输出空格
			PUTCHAR(0x08);		// 输出退格
			g_cmdLine.cmdPointer--;
		}

		// 显示历史命令
		if (g_cmdLine.cmdExec == 0 && g_cmdLine.newCmd == 0)
		{
			char ch;
			for (int i = 0; i < MAX_CMD_LINE; i++)
			{
				ch = g_cmdHistory[g_cmdHisSer][i];
				if (ch > 0x1F && ch < 0x7F)		// 添加字符到命令行中
				{
					if (g_cmdLine.cmdPointer < MAX_CMD_LINE-1)
					{
						PUTCHAR(ch);	// 回显示
						g_cmdLine.cmdBuf[g_cmdLine.cmdPointer] = ch;
						g_cmdLine.cmdPointer++;
					}
				}
			}
		}
		else
		{
			g_cmdLine.cmdPointer = 0;
			g_cmdLine.cmdBuf[0] = 0;
		}
	}
}

// 下光标处理
void DownCursorProc(void)
{
	if (g_cursorNum < g_cmdHisNum)
	{
		g_cursorNum++;
	}
	else
	{
		return;
	}

	g_cmdHisSer++;

	if (g_cursorNum == g_cmdHisNum)
	{
		// 输出退格,清空所有
		while (g_cmdLine.cmdPointer != 0)
		{
			PUTCHAR(0x08);		// 输出退格
			PUTCHAR(' ');		// 输出空格
			PUTCHAR(0x08);		// 输出退格
			g_cmdLine.cmdPointer--;
		}
		return;
	}

	if (g_cmdHisSer >= g_cmdHisNum)
	{
		g_cmdHisSer = 0;
	}

	if (1)
	{
		// 输出退格,清空所有
		while (g_cmdLine.cmdPointer != 0)
		{
			PUTCHAR(0x08);		// 输出退格
			PUTCHAR(' ');		// 输出空格
			PUTCHAR(0x08);		// 输出退格
			g_cmdLine.cmdPointer--;
		}

		// 显示历史命令
		if (g_cmdLine.cmdExec == 0 && g_cmdLine.newCmd == 0)
		{
			char ch;
			for (int i = 0; i < MAX_CMD_LINE; i++)
			{
				ch = g_cmdHistory[g_cmdHisSer][i];
				if (ch > 0x1F && ch < 0x7F)		// 添加字符到命令行中
				{
					if (g_cmdLine.cmdPointer < MAX_CMD_LINE-1)
					{
						PUTCHAR(ch);	// 回显示
						g_cmdLine.cmdBuf[g_cmdLine.cmdPointer] = ch;
						g_cmdLine.cmdPointer++;
					}
				}
			}
		}
		else
		{
			g_cmdLine.cmdPointer = 0;
			g_cmdLine.cmdBuf[0] = 0;
		}
	}
}

//---------------------------------------------------------------------------------------------

void OutNewCmdLine(void)
{
	g_cmdLine.cmdPointer = 0;		// 命令行指针
	g_cmdLine.cmdLen = 0;			// 命令长度

	PUTCHAR(0x0D);			// 回车
	PUTCHAR(0x0A);			// 换行
	PUTCHAR('C');
	PUTCHAR('M');
	PUTCHAR('D');
	PUTCHAR(':');
	PUTCHAR('>');
}

//---------------------------------------------------------------------------------------------

void InitConsole(void)
{
	InitTrigger();
#if (CONSOLE_PORT != COMM_NONE)
	INIT_USART(B115200, '8', 'N', '1');
#endif

	AddTriggerToList(10, ConsoleCmdScan, NULL);		// 10ms 响应控制台

	printf("\x0c");					// 超级终端清屏
    printf("\033[1;40;32m");		// 设置超级终端背景为黑色，字符为绿色
	printf("\x0c");					// 超级终端清屏

	memset(&g_cmdLine, 0, sizeof(CmdLine));

	g_useQueue = 1;		// = 0, 不使用队列输出，同步等待串口发送完成。= 1，使用队列输入输出

	InitHistory();
}

// 定时器处理回显和检测命令输入
void ConsoleCmdScan()
{
	int ch;

	if (g_cmdLine.pause != 0)
	{
		return;
	}

	ch = GETCHAR();
	if (ch < 0)
	{
		g_cmdLine.cmdInCtrl = 0;
		return;
	}

	// 命令处理
	switch(ch)
	{
	case 0x00:  //    NUL    (Null char)
	case 0x01:  //    SOH    (Start of Header) 发送文件首
	case 0x02:  //    STX    (Start of Text) 文本开始
		ch = ch;
		break;
	case 0x03:  //    ETX    (End of Text) 文本尾
		if (g_cmdLine.cmdExec == TRUE)	// ctrl+C 为终止命令
		{
			OutNewCmdLine();
			g_cmdLine.cancel = 1;
		}
		break;
	case 0x04:  //    EOT    (End of Transmission) 发送结束
	case 0x05:  //    ENQ    (Enquiry)
	case 0x06:  //    ACK    (Acknowledgment) 确认
	case 0x07:  //    BEL    (Bell) 蜂鸣
		ch = ch;
		break;
	case 0x08:  //     BS    (Backspace) 退格
		if (g_cmdLine.cmdPointer != 0)
		{
			PUTCHAR(0x08);		// 输出退格
			PUTCHAR(' ');		// 输出空格
			PUTCHAR(0x08);		// 输出退格
			g_cmdLine.cmdPointer--;
		}
		break;
	case 0x09:  //     HT    (Horizontal Tab)
		// 自动命令补全......
		break;
	case 0x0A:  //     LF    (Line Feed) 换行
	case 0x0B:  //     VT    (Vertical Tab)
	case 0x0C:  //     FF    (Form Feed) 换页/清屏
		ch = ch;
		break;
	case 0x0D:  //     CR    (Carriage Return) 回车
	{
		if (g_cmdLine.newCmd == 0 && g_cmdLine.cmdExec == 0)
		{
			PUTCHAR(0x0D);			// 增加回车
			PUTCHAR(0x0A);			// 增加换行
			g_cmdLine.cmdBuf[g_cmdLine.cmdPointer] = 0;		// 字符串尾
			g_cmdLine.cmdLen = g_cmdLine.cmdPointer;		// 长度
			strcpy(g_cmdLine.command, g_cmdLine.cmdBuf);	// 拷贝新命令
			if (g_cmdLine.cmdLen != 0)	// 20220412 命令长度不为0,才存入历史命令
			{
				AddNewCmdToHistory(g_cmdLine.cmdBuf);			// 命令行内容
			}
			g_cmdHisSer = g_cmdHisIdx;		// 20220412
			g_cursorNum = g_cmdHisNum;
			g_cmdLine.newCmd = 1;	// 新命令
		}
		break;
	}
	case 0x0E:  //     SO    (Shift Out)SHIFT  松开
	case 0x0F:  //     SI    (Shift In) 按下
	case 0x10:  //    DLE    (Data Link Escape) 清除
	case 0x11:  //    DC1    (XON) (Device Control 1)
	case 0x12:  //    DC2    (Device Control 2)
	case 0x13:  //    DC3    (XOFF)(Device Control 3)
	case 0x14:  //    DC4    (Device Control 4)
	case 0x15:  //    NAK    (Negative Acknowledgement)
	case 0x16:  //    SYN    (Synchronous Idle)
	case 0x17:  //    ETB    (End of Trans. Block)
	case 0x18:  //    CAN    (Cancel)
	case 0x19:  //     EM    (End of Medium)
	case 0x1A:  //    SUB    (Substitute)		// pause 键
		ch = ch;
		break;
	case 0x1B:  //    ESC    (Escape) 退出
		g_cmdLine.cmdInCtrl = 1;
		break;
	case 0x1C:  //     FS    (File Separator)
	case 0x1D:  //     GS    (Group Separator)
	case 0x1E:  //     RS    (Request to Send/Record Separator)
	case 0x1F:  //     US    (Unit Separator)
		ch = ch;
		break;
	case 0x7F:
		if (g_cmdLine.cmdPointer != 0)
		{
			PUTCHAR(0x08);		// 输出退格
			PUTCHAR(' ');		// 输出空格
			PUTCHAR(0x08);		// 输出退格
			g_cmdLine.cmdPointer--;
			if (g_cmdLine.cmdLen != 0)
			{
				g_cmdLine.cmdLen--;
			}
		}
		break;
	default:
		break;
	}

	if (ch != 0x1B && g_cmdLine.cmdInCtrl != 0)
	{
		if (g_cmdLine.cmdInCtrl == 1 && ch == 0x5B)
		{
			ch = GETCHAR();
			switch(ch)
			{
			case 0x41:		// 上光标
				ch = 'u';
				// 上翻历史命令记录
				UpCursorProc();	// 20220412
				break;
			case 0x42:		// 下光标
				ch = 'd';
				DownCursorProc();			// 下翻历史命令记录
				break;
			case 0x43:		// 右光标
				ch = 'r';
				break;
			case 0x44:		// 左光标
				ch = 'l';
				break;
			case 0x31:
			{
				ch = GETCHAR();
				if (ch == 0x7E)		// HOME 键
				{
					ch = 'h';
				}
				else if (ch == 0x31)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F1 键
					{
						ch = '1';
					}
				}
				else if (ch == 0x32)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F2 键
					{
						ch = '2';
					}
				}
				else if (ch == 0x33)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F3 键
					{
						ch = '3';
					}
				}
				else if (ch == 0x34)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F4 键
					{
						ch = '4';
					}
				}
				else if (ch == 0x35)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F5 键
					{
						ch = '5';
					}
				}
				else if (ch == 0x37)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F6 键
					{
						ch = '6';
					}
				}
				else if (ch == 0x38)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F7 键
					{
						ch = '7';
					}
				}
				else if (ch == 0x39)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F8 键
					{
						ch = '8';
					}
				}
				break;
			}
			case 0x32:
			{
				ch = GETCHAR();
				if (ch == 0x7E)			// INS 键
				{
					ch = 'i';
				}
				else if (ch == 0x30)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F9 键
					{
						ch = '9';
					}
				}
				else if (ch == 0x31)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F10 键
					{
						ch = 'a';
					}
				}
				else if (ch == 0x33)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F11 键
					{
						ch = 'b';
					}
				}
				else if (ch == 0x34)
				{
					ch = GETCHAR();
					if (ch == 0x7E)		// F12 键
					{
						ch = 'c';
					}
				}
				break;
			}
			case 0x33:
				ch = GETCHAR();
				if (ch == 0x7E)			// DEL 键
				{
					ch = 'd';
				}
				break;
			case 0x34:
				ch = GETCHAR();
				if (ch == 0x7E)			// END 键
				{
					ch = 'e';
				}
				break;
			case 0x35:
				ch = GETCHAR();
				if (ch == 0x7E)			// PAGE UP 键
				{
					ch = 'u';
				}
				break;
			case 0x36:
				ch = GETCHAR();
				if (ch == 0x7E)			// PAGE DOWN 键
				{
					ch = 'd';
				}
				break;
			default:
				g_cmdLine.cmdInCtrl = 0;
				break;
			}
		}
		else
		{
			g_cmdLine.cmdInCtrl = 0;
		}

		if (g_cmdLine.cmdInCtrl != 0)
		{
			ch = 0;
			g_cmdLine.cmdInCtrl = 0;
		}
	}

	if (g_cmdLine.cmdExec == 0 && g_cmdLine.newCmd == 0)
	{
		if (ch > 0x1F && ch < 0x7F)		// 添加字符到命令行中
		{
			if (g_cmdLine.cmdPointer < MAX_CMD_LINE-1)
			{
				PUTCHAR(ch);	// 回显示

				g_cmdLine.cmdBuf[g_cmdLine.cmdPointer] = ch;
				g_cmdLine.cmdPointer++;
			}
		}
	}
	else
	{
		g_cmdLine.cmdPointer = 0;
		g_cmdLine.cmdBuf[0] = 0;
	}
}


int IsConsoleCancel(void)
{
	int rslt = g_cmdLine.cancel;
	g_cmdLine.cancel = 0;
	return rslt;
}

// 20220412 提供一个外部接口,用于获取存储的历史命令
int GetHistoryCmd(int hisIdx, char * pch)
{
	if (hisIdx < 0 || hisIdx > HISTORY_CMD_NUM || pch == NULL)
	{
		return -1;
	}

	strncpy(pch, &(g_cmdHistory[hisIdx][0]), MAX_CMD_LINE);

	return 0;
}

int GetHistoryNum(void)
{
	return g_cmdHisNum;
}

int GetHistoryMaxNum(void)
{
	return HISTORY_CMD_NUM;
}

int GetHistoryIdx(void)
{
	return g_cmdHisIdx;
}
//---------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------


