搜索
bottom↓
回复: 36

分享一个ESP32命令行解析框架

  [复制链接]

出0入0汤圆

发表于 2018-10-27 13:24:51 | 显示全部楼层 |阅读模式
该命令行解析框架,可以轻松实现,读写HEX类型的数据,读写数值型数据,读写IP,MAC,字符串,运行函数,浮点型数据暂时不支持,带符号的数据暂时不支持。
命令行解析框架,使用链表将所有注册的信息串联起来,然后每个节点node包含了,keyword,help,数据类型描述,命令执行的回调函数,和参数存储的回调函数。主要的操作是,已知函数变量地址,类型,和地址宽度,然后强制转换后对变量读写操作。
命令节点结构如下
  1. typedef                struct  fun_node
  2. {
  3.         struct  fun_node *pNext;
  4.         const                char        *pHelp;
  5.         const                char        *pName;
  6.         uint8_t                 paraNum;
  7.         FUN_CMD_BK  RunFun;
  8.         uint8_t                 EnableState;
  9. }ST_FUN_NODE;

  10. typedef                enum
  11. {
  12.         emCmdDataType_Dec                =1,
  13.         emCmdDataType_Hex                =2,
  14.         emCmdDataType_Str                =3,
  15.         emCmdDataType_IP                =4,
  16.         emCmdDataType_MAC                =5,
  17.        
  18. }EM_CMD_DATA_TYPE;


  19. typedef                struct   cmd_para
  20. {
  21.         struct   cmd_para  *pNext;       
  22.         const        char  *pName;
  23.         void                 *pDataAddr;       
  24.         uint16_t        dataLen;
  25.         EM_CMD_DATA_TYPE  dataType;
  26.         uint8_t         EnableState;
  27. }ST_CMD_PARA;


  28. typedef                struct        cmd_node
  29. {
  30.         const        char         *pKeyword;
  31.         const        char   *pHelp;
  32.         ST_CMD_PARA  *pData;
  33.         ST_FUN_NODE         *pFuntion;
  34.         FUN_STOR_BK   StorageFun;
  35. }ST_CMD_NODE;
复制代码

参数注册配置实例如下:

  1. void         cla_parametersConfig(void)
  2. {
  3.                 cla_init();
  4.                 cla_regsister("uuid","uuid <only read>");
  5.                 cla_addParameter("uuid","uuid ",(void *)&uuid,emCmdDataType_Str,                sizeof(uuid));

  6.                 cla_regsister("wifi","wifi or wifi ssid=xxx password=xxx");
  7.                 cla_addParameter("wifi","ssid",(void *)ssid,emCmdDataType_Str,                        sizeof(ssid));
  8.                 cla_addParameter("wifi","password",(void *)password,emCmdDataType_Str,        sizeof(password));

  9.                 cla_regsister("hex","hex or hex hex8=xx hex16=xx hex32=xx");
  10.                 cla_addParameter("hex","hex8",(void *)&hex8,emCmdDataType_Hex,                        sizeof(data8));
  11.                 cla_addParameter("hex","hex16",(void *)&hex16,emCmdDataType_Hex,                sizeof(data16));
  12.                 cla_addParameter("hex","hex32",(void *)&hex32,emCmdDataType_Hex,                sizeof(data32));
  13.                
  14.                 cla_regsister("data","data or data data8=xx data16=xx data32=xx");
  15.                 cla_addParameter("data","data8",(void *)&data8,emCmdDataType_Dec,                sizeof(data8));
  16.                 cla_addParameter("data","data16",(void *)&data16,emCmdDataType_Dec,                sizeof(data16));
  17.                 cla_addParameter("data","data32",(void *)&data32,emCmdDataType_Dec,                sizeof(data32));

  18.                 cla_regsister("ipconfig","ipconfig or ipconfig ipaddr=192.168.1.1");
  19.                 cla_addParameter("ipconfig","ipaddr",(void *)IPaddr,emCmdDataType_IP,        sizeof(IPaddr));
  20.                 cla_addParameter("ipconfig","mask",(void *)maskIP,emCmdDataType_IP,                sizeof(maskIP));
  21.                 cla_addParameter("ipconfig","dns",(void *)dnsIP,emCmdDataType_IP,                sizeof(dnsIP));
  22.                 cla_addParameter("ipconfig","mac",(void *)Mac,emCmdDataType_MAC,                sizeof(Mac));

  23.                 cla_regsister("run","<funtions>");
  24.                 cla_addRunFun("run",ptest_3fun_help,"test",test_3fun,3);
  25.                 cla_addRunFun("run",ptest_2fun_help,"test2",test_2fun,2);
  26. }
