CCN Gateway 版本升级记录

请下载并解压缩zip压缩包,内有2个固件文件,一个是BACnet版本,另一个是Modbus版本

对于CCN Gateway 3.00之前的版本,请参见本页的底部

3.06  2025.04.10  下载

修复“IP路由”重启后丢失的问题。

3.05  2025.02.26  下载

修复bug当CCN总线上冲突时可能导致后台进程崩溃。

从BACRouter 6.09同步升级BACnet ms/tp驱动。

2.26  下载

BACRouter 版本升级记录6.00+

BACRouter从v6.00开始改用ARM芯片,新的固件文件格式为:xxxx_xxxx_6.00_arm_xxxx.tar.gz

v6.00之前的固件,  请访问:  老固件升级记录

6.12  2025.04.29  下载

ARC156: 当下一站点已被证实,如传递令牌失败时,重试一次。

ARC156: 当一帧的时间小于5位时,将其视为噪声。

6.11  2025.04.02  下载

ARCnet 标准和 COM20019i 的数据手册规定时钟精度应为 0.01% 或更高,因此我们之前的实现采用保守的时钟误差校正逻辑来容忍 0.05% 的时钟误差。在测试 ZN551 和 AAR 模块后,我们发现在解码数据包时,它们实际上可以容忍高达 4.5% 的时钟误差(当然重配置过程允许时钟误差仍须小于0.2%),猜测它们将接收器时钟与每个字节之前的脉冲同步。在此版本中,我们实施了一种激进的逻辑来实现类似或更好的性能。

6.10  2025.03.28

ARC156: 当2段总线均有活跃节点,在合并时,运行信息中“总线上节点”可能检测到错误的“活跃节点“。其解决方案是两次检测以避免假信号。

ARC156: 当BACRouter是总线上唯一节点时,BACRouter将不停发送ITT包(邀请发言包)以查找其它节点,数据包将无法被发出,所有发往此端口的NPDU将在队列中超时,这将在日志内留下烦人的记录。在此版本中,如果 BACRouter 发现自己是总线上的唯一节点,它会以合理的速率删除队列中的数据包,并将其记录在包捕捉缓冲区中以假装将数据包发送出去。因此,在捕捉到的包记录时,可以看到BACRouter 发送数据包但没有得到响应,此行为模式与其他数据链路类型一致。

Modbus RTU:某些设备不遵守字节之间的 T15空闲时间规定,我们删除了该验证以提高兼容性。

应用程序设置:删除了“客户端模式”以符合 BTL 要求。

Modbus/自由协议:调试映射或脚本时,经常需要从 BACnet 端执行写入,此时用户必须启动 BACnet 客户端,例如 Yabe。而计算机上通常已经有一个 BACnet 服务器在运行,此时用户必须启动 虚拟机 来运行 Yabe。这浪费了很多时间,所以我们在运行信息页面上集成了写入功能。

6.09  2025.02.26  下载

MSTP bug可能导致特定的NPDU包内容被丢弃。

6.08  2025.01.23  下载

Modbus WebUI:

当对映射于单个寄存器的Analog对象进行写测试时,其字节序应该引用“单寄存器字节顺序”设定,而不是“大整数字节顺序”设定。

当对映射于2个寄存器的Multi-state对象进行写测试时,其字节序应该引用“大整数字节顺序”设定,而不是“单寄存器字节顺序”设定。

自由协议设备的运行信息页面中,Binary对象的真实值应参考极性设定。

6.07  2025.01.10  下载

BACRouter高度依赖高精度定时器,当有电磁干扰的场合,板上晶振可能受到干扰,造成定时器偏移,进而导致程序错误。本版本加入了纠正程序。

6.06  2025.01.07  下载

自由协议的Binary输出对象的bug,由v6.01的“信号极性”特性引入。

Modbus主站模块:当写入到只读数据地址时,有的设备无响应,而不是报告错误码。在这种情况下,BACRouter将会不停尝试造成设备掉线。在本版本中,BACRouter只会重试3次。

6.05  2025.01.04

重构底层arc156及mstp驱动以简化代码。

ARC156: 当节点对“Free Buffer Enquiry”持续回应NAK时,丢弃发往该节点的包。

