Chapter 3 配置和构建

配置

用代码的方式构建项目的好处是强类型支持和优秀的智能提示,但是纯代码的方式既不够简洁,也不够灵活。我们可以把测点项目中的纯静态结构用一个配置文件加以描述:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <!-- 可以有1~N个通道 -->
	<Channel name="S7-1" driver="S7">
		<IpAddr>192.168.10.2</IpAddr>
		<Rack>0</Rack>
		<Slot>1</Slot>
	</Channel>
	<Channel name="S7-2" driver="S7">
		<IpAddr>192.168.10.2</IpAddr>
		<Rack>0</Rack>
		<Slot>1</Slot>
	</Channel>

    <!-- 可以有1~N个测点组作为入口 -->
	<TagGrp name="信号区-1#" isEntry="true" isEnabled="true" channel="S7-1" scanInterval="10">
		<TagCbnt name="PLC" address="DB10.16" access="RO">
			<Tag name="心跳" address="DB10.16.0" type="BIT"></Tag>
			<Tag name="复位" address="DB10.16.1" type="BIT"></Tag>
			<Tag name="故障" address="DB10.18" type="INT16" endian="BigEndian"></Tag>
            <!--  ...more... -->
		</TagCbnt>
		<TagCbnt name="IPC" address="DB10.0" access="RW">
			<Tag name="心跳" address="DB10.0.0" type="BIT"></Tag>
			<Tag name="复位" address="DB10.0.1" type="BIT"></Tag>
			<Tag name="自动" address="DB10.0.2" type="BIT"></Tag>
			<Tag name="结束确认" address="DB10.0.3" type="BIT"></Tag>
            <!--  ...more... -->
		</TagCbnt>
	</TagGrp>

	<TagGrp name="信号区-2#" isEntry="true" isEnabled="true" channel="S7-1" scanInterval="10">
        <!--  ...more... -->
	</TagGrp>


    <!-- 可以有0~N个逻辑组件 -->
	<Logicet>Samples.Plugin1/Samples.Plugin1.dll</Logicet>
	<Logicet>Samples.Plugin2/Samples.Plugin2.dll</Logicet>
	<!--  ...more... -->
</root>

这里的有些基本规则:

  • 整个<root/>可以分成三大部分:
    • <Channel/>(1~N个):描述了项目中用到的通道。
    • <TagGrp/>(1~N个): 描述了项目中用到的测点树。
    • <Logicet/>(0~N个): 描述了项目中用到的业务逻辑(插件)。
  • <Channel/>
    • name属性:表示通道的名称,会被测点(以及TagCbnt,TagGrp)所引用。
    • driver属性:表示该通道使用的底层驱动,e.g. S7COM等。每种驱动的通信方式并不相同。
  • <TagGrp>
    • 通常顶层的<TagGrp/>会标注isEntry来表明这是一个入口。一个项目可以有多个入口,这些入口会被并行执行。
    • <TagGrp/> 表示一个逻辑分组,其下可以套多层,最终会嵌<TagCbnt/>或者<Tag/>。但是有一些底层驱动不支持批量读写,这时候<TagCbnt/>就是非法的;而另一些底层驱动可能并没有针对单个测点的读写提供支持,这时候直接嵌套<Tag/>也是非法的。总之,使用 <TagCbnt/>还是<Tag/>,要查看通道测点的驱动。
    • 测点的地址是和通道驱动密切相关的,每种驱动的地址都不相同。比如在S7DB100.10.0代表的是DB100的第10个字节的第0个比特,特别的,可以用$$10.0代表使用和父级一致的Block;而对于OpcUA,地址则可能是ns=4;s=|var|CODESYS Control Win V3 x64.Application.PLC_PRG.var3
    • 测点的访问方式有RO| WO | RW | R1W,对应的是 只读只写读写只在开始时读1次,后续只写,默认是RW
    • 测点的通道检索是冒泡的。即如果本层节点未指定channel特性,则会向上冒泡检索,直至在祖先节点上检索到非空的通道(或者最终都没有检索到,会给出null)
  • <Logicet/>: 如果你偏好使用代码的方式注册逻辑,可以不用这里的动态插件机制。

构建

然后,我们可以使用这个配置文件来构建ITagsProject

var dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 

// 或者,如果不指定root,将会自动加载`dir/`下的`index.xml`文件
var root = XDocument.Load(xmlFileName).Root;
var proj = factory.Create(dir!, root);  

// ... 可选:可以手动注册 Logicets 、可以手动监听事件

// 运行测点项目
await proj.RunAsync(ct);