Expressions as Tag Parameters
The PTypeToggle widget (following image), provides the user with a choice between a tag, a constant value, or a block of steady state VTScada code (i.e. an expression).
If you intend to add support for expressions, you must ensure that the ExpressionManager is started in the tag's initialization state before any other actions take place. This is commonly done as follows (example taken from the Analog Status tag with relevant code in bold).
AnalogInit [
If \AlarmManager\Started && \ExpressionManager\Started AnalogInMain;
[
CriticalSection(
Root = Self;
{ Set up initial values }
Refresh();
);
]
]
In the Refresh() method of the module, use SafeRefresh() to update any parameters that may be assigned an expression. For example:
\ExpressionManager\SafeRefresh(&AlarmLo, Parm[#AlarmLo]);
In the tag's configuration folder, use a PTypeToggle for each variable that may be an expression. For example, here is the code that draws the user input for the low alarm setpoint of an Analog Status tag:
{***** Low Setpoint *****}
GUITransform(30, 103, WIDTH/2 - 5, 45,
1, 1, 1, 1, 1 { No scaling },
0, 0, 1, 0 { No movement; visible; reserved },
0, 0, 0 { Not selectable },
\DialogLibrary.PTypeToggle(\#AlarmLo, "Numeric" { point type },
\GetPhrase("LowAlarmSetpointLabel"), 1 { to 3 - ID },
0 { top align }, 1 { align title },
Invalid, Invalid { limits },
Trigger, 1 { Allow Expression }));
Issues and Risks
Care must be taken when assigning to and from variables that may hold expression values. The implementation of expressions assumes that only one variable at a time holds a reference to a running expression.
A running expression must be slain before assigning to a variable that refers to it. Failing to do this will result in an orphaned expression, which is worse than creating a memory leak, because processor cycles are additionally wasted.
A reference to a running expression should not be copied. Instead of copying the reference, a new expression should be started with the same source. Failing to do this consistently will result in expressions dying unexpectedly.
The convenience methods \ExpressionManager\SafeAssign() and \ExpressionManager\SafeCopy() are provided to make this easier for developers.
Care must be taken not to rely on expressions running on different servers to return the same thing (example: Now(1))
It is possible, in theory, to create a situation where expressions are returning different values from each PC in a multi-server application. For example, suppose that a Logger is created that accepts input from a Calculation tag, which in turn uses an expression that relies on the local clock. If the local clock is slightly different on each PC, then this may result in odd log data when synchronizing between different PCs.