<?xml version="1.0" encoding="UTF-8"?>        <rss version="2.0"
             xmlns:atom="http://www.w3.org/2005/Atom"
             xmlns:dc="http://purl.org/dc/elements/1.1/"
             xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
             xmlns:admin="http://webns.net/mvcb/"
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
             xmlns:content="http://purl.org/rss/1.0/modules/content/">
        <channel>
            <title>
									twinControls Forum - Recent Posts				            </title>
            <link>https://twincontrols.com/community/</link>
            <description>twinControls  Discussion Board</description>
            <language>en-US</language>
            <lastBuildDate>Thu, 23 Apr 2026 00:28:40 +0000</lastBuildDate>
            <generator>wpForo</generator>
            <ttl>60</ttl>
							                    <item>
                        <title>Advanced Interfaces: Functional Interfaces - Part 2 (Context &amp; Capturing)</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-2-context-capturing/#post-2305</link>
                        <pubDate>Wed, 31 Dec 2025 07:02:09 +0000</pubDate>
                        <description><![CDATA[In Part 1, we explored the concept of functional interfaces, where we used an interface with a single abstract method to pass logic around like a variable. We looked at a pure Aggregate  fun...]]></description>
                        <content:encoded><![CDATA[<p>In <a href="https://twincontrols.com/community/postid/2304/" target="_blank" rel="noopener">Part 1</a>, we explored the concept of <strong>functional interfaces</strong>, where we used an interface with a single abstract method to pass logic around like a variable. We looked at a pure <strong><em><span style="color: #000000">Aggregate</span></em></strong>  function that summed or multiplied values, or returned the largest value in an array.</p>
<p>Those examples were "stateless", meaning that the operations depended only on the arguments passed to them (<strong><em><span style="color: #000000">a</span></em></strong> and <strong><em><span style="color: #000000">b</span></em></strong> in <strong><em><span style="color: #000000">(a, b) =&gt; &lt;expression&gt;</span></em></strong>). In the real world, however, logic rarely exists in a vacuum. Functions often need <strong>context</strong>: thresholds, configuration values, or system parameters that aren't part of the function arguments themselves.</p>
<div>
<div><span>In modern languages like C#, Java, Python, and C++, this is solved through a concept called </span><span><strong>closures</strong></span><span> or </span><span><strong>lambda capturing</strong></span><span>. This is when a function "captures" variables from its surrounding scope so it can use them later, even after the original scope has ended.</span></div>
</div>
<div> </div>
<div>
<div>
<div><span>Here's an example in C++ that demonstrates capturing:</span></div>
<div>
<pre contenteditable="false">#include &lt;iostream&gt;

int main() 
{
    int scale = 10;
    
    // Capture by value (copy)
    auto scaleByValue = (int a, int b) { return (a + b) * scale; };

    // Capture by reference (observes changes)
    auto scaleByRef = (int a, int b) { return (a + b) * scale; };

    scale = 20;

    std::cout &lt;&lt; scaleByValue(1, 2) &lt;&lt; std::endl; // 30 (uses original scale = 10)
    std::cout &lt;&lt; scaleByRef(1, 2) &lt;&lt; std::endl;   // 60 (uses updated scale = 20)

    return 0;
}</pre>
</div>
</div>
</div>
<div>
<div>
<div><span>In this example:</span></div>
<div><span>- </span><span><strong><em><span style="color: #000000">scaleByValue</span></em></strong></span><span> captures </span><span><strong><em><span style="color: #000000">scale </span></em></strong></span><span><strong>by value</strong></span><span>, storing a copy of </span><span><strong><em><span style="color: #000000">10</span></em></strong></span><span> that won't change even when the original variable is modified.</span></div>
<div><span>- </span><span><strong><em><span style="color: #000000">scaleByRef</span></em></strong></span><span> captures </span><span><strong><em><span style="color: #000000">scale </span></em></strong></span><span><strong>by reference</strong></span><span>, observing changes to the original variable.</span></div>
<br />
<div><span>This flexibility allows functions to carry context with them, making them far more powerful and adaptable.</span></div>
<div> </div>
</div>
</div>
<div>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">The Challenge in Structured Text</span></h2>
</div>
<div>
<div>
<div> </div>
<div><span>Unfortunately, as discussed in <a href="https://twincontrols.com/community/postid/2304/" target="_blank" rel="noopener">Part 1</a></span><span>, ST doesn't support closures or lambda capturing. We can't create inline functions that automatically capture surrounding variables. However, we can achieve similar functionality using two approaches:</span></div>
</div>
</div>
<ol>
<li><strong>Function blocks with state</strong> - storing context as member variables</li>
<li>
<div><span><strong>Fluent interfaces</strong></span><span> - chainable methods that configure and return the function block</span></div>
</li>
</ol>
<p>The fluent interface approach is particularly elegant, as it allows us to configure operations inline, similar to how we'd use closures in modern languages.</p>
<p>&nbsp;</p>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Approach 1: Direct Configuration</span></h2>
<p>&nbsp;</p>
<div>
<div><span>Let's start with the straight-forward approach of configuring function blocks before use:</span></div>
</div>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_SumIfInRangeFunction IMPLEMENTS I_BiFunction
    VAR_INPUT
        nLowerThreshold,
        nUpperThreshold : INT;
    END_VAR

    METHOD Apply : INT
        VAR_INPUT
            nA, nB : INT;
        END_VAR

        // Only add nB if it's within the range
        IF nB &gt;= nLowerThreshold AND nB &lt;= nUpperThreshold THEN
            Apply := nA + nB;
        ELSE
            Apply := nA;
        END_IF
    END_METHOD
END_FUNCTION_BLOCK</pre>
<p>&nbsp;</p>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Example Usage</span></h4>
<p>&nbsp;</p>
<pre contenteditable="false">PROGRAM P_Example2_Direct
VAR
    arNumbers       : ARRAY OF INT := ;
    fbSum           : FB_SumIfInRangeFunction;
    nFilteredSum    : INT;
END_VAR

// Configure the thresholds
fbSum.nLowerThreshold := 10;
fbSum.nUpperThreshold := 20;

// Apply operation
nFilteredSum := P_Operations.Aggregate(arNumbers, fbSum);
// Result: 15 + 12 + 19 = 46 (8 and 23 are excluded)</pre>
<p>&nbsp;</p>
<div>
<div><span>This works, but it's limiting and requires separate configuration steps. We can do better.</span></div>
</div>
<p>&nbsp;</p>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Approach 2: Fluent Interface (Method Chaining)</span></h2>
<p>&nbsp;</p>
<p>A <strong>fluent interface</strong> allows us to chain method calls together, configuring the function block inline. The key is that configuration methods return a reference to the function block itself (<span><strong><em><span style="color: #000000">THIS^</span></em></strong></span>), enabling multiple calls to be chained together.</p>
<div><br />
<div><span>By defining separate interfaces for different configuration capabilities, we can create a flexible and type-safe fluent API that guides developers toward correct usage.</span></div>
<div> </div>
<div>First, let's define interfaces that represent different configuration capabilities:</div>
</div>
<pre contenteditable="false">INTERFACE I_GreaterThanCondition
    METHOD AnyGreaterThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
    END_METHOD
END_INTERFACE</pre>
<pre contenteditable="false">INTERFACE I_LessThanCondition
    METHOD AnyLessThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
    END_METHOD
END_INTERFACE</pre>
<pre contenteditable="false">INTERFACE I_InRangeCondition
    METHOD AnyInBetween : I_BiFunction
        VAR_INPUT
            nLowerThreshold, nUpperThreshold : INT;
        END_VAR
    END_METHOD
END_INTERFACE</pre>
<div>
<div><span>Now we can implement a function block that supports multiple configuration interfaces: </span></div>
</div>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_SumFunction 
IMPLEMENTS I_BiFunction, I_GreaterThanCondition, I_LessThanCondition, I_InRangeCondition
    VAR_STAT CONSTANT
        _nMIN_INT : INT := -32768;
        _nMAX_INT : INT := 32767;
    END_VAR
    VAR
        _nLowerThreshold : INT := _nMIN_INT;
        _nUpperThreshold : INT := _nMAX_INT;;
    END_VAR
    
    // Sets the minimum threshold (inclusive)
    // Values must be GREATER THAN OR EQUAL to this threshold
    METHOD AnyGreaterThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
        AnyGreaterThan   := THIS^;

        _nLowerThreshold := nThreshold;
        _nUpperThreshold := _nMAX_INT;
    END_METHOD

    // Sets the maximum threshold (inclusive)
    // Values must be LESS THAN OR EQUAL to this threshold
    METHOD AnyLessThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
        AnyLessThan      := THIS^;

        _nLowerThreshold := _nMIN_INT;
        _nUpperThreshold := nThreshold;
    END_METHOD

    // Sets the lower and upper threshold (inclusive)
    // Values must be BETWEEN these thresholds
    METHOD AnyInBetween : I_BiFunction
        VAR_INPUT
            nLowerThreshold, nUpperThreshold : INT;
        END_VAR
        AnyInBetween     := THIS^;

        _nLowerThreshold := nLowerThreshold;
        _nUpperThreshold := nUpperThreshold;
    END_METHOD

    // Resets the configuration so that all values are allowed
    METHOD Everything : I_BiFunction
        VAR_INPUT
        END_VAR
        Everything := THIS^;

        _nLowerThreshold := _nMIN_INT;
        _nUpperThreshold := _nMAX_INT;
    END_METHOD

    METHOD Apply : INT
        VAR_INPUT
            nA, nB : INT;
        END_VAR
        // Only add nB if it's within the configured range
        IF nB &gt;= _nLowerThreshold AND nB &lt;= _nUpperThreshold THEN 
            Apply := nA + nB;
        ELSE
            Apply := nA;
        END_IF
    END_METHOD
END_FUNCTION_BLOCK</pre>
<p>&nbsp;</p>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Example Usage</span></h4>
<p>&nbsp;</p>
<div>
<div><span>Now we can configure and use operations in clean, readable expressions:</span></div>
<div>
<pre contenteditable="false">ROGRAM P_Example2_Fluent
VAR
    arNumbers        : ARRAY OF INT := ;
    fbSum            : FB_SumFunction;
    nFilteredSum1,
    nFilteredSum2,
    nFilteredSum3    : INT;
END_VAR

// Configure and apply operations inline
nFilteredSum1 := P_Operations.Aggregate(arNumbers, fbSum.AnyLessThan(20));
// Result: 15 + 8 + 12 + 19 = 54 (23 is excluded)

nFilteredSum2 := P_Operations.Aggregate(arNumbers, fbSum.AnyGreaterThan(10));
// Result: 15 + 23 + 12 + 19 = 69 (8 is excluded)

nFilteredSum3 := P_Operations.Aggregate(arNumbers, fbSum.AnyInBetween(10, 20));
// Result: 15 + 12 + 19 = 46 (8 and 23 are excluded)

nSum          := P_Operations.Aggregate(arNumbers, fbSum.Everything());
// Result: 15 + 8 + 23 + 12 + 19 = 77 (all values are included)</pre>
</div>
</div>
<p>&nbsp;</p>
948
<p>&nbsp;</p>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Benefits of the Fluent Approach</span></h4>
<p>&nbsp;</p>
<div>
<div>
<div>
<div><span>The fluent interface pattern provides several advantages:</span></div>
<br />
<ol>
<li><span><strong>Readability</strong></span><span>: Configuration reads like natural language</span></li>
<li><span><strong>Type Safety</strong></span><span>: Each interface clearly defines what operations are available</span></li>
<li><span><strong>Inline Configuration</strong></span><span>: No need for separate setup steps</span></li>
<li><span><strong>Discoverability</strong></span><span>: Separate interfaces guide developers through available options</span></li>
<li><span><strong>Immutability Simulation</strong></span><span>: Each call appears to create a configured version without mutating the original (though technically it does modify the instance)</span></li>
<li><span><strong>Composability</strong></span><span>: Easy to build complex behaviors from simple building blocks</span></li>
</ol>
</div>
</div>
</div>
<div> </div>
<div>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Real World Applications</span></h2>
</div>
<div>
<div>
<div> </div>
</div>
</div>
<div>
<div><span>Context-aware operations with fluent interfaces are invaluable across many automation scenarios:</span></div>
</div>
<p><strong>Data Transformation &amp; Mapping</strong></p>
<pre contenteditable="false">// Transform raw ADC values to engineering units with calibration offset
fCalibratedTemps := P_DataTransform.Map(
    nRawSensorData,
    fbADCToTemp.WithOffset(nZeroOffset).WithGain(fCalibrationGain)
);</pre>
<p><strong>Filtering &amp; Selection</strong></p>
<pre contenteditable="false">// Select production batches exceeding quality threshold
nCount := P_DataFilter.Filter(
    arAllBatches,
    fbQualityCheck
        .AnyGreaterThan(nPremiumThreshold)
        .WithMargin(fSafetyMargin),
    arPremiumBatches
);

// Find active alarms above critical severity
nCount := P_DataFilter.Filter(
    arAlarmList,
    fbAlarmFilter
        .AnyGreaterThan(E_Severity.High)
        .IsActive()
        .NotAcknowledged(),
    arCriticalAlarms
);</pre>
<p><strong>Validation &amp; Predicates</strong></p>
<pre contenteditable="false">// Verify all safety sensors are within safe range
bSystemSafe := P_SafetyCheck.Every(
    arSafetySensors,
    fbSafetyValidator
        .AnyInBetween(nSafeMin, nSafeMax)
        .WithHysteresis(nHysteresisBand)
);</pre>
<p><strong>Sorting &amp; Ranking</strong></p>
<pre contenteditable="false">// Sort machines by efficiency, excluding standby units
P_EquipmentSort.Sort(
    arMachines,
    fbEfficiencyCompare.AnyGreaterThan(nMinEfficiency).ByDescending()
);

// Rank production runs by yield within quality band
P_BatchSort.Sort(
    arProductionRuns,
    fbYieldCompare.AnyInBetween(nMinQuality, nMaxQuality).ByYield()
);</pre>
<p><strong>Search &amp; Analysis</strong></p>
<pre contenteditable="false">// Find first sensor reading exceeding alarm threshold
ipFirstAlarm := P_DataSearch.Find(
    arSensorReadings,
    fbThresholdCheck.AnyGreaterThan(nAlarmThreshold).Confirmed(T#2s)
);

// Identify optimal batch by cost-to-quality ratio
ipBestBatch := P_BatchAnalysis.FindOptimal(
    arBatches,
    fbCostAnalysis.AnyGreaterThan(nMinYield).WithQualityWeight(0.6)
);</pre>
<p><strong>Statistical Aggregation</strong></p>
<pre contenteditable="false">// Calculate weighted average excluding statistical outliers
fWeightedAvg := P_Statistics.Aggregate(
    arMeasurements,
    fbWeightedAvg
        .AnyInBetween(fMean - 3*fStdDev, fMean + 3*fStdDev)
        .WithWeights(arWeights)
);

// Compute RMS vibration in bearing frequency range
fBearingVibration := P_VibrationAnalysis.Aggregate(
    arFFTData,
    fbRMS
        .AnyInBetween(fBearingFreqLow, fBearingFreqHigh)
        .WithHanningWindow()
);</pre>
<div>
<div><span>The key advantage across all these scenarios is that </span><span><strong>different functional interfaces</strong></span><span> (</span><span><strong><em><span style="color: #000000">Map</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Filter</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Every</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Some</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">None</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Sort</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Find</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Aggregate</span></em></strong></span><span>) provide the appropriate abstraction for each use case, while fluent configuration makes the code expressive and maintainable.</span></div>
</div>
<div> </div>
<div>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Conclusion</span></h2>
</div>
<div>
<div>
<div> </div>
</div>
</div>
<div>
<div><span>While Structured Text doesn't support closures or lambda capturing, we can achieve remarkably similar functionality using function blocks with fluent interfaces. By:</span></div>
<br />
<ol>
<li><span><strong>Storing context as member variables</strong></span><span> within function blocks</span></li>
<li><span><strong>Exposing configuration through dedicated interfaces</strong></span><span> for type safety and discoverability</span></li>
<li><span><strong>Returning references to the functional interface</strong></span><span> (</span><span><strong><em><span style="color: #000000">THIS^</span></em></strong></span><span>) to enable inline configuration</span></li>
</ol>
<br />
<div><span>We create expressive, readable code that rivals modern functional programming languages. The fluent interface pattern provides:</span></div>
<br />
<ul>
<li><span><strong>Inline configuration</strong></span><span> that mimics closure capturing</span></li>
<li><span><strong>Type-safe composition</strong></span><span> through interface segregation</span></li>
<li><span><strong>Natural, readable syntax</strong></span><span> that expresses intent clearly</span></li>
<li><span><strong>Flexible, reusable components</strong></span><span> that adapt to different contexts</span></li>
</ul>
<br />
<div><span>This approach bridges the gap between traditional PLC programming and modern functional paradigms, bringing greater modularity, maintainability, and expressiveness to industrial automation code without sacrificing the determinism and reliability that automation systems demand.</span></div>
<br />
<div><span>In Part 3, we'll explore how to extend this pattern further with </span><span><strong>function composition</strong></span><span> and </span><span><strong>higher-order functions</strong></span><span>, building even more powerful abstractions that allow us to combine simple operations into complex processing pipelines.</span></div>
</div>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>FisoThemes</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-2-context-capturing/#post-2305</guid>
                    </item>
				                    <item>
                        <title>Advanced Interfaces: Functional Interfaces - Part 1</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-1/#post-2304</link>
                        <pubDate>Wed, 24 Dec 2025 03:53:36 +0000</pubDate>
                        <description><![CDATA[Lately, I’ve been thinking a lot about how to abstract complexity and improving the flexibility of code in industrial automation systems. With systems growing in size and complexity, it&#039;s im...]]></description>
                        <content:encoded><![CDATA[<p class="code-line" dir="auto" data-line="2">Lately, I’ve been thinking a lot about how to abstract complexity and improving the flexibility of code in industrial automation systems. With systems growing in size and complexity, it's important to find a balance between control and modularity. I’ve been exploring different approaches to achieve this, and I decided to start by talking about<span> </span><strong>functional interfaces</strong><span> </span>- a powerful tool that can help you break down large systems into smaller, reusable components.</p>
<p class="code-line" dir="auto" data-line="4">Many modern programming languages, like Rust, Java, Python, or C#, have what is known as<span> </span><strong>first-class functions</strong>. These are functions that can be passed around just like variables, meaning they can be assigned to variables, passed as arguments to other functions, or even returned as values from functions. This flexibility allows for more dynamic and reusable code. This is the fundamental concept behind<span> </span><strong>lambdas</strong>,<span> </span><strong>closures</strong>, and<span> </span><strong>anonymous functions</strong>, which are compact ways to define behaviour on the fly without needing to declare a full function or method. By embedding logic directly where it’s needed, they allow developers to write cleaner, more concise, and more modular code.</p>
<p class="code-line code-active-line" dir="auto" data-line="6">Here’s an example of an anonymous function in C# that reduces a list of numbers:</p>
<pre contenteditable="false">using System;
using System.Linq;

int[] numbers = {2, 1, 3, 5, 4};

// Using an anonymous function to sum the array
int sum = numbers.Aggregate((a, b) =&gt; a + b);

// Using an anonymous function to get the product of the array
int product = numbers.Aggregate((a, b) =&gt; a * b);

// Output: 15
Console.WriteLine(sum);

// Output: 120
Console.WriteLine(product);</pre>
<p dir="auto" data-line="6"> </p>
<p class="code-line" dir="auto" data-line="26">In this example, the <strong><em><span style="color: #000000">Aggregate</span></em></strong> method uses a lambda expression to define how two numbers should be combined, either summing (<strong><em><span style="color: #000000">(a, b) =&gt; a + b</span></em></strong>) or multiplying (<strong><em><span style="color: #000000">(a, b) =&gt; a * b</span></em></strong>) the values. The power here is that the <strong><em><span style="color: #000000">Aggregate</span></em></strong> <strong>method itself is decoupled from the specific operation</strong>. It doesn’t care whether you’re summing or multiplying numbers. This makes the logic highly reusable and flexible, allowing the function to process data in different ways based on the behaviour you pass in.</p>
<p class="code-line" dir="auto" data-line="28">Unfortunately, Structured Text (ST) doesn’t have first-class functions (<a href="https://stackoverflow.com/questions/43139073/how-to-create-pointer-to-function-in-codesys-v3" data-href="https://stackoverflow.com/questions/43139073/how-to-create-pointer-to-function-in-codesys-v3">sort of...</a>), but we can still introduce some of these principles through functional interfaces. Although ST doesn’t support lambdas, closures, or anonymous functions, functional interfaces can give us a way to mimic some of this functionality.</p>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">What is a Functional Interface?</span></h2>
<p class="code-line" dir="auto" data-line="32">A functional interface is an interface that contains exactly<span> </span><strong>one</strong><span> </span>abstract method. This single-method contract allows for a concise and focused interaction between components, making it ideal for situations where you need to define a single behaviour or action. While functional interfaces can have other members like default methods or constants (these aren't supported in ST), they are designed around the core idea of<span> </span><strong>one abstract method</strong>, ensuring they remain lightweight and purpose-driven.</p>
<p class="code-line" dir="auto" data-line="34">Here's an example of a functional interface in Java:</p>
<pre contenteditable="false">@FunctionalInterface
public interface BiFunction&lt;T, U, R&gt; {
     R apply(T t, U u); 
}</pre>
<p class="code-line" dir="auto" data-line="34"> </p>
<p class="code-line" dir="auto" data-line="42">This<span> <strong><em><span style="color: #000000">BiFunction</span></em></strong><b><i> </i></b></span>interface represents a function that accepts two arguments (<span><strong><em><span style="color: #000000">T</span></em></strong><b><i> </i></b></span><b><i> </i></b>and<span> <b><i><strong><em><span style="color: #000000">U</span></em></strong> </i></b></span>) and returns a result (<b><i><span><strong><em><span style="color: #000000">R</span></em></strong></span></i></b>). The <strong><em><span style="color: #000000">Apply</span></em></strong><span><b><i> </i></b></span>method is the single abstract method that makes this a functional interface.</p>
<p class="code-line" dir="auto" data-line="44">Here's an example of using this interface:</p>
<pre contenteditable="false">import java.util.function.BiFunction;

public class Main
{
    public static void main(String[] args) {
        // Define a BiFunction that adds two integers
        BiFunction&lt;Integer, Integer, Integer&gt; foo = (a, b) -&gt; a + b;

        // Invoke the BiFunction to add two integers
        Integer result = foo.apply(2, 3);

        // Output: 5
        System.out.println(result);
    }
}</pre>
<p class="code-line" dir="auto" data-line="34"><br /><span>In this example, we create a <strong><em><span style="color: #000000">BiFunction</span></em></strong><b><i> </i></b>to add two integers. The lambda expression <strong><em><span style="color: #000000">(a, b) =&gt; a + b </span></em></strong></span><span>defines the behaviour, and the <b><i>apply </i></b></span><span>method calls the function with the specified arguments.<br /></span></p>
<h2 id="application-in-industrial-automation" class="code-line" dir="auto" data-line="65"><span style="font-size: 18pt">Application in Industrial Automation</span></h2>
<p class="code-line" dir="auto" data-line="67">In<span> </span><strong>automation systems</strong>, functional interfaces can be used to define well-scoped behaviours that can be applied across different components or modules. By encapsulating specific functionality within a clear, single-purpose interface, functional interfaces help make systems easier to maintain, extend, and understand. This modularity also enables greater flexibility when it comes to introducing new behaviours or modifying existing ones without affecting the overall system.</p>
<p class="code-line" dir="auto" data-line="69">In this section, I’ll walk you through a simple example that demonstrate the use of functional interfaces in Codesys/TwinCAT's implementation of the IEC 61131-3 Structured Text language. I’ll be replicating the aggregate function discussed earlier <span>to perform operations like summing and finding the maximum in an array of numbers.</span></p>
<h4 dir="auto" data-line="75"> </h4>
<h4 id="step-1-define-the-functional-interface" class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Define the Functional Interface</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p class="code-line" dir="auto" data-line="34"><span>First, let's define the <strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b>interface that will serve as a blueprint for any function that performs an operation on two integers and returns an integer result:<br /></span></p>
<pre contenteditable="false">INTERFACE I_BiFunction
    METHOD Apply : INT 
    VAR_INPUT 
        nA, nB : INT;
    END_VAR 
END_INTERFACE</pre>
<p class="code-line" dir="auto" data-line="34"><span>This interface contains a single method, <strong><em><span style="color: #000000">Apply</span></em></strong><b><i> </i></b>, which takes two integers as inputs (<strong><em><span style="color: #000000">nA</span></em></strong><b><i> </i></b><b><i>, <strong><em><span style="color: #000000">nB</span></em></strong> </i></b>) and returns an integer result.</span></p>
<h4 dir="auto" data-line="75"> </h4>
<h4 class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Implement a Method that Utilises the Functional Interface</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p class="code-line" dir="auto" data-line="34"><span>Next, we’ll create the <strong><em><span style="color: #000000">P_Operations</span></em></strong><b><i> </i></b> program that contains a method called <strong><em><span style="color: #000000">Aggregate</span></em></strong>. This method will iterate over an array of integers and apply the operation defined by the <strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b>interface to aggregate the values in the supplied array.<br /></span></p>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this program directly is not allowed'}
PROGRAM P_Operations
    METHOD Aggregate : INT
    VAR_IN_OUT CONSTANT
        {warning disable C0228}
        arNumbers : ARRAY  OF INT;
    END_VAR
    VAR_INPUT
        ipOperation : I_BiFunction;
    END_VAR
    VAR
        i : __XINT;
    END_VAR

    // Exit the function call if the operation is not supplied.
    IF ipOperation = 0 THEN RETURN; END_IF

    // Initialise the result with the first element of the array.
    Aggregate := arNumbers;

    // Loop through the array and apply the operation defined by the interface.
    FOR i := LOWER_BOUND(arNumbers, 1) + 1 TO UPPER_BOUND(arNumbers, 1) DO
        Aggregate := ipOperation.Apply(Aggregate, arNumbers);
    END_FOR

    END_METHOD
END_PROGRAM</pre>
<h4 id="explanation" class="code-line" dir="auto" data-line="121">Explanation:</h4>
<ul class="code-line" dir="auto" data-line="123">
<li class="code-line" dir="auto" data-line="123">
<p class="code-line" dir="auto" data-line="123">The <span><strong><em><span style="color: #000000">ipOperations</span></em></strong><b><i> </i></b> </span>input parameter is an instance of the <span><strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b></span>interface, which defines the operation to be applied (such as summing or multiplying).</p>
</li>
<li class="code-line" dir="auto" data-line="125">
<p class="code-line" dir="auto" data-line="125">The method initialises the result (<span><strong><em><span style="color: #000000">Aggregate</span></em></strong></span>) with the first element of the array.</p>
</li>
<li class="code-line" dir="auto" data-line="127">
<p class="code-line" dir="auto" data-line="127">It then iterates through the rest of the array, applying the operation (via <span><strong><em><span style="color: #000000">ipOperations.Apply(...)</span></em></strong></span>) to the running result and each element of the array.</p>
</li>
</ul>
<h4 dir="auto" data-line="75"> </h4>
<h4 class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Implementing the Operations</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p><span>Now, let’s implement specific operations by creating function blocks that implement the <strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b> interface. We will use these to perform different actions on the array elements.</span></p>
<h4 id="product-operation" class="code-line" dir="auto" data-line="133">Product Operation</h4>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_ProductFunction IMPLEMENTS I_BiFunction
    METHOD Apply : INT
    VAR_INPUT
        nA, nB : INT;
    END_VAR

    // Return the product of two values
    Apply := nA * nB;

    END_METHOD
END_FUNCTION_BLOCK</pre>
<h4 id="maximum-value-operation" class="code-line" dir="auto" data-line="150">Maximum Value Operation</h4>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_MaximumValueFunction IMPLEMENTS I_BiFunction
    METHOD Apply : INT
    VAR_INPUT
        nA, nB : INT;
    END_VAR

    // Return the maximum of two values
    Apply := MAX(nA, nB);

    END_METHOD
END_FUNCTION_BLOCK</pre>
<h4 dir="auto" data-line="75"> </h4>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Example Usage</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p class="code-line" dir="auto" data-line="34"><span>Now that we've defined the functional interface and its implementations, we can use the <strong><em><span style="color: #000000">P_Operations</span></em></strong><b><i> </i></b>program to apply different operations to an array of numbers.<br /></span></p>
<pre contenteditable="false">PROGRAM P_Example1
VAR
    nProduct, 
    nLargest    : INT;
    arNumbers   : ARRAY OF INT := ;
    fbProduct   : FB_ProductFunction;
    fbLargest   : FB_MaximumValueFunction;
END_VAR

nProduct := P_Operations.Aggregate(arNumbers, fbProduct);
nLargest := P_Operations.Aggregate(arNumbers, fbLargest);</pre>
<p class="code-line" dir="auto" data-line="34"><span> </span></p>
947
<h4 dir="auto" data-line="75"> </h4>
<h4 id="step-1-define-the-functional-interface" class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Real World Applications</span></h4>
<div>
<div> </div>
<div><span>Here are some practical examples of how functional interfaces shine in industrial automation:</span></div>
</div>
<div> </div>
<div><strong>Data Processing</strong></div>
<div>
<pre contenteditable="false">// Transform sensor data through different conversion functions
fCelsius    := P_DataTransform.Map(nRawSensorData, fbADCToCelsius);
fFahrenheit := P_DataTransform.Map(nRawSensorData, fbADCToFahrenheit);</pre>
</div>
<div> </div>
<div><strong>Batch Operations</strong></div>
<div>
<pre contenteditable="false">// Apply different operations to production batches
bAllPassed := P_BatchProcessor.Every(arQualityChecks, fbMeetsStandard);
bAnyFailed := P_BatchProcessor.Some(arQualityChecks, fbBelowThreshold);</pre>
</div>
<div> </div>
<div><strong>Validation and Filtering</strong></div>
<div>
<pre contenteditable="false">// Filter arrays based on different validation criteria
// Filter(&lt;source&gt;, &lt;predicate&gt;, &lt;destination&gt;) -&gt; &lt;Count&gt;
nCount := P_DataFilter.Filter(arSensorData, fbWithinTolerance, arValidReadings);
nCount := P_DataFilter.Filter(arSensorData, fbOutsideExpected, arOutliers);
nCount := P_DataFilter.Filter(arAlarms, fbHighSeverity, arCritical);</pre>
</div>
<div> </div>
<div><strong>Validation and Filtering</strong></div>
<div>
<pre contenteditable="false">// Sort machine data by different criteria
P_DataSort.Sort(arMachines, fbByEfficiency);
P_DataSort.Sort(arMachines, fbByUptime);
P_DataSort.Sort(arMachines, fbByProductionCount);</pre>
</div>
<p class="code-line" dir="auto" data-line="34">The key advantage here is that the processing logic (<strong><em><span style="color: #000000">Aggregate</span></em></strong>, <strong><em><span style="color: #000000">Map</span></em></strong>, <strong><em><span style="color: #000000">Filter</span></em></strong>, etc.) remains unchanged while the behaviour is completely customisable through different function block implementations.<span></span></p>
<h2 id="application-in-industrial-automation" class="code-line" dir="auto" data-line="65"><span style="font-size: 18pt">Conclusion</span></h2>
<p class="code-line" dir="auto" data-line="220">Functional interfaces bring a powerful abstraction mechanism to Structured Text programming. While ST lacks first-class functions, lambdas, and closures, functional interfaces allow us to:</p>
<ol class="code-line" dir="auto" data-line="222">
<li class="code-line" dir="auto" data-line="222">
<p class="code-line" dir="auto" data-line="222"><strong>Decouple algorithms from operations</strong>: The <strong><em><span style="color: #000000">Aggregate</span></em></strong> method doesn't know or care whether it's summing, multiplying, or finding maximums. It just applies the provided operation.</p>
</li>
<li class="code-line" dir="auto" data-line="224">
<p class="code-line" dir="auto" data-line="224"><strong>Increase code reusability</strong>: Write the processing logic once, then reuse it with countless different behaviors by simply implementing new function blocks.</p>
</li>
<li class="code-line" dir="auto" data-line="226">
<p class="code-line" dir="auto" data-line="226"><strong>Improve testability</strong>: Each operation is encapsulated in its own function block, making it easy to test in isolation.</p>
</li>
<li class="code-line" dir="auto" data-line="228">
<p class="code-line" dir="auto" data-line="228"><strong>Enhance maintainability</strong>: Changes to specific operations don't affect the core processing logic, and vice versa.</p>
</li>
<li class="code-line" dir="auto" style="text-align: left" data-line="230">
<p class="code-line" dir="auto" data-line="230"><strong>Create more expressive code</strong>: The intent becomes clear when you read <strong><em><span style="color: #000000">P_Operations.Aggregate(arNumbers, fbProduct) </span></em></strong>versus a hardcoded multiplication loop.</p>
</li>
</ol>
<p class="code-line" dir="auto" data-line="230">While we've focused on simple, stateless operations in this part, functional interfaces become even more powerful when combined with context and state. In <a href="https://twincontrols.com/community/postid/2305/" target="_blank" rel="noopener">Part 2</a>, we'll explore how to add <strong>context and capturing</strong> to our functional interfaces, allowing operations to carry configuration and state-mimicking the closure behaviour found in modern programming languages.</p>
<div>
<div><span>This approach bridges the gap between traditional PLC programming and modern software engineering practices, allowing for greater flexibility and maintainability in industrial automation systems without sacrificing the determinism and reliability that automation demands.</span></div>
</div>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>FisoThemes</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-1/#post-2304</guid>
                    </item>
				                    <item>
                        <title>RE: Twincat4026, Running Inside dockerized Windows11, Access via Mstsc</title>
                        <link>https://twincontrols.com/community/twincat-tips-tricks/twincat4026-running-inside-dockerized-windows11-access-via-mstsc/#post-2294</link>
                        <pubDate>Wed, 19 Nov 2025 07:38:02 +0000</pubDate>
                        <description><![CDATA[A lot has changed since the last post.I now run HyperV Win11 with the User Mode Runtime, the works well.
Probably a much simpler solution]]></description>
                        <content:encoded><![CDATA[<p>A lot has changed since the last post.<br />I now run HyperV Win11 with the User Mode Runtime, the works well.</p>
<p>Probably a much simpler solution</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>RomanG</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-tips-tricks/twincat4026-running-inside-dockerized-windows11-access-via-mstsc/#post-2294</guid>
                    </item>
				                    <item>
                        <title>MMOexp Poe 2 offering a detailed look at skills</title>
                        <link>https://twincontrols.com/community/lounge/mmoexp-poe-2-offering-a-detailed-look-at-skills/#post-2283</link>
                        <pubDate>Fri, 14 Nov 2025 01:37:59 +0000</pubDate>
                        <description><![CDATA[Path of Exile 2 (PoE 2) continues the legacy of its predecessor with deeper mechanics, more complex builds, and a world teeming with challenge. One of the most iconic and flexible classes in...]]></description>
                        <content:encoded><![CDATA[<p>Path of Exile 2 (PoE 2) continues the legacy of its predecessor with deeper mechanics, more complex builds, and a world teeming with challenge. One of the most iconic and flexible classes in PoE 2 is the Witch, known for her potent spellcasting abilities and mastery over elements, summons, and arcane energy. Whether you're new to PoE 2 or a seasoned player looking to optimize your leveling journey, a well-crafted Witch build can take you from the start of the game all the way through to endgame content.</p>
<p>&nbsp;</p>
<p>This guide will walk you through the best Witch leveling build for PoE 2, offering a detailed look at skills, passive tree progression, gear recommendations, and general tips for efficient leveling. By following this guide, you'll be able to speed through the early stages of the game, progress quickly through Acts, and lay the foundation for an effective Witch build in the late game.</p>
<p>&nbsp;</p>
<p>Overview of the Witch Class in PoE 2</p>
<p>&nbsp;</p>
<p>The Witch is a powerful spellcaster who specializes in intelligence-based skills, manipulating elemental forces, summoning minions, and manipulating arcane energy. In Path of Exile 2, the Witch's versatility is one of her standout features. Her skill tree offers various paths, including Fire, Cold, Lightning, and Necromancy, which all provide unique playstyles for leveling and endgame content.</p>
<p>&nbsp;</p>
<p>While other classes may focus on brute force or tanking, the Witch excels at dealing massive elemental damage, summoning hordes of minions to do her bidding, and providing versatile defensive mechanics through shields or energy. When leveling your Witch, your goal will be to balance damage output, survivability, and movement speed to clear content efficiently.</p>
<p>&nbsp;</p>
<p>Choosing the Best Witch Leveling Build in PoE 2</p>
<p>&nbsp;</p>
<p>When deciding on the best Witch build for leveling, it's crucial to pick a build that combines damage with speed to clear early content. While you can branch out into more specialized builds later in the game, starting with something that scales well throughout the acts will ensure you don't hit roadblocks in your progress.</p>
<p>Poe 2 trade was amazing. He made my deal go seamlessly. He was professional and friendly. Would absolutely buy from again! You can also purchase it at MMOEXP.com</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>BennieDe</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/lounge/mmoexp-poe-2-offering-a-detailed-look-at-skills/#post-2283</guid>
                    </item>
				                    <item>
                        <title>MMOexp Diablo4 on supporting abilities to soften up enemies</title>
                        <link>https://twincontrols.com/community/lounge/mmoexp-diablo4-on-supporting-abilities-to-soften-up-enemies/#post-2282</link>
                        <pubDate>Fri, 14 Nov 2025 01:37:18 +0000</pubDate>
                        <description><![CDATA[In Diablo 4, the Barbarian is a brutal powerhouse known for its raw physical damage, tanking ability, and control over the battlefield. With the right build, Barbarians can become nearly uns...]]></description>
                        <content:encoded><![CDATA[<p>In Diablo 4, the Barbarian is a brutal powerhouse known for its raw physical damage, tanking ability, and control over the battlefield. With the right build, Barbarians can become nearly unstoppable forces of nature. Among the various builds available, the Rupture Barbarian Build stands out as one of the most exciting and powerful, centered around the devastating Rupture skill. This build is designed to deal massive burst damage, especially to enemies who are already wounded, and it excels in both single-target and AoE (area-of-effect) damage.<br /><br />In this guide, we'll break down how to effectively build and play a Rupture Barbarian in Diablo 4, covering essential skills, stat priorities, gear recommendations, and strategies to maximize your damage output.<br /><br />What is the Rupture Barbarian Build?<br /><br />The Rupture Barbarian Build revolves around the Rupture skill, which is a unique finisher ability in Diablo 4. Rupture becomes available once your enemies are reduced to a low health threshold, and the skill causes them to explode, dealing massive damage to both the target and nearby enemies.<br /><br />While the Rupture skill itself deals enormous damage, the Rupture Barbarian Build also relies on supporting abilities to soften up enemies and make the most of Rupture's explosive potential. These supporting skills help maintain aggro, provide crowd control, boost your damage, and enhance your survivability, ensuring that you're always in the right position to trigger a devastating Rupture.<br /><br />The key to success with this build is managing resource generation, enemy positioning, and keeping your foes at a low enough health to ensure the Rupture explosion hits as hard as possible.<br /><br />Key Skills for the Rupture Barbarian Build<br /><br />The Rupture Barbarian Build uses a combination of core offensive and defensive skills to enable smooth execution of its high-damage rotations. Here's a breakdown of the essential skills for this build:<br /><br />1. Rupture<br /><br />Rupture is the signature skill for this build, and it's responsible for the massive burst damage. The skill causes an explosion of damage when an enemy's health drops below a certain threshold. The more health an enemy has left when they're ruptured, the higher the damage dealt.<br /><br />Key Benefit: It's an incredibly satisfying ability that lets you finish off enemies with a huge damage spike, especially when used after softening enemies with other abilities.<br /><br />2. Whirlwind<br /><br />Whirlwind is the primary AoE damage skill in this build. While Rupture targets individual enemies, Whirlwind allows you to deal continuous damage to multiple enemies at once, helping to quickly reduce their health to the threshold required for Rupture to trigger.<br /><br />Key Benefit: It provides consistent damage and crowd control while you're positioning yourself for the finishing blow with Rupture. Whirlwind is ideal for clearing out mobs, allowing you to set up a devastating Rupture explosion for any enemies that survive.</p>
<p>MMOexp.com provides high quality and cheap D4 gold Softcore/Hardcore with fast delivery and 24/7 online. Welcome to buy Diablo IV gold/Items for sale to enhance your adven.</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>BennieDe</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/lounge/mmoexp-diablo4-on-supporting-abilities-to-soften-up-enemies/#post-2282</guid>
                    </item>
				                    <item>
                        <title>MMOexp FC26 to climb the ranks</title>
                        <link>https://twincontrols.com/community/lounge/mmoexp-fc26-to-climb-the-ranks/#post-2281</link>
                        <pubDate>Fri, 14 Nov 2025 01:36:08 +0000</pubDate>
                        <description><![CDATA[In EA FC 26, central midfielders (CMs) are often the heartbeat of a team. They control the tempo of the game, dictate passes, break up opposition attacks, and provide both defensive stabilit...]]></description>
                        <content:encoded><![CDATA[<p>In EA FC 26, central midfielders (CMs) are often the heartbeat of a team. They control the tempo of the game, dictate passes, break up opposition attacks, and provide both defensive stability and attacking creativity. Whether you're building your dream team in Career Mode or aiming to climb the ranks with a lower-league side, selecting the right central midfielders can make all the difference. The right blend of technical ability, physicality, and mental attributes is crucial for success, and EA FC 26 gives players a wealth of options to choose from. Here, we'll explore some of the best central midfielders you can target in Career Mode, whether you're looking for established stars or up-and-coming talent.</p>
<p>&nbsp;</p>
<ol>
<li>Kevin De Bruyne (OVR 91)</li>
</ol>
<p>&nbsp;</p>
<p>It's hard to discuss central midfielders in EA FC 26 without mentioning Kevin De Bruyne. The Belgian playmaker is a consistent performer in the game and is arguably one of the most complete midfielders in the game. With 91 overall, his vision, passing, and dribbling are exceptional, and he is a maestro in the middle of the park. De Bruyne's passing range is phenomenal, able to thread through balls to your forwards with pinpoint accuracy. His ability to dictate the tempo and create chances makes him a must-have for teams with ambitions of winning the league or even the Champions League.</p>
<p>&nbsp;</p>
<p>In Career Mode, he's a great addition if you're looking for a player who can control the game and provide assists, though his age (32) and high price tag (around £60 million) mean he may be a more feasible option for bigger clubs rather than lower-league teams.</p>
<p>&nbsp;</p>
<p>Key Stats: Passing 92, Vision 91, Dribbling 87, Stamina 77</p>
<p>&nbsp;</p>
<ol start="2">
<li>Luka Modrić (OVR 88)</li>
</ol>
<p>&nbsp;</p>
<p>Luka Modrić is another seasoned veteran who is still a master in the central midfield role. Though he is now in his 30s (he's 39 in EA FC 26), his technical ability and vision remain top-notch. As a player, Modrić offers everything you'd want from a deep-lying playmaker. His ball control and passing are phenomenal, and he is able to transition play quickly from defense to attack with his incredible vision and decision-making.</p>
<p>&nbsp;</p>
<p>Though his physicality has slightly decreased due to his age, his intelligence on the ball more than compensates for it. In Career Mode, you'll find him at a relatively low cost compared to De Bruyne, making him a viable option for teams looking to add experience and creativity to the midfield without breaking the bank.</p>
<p>&nbsp;</p>
<p>Key Stats: Passing 91, Vision 88, Dribbling 86, Stamina 70</p>
<p>FC 26 coins serve as a virtual currency within the game. Players can use FC 26 coins to buy in-game items such as player packs, consumables, and other virtual. so you can buy FC FUT Coins at mmoexp.com</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>BennieDe</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/lounge/mmoexp-fc26-to-climb-the-ranks/#post-2281</guid>
                    </item>
				                    <item>
                        <title>RE: Twincat4026, Running Inside dockerized Windows11, Access via Mstsc</title>
                        <link>https://twincontrols.com/community/twincat-tips-tricks/twincat4026-running-inside-dockerized-windows11-access-via-mstsc/#post-2276</link>
                        <pubDate>Fri, 07 Nov 2025 15:01:06 +0000</pubDate>
                        <description><![CDATA[@romang Hi, are you enable to enter in run mode in Twincat with this technic ?]]></description>
                        <content:encoded><![CDATA[@romang Hi, are you enable to enter in run mode in Twincat with this technic ?]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>Gauth</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-tips-tricks/twincat4026-running-inside-dockerized-windows11-access-via-mstsc/#post-2276</guid>
                    </item>
				                    <item>
                        <title>TwinCAT 3.1 (Build 4026) &amp; Git – Online Change fails after cloning project (mapping mismatch)</title>
                        <link>https://twincontrols.com/community/twincat-troubleshooting/twincat-3-1-build-4026-git-online-change-fails-after-cloning-project-mapping-mismatch/#post-2275</link>
                        <pubDate>Thu, 06 Nov 2025 21:02:29 +0000</pubDate>
                        <description><![CDATA[Hi everyone,
we’re currently running a TwinCAT 3.1 project (version 4026) with Git as our version control system, and we’ve run into a workflow issue that we can’t seem to solve.
Setup:
...]]></description>
                        <content:encoded><![CDATA[<p data-start="106" data-end="118">Hi everyone,</p>
<p data-start="120" data-end="285">we’re currently running a TwinCAT 3.1 project (version 4026) with Git as our version control system, and we’ve run into a workflow issue that we can’t seem to solve.</p>
<p data-start="287" data-end="297"><strong data-start="287" data-end="297">Setup:</strong></p>
<ul data-start="299" data-end="650">
<li data-start="299" data-end="335">
<p data-start="301" data-end="335">3 developers working in parallel</p>
</li>
<li data-start="336" data-end="396">
<p data-start="338" data-end="396">Multi-PLC project (separate PLC task for each developer)</p>
</li>
<li data-start="397" data-end="472">
<p data-start="399" data-end="472">One “main” development PC where the hardware configuration is activated</p>
</li>
<li data-start="473" data-end="544">
<p data-start="475" data-end="544">Each colleague clones the project from Git and works on <em data-start="531" data-end="538">their</em> PLC</p>
</li>
<li data-start="545" data-end="650">
<p data-start="547" data-end="650">The goal is that all of us can be logged into <em data-start="593" data-end="602">our own</em> PLC at the same time and perform Online Changes</p>
</li>
</ul>
<p data-start="652" data-end="668"><strong data-start="652" data-end="668">The problem:</strong></p>
<p data-start="670" data-end="953">After the hardware config is activated on the main PC and we all pull the project from Git, TwinCAT refuses Online Change on the other machines.<br data-start="814" data-end="817" />We get an error saying that the <strong data-start="849" data-end="875">mapping does not match</strong> or is invalid, even though nothing has been changed in the I/O configuration.</p>
<p data-start="955" data-end="1138">It seems like TwinCAT thinks the project is different from what’s running on the target, although everything (in theory) is identical – same commit, same configuration, same PLC code.</p>
<p data-start="1140" data-end="1158"><strong data-start="1140" data-end="1158">What we tried:</strong></p>
<ul data-start="1160" data-end="1529">
<li data-start="1160" data-end="1209">
<p data-start="1162" data-end="1209">Full rebuild on every workstation → no effect</p>
</li>
<li data-start="1210" data-end="1306">
<p data-start="1212" data-end="1306">Deleting the <code data-start="1225" data-end="1239">.compileinfo</code>, <code data-start="1241" data-end="1247">.tmc</code>, and generated build folders before building → no effect</p>
</li>
<li data-start="1307" data-end="1452">
<p data-start="1309" data-end="1452">Re-activating hardware locally on every PC → works, but then every developer ends up committing different hardware GUIDs to Git → merge chaos</p>
</li>
<li data-start="1453" data-end="1529">
<p data-start="1455" data-end="1529">Using “PLC only” activation → same mapping error when trying Online Change</p>
</li>
</ul>
<p data-start="1531" data-end="1562"><strong data-start="1531" data-end="1562">What we think is happening:</strong></p>
<p data-start="1564" data-end="1826">TwinCAT stores some hardware-related GUIDs / internal hashes locally, and after cloning the project, they don't match the target runtime, even if the code is identical.<br data-start="1732" data-end="1735" />As soon as one person re-activates the solution, the others can no longer do Online Change.</p>
<p data-start="1828" data-end="1841"><strong data-start="1828" data-end="1841">Question:</strong></p>
<p data-start="1843" data-end="1954">Has anyone found a clean workflow for <strong data-start="1881" data-end="1926">multi-developer TwinCAT projects with Git</strong>, where multiple people can:</p>
<ul data-start="1956" data-end="2098">
<li data-start="1956" data-end="1974">
<p data-start="1958" data-end="1974">clone the repo</p>
</li>
<li data-start="1975" data-end="2005">
<p data-start="1977" data-end="2005">go online with <em data-start="1992" data-end="1999">their</em> PLC</p>
</li>
<li data-start="2006" data-end="2026">
<p data-start="2008" data-end="2026">do Online Change</p>
</li>
<li data-start="2027" data-end="2098">
<p data-start="2029" data-end="2098"><strong data-start="2029" data-end="2040">without</strong> everyone having to re-activate the I/O tree individually?</p>
</li>
</ul>
<p data-start="2100" data-end="2276">Is there a recommended “.gitignore” setup to avoid committing machine-specific files?<br data-start="2185" data-end="2188" />Or is TwinCAT simply not made for true parallel development with shared hardware config?</p>
<p data-start="2278" data-end="2360">Any best practices, workarounds, or real-world experiences are highly appreciated!</p>
<p data-start="2362" data-end="2380" data-is-last-node="" data-is-only-node="">Thanks in advance!</p>
<p data-start="2362" data-end="2380" data-is-last-node="" data-is-only-node=""> </p>
<p data-start="2362" data-end="2380" data-is-last-node="" data-is-only-node="">Note: English is not my native language, so I used ChatGPT to help write this post. Hopefully everything is understandable – feel free to correct me if something sounds unclear.</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>funka84</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-troubleshooting/twincat-3-1-build-4026-git-online-change-fails-after-cloning-project-mapping-mismatch/#post-2275</guid>
                    </item>
				                    <item>
                        <title>RE: System time to DT</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/system-time-to-dt/#post-2271</link>
                        <pubDate>Tue, 14 Oct 2025 12:13:03 +0000</pubDate>
                        <description><![CDATA[Hello,
Did you try this ?
DateTime:= FILETIME64_TO_DT(F_GetSystemTime());]]></description>
                        <content:encoded><![CDATA[<p>Hello,</p>
<p>Did you try this ?<br /><br /></p>
<pre contenteditable="false">DateTime:= FILETIME64_TO_DT(F_GetSystemTime());</pre>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>Alex</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/system-time-to-dt/#post-2271</guid>
                    </item>
				                    <item>
                        <title>System time to DT</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/system-time-to-dt/#post-2263</link>
                        <pubDate>Mon, 29 Sep 2025 06:17:57 +0000</pubDate>
                        <description><![CDATA[Hi
I have a very simple task that I am struggling with. 
I need to write systemtime to a var type DT.
I try using F_GetSystemtime(); but I can not figure out how to convert the UNLINT to ...]]></description>
                        <content:encoded><![CDATA[<p>Hi</p>
<p>I have a very simple task that I am struggling with. </p>
<p>I need to write systemtime to a var type DT.</p>
<p>I try using F_GetSystemtime(); but I can not figure out how to convert the UNLINT to DT. </p>
<p>DateTime:= ULINT_TO_DT(F_GetSystemTime()) gives me a very strange result. </p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/"></category>                        <dc:creator>jthyge</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/system-time-to-dt/#post-2263</guid>
                    </item>
							        </channel>
        </rss>
		