Data Types

In the automation interface and via ADS complex properties are coded as byte arrays. This section explains how the BACnet data concepts are mapped to C data structures within TwinCAT BACnet/IP, and how they can be used during configuration via the automation interface or ADS. Section 21 of the BACnet standard ("FORMAL DESCRIPTION OF APPLICATION PROTOCOL DATA UNITS") specifies the BACnet data structures.

Apart from a few exceptions, the mapping from BACnet to C is based on the BACnet specification. Exceptions are dynamic data, which are mapped to lists or AnyTypes. The type of a property can generally be determined with the aid of the TwinCAT System Manager. The data type of each property, including the structure (by expanding the property data), can be seen in the Type column in the Settings and Online tabs. Data type names in the Type column ending in "[]" are arrays, names ending in List are lists. Choice-based data types can be recognised by the selection combo box in the Type column, data types with optional fields by a checkbox in the ID field.

Primitive data types

0 = zero

Mapped through a data length of 0.

1 = Boolean

Mapped to ULONG (4 bytes) with the values 0x00000001 for TRUE and 0x00000000 for FALSE

2 = Unsigned Integer

Mapped to ULONG (4 bytes). An optimised variant can be used, whereby integer values up to 255 are shown as 1 byte and integer values up to 65535 as 2 bytes (USHORT).

3 = Signed Integer

Mapped to LONG (4 bytes)

4 = Real

Mapped to FLOAT (4 bytes)

5 = Double

Currently not used

6 = Octet String

Mapped to BYTE[]

7 = Character String

Mapped to CHAR[]. I.e. 0-terminated ISO 8859-1 strings. Currently TwinCAT BACnet/IP supports strings of length 256.

8 = Bit String

Mapped to BYTE[]. The highest-value (most significant) byte contains the number of bits that are not used in the following byte ( 0..7 ). The highest-value bit of the subsequent byte contains the first Boolean value. Apart from a few exceptions, bit strings have a length of 2 bytes.

9 = Enumerated

Mapped to C enumerations ( 4 bytes ), starting from 0.

10 = Date

Mapped to:

struct BACnetDate

  BYTE year; // year minus 1900 X'FF' = unspecified
  BYTE month; // (1.. 12) 1 = January X'FF' = unspecified
  BYTE day; // day of month (1..31), X'FF' = unspecified
  BYTE dayOfWeek; // day of week (1..7) 1 = Monday -- 7 = Sunday -- X'FF' = unspecified
}

11 = Time

Mapped to:

struct BACnetTime
{
  BYTE hour; // hour (0..23), (X'FF') = unspecified
  BYTE minute; // minute (0..59), (X'FF') = unspecified
  BYTE second; // (0..59), (X'FF') = unspecified
  BYTE hundredths; // hundredths (0..99), (X'FF') = unspecified
}

12 = BACnetObjectIdentifier

Mapped to a 4-byte ObjektIdentifier with 10 bits for the object type and a 22-bit object instance

struct BACnetObjectIdentifier
{
  DWORD objInst : 22;
  DWORD objType : 10;
}

Structures

BACnet sequences without optional fields are mapped to structures. An example is shown below.

BACnetPrescale ::=
SEQUENCE
{
  multiplier [0] Unsigned,
  moduloDivide [1] Unsigned
}
struct BACnetPrescale
{
  ULONG multiplier;
  ULONG moduloDivide;
}

Optional fields

BACnet sequences with optional fields are mapped to structures with an additional field validFields. The additional field indicates which fields are active in the structure. Bit 0 of validFields indicates whether the next field (ObjectIdentifier in the example) is active. For non-optional fields the respective bit always must be set.

BACnetObjectPropertyReference ::= SEQUENCE
{
  objectIdentifier [0] BACnetObjectIdentifier,
  propertyIdentifier [1] BACnetPropertyIdentifier,
  propertyArrayIndex [2] Unsigned OPTIONAL
}
struct BACnetObjectPropertyReference
{
  ULONG validFields;
  BACnetObjectIdentifier objectIdentifier; // [0]
  BACnetPropertyIdentifier propertyIdentifier; // [1]
  ULONG propertyArrayIndex; // [2] Unsigned OPTIONAL
}

Choice

A BACnet choice is mapped to a structure with the field choiceField and a union. The choiceField determines which field of the union is active. The length of the data is determined by the largest field of the union. The choiceField is an enumeration (4 bytes).

BACnetRecipient ::=
CHOICE
{
  device [0] BACnetObjectIdentifier,
  address [1] BACnetAddress
}
enum BACnetRecipient_Choice
{
  device,
  address
};struct _BACnetRecipient
{
  BACnetRecipient_Choice choiceField;
  union
  {
      BACnetObjectIdentifier device;
      BACnetAddress address;
  };
}

