TS8020 | TwinCAT BACnet Supplement

PLC automapping


Special comments that are added after the PLC variable declaration can be used for automated configuration of BACnet objects from the PLC program. The procedure can be used to configure BACnet objects, link BACnet property variables with PLC variables and initialise BACnet properties.

PLC automapping can be carried out via the BACnet server in the Settings tab, once the PLC project has been added to the hardware configuration. Automapping is triggered by pressing the Map button once the required PLC program has been selected:

PLC automapping 1:

PLC automapping for BACnet servers

The following source code extract illustrates the application of automapping comments. An allocated variable "av0" of type REAL created. The used comments define BACnet properties for use with automapping. The general comment syntax is defined by the PLC. Comments start with "(*" and end with "*)". Comments with the special prefix "~" are transferred by the PLC compiler into the TPY file for the respective symbols. These special comments, referred to as property, always have the following structure: "( NAME : VALUE : COMMENT )". For BACnet automapping the name is composed of "BACnet_[BACnet-Property-Name]". "VALUE" depends on the BACnet property and is explained accordingly.

In the example the symbol "av0" is annotated with 3 BACnet properties, which specify that it is an AnalogValue object (AV). The object instance is 100. For the property ObjectIdentifier it should be noted that in the PLC comment it only contains the instance number, not the coded object type, as in BACnet. In the example, automapping creates a BACnet object of type AnalogValue with the instance number 100. For each symbol a link can be made with a cyclic BACnet property variable. For variables that are not to be linked the comment "NOLINK" (see note in the appendix) can be used. For each symbol only one property may exist for linking. In the example the property PresentValue of the AnalogValue object is linked with the PLC variable "av0".

