摘 要∶根据计算机监控系统的特点,用Visual Basic 6.0开发通用的计算机监控系统测试软件。该软件既能充当主控机,又能充当受控机,还可用来破译通讯协议,可靠性高,实用性强。同时,对Microsoft的MSComm通讯控件中的Bug作了修正。
关键词∶通用软件,监控,主/受控机,可靠实用,通讯,Bug
一、MSComm控件中存在的问题及解决方法
VB5.0/6.0的MSComm通信控件提供了一系列标准通信命令的接口,它允许建立串口连接,可以连接到其它的通信设备(如Modem),还可发送命令,进行数据交换以及监视和响应在通信过程中可能发生的各种错误和事件,从而可以用它建立全双工的、事件驱动的、高效实用的通信程序。但在实际通信软件设计过程中,MSComm控件并非象想象中的那么完美和容易控制,特别是在中文Win9X环境下通信时更会出现问题。
MSComm控件是通过向其Input 与 Output属性输入字符串来实现数据的输入与输出的。由于在中文Win9X环境下使用的是双字节字符集(DBCS)系统,MSComm.Output=Chr(I), 当0<=I<129或I=255时,能正确发送数据,128<I<255时,发送出去的全是0。解决这个问题的方法是将需要发送的数据放入一个Byte型数组中。类似地,在接收数据时,也不能简单地将MSComm.Input中的内容放入一个字符串变量中,否则,同样会丢失数据,这可通过采用Variant变量来解决。
RThreshold属性为设置并返回需要接收多少数据才能激发ONComm事件comEvReceive。如果取1,则一接收到数据便产生comEvReceive事件,当数据量较大时,一个数据包将被分成多个小的数据包;如果为N(N>1),则接收到N-1个数据时,却不会产生comEvReceive事件,这样就不能及时响应并处理受控机主动发送过来的较短的报警信息。显然,该属性应取1,对于大批量数据,估算其时间,进行累加即可。因为在计算机监控系统中,通讯协议是明确的,最大的数据包的长度以及主控机发送查询命令时,受控机的响应数据长度也是已知的。其它有关属性可以参考Visual Basic的例子程序VBTerm.
MSComm控件是用32位Windows API函数来实现的,其中,COMMTIMEOUTS结构用来限时。其结构成员ReadIntervalTimeout表示相邻两个字节之间的最大延时(单位为毫秒,下同),如果超过这段时间,则立即返回,其后的数据被当做下一个数据包。ReadTotalTimeoutMultiplier表示读取每个字节所花费的时间。ReadTotalTimeoutMultiplier与所接收到的字节数的乘积加上ReadTotalTimeoutConstant,即为本次读取操作的最大时间(限时)。写操作限时WriteTotalTimeoutMultiplier与 WriteTotalTimeoutConstant和相应的读操作限时类似。经过调试跟踪发现,在运行过程中,ReadIntervalTimeout被设置为-1, WriteTotalTimeoutConstant=5000(即5秒),其余成员的值均为0。即对于读操作,一接收到数据则立即返回,即使没有收到数据也可导致返回,这就可能导致接收时数据丢失;对于写操作,不能超过5秒,5秒后的数据被中断,这对于低传输率的计算机监控造成了困难。解决方法见程序1。
Public Type COMMTIMEOUTS
ReadIntervalTimeout As Long
ReadTotalTimeoutMultiplier As Long
ReadTotalTimeoutConstant As Long
WriteTotalTimeoutMultiplier As Long
WriteTotalTimeoutConstant As Long
End Type
Public timeouts As COMMTIMEOUTS
Declare Function GetCommTimeouts Lib "Kernel32" _
(ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
Declare Function SetCommTimeouts Lib "Kernel32" _
(ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
Public Sub OpenAndAdjustPort()
Dim Ret As Long
If Main.MSComm1.PortOpen = False Then
Main.MSComm1.PortOpen = True
Ret = GetCommTimeouts(Main.MSComm1.CommID, timeouts)
timeouts.ReadIntervalTimeout = 1000 * 10 \ Val(Main.MSComm1.Settings) + 100
timeouts.ReadTotalTimeoutMultiplier = 1000*10\Val(Main.MSComm1.Settings) + 100
timeouts.ReadTotalTimeoutConstant = 1000
timeouts.WriteTotalTimeoutMultiplier = 1000*10\Val(Main.MSComm1.Settings)+ 100
timeouts.WriteTotalTimeoutConstant = 1000
Ret = SetCommTimeouts(Main.MSComm1.CommID, timeouts)
End If
End Sub
程序1对MSComm控件的修正
二、软件的设计与开发
主界面见图1所示。其中,Hex与Char文本框以两种方式显示需要发送或接收到的数据。下面的客户区用来监视通讯状态,包括当前端口的开关、参数等,以及信号线的变化、接收到的数据。所有事件均在客户区显示其发生的时间(TickCount)。Open按钮打开串口,Close关闭串口,Setup设置串口参数(见图2),Send则用来发送数据(当Hex与Char文本框中都有数据时,Hex中的数据优先),Parity(见图6)用来计算Xor、Add、Crc校验码,还可计算数据长度,Char/Hex实现字符与ASCII码的相互转换,Find用来查找客户区中的信息,Clear则清除所有文本框中的内容。主界面如此小巧,是为了实现在同一屏幕对多个串口同时进行监控或测试。
在图1中按下Setup按钮时,显示图2所示的对话框。Port可从1至16,因而,理论上,本软件可以同时调试16个串行口;波特率从110至256000,选择范围较大。
某些带隔离的RS232/485转换器在RS232端需要通过设置DTR有效来提供电源(RS485端另配电源),这可通过核选DTR来实现。RecErr核选框用来记录错误数据包,图2表示,如果接收到的数据不是Crc校验,则认为数据有误,并记录之。图3为错误记录,包括发生时间及数据,图4为测试报告,其中包括详细的测试时间,发送的数据报文总数,响应和未响应的数目、错误的数目,最后是用百分数表示的正确率。同时,图2 的校验也是数据报文的校验,根据图2的选择,可以在图1 发送的数据中自动添加相应的数据报文校验码。Length文本框中为一次接收的最大数据长度,因为有些智能设备或数采器的数据发送并不太连续,需要作一定的等待,本程序根据数据长度及波特率决定等待的时间长度。其下的组合框主要用来破译通讯协议,如图2选择Receive时,主控机发送图5所示的第1栏中的数据时,自动记录受控机响应的数据(放入对应的第2栏中)。Auto核选框用来选择是否工作在自动状态,当选择自动时,如果Time(ms)中的数据为零,则该计算机可作为受控机使用,当收到图5所示的“ff03fc010016”时,则自动应答“ff0312345600000078”;如果Time(ms)中的数据不为零,则该计算机作主控机使用,每隔一段时间(Time(ms)中所示的毫秒数),轮流发送图5第1栏中的通讯协议,并接收受控机的响应。核选Sound核选框时,当有数据到达,则声音提示,否则关闭此功能。
在图1中按下Parity按钮时,显示图6所示的对话框。此对话框可计算三种校验码及字节长度。
三、软件的应用
1.一般应用
在图2中设置好串口参数,校验码,如Add,所接收的最大的数据字节数即可。然后,在图1中打开串口,在Hex文本框中输入需要发送的数据,如320F,再点击Send按钮,则发送320F41(41为自动计算的Add校验码)。
如果需要发送的数据在校验码后还有其它数据时,就得另行计算了。如对于松下PLC,报文“%01#WDD 10000 10001 0100 5000 BCC CR”的含义为∶往PLC的10000数据寄存器中写入0001(低字节在前),10001中写入0050,BCC为异或校验码,CR为回车符0X0D。将BCC以前的字符输入图1中的Char文本框中,点击Char/Hex按钮,即可在Hex文本框中得到对应的16进制值,再点击Parity按钮,将原先的16进制值输入图6中的Hex文本框中(可利用剪贴板进行),点击Calculate按钮,即可在Result文本框中得到异或结果,将此结果追加至图1中的Hex文本框中,再添上0D(即CR,松下PLC的报文结束标志),点击Send按钮,任务完成。
2.作为受控机
如果核选图2中的Auto核选框,并且,Time(ms)中的数据为零,则该计算机可充当受控机角色,自动应答主控机的查询命令,如图5所示,当收到第1栏中的数据时,自动发送对应的第2栏中的内容。这种功能可用来调试或开发主控机程序,特别地,当受控机为昂贵的智能设备时,可用下文3.4和3.5介绍的方法截取通讯协议,然后,用多台计算机模拟该昂贵的智能设备,使多位科研人员并行开发,从而大大节省了投资,也极大地提高了工作进度。
3.作为主控机
如果核选图2中的Auto核选框,并且,Time(ms)中的数据不为零,则该计算机可充当主控机角色,根据Time(ms)文本框中确定的毫秒数,自动发送图5第1栏中的通讯协议,同时接收受控机响应数据,并在图1以两种格式(16进制及字符)进行显示。这种功能可以用来调试受控机程序。
如果同时核选RecErr核选框,并选择其下的校验标志,则在作为主控机使用的同时,可以测试受控机的性能(测试报告格式见图4所示),在计算机监控系统中,需要选择一些数采器,可用此方法测试该数采器的性能,从而决定取舍。
4.截取测试机发送的通讯协议
现假设某公司生产一智能设备,与该设备配套的厂家的测试软件运行于测试机上。作者的通用多功能计算机监控系统测试软件运行于侦听机上,现欲截取测试机与智能设备之间的通讯协议,并破译之。见图7所示。
将侦听机中的软件设置为受控机状态(见3.2节),并在图2中选择Send(与Receive相对),则测试机发往智能设备的所有通讯协议全部被收录进图5所示的第1栏中,而对于重复的数据,只记录第一批。
5.截取智能设备响应的通讯协议
将侦听机中的软件设置为主控机状态(见3.3节),并在图2中选择Receive (与Send相对),改为由侦听机向智能设备发送通讯协议,则智能设备所响应的通讯协议自动收录进图5所示的第2栏中,并且,新数据将覆盖旧数据。
6.破译通讯协议
由于图1下面的客户区充分地显示了串口的历史状态,又能采用3.4与3.5两节的方法完全截取通讯协议,因而,破译通讯协议就不成为什么大问题了,只要根据数据库中的内容和相应的历史状态进行编程即可,从而,用自己的软件来监控智能设备。例如,当手机发生死锁时,也可截取其通讯协议,以后发生类似的情况后,可以自己进行解锁了。
本软件的主界面较小,对话框为非模型的,因而,可以在一个屏幕上同时监控多个智能串口设备,而且,可以共享一个校验码对话框。
四、结论
该软件经过反复调试,在实际工作及工程中得到了验证,并多次进行了改进和加强,可靠性高,方便实用。(bjmyc@263.net)
参考文献∶
1Microsoft著,Microsoft Visual Basic 6.0 Component Tools Guide,America,Microsoft Press,1999
2 Microsoft著,欣力、李莉等译·Microsoft Win32程序员大全(1~5),北京:清华大学出版社,1995
3 马玉春·用Visual C++ 5.0开发串行通讯控件·微型机与应用,1999·7,P11
|