2.受控机协议的动态生成技术
图8的第1条受控机协议(Slave)中有6个“*”号,表示3个随机字节,来模拟动态的仿真模块的 Reply 协议(见图1)。带“*”号的受控机协议作为 RandomPackage 函数的参数,最后返回将“*”号替换成随机字节的16进制字符串。其中的 oString 是一个自定义字符串处理类的对象,FeatureCount 函数仅完成第一个字符串中包含的第二个子字符串的个数;ReplaceSubString 函数将 strData 中第一次出现“**”的地方用 strTmp 替代。
Public Function RandomPackage(ByVal strData As String) As String
Dim strTmp As String
Dim I As Integer = 0
Dim rnd As New Random
'计算随机字节的个数
Dim nCount As Integer = oString.FeatureCount(strData, "**")
Dim ByteBuffer(nCount - 1) As Byte '定义数组存放随机字节
rnd.NextBytes(ByteBuffer) '产生随机字节放入数组
Do While nCount > 0
strTmp = ByteToTwoHexChars(ByteBuffer(I)) '字节转换为16进制字符串
'2个 ** 用2个16进制字符替换
strData = oString.ReplaceSubString(strData, "**", strTmp)
I += 1
nCount = oString.FeatureCount(strData, "**")
Loop
Return strData
End Function
如图8配置通信协议,将 TestPort 设置为自动受控机,配合主控程序,截取的Oven2 的温度曲线如图11所示,跟图3相比,显然非常随机。主控程序正常测试,不知道已经将仿真模块替换成了 TestPort 工具。

3.数据库与 DataGridView 的使用技巧
RS-232/RS-232 协议转换器有协议截取功能,截取的通信协议可以直接供 TestPort 使用。这些工作都离不开数据库的操作。本文还设计了 ADO_NET_ACCESS 类,用来处理 Access 数据库,首先根据数据库(包括绝对路径)获取连接字符串 ConnectionString,然后,完成数据库的初始化(New)。WriteData 方法用来更新数据库。
GetAccessConnection 方法用来获取 ConnectionString。首先声明一个 OleDbConnectionStringBuilder 对象 csb,显然,数据库的类型是确定的,其 Provider 也随之而定;DataSource 是包含数据库的绝对路径,如果不为空,即返回构造完毕的 ConnectionString。
Private Function GetAccessConnection(ByVal strDB As String) As String
Dim csb As OleDbConnectionStringBuilder = _
New OleDbConnectionStringBuilder()
csb.Provider = "Microsoft.Jet.OLEDB.4.0"
csb.DataSource = strDB
If strDB = "" Then
Return ""
Else
Return csb.ConnectionString
End If
End Function
ADO_NET_ACCESS 类的构造函数 New 有两个参数,strDB 是数据库名,strCommand 是 SQL 语句,用来选择一个表。调用 GetAccessConnection 方法获得 ConnectionString 后,即可调用数据库适配器 OleDbAdapter 的构造函数,得到初始化后的对象 _adapter(全局变量,定义略)。通过字符串操作,在 _strCharSet 中找到表名,映射到 DataSet 中。最后,填充数据集 DataSet 对象 ds,数据表DataTable 对象dt 和表的数目。如果有错误,则表的数目为0,错误提示保存到变量中。
Public Sub New(ByVal strDB As String, ByVal strCommand As String)
'permit only one select with primary key
_strConnection = GetAccessConnection(strDB)
_strCharSet = strCommand
_adapter = New OleDbDataAdapter(_strCharSet, _strConnection)
'以下代码获取表的名称
Dim nLocation As Integer = InStr(_strCharSet, "From", CompareMethod.Text)
Dim strTmp As String = Mid(_strCharSet, nLocation + 5)
Dim J As Integer = 1
Dim strSub As String = Mid(strTmp, J, 1)
Do While strSub <> " " And strSub <> ";" And strSub <> ""
_strTableName &= strSub
J += 1
strSub = Mid(strTmp, J, 1)
Loop
'将表的名称映射到 DataSet 中,以便使用
_adapter.TableMappings.Add("Table", _strTableName)
_ds = New DataSet
Try
_adapter.Fill(_ds)
_dt = _ds.Tables(0)
_nTables = 1
_strErrorAdapter = ""
Catch ex As Exception
_nTables = 0
_strErrorAdapter = ex.Message
End Try
End Sub
数据库的更新是一个非常繁琐的操作,WriteData 巧妙地利用了 OleDbCommandBuilder 对象,可以对Update、Delete 和 Insert 命令造成的数据库变化进行统一的更新。如果更新成功,则返回0;否则返回1,并保存错误提示信息。
Public Function WriteData() As Integer
Dim cmdBuilder As OleDbCommandBuilder = _
New OleDbCommandBuilder(_adapter)
_adapter.UpdateCommand = cmdBuilder.GetUpdateCommand
_adapter.DeleteCommand = cmdBuilder.GetDeleteCommand
_adapter.InsertCommand = cmdBuilder.GetInsertCommand
Try
_adapter.Update(_ds)
_strErrorWrite = ""
Return 0 'Success
Catch ex As Exception
_strErrorWrite = ex.Message
Return -1 'Error
End Try
End Function
ADO_NET_ACCESS 类提供的外部可见的只读属性如表1所示,这些属性可以方便地用于数据库操作以及在 DataGridView 控件中使用。

