Table of Contents

Sequence

Namespace
ZApplication
Extends
Inherited Properties
Inherited Methods
Implements

Interface to the Zeugwerk Framework Sequence function block which defines the basic methods that have to be implemented.

To run a sequence and start it from the beginning this can be done and should be implemented by using RunAsync. There, a cancellation token can be used to check could be started successfully. A running sequence can be stopped by calling Stop method.

There are also several methods to make life easier for application engineers on waiting an aborting the sequence if an execution of an object fails like Await (waiting for one object), Await2 (waiting for two objects) and Await3 (waiting for three objects).

Note

While implementing a SetLogger method, the platform-dependent nature of logging limits the log-ability of the implementation. This is the reason why this specific object is marked as abstract and one of the following objects should be used instead.

The typical declaration of the function body of a sequence is

FUNCTION_BLOCK <UnitName>Sequence EXTENDS ZAux.Sequence
VAR
  _step : ZCore.Step(<UnitName>Step.Begin, <UnitName>Step.End); // i.e. ZCore.Step(GoHomeStep.GoHomeBegin, GoHomeStep.GoHomeEnd);
END_VAR

Here, <UnitName>Step is an enumeration that contains all steps that the sequence may attain. The enumeration is suggested for better readability, and may be replaced with numbers - for better traceability in a log we strongly recommend to use an enumeration though. The implementation looks like

IF NOT Busy THEN
  RETURN;
END_IF

IF OnStart(_step)
THEN
  ;// init custom sequence variables here ...
END_IF

IF OnStop()
THEN
  ;// external stop was called ...
END_IF

IF OnHalt()
THEN
  ;// Halting := TRUE; // Uncomment to acknowledge that the sequence is halting
END_IF

REPEAT
  LogStep();
 
  CASE _step.Index OF
    (* ------------------------------------------------------------------ *)
    <UnitName>Step.Begin:
    (* ------------------------------------------------------------------ *)
      IF _step.OnEntry()
      THEN
        ; // ...
      END_IF
       
      Await(..., nextStep:=<UnitName>Step.End);
 
    (* ------------------------------------------------------------------ *)
    <UnitName>Step.End:
    (* ------------------------------------------------------------------ *)
      SetBusy(FALSE);
   
  ELSE
    Abort('sequence contains an unhandled step');
  END_CASE
UNTIL _step.IsNotRepeatable() OR_ELSE NOT Busy END_REPEAT

If there are some actions which have to be done when the started object has finished, Await might not be the right statement here. Of course the Framework offers the classical approach by testing Error and Busy properties in an IF and ELSIF statement.

IF NOT Busy THEN
  RETURN;
END_IF

IF OnStart(_step)
THEN
  ;// init custom sequence variables here ...
END_IF

IF OnStop()
THEN
  ;// external stop was called ...
END_IF

IF OnHalt()
THEN
  ;// Halting := TRUE; // Uncomment to acknowledge that the sequence is halting
END_IF

REPEAT
  LogStep();
 
  CASE _step.Index OF
    (* ------------------------------------------------------------------ *)
    <UnitName>Step.Begin:
    (* ------------------------------------------------------------------ *)
      IF _step.OnEntry()
      THEN
        <object>.RunAsync(THIS^); // ...
      END_IF
       
      IF <object>.Error THEN
        // if object finished with an error do something else here
        _step.SetNext(nextStep:=<UnitName>Step.End);
      ELSIF NOT <object>.Busy THEN
        // if object finished successfully do something else
        _step.SetNext(nextStep:=<UnitName>Step.End);
      END_IF
 
    (* ------------------------------------------------------------------ *)
    <UnitName>Step.End:
    (* ------------------------------------------------------------------ *)
      SetBusy(FALSE);
   
  ELSE
    Abort('sequence contains an unhandled step');
  END_CASE
UNTIL _step.IsNotRepeatable() OR_ELSE NOT Busy END_REPEAT

The enumeration is usually implemented for several sequences which are based on one unit and looks like this:

{attribute 'qualified_only'}
{attribute 'to_string'}
TYPE <UnitName>Step :
(
  BootingBegin,
  BootingInitializeEquipment,
  BootingEnd,

  AutomaticBegin,
  AutomaticDoSomething,
  AutomaticEnd
);
END_TYPE

The following code is an example, which is taken from the Quickstart Tutorial. Note that the example uses a specialized version of Sequence, which supports logging.

FUNCTION_BLOCK PickerSequenceGoHome EXTENDS ZAux.Sequence
VAR
  _step : ZCore.Step(PickerStep.GoHomeBegin, PickerStep.GoHomeEnd);
  _timer : ZAux.Timer;
END_VAR
IF NOT Busy THEN
  RETURN;
END_IF

IF OnStart(_step)
THEN
  // init custom sequence variables here ...
END_IF

IF OnStop()
THEN
  // external stop was called ...
END_IF

IF OnHalt()
THEN
  // Halting := TRUE; // Uncomment to acknowledge that the sequence is halting
END_IF

REPEAT
  LogStep();
 
  CASE _step.Index OF
    (* ---------------------------------------------- *)
    PickerStep.GoHomeBegin:
    (* ---------------------------------------------- *)
      IF _step.OnEntry()
      THEN
        _timer.WaitAsync(2.0);
      END_IF
       
      Await(_timer, nextStep:=PickerStep.GoHomeEnd);
 
    (* ---------------------------------------------- *)
    PickerStep.GoHomeEnd:
    (* ---------------------------------------------- *)
      SetBusy(FALSE);
   
  ELSE
     Abort('sequence contains an unhandled step');
  END_CASE
