ARC156 抗噪声性能

从固件版本6.00起,BACRouter的RS485端口内置了一个软件噪声过滤器,在这里我们将考察其在ARC156上的表现

对照设备的性能

我们使用的对照设备是ZN551与AAR模块。它们采用了微芯公司的COM20019i芯片来处理ARCnet通讯

从测试数据来看,对照设备只关心信号的下降沿,此处信号对应RS485的差分电压。信号的宽度对解码没有影响,除非信号的脉宽小于0.52us,此时信号被忽略。下面我们将解释其原理。

对照设备内置一个硬件滤噪电路,此电路由SN74HC164 与 SN74AHC1G32 器件组成。在10M时基下,由RS485收发器来的输入信号,只有在第1个时钟与第5个时钟同时为低电平时,COM20019i才能接收到低电平信号,所以当脉冲宽度小于0.5us的低电平信号将被滤除。

空闲状态下的RS485总线对噪声更敏感,因为此时的偏置电流只为数毫安,对比被驱动的总线,它将要花费长得多的时间来从噪声信号中恢复。

在空闲的总线上,脉冲宽度大于0.52us的噪声信号将被COM20019i错误地识别为帧的起始信号。

在被驱动的总线上,当位1被发送,一个差分电压的下降沿将出现在总线上,如果噪声信号的下降沿出现在有效信号下降沿的+/-3.2us范围内,COM20019i将检测到多个下降沿,重复的下降沿将被忽略。

当位0被发送,如果噪声信号出现在下降沿检测位置+/- 3.2us范围内,COM20019i将错误地将其解码为位1。

BACRouter的性能

在空闲的总线上,BACRouter能容忍脉冲宽度小于2.1us的噪声信号。

在被驱动的总线上,如果位1被连续发送,信号的脉宽为3.2us,BACRouter只能容忍脉冲宽度小于1.05us的噪声信号。如果位0被发送,则信号的脉宽将大于6.4us,BACRouter可以容忍脉冲宽度小于2.1us的噪声信号。

结论

容忍噪声信号宽度BACRouter对照设备
空闲总线2.1us0.52us
位1发送中1.05us噪声无影响
位0发送中2.1us0.52us

ARC156与发送多帧比例

ARCNET协议最大的特点之一是确定性。它有几个设计决策来帮助它实现确定性:

  • 每次传递令牌只能发送 1 个数据包。
  • 数据包的最大有效载荷限制为 507 字节。
  • 所有延迟都受到严格限制。

因此,对于 ARC156,在最坏的情况下,令牌传递节点的时间约为 40.1 毫秒,即节点有一个非广播数据包,其有效载荷为 507 字节,且传播延迟为极限值。

如果节点没有数据包要发送,忽略传播延迟,令牌传递仅需 448 微秒。与 ms/tp 相比,它非常之快。

在 BACnet 网络中,大多数数据包小于 50 字节。例如,从 BACnet IP 中继到 ARC156 的 ReadProperty 请求只有 25 字节的有效载荷,典型的响应只有 32 字节的有效载荷。

如果有一条带有 30 个节点的 ARC156 总线,其中一个节点是路由器,它从/向 BACnet IP 网络中继数据包。对于每个令牌传递轮次,路由器都会发送一个 ReadProperty 请求,询问其他节点之一的 Analog 对象的 Present_Value 属性,该节点会回复一个Complex ACK。此时令牌传递一轮的时间约为 21.4 毫秒,因此吞吐量为 1/21.4 = 每毫秒 0.0467 个事务。

如果我们允许路由器在持有令牌时发送多个请求,但在使用令牌 40.1 毫秒之前将令牌传递出去,则吞吐量将会提高,同时不影响确定性指标。

例如,如果路由器在传递令牌之前向不同的节点发送 10 个请求,则仅需要 36.7 毫秒。收到请求的节点将在令牌传递给它们时发送回复。此时令牌传递一轮的总时间约为 90.8 毫秒。吞吐量为 10/90.8 = 每毫秒 0.11 个事务,约为标准实现的 2.36 倍。

