Automation Interface

Der TwinCAT System Manager bietet eine XML-basierte Schnittstelle zur programmatischen Konfiguration u.a. von TwinCAT BACnet/IP. Zusätzlich können auch programmatisch alle BACnet-Elemente in einer TwinCAT-Konfiguration erzeugt werden. Generell wird hier auf die allgemeine Dokumentation des TwinCAT Automation Interface verwiesen. In diesem Abschnitt wird erläutert, welche Parameter für BACnet-spezifische Komponenten verwendet werden können.

Erzeugen von BACnet Client-, Server, Objekten

Für das Erzeugen von TwinCAT-Konfigurationselementen bietet der System Manager die Methode CreateChild. Als Parameter kann ein TreeItem-Name, ein Sub-Typ (bei BACnet immer 48), ein Einfügepositions-String und eine Sub-Typ-spezifische Information.

serverItem.CreateChild("Bi_Demo", 48, "", 0x03060203);

Der letzte Parameter wird auch als Class-ID bezeichnet und identifiziert das Element das angelegt werden soll. Es können ein BACnet-Device (CID_TcIoBACnetBACnetDevice), ein BACnet-Server (CID_TcIoBACnetServer) und ein BACnet-Client (CID_TcIoBACnetClient) angelegt werden. BACnet-Server-Objekte können mit der Class-ID CID_TcIoBACnetObjBase addiert mit dem Objekttyp angelegt werden. Ein BinaryInput-Objekt hat damit die Class-ID 0x03060203. BACnet-Client-Objekte mit der Basis Class-ID CID_TcIoBACnetObjRemoteBase.

ULONG CID_TcIoBACnetBACnetDevice   = 0x03060001;
ULONG CID_TcIoBACnetServer     = 0x03060110;
ULONG CID_TcIoBACnetClient     = 0x03060120;
ULONG CID_TcIoBACnetObjBase    = 0x03060200;
ULONG CID_TcIoBACnetObjRemoteBase  = 0x03060300;
ULONG CID_TcIoBACnetDynamicObject  = 0x030602FE;

Property-Konfiguration

Mit Hilfe der Methoden ProduceXml und ConsumeXml erfolgt die Konfiguration der einzelnen TwinCAT-Komponenten. Über das System Manager-Menü "Action" -> "Export XML Description ..." kann die XML-Beschreibung für Testzwecke exportiert und betrachtet werden.

<Parameter>
  <Name>TcIoBACnetPropCfg_PropTimeDelay</Name>
  <BaseType GUID="{18071995-0000-0000-0000-000000000007}">DWORD</BaseType>
  <PTCID>#x03060171</PTCID>
</Parameter>
...
<Value>
  <Name>TcIoBACnetPropCfg_PropTimeDelay</Name>
  <Value>0</Value>
</Value>

Die Abbildung zeigt einen Ausschnitt der mit ProduceXml erzeugten XML-Beschreibung eines BACnet-Objekts. In der Parameter-Sektion ist der Aufbau und Typ eines Parameters beschrieben. In der Value-Sektion wird der eigentliche Wert festgelegt. Die Parameter-ID setzt sich bei BACnet-Properties aus 0x03060100 addiert mit der jeweiligen Property-ID zusammen. Der folgende C#-Quellcode-Ausschnitt zeigt wie der Wert der Property TimeDelay wie im "Settings"-Reiter angezeigt, ausgelesen werden kann.

XmlDocument doc = new System.Xml.XmlDocument();
s = objItem.ProduceXml(true);
doc.LoadXml(s);
XmlNodeList list = doc.SelectNodes("//Value[./Name='" + "TcIoBACnetPropCfg_PropTimeDelay"+ "']/Value");
UInt32 timeDelay = Convert.ToUInt32(list[0].InnerText);

Beim Schreiben der Property-Daten empfiehlt es sich zunächst via ProcuceXml die Xml-Beschreibung auszulesen, dann den Parameterwert zu editieren und abschließend via ConsumeXml die Parameterdaten zu schreiben.

XmlDocument doc = new System.Xml.XmlDocument();
s = objItem.ProduceXml(true);
doc.LoadXml(s);
XmlNodeList list = doc.SelectNodes("//Value[./Name='" + "TcIoBACnetPropCfg_PropTimeDelay"+ "']/Value");
list[0].InnerText = 10;
objItem.ConsumeXml(doc.OuterXml);

Je nach Datentyp der Property kann es vorkommen, dass neben dem Parameterwert auch die Parameter-Sektion angepasst werden muss. Bei STRING-Datentypen muss beim Datentyp STRING(XX) die Länge der Zeichenkette eingetragen werden.

<Parameter>
  <Name>TcIoBACnetPropCfg_PropObjectName</Name>
  <BaseType GUID="{18071995-0000-0000-0000-000000010006}">STRING(5)</BaseType>
  <PTCID>#x0306014d</PTCID>
</Parameter>
...
<Value>
  <Name>TcIoBACnetPropCfg_PropObjectName</Name>
  <String>CAL_0</String>
</Value>

Bei Properties mit komplexen Datentypen werden die Konfigurationsdaten als Byte-Array gespeichert. Die genaue Kodierung der Daten wird im Abschnitt "Datentypen" beschrieben. Um komplexe Parameterdaten zu verändern muss entsprechend in der Parametersektion die BitSize und die Elements der ArrayInfo angepasst werden, welche die Anzahl der Bytes angibt. In der Value-Sektion sind die eigentlich Daten im HEXBIN-Format kodiert ( pro Byte 2 Hexadezimalwerte ).