Arrays

BACnet arrays with fixed data sizes are mapped to C arrays. Some BACnet arrays may contain data of variable length (lists or AnyTypes). In this case BACnet arrays are mapped to lists, as described in the following section.

Lists

BACnet lists and some BACnet arrays are mapped to a special list structure. Each list element has a header (ListEntryHdr), followed immediately by the element data. The highest bit of nEntrySize (nEntrySize & 0x80000000) indicates whether a further element follows ( bit 31 = 1 ), or whether it is the last list element (bit 31 = 0). The size of the subsequent data is coded in the lower 31 bit of nEntrySize as the number of bytes. The header contains a further internally used reserved field, followed by the data. The following list element starts at a 4-byte-aligned boundary, which follows the data.

struct
_ListEntryHdr
{
    DWORD nEntrySize;
    DWORD reserved;
}

For example, if a list contains a first element of length 1 with value 1, the list is coded as follows: 08 00 00 01 00 00 00 00 01, followed by 3 alignment bytes 00 00 00. If the next list element is the last element of the list with 1 byte of data with the value 3: 00 00 00 01 00 00 00 00 03. The data length of the example list would be 24 bytes since the last element is followed by 3 alignment bytes.

An empty list is coded as (4 bytes): 00 00 00 00.

AnyTypes

BACnet data of type ABSTRACT-SYNTAX.&Type are mapped through the structure AnyType. The field nSize contains the size of the following data, including the field dataType (4 bytes). The actual data therefore have the size nSize-4. The field dataType indicates the data type of the data element. A list of data types is provided below.

struct
AnyType
{
    ULONG nSize;
    BACnetDataTypes dataType;    //... Data
}

The data type codings used for AnyTypes are listed below:

