TS-7680 BACnet

From embeddedTS Manuals

BACnet is a data communication protocol for Building Automation and Control Networks. Developed by the American Society of Heating, Refrigerating and Air-Conditioning Engineers (ASHRAE), BACnet is a national standard in more than 30 countries around the world, and an ISO global standard. It was created to have a unified communication system for different devices across different manufacturers.

The information in this page is targeted at the TS-7680 SBC. The TS-7680 was designed from the ground up to support many features common to BACnet networks, including RS-485, two 10/100 ethernet interfaces, and the ability to operate at 24 VAC or VDC input.

All of the material and information below should work without issue on every other Technologic System's product, as all of the tools are userspace applications that rely on the kernel only for ethernet or RS-485 data transport. However, be advised that there may be some hurdles along the way.

The BACnet protocol defines a number of different data link (physical) layers, with the two most common being BACnet/IP and BACnetMS/TP. BACnet/IP uses a IPv4 network as its backbone, while BACnetMS/TP uses RS-485 (half-duplex) to create a network of devices.

BACnet

BACnet devices each have various Objects; many of which are pre-defined by the standard but vendors can also define proprietary Objects for use. Some standard Objects are Analog Input, Analog Output, Binary Input, Binary Output, Command, Device, Group, and Schedule.

Each Object has various sets of Properties; like Objects, there are defined standards, but vendors may implement proprietary Properties as well. Standard Properties contain information like name, identifier, type, description, units, and value. The device Object itself has Properties that describe the whole device, while other Objects contained in the device have Properties that describe I/O or other status information.

Additionally, BACnet describes Services which are used for device-to-device communication. These allow for things such as alarm and event notification, file access, direct Object access, remote management, and even virtual terminal access.

For further information on the BACnet specification and definition of operation, please see http://www.bacnet.org/

The Devices

This example uses two different BACnet devices, the iSMA-B-4I4O-H-IP for BACnet/IP, and the RIBTW2401B-BC for BACnetMS/TP.

The iSMA-B-4I4O-H-IP is a DIN rail mountable device, with 4 dry contact inputs and 4 output relays. It is powered from 24 V AC/DC, and includes 4 switches that can be used to manually override the output relays. The device supports MODBUS RTU, MODBUS ASCII, and of course BACnet/IP. While there is an RS-485 port, the -IP variant of the device is only set up to allow BACnet/IP or MODBUS TCP/IP; the RS-485 port is only set up to act as a MODBUS TCP/IP -> RS-485 gateway. Under the main cover is a set of DIP switches to select mode, baud, and set a factory reset.

In this example, each relay output is used to close its respective dry contact input. Specifically, C1 (common for relay 1 and 2) is connected to G0 (common ground for inputs), with O1 (relay NO output 1) and I1 (dry contact input 1) tied together, and O2 and I2 connected. The same is repeated for C2/G0, O3/I3, O4/I4. Enabling Binary Output 0, will cause Binary Input 0 to activate, same for 1, 2, and 3.


The RIBTW2401B-BC is a much more simple device contained in a flat square enclosure. It has a single dry contact input, and a single output relay. It can be powered from 24 V AC/DC or 120 V AC. The output relay does have an override, however it is located on the internal DIP switch header and is not necessarily practical for ready use. The device supports BACnetMS/TP vis RS-485. Inside of the unit is a set of DIP switches to set the baud rate, network address, and override current relay position. Note that this device uses index 1 for its input and output Object instance numbers; whereas many devices will use 0 as the first Object instance.

In this example, the relay common and NO contacts are wired directly in to the connections of the dry contact input. Activating the relay will close the input and cause it to read as a 1.

Software

This example uses BACnet Stack 0.8.3, a userspace API for BACnet in linux.

BACnet Stack API

Starting from our stock image, set up the software on the SBC to compile the API on the device itself:

apt-get update && apt-get install -y unzip build-essential subversion git

Download the bacnet-stack source using subversion:

svn checkout http://svn.code.sf.net/p/bacnet/code/tags/bacnet-stack-0.8.3/

Enter the newly unpacked directory and build as per instructions for IP or MS/TP below.

The devices themselves need to have their BACnet ID set up; refer to the specific device manual for information on doing this. Additionally, some BACnet/IP devices need to have an IP address manually set and will not use DHCP. BACnetMS/TP modules also need to have a known baud rate, they can either be set or the host interface set up to adjust to the specific baud rate. Ensure these parameters are all set to be valid for your specific TCP/IP network, or RS-485 settings.