<Parameter>
  <Name HideSubItems="1">TcIoBACnetPropCfg_PropDatelist</Name>
  <BitSize>96</BitSize>
  <BaseType GUID="{18071995-0000-0000-0000-000000000001}">BYTE</BaseType>
  <ArrayInfo>
    <LBound>0</LBound>
    <Elements>12</Elements>
  </ArrayInfo>
  <PTCID>#x03060117</PTCID>
</Parameter>
...
<Value>
  <Name>TcIoBACnetPropCfg_PropDatelist</Name>
  <Data>00000000ffffffff00000000</Data>
</Value>

Prozessdatenkonfiguration

Auch die Konfiguration der Prozessdaten kann über das Automation Interface innerhalb der XML-Beschreibung angepasst werden. Jede Property die als Prozessdatenvariable aktiviert wurde ist mit einem Eintrag in der Sektion DataArea vermerkt. In TwinCAT BACnet/IP existieren 2 DataAreas je eine für Eingangs- und Ausgangsprozessdaten. Im Beispiel ist die Konfiguration der DataArea mit 2 Eingangsprozessdaten gezeigt. Pro aktivierter Property existiert ein Symbol. Im Symbol ist jeweils der BitOffset vermerkt, der die Position der Property-Daten im Prozessdaten-Image bestimmt. Wichtig ist, dass die Properties jeweils an einer alignten Adresse beginnen (WORD-Symbol an durch 2 teilbaren Adressen, DWORD-Symbole an durch 4 teilbaren Adressen). Die ByteSize der DataArea gibt jeweils die Größe der Symbole an.

<DataAreas>
  <DataArea>
    <AreaNo AreaType="InputSrc" ChildArea="1">0</AreaNo>
    <Name>Inputs</Name>
    <ContextId>1</ContextId>
    <ByteSize>4</ByteSize>
    <Symbol>
      <Name>PresentValue</Name>
      <BaseType GUID="{18071995-0000-0000-0000-000000000004}">WORD</BaseType>
      <BitSize>16</BitSize>
      <BitOffs>0</BitOffs>
    </Symbol>
    <Symbol>
      <Name>StatusFlags</Name>
      <BaseType GUID="{18071995-0000-0000-0000-000000000004}">WORD</BaseType>
      <BitSize>16</BitSize>
      <BitOffs>16</BitOffs>
    </Symbol>
  </DataArea>
  <DataArea>
    <AreaNo AreaType="OutputDst" ChildArea="1">1</AreaNo>
    <Name>Outputs</Name>
    <ContextId>1</ContextId>
    <ByteSize>0</ByteSize>
  </DataArea>
</DataAreas>

Zusätzlich zur Konfiguration der DataArea-Symbole muss in den Parametern TcIoBACnetPdInCfg und TcIoBACnetPdOutCfg dem BACnet-Stack mitgeteilt werden, welche Property-Daten als Prozessdaten behandelt werden sollen. Beim Verändern der Parameter TcIoBACnetPdInCfg und TcIoBACnetPdOutCfg muss wieder jeweils die Datenlänge in der Parameter-Sektion angepasst werden. Die Struktur der beiden Parameter wird im Folgenden erläutert.

<Value>
  <Name>TcIoBACnetPdInCfg</Name>
  <Data>0000000055000000100000006f000000</Data>
</Value>

BACnet Server

Pro aktivierter Prozessdaten-Property müssen die Parameter TcIoBACnetPdInCfg und TcIoBACnetPdOutCfg jeweils ein Element der Struktur ProcessDataServerCfg enthalten. In der Struktur muss festgelegt werden an welches Bit-Offset die Daten kopiert werden sollen, um welche Property es sich handelt (propId) und bei Out-Prozessdaten mit welcher Priorität die Property-Daten ins PriorityArray kopiert werden sollen.

struct ProcessDataServerCfg
{
    ULONG bitOffs;
    USHORT propId;
    USHORT priority;
}

BACnet Client

Auch bei Client-Objekten existieren neben der Symbolkonfiguration zusätzliche Parameter, welche die Konfiguration der Property-Prozessdaten festlegen. Es wird bei Client-Objekten zwischen Ein- und Ausgangsprozessdaten unterschieden. Die Struktur-Felder entsprechen den Konfigurationsdialogen im System Manager.

struct ProcessDataClientInCfg
{
    USHORT propId;
    USHORT useCov      : 1;
    USHORT usePolling  : 1;
    USHORT reserved    : 6;
    USHORT tickModulo  : 8;
    ULONG timeDataCOV;
    ULONG timeDataPoll;
    ULONG bitOffs;
    ULONG bitLen;
    floatcovIncrement;
}
struct ProcessDataClientOutCfg
{
    USHORT propId;
    USHORT useWriteOnChange : 1;
    USHORT usePeriodicWrite : 1;
    USHORT usePriority      : 1;
    USHORT reserved     : 5;
    USHORT tickModulo       : 8;
    ULONG priority;
    ULONG cycleTime;
    ULONG bitOffs;
    ULONG bitLen;
}