当前位置: 首页 > news >正文

板级调试小助手(4)基于C语言的自定义脚本解析器

一、前言

        在之前的文章中介绍了板级调试小助手的结构、DDS外设以及如何使用PYNQ驱动OLED显示视频,在小助手结构的文章中提到,小助手具有自定义脚本功能,这个功能是使用C语言编写的,本质上来说就是一个字典树通过读取脚本的关键词进行识别。在这篇文章中就给大家介绍一下一个简易的自定义脚本解析器吧。

        本项目代码完全开源,需要查看源码请移步《板级调试小助手(1)系统结构和原理》文章最后

二、脚本函数定义

在编写之前根据小助手项目自定义四个脚本如下

DO_OUT(A);	//数字量输出函数 A 是一个8bit十进制数,它的每一个bit代表一个DO,例如bit0代表DO0AO_OUT(A,B);	//它是模拟量输出函数,A表示通道数,B表示值范围为0~4096Delay(A);//它是延迟函数,A表示延迟时间,单位是毫秒SIN_OUT(A,B,C);//它是正弦波输出函数,A表示通道数,B表示频率值,C表示相位值

三、脚本解析流程和代码结构

        解析脚本的流程大致为:读取文件->读取一行代码->放入字典树识别关键词->通过关键词读取参数->将识别到的代码解析并放入链表(或二叉树)供其他应用调用。关于字典树和链表的知识这里就不赘述了。解析函数如下

//脚本相关的全局变量
SubLink SubLinkHand;		//命令链表表头
mytrie	TrieHand;			//字典树头
unsigned char g_cTrieDeep;	//记录字典树的最大深度
//定义脚本命令
char g_cCommand[10][10] = {"DO_OUT\0","AO_OUT\0","SIN_OUT\0","Delay\0"};/*
功能:脚本解析初始化
初始化命令链表
*/
void init_SubScript(void)
{if(SubLinkHand == NULL){SubLinkHand = (SubLink)malloc(sizeof(struct LNode));		//给脚本头申请内存SubLinkHand->cCommand = 0;SubLinkHand->Data = 0;SubLinkHand->Data1 = 0;SubLinkHand->Data2 = 0;SubLinkHand->Next = NULL;}
}/*
功能,读取脚本文件并解析脚本文件
将解析后的结果放入链表
*/
char Sub_main()
{FILE *file;static char cData[50];				//用于存放一行数据unsigned char cCommand;				//用于暂存命令unsigned int iCmd[3] = {0};			//用于暂存命令数据DelLink(SubLinkHand);							//清空整个脚本链表file = fopen("/home/xilinx/jupyter_notebooks/Overlay_Assistant/scriptApp/script.s","r");		//读取文件if (file == NULL)								//如果打开失败{printf("文件打开失败\r\n");return -1;}while(feof(file)==0)							//读取整个脚本文件{memset(cData, 0, 50);						//清空数组fgets(cData, sizeof(cData), file);			//读取一行数据cCommand = InquiryCommand(cData, iCmd);		//检测命令if (cCommand != 0xff){WriteLink(SubLinkHand, cCommand, iCmd);	//写入链表}}fclose(file);									//关闭文件return 0;
}

        解析完毕之后就可以通过读取链表的内容按照顺序执行脚本代码,执行代码如下

/*
功能:循环读执行取链表并下脚本(通过TCP通讯)
*/
void ReadScrip(SubLink Hand)
{FILE *file;SubLink q;			//定义一个可在链表中移动的指针char TcpTxBuff[100];	//发送缓存uint32_t ui32Delay;		//延迟时间uswhile(1){//脚本文件是否还存在file = fopen("/home/xilinx/jupyter_notebooks/Overlay_Assistant/scriptApp/script.s","r");		//读取文件if(file == NULL){break;}fclose(file); 									// 关闭文件//执行一遍脚本for(q=Hand;q->Next != NULL;q = q->Next){switch(q->Next->cCommand)		//选择指令{case COMMAND_DO:				//DO指令memset(TcpTxBuff,0x00,100);	//清除缓存sprintf(TcpTxBuff,"{\"mode\":\"set\",\"DO\":\"%d\"}",q->Next->Data);	//转义名称write(g_iTcpSock, TcpTxBuff, strlen(TcpTxBuff));						//通过网络发送break;case COMMAND_AO:				//AO指令strlenmemset(TcpTxBuff,0x00,100);	//清除缓存sprintf(TcpTxBuff,"{\"mode\":\"set\",\"AO%d mode\":\"1\",\"AO%d phase\":\"%d\"}",q->Next->Data,q->Next->Data,q->Next->Data1);remove_spaces(TcpTxBuff);			//删除字符串中的空格write(g_iTcpSock, TcpTxBuff, strlen(TcpTxBuff));						//通过网络发送break;case COMMAND_DDS:				//DDS指令memset(TcpTxBuff,0x00,100);	//清除缓存sprintf(TcpTxBuff,"{\"mode\":\"set\",\"AO%d mode\":\"2\",\"AO%d fre\":\"%d\",\"AO%d phase\":\"%d\"}",q->Next->Data,q->Next->Data,q->Next->Data1,q->Next->Data,q->Next->Data2);remove_spaces(TcpTxBuff);			//删除字符串中的空格write(g_iTcpSock, TcpTxBuff, strlen(TcpTxBuff));						//通过网络发送break;case COMMAND_Delay:				//清屏指令memset(TcpTxBuff,0x00,100);	//清除缓存ui32Delay = (uint32_t)q->Next->Data * 1000;usleep(ui32Delay);break;}usleep(100);}}
}

        该代码是通过读取链表的数据,将指令通过TCP发送给另一个应用(小助手主要逻辑应用)。

四、总结

        综上介绍了如何使用字典树的方式简单的搭建了一个识别自定义脚本程序,本人学识有限若有疏漏欢迎指正。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Git远程操作】理解分布式管理 | 创建远程仓库
  • 3、宠物商店智能合约实战(truffle智能合约项目实战)
  • GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建
  • Python--pyecharts 入门笔记
  • 《基于 CDC、Spark Streaming、Kafka 实现患者指标采集》
  • LeetCode 3112.访问消失节点的最少时间:单源最短路的Dijkstra算法
  • Nginx详解(超级详细)
  • Mac Electron 应用如何进行签名(signature)和公证(notarization)?
  • cms wpscan使用方式--kali linux
  • You are running Vue in development mode.和undefined is not iterable白屏问题
  • 【Android】Intent基础用法及作用
  • Go网络编程-RPC程序设计
  • 前端路由History 和 Hash模式的区别以及Vue项目打包后显示白屏,路由router-view不加载问题
  • C语言之指针的奥秘(三)
  • 【python】OpenCV—Scanner
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • ESLint简单操作
  • JS数组方法汇总
  • miaov-React 最佳入门
  • PAT A1092
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • SAP云平台里Global Account和Sub Account的关系
  • Zepto.js源码学习之二
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 工程优化暨babel升级小记
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 回顾 Swift 多平台移植进度 #2
  • 前端js -- this指向总结。
  • 如何设计一个微型分布式架构?
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 一个SAP顾问在美国的这些年
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • C# - 为值类型重定义相等性
  • ​linux启动进程的方式
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (2020)Java后端开发----(面试题和笔试题)
  • (ibm)Java 语言的 XPath API
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (五)MySQL的备份及恢复
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)EOS中账户、钱包和密钥的关系
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .env.development、.env.production、.env.staging
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET编程C#线程之旅:十种开启线程的方式以及各自使用场景和优缺点