In the examples below, our BACnet/IP ID is 31337, the BACnetMS/TP address is set to 277000, and the baud rate is set to 38400.


BACnet example applications

Using the API above, we have created two example applications to verify functionality of the connection as well as the devices themselves. Please note that there is a difference between the MS/TP and IP builds, as the BACnet Stack API needs to be configured for one or the other. (It is possible to use both simultaneously, but that is outside the scope of this document.) Download our example code if wanted, and then jump to either the IP or MS/TP section below for information on building the API, testing connectivity, and ultimately running our example code.

Clone the example repository:

git clone https://github.com/embeddedTS/BACnet-demo


BACnet/IP

BACnet/IP is the default build for this tool. Ensure that the BACnet/IP device is set up correctly on the same TCP/IP network as the host and given proper power. The device is expecting 24 V DC or AC. The ID can be discovered with the demo tools (shown further down), but in most situations would already be known.

make clean all

Once this is compiled, a set of libraries as well as some demo applications will be built. Functionality will first be checked with some of these demo tools. Note that all of the demo tools when called without arguments show a brief about their use, however if the only argument is "--help" then a much more in-depth output and description is given for all of the arguments.

First, let's scan the network for any devices, this is using the "Who-Is" Service.

root@imx28:~/bacnet-stack-0.8.3# ./demo/whois/bacwi
Received I-Am Request from 31337, MAC = 10.10.10.231.186.192
;Device   MAC (hex)            SNET  SADR (hex)           APDU
;-------- -------------------- ----- -------------------- ----
  31337   0A:0A:0A:E7:BA:C0    0     00                   480
;
; Total Devices: 1

Our device is detected, and is reporting itself on the network.

Next, the demo tools can be used to do some basic inquiry of the device. The BACnet Stack demos require the use of "magic numbers" to represent various objects and properties, see Appendix A for a table of these.

# Get the the device name
root@imx28:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 31337 8 31337 77
"iSMA-B-4I4O-H-IP"

# Get the state of the first input
root@imx28:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 31337 3 0 85
inactive

# Get the state of the first relay
root@imx28:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 31337 4 0 85
inactive

With each output wired to close each input, setting the relay will also change the respective input:

# Check the first input
root@imx28:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 31337 3 0 85
inactive

# Set the first relay output
root@imx28:~/bacnet-stack-0.8.3# ./demo/writeprop/bacwp 31337 4 0 85 0 -1 9 1
WriteProperty Acknowledged!

# Check the first input again
root@imx28:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 31337 3 0 85
active

Example application

With the functionality verified, it is now time to compile our example code against the API. Copy bacnetip-test.c from our github repo to the root directory of the backnet-stack folder. Next, build the application:

gcc -Wall bacnetip-test.c demo/object/device-client.c -I ports/linux/ -I include/ -I demo/object/ -L lib/ -o bacnetip-test -lbacnet

This will output the binary 'bacnetip-test'. The example expects the setup described above where each output is connected to each input, so when the output is asserted the input will be active. The example will scan the network using a Who-Is message, it will attempt to connect to the first device that responds to the request. Then it will count the number of available inputs by querying each number in succession. Once the max is found, the example will proceed to use a binary count to walk through all of the output combinations, checking the input states after each output change. If at any time the input state does not match the output state then the program will immediately return with a failure notice.

The example can be run, and output similar to the following can be seen:

root@imx28:~/bacnet-stack-0.8.3# ./bacnetip-test
Received I-Am Request from 31337, MAC = 10.10.10.231.186.192
Received I-Am Request from 31337, MAC = 10.10.10.231.186.192
Located and bound to ID 31337
Found a total of 4 inputs, assuming an equal amount of outputs.
Cycling through all binary combinations of outputs.

BACnetMS/TP

BACnetMS/TP requires a different build of the bacnet-stack. Ensure that the BACnet device is set up correctly; wired to the RS-485 port on the J6 RJ-45 connector both power and RS-485 data, baud rate set to 38400, and address set. Like BACnet/IP, MS/TP can scan for bus addresses on the RS-485 bus.

The default files used by the demo assume an incorrect UART port. Before building bacnet-stack for MS/TP, modify ports/linux/rs485.c, and change the port on line 85. Our setup uses /dev/ttyAPP2 for the RS-485 UART on the TS-7680.

Once this modification is complete, the bacnet-stack tool can be built:

make BACDL_DEFINE=-DBACDL_MSTP=1 clean all

