Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
      <title>ix.core | System.Dynamic.ExpandoObject </title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta name="title" content="ix.core | System.Dynamic.ExpandoObject ">
      
      
      <link rel="icon" href="../../images/favicon.ico">
      <link rel="stylesheet" href="../../public/docfx.min.css">
      <link rel="stylesheet" href="../../public/main.css">
      <meta name="docfx:navrel" content="../../toc.html">
      <meta name="docfx:tocrel" content="../../toc.html">
      
      <meta name="docfx:rel" content="../../">
      
      
      <meta name="docfx:docurl" content="https://github.com/Inxton/AXOpen/blob/dev/src/data/ctrl/README.md/#L1">
      <meta name="loc:inThisArticle" content="In this article">
      <meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
      <meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
      <meta name="loc:tocFilter" content="Filter by title">
      <meta name="loc:nextArticle" content="Next">
      <meta name="loc:prevArticle" content="Previous">
      <meta name="loc:themeLight" content="Light">
      <meta name="loc:themeDark" content="Dark">
      <meta name="loc:themeAuto" content="Auto">
      <meta name="loc:changeTheme" content="Change theme">
      <meta name="loc:copy" content="Copy">
      <meta name="loc:downloadPdf" content="Download PDF">

      <script type="module" src="./../../public/docfx.min.js"></script>

      <script>
        const theme = localStorage.getItem('theme') || 'auto'
        document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
      </script>

  </head>

  <body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
    <header class="bg-body border-bottom">
      <nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
        <div class="container-xxl flex-nowrap">
          <a class="navbar-brand" href="../../index.html">
            <img id="logo" class="svg" src="../../images/logo.svg" alt="">
            
          </a>
          <button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
            <i class="bi bi-three-dots"></i>
          </button>
          <div class="collapse navbar-collapse" id="navpanel">
            <div id="navbar">
              <form class="search" role="search" id="search">
                <i class="bi bi-search"></i>
                <input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
              </form>
            </div>
          </div>
        </div>
      </nav>
    </header>

    <main class="container-xxl">

      <div class="content">
        <div class="actionbar">

          <nav id="breadcrumb"></nav>
        </div>

        <article data-uid="">
<h1 id="ixcore"><strong>ix.core</strong></h1>

<p><strong>ix.core</strong> provides basic blocks for building AXOpen applications.</p>
<h1 id="basic-concepts">Basic concepts</h1>
<h2 id="axocontext">AxoContext</h2>
<p>AxoContext encapsulates entire application or application units. Any solution may contain one or more contexts, however the each should be considered to be an isolated island and any <strong>direct inter-context access to members must be avoided</strong>.</p>
<p><strong>IMPORTANT</strong> Each AxoContext must belong to a single PLC task. Multiple IxContexts can be however running on the same task.</p>
<pre><code class="lang-mermaid">  classDiagram 
    class Context{
        #Main()*
        +Run()
    }     
