分享一个ESP32命令行解析框架
该命令行解析框架,可以轻松实现,读写HEX类型的数据,读写数值型数据,读写IP,MAC,字符串,运行函数,浮点型数据暂时不支持,带符号的数据暂时不支持。命令行解析框架,使用链表将所有注册的信息串联起来,然后每个节点node包含了,keyword,help,数据类型描述,命令执行的回调函数,和参数存储的回调函数。主要的操作是,已知函数变量地址,类型,和地址宽度,然后强制转换后对变量读写操作。
命令节点结构如下typedef structfun_node
{
structfun_node *pNext;
const char *pHelp;
const char *pName;
uint8_t paraNum;
FUN_CMD_BKRunFun;
uint8_t EnableState;
}ST_FUN_NODE;
typedef enum
{
emCmdDataType_Dec =1,
emCmdDataType_Hex =2,
emCmdDataType_Str =3,
emCmdDataType_IP =4,
emCmdDataType_MAC =5,
}EM_CMD_DATA_TYPE;
typedef struct cmd_para
{
struct cmd_para*pNext;
const char*pName;
void *pDataAddr;
uint16_t dataLen;
EM_CMD_DATA_TYPEdataType;
uint8_t EnableState;
}ST_CMD_PARA;
typedef struct cmd_node
{
const char *pKeyword;
const char *pHelp;
ST_CMD_PARA*pData;
ST_FUN_NODE *pFuntion;
FUN_STOR_BK StorageFun;
}ST_CMD_NODE;
参数注册配置实例如下:
void cla_parametersConfig(void)
{
cla_init();
cla_regsister("uuid","uuid <only read>");
cla_addParameter("uuid","uuid ",(void *)&uuid,emCmdDataType_Str, sizeof(uuid));
cla_regsister("wifi","wifi or wifi ssid=xxx password=xxx");
cla_addParameter("wifi","ssid",(void *)ssid,emCmdDataType_Str, sizeof(ssid));
cla_addParameter("wifi","password",(void *)password,emCmdDataType_Str, sizeof(password));
cla_regsister("hex","hex or hex hex8=xx hex16=xx hex32=xx");
cla_addParameter("hex","hex8",(void *)&hex8,emCmdDataType_Hex, sizeof(data8));
cla_addParameter("hex","hex16",(void *)&hex16,emCmdDataType_Hex, sizeof(data16));
cla_addParameter("hex","hex32",(void *)&hex32,emCmdDataType_Hex, sizeof(data32));
cla_regsister("data","data or data data8=xx data16=xx data32=xx");
cla_addParameter("data","data8",(void *)&data8,emCmdDataType_Dec, sizeof(data8));
cla_addParameter("data","data16",(void *)&data16,emCmdDataType_Dec, sizeof(data16));
cla_addParameter("data","data32",(void *)&data32,emCmdDataType_Dec, sizeof(data32));
cla_regsister("ipconfig","ipconfig or ipconfig ipaddr=192.168.1.1");
cla_addParameter("ipconfig","ipaddr",(void *)IPaddr,emCmdDataType_IP, sizeof(IPaddr));
cla_addParameter("ipconfig","mask",(void *)maskIP,emCmdDataType_IP, sizeof(maskIP));
cla_addParameter("ipconfig","dns",(void *)dnsIP,emCmdDataType_IP, sizeof(dnsIP));
cla_addParameter("ipconfig","mac",(void *)Mac,emCmdDataType_MAC, sizeof(Mac));
cla_regsister("run","<funtions>");
cla_addRunFun("run",ptest_3fun_help,"test",test_3fun,3);
cla_addRunFun("run",ptest_2fun_help,"test2",test_2fun,2);
}
命令解析的进程如下:
void cla_precess(uint8_t *pCmd,uint16_t cmdLen,FUN_PRINT_OUT printFun)
{
uint16_t i,outlen;
FUN_STOR_BK storageFun=NULL;
BOOLEAN res;
static ST_CMD_STR cmdStr;
static char outBuff;
if((pCmd !=NULL)&&(cmdLen > 2))
{
cla_cmdMake(&cmdStr,pCmd,cmdLen);
if((cla_CheckIn(&cmdStr,printFun))&&(cmdStr.argCount >= 1))
{
for(i=0;i<CMD_NODE_TOTAL;i++)
{
if(CmdNodeGroup.pKeyword != NULL)
{
if(strcmp((const char *)CmdNodeGroup.pKeyword,cmdStr.pArgValue) == 0)
{
if(cmdStr.argCount== 1)//查询参数
{
outlen =cla_sprintfPara(CmdNodeGroup.pData,outBuff,OUT_BUFF_MAX_LEN);
if(printFun !=NULL)
{
printFun(outBuff,outlen);
}
Debug("out done\n");
}
else if(strcmp("run",cmdStr.pArgValue) == 0)
{
cmdStr.argPos =1;
res =cla_runFuntion(CmdNodeGroup.pFuntion,&cmdStr);
Debug("run done\n");
}
else
{
cmdStr.argPos =1;
res =cla_scanfPara(CmdNodeGroup.pData,&cmdStr);
if(res)
{
Debug("cfg done\n");
storageFun =CmdNodeGroup.StorageFun;
if(storageFun !=NULL)
{
storageFun();
}
}
}
return ;
}
else if(strcmp("help",cmdStr.pArgValue) == 0)
{
cla_help(printFun,outBuff,OUT_BUFF_MAX_LEN);
return ;
}
}
}
}
}
}
代码可以直接下载下来,在ESP32上使用 TELNET 操作,也可以移植到其他地方,比如用串口操作
赞,不错的东东 看着挺精简的,不过没看明白,先收藏慢慢看。 不知道有啥用途 本帖最后由 dukelec 于 2018-10-27 23:07 编辑
我直接把 Linux 的红黑树拿到单片机用(不用修改就可以用),可以做成类似电脑 socket 编程的效果,可以裸跑,也可以上系统。
既支持被调用(做服务器),也支持主动查询(做客户端)。
而且,可以分散在不同 c 文件,不用集中 switch case, 更加干净。
譬如这个裸跑的小步进电机的代码 https://github.com/dukelec/stepper_motor_controller/blob/master/fw/usr/app_motor.c
库存放在:https://github.com/dukelec/cdnet , 其中还有很多好用的工具。
static cdnet_socket_t pos_sock = { .port = 20 };
static cdnet_socket_t speed_sock = { .port = 21 };
static void pos_mode_service_routine(void)
{
cdnet_packet_t *pkt = cdnet_socket_recvfrom(&pos_sock);
if (!pkt)
return;
// 处理接收的命令
....
pkt->len = 2;
pkt->dat = cmd ? 0x80 : 0x81; // 返回状态
pkt->dat = cmd_pend_head.len; // 返回命令队列长度
pkt->dst = pkt->src;
cdnet_socket_sendto(&pos_sock, pkt);
}
void main(void)
{
....
cdnet_socket_bind(&pos_sock, NULL);
cdnet_socket_bind(&speed_sock, NULL);
....
while (true) {
....
pos_mode_service_routine();
speed_mode_service_routine();
....
}
}
同样,即便是字符串命令,也是建议通过红黑树做成高级语言的 dict 形式,普通 for 循环遍历链表或数组效率太差。
另外,其它需要用到链表的地方,也建议使用 Linux 的 container_of 的方式实现,这样能最优雅的实现代码共用。当然我也整理了一份在我的库里。
我还写过一个命令行解析的小程序,由于只是电脑程序启动时使用一次,所以不用考虑效率,是用链表实现的:
https://github.com/dukelec/cdipc/blob/master/cdipc/utils/cd_args.h 不错收藏学习 感谢分享,学习一下 赞,不错的东东 mark mark 这个是通用么 ESP32感觉还是直接用里面的核比较好,双核够强的了 楼主有没有和RT-Thread AT组件比较呢,这个组件是专门解析AT指令,似乎很强大 mark 厉害 不错,学习了 dukelec 发表于 2018-10-27 22:36
我直接把 Linux 的红黑树拿到单片机用(不用修改就可以用),可以做成类似电脑 socket 编程的效果,可以裸 ...
谢谢分享,最近比较忙,空了来研究一下!你这个应该效率高不少。 huangqi412 发表于 2018-10-28 19:46
这个是通用么
可以通用。 honami520 发表于 2018-10-27 21:58
不知道有啥用途
LINUX 命令解析,比如cd ...ls copy 等一些列命令都是这么做的 guxingganyue 发表于 2018-10-29 21:14
楼主有没有和RT-Thread AT组件比较呢,这个组件是专门解析AT指令,似乎很强大 ...
我有AT 指令命令框架,这个也能简单修改,适配AT指令 LingYi 发表于 2018-10-30 21:38
我有AT 指令命令框架,这个也能简单修改,适配AT指令
不明白你这个主题里的命令行是指?
给讲解一下呗,不晓得在哪里用的。。
学习了
LingYi 发表于 2018-10-30 21:38
我有AT 指令命令框架,这个也能简单修改,适配AT指令
哦,你这个是ESP32的指令解析架构,记成AT指令架构了。。。
这2个差别不大吧?以前只解析过几个AT直接,解的非常麻烦,想找个通用的AT指令解析架构学习下 LingYi 发表于 2018-10-30 21:37
LINUX 命令解析,比如cd ...ls copy 等一些列命令都是这么做的
是的,linux里的命令行解析功能很强大,一直想找一个可以在单片机上跑的,一直没找到 guxingganyue 发表于 2018-10-30 21:49
是的,linux里的命令行解析功能很强大,一直想找一个可以在单片机上跑的,一直没找到 ...
这个已经实现了得差不多了,可以直接移植,非常容易实现的。 kinsno 发表于 2018-10-30 21:42
不明白你这个主题里的命令行是指?
给讲解一下呗,不晓得在哪里用的。。
linux的
cd ../
copy ./a ./b
reboot
这些没有用过嘛,都是这样实现的,只不过初始化的时候需要自己去注册函数,变量 等
linux 内核代码已经帮你注册了,所有你可以使用 dukelec 发表于 2018-10-27 22:36
我直接把 Linux 的红黑树拿到单片机用(不用修改就可以用),可以做成类似电脑 socket 编程的效果,可以裸 ...
用socket 的方式确实很高级,我明白中心思想了,哪个container_of 的方式,几年前我已经用过了,只是当时不知道,哈哈。优秀的代码还是要去linux里面抠。 LingYi 发表于 2018-10-30 21:54
linux的
cd ../
copy ./a ./b
我懂了。。。
以前玩过。。
LingYi 发表于 2018-10-30 21:52
这个已经实现了得差不多了,可以直接移植,非常容易实现的。
直接从linux的相关源码里面移植到mcu上? 还是需要学linux啊 MARK,shell相关 mark shell 谢谢,很好的思路 更新一下,基于红黑树的 命令解析
mark,移植用用,应该效率不错 面试的时候,如果有人问我什么是红黑树,我扭头就走
不是因为这题太容易
而是老子真的不会啊
--段子 收藏,谢谢大神
谢谢分享,{:smile:}{:smile:}{:smile:} mark.................
页:
[1]