BACRouter 的 ARC156 端口的“发送多帧比例”参数定义了 BACRouter 可以持有令牌以发送多个数据包的时间。例如,如果“发送多帧比例”为 0.5,则 BACRouter 可以持有令牌 0.5 * 40.1 毫秒 = 20 毫秒。这里的 40.1 毫秒是我们一开始讨论的节点可以持有令牌的最长时间。

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  下载

最灵活的Modbus网关

BACRouter内置了一个强大的Modbus主站模块,但是基于现场的复杂性,它仍然不能很好的应对某些场景,比如:

  1. 点的值从寄存器3X0001读取,但是写时需要写到寄存器4X0001
  2. Modbus值1读入时,映射到BACnet值1,  但是写BACnet值1时,需要写10到Modbus。(Modbus主站模块的Lua脚本可以处理非对称的自定义类型的模拟对象的换算)
  3. 模拟对象或多状态对象映射到线圈或离散输入点的多个位。
  4. 只写的Modbus数据地址,读取时报错或无响应。

幸运的是,从固件版本v5.00起,我们引入了自由协议模块,可以用Lua脚本实现一个非常灵活的Modbus网关, 我们把modbus.lua 脚本托管于 github.com

modbus.lua定义的总线上所有设备采用相同的波特率/校验/超时参数。而对于Modbus主站模块,每个设备可以采用不同的设定。

用户应该首选尝试Modbus主站模块,因为Modbus主站模块内置的测试功能,可以方便用户在编辑映射时快速地验证。

当所有的常规点编辑完毕,可能留下几个古怪的点无法处理,但是请先对读操作进行验证。

接下来,请验证“编组读取”。

然后将Modbus设备的配置导出。

在github仓库中有一个 fcmbconv.py python程序, 请先安装 python 再运行它。它将提示你选择modbus.lua文件,再选择导出的Modbus设备配置文件,它会将其转换为自由协议总线配置文件。

然后在BACRouter的自由协议模块下导入上述配置文件。

最后编辑配置,处理那些古怪的点。

示例:

我们假设有一个这样的Modbus设备,除了几个常规点,还有:

  1. 模拟输出对象”lamp1″与”lamp2″从寄存器4X00032的位0与位1读取开关值,对应位为1值代表开,0值代表关。但是输出开关值,必须写到寄存器4X00031中,且对应位的1值代表关,0值代表开。
  2. 离散输入1X00008开始的8个位映射成模拟输入对象“temperature3″
  3. 4X00100是一个只写寄存器,读将无响应或报错。该寄存器的低字节映射为模拟输出对象”load1“,寄存器的高字节映射为模拟输出对象”load2″

首先我们配置一个Modbus主站模块的Modbus设置,配置文件: ExampleModbusDevice,  用“编组读取”测试验证
使用上述的 fcmbconv.py将其转为自由协议的总线配置文件:  FCModbus

将其导入到BACRouter的自由协议模块:

修改那些古怪的点配置。

如 lamp1:

如 temperature3:

如 load1 与 load2:

修改完毕后,使用Yabe 进行验证。假如脚本运行失败,请检查日志。

修改完毕的自由协议总线配置文件见:FCModbusFinal

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增加新IP

我们经常在现场面对IP无法修改的第三方设备,而且其IP与BACRouter或其它BIP设备不在同一个子段内。
已有的解决方案是增加一个IP路由器,这样将导致成本与复杂度增加。
通常我们只需要BACRouter与这种第三方设备采用Modbus TCP或BACnet IP协议进行通讯,因此最简单的办法是为BACRouter增加一个专用于与此设备通讯的IP

例如,当前IP子网是192.168.100.0/24,  BACRouter的IP是192.168.100.1, 第三方设备的IP是172.16.1.20, 子网掩码为255.255.255.0

我们将为BACRouter添加一个新IP:172.16.1.1
初始的/etc/rc.local:

root@OpenWrt:~# cat /etc/rc.local
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

cd /root
./webui&
exit 0

修改/etc/rc.local: (也可以用vi编辑)

root@OpenWrt:~# cat>/etc/rc.local
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

ifconfig br-lan:1 172.16.1.1 netmask 255.255.255.0
cd /root
./webui&
exit 0
CTRL+D

这里的ifconfig指令将添加br-lan:1 新接口,其IP为172.16.1.1。如果我们需要以BIP协议连接第三方设备,我们还需要将新接口添加到BACRouter的配置文件中:

初始的/root/resource.conf:

~#cat /root/resource.conf
{ “eth0”: { “type”: “ETH”, “ifname”: “br-lan” }, “RS485-1”: { “type”: “USB”, “ifname”: “0:0” }, “RS485-2”: { “type”: “USB”, “ifname”: “0:1” } }

修改/root/resource.conf: (也可以用vi编辑)

~#cat >/root/resource.conf
{ “eth0”: { “type”: “ETH”, “ifname”: “br-lan” }, “eth1”:{“type”:”ETH”, “ifname”:”br-lan:1″}, “RS485-1”: { “type”: “USB”, “ifname”: “0:0” }, “RS485-2”: { “type”: “USB”, “ifname”: “0:1” } }
CTRL+D

现在断电重启BACRouter!

Modbus设备配置 & Lua 脚本 & 配置转换

Modbus 设备配置

Siemens_RDF302.json西门子 RD302 温控器
Schneider_TC500.json施耐德 TC500 温控器
JCI_T8600.json江森 T8600 温控器
JCI_T7000.json江森 T7000 系列温控器
ABB_ACS510.jsonABB ACS510 变频器

Lua 脚本

bcd.luaBCD码。每个字节存储0~9, 例如: 0x05090702 = 5972
字节序由“大整数字节顺序”定义。
compat_bcd.lua紧凑式BCD码。每半字节存储0-9, 例如: 0x78695231 = 78695231
字节序由“大整数字节顺序”定义。
m10k.lua每个寄存器存储 -9999 ~ 9999, 例如: 0x1f740a69 = 0x1f74*10000 + 0x0a69 = 80522665
字节序由“大整数字节顺序”定义。
low10th.lua只有一个寄存器, 低字节单位为1/10, 所以数值范围为 0.0 to 255.9 例如: 0x0503 = 5.3
字节序由“”单寄存器字节顺序“定义。
此表达方式在约克TMS2100 风机盘管温控器上发现。

配置转换

转换BASgatewayLX的CSV格式配置文件

转换X2BACnet的XML格式工程文件

转换X2BACnet的XML格式工程文件

X2BACnet(以下简单X2B)的工程文件采用XML格式,其配置软件自带了一部分工程模板,用户可以自行免费下载。本转换工具将其工程文件转为BACRouter的配置文件

在我们网站上直接转换

下载转换工具解压缩后用浏览器打开index.html

几点注意事项:

X2B的配置似乎不做错误较验,比如从站ID可以输入0或65537。转换工具根据我们的规则做了所有校验。

因为底层机制的不同,X2B的”请求帧间隔”与”写值刷新间隔”无法简单映射到BACRouter,所以BACRouter的从站的”Modbus参数”中的时序参数采用默认值,但”回应超时”参数采用X2B通道的“超时时间”。

X2B可以将部分点配置为“单点写“(功能码5或6),另一部分点采用多点写(功能码15或16)。转换中如果发现任一点为多点写,则其它点也全部采用多点写。如果发现任一AO映射到多个保持寄存器,则采用功能码16(这个逻辑与BACRouter相同)

X2B的寄存器地址可以用“.”引用内置的数据处理,如1.sum, 1.hibyte,1.lobyte,转换中将提示采用脚本处理。

X2B几乎允许所有的数据类型,BACnet类型,取位的组合,但大部分在工程上没有意义,工程模板中也找不到用例,转换中将放弃或跳过处理。

BACRouter与VPN

基于OpenWRT平台,BACRouter可以支持众多VPN协议,包括OpenVPN, wireguard, IPSec,等等。为了节省板上存储空间以存入应用程序,在默认情况下,VPN的支持并未启用。

我们的 OpenWRT 代码托管于 https://github.com/hvacrcontrol/openwrt, 代码分支 “bacrouter_new” 就是目前的生产代码。

代码仓库内的 vpn.config 就是 VPN 的配置文件,其中已使能 OpenVPN 与 wireguard

以上述配置编译的 OpenWRT 固件文件在这里下载: vpn_bacrouter_19.07_8fe8c902.tar.gz

关于如何使用上述固件文件升级,请参考 升级BACRouter底层固件