UNTIL _step.IsNotRepeatable() OR_ELSE NOT Busy END_REPEAT

If you want to use this sequence in an actual program it has to be instantiated and called properly. Create an empty solution with a MAIN.PRG and insert the following snippet

PROGRAM MAIN
VAR
  Step : ZCore.Step(0, 100);
  Picking : PickerSequenceGoHome;
END_VAR
------------------------------------------
CASE Step.Index OF
  0:
    IF Step.OnEntry() THEN
      Picking.RunAsync(0);
    END_IF
 
    Picking.Cyclic();
    IF Picking.Error THEN
      Step.SetNext(99);
    ELSIF NOT Picking.Busy THEN
      Step.SetNext(20);
    END_IF
   
  20: // Idle
    ;
   
  99: // Error
    ;
 
END_CASE
Note

When using this function block it is strongly recommended to overwrite StepDecoded such that the logging mechanism of the object can write strings for distinct steps of the sequence instead of mere numbers.

Note

A sequence is also an ExecutionToken to be used as a parameter for async calls (e.g. _axis.AxisName.MoveAbsolutAsync(THIS^)). A sequence as an ExecutionToken gets informed (aborted) from an object if the originally started task has changed unexpected.

Note

A sequence cannot be recovered.

This extension ojbect adds Alarming capabilities. In order to make use the the internal held interface to an alarming object, the constructor of this object, usually the constructor should be overloaded and/or the SetAlarming method may be utilized.

Note

In the Zeugwerk Framework, alarming is a built-in functionality and initialized automatically: An alarming function block is instantiated in the Unit function block and forwarded to in every sequence the runs in a Unit context at construction time. If alarming should be disabled for sequence then simply remove the assignment of the Unit alarming function block in FB_init of the sequence.

This implementation of (ISequence)[ZCore.ISequence] is the favourable implementation for sequences that require an alarming mechanismn in addition to logging.

FUNCTION_BLOCK Sequence EXTENDS ZAux.Sequence IMPLEMENTS ZCore.ISequence, ZCore.IObject, ZCore.IError, ZCore.ICancellationToken, ZCore.IHaltable, ZCore.IStartToken, ZCore.IHaltToken, ZCore.IRecoverable

Methods

Abort

This method should be called in an actual implementation of a framework object if an error occcured during execution of a sequence. The method changes the internal state of the object to error and additionally, sets a message to indicate the problem.

If an alarming object is available the error message will be inserted and depending on the alarming state evaluated accordingly. For more information on alarming in the Zeugwerk Framework, please refer to the alarming documentation.

METHOD Abort (
 message : ZCore.ZString)

Inputs

message ZString

message which holds the actual cause of the sequence abortion

AbortErrorId

This method should be called in an actual implementation of a framework object if an error occcured during execution of a sequence. The method changes the internal state of the object to error and additionally, sets a message to indicate the problem.

This method should be used for the most inner object that caused an error.

If called during initialization (State = Booting) the state variable is set to BootingError instead of Error.

If an alarming object is available the error message will be inserted and depending on the alarming state evaluated accordingly. For more information on alarming in the Zeugwerk Framework, please refer to the alarming documentation.

METHOD AbortErrorId (
 errorId : UDINT,
 message : ZCore.ZString)

Inputs

errorId UDINT

error identification number which allows to uniquely identify the cause of the abortion in order to be able to react as caller of the sequence accordingly

message ZString

message which holds the actual cause of the sequence abortion

AbortWithContext

This method should be called in an actual implementation of a framework object if an error occcured during executing a sequence. The method changes the internal state of the object to error and additionally, sets a message to indicate the problem. The error source of the issue is set to THIS^ object and the error code is set to errorId.

If called during initialization (state_ = Booting) the state variable is set to BootingError.

Note

For pure Objects the abort method is not callable from the outside, because its abort method is PROTECTED. The StartToken, however, make the method available from the outside API.

If the optional context parameter is provided, error tracing is more detailed

METHOD PUBLIC AbortWithContext (
 message : ZCore.ZString,
 context : REFERENCE TO ZCore.ManagedObject)

Inputs

message ZString

context REFERENCE TO ManagedObject

Assert

This method sets the object into the error state and stores a message to indicate the problem. It is a shortcut for writing

{attribute 'common style'}
IF obj <> 0 AND_THEN obj.Error
THEN
  Abort(obj.ErrorMessage());
END_IF

{attribute 'shorter'}
Assert(obj);

and is used for convenience.

If an alarming object is available the error message will also be inserted and depending on the alarming state evaluated accordingly. For more information on alarming in Zeugwerk Framework, please refer to the documentation here TODO: add Alarming doc

METHOD Assert (
 obj : ZCore.IError) : BOOL

Inputs

obj IError

object which has to be checked if it is on error state or not

Returns

BOOL

SetAlarming

This method can be used to set the alarming object that can be utilized in this sequence (i.e. in the function body). The alarming object that is passed with this method is also automatically used if the sequence goes into its error state if the abort method or any of its derivatives (i.e. Assert) are called. In the later case, an 'error' alarm containing ErrorMessage is automatically emitted.

To disable alarming for this sequence (even temporarily) a call to SetAlarming(0) can be used at any time.

METHOD SetAlarming (
 alarming : IAlarming)

Inputs

alarming IAlarming