Offline configuration and import/export

From firmware v4.x,Offline configuration had been introduced. Now user could configure a BACRouter without device on hand, then export configuration to a file. When commissioning on the field, user just need to import previously exported configuration file, “Save&Reboot” to take effect the configuration.

Offline configure on our website

Download and extract it to disk, open index.html by your web browser

There are 3 types of configuration file:

BACRouter Configuration File

This type of configuration file keeps all settings in BACRouter. If the firmware version of exporting one is same to importing one, WebUI should not complain of the configuration file.

Modbus Master Configuration File

This type of configuration file keeps setting under the scope of Modbus master.  When importing it, collision detecting logic based on current mapping mode will check every enabled slave in this master, if collision is found, the slave will be disabled.

If the master is RTU/ASCII type, it may also be disabled if there are contention for RS485 port.

With these problem, WebUI will prompt user to re-check configuration.

Modbus Slave Configuration File

This type of configuration file keeps setting under the scope of Modbus slave.  When importing it, if collision detecting logic based on current mapping mode found problem, the slave will be disabled.

It is allowed to import TCP salve configuration file in RTU/ASCII master, and vice versa, but the slave may be disabled if Modbus parameter setting do not work.

With these problem, WebUI will prompt user to re-check configuration.

Modbus Gateway in BACRouter

From firmware version 4.x,  BACRouter has builtin Modbus gateway functionality. This article will try to explain the underlying mechanism.

Modbus Read

To improve performance, BACRouter will read as more as possible data in one transcation. In Modbus standard, at most 2000 bits (coil or discrete) or 125 registers (input or holding register) could be read in one request, but specific Modbus slave device may only support a lower value.  In BACRouter’s WebUI, there is a Modbus parameter edit dialog in “Slave Settings”, “Multiply read bits” and “Multiply read registers” parameters define the ability of the slave device.

BACRouter will not segment reading of single point even the “Multiply read registers” is less than registers used by the point.

Usually the data we care for has discontinuous Modbus address, for example, We only care for coils on address 1 and 2000, though we could read coil data from address 1 to 2000 in one request and skip returned data from address 2 to 1999,  sending a request to read coil on address 1, then sending another request to read address 2000 maybe more efficient. “Bits skipped” and “Registers skipped” parameter define how many unused data units between 2 cared data units are allowed to be skipped. As previous example, if “Bits skipped” is set to 1998, the BACRouter will try to read coil 1 and 2000 in single request. If “Bits skipped” is set to 1997, then BACRouter will read Coil 1 first, then Coil  2000, because bits skipped is 1998 and is greater than the setting of 1997.

When point’s data age which is defined as time past from data updating, is greater or equal to “Update interval”, BACRouter will queue read request try to update it.

Modbus Write

BACRouter will not combine multiple writing demand into one writing request.

For writing single data unit, there are two Modbus function codes available. For example, function code 5 is writing single coil,  function code 15 is writing multiple coils but the quantity of coil to write could be assigned to 1. Some devices only support one of them.  “Coil write singly” parameter will specify which function code is used.

In the same way, “Register write singly” is applied to register writing. If any BACnet output object maps to multiple holding registers, it implies the slave device support function code 16 for write multiple registers, function code 16 will be used for writing any register whatever “Register write singly” is set.

To avoid too frequently sending write request to slave device, BACRouter will wait “Write interval” from last write.


If any read/write request failed, BACRouter will retry it, when the continuous fail count reachs 3, BACRouter will regard the slave device as offline. In offline state, BACRouter will retry the request every “Offline update interval”.

The BACnet side reaction for offline event will be described later.

Modbus Test

“Batch read” test method could be used to verify slave’s support for “Multiply read bits”/”Multiply read registers” and validity of address space.

“Point read/write” test method will help user to confirm the data type and byte order of complex points.

To perform a test, a master should be defined and enabled, then be saved into BACRouter to take effect.

Modbus Serial Bus

BACRouter supports serial slave devices with different baudrate, parity, RTU/ASCII mode on same RS485 bus. Before sending request, BACRouter will change it serial port parameter based on slave device’s settings.

