Tags - Krystian-L-Lis/Stage GitHub Wiki

#Guide #Tags

Overview

The primary characteristic of a decoupled system, like the one the Stage aims to implement, is its ability to identify entities and components in a human-readable way. This ensures they can be accessed at any point during program execution, as long as the querying object possesses the corresponding unique ID string. TwinCAT supports automatic generation of path strings through the instance-path attribute, but manually typing these paths can be cumbersome and error-prone since attributes are not validated during static analysis. To address this, Tag and other related function blocks are introduced to simplify this process.

Core elements

The Tag instance simplifies handling of reflection and path modifications for the user. It ensures that paths are human-readable and minimizes complexity by stripping unnecessary segments such as proj, plc_proj, and _tag. This simplifies navigation and makes paths easier to manage.

Example: Standard Path: Input:
proj.plc_proj.MAIN.taggedFb._tag
Processed:
MAIN.taggedFb

Array Path: Input:
proj.plc_proj.MAIN.taggedFb[5]._tag
Processed:
MAIN.taggedFb.5

This simplification enables easier use of wildcards and enhances browsing flexibility.

The Tag instance includes an optional Option segment, which is internally part of the Id but can be accessed separately. However, Option is read-only through the interface and can only be modified via the original instance to ensure integrity.

Example:

FUNCTION_BLOCK TaggedFb IMPLEMENTS I_Tagged
VAR
	_tag : Tag := (Option := 'Tagged'); // Tag instance with 'Tagged' as the Option
END_VAR
PROPERTY Tag : I_Tag
GET:
	Tag := _tag;
END_PROPERTY

PROGRAM Main
VAR
	taggedFb 	: TaggedFb; // Instance of the function block
	iTag		: I_Tag := taggedFb; // Interface reference
	sTagId		: STRING; // Holds the tag ID
	sOption		: STRING; // Holds the Option value
END_VAR

// Accessing the tag's ID
sTagId := taggedFb.Tag.Id;
// Result: sTagId = 'MAIN.taggedFb'

// Accessing the Option value
sOption := taggedFb.Option;
// Result: sOption = 'Tagged'

// Attempting to modify the Option via the function block instance
taggedFb.Option := 'NewOption';
sOption := taggedFb.Option;
// Result: sOption = 'NewOption'

// Accessing Option via the interface
sOption := iTag.Option;
// Result: sOption = 'NewOption'

// Attempting to modify Option via the interface
iTag.Option := 'SecondOption';
// Compiler error
END_PROGRAM

TagCmp is a chainable comparison tool for I_Tag components, allowing users to compare tags with advanced functionality similar to a CASE statement. It operates in three primary steps:

  1. Set: Define the base Tag (or I_Tag) for comparison.
  2. Chain Matches: Use methods like HasOption, MatchId, or MatchWcdId to define matching conditions.
  3. Evaluate Results: Check results using methods like IsTrue, IsFalse, or IsErr.

If any condition evaluates to TRUE, IsTrue returns TRUE, locks the internal state, and halts further evaluations in the chain. If any condition triggers an error, IsErr returns TRUE and locks. If no conditions are met, IsFalse returns TRUE and locks.

**Example 1: Basic Usage

PROGRAM Main
VAR
	taggedFb: ARRAY[0..11] OF TaggedFb;
	iSelected: I_Tag;
	cmp: TagCmp;
	i: UDINT;
	sResult: STRING;
END_VAR

iSelected := taggedFb[REAL_TO_UDINT(Random() * 10.0)].Tag;
cmp.Set(iSelected);

FOR i := 1 TO 11 DO
	IF cmp.Match(taggedFb[i].Tag).IsTrue() THEN
		sResult := CONCAT('Selected: ', TO_STRING(i));
	END_IF
END_FOR

**Example 2: Chain Matching

iSelected := taggedFb[REAL_TO_UDINT(Random() * 10.0)].Tag;
cmp.Set(iSelected);

IF cmp.Match(taggedFb[0].Tag).Match(taggedFb[1].Tag).IsTrue() THEN
	sResult := 'I\'m 0 or 1!';
END_IF

IF cmp.Match(taggedFb[2].Tag).Match(taggedFb[3].Tag).IsTrue() THEN
	sResult := 'I\'m 2 or 3!';
END_IF

IF cmp.IsFalse() THEN
	sResult := 'I\'m any other value!';
END_IF

**Resetting Comparisons

iSelected := taggedFb[1].Tag;
cmp.Set(iSelected);

IF cmp.Match(taggedFb[1].Tag).IsTrue() THEN
	sResult := 'I\'m 1';
END_IF

// Subsequent conditions won't execute after the first match:
IF cmp.Match(taggedFb[1].Tag).IsTrue() THEN
	// This block will never execute.
END_IF

// Reset comparison state:
cmp.Set(iSelected);

IF cmp.Match(taggedFb[1].Tag).IsTrue() THEN
	// This block will execute again.
	sResult := 'I\'m 1';
END_IF

The MatchId method compares tag IDs from right to left for flexibility.

Example 4: Using MatchId

PROGRAM Main
VAR
	taggedFb_01: TaggedFb;
	taggedFb_02: TaggedFb;
	cmp: TagCmp;
	sResult: STRING;
END_VAR

cmp.Set(taggedFb_01);

IF cmp.MatchId('taggedFb_01').IsTrue() THEN
	sResult := 'Im taggedFb_01!';
END_IF

IF cmp.MatchId('taggedFb_02').IsTrue() THEN
	sResult := 'Im taggedFb_02!';
END_IF

IF cmp.IsFalse() THEN
	sResult := 'Im neither!';
END_IF

The MatchWcdId method supports wildcards (*), allowing flexible comparisons.

Example: Wildcard pattern *.nestedFb.*.taggedFb

This pattern indicates that the system will ignore any number of segments between the first segment and nestedFb, as well as any number of segments between nestedFb and taggedFb. For instance, consider the following example with a wildcard.

Example 5: Using MatchWcdId with Wildcards

FUNCTION_BLOCK TaggedFb IMPLEMENTS I_Tagged
VAR
	_tag : Tag := (Option := 'Tagged'); // Tag instance with 'Tagged' as the Option
END_VAR
PROPERTY Tag : I_Tag
GET:
	Tag := _tag;
END_PROPERTY
END_FUNCTION_BLOCK

FUNCTION_BLOCK NestedFb
VAR
	taggedFb_01: TaggedFb;
	taggedFb_02: TaggedFb;
END_VAR
PROPERTY Tag_1 : I_Tag
GET:
	Tag := taggedFb_01.Tag;
END_PROPERTY
PROPERTY Tag_2 : I_Tag
GET:
	Tag := taggedFb_02.Tag;
END_PROPERTY
END_FUNCTION_BLOCK

PROGRAM Main
VAR
	nestedFb_01: NestedFb;
	nestedFb_02: NestedFb;
	cmp: TagCmp;
	sResult: STRING;
END_VAR

cmp.Set(nestedFb_01.Tag_1);
IF cmp.MatchWcdId('*.nestedFb_01.*').IsTrue() THEN
	sResult := 'Im part of nestedFb_01!';
END_IF

cmp.Set(nestedFb_01.Tag_2);
IF cmp.MatchWcdId('*.nestedFb_01.*').IsTrue() THEN
	sResult := 'Im part of nestedFb_01!';
END_IF

cmp.Set(nestedFb_02.Tag_1);
IF cmp.MatchWcdId('*.nestedFb_01.*').IsFalse() THEN
	sResult := 'Im not part of nestedFb_01!';
END_IF

< Previous | Home | Next >

⚠️ **GitHub.com Fallback** ⚠️