(*
 *  This file is part of matiec - a compiler for the programming
 *  languages defined in IEC 61131-3
 *
 *  Copyright (C) 2011  Mario de Sousa (msousa@fe.up.pt)
 *
 * See COPYING and COPYING.LESSER files for copyright details.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * This code is made available on the understanding that it will not be
 * used in safety-critical situations without a full and competent review.
 *)

(*
 * An IEC 61131-3 compiler.
 *
 * Based on the
 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
 *
 *)

(*
 * This is part of the library conatining the functions
 * and function blocks defined in the standard.
 *
 * Timer Function Blocks
 * ---------------------
 *
 * NOTE: The timing diagrams in the comments (except the state variable) 
 *       were taken from the IEC 61131-3 standard.
 *)



(****************************************************************

                  TP - pulse timing - state machine


            +--------+     ++ ++   +--------+
       IN   |        |     || ||   |        |
          --+        +-----++-++---+        +---------
            t0       t1    t2 t3    t4       t5
            +----+         +----+  +----+
       Q    |    |         |    |  |    |
          --+    +---------+    +--+    +-------------
            t0   t0+PT    t2 t2+PT t4  t4+PT
         PT      +---+          +       +---+
          :     /    |         /|      /    |
       ET :    /     |        / |     /     |
          :   /      |       /  |    /      |
          :  /       |      /   |   /       |
          0-+        +-----+    +--+        +---------
            t0       t1    t2      t4       t5


        2        +---+          +       +---+
STATE   1   +----+   |     +----|  +----+   | 
        0 --+        +-----+    +--+        +---------


****************************************************************)

FUNCTION_BLOCK TP
  VAR_INPUT
    IN : BOOL;  (* first input parameter *)
    PT : TIME;  (* second input parameter *)
  END_VAR
  VAR_OUTPUT
    Q : BOOL := FALSE;  (* first output parameter *)
    ET : TIME := T#0s;  (* second output parameter *)
  END_VAR

  VAR
    STATE : SINT := 0;  (* internal state: 0-reset, 1-counting, 2-set *)
    PREV_IN : BOOL := FALSE;
    CURRENT_TIME, START_TIME : TIME;
  END_VAR

  {__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;

END_FUNCTION_BLOCK




(****************************************************************

             TON - On-delay timing - state machine


            +--------+        +---+   +--------+
       IN   |        |        |   |   |        |
          --+        +--------+   +---+        +-------------
            t0       t1       t2  t3  t4       t5
                 +---+                     +---+
       Q         |   |                     |   |
          -------+   +---------------------+   +-------------
              t0+PT  t1                t4+PT   t5
         PT      +---+                     +---+
          :     /    |            +       /    |
       ET :    /     |           /|      /     |
          :   /      |          / |     /      |
          :  /       |         /  |    /       |
          0-+        +--------+   +---+        +-------------
            t0       t1       t2  t3  t4       t5


        2        +---+                     +---+
STATE   1   +----+   |        +---+   +----+   |
        0 --+        +--------+   +---+        +------


****************************************************************)


FUNCTION_BLOCK TON
  VAR_INPUT
    IN : BOOL;  (* first input parameter *)
    PT : TIME;  (* second input parameter *)
  END_VAR
  VAR_OUTPUT
    Q : BOOL := FALSE;  (* first output parameter *)
    ET : TIME := T#0s;  (* second output parameter *)
  END_VAR

  VAR
    STATE : SINT := 0;  (* internal state: 0-reset, 1-counting, 2-set *)
    PREV_IN : BOOL := FALSE;
    CURRENT_TIME, START_TIME : TIME;
  END_VAR

  {__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;

END_FUNCTION_BLOCK





(****************************************************************

             TOF - Off-delay timing - state machine


              +--------+        +---+   +--------+
       IN     |        |        |   |   |        |
           ---+        +--------+   +---+        +-----------
              t0       t1       t2  t3  t4       t5
              +-------------+   +---------------------+
       Q      |             |   |                     |
           ---+             +---+                     +------
              t0          t1+PT t2                  t5+PT
         PT                 +---+                     +------
          :                /    |       +            /
       ET :               /     |      /|           /
          :              /      |     / |          /
          :             /       |    /  |         /
          0------------+        +---+   +--------+
                       t1           t3           t5


        2                   +---+                     +------
STATE   1              +----+   |   +---+        +----+
        0 -------------+        +---+   +--------+


****************************************************************)

FUNCTION_BLOCK TOF
  VAR_INPUT
    IN : BOOL;  (* first input parameter *)
    PT : TIME;  (* second input parameter *)
  END_VAR
  VAR_OUTPUT
    Q : BOOL := FALSE;  (* first output parameter *)
    ET : TIME := T#0s;  (* second output parameter *)
  END_VAR

  VAR
    STATE : SINT := 0;  (* internal state: 0-reset, 1-counting, 2-set *)
    PREV_IN : BOOL := FALSE;
    CURRENT_TIME, START_TIME : TIME;
  END_VAR

  {__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;

END_FUNCTION_BLOCK