WebUI:当IP或子网掩码被修改,但DHCP服务仍保持启用时,提醒用户。

6.04  2024.12.26  下载

ms/tp错误修正: 当往ms/tp端口发送NPDU接近1497字节时可能触发bug.

6.03  2024.12.25

ARC156 驱动已可用。

6.01  2024.12.06

修正bug: Modbus与自由协议模块中总线名称冲突检测。

自由协议:Binary对象增加“信号极性”属性。MultiState对象的状态数量增加最多256限制。

BACRouter内置的Modbus 网关

因版本4.26于2023-03-07更新

从固件版本4.x起,BACRouter内置了Modbus网关功能。这篇文章尝试解释其底层运作机制。

Modbus 读

BACRouter周期性地读取点数据并缓存。“刷新间隔”定义读取数据的间隔。

为了提高性能,BACRouter将尽可能在一次事务读取更多数据。在Modbus标准中,最多2000个位(指线圈或离散输入)或125个寄存器(指输入或保持寄存器)可以在一次请求中读回,但是特定的Modbus从站可能不支持读取大量的数据。在BACRouter的WebUI的”从站设定“页面的Modbus参数对话框中,”批量读比特位数“与”批量读寄存器数“两个参数定义了从站的对批量读数据的支持。

BACRouter不会分段读取单点的数据,即使”批量读寄存器数“小于该点占用的寄存器数。

通常来说,我们关心的数据的Modbus地址并不连续,比如我们只关心地址为1及2000的线圈,虽然我们可以一次批量读回地址1~2000的数据,然后抛弃地址2~1999的数据,先读取地址1的数据,再发请求读取地址2000的数据的做法可能更有效率。”比特位跳过“与”寄存器跳过“参数定义了在两个我们关心的数据地址中间,有多少个无用的数据允许被抛弃。假设在上述例子中,”比特位跳过“设为1998,BACRouter将尝试一次性读回地址1~2000,抛弃中间1998个数据。倘若”比特位跳过“为1997,则BACRouter将分两次读取地址1与地址2000。因为中间跳过的1998个数据大于设定值1997。

在从站的配置页面,“编组读取”显示读操作如何编组,并可进行测试。请特别关注服务端报告的非法数据地址!

Modbus 写

BACRouter不会合并写请求。当接收到写指令时将马上发出Modbus写请求。

对于写单个数据,有两个Modbus功能号可供使用。例如,功能5为写单个线圈,功能号15为写多个线圈但写数量可以为1。有的从站只支持其中一个功能号。”写单个线圈”参数指定采用哪个功能号。

同样地,”写单个寄存器“参数指定用于写单个寄存器的功能号。假设有任一个BACnet输出对象映射到多个保持寄存器,这意味着从站支持功能号16写多个寄存器,”写单个寄存器“将被关闭,功能号16将被采用。

离线

如果任何读写请求失败,BACRouter将会重试,如果连续失败次数达到3次,BACRouter将认为该从站离线。在离线状态下,BACRouter将间隔”离线刷新间隔“时间重试该请求。

在离线事件中,BACnet侧的反应将在后面描述。

Modbus 串行总线

BACRouter支持在同一条RS485总线上,不同波特率、奇偶较验、RTU/ASCII模式的从站共存。在发出请求前,BACRouter将根据从站的设定切换串口的参数。

如总线上的两个从站拥有相同的从站地址但是波特率或RTU/ASCII模式不同,BACRouter可以无冲突地通信。但是如果仅依赖不同的奇偶较验来防范冲突并不可靠,因为有的从站并不检查奇偶错误。

单设备映射模式

如VBUS网络端口未使能,BACRouter将工作于单设备模式,每个Modbus从站将被映射到”应用层设定“中定义的BACnet设备的不同对象实例空间。每个从站将占据1000实例空间。

对象的实际名称为“主站名称|从站名称|对象名称”,名隔分隔符”|”可由用户在数十个字符中选择。

依据BACnet标准的推荐做法,BACRouter将为每一个从站创建一个结构化视图对象。

本模式下当从站切换到离线状态,所有点的可靠性将被设为”COMMUNICATION_FAILURE”,当从站重新上线时,随着点数据的更新,各点的可靠性将被重新置回到”NO_FAULT_DETECTED”。