复制代码


命令解析的进程如下:

  1. void        cla_precess(uint8_t *pCmd,uint16_t cmdLen,FUN_PRINT_OUT printFun)
  2. {
  3.         uint16_t         i,outlen;
  4.         FUN_STOR_BK                storageFun=NULL;
  5.         BOOLEAN         res;
  6.         static        ST_CMD_STR                cmdStr;
  7.         static        char        outBuff[OUT_BUFF_MAX_LEN];
  8.         if((pCmd !=NULL)&&(cmdLen > 2))
  9.         {
  10.                         cla_cmdMake(&cmdStr,pCmd,cmdLen);       
  11.                         if((cla_CheckIn(&cmdStr,printFun))&&(cmdStr.argCount >= 1))
  12.                         {
  13.                                 for(i=0;i<CMD_NODE_TOTAL;i++)
  14.                                 {
  15.                                          if(CmdNodeGroup[i].pKeyword != NULL)
  16.                                          {                                               
  17.                                                    if(strcmp((const char *)CmdNodeGroup[i].pKeyword,cmdStr.pArgValue[0]) == 0)
  18.                                                         {
  19.                                                                         if(cmdStr.argCount  == 1)//查询参数
  20.                                                                         {
  21.                                                                                         outlen =cla_sprintfPara(CmdNodeGroup[i].pData,outBuff,OUT_BUFF_MAX_LEN);
  22.                                                                                         if(printFun !=NULL)
  23.                                                                                         {
  24.                                                                                                  printFun(outBuff,outlen);
  25.                                                                                         }
  26.                                                                                         Debug("out done\n");
  27.                                                                         }
  28.                                                                         else if(strcmp("run",cmdStr.pArgValue[0]) == 0)
  29.                                                                         {
  30.                                                                                         cmdStr.argPos                =1;
  31.                                                                                         res        =cla_runFuntion(CmdNodeGroup[i].pFuntion,&cmdStr);
  32.                                                                                         Debug("run done\n");                                                                                       
  33.                                                                         }
  34.                                                                         else
  35.                                                                         {
  36.                                                                                         cmdStr.argPos                =1;
  37.                                                                                         res         =cla_scanfPara(CmdNodeGroup[i].pData,&cmdStr);
  38.                                                                                         if(res)
  39.                                                                                         {
  40.                                                                                                         Debug("cfg done\n");
  41.                                                                                                         storageFun =CmdNodeGroup[i].StorageFun;
  42.                                                                                                         if(storageFun !=NULL)
  43.                                                                                                         {
  44.                                                                                                                         storageFun();
  45.                                                                                                         }
  46.                                                                                         }                                                                                       
  47.                                                                         }
  48.                                                                         return ;
  49.                                                         }
  50.                                                         else if(strcmp("help",cmdStr.pArgValue[0]) == 0)
  51.                                                         {
  52.                                                                         cla_help(printFun,outBuff,OUT_BUFF_MAX_LEN);
  53.                                                                         return ;
  54.                                                         }
  55.                                          }
  56.                                 }
  57.                         }
  58.         }       
  59. }


复制代码


代码可以直接下载下来,在ESP32上使用 TELNET 操作,也可以移植到其他地方,比如用串口操作



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2018-10-27 13:40:42 | 显示全部楼层
赞,不错的东东

出0入8汤圆

发表于 2018-10-27 21:39:35 来自手机 | 显示全部楼层
看着挺精简的,不过没看明白,先收藏慢慢看。

出0入90汤圆

发表于 2018-10-27 21:58:02 | 显示全部楼层
不知道有啥用途

出615入1076汤圆

发表于 2018-10-27 22:36:27 | 显示全部楼层
本帖最后由 dukelec 于 2018-10-27 23:07 编辑

