etisserant@0: (*
msousa@277:  *  This file is part of matiec - a compiler for the programming
msousa@277:  *  languages defined in IEC 61131-3
msousa@277:  *
msousa@277:  *  Copyright (C) 2011  Mario de Sousa (msousa@fe.up.pt)
msousa@277:  *
msousa@277:  * See COPYING and COPYING.LESSER files for copyright details.
msousa@277:  * This library is free software; you can redistribute it and/or
msousa@277:  * modify it under the terms of the GNU Lesser General Public
msousa@277:  * License as published by the Free Software Foundation; either
msousa@277:  * version 3 of the License, or (at your option) any later version.
msousa@277:  *
msousa@277:  * This library is distributed in the hope that it will be useful,
msousa@277:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
msousa@277:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
msousa@277:  * Lesser General Public License for more details.
msousa@277:  * 
msousa@277:  * You should have received a copy of the GNU Lesser General Public
msousa@277:  * License along with this library; if not, write to the Free Software
msousa@277:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
msousa@277:  * USA
etisserant@0:  *
etisserant@0:  * This code is made available on the understanding that it will not be
etisserant@0:  * used in safety-critical situations without a full and competent review.
etisserant@0:  *)
etisserant@0: 
etisserant@0: (*
msousa@276:  * An IEC 61131-3 compiler.
etisserant@0:  *
etisserant@0:  * Based on the
etisserant@0:  * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
etisserant@0:  *
etisserant@0:  *)
etisserant@0: 
etisserant@0: (*
etisserant@0:  * This is part of the library conatining the functions
etisserant@0:  * and function blocks defined in the standard.
etisserant@0:  *
etisserant@0:  * Timer Function Blocks
etisserant@0:  * ---------------------
etisserant@0:  *
msousa@276:  * NOTE: The timing diagrams in the comments (except the state variable) 
msousa@276:  *       were taken from the IEC 61131-3 standard.
etisserant@0:  *)
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: (****************************************************************
etisserant@0: 
etisserant@0:                   TP - pulse timing - state machine
etisserant@0: 
etisserant@0: 
etisserant@0:             +--------+     ++ ++   +--------+
etisserant@0:        IN   |        |     || ||   |        |
etisserant@0:           --+        +-----++-++---+        +---------
etisserant@0:             t0       t1    t2 t3    t4       t5
etisserant@0:             +----+         +----+  +----+
etisserant@0:        Q    |    |         |    |  |    |
etisserant@0:           --+    +---------+    +--+    +-------------
etisserant@0:             t0   t0+PT    t2 t2+PT t4  t4+PT
etisserant@0:          PT      +---+          +       +---+
etisserant@0:           :     /    |         /|      /    |
etisserant@0:        ET :    /     |        / |     /     |
etisserant@0:           :   /      |       /  |    /      |
etisserant@0:           :  /       |      /   |   /       |
etisserant@0:           0-+        +-----+    +--+        +---------
etisserant@0:             t0       t1    t2      t4       t5
etisserant@0: 
etisserant@0: 
etisserant@0:         2        +---+          +       +---+
etisserant@0: STATE   1   +----+   |     +----|  +----+   | 
etisserant@0:         0 --+        +-----+    +--+        +---------
etisserant@0: 
etisserant@0: 
etisserant@0: ****************************************************************)
etisserant@0: 
etisserant@0: FUNCTION_BLOCK TP
etisserant@0:   VAR_INPUT
etisserant@0:     IN : BOOL;  (* first input parameter *)
etisserant@0:     PT : TIME;  (* second input parameter *)
etisserant@0:   END_VAR
etisserant@0:   VAR_OUTPUT
etisserant@0:     Q : BOOL := FALSE;  (* first output parameter *)
etisserant@0:     ET : TIME := T#0s;  (* second output parameter *)
etisserant@0:   END_VAR
etisserant@0: 
etisserant@0:   VAR
etisserant@0:     STATE : SINT := 0;  (* internal state: 0-reset, 1-counting, 2-set *)
etisserant@0:     PREV_IN : BOOL := FALSE;
etisserant@0:     CURRENT_TIME, START_TIME : TIME;
etisserant@0:   END_VAR
etisserant@0: 
laurent@392:   {__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
etisserant@0: 
etisserant@0:   IF ((STATE = 0) AND NOT(PREV_IN) AND IN)   (* found rising edge on IN *)
etisserant@0:   THEN
etisserant@0:     (* start timer... *)
etisserant@0:     STATE := 1;
etisserant@0:     Q := TRUE;
etisserant@0:     START_TIME := CURRENT_TIME;
etisserant@0: 
etisserant@0:   ELSIF (STATE = 1)
etisserant@0:   THEN
etisserant@0:     IF ((START_TIME + PT) <= CURRENT_TIME)
etisserant@0:     THEN
etisserant@0:       STATE := 2;
etisserant@0:       Q := FALSE;
etisserant@0:       ET := PT;
etisserant@0:     ELSE
etisserant@0:       ET := CURRENT_TIME - START_TIME;
etisserant@0:     END_IF;
etisserant@0:   END_IF;
etisserant@0: 
etisserant@0:   IF ((STATE = 2) AND NOT(IN))
etisserant@0:   THEN
etisserant@0:     ET := T#0s;
etisserant@0:     STATE := 0;
etisserant@0:   END_IF;
etisserant@0: 
etisserant@0: 
etisserant@0:   PREV_IN := IN;
etisserant@0: 
etisserant@0: END_FUNCTION_BLOCK
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: (****************************************************************
etisserant@0: 
etisserant@0:              TON - On-delay timing - state machine
etisserant@0: 
etisserant@0: 
etisserant@0:             +--------+        +---+   +--------+
etisserant@0:        IN   |        |        |   |   |        |
etisserant@0:           --+        +--------+   +---+        +-------------
etisserant@0:             t0       t1       t2  t3  t4       t5
etisserant@0:                  +---+                     +---+
etisserant@0:        Q         |   |                     |   |
etisserant@0:           -------+   +---------------------+   +-------------
etisserant@0:               t0+PT  t1                t4+PT   t5
etisserant@0:          PT      +---+                     +---+
etisserant@0:           :     /    |            +       /    |
etisserant@0:        ET :    /     |           /|      /     |
etisserant@0:           :   /      |          / |     /      |
etisserant@0:           :  /       |         /  |    /       |
etisserant@0:           0-+        +--------+   +---+        +-------------
etisserant@0:             t0       t1       t2  t3  t4       t5
etisserant@0: 
etisserant@0: 
etisserant@0:         2        +---+                     +---+
etisserant@0: STATE   1   +----+   |        +---+   +----+   |
etisserant@0:         0 --+        +--------+   +---+        +------
etisserant@0: 
etisserant@0: 
etisserant@0: ****************************************************************)
etisserant@0: 
etisserant@0: 
etisserant@0: FUNCTION_BLOCK TON
etisserant@0:   VAR_INPUT
etisserant@0:     IN : BOOL;  (* first input parameter *)
etisserant@0:     PT : TIME;  (* second input parameter *)
etisserant@0:   END_VAR
etisserant@0:   VAR_OUTPUT
etisserant@0:     Q : BOOL := FALSE;  (* first output parameter *)
etisserant@0:     ET : TIME := T#0s;  (* second output parameter *)
etisserant@0:   END_VAR
etisserant@0: 
etisserant@0:   VAR
etisserant@0:     STATE : SINT := 0;  (* internal state: 0-reset, 1-counting, 2-set *)
etisserant@0:     PREV_IN : BOOL := FALSE;
etisserant@0:     CURRENT_TIME, START_TIME : TIME;
etisserant@0:   END_VAR
etisserant@0: 
laurent@392:   {__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
etisserant@0: 
etisserant@0:   IF ((STATE = 0) AND NOT(PREV_IN) AND IN)   (* found rising edge on IN *)
etisserant@0:   THEN
etisserant@0:     (* start timer... *)
etisserant@0:     STATE := 1;
etisserant@0:     Q := FALSE;
etisserant@0:     START_TIME := CURRENT_TIME;
etisserant@0: 
etisserant@0:   ELSE
etisserant@0:     (* STATE is 1 or 2 !! *)
etisserant@0:     IF (NOT(IN))
etisserant@0:     THEN
etisserant@0:       ET := T#0s;
etisserant@0:       Q := FALSE;
etisserant@0:       STATE := 0;
etisserant@0: 
etisserant@0:     ELSIF (STATE = 1)
etisserant@0:     THEN
etisserant@0:       IF ((START_TIME + PT) <= CURRENT_TIME)
etisserant@0:       THEN
etisserant@0:         STATE := 2;
etisserant@0:         Q := TRUE;
etisserant@0:         ET := PT;
etisserant@0:       ELSE
etisserant@0:         ET := CURRENT_TIME - START_TIME;
etisserant@0:       END_IF;
etisserant@0:     END_IF;
etisserant@0: 
etisserant@0:   END_IF;
etisserant@0: 
etisserant@0:   PREV_IN := IN;
etisserant@0: 
etisserant@0: END_FUNCTION_BLOCK
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: (****************************************************************
etisserant@0: 
etisserant@113:              TOF - Off-delay timing - state machine
etisserant@0: 
etisserant@0: 
etisserant@0:               +--------+        +---+   +--------+
etisserant@0:        IN     |        |        |   |   |        |
etisserant@0:            ---+        +--------+   +---+        +-----------
etisserant@0:               t0       t1       t2  t3  t4       t5
etisserant@0:               +-------------+   +---------------------+
etisserant@0:        Q      |             |   |                     |
etisserant@0:            ---+             +---+                     +------
etisserant@0:               t0          t1+PT t2                  t5+PT
etisserant@0:          PT                 +---+                     +------
etisserant@0:           :                /    |       +            /
etisserant@0:        ET :               /     |      /|           /
etisserant@0:           :              /      |     / |          /
etisserant@0:           :             /       |    /  |         /
etisserant@0:           0------------+        +---+   +--------+
etisserant@0:                        t1           t3           t5
etisserant@0: 
etisserant@0: 
etisserant@0:         2                   +---+                     +------
etisserant@0: STATE   1              +----+   |   +---+        +----+
etisserant@0:         0 -------------+        +---+   +--------+
etisserant@0: 
etisserant@0: 
etisserant@0: ****************************************************************)
etisserant@0: 
etisserant@113: FUNCTION_BLOCK TOF
etisserant@0:   VAR_INPUT
etisserant@0:     IN : BOOL;  (* first input parameter *)
etisserant@0:     PT : TIME;  (* second input parameter *)
etisserant@0:   END_VAR
etisserant@0:   VAR_OUTPUT
etisserant@0:     Q : BOOL := FALSE;  (* first output parameter *)
etisserant@0:     ET : TIME := T#0s;  (* second output parameter *)
etisserant@0:   END_VAR
etisserant@0: 
etisserant@0:   VAR
etisserant@0:     STATE : SINT := 0;  (* internal state: 0-reset, 1-counting, 2-set *)
etisserant@0:     PREV_IN : BOOL := FALSE;
etisserant@0:     CURRENT_TIME, START_TIME : TIME;
etisserant@0:   END_VAR
etisserant@0: 
laurent@392:   {__SET_VAR(data__->,CURRENT_TIME,__CURRENT_TIME)}
etisserant@0: 
etisserant@0:   IF ((STATE = 0) AND PREV_IN AND NOT(IN))   (* found falling edge on IN *)
etisserant@0:   THEN
etisserant@0:     (* start timer... *)
etisserant@0:     STATE := 1;
etisserant@0:     START_TIME := CURRENT_TIME;
etisserant@0: 
etisserant@0:   ELSE
etisserant@0:     (* STATE is 1 or 2 !! *)
etisserant@0:     IF (IN)
etisserant@0:     THEN
etisserant@0:       ET := T#0s;
etisserant@0:       STATE := 0;
etisserant@0: 
etisserant@0:     ELSIF (STATE = 1)
etisserant@0:     THEN
etisserant@0:       IF ((START_TIME + PT) <= CURRENT_TIME)
etisserant@0:       THEN
etisserant@0:         STATE := 2;
etisserant@0:         ET := PT;
etisserant@0:       ELSE
etisserant@0:         ET := CURRENT_TIME - START_TIME;
etisserant@0:       END_IF;
etisserant@0:     END_IF;
etisserant@0: 
etisserant@0:   END_IF;
etisserant@0: 
etisserant@0:   Q := IN OR (STATE = 1);
etisserant@0:   PREV_IN := IN;
etisserant@0: 
etisserant@0: END_FUNCTION_BLOCK
etisserant@0: