PACFramework

Equipment Procedures

In procedural control according to ISA-88, a process program is a collection of procedures that, when coordinated, execute a certain sequence of technological actions. The top-level procedure (cell procedure) coordinates lower-level procedures (unit procedures), which in turn coordinate the execution of operations and/or phases.

In PLCs, equipment procedures are implemented in contrast to recipe procedures, which only reference equipment procedures or coordinate embedded procedures that themselves reference equipment procedures. In the framework, equipment procedures are implemented as functions. In the standard, procedures are also referred to as procedural elements, allowing them to be referenced as building blocks of higher-level procedures.

Functions for phases, unit procedures, operations, and cell procedures must be called in every cycle unconditionally and without nesting! If a procedure should perform no actions, an IDLE state is provided.

Organization of the state machine for a procedural element

According to ISA-88, the state machine for procedures can be defined arbitrarily. However, the 2010 edition of the standard proposed two example state machines. Figure 1 shows a combined state machine formed from these two, adding “Starting” and “Completing” states to the classic variant.

In Figure 1, groups of states run, active, and operate are introduced; these are not separate states but are used to simplify the diagram, showing commands that act identically on any state within the group.

stateDiagram-v2
    [*] --> Idle
    Idle --> Starting: Start
    state operate {
     state active {
       state run{
         Running --> Completing
         Running --> Pausing: Pause
         Pausing --> Paused
         Paused --> Running: Resume
         Starting --> Running
         Restarting --> Running
       }
       Completing
       Holding
       Held
       state cmdHold <<join>>
       run --> cmdHold 
       cmdHold --> Holding : Hold
       Held --> Restarting: Restart
       Holding --> Held
     }
     state cmdStop <<join>>
     active --> cmdStop 
     cmdStop --> Stopping: Stop  
     Stopping --> Stopped
    }
    Completing --> Complete
    state cmdAbort <<join>>
    operate --> cmdAbort 
    cmdAbort --> Aborting: Abort
    Aborting --> Aborted
    Stopped --> Idle: Reset
    Complete --> Idle: Reset
    Aborted --> Idle: Reset 

Fig. 1. Proposed state machine for procedures in the framework.

Intermediate states are used for synchronizing SCADA/HMI with the PLC, and also between subsystems (e.g., functions synchronized across different PLCs). They also allow transition logging in journals and databases. Let us now examine this state machine in more detail.

When a procedural element is not executing, it is in the IDLE state. This is a passive state in which typically no control actions are performed. Upon system initialization, the procedural element enters this initial state. Normal execution involves the sequential transition through the following states:

stateDiagram-v2
direction LR
[*] --> IDLE
IDLE --> STARTING: START
STARTING --> RUNNING
RUNNING --> COMPLETING
COMPLETING --> COMPLETE
COMPLETE --> IDLE: RESET

The procedure is started by the START command, instructing the procedural element to begin executing the RUNNING logic. This command is valid only when the procedural element is in the IDLE state. However, before transitioning to the RUNNING state, the framework introduces an intermediate STARTING state, where preparatory actions can be performed. After completing these actions, the procedure transitions to COMPLETING (a state not originally defined in ISA-88). Upon completing the finalization logic, it transitions to COMPLETE. This state is necessary so that before the next execution, the procedural element receives a RESET command, confirming completion by the higher-level system.

Note that only two transitions are triggered by external commands to the procedural element; the rest occur based on internal logic of the procedural element or higher-level procedural elements (e.g., transition conditions in PFC). The sequence of states in normal transitions:

For short-term issues requiring special handling (e.g., temporary material shortage), the procedural element may enter the PAUSED state. The standard and the framework provide an intermediate PAUSING state, entered upon the PAUSE command, followed by an internal transition to PAUSED. Exiting PAUSED to RUNNING occurs via the RESUME command.

stateDiagram-v2
direction LR
RUNNING --> PAUSING: PAUSE
PAUSING --> PAUSED 
PAUSED --> RUNNING: RESUME

According to the standard:

Unlike pause, the HELD state is for long-term stops (e.g., storage of material before further processing). Transition to HOLDING occurs from any state in the run group upon the HOLD command, then proceeds to HELD. Exiting HELD occurs via RESTART through RESTARTING, which transitions back to RUNNING.

stateDiagram-v2
direction LR
state run {
 Running
}
state cmdHold <<join>>
run --> cmdHold 
cmdHold --> HOLDING: HOLD
HELD --> RESTARTING: RESTART
HOLDING --> HELD 
RESTARTING --> Running

According to the standard:

The STOP command’s use is ambiguous in the standard but in the PACFramework is intended for abnormal stops only. For normal stops, a higher-level command transitions from RUNNING to COMPLETING, considered an internal condition by the standard. A fragment is shown below:

stateDiagram-v2
direction LR
[*] --> IDLE
IDLE --> active
active: active\n(all states in the group)
state cmdStop <<join>>
active --> cmdStop 
cmdStop --> STOPPING: STOP
STOPPING --> STOPPED 
STOPPED --> IDLE: RESET

From any active state, the STOP command transitions to STOPPING, performing the abnormal stop logic, then to STOPPED, which awaits RESET to transition back to IDLE.

The standard defines:

For fast interruptions, the ABORT command forces a transition from any operate state without waiting for completion conditions, acting as an emergency exit (e.g., valve limit switch failure). The standard provides an ABORTING state for quick actions before transitioning to ABORTED, which, like COMPLETE and STOPPED, requires a RESET before restarting.

stateDiagram-v2
direction LR
[*] --> IDLE
IDLE --> operate
operate: operate\n(all states in the group and subgroups)
state cmdStop <<join>>
operate --> cmdStop 
cmdStop --> ABORTING: ABORT
ABORTING --> ABORTED 
ABORTED --> IDLE: RESET

According to the standard:

According to the standard, command functions are:

Variables in the framework associated with a procedural element

Several variables of different types are associated with a procedural element:

These variables are described in more detail below.

State representation in the framework (STEP1)

All states described above are represented in the framework by several variables:

The table below lists these states and additional state aggregations for convenience in algorithm implementation.

Field name in PROC_CTRL STEP1 value State name Note
  0 initialization (not a state) in other cases, an invalid value
STA_RUNNING 2 RUNNING  
STA_IDLE 1 IDLE  
STA_RESUMING 15 RESUMING For optional PAUSED -> RUNNING transitional state. Absent in the standard solution
STA_PAUSING 3 PAUSING  
STA_PAUSED 4 PAUSED  
STA_HOLDING 5 HOLDING  
STA_HELD 6 HOLD  
STA_RESTARTING 7 RESTARTING  
STA_COMPLETE 8 COMPLETE  
STA_STOPPING 9 STOPPING  
STA_STOPPED 10 STOPPED  
STA_ABORTING 11 ABORTING  
STA_ABORTED 12 ABORTED  
STA_STARTING 13 STARTING  
STA_COMPLETING 14 COMPLETING  
STA_NOTWRK - any end states = STA_COMPLETE OR STA_STOPPED OR STA_ABORTED OR STA_IDLE  
STA_WRK - any working states = STA_RUNNING OR STA_STARTING OR STA_COMPLETING  

Conditions for state transitions in the framework

Transition conditions are triggered by one or a combination of the following event types:

Higher-level control commands and the triggering of transition conditions by internal logic are implemented via the PROC_CTRL structure variable. Commands from the HMI are transmitted via a field in the PROC_HMI type (i.e., PROC_HMI.CMD).

The following commands defined in the standard and described earlier are implemented in the framework as boolean fields in the structure variable with the CMD_ prefix and can be sent from higher-level procedural elements. They have equivalent command codes in PROC_HMI.CMD. A typical framework approach for minimizing these commands (grouping) will be described later.

Command/field name in PROC_CTRL Value in PROC_HMI.CMD Purpose
CMD_START 1 START
CMD_RESUME 2 RESUME
CMD_RESTART 5 RESTART
CMD_PAUSE 3 PAUSE
CMD_HOLD 6 HOLD
CMD_STOP 7 STOP
CMD_ABORT 8 ABORT
CMD_RESET 4 RESET

Other transition conditions are represented by boolean fields in the PROC_CTRL type variable with the _CMPLT suffix. All boolean fields except HL_RUNNING_CMPLT are triggered by the internal execution logic of the procedural element, meaning they are modified inside the procedural element.

Field name in PROC_CTRL Purpose Transition
STARTING_CMPLT condition for transitioning to RUNNING is met STARTING -> RUNNING
HL_RUNNING_CMPLT external (high-level) completion condition triggered, must handle RUNING_CMPLT. HL (HighLevel) is needed for proper completion of a lower-level procedural element when a transition condition is triggered in the higher-level procedure. RUNNING -> COMPLETING
RUNING_CMPLT procedure completed (internal completion condition triggered) RUNNING -> COMPLETING
COMPLETING_CMPLT condition for transitioning to COMPLETE is met COMPLETING -> COMPLETE
PAUSING_CMPLT condition for transitioning to PAUSED is met PAUSING -> PAUSED
RESTARTING_CMPLT condition for transitioning to RUNNING from HOLD is met RESTARTING -> RUNNING
RESUMING_CMPLT condition for transitioning to RUNNING from RESUMING is met; needed only if RESUMING state is used. Not used in the standard framework version. RESUMING -> RUNNING
HOLDING_CMPLT condition for transitioning to HOLD from RUNNING is met HOLDING -> RUNNING
STOPPING_CMPLT condition for transitioning to STOPPED is met STOPPING -> STOPPED
ABORTING_CMPLT condition for transitioning to ABORTED is met ABORTING -> ABORTED

