用于读取和写入 PLC 标签(在 AB Logix 5000 控制器上)的 CIP 服务是原子的吗?
Are CIP services for reading and writing PLC tags (on AB Logix 5000 controllers) atomic?
我正在关注使用 CIP 访问控制器数据的 Allen-Bradley 文档,特别是读取标签服务、写入标签服务以及 reading/writing 整个 UDT 的详细信息:https://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf。我正在使用 EIP 库来执行 read/write 标记服务和多服务请求。
我想澄清的是读取或写入整个 UDT 是否是一个原子操作(使用手册中概述的方法在一个服务请求中执行 read/write 并了解元数据以将其解包)?也就是说,当整体 read/written 成功时,PLC 或软件端是否永远不会看到部分更新的 UDT 值?
一个相关的问题是:如果我想通过在多服务请求中发送多个 Read/Write 标签服务请求来 read/write 多个标签,我对同步 [=18= 有任何保证吗? ] 对于标签集?我假设不是,但我似乎找不到关于该主题的任何权威文档。特别是如果请求在多个 CIP 数据包中被分割。
我们通常检查消息响应字段中的 "General Status" 以确定 CIP 消息的成功(完成??)或失败。但是,如果 PLC 在使用任何数据之前接收整个数据包至关重要,我将添加某种类型的计时器逻辑以确保在(自信地)使用数据之前(在启动消息之后)有足够的时间。懒惰的?是的。但它有效。
具体针对您关于通过 read/write 服务实现原子性的问题。一般的经验法则是不要依赖任何消息数据是原子的(尤其是大数据包)。您必须等待服务请求 feedback/response。
希望这对您有所帮助。
我能够对此进行测试并确认 read/write 标记 CIP 服务对于单个 UDT 或数组不是原子的。我最初关心的是我是否可以安全地写入整个 UDT 或数组,并确保处理该数据的 PLC 会看到该数据处于 "before written" 或 "after written" 状态,而不是某些部分写入的状态。我执行了一些测试,从 CIP 写入标签服务写入一个 10 元素 DINT 数组。在 PLC 上,我执行同步复制 (CPS) 将数组复制到另一个标签中,然后检查它以查看数据是否与被原子复制一致。我看到数据偶尔处于部分写入状态,这意味着写入标签服务与同步复制指令不同步。请注意,我使用单个 CIP 服务请求来写入数组,而不是针对每个元素的多个请求。这并非完全出乎意料,但很高兴知道来自 CIP 服务的任何 reading/writing 多个值都知道缺少同步。在需要的情况下,我可以添加自己的同步机制。
在工作中我们发现任何超过 DINT 的 read/write(我们没有尝试更小的数据)绝对不是原子的。
我们努力寻找一种方法来确定读取何时返回 "torn" 数据。我们最终发现 "tearing" 总是连续的。 read/written 值的第一部分是最新的,而下一部分不是。
所以我们使用了一组标记值。一个 DINT 在我们要读取或写入的任何标签的开头,一个在结尾。我们会将第一个哨兵设置为一个值,然后更新标签的其余部分。然后我们将设置最后一个哨兵。我们使用单调递增的值和哨兵的强制换行。
在读取这样的标签时,我们比较标记值。如果它们相同,那么我们就得到了很好的阅读。如果不是,我们再读一遍。
sentinel X header
<data>
sentinel X footer
如果数据在传输过程中是 "torn",我们看到:
sentinel X header
<data>
sentinel X-1 footer
我对此进行了大量测试(我创建并维护了一个用于与 Allen-Bradley PLC 通信的 C 库)并且我能够显示 "tearing" 两个 DINT 的简单数组。我没有尝试较小值的数组。
根据我们的经验,UDT 与 DINT 数组没有什么不同。如果该值大于 DINT,则可以相对于程序扫描对其进行部分读取或写入。
我正在关注使用 CIP 访问控制器数据的 Allen-Bradley 文档,特别是读取标签服务、写入标签服务以及 reading/writing 整个 UDT 的详细信息:https://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf。我正在使用 EIP 库来执行 read/write 标记服务和多服务请求。
我想澄清的是读取或写入整个 UDT 是否是一个原子操作(使用手册中概述的方法在一个服务请求中执行 read/write 并了解元数据以将其解包)?也就是说,当整体 read/written 成功时,PLC 或软件端是否永远不会看到部分更新的 UDT 值?
一个相关的问题是:如果我想通过在多服务请求中发送多个 Read/Write 标签服务请求来 read/write 多个标签,我对同步 [=18= 有任何保证吗? ] 对于标签集?我假设不是,但我似乎找不到关于该主题的任何权威文档。特别是如果请求在多个 CIP 数据包中被分割。
我们通常检查消息响应字段中的 "General Status" 以确定 CIP 消息的成功(完成??)或失败。但是,如果 PLC 在使用任何数据之前接收整个数据包至关重要,我将添加某种类型的计时器逻辑以确保在(自信地)使用数据之前(在启动消息之后)有足够的时间。懒惰的?是的。但它有效。
具体针对您关于通过 read/write 服务实现原子性的问题。一般的经验法则是不要依赖任何消息数据是原子的(尤其是大数据包)。您必须等待服务请求 feedback/response。
希望这对您有所帮助。
我能够对此进行测试并确认 read/write 标记 CIP 服务对于单个 UDT 或数组不是原子的。我最初关心的是我是否可以安全地写入整个 UDT 或数组,并确保处理该数据的 PLC 会看到该数据处于 "before written" 或 "after written" 状态,而不是某些部分写入的状态。我执行了一些测试,从 CIP 写入标签服务写入一个 10 元素 DINT 数组。在 PLC 上,我执行同步复制 (CPS) 将数组复制到另一个标签中,然后检查它以查看数据是否与被原子复制一致。我看到数据偶尔处于部分写入状态,这意味着写入标签服务与同步复制指令不同步。请注意,我使用单个 CIP 服务请求来写入数组,而不是针对每个元素的多个请求。这并非完全出乎意料,但很高兴知道来自 CIP 服务的任何 reading/writing 多个值都知道缺少同步。在需要的情况下,我可以添加自己的同步机制。
在工作中我们发现任何超过 DINT 的 read/write(我们没有尝试更小的数据)绝对不是原子的。
我们努力寻找一种方法来确定读取何时返回 "torn" 数据。我们最终发现 "tearing" 总是连续的。 read/written 值的第一部分是最新的,而下一部分不是。
所以我们使用了一组标记值。一个 DINT 在我们要读取或写入的任何标签的开头,一个在结尾。我们会将第一个哨兵设置为一个值,然后更新标签的其余部分。然后我们将设置最后一个哨兵。我们使用单调递增的值和哨兵的强制换行。
在读取这样的标签时,我们比较标记值。如果它们相同,那么我们就得到了很好的阅读。如果不是,我们再读一遍。
sentinel X header
<data>
sentinel X footer
如果数据在传输过程中是 "torn",我们看到:
sentinel X header
<data>
sentinel X-1 footer
我对此进行了大量测试(我创建并维护了一个用于与 Allen-Bradley PLC 通信的 C 库)并且我能够显示 "tearing" 两个 DINT 的简单数组。我没有尝试较小值的数组。
根据我们的经验,UDT 与 DINT 数组没有什么不同。如果该值大于 DINT,则可以相对于程序扫描对其进行部分读取或写入。