Files
JIMRI/help/en/html/tools/logixng/reference/chapter8.shtml
T
2026-06-17 14:00:51 +02:00

406 lines
18 KiB
Plaintext

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content="HTML Tidy for HTML5 for Apple macOS version 5.8.0">
<title>LogixNG Reference - Chapter 8</title>
<meta name="author" content="Daniel Bergqvist">
<meta name="author" content="Dave Sand">
<meta name="keywords" content="jmri LogixNG reference local variables">
<!--#include virtual="/help/en/parts/Style.shtml" -->
</head>
<body>
<!--#include virtual="/help/en/parts/Header.shtml" -->
<div id="mBody">
<div id="mainContent" class="no-sidebar">
<h1>LogixNG Reference - Chapter 8</h1>
<h2>Local Variables</h2>
<p>JMRI has memories that can store data. And that's great. But there is a problem with
memories. They are global, which means that anyone can change them. Lets assume you want to
count something so you create a memory IMCOUNTER. You create a LogixNG that does the counting
and everything works fine.</p>
<p>A year passes and you need to count something else. You create a new LogixNG that does the
new counting and you need a memory, so you decide to use the memory IMCOUNTER. And your new
LogixNG works fine. But then you suddenly realize that something else on the layout stops
working. Why? What has happen? Well, the problem is that you use the same memory IMCOUNTER
for two different things in two different places. And when that happens, you get into
trouble.</p>
<p>LogixNG has a simple solution to this problem, <strong>local variables</strong>. A local
variable is similar to a memory, but it only exists in a very limited context and nothing
outside that context can interfere with the variable. The local variable is also transient. It
is only available during the execution of the ConditionalNG and it goes away when the
execution is finished. This protects the local variable from being changed in an
unpredictable way.</p>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h3>Defining local variables</h3>
<p>Local variables are created in the ConditionalNG editor. Open the editor of a
ConditionalNG and right-click on an action or expression and select <strong>Local
variables</strong>.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variables_menu.png"><img class="image-border" src=
"images/chapter8/local_variables_menu.png" alt="Chapter 8 local variable menu item"></a>
</div>
<p>The local variable dialog window will open.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variables_dialog.png"><img src=
"images/chapter8/local_variables_dialog.png" alt="Chapter 8 local variables dialog"></a>
</div>
<p>To create a local variable, click on the <strong>Add variable</strong> button. A new row
will be added. Double click in the <strong>Name</strong> field and give it a name. Select the
<strong>Type</strong> and provide an initial value if desired. The <strong>Select</strong>
menu is used to <strong>Delete</strong> a local variable and has <strong>Move Up</strong> and
<strong>Move Down</strong> options if there is more than one variable.</p>
<p>Click on <strong>OK</strong> to finish. The local variable will be added to the tree. See
the editor image below.</p>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h3 id="variableTypes">Local variable types</h3>
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variable_types.png"><img src=
"images/chapter8/local_variable_types.png" alt="Chapter 8 local variable types"></a>
</div>
<dl>
<dt>None</dt>
<dd>The initial value will be <code>null</code>.</dd>
<dt>Boolean <span class="since">since 5.7.5</span></dt>
<dd>Contains the boolean value <strong>true</strong> or <strong>false</strong>. The state
is set or referenced by using the words <strong><em>true</em></strong> and
<strong><em>false</em></strong>. The words are case insensitive. Setting an initial value
is recommended.</dd>
<dt>Integer</dt>
<dd>A whole number such as 123</dd>
<dt>Floating number</dt>
<dd>A number such as 123.4</dd>
<dt>String</dt>
<dd>A series of characters, such as ABC123def</dd>
<dt>Array</dt>
<dd>A list of items. This is implemented using the Java ArrayList. This is similar to the
Python List.</dd>
<dt>Map</dt>
<dd>A list of kev/value items. This is implemented using the Java HashMap. This is similar
to the Python Dictionary.</dd>
<dt>Local Variable</dt>
<dd>Use the value from another local variable.</dd>
<dt>Memory</dt>
<dd>Use the value from a memory variable.</dd>
<dt>Reference</dt>
<dd>Use the value from an indirect reference.</dd>
<dt>Formula</dt>
<dd>Use the value from a formula</dd>
<dt>Script expression</dt>
<dd>Use a one line script command to set the value of the variable. For example:
<code>sensors.getSensor("BlinkSensor")</code>. This gets a sensor object which can then
be set active or inactive. For details on accessing LogixNG objects from a script see
<a href="chapter13.shtml">Chapter 13 - Jython Scripting Support</a>.</dd>
<dt>Script file</dt>
<dd>For more complex logic, a script file can be used to set the value. There are sample
scripts at the <strong>jython/LogixNG</strong> directory within the JMRI install location.
Note: The results of the script are passed back to LogixNG using
<code>variable.set(<em>some_python_variable</em>)</code>. This is a Python global variable
that is added by the LogixNG scripting support. For details on accessing LogixNG objects
from a script see <a href="chapter13.shtml">Chapter 13 - Jython Scripting Support</a>.</dd>
<dt>LogixNG Table</dt>
<dd>Load the contents of a specified LogixNG table into a variable. The table name is
specified in the data column when creating the local variable. For global variables, use
the initial value field. Here is an example that creates the local variable and provides
access to the table rows and columns:
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variable_table_type.png"><img src=
"images/chapter8/local_variable_table_type.png" alt="Chapter 8 local variable table_type"></a>
</div>
</dd>
</dl>
<p>Note: The type of a variable can change based on the last assignment. For example, a
local variable with the name <code>index</code> defined as integer would change to string if
"XVZ" was assigned to <code>index</code>.</p>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h5>Array<span class="since">since 4.25.8</span></h5>
<p>When an <strong>Array</strong> Local Variable is defined, it will default to empty. Rows
can be added to the Array using the <strong>add</strong> method. The rows can also be
defined by providing a value in the data column, in this example 5 rows for Array2.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variable_array.png"><img src=
"images/chapter8/local_variable_array.png" alt="Chapter 8 local variable array"></a>
</div>
<p>Some examples of setting the initial Array values. <strong>size</strong> is another local
variable that contains the row count, such as 23.</p>
<div style="margin-left: 2em;">
<table>
<tr><th>Example</th><th>Result</th></tr>
<tr><td>Data field is empty</td><td>The array is empty</td></tr>
<tr><td>12</td><td>12 empty strings in the array</td></tr>
<tr><td>size</td><td>23 empty strings in the array</td></tr>
<tr><td>12:"Hello world"</td><td>12 "Hello world" strings in the array</td></tr>
<tr><td>size:"Hello world"</td><td>23 "Hello world" strings in the array</td></tr>
<tr><td>12:233</td><td>12 items with the number 233 in the array</td></tr>
<tr><td>size:233</td><td>23 items with the number 233 in the array</td></tr>
<tr><td>12:43.323</td><td>12 items with the number 43.323 in the array</td></tr>
<tr><td>size:43.323</td><td>23 items with the number 43.323 in the array</td></tr>
</table>
</div>
<p>The rows in the array are accessed by using the row number. The first row has a row number
of zero. The last row number is the size of the array minus 1. To set the value of a row:
<code>array[1] = value</code>. To get the value: <code>value = array[1]</code>.</p>
<p>The following list has the common ArrayList methods using the Java syntax.</p>
<ul>
<li>add(value) &mdash; Append a row to the array with the specified value.</li>
<li>clear() &mdash; Remove all of the rows from the array.</li>
<li>get(row) &mdash; Get the value of a row using a row number.</li>
<li>set(row, value) &mdash; Set the value of a row using a row number and the new value.</li>
<li>size() &mdash; Return the number of rows in the array</li>
</ul>
<p>The following image shows some of the options for working with an array.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/array_sample.png"><img src=
"images/chapter8/array_sample.png" alt="Chapter 8 local variable array sample"></a>
</div>
<ul>
<li>A1
<pre>
Log local variables:
Name: size1, value: 0
Name: size2, value: 0
Name: Array1, value: []
Name: Array2, value: [, , , , ]
Log local variables done
</pre>
</li>
<li>A2 and A3 changes two of the rows of Array2 to new values. The array was set with five
rows. The rows are referenced using the row numbers.</li>
<li>A5 and A6 copy the two rows from Array2 and <strong>adds</strong> them to Array1. The
Array2 rows are referenced by row number, but the rows are appended to Array1. The
corresponding row numbers in Array1 will be 0 and 1.</li>
<li>A8
<pre>
Log local variables: (A8)
Name: size1, value: 2
Name: size2, value: 5
Name: Array1, value: [Zero, XYZ]
Name: Array2, value: [Zero, , , XYZ, ]
Log local variables done
</pre>
</li>
<li>A9 removes all of the rows from Array2.</li>
<li>A10
<pre>
Log local variables: (A8)
Name: size1, value: 2
Name: size2, value: 5
Name: Array1, value: [Zero, XYZ]
Name: Array2, value: [] <== Note zero length
Log local variables done
</pre>
</li>
</ul>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h5 id="lv_map">Map<span class="since">since 4.25.8</span></h5>
<p>When a <strong>Map</strong> Local Variable is defined, it is empty. Rows are added as
shown in the example.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variable_map.png"><img src=
"images/chapter8/local_variable_map.png" alt="Chapter 8 local variable map"></a>
</div>
<p>The rows in the map are accessed by using the key for the row. To add a new key/value pair:
<code>map{key} = value</code>. The same syntax will replace the value for an existing key.
To get the value for a key: <code>value = map{key}</code>.</p>
<p>The following list has the common HashMap methods using the Java syntax.</p>
<ul>
<li>get("key") &mdash; Get the value for the key.</li>
<li>put("key", "value") &mdash; Assign a value to the key. If a value already exists
it is replaced with the new value.</li>
<li>clear() &mdash; Remove all of the rows from the map.</li>
<li>size() &mdash; Return the number of key/value pairs in the map</li>
</ul>
<p>The following image shows some of the options for working with an array.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/map_sample.png"><img src=
"images/chapter8/map_sample.png" alt="Chapter 8 local variable map sample"></a>
</div>
<div style="margin-left: 2em;">
<pre>
Log local variables:
Name: Map1, value: {key=value}
Name: Map2, value: {new=value, abc=xyz}
Name: Size2, value: 2
Name: Size1, value: 1
Log local variables done
</pre>
</div>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h3>Order of local variables</h3>
<p>The order of the local variables that are defined in an action or expression matters if
you use one variable in the initialization of another. Lets say you define two variables "a"
and "b", and that you define "a" to be initialized to the formula "34 * 4" and you define "b"
to be initialized to "a * 3". This will work if "a" is defined before "b". You can define
both variables in the same action or expression, but "a" needs to be before "b" since "b"
uses "a" in its initialization.</p>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h3>Local variables are local</h3>
<p>This may seem obvious, but when writing scripts that uses local variables, it's important
to remember this. A script can access the symbol table if it has access to the ConditionalNG,
but the symbol table is dependent on which action or expression that's currently running.</p>
<p>The <strong>scope</strong> of a local variable depends on where it is defined in the tree.
This a contrived example to show scope behavior.</p>
<p>There are two local variables defined. One at the root of the tree and a second one part
way up the first branch.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/local_variables_scope.png"><img src=
"images/chapter8/local_variables_scope.png" alt="Chapter 8 local variables scope"></a>
</div>
<p>The output on the JMRI system console shows the result when the ConditionalNG is
executed.</p>
<div style="margin-left: 2em;">
<pre>
in if trees
WARN - Log local variables: [JMRI LogixNGThread]
WARN - Name: rootlevel, value: null [JMRI LogixNGThread]
WARN - Name: iftree, value: null [JMRI LogixNGThread]
WARN - Log local variables done [JMRI LogixNGThread]
root level
WARN - Log local variables: [JMRI LogixNGThread]
WARN - Name: rootlevel, value: null [JMRI LogixNGThread]
WARN - Log local variables done [JMRI LogixNGThread]
</pre>
</div>
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
<h3>Initialization of local variables</h3>
<p>When an action or expression is executed that defines local variables, these local
variables are created with an initial value. When you create the local variable, you define
what the initial value should be. 'None' means that the value will be 'null'. Reference means
that the value will be the value that the reference is pointing at. Formula means the result
of the formula.</p>
<a id="LogLocalVariables"></a>
<h3>Debugging local variables</h3>
<p>What to do if the ConditionalNG doesn't do the expected? The debugger provides one tool,
but another tool is the action <strong>Log local variables</strong>. Each time it's executed,
it prints all the local variables and their values to the JMRI Sytem Console.</p>
<div style="margin-left: 2em;">
<a href="images/chapter8/log_variables.png"><img src=
"images/chapter8/log_variables.png" alt="Chapter 8 log variables"></a>
</div>
<p>Options:</p>
<ul>
<li><strong>Include global variables</strong> &mdash; The global variables will be
listed after the local variables.</li>
<li><strong>Expand arrays and maps</strong> &mdash; The contents of each array and map
will be listed.</li>
<li><strong>Show class name</strong> &mdash; The name of the Java class will be included
for each item. Sometimes it is useful for debugging to know the actual type of the value.</li>
</ul>
<p>Example:</p>
<div style="margin-left: 2em;">
<pre>
WARN - Log local variables: [JMRI LogixNGThread]
WARN - Name: time, Value: Time is 13:02 [JMRI LogixNGThread]
WARN - Global variables: [JMRI LogixNGThread]
WARN - Global Name: gHour, value: 13 [JMRI LogixNGThread]
WARN - Global Name: gMin, value: 2 [JMRI LogixNGThread]
WARN - Global Name: timeMap, [JMRI LogixNGThread]
WARN - theHour -> 13, [JMRI LogixNGThread]
WARN - theMin -> 2, [JMRI LogixNGThread]
WARN - theTime -> The map time is 13:02, [JMRI LogixNGThread]
WARN - Global Name: timeArray, [JMRI LogixNGThread]
WARN - 0: 13, [JMRI LogixNGThread]
WARN - 1: 2, [JMRI LogixNGThread]
WARN - 2: The array time is 13:02, [JMRI LogixNGThread]
WARN - Global Name: null, value: null [JMRI LogixNGThread]
WARN - Log local variables done [JMRI LogixNGThread]
</pre>
</div>
<hr>
<p><a href="chapter9.shtml">Chapter 9 - Formula</a>
</p>
<p><a href="index.shtml">Return to the Reference TOC</a>
</p>
<!--#include virtual="/help/en/parts/Footer.shtml" -->
</div>
<!-- closes #mainContent-->
</div>
<!-- closes #mBody-->
<script src="/js/help.js"></script>
</body>
</html>