The RUNING_CMPLT bit is used to form the internal procedure completion condition. When creating a recipe procedure in PFC, this forms an implicit transition. For the state machine engine function PROC_MACH, this acts as an external signal since it is set in the procedural element’s main logic.

The HL_RUNNING_CMPLT bit is used to form the external procedure completion condition. It is an external command from higher-level control, such as a recipe procedure, and can define an explicit transition. In PROC_MACH logic, this bit is not used directly but is processed within the procedure logic, which then sets RUNING_CMPLT. An example will be provided in the next subsection.

PROC_CTRL.ENBL and PROC_CTRL.DSBL_COMPLETE

The PROC_CTRL.ENBL bit allows blocking the procedure start (from IDLE to Starting) under certain conditions. This bit can be set either by the procedure’s own logic or by higher-level control logic, including via basic functions. The procedure’s state machine engine will not react to the CMD_START command if PROC_CTRL.ENBL=FALSE, and all HMI commands will also be ignored.

The PROC_CTRL.DSBL_COMPLETE bit can be used to hold the procedure in the RUNNING state even if the RUNING_CMPLT bit is set to 1. This is necessary if the transition should occur only when RUNING_CMPLT=TRUE AND PROC_CTRL.DSBL_COMPLETE=FALSE. This bit is not standard in the framework and is added when needed.

The STA_NOTWRK and STA_WRK bits simplify procedure monitoring and are used in logic.

PROC_CTRL attribute STA bit Description Note
ENBL 14 permission to activate the procedure read-only in HMI
DSBL_COMPLETE - disable completion (e.g., when waiting for a condition from a higher-level procedure) not standard in the framework

Steps (STEP) and step times (T_STEP)

The structured variables PROC_CFG and PROC_HMI contain fields for steps and step times.

STEP1, described above, indicates the procedural element’s state. STEP2, by contrast, is the procedural element’s step number. For easier debugging, steps are numbered consecutively across all states, allowing the state to be identified by the step number.

T_STEP1 indicates the time spent in the RUNNING state in ms. In all other intermediate and final states, time is not counted. It resets to 0 upon transition to IDLE and HOLDING.

T_STEP2 indicates the step execution time in ms across all states except IDLE, where it is 0.

Field Type Purpose Note
STEP1 INT main state value  
STEP2 INT step within the state step numbering across states with a granularity of 1000 (15 states = 1000–15000)
T_STEP1 UDINT procedure execution time in ms counted only in RUNNING, typically frozen in PAUSED, reset in HOLDING
T_STEP2 UDINT step execution time in ms equals 0 in IDLE

If multiple parallel steps need to be executed, it is recommended to create separate procedural elements to run in parallel, as the framework does not provide other options.

Control and monitoring from HMI and modes

Appearance

All states, modes, and alarms are visible in the respective control window, where control commands are also available.

image_2022-08-23_14-30-07

States are highlighted with color (or white shades) and corresponding state text, along with state time.

For steps, the step number, text, and step time are displayed. Each step number is expected to have its own text message displayed on the screen. For automated deployment utilities, it is recommended that these messages be recorded as comments next to the step numbers in the CASE structure.

Control buttons execute commands and are shown or hidden depending on modes and states.

HMI commands

Control provides the following buttons:

All these commands must require confirmation to prevent accidental actions.

The following commands are optional, allowing manual control of procedure execution. Their implementation depends on the project and is therefore not part of the core framework, but they are listed, with some functionality implemented (notably in PROC_TRANS_A and PROC_TRANS_M functions):

All commands undergo a preliminary check before execution. Status bits indicating permission for execution are sent to the HMI, allowing the corresponding buttons to be deactivated if the command is not permitted.

Modes

The framework provides procedural element control modes according to ISA-88:

In automatic mode, state control from the HMI is disabled, and all state control buttons are deactivated. If the procedural element is controlled by a higher-level element, it may first switch the element to automatic mode before starting it, ensuring that it is fully controlled by the higher-level element by default.

Other mode implementation requirements are outside the current scope of PACFramework as they may be managed by external engines (procedure implementation) and can affect step transitions. This should be specified in technical requirements. For example, transitions between steps within a procedural element may operate depending on mode as follows:

  1. in automatic mode – only when the condition is met, in manual mode – only upon sending CMD_NEXT, in semi-automatic mode – automatically or upon CMD_NEXT; between states upon condition AND CMD_NEXT
  2. in automatic mode – only when the condition is met, in manual mode – when the condition is met OR upon CMD_NEXT, in semi-automatic mode – upon condition AND CMD_NEXT

Mode transitions of a procedural element should be logged in the event journal.

Alarms

The framework provides the following standard alarms:

A specific technological alarm defined within a technological procedural element can be identified by the step number (as an implementation option), where a specific step is allocated for a particular alarm.

State and mode bits STA

The main state of a procedural element is indicated by STEP1. However, other functional elements associated with the procedure are combined in STA, i.e., PROC_CFG.STA and PROC_HMI.STA.