虚拟设备映射模式

当VBUS网络端口被使能,每个从站将被映射为VBUS网络上的虚拟BACnet设备。虚拟设备的MAC地址将从1开始。

在本模式下,所有从站必须有一个唯一的“设备实例号”。从站的BACnet设备名称为”主站名称|从站名称”,其中”|”为可选择的名称分隔符。

在本模式下如果从站切换到离线,依据BACnet标准的推荐做法,对应的虚拟BACnet设备将停止收发包以模拟离线状态。当从站重新上线时后,当更新完所有点数据后,虚拟BACnet设备将退出离线状态。

从站状态

针对每一个从站,BACRouter在缺省BACnet设备内创建3个对象。一个名为”online”的二进制输入对象,代表从站的上线状态。一个名为”update_delay”的模拟输入对象,代表最近平均数据更新延迟(对比”update_delay”), 最后一个是名为”fail_rate”的模拟输入对象,代表相对长时间内的Modbus侧通讯失败率。

这些对象名均有“主站名称|从站名称|comm|”的前缀,其中“|”为可选择的名称分隔符。

对象实例号分配

对象的实例号单独进行定义。当对象编辑窗口提交时,如对象被启用,将分配其声明的实例号,如该实例号被占用,将自动选择一个可用的实例号。

值对象

值对象的特性与属入对象类似,如值对象映射到可写Modbus地址时(0X或4X),此时值对象的当前值可写,写入的值被转发到Modbus侧(有以下2个例外)。

例外1:如果AV对象映射到保持寄存器,其数据类型为自定义,且其绑定的脚本不支持输出,此AV对象为只读。

例外2:如果AV对象映射到多个保持寄存器,但“写单个寄存器“参数生效,此AV对象为只读。

输出对象

输出对象对应的点值仍然会被定期读回,且设置成对象的Relinguish_Default属性。如果读回的值与上次写入的值不匹配,BACRouter将把该对象的可靠性置为 “UNRELIABLE_OTHER”,BACRouter将尝试每隔一段时间重新写入。如“容忍不匹配”选项被启用,如果读回的值与上次写入的值不匹配,该对象的可靠性将不变,BACRouter将尝试以”离线刷新间隔“重新写入。(于v4.34版更新)

因为以上的验证重写机制,BACRouter禁止2个输出对象映射的可写Modbus地址发生重叠。

浮点数的NaN

NaN是IEEE-754标准规定的特殊值,其意思为非有效数,BACRouter不接受NaN(正负无穷大仍然被视为有效值).

当一个Modbus点被定义为单精度浮点或双精度浮点,且BACRouter读到NaN值时,该点对应对象的可靠性将被设为”UNRELIABLE_OTHER”。

脚本不支持的数据

如一个模拟量对象为自定义,当从Modbus换算到BACnet时,脚本报告不支持的数据,此对象的可靠性将被置为”UNRELIABLE_OTHER”。

对于一个AO对象,如从BACnet换算到Modbus时,脚本报告不支持的数据,此对象的可靠性将被置为“PROCESS_RROR”。

对于一个AV对象,如从BACnet换算到Modbus时,脚本报告不支持的数据,此输出尝试被放弃,对象的可靠性保持不变。

BACnet MSTP自动地址分配

因为固件版本3.x,于2020.3.25添加:

因为不能保证所有设备同时上电,目前没有任何一种自动地址分配方案能够完全避免MAC地址冲突,所以我们从固件3.x版中移除了自动地址分配特性。为了帮助确定当前总线的“最大扫描地址”与空闲的MAC地址,用户可以启用“侦听”模式,然后在“运行信息”页面中,找到“当前最大扫描地址”,再通过“最近活动的其它站点”,找到未使用的MAC地址。

MSTP总线上的每一个设备必须有一个独特的MAC地址。对于主站设备,合法的地址范围为0~127,而对于从站设备的范围为128~254。

通常MAC地址采有以下几种方式确定:拨码开关,板上跳线,HMI界面,固件传输等。有的设备支持通过BACnet写属性服务修改MAC地址,但是这之前,设备必须要有合法的MAC地址以接入BACnet网络。

