如何使用LUA脚本动态解析外部智能设备的通信协议

如何使用LUA脚本动态解析外部智能设备的通信协议


原文链接:https://blog.csdn.net/shjhuang/article/details/104278509

有一个项目,需要通过串口或者TCP/IP读取一些设备的运行参数,例如温湿度、发电机等,通信协议一般是MODBUS或者电总协议的帧格式协议。为了使程序使用更多的设备,打算用LUA来解析通信协议。这样子在设备在不同的应用场合时,只需要更新或者增加LUA脚本就可以接入新的设备类型。

实现思路

  1. 每个唯一LUA文件对应特定设备的协议接入,在协议里完成数据帧的发送、接收、校验,并得到设备的运行参数,最后返回C应用程序。

  2. 要解决的问题:

           1)数据的发送、CRC校验是在C程序那边完成的,所以需要解决如何将数组(表)传递给C。
    
           2)LUA的函数解析完了之后,如何将设备的参数返回到C,C如何得到LUA返回的参数。参数是多个,且数量不定,内容不定,可能是整形、可能是字符串。
    
  3. 经过搜索网上一些资料,做了一个简单测试程序,基本实现了上述的问题。剩下的就是完善和移植到现有C系统中了。实现例子:

1)https://blog.csdn.net/shjhuang/article/details/104273145

2)https://blog.csdn.net/shjhuang/article/details/104275278

     以上只是实现的方法,最终的程序还要继续完善,如有机会再发布。

LUA调用有数组参数的C函数

https://blog.csdn.net/shjhuang/article/details/104273145
LUA发送一包数据到串口中,发送前需要校验,校验在C完成,所以要将一个数组传递到C那边,代码如下:

  1. C代码的校验函数如下
//--- lua中以数组传递参数
static int calc_chksum(lua_State *L)
{
 	int 	i;
	int 	DatLen;
	unsigned char *DatInf;
	unsigned short crc;
	 
	if(!lua_istable(L, 1)){					//判断第一个参数是否为表,否则退出
        lua_pushnil(L);
        return -1;
    }
	DatLen = luaL_checknumber(L,2);			//获取第二个参数,数据长度
	DatInf =(unsigned char *)malloc(DatLen);
	for(i=1; i<=DatLen; i++){
		lua_rawgeti(L, 1, i);
		DatInf[i-1] = lua_tointeger(L, -1);
		lua_pop(L, 1);						//把上一个内容的出栈
	}
	crc = CalcChkSum(DatInf, DatLen);		//计算校验值
	lua_pushinteger(L,(crc>>8)&0xff);		//校验值高位压栈
	lua_pushinteger(L,(crc)&0xff);			//校验值低位压栈
	free(DatInf);
    return 2;   							//返回参数个数
}
  1. LUA代码如下
function collection_data(if_id, ipaddr, port, devaddr)                                                                                                                                                                          
                                                                                                                                                                                                                                
        print("if_id:", if_id);                                                                                                                                                                                                 
        print("ipaddr:", ipaddr);                                                                                                                                                                                               
        print("ip port:", port);                                                                                                                                                                                                
        print("dev addr", devaddr);                                                                                                                                                                                             
                                                                                                                                                                                                                                
        cmd = {devaddr, 0x04, 0x00, 0x00, 0x00, 0x02};                                                                                                                                                                          
        crc1, crc2  = dev_lib.calc_chksum(cmd, 6);          //调用C函数完成数组的计算得到CRC的高低字节                                                                                                                                                                           
        cmd[7] = crc1;                                                                                                                                                                                                          
        cmd[8] = crc2;                                                                                                                                                                                                          
        dev_lib.write_data(if_id, cmd, 8);                  //最后通过接口发送出去                                                                                                                                                                                  
                                                                                                                                                                                                                                
end  

C调用LUA函数返回的表

C语言调用LUA的程序,LUA程序返回表,C获取表格的内容。

例子如下:

C语言端:

int lua_collection_data(int if_id, char *ipaddr, int ipport, int devaddr){
	float res;
	int k;
	double v;
	const char *c;
	
	lua_getglobal(L,"collection_data");
	lua_pushnumber(L, if_id);
	lua_pushstring(L, ipaddr);
	lua_pushnumber(L, ipport);
	lua_pushnumber(L, devaddr);
	
	lua_call(L, 4, 1);									//输入4个参数,返回1个参数(table)
	lua_pushnil(L);  									
	while(lua_next(L, -2)){
		k = lua_tonumber(L, -2);                	    
		if(k==3) 										//表的索引3为字符串,其它为浮点点数
			 c = lua_tostring(L, -1); 
		else
			v = (double)lua_tonumber(L, -1);    
		
		if(k==3) 
			printf("k=%d,c=%s\n", k, c);				//打印测试
		else 
			printf("k=%d,v=%f\n", k, v);
		
		lua_pop(L,1);                          
	}	
	return res;
	
}

LUA语言端:

function collection_data(if_id, ipaddr, port, devaddr)
 
        print("if_id:", if_id);
        print("ipaddr:", ipaddr);
        print("ip port:", port);
        print("dev addr", devaddr);
 
        cmd = {devaddr, 0x04, 0x00, 0x00, 0x00, 0x02};
        crc1, crc2  = dev_lib.calc_chksum(cmd, 6);
        cmd[7] = crc1;
        cmd[8] = crc2;
        dev_lib.write_data(if_id, cmd, 8);
 
        --以下是测试用的
        spots[1] = 12.45
        spots[2] = 32
        spots[3] = "TEST MESSAGE"
        --return 10,12,13;
        return spots        --返回表格
end

测试结果:

k=1,v=12.450000
k=2,v=32.000000
k=3,c=TEST MESSAGE
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Wireshark解析视频时,可以使用Lua脚本来提取和分析视频流的相关信息。下面是一个示例脚本,演示了如何使用Lua脚本解析视频流: ```lua -- 视频解析脚本示例 -- 过滤器,仅匹配特定的视频流 local filter = "udp.port == 1234" -- 打开新的输出文件 local output_file = io.open("video_data.txt", "w") -- 定义回调函数,用于处理每个数据包 local function packet_callback(packet) -- 检查是否为UDP数据包 if packet.udp then -- 检查是否匹配过滤器 if packet:match(filter) then -- 提取视频数据 local video_data = packet.data -- 在输出文件中写入视频数据 output_file:write(video_data .. "\n") end end end -- 注册回调函数以处理每个数据包 local function init_listener() local tap = Listener.new(nil, filter) tap.packetops:register(packet_callback) end -- 启动Wireshark监听器 init_listener() ``` 上述示例脚本使用了Wireshark的Lua API。它首先定义了一个过滤器,以仅匹配特定的视频流(在示例中使用UDP端口1234)。然后,它打开一个输出文件(video_data.txt),将视频数据写入其中。最后,它注册了一个回调函数,以便在每个数据包到达时进行处理。 你可以将此脚本保存为.lua文件,并在Wireshark中通过"File"->"Load Script"加载它。然后,启动Wireshark的捕获功能,它将开始解析并提取匹配过滤器的视频数据。视频数据将写入指定的输出文件中。 请注意,这只是一个简单的示例,可以根据你的需求进行修改和扩展。你可能需要更多的逻辑来处理视频数据,并进行更复杂的解析操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值