av0 AT %I* : REAL;             (* ~ (BACnet_ObjectType         :
AV             : NOLINK)
(BACnet_ObjectIdentifier : 100 : NOLINK)
(BACnet_PresentValue : : )

A further example is provided below. In this case a BACnet object of type BinaryInput is created. No object instance is defined. During automapping an available object instance number is generated automatically. The example demonstrates how the values of certain BACnet properties can be pre-initialised. The BACnet properties Description and ObjectName are initialised with the values "Hello, BACnet" and "BinaryInput_1". After automapping the corresponding values appear in the generated BACnet object (Settings tab) when the configuration is activated "Online". In addition the object name is used in the System Manager tree. In the example a variable of type BOOL is linked with the property PresentValueBool. Although the BACnet data type of the PresentValues of binary objects is an enumeration type, the auxiliary property PresentValueBool was introduced for efficient handling of the PLC, in order to be able to link Boolean variables. For further details please refer to section "Process data".

bi0 AT %I* : BOOL;             (* ~ (BACnet_ObjectType         :
BI             : NOLINK)              
(BACnet_Description        : Hello, BACnet  : NOLINK)
(BACnet_ObjectName : BinaryInput_1 : NOLINK)
(BACnet_PresentValueBool : :)*)

Even if variables of primitive type are used, several variables can be linked with a BACnet object. To this end identical object type and object instance parameters should be specified for two variables. In the example the BACnet properties PresentValue and StatusFlags are linked with AnalogValue object "100".

av0 AT %I* : REAL;             (* ~ (BACnet_ObjectType         : AV             :
(BACnet_ObjectIdentifier : 100 : NOLINK)
(BACnet_PresentValue : :)
av0_StatusFlags AT %I* : WORD; (* ~ (BACnet_ObjectType : AV : NOLINK)
(BACnet_ObjectIdentifier : 100 : NOLINK)
(BACnet_StatusFlags : :)

Commandable properties

BACnet objects can also be accessed in write mode from the PLC. We recommend to only link commandable BACnet properties in this way. Commandable BACnet properties are linked with a PriorityArray and support write access with priorities 1 to 16. For BACnet properties without support of priorities, which are linked to the PLC, the behaviour for BACnet network write access via BACnet WriteProperty is undefined, since the property value is overridden cyclically by the PLC.

In the example a "Q"-allocated variable is defined, which is linked with the PresentValue of an AnalogOutput object. Writing from the PLC results in an entry with priority level "8" in the PriorityArray. The PresentValue properties of BinaryValue, BinaryOutput, AnalogValue, AnalagOutput, MultistateValue and MultistateOutput objects are commandable. The highest active priority (1=highest, 16=lowest) is set as PresentValue. A priority in the PriorityArray is active if it is not NULL.

ao0_PresentValue8 AT %Q* : REAL;(*~ (BACnet_ObjectType         : AO             :
(BACnet_PresentValue_Priority8 : :)

A special feature of commandable properties is the entry NULL in the PriorityArray, which in BACnet represents a distinct data type that is different from the respective value data types (REAL, BINARY_PV, UNSIGNED). The value NULL, which deactivates a priority level in the PriorityArray, can be written for the respective objects via the linked variable as follows:


Function blocks (FBs) are also supported for structured linking of BACnet objects during automapping. The source code extract shown below illustrates the declaration of a BACnet function block. In order to be considered in automapping, these blocks must begin with the prefix "FB_BACnet". The example defines an FB for an AnalogOutput object, which is available as a template in the BACnet PLC library "TcBACnet.lib". The properties PresentValue, StatusFlags, Reliability and OutOfService are linked as input variables to the PLC, the property PresentValue with write-access, priority 8.

    ObjectType: E_BACNETOBJECTTYPE;           (* ~ (BACnet_ObjectType       :AO    : NOLINK) *)
    PresentValue AT%I*: REAL;                 (* ~ (BACnet_PresentValue     :      :) *)
    StatusFlags AT%I*: UINT;                  (* ~ (BACnet_StatusFlags      :      :) *)
    Reliability AT%I*: E_BACNETRELIABILITY;   (* ~ (BACnet_Reliability      :      :) *)
    OutOfService AT%I*: BOOL;                 (* ~ (BACnet_OutOfService     :      :) *)
    PresentValue_Priority8 AT%Q*: REAL;       (* ~ (BACnet_PresentValue_Priority8 ::) *)

This FB can be instantiated in the main program (or another FB, program). Additional comments can be specified during instantiation. Comments at the instantiation level have higher priority than comments at FB declaration level. In the example an AnalogOutput object is created, and the object instance and the BACnet property Description are initialised at instantiation level. Through the FB declaration the properties PresentValue, StatusFlags, Reliability, OutOfService and PresentValue_Priority8 are linked in the generated BACnet object.

ao1 : FB_BACnet_AnalogOutput;                 (* ~ (BACnet_ObjectIdentifier : 100 : NOLINK) *)
ao1 : FB_BACnet_AnalogOutput;                 (* ~ (BACnet_ObjectIdentifier : 100   : NOLINK)
                                                   (BACnet_Description      : hi,ao : NOLINK)

BACnet FBs can be used hierarchically, i.e. an "FB_BACnet_Pump" containing several FB_BACnet_AnalogOutput instances can be defined, for example. For nesting depths greater than one a StructuredView object is created in the System Manager. BACnet comments are not handed down to several hierarchical levels. Only the instantiation and declaration levels are supported. An exception is the BACnet comment BACnet_ObjectIdentifier, which is resolved over several hierarchical levels, in order to support ID allocation for nested FBs.

PLC automapping 2: If an object instance is specified at a higher level, it may potentially affect many objects of the same type. The starting point for generating an object ID is the specified ID (if, for example, 1000 is specified as the object instance, a new free ID above 1000 is identified). An FB_BACnet_Room with 2 AV and 2 BV objects and a start ID of 1000 will therefore generate BACnet objects AV:1000, AV1001, BV:1000 and BV:1001. The resulting object IDs are calculated before the actual mapping operation. If objects with the determined IDs already exist, e.g. from an IO mapping, the existing objects are used/linked, and no new objects are created.

In addition to nested FBs, one-dimensional arrays are also supported. The following example shows the declaration of an array raume of type FB_BACnet_Raum that contains further BACnet objects. In this way systematic units with identical functionality can be managed. Arrays at different nesting levels are also supported, so that a BACnet object fbHaus[1].EtageU.Raum[10].tmpSollt can be generated, for example.

raume : ARRAY[0..10] OF FB_BACnet_Raum;

Configuration function block instances

BACnet comments on function block declaration level are used for all instances of the function block in common. For certain BACnet properties it is important to be defined per instance. As one example, this feature allows to define object identifiers of sub function block BACnet objects. It is also possible to link hardware modules on an instance level. In the following example, BACnet properties are defined per function block instance.

bi : FB_BACnet_BinaryInput; (*~(BACnet_OutOfService : TRUE: NOLINK)*)
bi2 : FB_BACnet_BinaryInput;
sub1 : FB_BACnet_SubSub;
sub2 : FB_BACnet_SubSub; 
subArr : ARRAY[0..1] OF FB_BACnet_SubSub;
s1 :FB_BACnet_Sub; (* ~   { BACnet_ObjectIdentifier<sub1/bi>                : 1017   : }
                        { BACnet_ObjectIdentifier<sub2>           : 1028   : }
                        { BACnet_ObjectIdentifier<subArr[0]/bi>   : 5555   : }
                        { BACnet_ObjectName<sub2/bi>              : biname : NOLINK }

By the annotation of an instance path after the BACnet property name comment, BACnet comments can be applied to sub elements of a function block instance. For this, the instance path can be given in "<" and ">". Within the example above, to the BACnet object bi of instance sub1, object identifier 1017 will be applied. Single sub levels can be separated using "/". BACnet property comments can also be applied to sub levels. In the example, object identifier 1028 is applied to the function block FB_BACnet_SubSub instance sub2, causing the generatin of object identifiers 1028 for object s1.sub2.bi and 1029 for object s1.sub1.bi2. The instance path is also allowed to contain array elements.

Write protection and optional properties

Special comment options were introduced for controlling write protection and optional properties. Additional options can be specified in the form of a comma-separated list in the comment part of the PLC comments. DISABLE deactivates an optional property. WRITEPROTECT activates write protection for a writeable property. Make sure that the option NOLINK is specified when configuring multiple properties. The following example shows the configuration of write protection and optional properties.

bo1: FB_BACnet_BinaryOutput; (* ~(BACnet_NotifyType             :        : DISABLE,NOLINK)
                                 (BACnet_ChangeOfStateTime      :        : DISABLE,NOLINK)
                                 (BACnet_ChangeOfStateCount     :        : DISABLE,NOLINK)
                                 (BACnet_ActiveText             : AN     : WRITEPROTECT,NOLINK)
                                 (BACnet_InactiveText           : AUS    : WRITEPROTECT,NOLINK)                    

Property references

The REFERENCE option was introduced for configuring reference properties. Automatic generation of object IDs means that value initialisation of properties cannot be used for referencing properties of other PLC BACnet objects, since the object IDs are unknown when the PLC program is implemented. Specification of the REFERENCE option and property name as a suffix enables referencing of automatically generated objects. A simple heating system is described below as an example. Set values, actual values and control values are specified via analog* BACnet objects, which are linked with a Loop object via references.

fbSollwert   : FB_BACnet_AnalogValue;
fbStellwert  : FB_BACnet_AnalogOutput;
fbIstwert    : FB_BACnet_AnalogInput;
fbTempRegler : FB_BACnet_Loop; (* ~ (BACnet_ManipulatedVariableReference : ./fbStellwert : REFERENCE_PresentValue) 
                                    (BACnet_SetpointReference            : ./fbSollwert  : REFERENCE_PresentValue)
                                    (BACnet_ControlledVariableReference  : ./fbIstwert   : REFERENCE_PresentValue) 

The REFERENCE option also works for Schedule and TrendLog objects:

bi       : FB_BACnet_BinaryInput;
bv      : FB_BACnet_BinaryValue;
tl      : FB_BACnet_TrendLog; (* ~(BACnet_LogDeviceObjectProperty  : ./bi : REFERENCE_PresentValue) *)
sched   : FB_BACnet_Schedule; (* ~(BACnet_ListOfObjectPropertyRefs : ./bv : REFERENCE_PresentValue) *)

View configuration

During PLC automapping, StructuredView objects are created for each nesting depth in the form of programs and function blocks, in order to map the PLC structure to BACnet. Depending on the component identification system used, it may be necessary to adapt the names BACnet objects and their structure with a name prefix. The PLC comment "BACnet_StructuredViewPath" can be used to define dedicated name prefixes for PLC automapping. "BACnet_StructuredViewPath" can be used to annotate any variable at the required structuring levels.

  viewDummy : BOOL; (* ~( BACnet_StructuredViewPath : \/Building1\/Floor2 : ) *)
  room1 : FB_BACnet_Room;
  room2 : FB_BACnet_Room;

In the example the name Building1.Floor2.room1.XXX is used for all BACnet objects within the function block FB_BACnet_Room, instead of the name MAIN.room1.XXX. In addition to the use for the names of BACnet objects, a StructuredView object is also created for each hierarchical level. Hierarchical levels are defined by the string "\/".

Facility identitication

Depending on the used facility identification system, it can be neccessary to adjust generated BACnet object names. As a default structure levels will be separated using ".". By annotating the key word "StructureSeparator" to any variable of a programm or global variable, the separator symbol can be exchanged or even totally eliminated. The following example demonstrates the annotation of the separator symbol "_". A new separator symbol should only be defined once within a project.

dummy : BOOL; (* ~( BACnet_StructureSeparator :_: ) *) 

Initialisation of complex property values

The initialisation of property values via PLC automapping is limited by the PLC comment syntax. The reserved characters "(", ")", ":", "*" and " cannot be used. In addition, for BACnet properties with selection type (Choice) or optional fields it is not always possible to unambiguously analyse each string, if an optimised display form is used, as in the System Manager.

For certain properties special parsers were implemented, which enable simplified configuration of property values. The following example shows how the StateText property of a MultiStateValue object can be initialised.

mv : FB_BACnet_MultiStateValue;  (* ~(BACnet_StateText   : {Low;Medium;High}       : NOLINK )*)

BitField properties (EventEnable, AckRequired) can be initialised by specifying a hexadecimal number. In this case it is advisable to use the corresponding value from the System Manager:

bi : FB_BACnet_BinaryInput;      (* ~(BACnet_EventEnable : 0xE005                  : NOLINK )*)

The Priority property of the NotificationClass object can also be initialised in abbreviated form. In the example this array property is initialised with the values 12, 12 and 122. For the initialisation of BitField properties the more transparent form of array-like initialisation was implemented. In the example the bits for "to_offnormal" and "to_fault" are set in the property AckRequired. A BitField property without set bit can be initialised with the string "{}".

nc : FB_BACnet_NotificationClass;(* ~(BACnet_Priority    : {12;12;222}             : NOLINK)
                                     (BACnet_AckRequired : {to_offnormal;to_fault} : NOLINK)

Since it is not possible to implement dedicated parsers for all complex properties, the option of initialisation with the aid of XML was introduced. XML has the advantage that it is not necessary to use the reserved comment syntax characters, so that there are no restrictions for initialisation of the property values. The XML values for the property initialisation can simply be created via the Copy&Paste function for the property values. A property can be created in the System Manager using wizards. Via the context menu in the property view ("Online" or "Settings") the current value of a property can be added to the clipboard via "Copy Value" (or via the shortcut CTRL-C) and used in PLC Control via "Paste" or CTRL-V.

PLC automapping 3:

Is the SHIFT key is pressed while using the "Copy Value" function, the XML string is copied as a line. Otherwise a structured variant is generated in multi-line mode. Using single-line mode makes the variable declaration in the PLC program more transparent. The following example illustrates how the property StartTime of a TrendLog object is initialised via the XML syntax:

tl : FB_BACnet_TrendLog; (* ~(BACnet_StartTime : 
: NOLINK )*)

Connecting hardware modules

In general, the connection to hardware modules can be done via Io-Automapping and the assignment of according object identifiers to BACnet objects defined within PLC code. To support an efficient generation of BACnet projects, it is possible to configure the connection to hardware modules directly within PLC code, without the requirement of an Io-Automapping. Using the key word LINKPATH, it is possible to link a BACnet property variable directly to an Io-variable. Despite linking a PLC variable to a BACnet property variable, in this case a BACnet property variable will directly be linked to a variable of another device ( device-device mapping).

PLC automapping 4: Please pay attention to the comment start- and ending symbol. PLC comments can be started by "(" or "{" and closed by ")" or "}" respectively. If the content of a comment contains e.g. "(" start- and end-symbol should be "{" and "}" and vice e versa. Usually external link may contain "(" or ")". So togehter with the LINKPATH option "{" and "}" should be used.

The following example shows the connection of a BinaryInput BACnet object with the first channel of the third module (KL1002). Using the variable PresentValue of FB_BACnet_BinaryInput the PLC code can directly access the hardware value.

bi : FB_BACnet_BinaryInput;(* ~{ BACnet_RawIoBinaryBoolValue : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 1^Input : LINKPATH } *)

By using additional parameters of the LINKPATH option: Offset1, Offset2 and the bit size of the link can be specified (LINKPATH<[Offset1],[Offset2],[bitsize]>). Using a bit size of 0, automatically the maximal possible number of bits will be linked. Without the specification of additional parameters Offset1 and Offset2 will be initialised to 0. Offset1 refers to the BACnet property variable. Offset2 refers to the external link.

bx : FB_BACnet_BinaryInput;(* ~{ BACnet_RawIoBinaryBoolValue : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 1^Input : LINKPATH<0,0,1> } *)

In conjunction with function blocks, also sub elements of function block instances can be linked to hardware variables. By using the instance path syntax "<[]>", a BACnet property variable can be link to hardware.

s1 :FB_BACnet_Sub; (* ~   { BACnet_RawIoBinaryBoolValue<sub1/bi>  : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 1^Input : LINKPATH }
                        { BACnet_RawIoBinaryBoolValue<sub2/bi>  : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 2^Input : LINKPATH }
                        { BACnet_RawIoBinaryBoolValue<sub1/bi2> : TIID^Rt-Ethernet^BK9000^Term 2 KL1002^Channel 2^Input : LINKPATH }      

In addition, PLC-automapping allows linking variables out of BACnet. Using the option "ExtLink", any (located) PLC symbol can be linked to an external variable (e.g. a hardware component). Using the option "ExtLink2" 2 external variables can be linked together. Using addional parameters as already introduces to LINKPATH, Offset1, Offset2 and the bit size can be defined for the link. In the following example the usage of this option is demonstrated.

b1 AT%I*        : BOOL;     (* ~{ ExtLink             : TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input       : } *)
bDummy  : BOOL;  (* ~{ ExtLink2              : TIID^Rt-Ethernet^BK9000^Term 5 (KL2012)^Channel 1^Output      : TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input } *)
b1 AT%I*        : BOOL;     (* ~{ ExtLink<0;0;1>        : TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input       : } *)
bDummy  : BOOL;  (* ~{ ExtLink2<0;0;1>         : TIID^Rt-Ethernet^BK9000^Term 5 (KL2012)^Channel 1^Output      : TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input } *)

As a good starting point for linking hardware modules the EXP-export of TwinCAT BACnet/IP can be used. Within the EXP-Export configuration dialog, the option "Export I/O configuration" enables the generation of function block definitions of hardware modules for TcBACnet.lib. For each found IO-Bus definitions for BACnet function blocks will be generated. The procedure EXP-Export together with a PLC automapping creates a similar configuration as an IO-Automapping. The advantage of the PLC procedure is that hardware modules can be integrated into the logic structure of the PLC-/facility. In addition hardware module, which are not desired to be visible via BACnet can be deleted easiely.

PLC automapping 5:

PLC automapping for BACnet clients

To link PLC variables with process data properties of remote BACnet objects, Device ID can be specified as a comment, in addition to the object type and instance. In this case the PLC variables are linked with previously created BACnet objects (e.g. through scanning of clients). Support for creating remote BACnet objects via PLC automapping is currently not offered (unlike for servers). Only automatic activation of process data and linking is supported.

In the following source text extract a variable of type REAL is created. During automapping it is linked with the property PresentValue of object AnalogValue:100 under the client with the BACnet-ID "42". The process data variable of the remote BACnet object is activated automatically.

av0 AT %I* : REAL;             (* ~ (BACnet_ObjectType             : AV    :
(BACnet_DeviceID : 42 : NOLINK)
(BACnet_ObjectIdentifier : 100 : NOLINK)
(BACnet_PresentValue : :)

Auxiliary properties are available for the configuration of the process data-specific parameters of client properties, which enable all options that can be set in the System Manager to be configured automatically. These are write priority for PresentValue properties, cycle time, COV increment, COV resubscription interval for COV subscriptions and flags for configuring whether data are to be processed cyclically or via COV or OnChange. The following source code extract illustrates the application of these auxiliary properties.

ao0 AT %Q* : REAL;             (* ~
(BACnet_ObjectType             : AO     : NOLINK)
(BACnet_DeviceID : 42 : NOLINK)
(BACnet_ObjectIdentifier : 0 : NOLINK)
(BACnet_RemotePriority : 8 : )
(BACnet_RemoteCycleTimeWrite : 1000 : )
(BACnet_RemoteFlagsWrite : 1 : )
(BACnet_PresentValue : : )
ao1 AT %I* : REAL; (* ~ (BACnet_ObjectType : AO : NOLINK)
(BACnet_DeviceID : 42 : NOLINK)
(BACnet_ObjectIdentifier : 0 : NOLINK)
(BACnet_PresentValue : : )
(BACnet_RemoteCycleTimeRead : 1000 : )
(BACnet_RemoteFlagsRead : 1 : )
(BACnet_RemoteCovincrement : 0,5 : )
(BACnet_RemoteResubscriptionInterval : 60 : )

The RemoteFlagsWrite have the following meaning for output variable (%Q), from the configured controller to the remote device:

For RemoteFlagsRead - input variable (%I) - reading from a remote device the following applies:

If no auxiliary properties are specified for remote objects, the default settings of the System Manager are used:

For priority-based properties (PresentValue) a write priority can be configured, in order to enable access to higher priorities of the PriorityArray. As for servers, the value NULL can be written to the associated PriorityArray in order to disable this priority level. For analog and binary objects this is done in the same way as for servers (value > 1 for binary objects; NaN for analog objects). For AnalogOutput objects the Min/MaxPresValue range is not monitored, which means that NULL can only be generated via NaN. In contrast to servers, for multistate objects only writing of 0 results in NULL in the PriorityArray. For performance reasons the property NumberOfStates is not read by the remote device.

In conjunction with the TwinCAT BACnet PLC library "TcBACnet.lib" an efficient option for using client configurations in the PLC is available. Once the clients to be used have been added to the System Manager (e.g. through scanning of a BACnet network), the variable declaration and associated annotation with automapping comments can be generated by specifying a destination file with the extension "EXP" in the Export option of the Settings tab in the BACnet device. This can then be imported in a PLC project in PLC Control. The basis BACnet FBs of the library are used (e.g. "FB_BACnet_AnalogInput"). It is advisable to use the following approach:

  1. Create a new PLC project in PLC Control and add the library "TcBACnet.lib"
  2. Adjust the remote properties for automatic configuration of the client process data (comments after the instances of the library blocks)
  3. Compile and add the PLC project in the System Manager
  4. Via a BACnet server (not essential for running a client project) trigger PLC automapping (the BACnet server can then be deleted ...)
  5. The PLC variables are automatically linked with the client object properties, and the process data are set accordingly...