如果独特的MAC地址能够自动获得,就象我们将笔记本接入家庭或办公网络一样通过DHCP服务自动获取,我们就可以节省大量的调试时间。

这里讨论了好几种方案.    目前看来委员会更倾向于 “零配置方案” (附录135-2012bb)

开源的BACnet stack已经实现了 “零配置方案”.

“零配置方案” 只适用于最大扫描地址为127的情况,且自动地址分配范围为64~127。如不满足,可能带来混乱。

为了避免以上限制, BACRouter实现了私有的自动地址分配方案,并且与“零配置方案”保持兼容。它有以下吸引人的特性:

  1. 从总线流量中学习最大扫描地址。
  2. 从最大的未使用地址开始分配。

所以用户可以更加自由地规划地址,例如,将0~30留给固定地址的设备,将最大扫描地址设为40。这样自动获取地址的设备接入总线后,将从高到低依次使用40~31的地址。

不管是“零配置方案”还是BACRouter的方案,当已经自动获得地址的设备从总线中断开后,再重新接入总线,非常有可能遇到地址冲突,因为在断开期间,其地址可能被其它新接入的自动获取地址的设备占用。(BACRouter可能更容易遇到问题,因为它的地址分配不是随机的), 所以

一定要在接入总线的情况下,给自动获取地址的设备上电。

MSTP支持扩展帧设备与旧设备的互操作问题

最早的BACnet MS/TP设计只支持NPDU长度到501字节,大幅地小于IP与Ethernet链路层的1497字节长度。这限制了MS/TP的传输效率,增加了应用层的复杂度,特别当两个IP或Ethernet子网通过MS/TP子网连接在一起的时候。

扩展帧设计用于解决这个问题。标准附录此处可见. 简要地说, 此附录增加了两种帧类型:

  • 32: BACnet扩展帧须应答
  • 33: BACnet扩展帧无须应答

帧类型32由帧类型5(BACnet帧须应答)扩展而来,特殊之处在于它以COBS规则编码及NPDU长度为502到1497字节。

同样地,帧类型33由帧类型6 (BACnet帧无须应答)扩展而来。

扩展帧支持从修订版16开始正式引入标准。但是现场及市场上仍然有大量的旧设备不支持。支持扩展帧设备与旧设备之间的互操作性值得探讨。

  • 非路由旧设备与支持扩展帧设备:因为所有发往旧设备的NPDU都是应用层包,在旧设备的Device对象或发出的确认服务请求中的”最大可接受APDU长度”参数限制了NPDU包的大小,所以这种配置没有问题。
  • 旧路由与支持扩展帧设备: 须经由旧路由转发到其它子网的NPDU,如果其长度超过501字节将无法被旧路由识别而丢弃,发送方也收不到”包长超出”的网络层拒绝包。甚而,旧路由的”最大可接受APDU长度” 参数有可能是由其它路由口的参数决定的 (BACnet标准允许这种做法),因而其封包长度可能超出501字节,此时发往旧路由的应用层包也可能被丢弃。因此这种配置可能造成互操作问题。

BACRouter在非常早的版本就支持了扩展帧。从固件版本3.18开始,我们在BACRouter的MS/TP配置中引入了”扩展帧支持“选项,如果在总线上有不支持扩展帧的旧路由,此选项必须关闭以避免互操作性问题。

值得注意的是,即使”扩展帧支持“选项被关闭,不象旧路由,BACRouter仍然与支持扩展帧的设备有良好的互操作性。

(截图于2021-08-05更新,因为扩展帧是标准修订版16的强制要求,所以从固件4.13起,我们把这个功能选项移入到扩展配置模式中)

针对BACnet MSTP的帧失步攻击

如前面的文章 “BACnet MSTP 帧失步” 所指, BACnet MSTP 有一个帧失步的设计缺陷,但是是否可以利用这个缺陷,在完全遵守协议的前提下,对MSTP总线进行破坏呢?

设计这个攻击,我们先做以下几个假设:

  1. 总线上至少有3个设备,MAC地址分别为1, 8, 10。其中设备1是精心设计用来发动攻击的,设备8与10是无辜的。
  2. 设备1支持扩展帧,设备8与10不支持。
  3. 这3个设备的定时器都足够精确。