It should be safe to have 2 devices with same slave address but different baudrate or RTU/ASCII  mode, but preventing collision based on different parity might not be enough, because some devices do not examine parity error.

Single Device Mapping Mode

If VBUS network port is not enabled, BACRouter will work in single device mapping mode, every Modbus slave device will be mapped into exclusive object instance space of 1000 in BACnet device defined in “Application Settings”.  for example, first device will occupy 0~999, next device will occupy 1000~1999, so on.

If “Packet capture mapping” in “Application Settings” page is enabled, the packet capture mapping module will occupy first 1000 instance space, that is said 0~999.  Slave device will go after it.

BACRouter will create one StructuredView object for each slave device,  the object name is loaded from slave device’s “Device name”.

In this mode, each slave’s “Device name” and “Point name” shall be unique to global scope, including “Device name” defined in “System Settings” and object name used by packet capture mapping module. To avoid name collision, there is a “Prefix to name” in “Slave Settings”, this string will be prepended to slave’s “Device name” and “Point name”.

When the slave device turn to offline in this mode, all points’ reliability will be set to “COMMUNICATION_FAILURE”, if slave device is back to online, upon updating of point value, the point’s reliability will be set back to “NO_FAULT_DETECTED”.

Virtual Device Mapping Mode

If VBUS network port is enabled. Each slave device will be mapped to a virtual BACnet device on VBUS network. The MAC address will start from 1.

In this mode, each slave shall has a unique “Device instance”.

When the slave device turn to offline in this mode, the virtual BACnet device will stop sending/receiving any packet to simulate offline state. if slave device is back to online, after updating all point’s value, the virtual BACnet device will quite offline state.

Object Instance Assignment

Object Instance is automatically assigned by growth in order of define. The actual object id used by point could be read from “Mapping” dialog box on “Slave Settings” page.

Output Object

The point value of output object is still be polled and set to object’s Relinguish_Default property. If the value read back does not match last value written, BACRouter will set the reliability of that object to “UNRELIABLE_OTHER”,  and if the time past from last writing is longer than “Re-write interval”, BACRouter will queue another write.

Because of above verifying mechanism, if the Modbus addresses of 2 output objects overlap, weird behavior would be expected, the WebUI will prevent such overlap in slave’s configuration.

NaN For Float And Double

NaN is a special value defined by IEEE-754, BACRouter does not accept NaN (Infinite is still valid for BACRouter).

When a point is defined as Float and Double, but NaN is read from slave, BACRouter will set the reliability to “UNRELIABLE_OTHER”.

Interoperability between extended MS/TP frame capable devices and legacy devices

Original BACnet MS/TP data link specification only supports NPDU length up to 501 bytes, which is much shorter than 1497 bytes of Ethernet and IP data link. It limits transmission performance, increases complexity on application layer, especial when two IP/Ethernet network are conjoined by a MS/TP network.

Extended frame was designed to solve this problem. The detail could be found here. Briefly, this addendum added two new frame types as:

  • 32: BACnet Extended Data Expecting Reply
  • 33: BACnet Extended Data Not Expecting Reply

Frame type 32 is extended from frame type 5 (BACnet Data Expecting Reply),  the special of it is that it is encoded by COBS and the NPDU length it carried is in range of 502 to 1497 bytes.

In the same way, frame type 33 is extended from frame type 6 (BACnet Data Not Expecting Reply)

Extended frame support was added into BACnet standard since revision 16. There are still lot of devices installed or on the market that do not support it. The interoperability between extended frame capable devices and legacy device is discussed below.

  • Non-router legacy device and extended frame capable device: Because all messages sent to legacy device are application layer message, the “Max APDU Length Accepted” from Device object property or confirmed service request should be respected, the NPDU length will not exceed 501 bytes. So there are no problem with this configuration.
  • Legacy router and extended frame capable device: NPDU that should be relayed to other network through legacy router with length over 501 bytes will be discarded, no reject-message-to network with reason “Message Too Long” will be responded. Even more, the “Max APDU Length Accepted” of legacy router may be determined by other port that has a NPDU length larger than 501 bytes, so NPDU for local application layer sent to legacy router will still possibly be carried on extended frame and discarded. So this configuration may cause problem in field.