#define ARRAYTYPE 0x100
#define LISTTYPE 0x200
enum BACnet  DataTypes
{
// Primitive Data
  DataTypeNull = 0,
  DataTypeBool = 1,
  DataTypeCharacterStringExt = 2,
  DataTypeUnsignedInteger = 3,
  DataTypeSignedInteger = 4,
  DataTypeReal = 5,
  DataTypeDouble = 6,
  DataTypeOctetString = 7,
  DataTypeEnumerated = 8,
  DataTypeBACnetObjectIdentifier = 9,
  DataTypeAddressBinding = 10,
  DataTypeBitString = 11,
  DataTypeDate = 12,
  DataTypeTime = 13,
// Complex Data
  DataTypeDateTime = 14,
  DataTypeArrayIndex = 15,
  DataTypeBACnetCalendarEntry = 16,
  DataTypeBACnetObjectType = 17,
  DataTypeBACnetEventTransitionBits = 18,
  DataTypeBACnetStatusFlags = 20,
  DataTypeBACnetEventState = 21,
  DataTypeBACnetReliability = 22,
  DataTypeBACnetPolarity = 23,
  DataTypeBACnetDateTime = 24,
  DataTypeBACnetEngineeringUnits = 25,
  DataTypeBACnetPriorityValue = 26,
  DataTypeBACnetLimitEnable = 27,
  DataTypeBACnetNotifyType = 29,
  DataTypeBACnetTimeStamp = 30,
  DataTypeBACnetDeviceObjectPropertyReference = 31,
  DataTypeBACnetDeviceStatus = 32,
  DataTypeBACnetServicesSupported = 33,
  DataTypeBACnetObjectTypesSupported = 34,
  DataTypeBACnetSegmentation = 35,
  DataTypeBACnetVTClass = 36,
  DataTypeBACnetVTSession = 37,
  DataTypeBACnetSessionKey = 38,
  DataTypeBACnetRecipient = 39,
  DataTypeBACnetAddressBinding = 40,
  DataTypeBACnetCOVSubscription = 41,
  DataTypeBACnetEventType = 42,
  DataTypeBACnetEventParameter = 43,
  DataTypeBACnetFileAccessMethod = 44,
  DataTypeReadAccessSpecification = 45,
  DataTypeReadAccessResult = 46,
  DataTypeBACnetObjectPropertyReference = 47,
  DataTypeBACnetSetpointReference = 48,
  DataTypeBACnetDestination = 49,
  DataTypeBACnetProgramState = 50,
  DataTypeBACnetProgramRequest = 51,
  DataTypeBACnetProgramError = 52,
  DataTypeBACnetDateRange = 53,
  DataTypeBACnetDailySchedule = 54,
  DataTypeBACnetSpecialEvent = 55,
  DataTypeBACnetClientCOV = 56,
  DataTypeBACnetLogRecord = 57,
  DataTypeBACnetLifeSafetyState = 58,
  DataTypeBACnetLifeSafetyMode = 59,
  DataTypeBACnetSilencedState = 60,
  DataTypeBACnetLifeSafetyOperation = 61,
  DataTypeBACnetBinaryPV = 62,
  DataTypeBACnetDaysOfWeek = 63,
  DataTypeBACnetWeekNDay = 64,
  DataTypeBACnetTimeValue = 65,
  DataTypeBACnetValue = 66,
  DataTypeBACnetAddress = 67,
  DataTypeBACnetPropertyIdentifier = 68,
  DataTypeEnumerationValueType = 69,
  DataTypeBitFieldBit = 70,
  DataTypeBACnetLogDatum = 71,
  DataTypeAnyType = 72,
  DataTypePresentValue = 73,
  DataTypeContextTag = 74,
  DataTypeValueChoice = 75,
  DataTypeBACnetLogStatus = 76,
  DataTypeBACnetRecipientProcess = 77,
  DataTypeSubscribeCOVPropertyRequest = 78,
  DataTypeBACnetPropertyReference = 79,
  DataTypeBACnetPropertyResult = 80,
  DataTypeBACnetDeviceObjectPropertyValue = 81,
  DataTypeCOVNotificationRequest = 82,
  DataTypeEventNotificationRequest = 83,
  DataTypeBACnetNotificationParameters = 84,
  DataTypeChange_of_Bitstring = 85,
  DataTypeChange_of_State=86,
  DataTypeChange_of_Value=87,
  DataTypeCommand_failure=88,
  DataTypeFloating_limit=89,
  DataTypeOut_of_Range =90,
  DataTypeBACnetPropertyValue=91,
  DataTypeComplex_Tag=92,
  DataTypeChange_of_life_safety = 93,
  DataTypeExtended=94,
  DataTypeBuffer_ready =95,
  DataTypeUnsigned_range = 96,
  DataTypeBACnetPropertyResultValue = 97,
  DataTypeServiceCOVPropSubscription = 98,
  DataTypeServiceCOVSubscription = 99,
  DataTypeCOVNotification = 100,
  DataTypeAcknowledgeAlarmRequest = 101,
  DataTypeBACnetVTOpenRequest = 102,
  DataTypeBACnetPrescale = 103,
  DataTypeBACnetScale = 104,
  DataTypeBACnetAction = 105,
  DataTypeBACnetError = 106,
  DataTypeBacnetErrorType = 107,
  DataTypeErrorClass = 108,
  DataTypeErrorCode = 109,
  DataTypeBACnetRejectReason = 110,
  DataTypeBACnetAbortReason = 111,
  DataTypeBDTEntry = 112,
  DataTypeIpEntry = 113,
  DataTypeMaskEntry = 114,
  DataTypeBACnetEthernetAddress = 115,
  DataTypeBACnetLonTalkAddress = 116,
  DataTypeBACnetLonTalkNeuronId = 117,
  DataTypeBACnetNodeType = 118,
  DataTypeBACnetDeviceObjectReference = 119,
  DataTypeBACnetActionCommand = 120,
  DataTypeGetEventInformation = 121,
  DataTypeGetEnrollmentSummaryCriteria = 122,
  DataTypeGetEnrollmentSummaryCriteriaResponse = 123,
  DataTypeDeviceCommunicationControl = 124,
  DataTypeInt16 = 125,
  DataTypeUInt16 = 126,
  DataTypeUInt8 = 127,
  DataTypeInt8 = 128,
  DataTypeByte = 129,
  DataTypeFDTEntry = 130,
  DataTypeBACnetAddress_3 = 131,
  DataTypeBACnetAddress_4 = 132,
  DataTypeBACnetAddress_5 = 133,
  DataTypePersistentDataState = 134,
  DataTypeFallbackRealValue = 135,
  DataTypeFallbackBinaryValue = 136,
  DataTypeRealNull = 137, // PresentValue in AnalogObj
  DataTypeEnumeratedNull = 138, // PresentValue in BinaryObj
  DataTypeUnsignedIntegerNull = 139, // PresentValue in Multistate
  DataTypeUnknown = 140,
  DataTypeBACnetDiagnosisPerformance = 200,
  DataTypeBACnetDiagnosisEthStatistics = 201,
  DataTypeBACnetFrameStatistics = 202,
  DataTypeBACnetInfo = 203,
  DataTypeBACnetDiagnosis = 204,
  DataTypeTcIoEthStatistic = 205,
  DataTypeTcIoEthTxRxErrorCount = 206,
  DataTypeTcIoEthPortStatistic = 207,
  DataTypeBACnetServerStatistics = 208,
  DataTypeBACnetFrameServicesDiag = 209,
// Array types
  DataTypeBACnetCalendarEntryArr = ARRAYTYPE +   DataTypeBACnetCalendarEntry,
  DataTypeBACnetObjectIdentifierArr = ARRAYTYPE +   DataTypeBACnetObjectIdentifier,
  DataTypeCharacterStringExtArr = ARRAYTYPE +   DataTypeCharacterStringExt,
  DataTypeBACnetPriorityValueArr = ARRAYTYPE +   DataTypeBACnetPriorityValue,
  DataTypeBACnetTimeStampArr = ARRAYTYPE +   DataTypeBACnetTimeStamp,
  DataTypeBACnetVTClassArr = ARRAYTYPE +   DataTypeBACnetVTClass,
  DataTypeBACnetVTSessionArr = ARRAYTYPE +   DataTypeBACnetVTSession,
  DataTypeBACnetSessionKeyArr = ARRAYTYPE +   DataTypeBACnetSessionKey,
  DataTypeBACnetRecipientArr = ARRAYTYPE +   DataTypeBACnetRecipient,
  DataTypeBACnetAddressBindingArr = ARRAYTYPE +   DataTypeBACnetAddressBinding,
  DataTypeBACnetCOVSubscriptionArr = ARRAYTYPE +   DataTypeBACnetCOVSubscription,
  DataTypeUnsignedIntegerArr = ARRAYTYPE +   DataTypeUnsignedInteger,
  DataTypeBACnetDestinationArr = ARRAYTYPE +   DataTypeBACnetDestination,
  DataTypeBACnetDeviceObjectPropertyReferenceArr = ARRAYTYPE +   DataTypeBACnetDeviceObjectPropertyReference,
  DataTypeBACnetLifeSafetyStateArr = ARRAYTYPE +   DataTypeBACnetLifeSafetyState,
  DataTypeEnumeratedArr = ARRAYTYPE +   DataTypeEnumerated,
  DataTypeReadAccessSpecificationArr = ARRAYTYPE +   DataTypeReadAccessSpecification,
  DataTypeReadAccessResultArr = ARRAYTYPE +   DataTypeReadAccessResult,
  DataTypeBACnetSpecialEventArr = ARRAYTYPE +   DataTypeBACnetSpecialEvent,
  DataTypeBACnetLogRecordArr = ARRAYTYPE +   DataTypeBACnetLogRecord,
  DataTypeBACnetTimeValueArr = ARRAYTYPE +   DataTypeBACnetTimeValue,
  DataTypeBACnetDeviceObjectReferenceArr = ARRAYTYPE +   DataTypeBACnetDeviceObjectReference,
// Listes
  DataTypeBACnetTimeValueList = LISTTYPE +   DataTypeBACnetTimeValue,
  DataTypeBACnetSpecialEventList = LISTTYPE +   DataTypeBACnetSpecialEvent,
  DataTypeBACnetDailyScheduleList = LISTTYPE +   DataTypeBACnetTimeValueList,
  DataTypeCharacterStringExtList = LISTTYPE +   DataTypeCharacterStringExt,
  DataTypeBACnetLogRecordList = LISTTYPE +   DataTypeBACnetLogRecord,
  DataTypeUnsignedIntegerList = LISTTYPE +   DataTypeUnsignedInteger,
  DataTypeReadAccessResultList = LISTTYPE +   DataTypeReadAccessResult,
  DataTypeReadAccessSpecificationList = LISTTYPE +   DataTypeReadAccessSpecification,
  DataTypeBACnetValueList = LISTTYPE +   DataTypeBACnetValue,
  DataTypeBACnetLogDatumList = LISTTYPE +   DataTypeBACnetLogDatum,
  DataTypeBACnetPropertyResultList = LISTTYPE +   DataTypeBACnetPropertyResult,
  DataTypeBACnetPropertyReferenceList = LISTTYPE +   DataTypeBACnetPropertyReference,
  DataTypeCOVNotificationRequestList = LISTTYPE +   DataTypeCOVNotificationRequest,
  DataTypeEventNotificationRequestList = LISTTYPE +   DataTypeEventNotificationRequest,
  DataTypeBACnetPropertyValueList = LISTTYPE +   DataTypeBACnetPropertyValue,
  DataTypeBACnetActionList = LISTTYPE +   DataTypeBACnetActionCommand,
  DataTypeBACnetActionListList = LISTTYPE +   DataTypeBACnetActionList,
};