设备1的工作流程如下:

  1. 得到令牌,发送A帧
  2. 传递令牌到其它设备
  3. 再次得到令牌时,发送B帧
  4. 传递令牌到其它设备
  5. 重复步骤1.

A帧是一个合法的私有数据帧,十六进制数据如下:

55 ff 80 ff 01 00 1d a3 02 2b 72 fe 55 ff 03 08 01 00 11 a0 ff 55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

B帧也是一个合法的私有数据帧,十六进制数据如下:

55 ff 80 ff 01 00 1d a3 02 2b fe dc 55 ff 03 0a 01 00 11 b1 ff 55 ff 21 01 0a 00 09 fd 8a 51 55 ff 00 01 0a 00 00 8c

如果没有帧失步,一切都将正常运行。但是可能几小时,也可能几天后,设备8对设备1发出的A帧失步了,错过了A帧的帧头(设备10如对B帧失步,也是同样的效果),则设备8继续扫描A帧的数据部分,发现另一个有效帧:

55 ff 03 08 01 00 11 a0 ff 55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

这是发给设备8的Test-Request帧,设备8等待Tturnaround后发送Test-Response帧进行应答:

55 ff 04 01 08 00 11 ae ff 55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

但是此时,设备1正在传出令牌:

55 ff 00 02 01 00 00 73

令牌帧与Test_Response的前8个字节冲突了,对于设备10来说,收到了几个错误字节后,继续扫描,在Test_Response的数据部分又发现了一个帧:

55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

对设备10来说,这不是发给它的帧,所以他进入SKIP-DATA状态,抛弃数据,等这个帧结束,但是直到设备8发完数据,设备10还差一个字节来结束帧,他将继续等待。

对设备1来说,它发出令牌帧后,收到如下数据:

55 ff 21 01 08 00 09 ce d4 f3 55 ff 00 01 08 00 00 bf

这是一个扩展数据帧,因为它支持扩展帧,所以他按 Addendum 135-2012an规定的流程校验帧头,发现数据长度过短,中断前帧后又开始扫描,发现新帧:

55 ff 00 01 08 00 00 bf

这是一个发给设备1的令牌帧,设备1又得到令牌,经过Tturnaround后,重新发送B帧:

55 ff 80 ff 01 00 1d a3 02 2b fe dc 55 ff 03 0a 01 00 11 b1 ff 55 ff 21 01 0a 00 09 fd 8a 51 55 ff 00 01 0a 00 00 8c

在前面提到,设备10还差1个字节来结束前面一帧,因Tframe_abort>Ttrurnaround,所以解析没有中断,B帧的第一个55字节被设备10抛弃,然后开始扫描新帧,发现了:

55 ff 03 0a 01 00 11 b1 ff 55 ff 21 01 0a 00 09 fd 8a 51 55 ff 00 01 0a 00 00 8c

这是一个发给设备10的Test-Request帧,事情又开始重复。

从上面可以看出,每个设备都严格地遵守标准,但是一旦帧失步发生,整条总线就永远地瘫痪了。

更多信息见:MSTP帧失步解决方案

MSTP帧失步解决方案

于2021.7.13更新

我们曾在下面的文章中讨论过BACnet MSTP协议中有帧失步的弱点:

BACnet MSTP 帧失步

针对 BACnet MSTP 的帧失步攻击

对于BACRouter 来说,怎么来防范这个漏洞呢?让我们从标准找线索:

9.5.2 变量

SilenceTimer(翻译为静默计时器): 名义精度5ms的计时器,每当总线上有活动或每发送一个字节后清零

9.5.3 参数

Tframe_gap(翻译为字节间隔): 节点在发送一个帧时,在两个字节之间允许的最长的空闲时间: 20位时间。以我们的经验市面上几乎所有MSTP设备的字节间隔为0

Tturnaround: 节点接收到最后一个字节与开始发送之间的最小时间间隔: 40位时间

Tpostdrive: 节点发送完最后一个字节的停止位,到关闭485的驱动器之间的最长时间: 15位时间

9.5.5 发送帧流程

当SilenceTimer小于Tturnaround时, 等待 (Tturnaround – SilenceTimer)时间