有时,我们需要在VPN侧运行BIP,从v4.23起的BACRouter固件 将支持本功能。下面简要说明如何配置它:

更新 Openwrt VPN 版固件,及 BACRouter 固件>= v4.23

先配置好 VPN, 以下以wiregurad 为例:

~#uci show network.vpn
network.vpn.proto=’wireguard’
network.vpn.private_key=’####################################’
network.vpn.addresses=’192.168.231.3/24′

~#uci show network.wg0
network.wg0=wireguard_vpn
network.wg0.public_key=’#####################################’
network.wg0.endpoint_host=’###.###.###.###’
network.wg0.endpoint_port=’####’
network.wg0.route_allowed_ips=’1′
network.wg0.persistent_keepalive=’25’
network.wg0.allowed_ips=’192.168.231.0/24′

有关 wireguard 的配置请参考: https://openwrt.org/docs/guide-user/services/vpn/wireguard/start

~#ifconfig vpn
vpn Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.231.3 P-t-P:192.168.231.3 Mask:255.255.255.0
UP POINTOPOINT RUNNING NOARP MTU:1420 Metric:1
RX packets:557 errors:0 dropped:0 overruns:0 frame:0
TX packets:3593 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:50348 (49.1 KiB) TX bytes:176736 (172.5 KiB)

将 vpn 接口加入到 BACRouter:
原始的/root/resource.conf:

~#cat /root/resource.conf
{ “eth0”: { “type”: “ETH”, “ifname”: “br-lan” }, “RS485-1”: { “type”: “USB”, “ifname”: “0:0” }, “RS485-2”: { “type”: “USB”, “ifname”: “0:1” } }

修改/root/resource.conf(您也可以用vi编辑)

~#cat >/root/resource.conf
{ “vpn0”: { “type”: “PPP”, “ifname”: “vpn”}, “eth0”: { “type”: “ETH”, “ifname”: “br-lan” }, “RS485-1”: { “type”: “USB”, “ifname”: “0:0” }, “RS485-2”: { “type”: “USB”, “ifname”: “0:1” } }
CTRL+D

因为 wireguard 工作于第三层 (tun 模式), 所以 vpn0 的类型定义为 “PPP”。对于工作于 tap 模式的VPN,必须使用 “ETH” 类型。

重启 WebUI, “系统设定”页面将显示如下:

创建另一个BIP端口,指定硬件为 “vpn0″。因为这是一个”PPP”接口,所以只有“外部设备”与“广播管理设备” 2种模式可用。

注意:当WebUI与BACRouter应用程序启动时,将读取所有的接口IP信息,所以所有接口必须采用静态配置。对于 wireguard 这不是问题,因为其 ip 是静态配置的。

对于 OpenVPN 的 tun 模式,请参考:给OpenVPN客户端分配静态IP地址 。 在OpenVPN客户端启动时,其需要时间与服务器建立连接并得到IP。下面示例启动脚本事先静态配置 tun0 接口的IP地址,以避免webui启动失败:

~#cat /etc/rc.local
ip tuntap add dev tun0 mode tun
ip link set tun0 up
ip addr add 192.168.231.3/24 dev tun0
/etc/init.d/openvpn start
cd /root
./webui&
exit 0

当 OpenVPN 的tap模式可用时,采用以太网网桥方式是最简单的,如此任何应用层设定都不需要调整。

关于BMS与VPN的精彩博客

升级BACRouter底层固件

BACRouter的底层平台是OpenWRT。自2016年发布以来,OpenWRT的版本未曾更新。安全审计机构时有报告内置的dropbear服务器有漏洞,虽然经我们评估,这些漏洞在BACRouter的应用场景下无法被利用。

不管怎样,我们决定将OpenWRT的版本升级到v19.07.10,这一版本发布于2022年4月20日。对于想升级的老客户,将照以下步骤执行:

1.  下载OpenWRT更新包

2.  在WebUI的“升级固件”功能中选用上述更新包。更新将持续二至三分钟时间。请注意,所有的设定,包括IP都将丢失。

3.  用浏览器打开”http://192.168.100.1″,页面将显示:

4. 选择任意版本的BACRouter固件,点击“upgrade”,页面将显示:

5. 等待1分钟之后再次刷新页面,WebUI就又回来了,请从备份中恢复原有的配置。