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.
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.
LogixNG has a simple solution to this problem, local variables. 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.
Local variables are created in the ConditionalNG editor. Open the editor of a ConditionalNG and right-click on an action or expression and select Local variables.
The local variable dialog window will open.
To create a local variable, click on the Add variable button. A new row will be added. Double click in the Name field and give it a name. Select the Type and provide an initial value if desired. The Select menu is used to Delete a local variable and has Move Up and Move Down options if there is more than one variable.
Click on OK to finish. The local variable will be added to the tree. See the editor image below.
null
.sensors.getSensor("BlinkSensor")
. This gets a sensor object which can then
be set active or inactive. For details on accessing LogixNG objects from a script see
Chapter 13 - Jython Scripting Support.variable.set(some_python_variable)
. This is a Python global variable
that is added by the LogixNG scripting support. For details on accessing LogixNG objects
from a script see Chapter 13 - Jython Scripting Support.Note: The type of a variable can change based on the last assignment. For example, a
local variable with the name index
defined as integer would change to string if
"XVZ" was assigned to index
.
When an Array Local Variable is defined, it will default to empty. Rows can be added to the Array using the add method. The rows can also be defined by providing a value in the data column, in this example 5 rows for Array2.
Some examples of setting the initial Array values. size is another local variable that contains the row count, such as 23.
Example | Result |
---|---|
Data field is empty | The array is empty |
12 | 12 empty strings in the array |
size | 23 empty strings in the array |
12:"Hello world" | 12 "Hello world" strings in the array |
size:"Hello world" | 23 "Hello world" strings in the array |
12:233 | 12 items with the number 233 in the array |
size:233 | 23 items with the number 233 in the array |
12:43.323 | 12 items with the number 43.323 in the array |
size:43.323 | 23 items with the number 43.323 in the array |
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:
array[1] = value
. To get the value: value = array[1]
.
The following list has the common ArrayList methods using the Java syntax.
The following image shows some of the options for working with an array.
Log local variables: Name: size1, value: 0 Name: size2, value: 0 Name: Array1, value: [] Name: Array2, value: [, , , , ] Log local variables done
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
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
When a Map Local Variable is defined, it is empty. Rows are added as shown in the example.
The rows in the map are accessed by using the key for the row. To add a new key/value pair:
map{key} = value
. The same syntax will replace the value for an existing key.
To get the value for a key: value = map{key}
.
The following list has the common HashMap methods using the Java syntax.
The following image shows some of the options for working with an array.
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
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.
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.
The scope of a local variable depends on where it is defined in the tree. This a contrived example to show scope behavior.
There are two local variables defined. One at the root of the tree and a second one part way up the first branch.
The output on the JMRI system console shows the result when the ConditionalNG is executed.
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]
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.
What to do if the ConditionalNG doesn't do the expected? The debugger provides one tool, but another tool is the action Log local variables. Each time it's executed, it prints all the local variables and their values to the JMRI Sytem Console.
Options:
Example:
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]
Thanks and congratulations to all who contributed! Contact us via the JMRI users Groups.io group.
Copyright © 1997 - 2024 JMRI Community. JMRI®, DecoderPro®, PanelPro™, DispatcherPro™, OperationsPro™, SignalPro™, SoundPro™, TrainPro™, Logix™, LogixNG™ and associated logos are our trademarks. Additional information on copyright, trademarks and licenses is linked here.
View the