Bit name STA bit number Purpose Note
ENCMD_START 0 =1, permission for HMI START command managed by PROC_MACH engine
ENCMD_PAUSE 1 permission for HMI PAUSE command managed by PROC_MACH engine
ENCMD_RESET 2 permission for HMI RESET command managed by PROC_MACH engine
ENCMD_HOLD 3 permission for HMI HOLD command managed by PROC_MACH engine
ENCMD_STOP 4 permission for HMI STOP command managed by PROC_MACH engine
ENCMD_CANCEL 5 permission for HMI negative confirmation (cancellation) managed by the main algorithm
ENCMD_NEXT 6 permission for HMI to proceed to the next step managed by the main algorithm
ENCMD_OK 7 permission for HMI to confirm action managed by the main algorithm
TMAXERR 8 maximum execution time error, time exceeds maximum  
TMINERR 9 minimum execution time error, time below minimum  
STA_ALM 10 procedure error present  
SEMI 11 =1 semi-automatic mode AUTO = NOT MAN AND NOT SEMI
INBUF 12 buffer occupied  
MAN 13 =1, manual mode AUTO = NOT MAN AND NOT SEMI
ENBL 14 permission to start  
CMD_BUF 15 load into buffer only PROC_HMI.STA

Organization of the procedural element function

A procedural element is implemented as a function that must be called unconditionally in the controller task. The function arguments are:

The variables are described above.

To simplify the handling of typical commands and the state machine, the framework provides the PROC_MACH function, which performs standard operations.

flowchart LR
  ID --> PROCEDURE
  PRCFG <--> PROCEDURE 
  PRCHMI <--> PROCEDURE
  PRCCTRL <--> PROCEDURE
  PRCBUF <--> PROCEDURE
  PARA <--> PROCEDURE
  IO <--> PROCEDURE
  subgraph PROCEDURE
    direction TB   
    proc_logic[Procedure\nLogic]
    subgraph PROC_MACH
      state_machine[State Machine\nLogic]
    end
    proc_logic --- PROC_MACH
  end

Thus, the program of any procedure includes the following parts:

Variables

PROC_CFG

The main structure (type) used for storing configurable procedure data, control, and management from the PLC program. It can also be used for buffered exchange with SCADA/HMI.

Attributes

Attribute Type Description Note
ID UINT identifier  
CLSID UINT CLSID  
STA UINT/INT as described above  
CMD UINT/INT Commands (numeric values below):  
    1 – START (start procedure)  
    2 – RESUME (resume, continue)  
    3 – PAUSE (pause)  
    4 – RESET (reset)  
    5 – RESTART (restart)  
    6 – HOLD (hold)  
    7 – STOP (stop procedure execution)  
    8 – ABORT (abort)  
    9 – CMPLT (complete transition state – for debugging)  
    16#A..F – reserved  
    16#0100 – read configuration from buffer (256)  
    16#0101 – write configuration to buffer (257)  
    16#102 – switch to automatic mode  
    16#103 – switch to manual mode  
    16#104 – toggle manual mode  
    16#105 – switch to semi-automatic (program) mode  
    16#0200 – CMD_NEXT (HMI – move to next T_STEP2 step, skip condition); implemented in the procedure’s main program  
    16#0300 – CMD_OK confirmation command; implemented in the procedure’s main program  
    16#0301 – CANCEL (HMI – negative confirmation (cancel) for manual operation); implemented in the procedure’s main program  
    2000…3000 (16#7D0 - 16#BB8) – move to the corresponding step; implemented in the procedure’s main program  
PRM INT bit parameters (bit set described below)  
    X7 AMAXENBL – activate max execution time alarm  
    X8 AMINENBL – activate min execution time alarm  
    X9 HMIMIN – =1 display time on HMI in hours/minutes  
rez1 INT for alignment  
STEP1 INT state step  
    0 – initialization (PLC start only) pink
    1 – Idle transparent
    13 – Starting light gray, circle with triangle
    2 – Running white, circle with triangle
    14 – Completing light gray, circle with checkmark
    3 – Pausing light yellow, circle with pause bars
    4 – Paused yellow, circle with pause bars
    5 – Holding light brown, circle with diamond
    6 – Hold brown, circle with diamond
    7 – Restarting beige, circle with triangle
    8 – Complete gray, circle with checkmark
    9 – Stopping light red, square within square (stop)
    10 – Stopped dark red, square within square (stop)
    11 – Aborting pink, diamond
    12 – Aborted purple, diamond with square
STEP2 INT step within state; step granularity across states is 1000 (15 states = 1000–15000)  
    0 – initialization (PLC start only)  
    1000 – Idle  
    13000 – Starting  
    2000 – Running  
    14000 – Completing  
    3000 – Pausing  
    4000 – Paused  
    5000 – Holding  
    6000 – Hold  
    7000 – Restarting  
    8000 – Complete  
    9000 – Stopping  
    10000 – Stopped  
    11000 – Aborting  
    12000 – Aborted  
    - steps within states should use a granularity of 10 for inserting additional steps - each state should have a first initialization step where actions are executed once per cycle  
T_STEP1 UDINT procedure execution time (in Running) in ms  
T_STEP2 UDINT procedure step execution time in ms  
TMIN UDINT minimum execution time limit, s  
TMAX UDINT maximum execution time limit, s  

PROC_HMI

The PROC_HMI structure is used for monitoring and controlling the procedure state from the HMI.

Attribute Type Description
STA UINT/INT mirrors PROC_CFG.STA
CMD UINT/INT mirrors PROC_CFG.CMD
STEP1 INT mirrors PROC_CFG.STEP1
STEP2 INT mirrors PROC_CFG.STEP2 (optional for detailed logging)
T_STEP1 UDINT mirrors PROC_CFG.T_STEP1
T_STEP2 UDINT mirrors PROC_CFG.T_STEP2

PROC_CTRL

The PROC_CTRL structure is used for controlling and managing the procedure within the PLC program from the same or higher-level procedures.

Attribute Type Description
ENBL Bool IN permission to activate the procedure
PAUSING_CMPLT Bool IN condition to transition to PAUSED is met
RUNING_CMPLT Bool IN procedure has completed (internal completion condition triggered). As the standard state machine does not define this command, it is included in the framework for standard condition handling. Conditions are generated outside PROC_MACH.
HL_RUNNING_CMPLT Bool IN external completion condition triggered, should handle RUNING_CMPLT. HL (HighLevel) is needed for correct lower-level procedure completion upon triggering the transition condition.
RESTARTING_CMPLT Bool IN condition to transition from HOLD to RUNNING is met
RESUMING_CMPLT Bool IN condition to transition from RESUMING to RUNNING is met
HOLDING_CMPLT Bool IN condition to transition from RUNNING to HOLD is met
STOPPING_CMPLT Bool IN condition to transition to STOPPED is met
ABORTING_CMPLT Bool IN condition to transition to ABORTED is met
STARTING_CMPLT Bool IN condition to transition to RUNNING is met
COMPLETING_CMPLT Bool IN condition to transition to COMPLETE is met
CMD_START Bool IN program command START
CMD_RESUME Bool IN program command RESUME
CMD_RESTART Bool IN program command RESTART
CMD_PAUSE Bool IN program command PAUSE
CMD_HOLD Bool IN program command HOLD
CMD_STOP Bool IN program command STOP
CMD_ABORT Bool IN program command ABORT
CMD_RESET Bool IN program command RESET
STA_RUNNING Bool OUT state RUNNING
STA_IDLE Bool OUT state IDLE
STA_RESUMING Bool OUT state RESUMING
STA_PAUSING Bool OUT state PAUSING
STA_PAUSED Bool OUT state PAUSED
STA_HOLDING Bool OUT state HOLDING
STA_HOLD Bool OUT state HOLD
STA_RESTARTING Bool OUT state RESTARTING
STA_COMPLETE Bool OUT state COMPLETE
STA_STOPPING Bool OUT state STOPPING
STA_STOPPED Bool OUT state STOPPED
STA_ABORTING Bool OUT state ABORTING
STA_ABORTED Bool OUT state ABORTED
STA_STARTING Bool OUT state STARTING
STA_COMPLETING Bool OUT state COMPLETING
STA_NOTWRK Bool OUT any end state = STA_COMPLETE OR STA_STOPPED OR STA_ABORTED OR STA_IDLE
STA_WRK Bool OUT any working state = STA_RUNNING OR STA_STARTING OR STA_COMPLETING
DSBL_COMPLETE Bool IN disable completion (e.g., when waiting for a condition from a higher-level procedure)

Function

PROC_MACH

flowchart LR
  PRCFG <--> state_machine 
  PRCHMI <--> state_machine
  PRCCTRL <--> state_machine
  PRCBUF <--> state_machine
  subgraph PROC_MACH
      state_machine[State Machine\nLogic]
  end

The PROC_MACH function performs the following tasks:

The general state machine is shown in the diagram.

stateDiagram-v2
    [*] --> Idle(1)
    Idle(1) --> Starting(13) : CMD_START & ENBL
    Starting(13) --> Running(2) : STARTING_CMPLT\n OR RUNING_CMPLT\n OR CMD_CMPLT
    Starting(13) --> Holding(5): CMD_HOLD
    Starting(13) --> Stopping(9): CMD_STOP
    Starting(13) --> Aborting(11): CMD_ABORT
    Running(2) --> Completing(14): RUNING_CMPLT\n OR CMD_CMPLT
    Running(2) --> Pausing(3) : CMD_PAUSE
    Running(2) --> Holding(5) : CMD_HOLD     
    Running(2) --> Stopping(9) : CMD_STOP     
    Running(2) --> Aborting(11) : CMD_ABORT     
    Completing(14) --> Complete(8) :COMPLETING_CMPLT\n OR CMD_CMPLT
    Completing(14) --> Stopping(9) : CMD_STOP
    Completing(14) --> Aborting(11) : CMD_ABORT     
    Completing(14) --> Starting(13) : CMD_START
    Pausing(3) --> Paused(4) :PAUSING_CMPLT\n OR CMD_CMPLT 
    Pausing(3) --> Holding(5) : CMD_HOLD     
    Pausing(3) --> Stopping(9) : CMD_STOP     
    Pausing(3) --> Aborting(11) : CMD_ABORT     
    Paused(4) --> Running(2) : CMD_RESUME\n OR CMD_RESTART\n OR CMD_START
    Paused(4) --> Completing(14) : RUNING_CMPLT   
    Paused(4) --> Holding(5) : CMD_HOLD     
    Paused(4) --> Stopping(9) : CMD_STOP     
    Paused(4) --> Aborting(11) : CMD_ABORT     
    Holding(5) --> Hold(6):HOLDING_CMPLT\n OR CMD_CMPLT 
    Holding(5) --> Stopping(9) : CMD_STOP     
    Holding(5) --> Aborting(11) : CMD_ABORT     
    Hold(6) --> Restarting(7) : CMD_RESTART 
    Hold(6) --> Stopping(9) : CMD_STOP     
    Hold(6) --> Aborting(11) : CMD_ABORT     
    Hold(6) --> Completing(14) :RUNING_CMPLT\n OR CMD_CMPLT
    Restarting(7) --> Running(2):RESTARTING_CMPLT OR CMD_CMPLT 
    Restarting(7) --> Holding(5) : CMD_HOLD 
    Restarting(7) --> Stopping(9) : CMD_STOP     
    Restarting(7) --> Aborting(11) : CMD_ABORT     
    Complete(8) --> Idle(1) :CMD_RESET 
    Stopping(9) --> Aborting(11) : CMD_ABORT  
    Stopping(9) --> Stopped(10) : STOPPING_CMPLT\n OR CMD_CMPLT
    Stopping(9) --> Starting(13) : CMD_START
    Stopped(10) --> Idle(1) : CMD_RESET
    Aborting(11) --> Aborted(12): ABORTING_CMPLT\n OR T_STEP2>3000 \n OR CMD_CMPLT
    Aborted(12) --> Idle(1): CMD_RESET\n OR CMD_START  
RUN
stateDiagram-v2
    direction LR
    [*] --> Idle(1)
    Idle(1) --> Starting(13) : CMD_START & ENBL
    Starting(13) --> Running(2) : STARTING_CMPLT\n OR RUNING_CMPLT\n OR CMD_CMPLT
    Running(2) --> Completing(14): RUNING_CMPLT\n OR CMD_CMPLT
    Completing(14) --> Complete(8) :COMPLETING_CMPLT\n OR CMD_CMPLT
    Completing(14) --> Starting(13) : CMD_START
    Complete(8) --> Idle(1) :CMD_RESET 
PAUSE
stateDiagram-v2
direction lr
    Running(2) --> Pausing(3) : CMD_PAUSE
    Pausing(3) --> Paused(4) :PAUSING_CMPLT\n OR CMD_CMPLT 
    Pausing(3) --> Holding(5) : CMD_HOLD     
    Pausing(3) --> Stopping(9) : CMD_STOP     
    Pausing(3) --> Aborting(11) : CMD_ABORT     
    Paused(4) --> Running(2) : CMD_RESUME\n OR CMD_RESTART\n OR CMD_START
    Paused(4) --> Completing(14) : RUNING_CMPLT   
    Paused(4) --> Holding(5) : CMD_HOLD     
    Paused(4) --> Stopping(9) : CMD_STOP     
    Paused(4) --> Aborting(11) : CMD_ABORT     
HOLD
stateDiagram-v2
direction LR
    Starting(13) --> Holding(5): CMD_HOLD
    Running(2) --> Holding(5) : CMD_HOLD     
    Pausing(3) --> Holding(5) : CMD_HOLD     
    Paused(4) --> Holding(5) : CMD_HOLD     
    Holding(5) --> Hold(6):HOLDING_CMPLT\n OR CMD_CMPLT 
    Holding(5) --> Stopping(9) : CMD_STOP     
    Holding(5) --> Aborting(11) : CMD_ABORT     
    Hold(6) --> Restarting(7) : CMD_RESTART 
    Hold(6) --> Stopping(9) : CMD_STOP     
    Hold(6) --> Aborting(11) : CMD_ABORT     
    Hold(6) --> Completing(14) :RUNING_CMPLT\n OR CMD_CMPLT
    Restarting(7) --> Running(2):RESTARTING_CMPLT OR CMD_CMPLT 
    Restarting(7) --> Holding(5) : CMD_HOLD 
    Restarting(7) --> Stopping(9) : CMD_STOP     
    Restarting(7) --> Aborting(11) : CMD_ABORT   

STOP
stateDiagram-v2
    Starting(13) --> Stopping(9): CMD_STOP
    Running(2) --> Stopping(9) : CMD_STOP     
    Completing(14) --> Stopping(9) : CMD_STOP
    Pausing(3) --> Stopping(9) : CMD_STOP     
    Paused(4) --> Stopping(9) : CMD_STOP     
    Holding(5) --> Stopping(9) : CMD_STOP     
    Hold(6) --> Stopping(9) : CMD_STOP     
    Restarting(7) --> Stopping(9) : CMD_STOP     
    Stopping(9) --> Stopped(10) : STOPPING_CMPLT\n OR CMD_CMPLT
    Stopped(10) --> Idle(1) : CMD_RESET
ABORT
stateDiagram-v2
    Starting(13) --> Aborting(11): CMD_ABORT 
    Running(2) --> Aborting(11) : CMD_ABORT     
    Completing(14) --> Aborting(11) : CMD_ABORT     
    Pausing(3) --> Aborting(11) : CMD_ABORT     
    Paused(4) --> Aborting(11) : CMD_ABORT      
    Holding(5) --> Aborting(11) : CMD_ABORT      
    Hold(6) --> Aborting(11) : CMD_ABORT      
    Restarting(7) --> Aborting(11) : CMD_ABORT     
    Stopping(9) --> Aborting(11) : CMD_ABORT  
    Aborting(11) --> Aborted(12): ABORTING_CMPLT\n OR T_STEP2>3000 \n OR CMD_CMPLT
    Aborted(12) --> Idle(1): CMD_RESET\n OR CMD_START  

PROC_TRANS_A

This function performs a transition when a condition is met in automatic mode and/or upon the CMD_NEXT command in manual/semi-automatic mode:

flowchart LR
  COND --умова переходу--> PROC_TRANS_A
  PRCFG <-- крок, час кроку --> PROC_TRANS_A
  PRCHMI <--режим, команди HMI--> PROC_TRANS_A
  PRCCTRL <--команди CMPLT--> PROC_TRANS_A 
  TOSTEP --куди\n переходити --> PROC_TRANS_A
  
  subgraph PROC_TRANS_A
    	cond_trans[Перевірка умови\n в залежності від режиму]
  end

PROC_TRANS_M

This function performs transitions for manual procedural elements controlled by commands:

The function performs the following:

flowchart LR
  PRCFG <-- крок, час кроку --> PROC_TRANS_M
  PRCHMI <--режим, команди HMI--> PROC_TRANS_M
  PRCCTRL <--команди CMPLT--> PROC_TRANS_M
  TOSTEPOK --куди переходити \n при CMD_ОК --> PROC_TRANS_M
  TOSTEPCANCEL --куди переходити \n при CMD_CANCEL  --> PROC_TRANS_M
  subgraph PROC_TRANS_M
    	cond_trans[Перевірка команди HMI]
  end

Procedure Implementation

Below is a template example for implementing a procedure. Cross-state step addressing is used across all states, which can simplify monitoring in SCADA/HMI.

(* set the enable condition *)
CTRL.ENBL := FALSE;

(* if logging transitions to the DB is needed, add delays at transition steps *)
(* if idle state actions are needed, they can be added inside the state *)
IF CTRL.STA_IDLE THEN
    CFG.STEP2 := 0;
END_IF;

IF CTRL.STA_STARTING THEN
    CASE CFG.STEP2 OF
        13000:
            CFG.STEP2 := 13001;
            CFG.T_STEP2 := 0;
        13001:
            CTRL.STARTING_CMPLT := TRUE; (* normal completion condition for STARTING *)
            CFG.T_STEP2 := 0;
        ELSE (* transition to RUNNING *)
            CFG.STEP2 := 13000;
            CFG.T_STEP2 := 0;
    END_CASE;
    (* allow normal phase completion even in STARTING *)
    IF CTRL.HL_RUNNING_CMPLT OR CTRL.RUNING_CMPLT THEN
        CTRL.RUNING_CMPLT := TRUE;
        CFG.STEP2 := 2000;
        CFG.T_STEP2 := 0;
    END_IF;
END_IF;

IF CTRL.STA_RUNNING THEN
    CASE CFG.STEP2 OF
        2000:
            CFG.STEP2 := 2001;
            CFG.T_STEP2 := 0;
        2001: (* main program steps *)
            ;
        ELSE
            CFG.STEP2 := 2000;
            CFG.T_STEP2 := 0;
    END_CASE;

    (* normal phase completion condition *)
    IF CTRL.HL_RUNNING_CMPLT OR CTRL.RUNING_CMPLT THEN
        CTRL.RUNING_CMPLT := TRUE;
        CFG.STEP2 := 14000;
        CFG.T_STEP2 := 0;
    END_IF;
    CTRL.RESTARTING_CMPLT := FALSE;
END_IF;

IF CTRL.STA_COMPLETING THEN
    CASE CFG.STEP2 OF
        14000:
            CFG.STEP2 := 14001;
            CFG.T_STEP2 := 0; (* initialization *)
        14001:
            CTRL.COMPLETING_CMPLT := TRUE;
            CFG.T_STEP2 := 0;
        ELSE
            CFG.STEP2 := 14000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_COMPLETE THEN
    CASE CFG.STEP2 OF
        8000:
            CFG.STEP2 := 8001;
            CFG.T_STEP2 := 0; (* initialization *)
        8001:
            IF CFG.T_STEP2 > 5000 THEN
                CTRL.CMD_RESET := TRUE;
            END_IF;
        ELSE
            CFG.STEP2 := 8000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_PAUSING THEN
    CASE CFG.STEP2 OF
        3000:
            CFG.STEP2 := 3001;
            CFG.T_STEP2 := 0; (* initialization *)
        3001:
            CTRL.PAUSING_CMPLT := TRUE;
            CFG.T_STEP2 := 0;
        ELSE
            CFG.STEP2 := 3000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_PAUSED THEN
    CASE CFG.STEP2 OF
        4000:
            CFG.STEP2 := 4001;
            CFG.T_STEP2 := 0; (* initialization *)
        4001:
            ;
        ELSE
            CFG.STEP2 := 4000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_RESTARTING THEN
    CASE CFG.STEP2 OF
        7000:
            CFG.STEP2 := 7001;
            CFG.T_STEP2 := 0; (* initialization *)
        7001:
            CTRL.RESTARTING_CMPLT := TRUE;
            CFG.T_STEP2 := 0;
        ELSE
            CFG.STEP2 := 7000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_STOPPING THEN
    CASE CFG.STEP2 OF
        9000:
            CFG.STEP2 := 9001;
            CFG.T_STEP2 := 0; (* initialization *)
        9001:
            CTRL.STOPPING_CMPLT := TRUE;
            CFG.T_STEP2 := 0;
        ELSE
            CFG.STEP2 := 9000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_STOPPED THEN
    CASE CFG.STEP2 OF
        10000:
            CFG.STEP2 := 10001;
            CFG.T_STEP2 := 0; (* initialization *)
        10001:
            IF CFG.T_STEP2 > 5000 THEN
                CTRL.CMD_RESET := TRUE;
            END_IF;
        ELSE
            CFG.STEP2 := 10000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_HOLDING THEN
    CASE CFG.STEP2 OF
        5000:
            CFG.STEP2 := 5001;
            CFG.T_STEP2 := 0; (* initialization *)
        5001:
            CTRL.HOLDING_CMPLT := TRUE;
            CFG.T_STEP2 := 0;
        ELSE
            CFG.STEP2 := 5000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_HELD THEN
    CASE CFG.STEP2 OF
        6000:
            CFG.STEP2 := 6001;
            CFG.T_STEP2 := 0; (* initialization *)
        6001:
            ;
        ELSE
            CFG.STEP2 := 6000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_ABORTING THEN
    CASE CFG.STEP2 OF
        11000:
            CFG.STEP2 := 11001;
            CFG.T_STEP2 := 0; (* initialization *)
        11001:
            CTRL.ABORTING_CMPLT := TRUE;
            CFG.T_STEP2 := 0;
        ELSE
            CFG.STEP2 := 11000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

IF CTRL.STA_ABORTED THEN
    CASE CFG.STEP2 OF
        12000:
            CFG.STEP2 := 12001;
            CFG.T_STEP2 := 0; (* initialization *)
        12001:
            IF CFG.T_STEP2 > 5000 THEN
                CTRL.CMD_RESET := TRUE;
            END_IF;
        ELSE
            CFG.STEP2 := 12000;
            CFG.T_STEP2 := 0;
    END_CASE;
END_IF;

PROC_MACH(
    ID := ID,
    PRCCFG := CFG,
    PRCHMI := HMI,
    PRCCTRL := CTRL,
    PRCBUF := PRCBUF,
    PLCCFG := PLCCFG
);

IF CFG.T_STEP2 > 16#7FFF_FFFF THEN
    CFG.T_STEP2 := 16#7FFF_FFFF;
END_IF;

Procedure calls are made unconditionally. For example, below is a sample call of two procedures for a single Unit:

PH_EXMPL1 (ID := 1, (* unique procedure identifier *)
           CFG := PHCFG_EXMPL1,
           HMI := PHHMI_EXMPL1,
           CTRL := PHCTRL_EXMPL1,
           PRCBUF := PRCBUF, (* buffer variable for configuration from HMI *)
           PLCCFG := PLC,
           ... // further parameters specific to the implementation
);