Once this is compiled, a set of libraries as well as some demo applications will be built. Functionality will first be checked with some of these demo tools. Note that all of the demo tools when called without arguments show a brief about their use, however if the only argument is "--help" then a much more in-depth output and description is given for all of the arguments.

Before any of the following examples will work, the RS-485 automatic TX enable must be set up, and power enabled to the BACnet device. This can be done with the following on the TS-7680:

tshwctl --autotxen 2 --baud 38400
tshwctl --modbuspoweron

Let's scan the network for any devices, this is using the "Who-Is" Service.

root@ts7680:~/bacnet-stack-0.8.3# ./demo/whois/bacwi
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
Received I-Am Request from 277000, MAC = 0.0.0.0.0.0
;Device   MAC (hex)            SNET  SADR (hex)           APDU
;-------- -------------------- ----- -------------------- ----
  277000  00                   0     00                   480
;
; Total Devices: 1

If your device is not found, then it is recommended to re-check all of the device settings (baud, address, wiring, power), verify that the ports/linux/rs485.c file was properly modified as needed, and re-run the make command to rebuild the whole application.

As seen above, our device is detected, and is reporting itself on the bus.

Next, the demo tools can be used to do some basic inquiry of the device. The BACnet Stack demos require the use of "magic numbers" to represent various objects and properties, see Appendix A for a table of these.

# Get the the device name
root@imx28:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 277000 8 277000 77
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
"DEV277000"

# Get the state of the first input, remember, on our demo device the single input is 1 indexed.
root@ts7680:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 277000 3 1 85
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
inactive

# Get the state of the first relay, remember, on our demo device the single output is 1 indexed.
root@ts7680:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 277000 4 1 85
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
inactive

With each output wired to close each input, setting the relay will also change the respective input:

# Check the first input
root@ts7680:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 277000 3 1 85
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
inactive

# Set the first relay output
root@ts7680:~/bacnet-stack-0.8.3# ./demo/writeprop/bacwp 277000 4 1 85 0 -1 9 1
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
WriteProperty Acknowledged!

# Check the first input again
root@ts7680:~/bacnet-stack-0.8.3# ./demo/readprop/bacrp 277000 3 1 85
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
active

Example application

With the functionality verified, it is now time to compile our example code against the API. Copy bacnetmstp-test.c from our github repo to the root directory of the backnet-stack folder. Next, build the application:

gcc -g -Wall bacnetmstp-test.c demo/object/device-client.c -I ports/linux/ -I include/ -I demo/object/ -L lib/ -DBACDL_MSTP=1 -o bacnetip-test -lbacnet -lpthread -lm

This will output the binary 'bacnetmstp-test'. The example expects the setup described above where the output is connected to the input, so when the output is asserted the input will be active. The example will scan the bus using a Who-Is message, it will attempt to connect to the first device that responds to the request. Since the device used for this example does not use a 0 index for each Object, it hard codes the interaction with Object instance 1 for the input and output. It will deassert the output, check the input, assert the output, and check the input again. If the input does not match the output for either output state, the example application will exit with an error message.

The example can be run, and output similar to the following can be seen:

root@imx28:~/bacnet-stack-0.8.3# ./bacnetip-test
RS485: Initializing /dev/ttyAPP2 at Baud Rate 38400=success!
MS/TP MAC: 7F
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
Received I-Am Request from 277000, MAC = 0.0.0.0.0.0
Received I-Am Request from 277000, MAC = 0.0.0.0.0.0
Located and bound to ID 277000
Setting and clearing relay and checking loopback.

Appendix A, BACnet Stack "magic numbers"

Below are some of the "magic numbers" that BACnet Stack uses for various Objects or Properties. These are needed when specifying commands on the command line for the demo tools. Note that not every Object or Property is listed, only the common ones used in the examples above, or that may be useful to those using the demonstration.

Object Num.
Analog Input 0
Analog Output 1
Analog Value 2
Binary Input 3
Binary Output 4
Binary Value 5
Device 8
Property Num.
Object_Identifier 75
Object_Name 77
Out_Of_Service 81
Polarity 84
Present_Value 85
Status 111
Data Type [1] Num.
Null 0
Boolean 1
Unsigned Int 2
Signed Int 3
Real 4
Double 5
Octet String 6
Character String 7
Bit String 8
Enumerated [2] 9
  1. BACnet Stack also refers to this as "Tag"
  2. This is one of the more commonly used datatypes