9.2.3 时序

驱动器关闭: 节点应该在一个帧的最后字节的停止位起的Tpostdrive时间内关闭驱动器。标准允许但不鼓励,在帧的最后一个字节后再发送一个填充字节,如果填充字节被使用,它必须是0xFF,填充字节不被认为是帧的一部分,且应该包括在Tpostdrive时间内。

(此处并不明确Tturnaround是否包括填充字节的时间,但是在135.1的测试标准的12.1.3.4章节就描述得很清晰:Tturnaround从最后一个字节的停止位后开始计时,如果节点采用了填充字节,则应该由填充字节前一个字节的停止位后开始)

如此可见,在一个正常帧内,2个字节之间的最大空闲时间为20位时间,如果计上前一个字节拖尾的“1”位,则最长的总线空闲时间为29位时间(假设前一个字节为0xFF)。

考虑到填充字节,两帧之间的最小总线空闲时间为:Tturnaround – Tpostdrive + 9 (填充字节拖尾的”1″的位数)= 34位时间

所以BACRouter采用一个改进的接收有限状态机:

  1. 在一个MSTP帧中,字节间隔如大于20位时间,认为MSTP帧中断。
  2. 总线空闲大于等于33位时间,认为新的MSTP帧出现。
  3. 为了尽量兼容部分不遵守Tturnaround的设备,所有在有效MSTP帧后的数据认为是新的一帧。

在115200波特率下,一个数据位的时间仅8.7微秒,为了精确地测量空闲时间,BACRouter采用了5微秒精度的定时器,它有效地防止帧失步出现,并且 在115.2kbps下达到98.8%的带宽利用率 因为BACRouter发包时精确地遵守40位的Tturnaround,没有浪费多余的等待时间。

一次最大发包数与根据令牌占用时间

从固件版本2.0开始,BACRouter引入一个新的特性:根据令牌占用时间的一次最大发包数。

在BACnet MSTP标准中,一个主站得到令牌后,可以发送“一次最大发包数”的包后,再传递出令牌。“一次最大发包数”的默认值是1。路由器作为流量汇聚点,提高这个值可以改进网络交换带宽,但是会增加令牌占用时间。大多数路由的建议值为5到20。

MSTP作为常见的现场总线,通常由控制器、传感器、执行器互联,这些设备构成直接的控制回路,数据交换延迟通常要得到保证。我们建议设备得到令牌的时间间隔要小于1秒 。

路由器发送的NPDU的长度通常在10~50字节之间。但是最大可达到501字节(或扩展帧的1497字节)。越大的帧需要越长的时间来收发。

对于需要回应的NPDU来说,路由器需要等待目标设备应答。通常目标设备需要更长的时间来处理长帧,即路由器需要等待更长的时间。

所以同样的“一次最大发包数”,每次路由持用令牌的时间变化很大,对MSTP总线的延迟保证非常不利。

为避免这个问题,我们引进“根据令牌占用时间”特性来限制路由器持有令牌的时间。这个特性启用后。路由器不计算发包数,而是计量持有令牌的时间,当时间达到:

每字节发送时长 * 32 * “一次最大发包数”

就不再发送新帧,并传出令牌。例如“一次最大发包数”为10, 波特率为76.8kbps,每字节发送时长为0.13毫秒,则最大令牌持有时间为:

0.13 * 32 * 10 = 41.6 毫秒.

这个特性可以通过WebUI方便地启用与关闭。

MSTP包延时保证

BACnet有两种类型的服务,分为无确认与有确认。有确认服务的发送者(客户端)会等待应答直至超时。

通常情况下,无确认服务的包延时不会带来副作用。但对于有确认服务的请求包与应答包,过长的包延时将导致应答包因为超时而被抛弃,浪费了通讯带宽。

更有甚者,过迟到达的应答包可能导致应用层的逻辑错误!原因如下:

有确认服务的请求包头带有一个InvokeID,值范围0~255。应答包有同样的InvokeID。客户端通过这个InvokeID匹配请求与应答。在一个繁忙的客户端,InvokeID会快速耗尽, 此时只能回收重用已完成的服务的InvokeID。