我直接把 Linux 的红黑树拿到单片机用(不用修改就可以用),可以做成类似电脑 socket 编程的效果,可以裸跑,也可以上系统。
既支持被调用(做服务器),也支持主动查询(做客户端)。
而且,可以分散在不同 c 文件,不用集中 switch case, 更加干净。

譬如这个裸跑的小步进电机的代码 https://github.com/dukelec/stepp ... /fw/usr/app_motor.c
库存放在:https://github.com/dukelec/cdnet , 其中还有很多好用的工具。

  1. static cdnet_socket_t pos_sock = { .port = 20 };
  2. static cdnet_socket_t speed_sock = { .port = 21 };


  3. static void pos_mode_service_routine(void)
  4. {
  5.     cdnet_packet_t *pkt = cdnet_socket_recvfrom(&pos_sock);
  6.     if (!pkt)
  7.         return;

  8.     // 处理接收的命令
  9.     ....

  10.     pkt->len = 2;
  11.     pkt->dat[0] = cmd ? 0x80 : 0x81; // 返回状态
  12.     pkt->dat[1] = cmd_pend_head.len; // 返回命令队列长度

  13.     pkt->dst = pkt->src;
  14.     cdnet_socket_sendto(&pos_sock, pkt);
  15. }

  16. void main(void)
  17. {
  18.     ....
  19.     cdnet_socket_bind(&pos_sock, NULL);
  20.     cdnet_socket_bind(&speed_sock, NULL);
  21.     ....
  22.     while (true) {
  23.         ....
  24.         pos_mode_service_routine();
  25.         speed_mode_service_routine();
  26.         ....
  27.     }
  28. }
复制代码


同样,即便是字符串命令,也是建议通过红黑树做成高级语言的 dict 形式,普通 for 循环遍历链表或数组效率太差。

另外,其它需要用到链表的地方,也建议使用 Linux 的 container_of 的方式实现,这样能最优雅的实现代码共用。当然我也整理了一份在我的库里。

我还写过一个命令行解析的小程序,由于只是电脑程序启动时使用一次,所以不用考虑效率,是用链表实现的:
https://github.com/dukelec/cdipc ... ipc/utils/cd_args.h

出0入0汤圆

发表于 2018-10-28 09:40:41 来自手机 | 显示全部楼层
不错收藏学习

出0入4汤圆

发表于 2018-10-28 10:02:54 来自手机 | 显示全部楼层
感谢分享,学习一下

出0入0汤圆

发表于 2018-10-28 12:34:42 | 显示全部楼层
赞,不错的东东

出15入118汤圆

发表于 2018-10-28 15:13:20 来自手机 | 显示全部楼层
mark mark

出0入0汤圆

发表于 2018-10-28 19:46:31 来自手机 | 显示全部楼层
这个是通用么

出30入54汤圆

发表于 2018-10-28 22:57:45 | 显示全部楼层
ESP32感觉还是直接用里面的核比较好,双核够强的了

出0入0汤圆

发表于 2018-10-29 21:14:54 | 显示全部楼层
楼主有没有和RT-Thread AT组件比较呢,这个组件是专门解析AT指令,似乎很强大

出0入0汤圆

发表于 2018-10-30 08:13:19 | 显示全部楼层
mark 厉害

出0入0汤圆

发表于 2018-10-30 08:28:46 | 显示全部楼层
不错,学习了

出0入0汤圆

 楼主| 发表于 2018-10-30 21:36:16 | 显示全部楼层
dukelec 发表于 2018-10-27 22:36
我直接把 Linux 的红黑树拿到单片机用(不用修改就可以用),可以做成类似电脑 socket 编程的效果,可以裸 ...

谢谢分享,最近比较忙,空了来研究一下!你这个应该效率高不少。

出0入0汤圆

 楼主| 发表于 2018-10-30 21:37:07 | 显示全部楼层

可以通用。

出0入0汤圆

 楼主| 发表于 2018-10-30 21:37:50 | 显示全部楼层

LINUX 命令解析,比如cd ...  ls copy 等一些列命令都是这么做的

出0入0汤圆

 楼主| 发表于 2018-10-30 21:38:49 | 显示全部楼层
guxingganyue 发表于 2018-10-29 21:14
楼主有没有和RT-Thread AT组件比较呢,这个组件是专门解析AT指令,似乎很强大 ...

我有AT 指令命令框架,这个也能简单修改,适配AT指令

