一个简单的通用命令工具(可以使用串口或其它的任意通信接口)

一直以来都是使用串口进行调试,非常方便,最近将命令工具进行了重新,将支持的命令与通信接口,处理等进行了分离,可移植性更强,并且不依赖通信接口,可以使用串口,网口,433等等通信接口,只需要实现一个printf类似的函数即可,因为串口是字符流,不像其它通信接口,一次传输一个块,因此在使用非串口的时候,建议发送的时候将数据用sprntf缓存到一个buff中,一次传输。


//sys_cmd.c

/*************************************************************************************************************
 * 文件名:			sys_cmd.c
 * 功能:			自定义的系统命令接口
 * 作者:			[email protected]
 * 创建时间:		2014-06-07
 * 最后修改时间:	2018-01-14
 * 详细:			分离底层,将命令缓冲区与接口句柄进行分离,并且命令可以自行控制添加,增加命令是否显示状态
*************************************************************************************************************/	
#include "SYSTEM.H"
#include "sys_cmd.h"
#include "string.h"

//命令缓冲区是否初始化ID
#define SYS_CMD_BUFF_INIT_ID		0x86877F9D

//管理密码状态
#define PASSWORD_STR 	"123456"
static u32 sg_PASSWORD_HASH=0;


u32 BKDRHash(const char *str);							//BKDR 哈希算法
void SYS_CMD_Help(SYS_CMD_HANDLE *pHandle, char *pStr);	//帮助命令
void SYS_CMD_Exit(SYS_CMD_HANDLE *pHandle, char *pStr);	//退出命令


//支持的命令定义
const SYS_CMD_TYPE  CMD_GET_HELP		=	{"?", SYS_CMD_Help, "\t\t帮助", TRUE};						//帮助
const SYS_CMD_TYPE  CMD_EXIT			=	{"EXIT", SYS_CMD_Exit, "\t\t退出,再次输入需要密码", TRUE};	//退出登录
		

/*************************************************************************************************************************
*函数        	:	void SYS_CMD_Init(SYS_CMD_BUFF_TYPE *pCmdBuff)
*功能        	:	初始化系统命令(会初始化系统命令缓冲区,并添加帮助命令)
*参数        	:	pCmdBuff:系统命令缓冲区
*返回        	:	无
*依赖        	:	无
*作者        	:	[email protected]
*时间        	:	2018-01-14
*最后修改时间	:	2018-01-14
*说明        	:	
*************************************************************************************************************************/
void SYS_CMD_Init(SYS_CMD_BUFF_TYPE *pCmdBuff)
{
	if(sg_PASSWORD_HASH == 0) sg_PASSWORD_HASH = BKDRHash(PASSWORD_STR);	//初始化密码的哈希值
	pCmdBuff->CmdCount = 0;													//清空命令
	pCmdBuff->InitId = 0;													//初始化为无效状态
	SYS_CMD_Add(pCmdBuff, &CMD_GET_HELP);									//添加帮助命令
	SYS_CMD_Add(pCmdBuff, &CMD_EXIT);										//添加退出命令
}


/*************************************************************************************************************************
*函数        	:	bool SYS_CMD_Add(SYS_CMD_BUFF_TYPE *pCmdBuff, const SYS_CMD_TYPE *pCmd)
*功能        	:	添加一个命令到命令缓冲区中
*参数        	:	pCmdBuff:当前使用的命令缓冲区指针;pCmd:当前要添加的命令
*返回        	:	TRUE:添加成功;FALSE:添加失败
*依赖        	:	无
*作者        	:	[email protected]
*时间        	:	2018-01-14
*最后修改时间	:	2018-01-14
*说明        	:	用于添加并初始化命令缓冲区
*************************************************************************************************************************/
bool SYS_CMD_Add(SYS_CMD_BUFF_TYPE *pCmdBuff, const SYS_CMD_TYPE *pCmd)
{
	if(pCmdBuff->InitId != SYS_CMD_BUFF_INIT_ID)				//没有被初始化过
	{
		pCmdBuff->CmdCount = 0;									//命令数量清零
		pCmdBuff->InitId = SYS_CMD_BUFF_INIT_ID;				//初始化ID有效
	}
	if(pCmdBuff->CmdCount >= SYS_MAX_CMD_COUNT) return FALSE;	//命令已经满了,无法添加了
	pCmdBuff->CmdPointerBuff[pCmdBuff->CmdCount] = pCmd;		//添加命令到命令缓冲区中
	pCmdBuff->CmdBKDHashBuff[pCmdBuff->CmdCount] = BKDRHash(pCmd->pCmdStr);	//计算当前命令的哈希值
	pCmdBuff->CmdCount ++;										//命令数量增加
	
	return TRUE;
}