如果一个有确认服务的应答包被过分延迟,客户端可能因为超时而结束服务,其InvokeID被回收,并被重新分配使用。此时被延迟的应答包被收到后,其InvokeID将被匹配到错误的服务。例如:

  • 客户端发出一个WriteProperty请求A,写设备X对象Y属性Z,分配的InvokeID为0。写入成功,但此请求包或者应答包延迟了。
  • 客户端等待超时而结束服务,InvokeID 0被回收。
  • 客户端发出一个WriteProperty请求B,写设备X对象U属性V,InvokeID又分配到0。写入失败。
  • 请求A的应答包先到达,由其InvokeID匹配到请求B。客户端认为请求B写入成功,造成应用层逻辑错误。

对高速的链路层如以太网或IP, 包延时通常是可忽略的,但是对于MSTP,有很多原因将造成过长的包延时:

  1. 信号噪声造成的令牌丢失或冲突。
  2. 不适当的设备配置(波特率,最大扫描站号,最大发包数)。
  3. 过高的流量。
  4. 过慢的设备。

为了避免InvokeID冲突及提高网络性能,版本2.0及以上的BACRouter实现了10秒钟 (参考BACnet的缺省APDU_Timeout,从v4.17起此延时修改为6秒钟) 的包延时保证,在收到后不能在此延时内完全转发的包将被抛弃。

虽然此策略可能造成服务无应答,但是比起错误应答,无应答是可以通过应用层的重试机制处理。

MSTP 固定/自动/强制 波特率

更新于2020-11-20(文末添加江森DDC内容)

MSTP的波特率设置一直是个现场工程师头痛的问题,如果设备的波特率设置有误,就无法加入MSTP网络中。

大部分设备采用固定的波特率,如需修改波特率,工程师必须接触到设备并调整DIP开关。有的设备支持通过BACnet服务修改波特率,但是在这之前,设备必须要能接入到BACnet网络中。

有的厂商实现了自动波特率配置,但是也带来了更多的问题,目前市场上的自动波特率有两种类型:

  • 启动时探测:设备在启动时监听总线并探测波特率,随后一直以该波特率运行。
  • 动态探测:设备不但在启动时探测波特率,在运行中如果在一段时间内持续发生通讯错误,即认为波特率改变,重新探测波特率。

不管是哪种类型,在总线运行时改变波特率都是非常困难的。仅仅改变所有固定波特率设备的设置是无法影响总线波特率的,因为其它自动波特率设备仍然以旧的波特率运中。唯一可靠的方法是在改变所有固定波特率设备的设置后,关掉所有自动波特率设备,再启动所有自动波特率设备(不能一个接一个的重新启动自动波特率设备!因为仍在运行中的自动波特率设备将维持总线波特率)

BACRouter的新版本固件(版本>=2.0)引入了新的波特率管理机制(专利申请中)。BACRouter有三种波特率模式:固定/自动/强制。

  • 固定波特率模式与传统的固定波特率一样
  • 自动波特率模式类似于前述的动态探测。重新探测的条件是10个连续的错误帧,通常只需要几秒钟。
  • 强制波特率模式类似于自动波特率模式,区别在于其在得到令牌后,将波特率改为预设的波特率。

当总线中有一个强制模式设备时,总线的波特率将会强制运行于预设值,而其它自动模式设备将自动同步波特率。固定模式但波特率设置值不同于预设值的设备将无法出现在总线中(通过检查BACRouter的运行信息中的“最近活动设备”项将很快地把这些设备找出)。对于上述的启动时探测设备,如果其探测到的波特率不同于预设值,也无法出现在总线中(同样可以通过检查BACRouter的运行信息中的“最近活动设备”项找出),但只需将其一个接一个的重新启动即可(不需全部断电,再全部上电)。

多个强制模式的设备可以共存在总线中,但这些设备中的波特率预设值必须相同。

江森自控的FEC与IOM模块即采用动态波特率,经测试,当波特率不匹配时间到150秒左右,模块开始重新检测波特率。

在BACRouter与FEC2611及IOM3731组成的测试总线中,双方完美协作,总线波特率可由BACRouter控制在9.6k~76.8k之间动态切换,FEC2611与IOM3731会延迟2.5分钟后刷新波特率。