在一个窗体中显示数据库中的数据,只要在窗体上绘制一个 DataGridView 控件(对象名为 dgv)即可,不需要额外的辅助控件。首先,在窗体类中定义如下变量,bDataChanged 变量表示 dgv 中的数据是否变化,如有变化,则需要写入数据库。bs 对象是 dgv 与数据库对象 myData 的纽带。
Dim strCommand As String = "select * from Protocols order by [ID]"
Dim bDataChanged As Boolean = False
Dim myData As ADO_NET_ACCESS
Dim dt As DataTable
Dim WithEvents bs As BindingSource = New BindingSource
通过 RefreshData 函数,将数据库中的数据填入 dgv 对象。myData 的 dt 对象,则可以直接用于在后台对数据库进行操作。RefreshData 函数一般放置在窗体的 Load 事件处理程序中。
Private Sub RefreshData()
myData = New ADO_NET_ACCESS(strDataPath, strCommand)
If myData.nTables = 0 Then
MessageBox.Show(myData.ErrorAdapter, Me.Text, _
MessageBoxButtons.OK, MessageBoxIcon.Error)
End
End If
dt = myData.dt
bs.DataSource = myData.ds
bs.DataMember = myData.TableName
dgv.DataSource = bs
End Sub
在 bs 对象的ListChanged 事件处理程序中输入如下代码,标志数据的变化。
If myData.ds.HasChanges Then bDataChanged = True
在 dgv 的 RowValidated 和窗体的 FormClosed 事件处理程序中,调用 SaveChanges 子程序,即可保存数据变化到数据库中。这样,几乎用最简捷的代码,完成了 dgv 的前台显示和数据库的后台更新。
Private Sub SaveChanges()
If bDataChanged Then
Dim nRet As Integer = myData.WriteData()
If nRet = -1 Then
MessageBox.Show(myData.ErrorWrite, Me.Text, _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Me.bDataChanged = False
End If
End Sub
4.在远程测试中的应用
TestPort 具有强大的功能,如果仅仅用于传输距离只有15米之内的串行通信测试,显然是个浪费。这个问题可以通过RS-232/RJ-45协议转换器来解决,具体模型如图12所示。TestPort 和远程受控机都通过 RS-232 接口与 RS-232/RJ-45 协议转换器连接,从而都具有了网络通信功能。与受控机相连的协议转换器工作在服务器模式,等待客户机的连接请求。与 TestPort 相连的协议转换器工作在客户机模式,连接到服务器,从而建立了 TCP 通信管道。这样,TestPort 就可以通过 Internet 对远程受控机进行透明测试。

六、 结论
计算机监控系统广泛应用于众多领域。本文设计了计算机监控系统中常用的仿真模块及其通信协议,开发了辅助工具及通用串口设备测试工具,并给出了相应的应用模型和实例。在计算机监控的通用数据处理技术以及串行通信方面给出了核心代码。数据库操作及显示通常是编程必不可少的环节,本文设计了 ADO_NET_ACCESS 类,并用简捷的代码实现了数据库中数据的显示与更新。利用本文的仿真模块、辅助工具及测试工具,可以在高校的计算机房零成本搭建多种形式的计算机监控系统的仿真开发平台。所有软件与实例系统均经过了严格的测试,可以广泛地用于仿真开发与教学工作。
参考文献
[1] 马玉春. 计算机监控技术与系统开发[M]. 北京: 清华大学出版社, 2007.1
|