/*************************************************************************************************************************
*函数        	:	void SYS_CMD_InterfaceInit(SYS_CMD_HANDLE *pHandle, int (*DataPrintf)(const char * format, ...))
*功能        	:	初始化通讯句柄
*参数        	:	pHandle:句柄;DataPrintf:字符串打印接口
*返回        	:	无
*依赖        	:	底层
*作者        	:	[email protected]
*时间        	:	2018-01-14
*最后修改时间	:	2018-01-14
*说明        	:	用于初始化底层通讯接口
*************************************************************************************************************************/
void SYS_CMD_InterfaceInit(SYS_CMD_HANDLE *pHandle, int (*DataPrintf)(const char * format, ...))
{
	pHandle->pCmdBuff = NULL;				//初始化命令缓冲区为无效状态
	pHandle->DataPrintf = DataPrintf;		//初始化通讯接口
	pHandle->isInputPassword = FALSE;		//密码输入状态无效
}


/*************************************************************************************************************************
*函数        	:	void SYS_CMD_Help(SYS_CMD_HANDLE *pHandle,char *pStr)
*功能        	:	帮助命令
*参数        	:	pHandle:句柄;pStr:当前输入的命令字符串
*返回        	:	无
*依赖        	:	底层
*作者        	:	[email protected]
*时间        	:	2018-01-14
*最后修改时间	:	2018-01-14
*说明        	:	用于初始化底层通讯接口
*************************************************************************************************************************/
void SYS_CMD_Help(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	u16 i;
	u16 cnt = 0;
	
	if(pHandle->pCmdBuff == NULL) return;
	pHandle->DataPrintf("\r\n\r\n=============================命令列表=============================\r\n");
	pHandle->DataPrintf("[编号]\t[命令]\t\t\t[功能]\r\n\r\n");
	for(i = 0;i < ((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdCount;i ++)
	{
		if(((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdPointerBuff[i]->isShow == TRUE)				//需要显示才进行打印
		{
			cnt ++;
			pHandle->DataPrintf("  %02d\t%s\t%s\r\n",cnt,((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdPointerBuff[i]->pCmdStr,((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdPointerBuff[i]->pFunExp);
		}
		
	}
	pHandle->DataPrintf("===================================================================\r\n");
	pHandle->DataPrintf("\r\n");
}

/*************************************************************************************************************************
*函数        	:	void SYS_CMD_Exit(SYS_CMD_HANDLE *pHandle,char *pStr)
*功能        	:	退出命令
*参数        	:	pHandle:句柄;pStr:当前输入的命令字符串
*返回        	:	无
*依赖        	:	底层
*作者        	:	[email protected]
*时间        	:	2018-01-14
*最后修改时间	:	2018-01-14
*说明        	:	用于退出命令,退出后下次必须输入密码才能使用
*************************************************************************************************************************/
void SYS_CMD_Exit(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	pHandle->isInputPassword = FALSE;	//输入密码无效
	pHandle->DataPrintf("[退出登录成功]:下次需要输入密码才能操作!\r\n");
}


/*************************************************************************************************************************
*函数        	:	bool SYS_CMD_Handle(SYS_CMD_HANDLE *pHandle, SYS_CMD_BUFF_TYPE *pCmdBuff, char *pStr)
*功能        	:	系统命令处理
*参数        	:	pHandle:句柄;pCmdBuff:当前所使用的命令缓冲区;pStr:当前输入的命令字符串
*返回        	:	TRUE:命令有效;FALSE:无效的命令
*依赖        	:	底层
*作者        	:	[email protected]
*时间        	:	2018-01-14
*最后修改时间	:	2018-01-14
*说明        	:	用于核心的命令处理函数
*************************************************************************************************************************/
bool SYS_CMD_Handle(SYS_CMD_HANDLE *pHandle, SYS_CMD_BUFF_TYPE *pCmdBuff, char *pStr)
{
	u8 len;
	u8 i;
	u32 CmdHash;
	char *p;
	
	if(pHandle == NULL || pCmdBuff == NULL || pStr == NULL) return FALSE;
	pHandle->pCmdBuff = pCmdBuff;					//记录当前的命令缓冲区指针
	len = strlen(pStr);
	//检测是否输入过密码
	if(pHandle->isInputPassword==FALSE)				//没有输入过密码
	{
		for(i = 0;i < len;i ++)	
		{
			if((pStr[i]>='a') && (pStr[i]<='z'))	//小写转换为大写
			{
				pStr[i] -= 32;						//变为大写字母
			}
			if((pStr[i] == '\r')||(pStr[i] == '\n'))
			{
				pStr[i] = 0;
				break;
			}
		}
		CmdHash = BKDRHash(pStr);					//计算命令的哈希值
		if(CmdHash == sg_PASSWORD_HASH)
		{
			pHandle->isInputPassword = TRUE;		//密码输入成功
			pHandle->DataPrintf("[密码正确]:可以继续操作!\r\n>");
			return TRUE;
		}
		pHandle->DataPrintf("[密码错误]:请输入管理密码!\r\n>");
		return FALSE;
	}
	
	pHandle->DataPrintf("%s\r\n", pStr);
	if(len > 200)									//检测参数的长度
	{
		pHandle->DataPrintf("[错误]:命令超出长度(>(%d))!\r\n>",200);
		return FALSE;
	}
	//检查命令的结束符-\r\n
	for(i = 0;i < len;i ++)
	{
		if((pStr[i] == '\r')||((pStr[i] == '\n')))
		{
			pStr[i] = 0;
			len = i;
			if(len == 0)
			{
				pHandle->DataPrintf("\r\n>");
				return FALSE;
			}
			break;
		}
	}
	
	//检测是否含有非法字符
	for(i = 0;i < len;i ++)	
	{
		if((pStr[i] < 32) || (pStr[i] > 126))
		{
			pHandle->DataPrintf("[错误]:含有非法字符!\r\n>");
			return FALSE;
		}
		if((pStr[i]>='a') && (pStr[i]<='z'))	//小写转换为大写
		{
			pStr[i] -= 32;						//变为大写字母
		}
	}
	
	p = strstr(pStr,"=");						//搜索等于
	if(p!=NULL)
	{
		p ++;									//跳过==
		len = strlen(p);						//获取命令的参数长度
		if(len > CMD_PARAMETER_STR_LEN)			//检测参数的长度
		{
			pHandle->DataPrintf("[错误]:命令参数超出长度(>(%d))!\r\n>",CMD_PARAMETER_STR_LEN);
			return FALSE;
		}
		strcpy(pHandle->CmdPara,p);				//复制参数
		p[0] = '\0';							//截断命令
	}
	else
	{
		pHandle->CmdPara[0] = 0;				//命令没有参数
	}
	
	CmdHash = BKDRHash(pStr);					//计算命令的哈希值
	//uart_printf("[调试]:%s(0x%X)\r\n",pStr, CmdHash);
	//循环查找命令
	for(i = 0;i < ((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdCount;i ++)
	{
		if(CmdHash == ((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdBKDHashBuff[i])	//判断哈希值是否一样
		{
			//cmd_printf("[解析成功]:!\r\n>");
			((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdPointerBuff[i]->CmdExe(pHandle, pHandle->CmdPara); //执行命令
			break;
		}
	}
	if(i == ((SYS_CMD_BUFF_TYPE *)pHandle->pCmdBuff)->CmdCount)
	{
		pHandle->DataPrintf("[错误]:不支持的命令!\r\n>");
		return FALSE;
	}		
	
	pHandle->DataPrintf(">");
	return TRUE;
}




/*************************************************************************************************************************
*函数        	:	u32 SYS_CMD_StringToDec(char *pStr, u8 NumDigits)
*功能        	:	将10进制样式字符串转换为整型数(必须保证完全为数字字符)
*参数        	:	pStr:字符串起始指针
* 					NumDigits:数字位数,10进制数字位数
*返回        	:	转换后的数字
*依赖        	:	无
*作者        	:	[email protected]
*时间        	:	2013-04-30
*最后修改时间	:	2018-01-14
*说明        	:	比如字符串"1865"转换后为1865,位数为4位
					必须保证完全为数字字符
*************************************************************************************************************************/
u32 SYS_CMD_StringToDec(char *pStr, u8 NumDigits)
{
	u32 temp;
	u32 DEC = 0;
	u8 i;
	u8 j;
	
	NumDigits = (NumDigits > 10) ? 10 : NumDigits;	//最大支持10位10进制数
	
	for(i = 0;i < NumDigits;i ++)
	{
		temp = pStr[i] - '0';
		if(temp > 9)			//只能是数字范围
			return 0;
		for(j = 1;j < (NumDigits - i);j ++)
		{
			temp *= 10;
		}
		DEC += temp;
	}
	return DEC;
}







// BKDR Hash Function  
//BKDR 哈希算法
u32 BKDRHash(const char *str)  
{  
    u32 seed = 131; // 31 131 1313 13131 131313 etc..  
    u32 hash = 0;  
   
    while (*str)  
    {  
        hash = hash * seed + (*str++);  
    }  
   
    //return (hash & 0x7FFFFFFF);  
	return hash;
}








//测试数据是否全部为数字以及空格
bool isStrNumAndSpc(char *pStr, u8 len,u8 SpcNum)
{
	u8 i;
	u8 n = 0;
	
	for(i = 0;i < len;i ++)
	{
		if((pStr[i] < '0')||(pStr[i] > '9'))
		{
			if(pStr[i] == ' ')
			{
				n ++;
				if(n > SpcNum) return FALSE;	//空格过多
			}
			else
				return FALSE;
		}
	}
	
	return TRUE;
}



//测试数据是否全部为数字
bool isStrNum(char *pStr, u8 len)
{
	u8 i;
	
	for(i = 0;i < len;i ++)
	{
		if((pStr[i] < '0')||(pStr[i] > '9'))
		{
				return FALSE;
		}
	}
	
	return TRUE;
}





//测试数据是否全部为字母,数字,'.'
bool isStrAndNum(char *pStr, u8 len)
{
	u8 i;
	
	for(i = 0;i < len;i ++)
	{
		if(((pStr[i] >= '0')&&(pStr[i] <= '9'))||((pStr[i] >= 'A')&&(pStr[i] <= 'Z'))||((pStr[i] >= 'a')&&(pStr[i] <= 'z'))||(pStr[i] == '.'))
		{
		
		}
		else
		{
			return FALSE;
		}
	}
	
	return TRUE;
}







/*************************************************************************************************************
 * 文件名:			sys_cmd.h
 * 功能:			自定义的系统命令接口
 * 作者:			[email protected]
 * 创建时间:		2014-06-07
 * 最后修改时间:	2018-01-14
 * 详细:			分离底层,将命令缓冲区与接口句柄进行分离,并且命令可以自行控制添加,增加命令是否显示状态
*************************************************************************************************************/	
#ifndef __SYS_CMD_H_
#define __SYS_CMD_H_
#include "system.h"


#define CMD_PARAMETER_STR_LEN				24		//限制命令的参数长度,过长会占用过多的内存,请按照实际设置
#define CMD_DEFAULT_COUNT					10		//默认的支持的命令数量,实际数量由SYS_CMD_COUNT决定


#ifndef SYS_CMD_COUNT			//系统文件中定义了数量
#define SYS_MAX_CMD_COUNT		SYS_CMD_COUNT		//最大支持的命令数量
#else
#define SYS_MAX_CMD_COUNT		CMD_DEFAULT_COUNT	//最大支持的命令数量
#endif //SYS_CMD_COUNT

//通信句柄
typedef struct
{
	int (*DataPrintf)(const char * format, ...);		//数据打印接口-尽可能将数据集中到一起进行打印输出
	void *pCmdBuff;										//当前使用的命令缓冲区指针-由于互相包含,因此这个地方将指针声明为空指针
	char CmdPara[CMD_PARAMETER_STR_LEN+4];				//命令参数缓冲区
	bool isInputPassword;								//用于指示是否输入密码
}SYS_CMD_HANDLE;

//系统命令结构
typedef struct
{
	const char *pCmdStr;		//命令字符串
	void(*CmdExe)(SYS_CMD_HANDLE *pHandle, char *);		//命令执行函数
	const char *pFunExp;		//功能说明
	bool isShow;				//是否显示(可以影藏一些特殊命令)
}SYS_CMD_TYPE;

//系统命令集合定义
typedef struct
{
	u32 InitId;												//用于指示是否进行了初始化
	const SYS_CMD_TYPE *CmdPointerBuff[SYS_MAX_CMD_COUNT];	//系统命令指针集合
	u32 CmdBKDHashBuff[SYS_MAX_CMD_COUNT];					//系统命令的哈希值
	u8	CmdCount;											//当前支持的系统命令数量
}SYS_CMD_BUFF_TYPE;



//相关命令接口
void SYS_CMD_Init(SYS_CMD_BUFF_TYPE *pCmdBuff);							//初始化系统命令(会初始化系统命令缓冲区,并添加帮助命令)
bool SYS_CMD_Add(SYS_CMD_BUFF_TYPE *pCmdBuff, const SYS_CMD_TYPE *pCmd);//添加一个命令到命令缓冲区中
void SYS_CMD_InterfaceInit(SYS_CMD_HANDLE *pHandle, int (*DataPrintf)(const char * format, ...));	//初始化通讯句柄
bool SYS_CMD_Handle(SYS_CMD_HANDLE *pHandle, SYS_CMD_BUFF_TYPE *pCmdBuff, char *pStr);				//系统命令处理
//工具命令接口
u32 SYS_CMD_StringToDec(char *pStr, u8 NumDigits);	//字符串转换为整形数
bool isStrNumAndSpc(char *pStr, u8 len,u8 SpcNum);	//测试数据是否全部为数字以及空格
bool isStrAndNum(char *pStr, u8 len);				//测试数据是否全部为字母,数字,'.'
bool isStrNum(char *pStr, u8 len);					//测试数据是否全部为数字



#endif //__SYS_CMD_H_

//命令的实现,以RTC为例

//使能系统命令行
#if SYS_CMD_EN_
#include "sys_cmd.h"
#include "string.h"

const SYS_CMD_TYPE  CMD_GET_TIME		=	{"TIME?", CMD_GetTime, "\t\t获取系统时间", TRUE};
const SYS_CMD_TYPE  CMD_GET_DATE		=	{"DATE?", CMD_GetDate, "\t\t获取系统日期", TRUE};
const SYS_CMD_TYPE  CMD_SET_TIME		=	{"TIME=", CMD_SetTime, "\t\t设置系统时间 如(12:32:54):TIME=12 32 54", TRUE};
const SYS_CMD_TYPE  CMD_SET_DATE		=	{"DATE=", CMD_SetDate, "\t\t设置系统日期 如(2014 6 8):TIME=2014 6 8", TRUE};

//获取时间
void CMD_GetTime(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	RTC_Get();		//更新时间
	pHandle->DataPrintf("[获取时间成功]:%02d:%02d:%02d\r\n",g_timer.hour, g_timer.min, g_timer.sec);
}

//获取日期
void CMD_GetDate(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	RTC_Get();		//更新时间
	pHandle->DataPrintf("[获取日期成功]:%04d-%02d-%02d\r\n",g_timer.year, g_timer.month, g_timer.date);
}

//设置时间
void CMD_SetTime(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	u8 hour,min,sec;
	u8 len;
	char *p;
	u8 num;
	
	len = strlen(pStr);	//获取长度
	if(isStrNumAndSpc(pStr, len, 2) == FALSE)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//小时
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	hour = SYS_CMD_StringToDec(pStr, num);
	if(hour>23)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	
	//分钟
	pStr = p+1;
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	min = SYS_CMD_StringToDec(pStr, num);
	if(min>59)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//秒钟
	pStr = p+1;
	num = strlen(pStr);
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	sec = SYS_CMD_StringToDec(pStr, num);
	if(sec>59)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	
	if(RTC_SetTime(hour, min, sec) == FALSE)
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[时间设置失败]:%02d:%02d:%02d\r\n",g_timer.hour, g_timer.min, g_timer.sec);
	}
	else
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[时间设置成功]:%02d:%02d:%02d\r\n",g_timer.hour, g_timer.min, g_timer.sec);
	}
	
} 


//设置日期
void CMD_SetDate(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	u16 year;
	u8 month, date;
	u8 len;
	char *p;
	u8 num;
	
	len = strlen(pStr);	//获取长度
	if(isStrNumAndSpc(pStr, len, 2) == FALSE)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//年
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 4) || (num == 0))
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	year = SYS_CMD_StringToDec(pStr, num);
	if(year>9999)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	
	//月
	pStr = p+1;
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	month = SYS_CMD_StringToDec(pStr, num);
	if(month>12)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//日
	pStr = p+1;
	num = strlen(pStr);
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	date = SYS_CMD_StringToDec(pStr, num);
	if(date>31)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	

	if(RTC_SetDate(year, month, date) == FALSE)
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[日期设置失败]:%04d-%02d-%02d\r\n",g_timer.year, g_timer.month, g_timer.date);
	}
	else
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[日期设置成功]:%04d-%02d-%02d\r\n",g_timer.year, g_timer.month, g_timer.date);
	}
	
} 


#endif //SYS_CMD_EN_
//命令的声明

//使能系统命令行
#if SYS_CMD_EN_
#include "sys_cmd.h"
#include "string.h"

extern const SYS_CMD_TYPE  CMD_GET_TIME;
extern const SYS_CMD_TYPE  CMD_GET_DATE;
extern const SYS_CMD_TYPE  CMD_SET_TIME;
extern const SYS_CMD_TYPE  CMD_SET_DATE;


//获取时间
void CMD_GetTime(SYS_CMD_HANDLE *pHandle,char *pStr);
//获取日期
void CMD_GetDate(SYS_CMD_HANDLE *pHandle,char *pStr);
//设置时间
void CMD_SetTime(SYS_CMD_HANDLE *pHandle,char *pStr);
//设置日期
void CMD_SetDate(SYS_CMD_HANDLE *pHandle,char *pStr);

#endif //SYS_CMD_EN_


//需要实现的一个通信接口,我直接使用了printf,如果需要使用其它接口,需要自己实现一个 int DataPrintf(const char * format, ...) 函数,结构与printf一样,可以网上找找-下面是一个例子
//调试信息输出-注意单次长度不要超过5K  
int Printf(const char * format, ...)  
{  
    DWORD len;  
    va_list ap;  
  
    
        va_start(ap, format);  
        len = vsnprintf(buff, format, ap);  
        va_end(ap);  
        SendData((BYTE *)buff, len);  
    
  
    return len;  
}  
  
//命令的初始化与添加命令

//初始化系统命令
SYS_CMD_HANDLE g_SysCmdHandle;	//系统命令句柄
SYS_CMD_BUFF_TYPE g_SysCmdBuff;	//系统命令缓冲区
	SYS_CMD_Init(&g_SysCmdBuff);//初始化系统命令(会初始化系统命令缓冲区,并添加帮助命令)
	SYS_CMD_InterfaceInit(&g_SysCmdHandle, printf);//初始化通讯句柄
	
	//添加RTC相关的命令支持
	SYS_CMD_Add(&g_SysCmdBuff, &CMD_GET_TIME);
	SYS_CMD_Add(&g_SysCmdBuff, &CMD_GET_DATE);
	SYS_CMD_Add(&g_SysCmdBuff, &CMD_SET_TIME);
	SYS_CMD_Add(&g_SysCmdBuff, &CMD_SET_DATE);

//命令的处理,收到数据后调用SYS_CMD_Handle
cnt1 = UARTx_GetRxCnt(UART_PRINTF_CH);
		OSTimeDlyHMSM(0,0,0,20);
		cnt2 = UARTx_GetRxCnt(UART_PRINTF_CH);
		if((cnt1 > 0) && (cnt1 == cnt2))
		{
			buff[cnt1] = 0;
			SYS_CMD_Handle(&g_SysCmdHandle, &g_SysCmdBuff, (char *)buff);								//命令处理
			UARTx_ClearRxCnt(UART_PRINTF_CH);
		}
		else
		{
			OSTimeDlyHMSM(0,0,0,100);;
		}


在测试时使用起来会非常方便,无需上位机支持,比如设置一些参数,调用xmodem下载升级等操作会非常方便,如下图所示












猜你喜欢

转载自blog.csdn.net/cp1300/article/details/79076489
今日推荐