出0入0汤圆

发表于 2018-10-30 21:42:33 | 显示全部楼层
LingYi 发表于 2018-10-30 21:38
我有AT 指令命令框架,这个也能简单修改,适配AT指令

不明白你这个主题里的命令行是指?
给讲解一下呗,不晓得在哪里用的。。

出0入0汤圆

发表于 2018-10-30 21:45:57 | 显示全部楼层
学习了

出0入0汤圆

发表于 2018-10-30 21:46:40 | 显示全部楼层
LingYi 发表于 2018-10-30 21:38
我有AT 指令命令框架,这个也能简单修改,适配AT指令

哦,你这个是ESP32的指令解析架构,记成AT指令架构了。。。

这2个差别不大吧?以前只解析过几个AT直接,解的非常麻烦,想找个通用的AT指令解析架构学习下

出0入0汤圆

发表于 2018-10-30 21:49:09 | 显示全部楼层
LingYi 发表于 2018-10-30 21:37
LINUX 命令解析,比如cd ...  ls copy 等一些列命令都是这么做的

是的,linux里的命令行解析功能很强大,一直想找一个可以在单片机上跑的,一直没找到

出0入0汤圆

 楼主| 发表于 2018-10-30 21:52:30 | 显示全部楼层
guxingganyue 发表于 2018-10-30 21:49
是的,linux里的命令行解析功能很强大,一直想找一个可以在单片机上跑的,一直没找到 ...

这个已经实现了得差不多了,可以直接移植,非常容易实现的。

出0入0汤圆

 楼主| 发表于 2018-10-30 21:54:22 | 显示全部楼层
kinsno 发表于 2018-10-30 21:42
不明白你这个主题里的命令行是指?
给讲解一下呗,不晓得在哪里用的。。

linux  的
cd ../
copy ./a ./b
reboot
这些没有用过嘛,都是这样实现的,只不过初始化的时候需要自己去注册函数,变量 等
linux 内核代码已经帮你注册了,所有你可以使用

出0入0汤圆

 楼主| 发表于 2018-10-30 22:01:34 | 显示全部楼层
dukelec 发表于 2018-10-27 22:36
我直接把 Linux 的红黑树拿到单片机用(不用修改就可以用),可以做成类似电脑 socket 编程的效果,可以裸 ...

用socket 的方式确实很高级,我明白中心思想了,哪个container_of 的方式,几年前我已经用过了,只是当时不知道,哈哈。优秀的代码还是要去linux里面抠。

出0入0汤圆

发表于 2018-10-30 22:02:02 | 显示全部楼层
LingYi 发表于 2018-10-30 21:54
linux  的
cd ../
copy ./a ./b

我懂了。。。
以前玩过。。

出0入0汤圆

发表于 2018-10-30 22:06:26 | 显示全部楼层
LingYi 发表于 2018-10-30 21:52
这个已经实现了得差不多了,可以直接移植,非常容易实现的。

直接从linux的相关源码里面移植到mcu上?

出0入0汤圆

发表于 2018-10-30 22:13:07 | 显示全部楼层
还是需要学linux啊

出0入0汤圆

发表于 2018-10-31 08:53:10 | 显示全部楼层
MARK,shell相关

出0入0汤圆

发表于 2018-10-31 09:27:41 | 显示全部楼层
mark     shell   

出0入0汤圆

发表于 2018-10-31 09:29:58 | 显示全部楼层
谢谢,很好的思路

出0入0汤圆

 楼主| 发表于 2018-11-6 09:51:36 | 显示全部楼层
更新一下,基于红黑树的 命令解析

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2018-11-17 22:26:45 | 显示全部楼层
mark,移植用用,应该效率不错

出0入0汤圆

发表于 2018-11-18 20:21:10 | 显示全部楼层
面试的时候,如果有人问我什么是红黑树,我扭头就走
不是因为这题太容易
而是老子真的不会啊

--段子

出100入101汤圆

发表于 2020-11-1 19:25:29 | 显示全部楼层
收藏,谢谢大神

出0入0汤圆

发表于 2020-11-1 21:56:32 | 显示全部楼层
谢谢分享,

出0入0汤圆

发表于 2022-4-29 15:07:26 | 显示全部楼层
mark.................
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 13:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表