BACRouter supports extended frame from very early version. From firmware version 3.18, we introduced “Extended frame” option on BACRouter’s MS/TP configuration, if there are legacy router that does not support extended frame on the bus, this option should be disabled to avoid Interoperability issues.

It’s worth noting that even “Extended frame” option is disabled, unlike legacy router, BACRouter will still be interoperable with extended frame capable devices.



MSTP message delay guarantee

There are 2 types of BACnet service: unconfirmed and confirmed. The sender(client) of confirmed service request will wait for reply until timeout expires.

Usually there are no side effect of excess message delay for unconfirmed service. For confirmed service request or reply,  excess message delay will result in poor network performance, because the service reply will be dropped by client due to timeout.

Furthermore, too late reply for confirmed service will cause application logic wrong. Each confirmed service request has a invokeID, the reply message carries same invokeID. The value range of invokeID is 0~255. On a busy client, the invokeID will be exhausted and re-used soon. if the invokeID of a delayed confirmed service reply is re-used by another service, the reply will be regarded as replying to later one. For exmaple:

  • Client send WriteProperty service A to device X object Y property Z. The invokeID is 0.  The request or reply messages is delayed.
  • Client waits until timeout expires. Service A fails so invokeID 0 is reclaimed.
  • Client send WriteProperty service B to device X object U property V. The invokeID 0 is chosed.
  • Reply for service A is arrived, because its invokeID is same as service B, client believes that service B success.

For high speed data link type as Ethernet or IP, the message delay is neglect-able, but for MSTP, there are several possible reasons for excess message delay:

  1. Signal noise.
  2. Incorrect/improper device configuration(baudrate, max-master, max_info_frames)
  3. Excess traffic.
  4. Slow device

To avoid invokeID conflict and improve network performance, BACRouter with firmware version >=2.0 implements message delay guarantee of 10 seconds. Messages which could not be sent within 10 seconds will be dropped by BACRouter.

Fixed/Auto/Forced baudrate for MSTP

Update on 2020-11-20 (Appended info. about JCI module)

MSTP baudrate is always painful for field technician. If the baudrate is wrong, device can’t join a MSTP bus.

Most devices have fixed baudrate. To modify the baudrate setting, technician have to physically access the device and change dip switches. Some devices support changing baudrate by BACnet service. but before that they should already have correctly baudrate setting for BACnet service to access it.

Some vendors implement auto baudrate, but introduce more problem than it solves. There are two types of auto baudrate mechanism:

  • Starting detection: The device detects and adopts baudrate on the bus when it starts. then never changes baudrate.
  • Dynamic detection: The device does same as starting detection type when it starts, but if it find there are error on bus for a predefined time, it considers that the baudrate is changed, it detects baudrate again.

For both types, it is difficult to change baudrate when devices is working. Simply changing baudrate on all fixed baudrate devices can not work, because auto baudrate devices are still working on old baudrate. The solution is to power off all auto baudrate devices, then power on all auto baudrate devices(Don’t power off/on auto baudrate devices one by one)

Our new firmware(>=2.0) introduces new baudrate management mechanism(Patent pending). There are 3 types of baudrate mode for BACRouter : Fixed/Auto/Force:

  • Fixed baudrate mode works as most traditional devices.
  • Auto baudrate mode is same as above-mentioned dynamic detection. The predefined time to re-initiate detection is 10 error frames.
  • Forced baudrate mode is same as auto mode except that when the device get token, it changes baudrate to predefined value.

When there is a device with forced baudrate mode, the baudrate on the bus will be forced to predefined value. Devices with auto baudrate mode will automatically synchronize to predefined baudrate. Devices with fixed baudrate mode but baudrate setting different with predefined value will not be seen on bus (It’s easy to check out in “Recent active devices” field from BACRouter’s runtime info). Devices with starting detection type may run on wrong baudrate, they will not be seen on bus too, but powering off/on them one by one will synchronize them to forced value.

More than one device with forced baudrate mode could coexist on a bus, but the baudrate values on them should be same.

