和深圳某家公司合作光伏云的项目,我们主要做数据传输模块,对方负责开发云端,光伏逆变器外采。针对不同的应用场景,做了三款产品。来来回回用了一段时间,反响还不错,和其他同类产品相比还比较稳定。图一是其中一款用得较多的数据传输模块。
前一段时间现场的工程师报了一个问题,处理过程比较有趣,就记录了下来。
数据传输模块(也即数据透传模块,简称DTU)安装在逆变器上,通过串口把逆变器的数据接收过来,DTU通过GPRS(2.5G)转发给服务器。DTU最重要的是不能断网,任何情况下导致断网都必须重新连接后台,保证数据的连续性。
工程师报告,使用组态软件连接DTU(串口连接),把数据发送到服务器。数据是按包的方式定时发送的,每过5分钟会有一个包丢失。有多个设备通过组态软件连接DTU,也就是说有很多包丢失了。
接到报告后,我开始着手搭建环境,模拟现场。工程师使用的是modbus slave,我找他要来相应的版本软件。DTU与一台小的Mini台式机相连,在我自己的阿里云上运行自己写的网络调试工具。
数据包一个个发出去,几个小时下来,没有出现丢包的现象。把modbus slave换成串口调试助手,也没有出现丢包现象。我把数据包调大,大概200字节一次发送,这次出现了。
联系后台软件工程师,用他的云平台配合modslave以及DTU配合测试。其中DTU与台式机通过USB转串的设备连接,后面也尝试直接用串口线连接。经过20小时的测试,现象不大一致。使用USB转串设备进行测试的,仍旧有拆包现象;使用原生串口的,没有发现拆包现象。不过,对比了服务器的后台记录,基本没有拆包,也有命令包直接就丢失了。
百思不得其解。要后台的工程师配合我,协调起来很麻烦。我回到阿里云,用自己的网络软件模拟后台。同时把modbus slave撤了,用自己以前的代码写了个串口调试的工具,继续测试。这回,不管是usb转串的还是原生串口连接,都没有出现丢包拆包。光伏云项目中,数据获取是有后端服务器软件发起的,由其发送命令包,通过DTU传送给设备,设备再通过DTU发给服务器。在测试中还发现一个现象,如果服务器发送命令包向设备要求数据,时间频率如果设为每5秒发一次,丢包现象还会出现;设置为30秒一次,则机会没有出现丢包过。
看起来有好几个问题混杂在一起,产生了这样奇怪的现象。首先,排除DTU本身固件的问题,DTU中采用了DMA机制,以单片机的处理速度,这点串口数据不应该会处理不了。最大的问题应该有两个:
1 modbus slave和串口调试助手在串口读写的编程中,有哪个地方没有处理好,导致了拆包的现象;
2 至于丢包现象,和服务器端的软件有关。工程师可能习惯了平常的internet,没有考虑到GPRS的网络稳定性远低于有线或者wifi网络。不能过于频繁的去塞数据。
分析完了,寻找证据。第二个问题好解决,请后端工程师改下通讯频率就行了,回头一起测试。 至于第一个问题,只能反汇编modbus slave了。很幸运,用IDA反汇编后,我读了半小时代码,找到了问题所在,如图2。
问题出在SetCommTimeouts函数。定位到SetCommTimeouts函数的调用位置,其前三个参数分别为ReadIntervalTimeout=0xffffffff;ReadTotalTimeoutMultiplier=0x00; ReadTotalTimeoutConstant=0x00。也就是说,modbus slave读取一次缓冲区,读操作就完成了。
这样操作是有点问题的,对照我自己的代码,把三个参数分别改为:0x64,0x0A,0x3E8。这些修改是把exe当做文件编辑的,相当于在字节码上直接修改了。
Modbus slave的软件hack完了,重新搭建环境。4个小时后,测试结果显示,修改后的modbus slave没有出现拆包丢包现象。