You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

521 lines
17 KiB

/**
****************************************************************************************************
* @file usmart.c
* @author 正点原子团队(ALIENTEK)
* @version V3.5
* @date 2020-12-20
* @brief USMART 串口调试组件
*
* USMART是由ALIENTEK开发的一个灵巧的串口调试互交组件,通过 它,你可以通过串口助手调用程
* 序里面的任何函数,并执行.因此,你可以随意更改函数的输入参数(支持数字(10/16进制,支持负数)
* 、字符串、函数入口地址等作为参数),单个函数最多支持10个输入参数,并支持函数返 回值显示.
* V2.1版本以后新增hex和dec两个指令.他们可以用于设置函数参数的显示格式.也可以用于数据的进
* 制转换,例如:
* 输入"hex 100" 会在串口调试助手上看到 HEX 0X64.
* 输入"dec 0X64" 会在串口调试助手上看到 DEC 100.
* @note
* USMART资源占用情况@MDK 3.80A@2.0版本:
* FLASH:4K~K字节(通过USMART_USE_HELP和USMART_USE_WRFUNS设置)
* SRAM:72字节(最少的情况下)
* SRAM计算公式: SRAM=PARM_LEN+72-4 其中PARM_LEN必须大于等于4.
* 应该保证堆栈不小于100个字节.
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
****************************************************************************************************
* @attention
*
* 在线视频:www.yuanzige.com
* 技术论坛:www.openedv.com
* 公司网址:www.alientek.com
* 购买地址:openedv.taobao.com
*
* 修改说明
*
* V3.4之前版本详细修改说明见USMART文件夹下的:readme.txt
*
* V3.4 20200324
* 1, 新增usmart_port.c和usmart_port.h,用于管理USMART的移植,方便修改
* 2, 修改变量命名方式为: uint8_t, uint16_t, uint32_t
* 3, 修改usmart_reset_runtime为usmart_timx_reset_time
* 4, 修改usmart_get_runtime为usmart_timx_get_time
* 5, 修改usmart_scan函数实现方式,改成由usmart_get_input_string获取数据流
* 6, 修改printf函数为USMART_PRINTF宏定义
* 7, 修改定时扫描相关函数,改用宏定义方式,方便移植
*
* V3.5 20201220
* 1,修改部分代码以支持AC6编译器
*
****************************************************************************************************
*/
#include "./USMART/usmart.h"
#include "./USMART/usmart_str.h"
#include "./USMART/usmart_port.h"
/* 系统命令 */
char *sys_cmd_tab[] =
{
"?",
"help",
"list",
"id",
"hex",
"dec",
"runtime",
};
/**
* @brief 处理系统指令
* @param str : 字符串指针
* @retval 0,成功处理;其他,错误代码;
*/
uint8_t usmart_sys_cmd_exe(char *str)
{
uint8_t i;
char sfname[MAX_FNAME_LEN]; /* 存放本地函数名 */
uint8_t pnum;
uint8_t rval;
uint32_t res;
res = usmart_get_cmdname(str, sfname, &i, MAX_FNAME_LEN); /* 得到指令及指令长度 */
if (res)return USMART_FUNCERR; /* 错误的指令 */
str += i;
for (i = 0; i < sizeof(sys_cmd_tab) / 4; i++) /* 支持的系统指令 */
{
if (usmart_strcmp(sfname, sys_cmd_tab[i]) == 0)break;
}
switch (i)
{
case 0:
case 1: /* 帮助指令 */
USMART_PRINTF("\r\n");
#if USMART_USE_HELP
USMART_PRINTF("------------------------USMART V3.5------------------------ \r\n");
USMART_PRINTF(" USMART是由ALIENTEK开发的一个灵巧的串口调试互交组件,通过 \r\n");
USMART_PRINTF("它,你可以通过串口助手调用程序里面的任何函数,并执行.因此,你可\r\n");
USMART_PRINTF("以随意更改函数的输入参数(支持数字(10/16进制,支持负数)、字符串\r\n"),
USMART_PRINTF("、函数入口地址等作为参数),单个函数最多支持10个输入参数,并支持\r\n"),
USMART_PRINTF("函数返回值显示.支持参数显示进制设置功能,支持进制转换功能.\r\n");
USMART_PRINTF("技术支持:www.openedv.com\r\n");
USMART_PRINTF("USMART有7个系统命令(必须小写):\r\n");
USMART_PRINTF("?: 获取帮助信息\r\n");
USMART_PRINTF("help: 获取帮助信息\r\n");
USMART_PRINTF("list: 可用的函数列表\r\n\n");
USMART_PRINTF("id: 可用函数的ID列表\r\n\n");
USMART_PRINTF("hex: 参数16进制显示,后跟空格+数字即执行进制转换\r\n\n");
USMART_PRINTF("dec: 参数10进制显示,后跟空格+数字即执行进制转换\r\n\n");
USMART_PRINTF("runtime:1,开启函数运行计时;0,关闭函数运行计时;\r\n\n");
USMART_PRINTF("请按照程序编写格式输入函数名及参数并以回车键结束.\r\n");
USMART_PRINTF("--------------------------正点原子------------------------- \r\n");
#else
USMART_PRINTF("指令失效\r\n");
#endif
break;
case 2: /* 查询指令 */
USMART_PRINTF("\r\n");
USMART_PRINTF("-------------------------函数清单--------------------------- \r\n");
for (i = 0; i < usmart_dev.fnum; i++)USMART_PRINTF("%s\r\n", usmart_dev.funs[i].name);
USMART_PRINTF("\r\n");
break;
case 3: /* 查询ID */
USMART_PRINTF("\r\n");
USMART_PRINTF("-------------------------函数 ID --------------------------- \r\n");
for (i = 0; i < usmart_dev.fnum; i++)
{
usmart_get_fname((char *)usmart_dev.funs[i].name, sfname, &pnum, &rval); /* 得到本地函数名 */
USMART_PRINTF("%s id is:\r\n0X%08X\r\n", sfname, (unsigned int)usmart_dev.funs[i].func); /* 显示ID */
}
USMART_PRINTF("\r\n");
break;
case 4: /* hex指令 */
USMART_PRINTF("\r\n");
usmart_get_aparm(str, sfname, &i);
if (i == 0) /* 参数正常 */
{
i = usmart_str2num(sfname, &res); /* 记录该参数 */
if (i == 0) /* 进制转换功能 */
{
USMART_PRINTF("HEX:0X%X\r\n", res); /* 转为16进制 */
}
else if (i != 4)return USMART_PARMERR; /* 参数错误. */
else /* 参数显示设定功能 */
{
USMART_PRINTF("16进制参数显示!\r\n");
usmart_dev.sptype = SP_TYPE_HEX;
}
}
else return USMART_PARMERR; /* 参数错误. */
USMART_PRINTF("\r\n");
break;
case 5: /* dec指令 */
USMART_PRINTF("\r\n");
usmart_get_aparm(str, sfname, &i);
if (i == 0) /* 参数正常 */
{
i = usmart_str2num(sfname, &res); /* 记录该参数 */
if (i == 0) /* 进制转换功能 */
{
USMART_PRINTF("DEC:%lu\r\n", (unsigned long)res); /* 转为10进制 */
}
else if (i != 4)
{
return USMART_PARMERR; /* 参数错误. */
}
else /* 参数显示设定功能 */
{
USMART_PRINTF("10进制参数显示!\r\n");
usmart_dev.sptype = SP_TYPE_DEC;
}
}
else
{
return USMART_PARMERR; /* 参数错误. */
}
USMART_PRINTF("\r\n");
break;
case 6: /* runtime指令,设置是否显示函数执行时间 */
USMART_PRINTF("\r\n");
usmart_get_aparm(str, sfname, &i);
if (i == 0) /* 参数正常 */
{
i = usmart_str2num(sfname, &res); /* 记录该参数 */
if (i == 0) /* 读取指定地址数据功能 */
{
if (USMART_ENTIMX_SCAN == 0)
{
USMART_PRINTF("\r\nError! \r\nTo EN RunTime function,Please set USMART_ENTIMX_SCAN = 1 first!\r\n");/* 报错 */
}
else
{
usmart_dev.runtimeflag = res;
if (usmart_dev.runtimeflag)
{
USMART_PRINTF("Run Time Calculation ON\r\n");
}
else
{
USMART_PRINTF("Run Time Calculation OFF\r\n");
}
}
}
else
{
return USMART_PARMERR; /* 未带参数,或者参数错误 */
}
}
else
{
return USMART_PARMERR; /* 参数错误. */
}
USMART_PRINTF("\r\n");
break;
default:/* 非法指令 */
return USMART_FUNCERR;
}
return 0;
}
/**
* @brief 初始化USMART
* @param tclk: 定时器的工作频率(单位:Mhz)
* @retval 无
*/
void usmart_init(uint16_t tclk)
{
#if USMART_ENTIMX_SCAN == 1
usmart_timx_init(1000, tclk * 100 - 1);
#endif
usmart_dev.sptype = 1; /* 十六进制显示参数 */
}
/**
* @brief 从str中获取函数名,id,及参数信息
* @param str: 字符串指针.
* @retval 0,识别成功;其他,错误代码.
*/
uint8_t usmart_cmd_rec(char *str)
{
uint8_t sta, i, rval; /* 状态 */
uint8_t rpnum, spnum;
char rfname[MAX_FNAME_LEN]; /* 暂存空间,用于存放接收到的函数名 */
char sfname[MAX_FNAME_LEN]; /* 存放本地函数名 */
sta = usmart_get_fname(str, rfname, &rpnum, &rval); /* 得到接收到的数据的函数名及参数个数 */
if (sta)return sta; /* 错误 */
for (i = 0; i < usmart_dev.fnum; i++)
{
sta = usmart_get_fname((char *)usmart_dev.funs[i].name, sfname, &spnum, &rval); /* 得到本地函数名及参数个数 */
if (sta)return sta; /* 本地解析有误 */
if (usmart_strcmp(sfname, rfname) == 0) /* 相等 */
{
if (spnum > rpnum)return USMART_PARMERR;/* 参数错误(输入参数比源函数参数少) */
usmart_dev.id = i; /* 记录函数ID. */
break; /* 跳出. */
}
}
if (i == usmart_dev.fnum)return USMART_NOFUNCFIND; /* 未找到匹配的函数 */
sta = usmart_get_fparam(str, &i); /* 得到函数参数个数 */
if (sta)return sta; /* 返回错误 */
usmart_dev.pnum = i; /* 参数个数记录 */
return USMART_OK;
}
/**
* @brief USMART执行函数
* @note
* 该函数用于最终执行从串口收到的有效函数.
* 最多支持10个参数的函数,更多的参数支持也很容易实现.不过用的很少.一般5个左右的参数的函数已经很少见了.
* 该函数会在串口打印执行情况.以:"函数名(参数1,参数2...参数N)=返回值".的形式打印.
* 当所执行的函数没有返回值的时候,所打印的返回值是一个无意义的数据.
*
* @param 无
* @retval 无
*/
void usmart_exe(void)
{
uint8_t id, i;
uint32_t res;
uint32_t temp[MAX_PARM]; /* 参数转换,使之支持了字符串 */
char sfname[MAX_FNAME_LEN]; /* 存放本地函数名 */
uint8_t pnum, rval;
id = usmart_dev.id;
if (id >= usmart_dev.fnum)return; /* 不执行. */
usmart_get_fname((char *)usmart_dev.funs[id].name, sfname, &pnum, &rval); /* 得到本地函数名,及参数个数 */
USMART_PRINTF("\r\n%s(", sfname); /* 输出正要执行的函数名 */
for (i = 0; i < pnum; i++) /* 输出参数 */
{
if (usmart_dev.parmtype & (1 << i)) /* 参数是字符串 */
{
USMART_PRINTF("%c", '"');
USMART_PRINTF("%s", usmart_dev.parm + usmart_get_parmpos(i));
USMART_PRINTF("%c", '"');
temp[i] = (uint32_t) & (usmart_dev.parm[usmart_get_parmpos(i)]);
}
else /* 参数是数字 */
{
temp[i] = *(uint32_t *)(usmart_dev.parm + usmart_get_parmpos(i));
if (usmart_dev.sptype == SP_TYPE_DEC)
{
USMART_PRINTF("%ld", (long)temp[i]); /* 10进制参数显示 */
}
else
{
USMART_PRINTF("0X%X", temp[i]); /* 16进制参数显示 */
}
}
if (i != pnum - 1)USMART_PRINTF(",");
}
USMART_PRINTF(")");
#if USMART_ENTIMX_SCAN==1
usmart_timx_reset_time(); /* 计时器清零,开始计时 */
#endif
switch (usmart_dev.pnum)
{
case 0: /* 无参数(void类型) */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)();
break;
case 1: /* 有1个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0]);
break;
case 2: /* 有2个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1]);
break;
case 3: /* 有3个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2]);
break;
case 4: /* 有4个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3]);
break;
case 5: /* 有5个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3], temp[4]);
break;
case 6: /* 有6个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3], temp[4], \
temp[5]);
break;
case 7: /* 有7个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3], temp[4], \
temp[5], temp[6]);
break;
case 8: /* 有8个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3], temp[4], \
temp[5], temp[6], temp[7]);
break;
case 9: /* 有9个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3], temp[4], \
temp[5], temp[6], temp[7], temp[8]);
break;
case 10:/* 有10个参数 */
res = (*(uint32_t(*)())usmart_dev.funs[id].func)(temp[0], temp[1], temp[2], temp[3], temp[4], \
temp[5], temp[6], temp[7], temp[8], temp[9]);
break;
}
#if USMART_ENTIMX_SCAN==1
usmart_timx_get_time(); /* 获取函数执行时间 */
#endif
if (rval == 1) /* 需要返回值. */
{
if (usmart_dev.sptype == SP_TYPE_DEC)USMART_PRINTF("=%lu;\r\n", (unsigned long)res); /* 输出执行结果(10进制参数显示) */
else USMART_PRINTF("=0X%X;\r\n", res); /* 输出执行结果(16进制参数显示) */
}
else USMART_PRINTF(";\r\n"); /* 不需要返回值,直接输出结束 */
if (usmart_dev.runtimeflag) /* 需要显示函数执行时间 */
{
USMART_PRINTF("Function Run Time:%d.%1dms\r\n", usmart_dev.runtime / 10, usmart_dev.runtime % 10); /* 打印函数执行时间 */
}
}
/**
* @brief USMART扫描函数
* @note
* 通过调用该函数,实现USMART的各个控制.该函数需要每隔一定时间被调用一次
* 以及时执行从串口发过来的各个函数.
* 本函数可以在中断里面调用,从而实现自动管理.
* 如果非正点原子用户,则USART_RX_STA和USART_RX_BUF[]需要用户自己实现
*
* @param 无
* @retval 无
*/
void usmart_scan(void)
{
uint8_t sta, len;
char *pbuf = 0;
pbuf = usmart_get_input_string(); /* 获取数据数据流 */
if (pbuf == 0) return ; /* 数据流空, 直接返回 */
sta = usmart_dev.cmd_rec(pbuf); /* 得到函数各个信息 */
if (sta == 0)
{
usmart_dev.exe(); /* 执行函数 */
}
else
{
len = usmart_sys_cmd_exe(pbuf);
if (len != USMART_FUNCERR)sta = len;
if (sta)
{
switch (sta)
{
case USMART_FUNCERR:
USMART_PRINTF("函数错误!\r\n");
break;
case USMART_PARMERR:
USMART_PRINTF("参数错误!\r\n");
break;
case USMART_PARMOVER:
USMART_PRINTF("参数太多!\r\n");
break;
case USMART_NOFUNCFIND:
USMART_PRINTF("未找到匹配的函数!\r\n");
break;
}
}
}
}
#if USMART_USE_WRFUNS == 1 /* 如果使能了读写操作 */
/**
* @brief 读取指定地址的值
* @param 无
* @retval 无
*/
uint32_t read_addr(uint32_t addr)
{
return *(uint32_t *)addr;
}
/**
* @brief 在指定地址写入指定的值
* @param 无
* @retval 无
*/
void write_addr(uint32_t addr, uint32_t val)
{
*(uint32_t *)addr = val;
}
#endif