JCI FEC/IOM modules implements baudrate dynamic detection mechanism, the re-detect interval is about 150 sec on the test.

On a test bus , BACRouter cooperate perfectly with FEC2611, IOM3731,  the baudrate is dynamically controlled by BACRouter from 9.6k ~ 76.8k, FEC2611 and IOM3731 will catch up after 2.5 minutes.

Max_info_frames by token occupy time

From firmware ver2.0, BACRouter introduced new “Max_info_frames by token occupy time” feature.

In BACnet standard of MSTP, a master device could hold token until it has sent frames up to Max_info_frames. The default value of Max_info_frames is 1. But for router, this value may be increased to improve bandwidth between networks. Mostly the suggested value for router is between 5 to 20.

MSTP works as a field bus for controllers; sensors and actuators. The data exchanging latency between devices usually should be guaranteed.  We recommend devices get token at least every 1 second.

The APDUs passing router usually have size between 10~50 bytes, but could be up to 480 or 1476 (Extended frame). Larger APDU need more time to send or receive.

For APDU which need a reply from targeted device, router has to wait for reply. Usually the targeted device need more time to handle or generate larger APDU, router has to wait longer.

So the time router holding token could be varied much, which impacts latency guaranty of MSTP bus. To avoid this problem, “Max_info_frames by token occupy time” feature limits router’s token holding time.

The limitation is calculated by:

byte_time * 32 * Max_info_frames

For example, Max_info_frames is set to 10. The baud rate is 76800bps, so the byte_time is 0.13 milliseconds:

0.13 * 32 * 10 = 41.6 milliseconds.

When router founds it have held token for 41.6 milliseconds, it passes token to next station, though the frames it sent may be less than 10.

This feature could be enabled/disabled by user from WebUI.

BACRouter benchmark for routing between BIP and Ethernet

The intent of this benchmark is to investigate the capability of BACRouter. Because of low baudrate of MSTP, there is not a bottleneck on routing packet to/from MSTP network.

BACRouter support 10/100M Ethernet interface, so there will be a challenge to flood it. The testing machine is a Notebook with i7 2.8G 4 cores CPU and 1000M Ethernet card, directly connected to BACRouter with CAT5+ cable. The result is:

PathAPDU size in byteMax routing rate without packet drop
(per second)
Routing rate in packet flooding
(per second)
Packet flood rate
(per second)

When BACRouter is flooded by small packets, the handling capability dramatically decreased, especially in BIP port.

On 2019-04-16, We made new benchmark on firmware version 2.18, with a new testing machine( i5 4 core CPU and 1000M Ethernet card). the result is:

PathAPDU size in byteMax routing rate without packet drop
(per second)
Routing rate in packet flooding
(per second)
Packet flood rate
(per second)

The performance is improved much with new firmware.

BACnet MSTP auto addressing

Updated on 2020.3.25 for firmware version 3.x

Because the same time online for all devices could not be guaranteed, there is no auto addressing solution could avoid MAC conflict. We remove this feature on firmware 3.x. To help determine max_master and unused MAC on bus, “Sniffer mode” could be enabled, then “Current max master” could be obtained from run time info. Unused MAC also could be chosen referred to “Recently active devices”.

Every device on a MSTP bus should have a unique MAC address.  For master device, the available address range is 0~127,  and 128~254 for slave device.

Usually MAC address is set by DIP switch, jumper, LCD screen, firmware downloaded by configuration tools. Some devices support MAC address modification through BACnet object/property, but before doing that, it should have a valid MAC address to join BACnet network.

If the unique MAC address could be automatic obtained like we get IP address just by plugging notebook into home/office network, it would save a lot of time in commission.

There are several solutions had been discussed.    Now seems committee prefer  “Zero-Config” (addendum 135-2012bb)

BACnet stack has implemented “Zero-Config”.

“Zero-Config” only works on fixed configuration that Max-master is 127 and automatic assigned address range is 64~127. If not, it may cause mess.

To avoid above limitation, BACRouter implements proprietary auto addressing solution and keep compatible with “Zero-Config”.  It has some attractive features:

  1. Learning Max-master from bus traffic.
  2. Assigning MAC address from highest unused one.