</code></pre>
<p>In its basic implementation AxoContext has relatively simple interface. The main method is the method where we place all calls of our sub-routines. <strong>In other words the <code>Main</code> is the root of the call tree of our program.</strong></p>
<p><code>Run</code> method runs the AxoContext. It must be called cyclically within a program unit that is attached to a cyclic <code>task</code>.</p>
<h3 id="why-do-we-need-axocontext">Why do we need AxoContext</h3>
<p><code>AxoContext</code> provides counters, object identification and other information about the execution of the program. These information is then used by the objects contained at different levels of the AxoContext.</p>
<h3 id="how-axocontext-works">How AxoContext works</h3>
<p>When you call <code>Run</code> method on an instance of a AxoContext, it will ensure opening AxoContext, running <code>Main</code> method (root of all your program calls) and AxoContext closing.</p>
<pre><code class="lang-mermaid">  flowchart LR
    classDef run fill:#80FF00,stroke:#0080FF,stroke-width:4px,color:#7F00FF,font-size:15px,font-weight:bold                                                      
    classDef main fill:#ff8000,stroke:#0080ff,stroke-width:4px,color:#7F00FF,font-size:15px,font-weight:bold                                                                                                           
    id1(Open):::run--&gt;id2(#Main*):::main--&gt;id3(Close):::run--&gt;id1
</code></pre>
<h3 id="how-to-use-axocontext">How to use AxoContext</h3>
<p>Base class for the AxoContext is <code>ix.core.AxoContext</code>. The entry point of call execution of the AxoContext is <code>Main</code> method. Notice that the <code>AxoContext</code> class is abstract and cannot be instantiated if not extended. <code>Main</code> method must be overridden in derived class notice the use of override keyword and also that the method is <code>protected</code> which means the it is visible only from within the <code>AxoContext</code> and derived classes.</p>
<p><strong>How to extend AxoContext class</strong></p>
<pre><code class="lang-SmallTalk">
USING ix.core

CLASS PUBLIC MyContext EXTENDS AxoContext
    METHOD PROTECTED OVERRIDE Main
        // Here goes all your logic for given AxoContext.
    END_METHOD
END_CLASS
</code></pre>
<p>Cyclical call of the AxoContext logic (<code>Main</code> method) is ensured when AxoContext <code>Execute</code> method is called. <code>Execute</code> method is public therefore accessible and visible to any part of the program that whishes to call it.</p>
<p><strong>How to start AxoContext's execution</strong></p>
<pre><code class="lang-SmallTalk">PROGRAM MyProgram
    VAR
        _myContext : MyContext;
    END_VAR

    _myContext.Run();
END_PROGRAM
</code></pre>
<h2 id="axoobject">AxoObject</h2>
<p>AxoObject is the base class for any other classes of AXOpen. It provides access to the parent AxoObject and the AxoContext in which it was initialized.</p>
<pre><code class="lang-mermaid">  classDiagram
    class Object{
        +Initialize(IAxoContext context)
        +Initialize(IAxoObject parent)        
    }     
</code></pre>
<p><strong>AxoObject initialization within a AxoContext</strong></p>
<pre><code class="lang-SmallTalk">    CLASS PUBLIC MyContext EXTENDS ix.core.AxoContext
        VAR
            _myObject : ix.core.AxoObject;
        END_VAR
        METHOD PROTECTED OVERRIDE Main
            _myObject.Initialize(THIS);            
        END_METHOD
    END_CLASS
</code></pre>
<p><strong>AxoObject initialization within another AxoObject</strong></p>
<pre><code class="lang-SmallTalk">    CLASS PUBLIC MyParentObject EXTENDS ix.core.AxoObject
        VAR
            _myChildObject : ix.core.AxoObject;
        END_VAR
        METHOD PROTECTED OVERRIDE Main
            _myChildObject.Initialize(THIS);            
        END_METHOD
    END_CLASS
</code></pre>
<h2 id="axotask">AxoTask</h2>
<p>AxoTask provides basic task execution. AxoTask needs to be initialized to set the proper AxoContext.</p>
<p><strong>AxoTask initialization within a AxoContext</strong></p>
<pre><code class="lang-SmallTalk">    CLASS IxTaskExample EXTENDS AxoContext         
        VAR PUBLIC
            _myTask : AxoTask;
            _myCounter : ULINT;
        END_VAR
    
        METHOD PUBLIC Initialize
            // Initialization of the context needs to be called first
            // It does not need to be called cyclically, just once
            _myTask.Initialize(THIS);
        END_METHOD
    END_CLASS  
</code></pre>
<p>There are two key methods for managing the AxoTask:</p>
<ul>
<li><code>Invoke()</code> fires the execution of the AxoTask (can be called fire&amp;forget or cyclically)</li>
<li><code>Execute()</code> method must be called cyclically. The method returns <code>TRUE</code> when the AxoTask is required to run until enters <code>Done</code> state or terminates in error.</li>
</ul>
<p>For termination of the execution of the AxoTask there are following methods:</p>
<ul>
<li><code>DoneWhen(Done_Condition)</code> - terminates the execution of the AxoTask and enters the <code>Done</code> state when the <code>Done_Condition</code> is <code>TRUE</code>.</li>
<li><code>ThrowWhen(Error_Condition)</code> - terminates the execution of the AxoTask and enters the <code>Error</code> state when the <code>Error_Condition</code> is <code>TRUE</code>.</li>
<li><code>Abort()</code> - terminates the execution of the AxoTask and enters the <code>Ready</code> state if the AxoTask is in the <code>Busy</code> state, otherwise does nothing.</li>
</ul>
<p>To reset the AxoTask from any state in any moment there is following method:</p>
<ul>
<li><code>Restore()</code> acts as reset of the AxoTask (sets the state into <code>Ready</code> state from any state of the AxoTask).</li>
</ul>
<p>Moreover, there are seven more &quot;event-like&quot; methods that are called when a specific event occurs (see the chart below).</p>
<pre><code class="lang-mermaid">flowchart TD
    classDef states fill:#80FF00,stroke:#0080FF,stroke-width:4px,color:#7F00FF,font-size:15px,font-weight:bold                                                      
    classDef actions fill:#ff8000,stroke:#0080ff,stroke-width:4px,color:#7F00FF,font-size:15px,font-weight:bold                                                      
    classDef events fill:#80FF00,stroke:#0080ff,stroke-width:4px,color:#7F00FF,font-size:15px,font-weight:bold                                                      

    s1((Ready)):::states
    s2((Kicking)):::states
    s3((Busy)):::states
    s4((Done)):::states
    s5((Error)):::states
    s6((Aborted)):::states
    a1(&quot;Invoke()#128258;&quot;):::actions
    a2(&quot;Execute()#128260;&quot;):::actions
    a3(&quot;DoneWhen(TRUE)#128258;&quot;):::actions
    a4(&quot;ThrowWhen(TRUE)#128258;&quot;):::actions
    a5(&quot;NOT Invoke() call for at&lt;br&gt;least two Context cycles#128260;&quot;):::actions
    a6(&quot;Restore()#128258;&quot;):::actions
    a7(&quot;Abort()#128258;&quot;):::actions
    a8(&quot;Resume()#128258;&quot;):::actions
    e1{{&quot;OnStart()#128258;&quot;}}:::events
    e2{{&quot;OnError()#128258;&quot;}}:::events
    e3{{&quot;WhileError()#128260;&quot;}}:::events
    e4{{&quot;OnDone()#128258;&quot;}}:::events
    e5{{&quot;OnAbort()#128258;&quot;}}:::events
    e6{{&quot;OnRestore()#128258;&quot;}}:::events
    
    subgraph legend[&quot; &quot;]
        direction LR
        s((State)):::states
        ac(&quot;Action #128260;:called&lt;br&gt;cyclically&quot;):::actions
        as(&quot;Action #128258;:single&lt;br&gt;or cyclical call &quot;):::actions
        ec{{&quot;Event #128260;:called&lt;br&gt;cyclically&quot;}}:::events
        es{{&quot;Event #128258;:triggered&lt;br&gt;once &quot;}}:::events
    end
    
    subgraph chart[&quot; &quot;]
        direction TB
        s1
        s1--&gt;a1
        a1--&gt;s2
        s2--&gt;a2
        s3--&gt;a3
        s3--&gt;a7
        a7--&gt;e5
        a7--&gt;s6
        s6--&gt;a8
        a8--&gt;s3
        a3--&gt;s4
        s4----&gt;a5
        a5--&gt;a1
        a2---&gt;s3
        s3---&gt;a4
        a4--&gt;s5
        s5--&gt;a6
        a6--&gt;e6
        a2--&gt;e1
        a4--&gt;e2
        a4--&gt;e3
        a3--&gt;e4
        a6--&gt;s1
    end
</code></pre>
<p>Example of using AxoTask:</p>
<pre><code class="lang-SmallTalk">    CLASS IxTaskExample EXTENDS AxoContext         
        VAR PUBLIC
            _myTask : AxoTask;
            _myCounter : ULINT;
        END_VAR
    
        METHOD PUBLIC Initialize
            // Initialization of the context needs to be called first
            // It does not need to be called cyclically, just once
            _myTask.Initialize(THIS);
        END_METHOD

        METHOD PROTECTED OVERRIDE Main
            // Cyclicall call of the Execute
            IF _myTask.Execute() THEN
                _myCounter := _myCounter + ULINT#1;
                _myTask.DoneWhen(_myCounter = ULINT#100);
            END_IF;
        END_METHOD
    END_CLASS  
</code></pre>
<p>The AxoTask executes upon the <code>Invoke</code> method call. <code>Invoke</code> fires the execution of <code>Execute</code> logic upon the first call, and it does not need cyclical calling.</p>
<pre><code class="lang-SmallTalk">    _myTask.Invoke();
</code></pre>
<p><code>Invoke()</code> method returns IAxoTaskState with the following members:</p>
<ul>
<li><code>IsBusy</code> indicates the execution started and is running.</li>
<li><code>IsDone</code> indicates the execution completed with success.</li>
<li><code>HasError</code> indicates the execution terminated with a failure.</li>
<li><code>IsAborted</code> indicates that the execution of the AxoTask has been aborted. It should continue by calling the method <code>Resume()</code>.</li>
</ul>
<pre><code class="lang-SmallTalk">            // Wait for AxoTask to Complete 
            IF _myTask.Invoke().IsDone() THEN
                ; //Do something
            END_IF;
            // ALTERNATIVELY
            _myTask.Invoke();
            IF _myTask.IsDone() THEN
                ; //Do something ALTERNATIV
            END_IF;
</code></pre>
<pre><code class="lang-SmallTalk">            // Make sure that the AxoTask is executing 
            IF _myTask.Invoke().IsBusy() THEN
                ; //Do something
            END_IF;
</code></pre>
<pre><code class="lang-SmallTalk">            // Check for AxoTask's error 
            IF _myTask.Invoke().HasError() THEN
                ; //Do something
            END_IF;
</code></pre>
<p>The AxoTask can be started only from the <code>Ready</code> state by calling the <code>Invoke()</code> method in the same Context cycle as the <code>Execute()</code> method is called, regardless the order of the methods calls. After AxoTask completion, the state of the AxoTask will remain in Done, unless:</p>
<p>1.) AxoTask's <code>Restore</code> method is called (AxoTask changes it's state to <code>Ready</code> state).</p>
<p>2.) <code>Invoke</code> method is not called for two or more consecutive cycles of its context (that usually means the same as PLC cycle); successive call of Invoke will switch the task into the Ready state and immediately into the <code>Kicking</code> state.</p>
<p>The AxoTask may finish also in an <code>Error</code> state. In that case, the only possibility to get out of <code>Error</code> state is by calling the <code>Restore()</code> method.</p>
<p>To implement any of the already mentioned &quot;event-like&quot; methods the new class that extends from the AxoTask needs to be created. The required method with <code>PROTECTED OVERRIDE</code> access modifier needs to be created as well, and the custom logic needs to be placed in.
These methods are:</p>
<ul>
<li><code>OnAbort()</code> - executes once when the task is aborted.</li>
<li><code>OnResume()</code> - executes once when the task is resumed.</li>
<li><code>OnDone()</code> - executes once when the task reaches the <code>Done</code> state.</li>
<li><code>OnError()</code> - executes once when the task reaches the <code>Error</code> state.</li>
<li><code>OnRestore()</code> - executes once when the task is restored.</li>
<li><code>OnStart()</code> - executes once when the task starts (at the moment of transition from the <code>Kicking</code> state into the <code>Busy</code> state).</li>
<li><code>WhileError()</code> - executes repeatedly while the task is in <code>Error</code> state (and <code>Execute()</code> method is called).</li>
</ul>
<p>Example of implementing &quot;event-like&quot; methods:</p>
<pre><code class="lang-SmallTalk">    CLASS MyCommandTask Extends CommandTask
        VAR
            OnAbortCounter : ULINT;
            OnResumeCounter : ULINT;
            OnDoneCounter : ULINT;
            OnErrorCounter : ULINT;
            OnRestoreCounter : ULINT;
            OnStartCounter : ULINT;
            WhileErrorCounter : ULINT;
        END_VAR
        METHOD PROTECTED OVERRIDE OnAbort 
            OnAbortCounter := OnAbortCounter + ULINT#1;
        END_METHOD

        METHOD PROTECTED OVERRIDE OnResume 
            OnResumeCounter := OnResumeCounter + ULINT#1;
        END_METHOD

        METHOD PROTECTED OVERRIDE OnDone 
            OnDoneCounter := OnDoneCounter + ULINT#1;
        END_METHOD
    
        METHOD PROTECTED OVERRIDE OnError 
            OnErrorCounter := OnErrorCounter + ULINT#1;
        END_METHOD

        METHOD PROTECTED OVERRIDE OnRestore 
            OnRestoreCounter := OnRestoreCounter + ULINT#1;
        END_METHOD

        METHOD PROTECTED OVERRIDE OnStart 
            OnStartCounter := OnStartCounter + ULINT#1;
        END_METHOD

        METHOD PROTECTED OVERRIDE WhileError 
            WhileErrorCounter := WhileErrorCounter + ULINT#1;
        END_METHOD    
    END_CLASS
</code></pre>
<h2 id="step">Step</h2>
<p>AxoStep is an extension class of the AxoTask and provides the basics for the coordinated controlled execution of the task in the desired order based on the coordination mechanism used.</p>
<p>AxoStep contains the <code>Execute()</code> method so as its base class overloaded and extended by following parameters:</p>
<ul>
<li>coord (mandatory): instance of the coordination controlling the execution of the AxoStep.</li>
<li>Enable (optional): if this value is <code>FALSE</code>, AxoStep body is not executed and the current order of the execution is incremented.</li>
<li>Description (optional): AxoStep description text describing the action the AxoStep is providing.</li>
</ul>
<p>AxoStep class contains following public members:</p>
<ul>
<li>Order: Order of the AxoStep in the coordination. This value can be set by calling the method <code>SetSteoOrder()</code> and read by the method <code>GetStepOrder()</code>.</li>
<li>StepDescription: AxoStep description text describing the action the AxoStep is providing. This value can be set by calling the <code>Execute()</code> method with <code>Description</code> parameter.</li>
<li>IsActive: if <code>TRUE</code>, the AxoStep is currently executing, or is in the order of the execution, otherwise <code>FALSE</code>. This value can be set by calling the method <code>SetIsActive()</code> and read by the method <code>GetIsActive()</code>.</li>
<li>IsEnabled: if <code>FALSE</code>, AxoStep body is not executed and the current order of the execution is incremented. This value can be set by calling the method <code>SetIsEnabled()</code> or  calling the <code>Execute()</code> method with <code>Enable</code> parameter and read by the method <code>GetIsEnabled()</code>.</li>
</ul>
<h2 id="axosequencer">AxoSequencer</h2>
<p>AxoSequencer is an IxCordinator class provides triggering the AxoStep-s inside the sequence in the order they are written.</p>
<p>AxoSequencer extends from AxoTask so it also has to be initialized by calling its <code>Initialize()</code> method and started using its <code>Invoke()</code> method.</p>
<p>AxoSequencer contains following methods:</p>
<ul>
<li><code>Open()</code>: this method must be called cyclically before any logic. It provides some configuration mechanism that ensures that the steps are going to be executed in the order, they are written. During the very first call of the sequence, no step is executed as the AxoSequencer is in the configuring state. From the second context cycle after the AxoSequencer has been invoked the AxoSequencer change its state to running and starts the execution from the first step upto the last one. When AxoSequencer is in running state, order of the step cannot be changed.</li>
<li><code>MoveNext()</code>: Terminates the currently executed step and moves the AxoSequencer's pointer to the next step in order of execution.</li>
<li><code>RequestStep()</code>: Terminates the currently executed step and set the AxoSequencer's pointer to the order of the <code>RequestedStep</code>. When the order of the <code>RequestedStep</code> is higher than the order of the currently finished step (the requested step is &quot;after&quot; the current one) the requested step is started in the same context cycle. When the order of the <code>RequestedStep</code> is lower than the order of the currently finished step (the requested step is &quot;before&quot; the current one) the requested step is started in the next context cycle.</li>
<li><code>CompleteSequence()</code>: Terminates the currently executed step, completes (finishes) the execution of this AxoSequencer and set the coordination state to Idle. If the <code>SequenceMode</code> of the AxoSequencer is set to <code>Cyclic</code>, following <code>Open()</code> method call in the next context cycle switch it again into the configuring state, reasign the order of the individual steps (even if the orders have been changed) and subsequently set AxoSequencer back into the running state. If the <code>SequenceMode</code> of the AxoSequencer is set to <code>RunOnce</code>, terminates also execution of the AxoSequencer itself.</li>
<li>`GetCoordinatorState()': Returns the current state of the AxoSequencer.
<ul>
<li><code>Idle</code></li>
<li><code>Configuring</code>: assigning the orders to the steps, no step is executed.</li>
<li><code>Running</code>: orders to the steps are already assigned, step is executed.</li>
</ul>
</li>
<li><code>SetSteppingMode()</code>: Sets the stepping mode of the AxoSequencer. Following values are possible.
<ul>
<li><code>None</code>:</li>
<li><code>StepByStep</code>: if this mode is choosen, each step needs to be started by the invocation of the <code>StepIn</code> commmand.</li>
<li><code>Continous</code>: if this mode is choosen (default), each step is started automaticcaly after the previous one has been completed.</li>
</ul>
</li>
<li><code>GetSteppingMode()</code>: Gets the current stepping mode of the AxoSequencer.</li>
<li><code>SetSequenceMode()</code>: Sets the sequence mode of the AxoSequencer. Following values are possible.
<ul>
<li><code>None</code>:</li>
<li><code>RunOnce</code>: if this mode is choosen, after calling the method <code>CompleteSequence()</code> the execution of the sequence is terminated.</li>
<li><code>Cyclic</code>: if this mode is choosen (default), after calling the method <code>CompleteSequence()</code> the execution of the sequence is &quot;reordered&quot; and started from beginning.</li>
</ul>
</li>
<li><code>GetSequenceMode()</code>: Gets the current sequence mode of the AxoSequencer.</li>
<li><code>GetNumberOfConfiguredSteps()</code>: Gets the number of the configured steps in the sequence.</li>
</ul>
<pre><code class="lang-SmallTalk">    CLASS IxSequencerExample EXTENDS AxoContext
        VAR PUBLIC
            _mySequencer : AxoSequencer;
            _step_1 : AxoStep;
            _step_2 : AxoStep;
            _step_3 : AxoStep;
            _myCounter : ULINT;
        END_VAR
    
        METHOD PUBLIC Initialize
            // Initialization of the context needs to be called first
            // It does not need to be called cyclically, just once
            _mySequencer.Initialize(THIS);
            _step_1.Initialize(THIS);
            _step_2.Initialize(THIS);
            _step_3.Initialize(THIS);
        END_METHOD

        METHOD PROTECTED OVERRIDE Main
            _mySequencer.Open();

            // Example of the most simple use of Execute() method of step class, only with IxCoordinator defined. 
            IF _step_1.Execute(_mySequencer) THEN
                // do something
                _myCounter := _myCounter + ULINT#1;
                IF (_myCounter MOD ULINT#5) = ULINT#0 THEN
                    // continue to the next step of the sequence
                    _mySequencer.MoveNext();
                END_IF;
            END_IF;

            // Example of use of the Execute() method of step class with Enable condition.
            // This step is going to be executed just in the first run of the sequence,
            // as during the second run, the Enable parameter will have the value of FALSE.
            IF _step_2.Execute(coord := _mySequencer, Enable := _myCounter &lt;= ULINT#20) THEN
                _myCounter := _myCounter + ULINT#1;
                IF _myCounter = ULINT#20 THEN
                    // Jumping to step 1. As it is jumping backwards, the execution of step 1  
                    // is going to be started in the next context cycle.
                    _mySequencer.RequestStep(_step_1);
                END_IF;
            END_IF;

            // Example of use of the Execute() method of step class with all three parameters defined.
            IF _step_3.Execute(coord := _mySequencer, Enable := TRUE, Description := 'This is a description of the step 3' ) THEN
                _myCounter := _myCounter + ULINT#1;
                IF (_myCounter MOD ULINT#7) = ULINT#0 THEN
                    // Finalize the sequence and initiate the execution from the first step.
                    _mySequencer.CompleteSequence();
                END_IF;
            END_IF;
        END_METHOD   
    END_CLASS
</code></pre>
<h2 id="axocomponent">AxoComponent</h2>
<p><code>AxoComponent</code> is an abstract class extending the AxoObject, and it is the base building block for the &quot;hardware-related devices&quot; like a pneumatic piston, servo drive, robot, etc., so as for the, let's say, &quot;virtual devices&quot; like counter, database, etc. <code>AxoComponent</code> is designed to group all possible methods, tasks, settings, and status information into one consistent class. As the <code>AxoComponent</code> is an abstract class, it cannot be instantiated and must be extended. In the extended class, two methods are mandatory.</p>
<p><code>Restore()</code> - inside this method, the logic for resetting the AxoComponent or restoring it from any state to its initial state should be placed.</p>
<p><code>ManualControl()</code> - inside this method, the logic for manual operations with the component should be placed. To be able to control the <code>AxoComponent</code> instance manually, the method <code>ActivateManualControl()</code> of this instance needs to be called cyclically.</p>
<p>The base class contains two additional method to deal with the manual control of the <code>AxoComponent</code>.
<code>ActivateManualControl()</code> - when this method is called cyclically, the <code>AxoComponent</code> changes its behavior to manually controllable and ensure the call of the <code>ManualControl()</code> method in the derived class.</p>
<p><code>IsManuallyControllable()</code> -returns <code>TRUE</code> when the <code>AxoComponent</code> is manually controllable.</p>
<p><strong>Layout attributes <code>ComponentHeader</code> and <code>ComponentDetails</code></strong></p>
<p>The visual view of the extended <code>AxoComponent</code> on the UI side could be done both ways. Manually with complete control over the design or by using the auto-rendering mechanism of the <code>RenderableContentControl</code> (TODO add a link to docu of the RenderableContentControl) element, which is, in most cases, more than perfect.
To take full advantage of the auto-rendering mechanism, the base class has implemented the additional layout attributes <code>ComponentHeader</code> and <code>ComponentDetails(TabName)</code>. The auto-rendered view is divided into two parts: the fixed one and the expandable one.
All <code>AxoComponent</code> members with the <code>ComponentHeader</code> layout attribute defined will be displayed in the fixed part.
All members with the <code>ComponentDetails(TabName)</code> layout attribute defined will be displayed in the expandable part inside the <code>TabControl</code> with &quot;TabName&quot;.
All members are added in the order in which they are defined, taking into account their layout attributes like <code>Container(Layout.Wrap)</code> or <code>Container(Layout.Stack)</code>.</p>
<p><strong>How to implement <code>AxoComponent</code></strong></p>
<p>Example of the implementation very simple <code>AxoComponent</code> with members placed only inside the Header.</p>
<pre><code class="lang-SmallTalk">using AXOpen.Core;

{#ix-attr:[Container(Layout.Stack)]}
{#ix-set:AttributeName = &quot;Component with header only example&quot;}
CLASS PUBLIC ComponentHeaderOnlyExample EXTENDS AxoComponent 
    METHOD PROTECTED OVERRIDE Restore: IAxoTask 
        // Some logic for Restore could be placed here.
        // For Example:
        valueReal := REAL#0.0;
        valueDint := DINT#0;
    END_METHOD

    METHOD PROTECTED OVERRIDE ManualControl
        // Some logic for manual control could be placed here.
        ;
    END_METHOD

    // Main method of the `AxoComponent` that needs to be called inside the `AxoContext` cyclically.
    METHOD PUBLIC Run
        // Declaration of the input and output variables.
        // In the case of &quot;hardware-related&quot; `AxoComponent`, 
        // these would be the variables linked to the hardware. 
        VAR_INPUT 
            inReal : REAL;
            inDint : DINT;
        END_VAR
        VAR_OUTPUT
            outReal : REAL;
            outDint : DINT;
        END_VAR
        
        // This must be called first.
        SUPER.Open();

        // Place the custom logic here.
        valueReal := valueReal * inReal;
        valueDint := valueDint + inDint;

        outReal := valueReal;
        outDint := valueDint;
    END_METHOD 

    VAR PUBLIC
        {#ix-attr:[Container(Layout.Wrap)]}
        {#ix-attr:[ComponentHeader()]}        
        {#ix-set:AttributeName = &quot;Real product value&quot;}
        valueReal : REAL := REAL#1.0; 
        {#ix-attr:[ComponentHeader()]}        
        {#ix-set:AttributeName = &quot;Dint sum value&quot;}
        valueDint : DINT:= DINT#0; 
    END_VAR
END_CLASS
</code></pre>
<p><strong>How to use <code>AxoComponent</code></strong></p>
<p>The instance of the extended <code>AxoComponent</code> must be defined inside the <code>AxoContext</code>.</p>
<pre><code class="lang-SmallTalk">.....................EXTENDS AxoContext
        VAR PUBLIC
            {#ix-set:AttributeName = &quot;Very simple component example with header only defined&quot;}
            MyComponentWithHeaderOnly : ComponentHeaderOnlyExample;  
        END_VAR
</code></pre>
<p>Inside the <code>Main()</code> method of the related <code>AxoContext</code> following rules must be applied. The <code>Initialize()</code> method of the extended instance of the <code>AxoComponent</code> must be called first.
The <code>Run()</code> method with the respective input and output variables must be called afterwards.</p>
<pre><code class="lang-SmallTalk">
</code></pre>

</article>

        <div class="contribution d-print-none">
          <a href="https://github.com/Inxton/AXOpen/blob/dev/src/data/ctrl/README.md/#L1" class="edit-link">Edit this page</a>
        </div>

        <div class="next-article d-print-none border-top" id="nextArticle"></div>

      </div>

      <div class="affix">
        <nav id="affix"></nav>
      </div>
    </main>

    <div class="container-xxl search-results" id="search-results"></div>

    <footer class="border-top text-secondary">
      <div class="container-xxl">
        <div class="flex-fill">
           Generated by DocFx. © 2023 MTS spol. s r.o., and awesome contributors
        </div>
      </div>
    </footer>
  </body>
</html>