Replaced standard function blocks library definition from dictionary to plcopen xml files
authorLaurent Bessard
Tue, 10 Sep 2013 23:10:58 +0200
changeset 1313 85c167bfff93
parent 1312 250c3ae0787c
child 1314 822d483197ad
Replaced standard function blocks library definition from dictionary to plcopen xml files
PLCControler.py
plcopen/Additional_Function_Blocks.xml
plcopen/Standard_Function_Blocks.xml
plcopen/plcopen.py
plcopen/structures.py
--- a/PLCControler.py	Tue Sep 10 10:37:42 2013 +0200
+++ b/PLCControler.py	Tue Sep 10 23:10:58 2013 +0200
@@ -30,7 +30,7 @@
 import datetime
 from time import localtime
 
-from plcopen import*
+from plcopen import *
 from graphics.GraphicCommons import *
 from PLCGenerator import *
 
@@ -1297,14 +1297,16 @@
         return variables
             
     # Add a global var to configuration to configuration
-    def AddConfigurationGlobalVar(self, config_name, type, var_name, 
+    def AddConfigurationGlobalVar(self, config_name, var_type, var_name, 
                                            location="", description=""):
         if self.Project is not None:
             # Found the configuration corresponding to name
             configuration = self.Project.getconfiguration(config_name)
             if configuration is not None:
                 # Set configuration global vars
-                configuration.addglobalVar(type, var_name, location, description)
+                configuration.addglobalVar(
+                    self.GetVarTypeObject(var_type), 
+                    var_name, location, description)
 
     # Replace the configuration globalvars by those given
     def SetConfigurationGlobalVars(self, name, vars):
@@ -1635,6 +1637,10 @@
             result = project.getpou(typename)
             if result is not None:
                 return result
+        for standardlibrary in [StdBlockLibrary, AddnlBlockLibrary]:
+            result = standardlibrary.getpou(typename)
+            if result is not None:
+                return result
         for confnodetype in self.ConfNodeTypes:
             result = confnodetype["types"].getpou(typename)
             if result is not None:
@@ -2410,21 +2416,36 @@
                     connection.setconnectionParameter(idx, None)
                 idx += 1
     
-    def AddEditedElementPouVar(self, tagname, type, name, location="", description=""):
+    def GetVarTypeObject(self, var_type):
+        var_type_obj = PLCOpenParser.CreateElement("type", "variable")
+        if not var_type.startswith("ANY") and TypeHierarchy.get(var_type):
+            var_type_obj.setcontent(PLCOpenParser.CreateElement(
+                var_type.lower() if var_type in ["STRING", "WSTRING"]
+                else var_type, "dataType"))
+        else:
+            derived_type = PLCOpenParser.CreateElement("derived", "dataType")
+            derived_type.setname(var_type)
+            var_type_obj.setcontent(derived_type)
+        return var_type_obj
+    
+    def AddEditedElementPouVar(self, tagname, var_type, name, location="", description=""):
         if self.Project is not None:
             words = tagname.split("::")
             if words[0] in ['P', 'T', 'A']:
                 pou = self.Project.getpou(words[1])
                 if pou is not None:
-                    pou.addpouLocalVar(type, name, location, description)
-    
-    def AddEditedElementPouExternalVar(self, tagname, type, name):
+                    pou.addpouLocalVar(
+                        self.GetVarTypeObject(var_type), 
+                        name, location, description)
+    
+    def AddEditedElementPouExternalVar(self, tagname, var_type, name):
         if self.Project is not None:
             words = tagname.split("::")
             if words[0] in ['P', 'T', 'A']:
                 pou = self.Project.getpou(words[1])
                 if pou is not None:
-                    pou.addpouExternalVar(type, name)
+                    pou.addpouExternalVar(
+                        self.GetVarTypeObject(var_type), name)
             
     def ChangeEditedElementPouVar(self, tagname, old_type, old_name, new_type, new_name):
         if self.Project is not None:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/Additional_Function_Blocks.xml	Tue Sep 10 23:10:58 2013 +0200
@@ -0,0 +1,522 @@
+<?xml version='1.0' encoding='utf-8'?>
+<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
+  <fileHeader companyName="Beremiz" productName="Additional Function Blocks Library" productVersion="1.0" creationDateTime="2013-09-09T09:56:11"/>
+  <contentHeader name="Standard Funtion Blocks" author="Laurent Bessard" modificationDateTime="2013-09-10T22:45:31">
+    <coordinateInfo>
+      <fbd>
+        <scaling x="0" y="0"/>
+      </fbd>
+      <ld>
+        <scaling x="0" y="0"/>
+      </ld>
+      <sfc>
+        <scaling x="0" y="0"/>
+      </sfc>
+    </coordinateInfo>
+  </contentHeader>
+  <types>
+    <dataTypes/>
+    <pous>
+      <pou name="RTC" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="IN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[0 - current time, 1 - load time from PDT]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PDT">
+              <type>
+                <DT/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Preset datetime]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[Copy of IN]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="CDT">
+              <type>
+                <DT/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Datetime, current or relative to PDT]]></xhtml:p>
+              </documentation>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="PREV_IN">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+            </variable>
+            <variable name="OFFSET">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+            <variable name="CURRENT_TIME">
+              <type>
+                <DT/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[{__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
+
+ IF IN
+ THEN
+   IF NOT PREV_IN
+   THEN
+       OFFSET := PDT - CURRENT_TIME;
+   END_IF;
+
+   (* PDT + time since PDT was loaded *)
+   CDT := CURRENT_TIME + OFFSET;
+ ELSE
+   CDT := CURRENT_TIME;
+ END_IF;
+
+ Q := IN;
+ PREV_IN := IN;
+]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="INTEGRAL" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="RUN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[1 = integrate, 0 = hold]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="R1">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Overriding reset]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="XIN">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Input variable]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="X0">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Initial value]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="CYCLE">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Sampling period]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[NOT R1]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="XOUT">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Integrated output]]></xhtml:p>
+              </documentation>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[Q := NOT R1 ;
+IF R1 THEN XOUT := X0;
+ELSIF RUN THEN XOUT := XOUT + XIN * TIME_TO_REAL(CYCLE);
+END_IF;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The integral function block integrates the value of input XIN over time.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="DERIVATIVE" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="RUN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[0 = reset]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="XIN">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Input to be differentiated]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="CYCLE">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Sampling period]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="XOUT">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Differentiated output]]></xhtml:p>
+              </documentation>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="X1">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+            <variable name="X2">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+            <variable name="X3">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[IF RUN THEN
+  XOUT := (3.0 * (XIN - X3) + X1 - X2)
+          / (10.0 * TIME_TO_REAL(CYCLE));
+  X3 := X2;
+  X2 := X1;
+  X1 := XIN;
+ELSE 
+  XOUT := 0.0;
+  X1 := XIN;
+  X2 := XIN;
+  X3 := XIN;
+END_IF;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The derivative function block produces an output XOUT proportional to the rate of change of the input XIN.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="PID" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="AUTO">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[0 - manual , 1 - automatic]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PV">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Process variable]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="SP">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Set point]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="X0">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Manual output adjustment - Typically from transfer station]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="KP">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Proportionality constant]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="TR">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Reset time]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="TD">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Derivative time constant]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="CYCLE">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Sampling period]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="XOUT">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="ERROR">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[PV - SP]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="ITERM">
+              <type>
+                <derived name="INTEGRAL"/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[FB for integral term]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="DTERM">
+              <type>
+                <derived name="DERIVATIVE"/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[FB for derivative term]]></xhtml:p>
+              </documentation>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[ERROR := PV - SP ;
+(*** Adjust ITERM so that XOUT := X0 when AUTO = 0 ***)
+ITERM(RUN := AUTO, R1 := NOT AUTO, XIN := ERROR,
+      X0 := TR * (X0 - ERROR), CYCLE := CYCLE);
+DTERM(RUN := AUTO, XIN := ERROR, CYCLE := CYCLE);
+XOUT := KP * (ERROR + ITERM.XOUT/TR + DTERM.XOUT*TD);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="RAMP" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="RUN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[0 - track X0, 1 - ramp to/track X1]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="X0">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+            <variable name="X1">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+            <variable name="TR">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Ramp duration]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="CYCLE">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Sampling period]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="BUSY">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[BUSY = 1 during ramping period]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="XOUT">
+              <type>
+                <REAL/>
+              </type>
+              <initialValue>
+                <simpleValue value="0.0"/>
+              </initialValue>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="XI">
+              <type>
+                <REAL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[Initial value]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="T0">
+              <type>
+                <TIME/>
+              </type>
+              <initialValue>
+                <simpleValue value="T#0s"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[Elapsed time of ramp]]></xhtml:p>
+              </documentation>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[BUSY := RUN ;
+IF RUN THEN
+  IF T >= TR THEN 
+    BUSY := 0;
+    XOUT := X1;
+  ELSE XOUT := XI + (X1-XI) * TIME_TO_REAL(T)
+                            / TIME_TO_REAL(TR);
+    T := T + CYCLE;
+  END_IF;
+ELSE
+  XOUT := X0;
+  XI := X0;
+  T := T#0s;
+END_IF;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The RAMP function block is modelled on example given in the standard.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="HYSTERESIS" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="XIN1">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+            <variable name="XIN2">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+            <variable name="EPS">
+              <type>
+                <REAL/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[IF Q THEN
+  IF XIN1 < (XIN2 - EPS) THEN 
+    Q := 0;
+  END_IF;
+ELSIF XIN1 > (XIN2 + EPS) THEN
+  Q := 1;
+END_IF;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2.]]></xhtml:p>
+        </documentation>
+      </pou>
+    </pous>
+  </types>
+  <instances>
+    <configurations/>
+  </instances>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/Standard_Function_Blocks.xml	Tue Sep 10 23:10:58 2013 +0200
@@ -0,0 +1,1469 @@
+<?xml version='1.0' encoding='utf-8'?>
+<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
+  <fileHeader companyName="Beremiz" productName="Standard Function Blocks Library" productVersion="1.0" creationDateTime="2013-09-09T09:56:11"/>
+  <contentHeader name="Standard Funtion Blocks" author="Laurent Bessard" modificationDateTime="2013-09-09T10:58:13">
+    <coordinateInfo>
+      <fbd>
+        <scaling x="0" y="0"/>
+      </fbd>
+      <ld>
+        <scaling x="0" y="0"/>
+      </ld>
+      <sfc>
+        <scaling x="0" y="0"/>
+      </sfc>
+    </coordinateInfo>
+  </contentHeader>
+  <types>
+    <dataTypes/>
+    <pous>
+      <pou name="SR" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="S1">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q1">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[Q1 := S1 OR ((NOT R) AND Q1);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The SR bistable is a latch where the Set dominates.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="RS" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="S">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R1">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q1">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[Q1 := (NOT R1) AND (S OR Q1);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The RS bistable is a latch where the Reset dominates.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="SEMA" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CLAIM">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="RELEASE">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="BUSY">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="Q_INTERNAL">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[Q_INTERNAL := CLAIM OR ( Q_INTERNAL AND (NOT RELEASE));
+BUSY := Q_INTERNAL;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="R_TRIG" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CLK">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars retain="true">
+            <variable name="M">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[Q := CLK AND NOT M;
+M := CLK;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The output produces a single pulse when a rising edge is detected.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="F_TRIG" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CLK">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars retain="true">
+            <variable name="M">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[Q := NOT CLK AND NOT M;
+M := NOT CLK;]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The output produces a single pulse when a falling edge is detected.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTU" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CU_T(CU);
+IF R THEN CV := 0;
+ELSIF CU_T.Q AND (CV < PV)
+  THEN CV := CV+1;
+END_IF;
+Q := (CV >= PV);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-counter can be used to signal when a count has reached a maximum value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTU_DINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <DINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <DINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CU_T(CU);
+IF R THEN CV := 0;
+ELSIF CU_T.Q AND (CV < PV)
+  THEN CV := CV+1;
+END_IF;
+Q := (CV >= PV);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-counter can be used to signal when a count has reached a maximum value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTU_LINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <LINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <LINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CU_T(CU);
+IF R THEN CV := 0;
+ELSIF CU_T.Q AND (CV < PV)
+  THEN CV := CV+1;
+END_IF;
+Q := (CV >= PV);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-counter can be used to signal when a count has reached a maximum value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTU_UDINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <UDINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <UDINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CU_T(CU);
+IF R THEN CV := 0;
+ELSIF CU_T.Q AND (CV < PV)
+  THEN CV := CV+1;
+END_IF;
+Q := (CV >= PV);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-counter can be used to signal when a count has reached a maximum value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTU_ULINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <ULINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <ULINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CU_T(CU);
+IF R THEN CV := 0;
+ELSIF CU_T.Q AND (CV < PV)
+  THEN CV := CV+1;
+END_IF;
+Q := (CV >= PV);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-counter can be used to signal when a count has reached a maximum value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTD" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+IF LD THEN CV := PV;
+ELSIF CD_T.Q AND (CV > 0)
+  THEN CV := CV-1;
+END_IF;
+Q := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The down-counter can be used to signal when a count has reached zero, on counting down from a preset value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTD_DINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <DINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <DINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+IF LD THEN CV := PV;
+ELSIF CD_T.Q AND (CV > 0)
+  THEN CV := CV-1;
+END_IF;
+Q := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The down-counter can be used to signal when a count has reached zero, on counting down from a preset value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTD_LINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <LINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <LINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+IF LD THEN CV := PV;
+ELSIF CD_T.Q AND (CV > 0)
+  THEN CV := CV-1;
+END_IF;
+Q := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The down-counter can be used to signal when a count has reached zero, on counting down from a preset value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTD_UDINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <UDINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <UDINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+IF LD THEN CV := PV;
+ELSIF CD_T.Q AND (CV > 0)
+  THEN CV := CV-1;
+END_IF;
+Q := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The down-counter can be used to signal when a count has reached zero, on counting down from a preset value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTD_ULINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <ULINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <ULINT/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+IF LD THEN CV := PV;
+ELSIF CD_T.Q AND (CV > 0)
+  THEN CV := CV-1;
+END_IF;
+Q := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The down-counter can be used to signal when a count has reached zero, on counting down from a preset value.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTUD" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="QU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="QD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <INT/>
+              </type>
+            </variable>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+CU_T(CU);
+IF R THEN CV := 0;
+ELSIF LD THEN CV := PV;
+ELSE
+  IF NOT (CU_T.Q AND CD_T.Q) THEN
+    IF CU_T.Q AND (CV < PV)
+    THEN CV := CV+1;
+    ELSIF CD_T.Q AND (CV > 0)
+    THEN CV := CV-1;
+    END_IF;
+  END_IF;
+END_IF;
+QU := (CV >= PV);
+QD := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTUD_DINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <DINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="QU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="QD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <DINT/>
+              </type>
+            </variable>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+CU_T(CU);
+IF R THEN CV := 0;
+ELSIF LD THEN CV := PV;
+ELSE
+  IF NOT (CU_T.Q AND CD_T.Q) THEN
+    IF CU_T.Q AND (CV < PV)
+    THEN CV := CV+1;
+    ELSIF CD_T.Q AND (CV > 0)
+    THEN CV := CV-1;
+    END_IF;
+  END_IF;
+END_IF;
+QU := (CV >= PV);
+QD := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTUD_LINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <LINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="QU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="QD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <LINT/>
+              </type>
+            </variable>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+CU_T(CU);
+IF R THEN CV := 0;
+ELSIF LD THEN CV := PV;
+ELSE
+  IF NOT (CU_T.Q AND CD_T.Q) THEN
+    IF CU_T.Q AND (CV < PV)
+    THEN CV := CV+1;
+    ELSIF CD_T.Q AND (CV > 0)
+    THEN CV := CV-1;
+    END_IF;
+  END_IF;
+END_IF;
+QU := (CV >= PV);
+QD := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTUD_UDINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <UDINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="QU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="QD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <UDINT/>
+              </type>
+            </variable>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+CU_T(CU);
+IF R THEN CV := 0;
+ELSIF LD THEN CV := PV;
+ELSE
+  IF NOT (CU_T.Q AND CD_T.Q) THEN
+    IF CU_T.Q AND (CV < PV)
+    THEN CV := CV+1;
+    ELSIF CD_T.Q AND (CV > 0)
+    THEN CV := CV-1;
+    END_IF;
+  END_IF;
+END_IF;
+QU := (CV >= PV);
+QD := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="CTUD_ULINT" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="CU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="R">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="LD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="PV">
+              <type>
+                <ULINT/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="QU">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="QD">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CV">
+              <type>
+                <ULINT/>
+              </type>
+            </variable>
+            <variable name="CD_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+            <variable name="CU_T">
+              <type>
+                <derived name="R_TRIG"/>
+              </type>
+            </variable>
+          </outputVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[CD_T(CD);
+CU_T(CU);
+IF R THEN CV := 0;
+ELSIF LD THEN CV := PV;
+ELSE
+  IF NOT (CU_T.Q AND CD_T.Q) THEN
+    IF CU_T.Q AND (CV < PV)
+    THEN CV := CV+1;
+    ELSIF CD_T.Q AND (CV > 0)
+    THEN CV := CV-1;
+    END_IF;
+  END_IF;
+END_IF;
+QU := (CV >= PV);
+QD := (CV <= 0);]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="TP" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="IN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[first input parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PT">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[second input parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[first output parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="ET">
+              <type>
+                <TIME/>
+              </type>
+              <initialValue>
+                <simpleValue value="T#0s"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[second output parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="STATE">
+              <type>
+                <SINT/>
+              </type>
+              <initialValue>
+                <simpleValue value="0"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[internal state: 0-reset, 1-counting, 2-set]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PREV_IN">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+            </variable>
+            <variable name="CURRENT_TIME">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+            <variable name="START_TIME">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[{__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
+
+IF ((STATE = 0) AND NOT(PREV_IN) AND IN)   (* found rising edge on IN *)
+THEN
+  (* start timer... *)
+  STATE := 1;
+  Q := TRUE;
+  START_TIME := CURRENT_TIME;
+
+ELSIF (STATE = 1)
+THEN
+  IF ((START_TIME + PT) <= CURRENT_TIME)
+  THEN
+    STATE := 2;
+    Q := FALSE;
+    ET := PT;
+  ELSE
+    ET := CURRENT_TIME - START_TIME;
+  END_IF;
+END_IF;
+
+IF ((STATE = 2) AND NOT(IN))
+THEN
+  ET := T#0s;
+  STATE := 0;
+END_IF;
+
+PREV_IN := IN;
+]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The pulse timer can be used to generate output pulses of a given time duration.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="TON" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="IN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[first input parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PT">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[second input parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[first output parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="ET">
+              <type>
+                <TIME/>
+              </type>
+              <initialValue>
+                <simpleValue value="T#0s"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[second output parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="STATE">
+              <type>
+                <SINT/>
+              </type>
+              <initialValue>
+                <simpleValue value="0"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[internal state: 0-reset, 1-counting, 2-set]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PREV_IN">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+            </variable>
+            <variable name="CURRENT_TIME">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+            <variable name="START_TIME">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[{__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
+
+IF ((STATE = 0) AND NOT(PREV_IN) AND IN)   (* found rising edge on IN *)
+THEN
+  (* start timer... *)
+  STATE := 1;
+  Q := FALSE;
+  START_TIME := CURRENT_TIME;
+
+ELSE
+  (* STATE is 1 or 2 !! *)
+  IF (NOT(IN))
+  THEN
+    ET := T#0s;
+    Q := FALSE;
+    STATE := 0;
+
+  ELSIF (STATE = 1)
+  THEN
+    IF ((START_TIME + PT) <= CURRENT_TIME)
+    THEN
+      STATE := 2;
+      Q := TRUE;
+      ET := PT;
+    ELSE
+      ET := CURRENT_TIME - START_TIME;
+    END_IF;
+  END_IF;
+
+END_IF;
+
+PREV_IN := IN;
+]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true.]]></xhtml:p>
+        </documentation>
+      </pou>
+      <pou name="TOF" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="IN">
+              <type>
+                <BOOL/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[first input parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PT">
+              <type>
+                <TIME/>
+              </type>
+              <documentation>
+                <xhtml:p><![CDATA[second input parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="Q">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[first output parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="ET">
+              <type>
+                <TIME/>
+              </type>
+              <initialValue>
+                <simpleValue value="T#0s"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[second output parameter]]></xhtml:p>
+              </documentation>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="STATE">
+              <type>
+                <SINT/>
+              </type>
+              <initialValue>
+                <simpleValue value="0"/>
+              </initialValue>
+              <documentation>
+                <xhtml:p><![CDATA[internal state: 0-reset, 1-counting, 2-set]]></xhtml:p>
+              </documentation>
+            </variable>
+            <variable name="PREV_IN">
+              <type>
+                <BOOL/>
+              </type>
+              <initialValue>
+                <simpleValue value="FALSE"/>
+              </initialValue>
+            </variable>
+            <variable name="CURRENT_TIME">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+            <variable name="START_TIME">
+              <type>
+                <TIME/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+            <xhtml:p><![CDATA[{__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
+
+IF ((STATE = 0) AND PREV_IN AND NOT(IN))   (* found falling edge on IN *)
+THEN
+  (* start timer... *)
+  STATE := 1;
+  START_TIME := CURRENT_TIME;
+
+ELSE
+  (* STATE is 1 or 2 !! *)
+  IF (IN)
+  THEN
+    ET := T#0s;
+    STATE := 0;
+
+  ELSIF (STATE = 1)
+  THEN
+    IF ((START_TIME + PT) <= CURRENT_TIME)
+    THEN
+      STATE := 2;
+      ET := PT;
+    ELSE
+      ET := CURRENT_TIME - START_TIME;
+    END_IF;
+  END_IF;
+
+END_IF;
+
+Q := IN OR (STATE = 1);
+PREV_IN := IN;
+]]></xhtml:p>
+          </ST>
+        </body>
+        <documentation>
+          <xhtml:p><![CDATA[The off-delay timer can be used to delay setting an output false, for fixed period after input goes false.]]></xhtml:p>
+        </documentation>
+      </pou>
+    </pous>
+  </types>
+  <instances>
+    <configurations/>
+  </instances>
+</project>
--- a/plcopen/plcopen.py	Tue Sep 10 10:37:42 2013 +0200
+++ b/plcopen/plcopen.py	Tue Sep 10 23:10:58 2013 +0200
@@ -23,7 +23,6 @@
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from xmlclass import *
-from structures import *
 from types import *
 import os, re
 from lxml import etree
@@ -296,16 +295,13 @@
     def setcontentHeader(self, contentheader):
         contentheader_obj = self.contentHeader
         for attr, value in contentheader.iteritems():
-            if attr == "projectName":
-                contentheader_obj.setname(value)
-            elif attr == "projectVersion":
-                contentheader_obj.setversion(value)
-            elif attr == "authorName":
-                contentheader_obj.setauthor(value)
-            elif attr == "pageSize":
-                contentheader_obj.setpageSize(*contentheader["pageSize"])
-            elif attr == "scaling":
-                contentheader_obj.setscaling(contentheader["scaling"])
+            func = {"projectName": contentheader_obj.setname,
+                    "projectVersion": contentheader_obj.setversion,
+                    "authorName": contentheader_obj.setauthor,
+                    "pageSize": lambda v: contentheader_obj.setpageSize(*v),
+                    "scaling": contentheader_obj.setscaling}.get(attr)
+            if func is not None:
+                func(value)
             elif attr in ["modificationDateTime", "organization", "language"]:
                 setattr(contentheader_obj, attr, value)
     setattr(cls, "setcontentHeader", setcontentHeader)
@@ -607,16 +603,7 @@
             globalvars.append(PLCOpenParser.CreateElement("varList"))
         var = PLCOpenParser.CreateElement("variable", "varListPlain")
         var.setname(name)
-        var_type_obj = PLCOpenParser.CreateElement("dataType")
-        if not var_type.startswith("ANY") and TypeHierarchy.get(var_type):
-            var_type_obj.setcontent(PLCOpenParser.CreateElement(
-                var_type.lower() if var_type in ["STRING", "WSTRING"]
-                else vartype, "dataType"))
-        else:
-            derived_type = PLCOpenParser.CreateElement("derived", "dataType")
-            derived_type.setname(var_type)
-            var_type_obj.setcontent(derived_type)
-        var.settype(var_type_obj)
+        var.settype(var_type)
         if location != "":
             var.setaddress(location)
         if description != "":
@@ -1164,16 +1151,7 @@
                 content[-1].addnext(varlist)
         var = PLCOpenParser.CreateElement("variable", "varListPlain")
         var.setname(name)
-        var_type_obj = PLCOpenParser.CreateElement("type", "variable")
-        if not var_type.startswith("ANY") and TypeHierarchy.get(var_type):
-            var_type_obj.setcontent(PLCOpenParser.CreateElement(
-                var_type.lower() if var_type in ["STRING", "WSTRING"]
-                else var_type, "dataType"))
-        else:
-            derived_type = PLCOpenParser.CreateElement("derived", "dataType")
-            derived_type.setname(var_type)
-            var_type_obj.setcontent(derived_type)
-        var.settype(var_type_obj)
+        var.settype(var_type)
         if location != "":
             var.setaddress(location)
         if description != "":
--- a/plcopen/structures.py	Tue Sep 10 10:37:42 2013 +0200
+++ b/plcopen/structures.py	Tue Sep 10 23:10:58 2013 +0200
@@ -23,6 +23,7 @@
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 import string, os, sys, re
+from plcopen import LoadProject
 
 LANGUAGES = ["IL","ST","FBD","LD","SFC"]
 
@@ -38,6 +39,44 @@
 #                        Function Block Types definitions
 #-------------------------------------------------------------------------------
 
+ScriptDirectory = os.path.split(os.path.realpath(__file__))[0]
+
+StdBlockLibrary = LoadProject(os.path.join(ScriptDirectory, "Standard_Function_Blocks.xml"))
+AddnlBlockLibrary = LoadProject(os.path.join(ScriptDirectory, "Additional_Function_Blocks.xml"))
+
+StdBlockComments = {
+    "SR": _("SR bistable\nThe SR bistable is a latch where the Set dominates."),
+    "RS": _("RS bistable\nThe RS bistable is a latch where the Reset dominates."),
+    "SEMA": _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."),
+    "R_TRIG": _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected."),
+    "F_TRIG": _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected."),
+    "CTU": _("Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value."),
+    "CTD": _("Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value."),
+    "CTUD": _("Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other."),
+    "TP": _("Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration."),
+    "TON": _("On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true."),
+    "TOF": _("Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false."),
+    "RTC": _("Real time clock\nThe real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on."),
+    "INTEGRAL": _("Integral\nThe integral function block integrates the value of input XIN over time."),
+    "DERIVATIVE": _("Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN."),
+    "PID": _("PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."),
+    "RAMP": _("Ramp\nThe RAMP function block is modelled on example given in the standard."),
+    "HYSTERESIS": _("Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."),
+}
+
+for block_type in ["CTU", "CTD", "CTUD"]:
+    for return_type in ["DINT", "LINT", "UDINT", "ULINT"]:
+        StdBlockComments["%s_%s" % (block_type, return_type)] = StdBlockComments[block_type]
+
+def GetBlockInfos(pou):
+    infos = pou.getblockInfos()
+    infos["comment"] = StdBlockComments[infos["name"]]
+    infos["inputs"] = [
+        (var_name, var_type, "rising")
+        if var_name in ["CU", "CD"]
+        else (var_name, var_type, var_modifier)
+        for var_name, var_type, var_modifier in infos["inputs"]]
+    return infos
 
 """
 Ordored list of common Function Blocks defined in the IEC 61131-3
@@ -56,81 +95,9 @@
 """
 
 StdBlckLst = [{"name" : _("Standard function blocks"), "list":
-               [{"name" : "SR", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], 
-                    "outputs" : [("Q1","BOOL","none")],
-                    "comment" : _("SR bistable\nThe SR bistable is a latch where the Set dominates.")},
-                {"name" : "RS", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("S","BOOL","none"),("R1","BOOL","none")], 
-                    "outputs" : [("Q1","BOOL","none")],
-                    "comment" : _("RS bistable\nThe RS bistable is a latch where the Reset dominates.")},
-                {"name" : "SEMA", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("CLAIM","BOOL","none"),("RELEASE","BOOL","none")], 
-                    "outputs" : [("BUSY","BOOL","none")],
-                    "comment" : _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources.")},
-                {"name" : "R_TRIG", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("CLK","BOOL","none")], 
-                    "outputs" : [("Q","BOOL","none")],
-                    "comment" : _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected.")},
-                {"name" : "F_TRIG", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("CLK","BOOL","none")], 
-                    "outputs" : [("Q","BOOL","none")],
-                    "comment" : _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected.")},
-                {"name" : "CTU", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("CU","BOOL","rising"),("R","BOOL","none"),("PV","INT","none")], 
-                    "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
-                    "comment" : _("Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value.")},
-                {"name" : "CTD", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("CD","BOOL","rising"),("LD","BOOL","none"),("PV","INT","none")], 
-                    "outputs" : [("Q","BOOL","none"),("CV","INT","none")],
-                    "comment" : _("Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value.")},
-                {"name" : "CTUD", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("CU","BOOL","rising"),("CD","BOOL","rising"),("R","BOOL","none"),("LD","BOOL","none"),("PV","INT","none")], 
-                    "outputs" : [("QU","BOOL","none"),("QD","BOOL","none"),("CV","INT","none")],
-                    "comment" : _("Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other.")},
-                {"name" : "TP", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
-                    "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
-                    "comment" : _("Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration.")},
-                {"name" : "TON", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
-                    "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
-                    "comment" : _("On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true.")},
-                {"name" : "TOF", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], 
-                    "outputs" : [("Q","BOOL","none"),("ET","TIME","none")],
-                    "comment" : _("Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false.")},
-                ]},
+               [GetBlockInfos(pou) for pou in StdBlockLibrary.getpous()]},
               {"name" : _("Additional function blocks"), "list":
-               [{"name" : "RTC", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("IN","BOOL","none"),("PDT","DATE_AND_TIME","none")], 
-                    "outputs" : [("Q","BOOL","none"),("CDT","DATE_AND_TIME","none")],
-                    "comment" : _("Real time clock\nThe real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on.")},
-                {"name" : "INTEGRAL", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("RUN","BOOL","none"),("R1","BOOL","none"),("XIN","REAL","none"),("X0","REAL","none"),("CYCLE","TIME","none")], 
-                    "outputs" : [("Q","BOOL","none"),("XOUT","REAL","none")],
-                    "comment" : _("Integral\nThe integral function block integrates the value of input XIN over time.")},
-                {"name" : "DERIVATIVE", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("RUN","BOOL","none"),("XIN","REAL","none"),("CYCLE","TIME","none")], 
-                    "outputs" : [("XOUT","REAL","none")],
-                    "comment" : _("Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN.")},
-                {"name" : "PID", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("AUTO","BOOL","none"),("PV","REAL","none"),("SP","REAL","none"),("X0","REAL","none"),("KP","REAL","none"),("TR","REAL","none"),("TD","REAL","none"),("CYCLE","TIME","none")], 
-                    "outputs" : [("XOUT","REAL","none")],
-                    "comment" : _("PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control.")},
-                {"name" : "RAMP", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("RUN","BOOL","none"),("X0","REAL","none"),("X1","REAL","none"),("TR","TIME","none"),("CYCLE","TIME","none")], 
-                    "outputs" : [("BUSY","BOOL","none"),("XOUT","REAL","none")],
-                    "comment" : _("Ramp\nThe RAMP function block is modelled on example given in the standard.")},
-                {"name" : "HYSTERESIS", "type" : "functionBlock", "extensible" : False, 
-                    "inputs" : [("XIN1","REAL","none"),("XIN2","REAL","none"),("EPS","REAL","none")], 
-                    "outputs" : [("Q","BOOL","none")],
-                    "comment" : _("Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2.")},
-##                {"name" : "RATIO_MONITOR", "type" : "functionBlock", "extensible" : False, 
-##                    "inputs" : [("PV1","REAL","none"),("PV2","REAL","none"),("RATIO","REAL","none"),("TIMON","TIME","none"),("TIMOFF","TIME","none"),("TOLERANCE","BOOL","none"),("RESET","BOOL","none"),("CYCLE","TIME","none")], 
-##                    "outputs" : [("ALARM","BOOL","none"),("TOTAL_ERR","BOOL","none")],
-##                    "comment" : _("Ratio monitor\nThe ratio_monitor function block checks that one process value PV1 is always a given ratio (defined by input RATIO) of a second process value PV2.")}
-                ]},
+               [GetBlockInfos(pou) for pou in AddnlBlockLibrary.getpous()]},
              ]
 
 
@@ -446,7 +413,7 @@
     
     return Standard_Functions_Decl
 
-std_decl = get_standard_funtions(csv_file_to_table(open(os.path.join(os.path.split(__file__)[0],"iec_std.csv"))))#, True)
+std_decl = get_standard_funtions(csv_file_to_table(open(os.path.join(ScriptDirectory,"iec_std.csv"))))#, True)
 
 StdBlckLst.extend(std_decl)
 
@@ -458,12 +425,11 @@
         words = desc["comment"].split('"')
         if len(words) > 1:
             desc["comment"] = words[1]
-        desc["usage"] = (
-            "\n (" +
-            str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in desc["inputs"]]).strip("[]").replace("'",'') +
-            " ) => (" +
-            str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in desc["outputs"]]).strip("[]").replace("'",'') +
-            " )")
+        desc["usage"] = ("\n (%s) => (%s)" % 
+            (", ".join(["%s:%s" % (input[1], input[0]) 
+                        for input in desc["inputs"]]),
+             ", ".join(["%s:%s" % (output[1], output[0]) 
+                        for output in desc["outputs"]])))
         BlkLst = StdBlckDct.setdefault(desc["name"],[])
         BlkLst.append((section["name"], desc))