So users have more freedom on MAC address schema,  For example, leave address 0~30 for fixed address devices, set Max-master as 40, so automatic addressing devices would use 31~40.

Both Zero-Config and BACRouter’s solution have trouble when a automatic addressing device is pulled out bus then plugged in again without reboot, because a new attached automatic addressing device would occupy the same address.(BACRouter is more weak in such situation because of it’s predictable address assigning), So

ALWAYS power on automatic addressing device after attaching to bus.

Solution to MSTP frame desynchronization

Updated on 2020.3.25 for firmware version 3.x

We had discussed BACnet MSTP weakness to frame desynchronization in below:

BACnet MSTP frame lost synchronization

Attack BACnet MSTP by frame desynchronization

But what is BACRouter’s solution to this problem, let’s looking for clue from standard 9.5.3:

Tframe_gap is “The maximum idle time a sending node may allow to elapse between octets of a frame the node is transmitting”, its value is 20 bits time. Almost every MSTP implementation have zero gap between octets in frame.

So BACRouter use a revised RSM:

  1. When there is a idle line longer than 20 bits time, the previous partial frame is aborted.
  2. Idle time on bus greater than or equal to Tturnaround means frame gap. Considering measure error introduced by byte frame desynchronization, Finally we use 30.5 bits idle time to distinguish new frame.
  3. To be compatible with devices not respecting to Tturnaround, any data following valid frame will be regarded as new frame.

In 115200bps, one bit time is only 8.7us. To precisely measure duration of idle line, the timer granularity of BACRouter is set to only 5us. It help to resist to frame desynchronization, and reach 98.8% bandwidth utilization on 115.2kbps because BACRouter no more waste time when 40 bits Tturnaround is over.

Attack BACnet MSTP by frame desynchronization

As pointed out by previous article “BACnet MSTP frame lost synchronization” , BACnet MSTP has a design flaw on frame synchronization, but how to utilize it to perform attack and strictly obey the standard at the same time?

We make some assumptions here:

  1. There are at least 3 devices on the bus with MAC address 1, 8,10. The device 1 is carefully designed to perform attack. Device 8 and 10 are innocent.
  2. Device 1 supports extended frame, device 8 and 10 are not.
  3. The timers of 3 devices is precise enough.

The work flow of device 1 is:

  1. When get token, send out frame A
  2. Pass token to MAC address 2
  3. When get token again, send out frame B
  4. Pass token to MAC address 2
  5. goto step 1 again.

Frame A is a valid proprietary frame (hexadecimal);

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

Frame B is also a valid proprietary frame as:

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

Every thing will go well if there is no frame desynchronization, but after hours running, if device 8 losses synchronization with frame A header (It has same effect if device 10 losses synchronization when device 1 sends frame B) , device 8 find another frame when scan Frame A’s data portion:

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

It’s a Test-Request frame send to device 8,  so device 8 try to reply it after Tturnaround with a Test-Response frame:

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

but at the same time, device 1 passes token by sending:

55 ff 00 02 01 00 00 73

So the first 8 bytes of two frames are collided, so device 10 drop invalid header, find data as below:

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

When device 1 finishs sending, it starts receiving data and get the same as:

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

For device 10, it get a valid Not-For-Us frame header, so it enter SKIP-DATA state, there is not enough data to skip, so device 10 will wait until Tframe_abort.

For device 1, it’s a BACnet-Extended-Not-Expecting-Reply frame header, because it support extended frame, so it validate header by procedure described in Addendum 135-2012an. Because the data length is too short, so it abort the frame enter IDLE state again, then find another frame:

55 ff 00 01 08 00 00 bf

It’s a token frame passing token to device 1, so device 1 get token then sending Frame B just after Tturnaround:

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

As mentioned above, Device 10 still wait 1 byte to skip previous frame (because Tturnaround < Tframe_abort), so it miss this frame header. get wrong frame as:

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

It’s another Test-Request frame send to device 10, thing repeats.

From above, every devices strictly obey standard, but once frame desynchronization occurs, the whole MSTP bus is stalled forever.

Read more on Solution to mstp frame desynchronization