1007 lines
43 KiB
Plaintext
1007 lines
43 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 99</title>
|
|
<meta name="author" content="Daniel Bergqvist">
|
|
<meta name="author" content="Dave Sand">
|
|
<meta name="keywords" content="jmri LogixNG Reference expression items">
|
|
<!--#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 99</h1>
|
|
|
|
<h2>Misc Items</h2>
|
|
|
|
<h1>+---------------------- Note ---------------------+ | The content in this file is not to
|
|
be published.| +-------------------------------------------------+</h1>
|
|
|
|
<h2 id="system_names">LogixNG system names</h2>
|
|
|
|
<p>System names in JMRI consists of a system prefix and a type letter. For LogixNG, the
|
|
system prefix is usually 'I' and the type letter is 'Q'. But LogixNG consists of several sub
|
|
types and if all of them would have its own type letter, the letters in the alphabet would
|
|
run out. Therefore LogixNG has sub type letters, except for LogixNG itself.</p>
|
|
|
|
<p>There is usually no need to work directly with system names and it's recommended to let
|
|
JMRI to auto generate them. But they can be created manually if desired.</p>
|
|
|
|
<p>LogixNG types and example system names</p>
|
|
<!-- <table border="1" cellspacing="0"> -->
|
|
|
|
<table>
|
|
<tr>
|
|
<th>LogixNG type</th>
|
|
<th>System name</th>
|
|
<th>Auto system name</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>LogixNG</td>
|
|
<td>IQ0001</td>
|
|
<td>IQ:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>A</strong>nalog <strong>A</strong>ction</td>
|
|
<td>IQAA0001</td>
|
|
<td>IQAA:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>A</strong>nalog <strong>E</strong>xpression</td>
|
|
<td>IQAE0001</td>
|
|
<td>IQAE:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>C</strong>onditionalNG</td>
|
|
<td>IQC0001</td>
|
|
<td>IQC:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>D</strong>igital <strong>A</strong>ction</td>
|
|
<td>IQDA0001</td>
|
|
<td>IQDA:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>D</strong>igital <strong>B</strong>oolean action</td>
|
|
<td>IQDB0001</td>
|
|
<td>IQDB:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>D</strong>igital <strong>E</strong>xpression</td>
|
|
<td>IQDE0001</td>
|
|
<td>IQDE:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>S</strong>tring <strong>A</strong>ction</td>
|
|
<td>IQSA0001</td>
|
|
<td>IQSA:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>S</strong>tring <strong>E</strong>xpression</td>
|
|
<td>IQSE0001</td>
|
|
<td>IQSE:AUTO:0001</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><strong>T</strong>able</td>
|
|
<td>IQT0001</td>
|
|
<td>IQT:AUTO:0001</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>"Auto system name" refers to system names that are generated automaticly.</p>
|
|
|
|
<p>All system names consists of the system prefix, the type letter, possible a sub type,
|
|
possible :AUTO: and a number. The number may begin with zeros and the system name IQ1 is
|
|
different from the system name IQ0001.</p>
|
|
|
|
<p>The LogixNG data types Map and Table are used to make generic LogixNGs. For a table, its
|
|
columns and rows can also be accessed as NamedBeans.</p>
|
|
|
|
<h3>LogixNG table structure</h3>
|
|
|
|
<p>A Table is a data type that holds a two dimensional array, like a spreadsheet.</p>
|
|
|
|
<p>Example:</p>
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
</th>
|
|
<th>A</th>
|
|
<th>B</th>
|
|
<th>C</th>
|
|
<th>D</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 1 </th>
|
|
<td>IQT22</td>
|
|
<td>Yard table</td>
|
|
<td>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 2 </th>
|
|
<td>
|
|
</td>
|
|
<td>West yard</td>
|
|
<td>East yard</td>
|
|
<td>North yard</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 3 </th>
|
|
<td>
|
|
</td>
|
|
<td colspan="3">Left entrance of the yard</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 4 </th>
|
|
<td>Leftmost turnout</td>
|
|
<td>IT101</td>
|
|
<td>IT201</td>
|
|
<td>IT301</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 5 </th>
|
|
<td>Left turnout</td>
|
|
<td>IT103</td>
|
|
<td>IT203</td>
|
|
<td>IT303</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 6 </th>
|
|
<td>
|
|
</td>
|
|
<td colspan="3">Right entrance of the yard</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 7 </th>
|
|
<td>Rightmost turnout</td>
|
|
<td>IT112</td>
|
|
<td>IT212</td>
|
|
<td>IT312</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 8 </th>
|
|
<td>Right turnout</td>
|
|
<td>IT114</td>
|
|
<td>IT214</td>
|
|
<td>IT314</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>LogixNG can use references to access layout items like turnouts in an indirect way. It's
|
|
done by entering the system name or user name in curly brackets. If a ActionTurnout has the
|
|
turnout IT1, it will access that turnout directly. But if the ActionTurnout has the turnout
|
|
{IM2}, it will read that memory and if that memory has a string as a value, it will use that
|
|
string value to find the turnout. So if the memory IM2 has the value IT5, and the
|
|
ActionTurnout has the turnout [IM2], the ActionTurnout will read the memory IM2 and find out
|
|
that it points to the turnout IT5 and therefore do it's action on turnout IT5. The benefit of
|
|
this is that the Memory can be changed during execution and therefore the same ActionTurnout
|
|
can be used to access different turnouts at different times.</p>
|
|
|
|
<p>It's possible to use indirect access recursive. If a ActionTurnout has the turnout {IM5},
|
|
and that Memory has the value {IM14}, and that the Memory IM14 has the value IT3, the
|
|
ActionTurnout will access IT3. The ActionTurnout has an indirect turnout IM5 so it will read
|
|
that Memory. And since that memory has the value {IM14} which also is an indirect access, it
|
|
will read the memory IM14 and find out that it has the value IT3, and therefore use IT3. This
|
|
is also true for tables. If the cell IQT1[5,3] has the value '{IM3}', and the memory IM3 has
|
|
the value 'IT5', the cell IQT1[5,3] will point to IT5.</p>
|
|
|
|
<p>A table can be used to create a lookup table. It's accessed by either its system name or
|
|
its user name, followed by a left square bracket, the name of the column, a comma, the name
|
|
of the row, and a right square bracket.</p>
|
|
|
|
<p>Instead of the names of the row and column, it's also possible to use the row number or
|
|
the column number. Note that row 1 has the system name and user name of the table, row 2 has
|
|
the names of the columns, and column 1 has the names of the rows. Note that for columns, 1 is
|
|
row A, 2 is row B, 22 is V, 23 is W, 26 is Z, 27 is AA and 28 is AB.</p>
|
|
|
|
<p>Note that spreadsheet software, like Excel and LibreOffice Calc, has cell <column
|
|
letter><row number> while references in JMRI has table[row,column]. Example: Cell B3
|
|
is table[3,2], since B3 is row 3 and column 2.</p>
|
|
|
|
<p>Example from the table above. These examples assume that IM3 has the value 'West yard',
|
|
IM4 has the value 'Rightmost turnout' and IM5 has the value 'IQT22'.</p>
|
|
|
|
<table>
|
|
<tr>
|
|
<td>Cell</td>
|
|
<td>Value</td>
|
|
<td>Note</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[1,1]</td>
|
|
<td>IQT22</td>
|
|
<td>Cell A1 has the system name of the table</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[1,2]</td>
|
|
<td>Yard table</td>
|
|
<td>Cell B1 has the user name of the table</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[2,2]</td>
|
|
<td>West yard</td>
|
|
<td>Cell B2 has the name of column B</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[4,1]</td>
|
|
<td>Leftmost turnout</td>
|
|
<td>Cell A4 has the name of row 4</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Yard table[4,1]</td>
|
|
<td>Leftmost turnout</td>
|
|
<td>The user name of the table can be used to access the table</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[5,3]</td>
|
|
<td>IT203</td>
|
|
<td>Cell C5 has the value 'IT203'</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[Left turnout,North yard]</td>
|
|
<td>IT303</td>
|
|
<td>Column 'North yard' and row 'Left turnout' has the cell D5 with the value
|
|
'IT303'</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Yard table[Left turnout,North yard]</td>
|
|
<td>IT303</td>
|
|
<td>Column 'North yard' and row 'Left turnout' has the cell D5 with the value
|
|
'IT303'</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[Leftmost turnout,{IM3}]</td>
|
|
<td>IT101</td>
|
|
<td>IM3 is in curly brackets and have the value 'West yard' so this points to cell
|
|
B4</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[{IM4},East yard]</td>
|
|
<td>IT212</td>
|
|
<td>IM4 is in curly brackets and have the value 'Rightmost turnout' so this points to
|
|
cell C7</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[{IM4},{IM3}]</td>
|
|
<td>IT112</td>
|
|
<td>Column {IM3} and row {IM4} points to cell B7</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>{IM5}[{IM4},{IM3}]</td>
|
|
<td>IT112</td>
|
|
<td>Even the table name can be accessed indirectly</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>Note that a Memory can point to a table. For example, if the memory IM7 has the value
|
|
'{Yard table[{IM3},Leftmost turnout]}', LogixNG will look at IM7, and find that it's value is
|
|
in curly brackets. It will then resolve the value inside these curly brackets, which is 'Yard
|
|
table[{IM3},Leftmost turnout]'. It will then resolve the value of IM3 which has the value
|
|
'West yard'. It will then get the table cell 'Yard table[West yard,Leftmost turnout]' which
|
|
is cell B4 with the value 'IT101'.</p>
|
|
|
|
<p>The ActionForEach iterates over a comma separated list of values. It can be used with
|
|
tables by using the keywords __columns__ and __rows__ . Note that it's two underscore
|
|
characters before and after. {IQT1[__columns__]} gives a comma separated list of all the
|
|
column names in the table IQT1. {IQT1[__rows__]} gives a comma separated list of all the row
|
|
names in the table IQT1. It's also possible to write {Yard table[__columns__]} and {Yard
|
|
table[__rows__]}. You can even use this syntax in ActionMemory to assign a Memory the list of
|
|
column names or row names. Note however that column names or row names that are empty is seen
|
|
as colums or rows with a comment and therefore they are not included.</p>
|
|
|
|
<p>Tables are loaded by a start up action. They are created in a spreadsheet, like Microsoft
|
|
Excel or LibreOffice Calc and then exported to a CSV file, separated by TAB characters. The
|
|
table is read only and is not stored in the panel filee, so it must be reloaded each time
|
|
JMRI starts.</p>
|
|
|
|
<h3>Note</h3>
|
|
|
|
<p>If a name has the characters comma, left or righ square bracket or left or right curly
|
|
brackets, these characters must be escaped by preceding them with a backslash. Examples: \,
|
|
\[ \] \{ \} \\</p>
|
|
|
|
<p>If a reference contains a backslash, it will take some more time to evaluate it than if it
|
|
doesn't contain any backslash. So if it's possible to not use these special characters in
|
|
references or names of beans, it's recommended.</p>
|
|
|
|
<h2 id="scripts">Scripts</h2>
|
|
|
|
<p>All types of LogixNG actions and expressions may use Python/Jython scripts. Below follows
|
|
the description of scripts for digital expressions, but the same pattern applies to all the
|
|
types of actions and expressions.</p>
|
|
|
|
<p>The digital expression that handles scripts is ExpressionScript.</p>
|
|
|
|
<p>The script that is executed by ExpressionScript must declare a class that extend the class
|
|
AbstractScriptDigitalExpression. The script must override the method evaluate(). For a script
|
|
that listen to other beans, it's recommended to also override the methods
|
|
registerScriptListeners() and unregisterScriptListeners().</p>
|
|
|
|
<p>When called, the script must tell the caller which class to use. It does that by setting
|
|
the variable params._scriptClass.set(instance)</p>
|
|
|
|
<p>Example of a digital expression script:</p>
|
|
|
|
<div style="margin-left: 2em;">
|
|
<p><code>import jmri<br>
|
|
<br>
|
|
class
|
|
MyExpression(jmri.jmrit.logixng.digital.expressions.AbstractScriptDigitalExpression):<br>
|
|
<br>
|
|
l = lights.provideLight(\"IL1\")<br>
|
|
<br>
|
|
def registerScriptListeners(self):<br>
|
|
self.l.addPropertyChangeListener(\"KnownState\", self);<br>
|
|
<br>
|
|
def unregisterScriptListeners():<br>
|
|
l.removePropertyChangeListener(\"KnownState\", this);<br>
|
|
<br>
|
|
def evaluate(self):<br>
|
|
return self.l.commandedState == ON<br>
|
|
<br>
|
|
params._scriptClass.set(MyExpression(params._parentExpression))<br></code>
|
|
</p>
|
|
</div>
|
|
|
|
<p><strong>ActionForEach</strong>
|
|
</p>
|
|
|
|
<p>ActionForEach is a for-loop.</p>
|
|
|
|
<p>This action has a list of items. Either a constant list, or it can use a NamedBeanMap.</p>
|
|
|
|
<p>The ActionForEach action loops thru the list. It takes the first item in the list, assigns
|
|
it to a Memory, and then executes its child action. Then it takes the second item in the
|
|
list, assigns it to the Memory, and executes the child action.</p>
|
|
|
|
<h2 id="digital_boolean_actions">List of digital boolean actions</h2>
|
|
|
|
<p>This section lists all the digital boolean actions that is currently available with
|
|
LogixNG.</p>
|
|
|
|
<p>Digital boolean actions takes a true/false value and do something. The most common use is
|
|
the digital action Logix together with the digital boolean action OnChange.</p>
|
|
|
|
<p>Digital boolean actions have system names with the letters <strong>DB</strong> (for
|
|
<strong>D</strong>igital <strong>B</strong>oolean action). Example: IQDB002 or IQDB:0053.
|
|
System names with colon are auto generated system names.</p>
|
|
|
|
<p style="color:red">Items in red may need rethink or removal. I have ideas, but not always
|
|
sure if these ideas are worth keeping. /Daniel</p>
|
|
|
|
<p style="color:blue">Items in blue is not up to date with documentation. The documentation
|
|
tells how they should work, but the code is not finished yet. /Daniel</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<p><strong>OnChange</strong>
|
|
</p>
|
|
|
|
<p>Executes a child action if the parameter is changed and to the desired value.</p>
|
|
</li>
|
|
</ul>
|
|
|
|
<h3>LogixNG table structure</h3>
|
|
|
|
<p>A Table is a data type that holds a two dimensional array, like a spreadsheet.</p>
|
|
|
|
<p>Example:</p>
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
</th>
|
|
<th>A</th>
|
|
<th>B</th>
|
|
<th>C</th>
|
|
<th>D</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 1 </th>
|
|
<td>IQT22</td>
|
|
<td>Yard table</td>
|
|
<td>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 2 </th>
|
|
<td>
|
|
</td>
|
|
<td>West yard</td>
|
|
<td>East yard</td>
|
|
<td>North yard</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 3 </th>
|
|
<td>
|
|
</td>
|
|
<td colspan="3">Left entrance of the yard</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 4 </th>
|
|
<td>Leftmost turnout</td>
|
|
<td>IT101</td>
|
|
<td>IT201</td>
|
|
<td>IT301</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 5 </th>
|
|
<td>Left turnout</td>
|
|
<td>IT103</td>
|
|
<td>IT203</td>
|
|
<td>IT303</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 6 </th>
|
|
<td>
|
|
</td>
|
|
<td colspan="3">Right entrance of the yard</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 7 </th>
|
|
<td>Rightmost turnout</td>
|
|
<td>IT112</td>
|
|
<td>IT212</td>
|
|
<td>IT312</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th> 8 </th>
|
|
<td>Right turnout</td>
|
|
<td>IT114</td>
|
|
<td>IT214</td>
|
|
<td>IT314</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>LogixNG can use references to access layout items like turnouts in an indirect way. It's
|
|
done by entering the system name or user name in curly brackets. If a ActionTurnout has the
|
|
turnout IT1, it will access that turnout directly. But if the ActionTurnout has the turnout
|
|
{IM2}, it will read that memory and if that memory has a string as a value, it will use that
|
|
string value to find the turnout. So if the memory IM2 has the value IT5, and the
|
|
ActionTurnout has the turnout [IM2], the ActionTurnout will read the memory IM2 and find out
|
|
that it points to the turnout IT5 and therefore do it's action on turnout IT5. The benefit of
|
|
this is that the Memory can be changed during execution and therefore the same ActionTurnout
|
|
can be used to access different turnouts at different times.</p>
|
|
|
|
<p>It's possible to use indirect access recursive. If a ActionTurnout has the turnout {IM5},
|
|
and that Memory has the value {IM14}, and that the Memory IM14 has the value IT3, the
|
|
ActionTurnout will access IT3. The ActionTurnout has an indirect turnout IM5 so it will read
|
|
that Memory. And since that memory has the value {IM14} which also is an indirect access, it
|
|
will read the memory IM14 and find out that it has the value IT3, and therefore use IT3. This
|
|
is also true for tables. If the cell IQT1[5,3] has the value '{IM3}', and the memory IM3 has
|
|
the value 'IT5', the cell IQT1[5,3] will point to IT5.</p>
|
|
|
|
<p>A table can be used to create a lookup table. It's accessed by either its system name or
|
|
its user name, followed by a left square bracket, the name of the column, a comma, the name
|
|
of the row, and a right square bracket.</p>
|
|
|
|
<p>Instead of the names of the row and column, it's also possible to use the row number or
|
|
the column number. Note that row 1 has the system name and user name of the table, row 2 has
|
|
the names of the columns, and column 1 has the names of the rows. Note that for columns, 1 is
|
|
row A, 2 is row B, 22 is V, 23 is W, 26 is Z, 27 is AA and 28 is AB.</p>
|
|
|
|
<p>Note that spreadsheet software, like Excel and LibreOffice Calc, has cell <column
|
|
letter><row number> while references in JMRI has table[row,column]. Example: Cell B3
|
|
is table[3,2], since B3 is row 3 and column 2.</p>
|
|
|
|
<p>Example from the table above. These examples assume that IM3 has the value 'West yard',
|
|
IM4 has the value 'Rightmost turnout' and IM5 has the value 'IQT22'.</p>
|
|
|
|
<table>
|
|
<tr>
|
|
<td>Cell</td>
|
|
<td>Value</td>
|
|
<td>Note</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[1,1]</td>
|
|
<td>IQT22</td>
|
|
<td>Cell A1 has the system name of the table</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[1,2]</td>
|
|
<td>Yard table</td>
|
|
<td>Cell B1 has the user name of the table</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[2,2]</td>
|
|
<td>West yard</td>
|
|
<td>Cell B2 has the name of column B</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[4,1]</td>
|
|
<td>Leftmost turnout</td>
|
|
<td>Cell A4 has the name of row 4</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Yard table[4,1]</td>
|
|
<td>Leftmost turnout</td>
|
|
<td>The user name of the table can be used to access the table</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[5,3]</td>
|
|
<td>IT203</td>
|
|
<td>Cell C5 has the value 'IT203'</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[Left turnout,North yard]</td>
|
|
<td>IT303</td>
|
|
<td>Column 'North yard' and row 'Left turnout' has the cell D5 with the value
|
|
'IT303'</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Yard table[Left turnout,North yard]</td>
|
|
<td>IT303</td>
|
|
<td>Column 'North yard' and row 'Left turnout' has the cell D5 with the value
|
|
'IT303'</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[Leftmost turnout,{IM3}]</td>
|
|
<td>IT101</td>
|
|
<td>IM3 is in curly brackets and have the value 'West yard' so this points to cell
|
|
B4</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[{IM4},East yard]</td>
|
|
<td>IT212</td>
|
|
<td>IM4 is in curly brackets and have the value 'Rightmost turnout' so this points to
|
|
cell C7</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>IQT22[{IM4},{IM3}]</td>
|
|
<td>IT112</td>
|
|
<td>Column {IM3} and row {IM4} points to cell B7</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>{IM5}[{IM4},{IM3}]</td>
|
|
<td>IT112</td>
|
|
<td>Even the table name can be accessed indirectly</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>Note that a Memory can point to a table. For example, if the memory IM7 has the value
|
|
'{Yard table[{IM3},Leftmost turnout]}', LogixNG will look at IM7, and find that it's value is
|
|
in curly brackets. It will then resolve the value inside these curly brackets, which is 'Yard
|
|
table[{IM3},Leftmost turnout]'. It will then resolve the value of IM3 which has the value
|
|
'West yard'. It will then get the table cell 'Yard table[West yard,Leftmost turnout]' which
|
|
is cell B4 with the value 'IT101'.</p>
|
|
|
|
<p>The ActionForEach iterates over a comma separated list of values. It can be used with
|
|
tables by using the keywords __columns__ and __rows__ . Note that it's two underscore
|
|
characters before and after. {IQT1[__columns__]} gives a comma separated list of all the
|
|
column names in the table IQT1. {IQT1[__rows__]} gives a comma separated list of all the row
|
|
names in the table IQT1. It's also possible to write {Yard table[__columns__]} and {Yard
|
|
table[__rows__]}. You can even use this syntax in ActionMemory to assign a Memory the list of
|
|
column names or row names. Note however that column names or row names that are empty is seen
|
|
as colums or rows with a comment and therefore they are not included.</p>
|
|
|
|
<p>Tables are loaded by a start up action. They are created in a spreadsheet, like Microsoft
|
|
Excel or LibreOffice Calc and then exported to a CSV file, separated by TAB characters. The
|
|
table is read only and is not stored in the panel filee, so it must be reloaded each time
|
|
JMRI starts.</p>
|
|
curly brackets, these characters must be escaped by preceding them with a backslash.
|
|
Examples: \, \[ \] \{ \} \\
|
|
<p>If a reference contains a backslash, it will take some more time to evaluate it than if it
|
|
doesn't contain any backslash. So if it's possible to not use these special characters in
|
|
references or names of beans, it's recommended.</p>
|
|
<!-- <h3>Important</h3>
|
|
|
|
<p>In order for indirect access to work, some limitations are put on the names
|
|
used in LogixNG. System names and user names must not contain comma, square brackets
|
|
and curly brackets. For example, if a turnout has the name 'Green yard, left turnout',
|
|
it cannot be used with its user name in LogixNG unless the name is changed and the
|
|
comma is removed.</p> -->
|
|
|
|
<p class="noted">LogixNG is both the name of the JMRI tool and the name of the main component
|
|
of that tool.</p>
|
|
|
|
<h2 id="enable">Enabled and Execution enabled</h2>
|
|
|
|
<p>The intention with LogixNG is to be similar to Logix, in order to make it easier for users
|
|
of Logix to understand how LogixNG works.</p>
|
|
|
|
<p>This has resulted in a big challenge when it comes to <strong>Enabled</strong>, since in
|
|
Logix, a Conditional that is not <strong>Enabled</strong> will still calculate its variables
|
|
but not execute its actions.</p>
|
|
|
|
<p>In LogixNG, there is a need to be able to completely disable the calculation too, and not
|
|
only the execution of actions. Therefore, in LogixNG, if a LogixNG or a ConditionalNG is not
|
|
<strong>enabled</strong>, it's not evaluated at all.</p>
|
|
|
|
<p>But LogixNG also needed to be somewhat compatible with Logix, for example to be able to
|
|
import Logixs to LogixNG. In order to solve that, LogixNG has <strong>execution
|
|
enabled</strong>. If a LogixNG or a ConditionalNG doesn't have <strong>execution
|
|
enabled</strong>, it's only evaluated but not executed.</p>
|
|
|
|
<p>There is however a problem with <strong>execution enabled</strong> . Not all of the
|
|
actions supports this. Only the actions <a href="#aaa">IfThenElse</a> and <a href=
|
|
"#bbb">Logix</a> supports <strong>execution enabled</strong>.</p>
|
|
|
|
<h2 id="scripts2">Scripts</h2>
|
|
|
|
<p>All types of LogixNG actions and expressions may use Python/Jython scripts. Below follows
|
|
the description of scripts for digital expressions, but the same pattern applies to all the
|
|
types of actions and expressions.</p>
|
|
|
|
<p>The digital expression that handles scripts is ExpressionScript.</p>
|
|
|
|
<p>The script that is executed by ExpressionScript must declare a class that extend the class
|
|
AbstractScriptDigitalExpression. The script must override the method evaluate(). For a script
|
|
that listen to other beans, it's recommended to also override the methods
|
|
registerScriptListeners() and unregisterScriptListeners().</p>
|
|
|
|
<p>When called, the script must tell the caller which class to use. It does that by setting
|
|
the variable params._scriptClass.set(instance)</p>
|
|
|
|
<p>Example of a digital expression script:</p>
|
|
|
|
<div style="margin-left: 2em;">
|
|
<p><code>import jmri<br>
|
|
<br>
|
|
class
|
|
MyExpression(jmri.jmrit.logixng.digital.expressions.AbstractScriptDigitalExpression):<br>
|
|
<br>
|
|
l = lights.provideLight(\"IL1\")<br>
|
|
<br>
|
|
def registerScriptListeners(self):<br>
|
|
self.l.addPropertyChangeListener(\"KnownState\", self);<br>
|
|
<br>
|
|
def unregisterScriptListeners():<br>
|
|
l.removePropertyChangeListener(\"KnownState\", this);<br>
|
|
<br>
|
|
def evaluate(self):<br>
|
|
return self.l.commandedState == ON<br>
|
|
<br>
|
|
params._scriptClass.set(MyExpression(params._parentExpression))<br></code>
|
|
</p>
|
|
</div>
|
|
|
|
<h2 id="indirect_accessing">Indirect adressing of NamedBeans</h2>
|
|
|
|
<p>In some cases, it may be useful to use indirect addressing of NamedBeans.</p>
|
|
|
|
<p>This can be done in two ways:</p>
|
|
|
|
<ul>
|
|
<li>Using a Memory that has the name of the NamedBean</li>
|
|
|
|
<li>Using a NamedBeanMap to lookup the name of the NamedBean</li>
|
|
</ul>
|
|
|
|
<p>Using a Memory that has the name of the NamedBean</p>
|
|
|
|
<p>Lets say we have an ActionTurnout that should throw a particulat turnout. But we wnat to
|
|
be able to select which turnout to throw at a later time. We can solve that by storing the
|
|
system name or user name in a Memory. We then tell the ActionTurnout to read the Memory and
|
|
lookup the turnout on the fly.</p>
|
|
|
|
<p>Since LogixNG fully supports string manipulation and calculations of both integers and
|
|
floating point values, where are plenty of possibilities here.</p>
|
|
|
|
<h3>Warning</h3>
|
|
|
|
<p>There is one major drawback with this. Since LogixNG doesn't know in advance which
|
|
NamedBeans will be accessed indirectly, it's not possible for LogixNG to automaticly register
|
|
listeners to the named beans that should trigger on change. For example, an ExpressionTurnout
|
|
registers a listener on the turnout, if the name of the turnout is given, but if the
|
|
ExpressionTurnout is using indirect addressing of the turnout, it's not able to do that.</p>
|
|
|
|
<p>The solution is to use the ActionListenOnBeans and tell this action which beans to listen
|
|
on. Any time any property of any of the named beans this action listen to, the ConditionalNG
|
|
will be executed.</p>
|
|
|
|
<p>Example:</p>
|
|
|
|
<p>A ConditionalNG is using turnouts IT1, IT2, IT3, IT4 and IT5 in it's expressions and wants
|
|
each of them to trigger on change. Turnouts IT1 and IT3 and IT4 are directly accessed in
|
|
expressions and IT2, IT3 and IT5 is indirect accessed.</p>
|
|
|
|
<p>Each turnout that is directly addressed in an expression will the ConditionalNG listen to
|
|
automaticly, so IT1, IT3 and IT4 will be listen to. But in order to listen on turnouts IT2
|
|
and IT5, the ActionListenOnBeans needs to be used.</p>
|
|
|
|
<p>The ActionListenOnBeans can be placed anythere in the ConditionalNG tree, as long as it
|
|
and its parents are enabled. If you disable this action, or any of its parent actions, the
|
|
ActionListenOnBeans will not listen on its named beans.</p>
|
|
|
|
<p><strong>ActionFor</strong>
|
|
</p>
|
|
|
|
<p>ActionFor is a for-loop. It has four children.</p>
|
|
|
|
<ul>
|
|
<li><strong>Init</strong> - this action is first executed once. It's used to initialize the
|
|
loop, for example setting a Memory to a particular value.</li>
|
|
|
|
<li><strong>Condition</strong> - this expression decides if the loop should run one lap
|
|
more. The loop will continue to run until this condition will be
|
|
<strong>false</strong>.</li>
|
|
|
|
<li><strong>Next</strong> - this action is executed at the end of the loop. It can for
|
|
example be used to increment a counter in a Memory.</li>
|
|
|
|
<li><strong>Action</strong> - this action is executed in each loop. It does the main
|
|
work.</li>
|
|
</ul>
|
|
|
|
<p>Then ActionFor is executed, the Init action is run once. After that, the Condition
|
|
expression is evaluated. If the condition returns <strong>true</strong>, the Action action is
|
|
executed and at last the Next action is executed. Then the process is repeated, except that
|
|
the Init action is only executed once.</p>
|
|
|
|
<p><strong>ActionForEach</strong>
|
|
</p>
|
|
|
|
<p>ActionForEach is a for-loop.</p>
|
|
|
|
<p>This action has a list of items. Either a constant list, or it can use a NamedBeanMap.</p>
|
|
|
|
<p>The ActionForEach action loops thru the list. It takes the first item in the list, assigns
|
|
it to a Memory, and then executes its child action. Then it takes the second item in the
|
|
list, assigns it to the Memory, and executes the child action.</p>
|
|
|
|
<p>The Logix action reads a digital child expression and then executes boolean actions. Each
|
|
boolean action takes the result from the expression and takes action accordingly. The
|
|
recommended child boolean actions for this action is the OnChange action. The Logix action,
|
|
together with the OnChange child boolean actions, acts like the JMRI Logix, with explains the
|
|
name of this action.</p>
|
|
|
|
<h2 id="digital_boolean_actions2">List of digital boolean actions</h2>
|
|
|
|
<p>This section lists all the digital boolean actions that is currently available with
|
|
LogixNG.</p>
|
|
|
|
<p>Digital boolean actions takes a true/false value and do something. The most common use is
|
|
the digital action Logix together with the digital boolean action OnChange.</p>
|
|
|
|
<p>Digital boolean actions have system names with the letters <strong>DB</strong> (for
|
|
<strong>D</strong>igital <strong>B</strong>oolean action). Example: IQDB002 or IQDB:0053.
|
|
System names with colon are auto generated system names.</p>
|
|
|
|
<p style="color:red">Items in red may need rethink or removal. I have ideas, but not always
|
|
sure if these ideas are worth keeping. /Daniel</p>
|
|
|
|
<p style="color:blue">Items in blue is not up to date with documentation. The documentation
|
|
tells how they should work, but the code is not finished yet. /Daniel</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<p><strong>OnChange</strong>
|
|
</p>
|
|
|
|
<p>Executes a child action if the parameter is changed and to the desired value.</p>
|
|
</li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li>
|
|
<p><strong style="color:blue">ResetOnTrue</strong>
|
|
</p>
|
|
|
|
<p><strong style="color:red">Update the code</strong>
|
|
</p>
|
|
|
|
<p>The ResetOnTrue expression has two child expressions, one primary expression and one
|
|
secondary expression. When the primary expression becomes <strong>true</strong>, the
|
|
secondary expression is reset. This expression is primary designed to be used with a
|
|
timer expression as the secondary expression. The timer will then restart when it's
|
|
reset.</p>
|
|
|
|
<p>The user can select between four different ways on when this expression answers
|
|
<strong>true</strong>.</p>
|
|
|
|
<ul>
|
|
<li>The primary expression trigger, and until the secondary expression becomes
|
|
true.</li>
|
|
|
|
<li>The primary expression trigger, and while the secondary expression is true.</li>
|
|
|
|
<li>The primary expression stays true, and until the secondary expression becomes
|
|
true.</li>
|
|
|
|
<li>The primary expression stays true, and while the secondary expression is true.</li>
|
|
</ul>
|
|
|
|
<p>Example usages for this expression:</p>
|
|
|
|
<ul>
|
|
<li>Wait on a timer. For example, when turnout IT1 is thrown, wait 5 seconds until
|
|
expression becomes true.</li>
|
|
|
|
<li>Wait on a timer. For example, when turnout IT1 is thrown, let the expression be
|
|
true for 5 seconds.</li>
|
|
</ul>
|
|
</li>
|
|
|
|
<h2 id="notes">Additional Notes</h2>
|
|
|
|
<p>This section contains questions and answers that normally are not needed by LogixNG
|
|
users, but in some cases were important or of interest for previous versions of
|
|
LogixNG.</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<p><strong>How is a LogixNG started?</strong>
|
|
</p>
|
|
|
|
<p>Start of a LogixNG is similar to the way a light, a route, or other continuously
|
|
running JMRI entity starts. Internally a LogixNG has an "activate" method, that is
|
|
called when the LogixNG is created, after it is edited, or when it is loaded from a
|
|
configuration file. This method starts listeners for items in the expressions of the
|
|
LogixNG's ConditionalNGs. When any of these listeners fires (indicating that the
|
|
watched property of a expression has changed), the LogixNG is calculated, resulting in
|
|
appropriate actions being taken, provided the LogixNG is enabled.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<strong>When should Triggers Calculation be unchecked in an expression?</strong>
|
|
<p>Normally Triggers Calculation should be checked in all expressions that has this
|
|
option, so a change in any of its expression will trigger calculation of a LogixNG.
|
|
This results in the LogixNG quickly reacting to changes on the layout, and maintaining
|
|
the status of signals, turnouts, etc. as desired. There are situations, however, where
|
|
it is desirable to test the state of an entity, but not use it as a calculation
|
|
trigger. The following paragraphs describe a couple of those situations, but there are
|
|
others.</p>
|
|
|
|
<p>Occasionally a "logic loop" can result if triggering is not suppressed. For example,
|
|
if the state of a turnout is tested in a expression, and the same turnout is set in an
|
|
action of the same or another ConditionalNG of the same LogixNG, continuous triggering
|
|
(a logic loop) could result. The easiest way out of this dilemma is to test the
|
|
turnout, without using it as a triggering entity. This is done by unchecking Triggers
|
|
Calculation in <strong>all</strong> expressions where the turnout is specified. If the
|
|
turnout is used in expressions of more than one ConditionalNG of the LogixNG, it must
|
|
be unchecked everywhere it is used to suppress using it as a trigger.</p>
|
|
|
|
<p>Another situation arises when Delayed Set Sensor action is used with an internal
|
|
sensor to trigger a second LogixNG after the delay time has elapsed. If the second
|
|
LogixNG is not to be triggered before the delay time elapses, all of its expressions,
|
|
except for the delayed internal sensor, should be unchecked. This scenario might occur,
|
|
for example, if a ConditionalNG turns on something as its first action, and sets a
|
|
Delayed Set Sensor as its second action to turn off that something after a specified
|
|
time provided certain conditions are met.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<strong>What is a "logic loop" and how can it be avoided?</strong>
|
|
<p>A "logic loop" results when the program appears to slow down significantly or lock
|
|
up as multiple LogixNGs are continuously triggered by changing references to each
|
|
other. The best way to avoid a "logic loop" is to be aware of situations that can lead
|
|
to a loop, and plan your logic to avoid such situations.</p>
|
|
|
|
<p>A "logic loop" can result within a single LogixNG when a expression (sensor,
|
|
turnout, etc.) that triggers the LogixNG is also changed by that same LogixNG. The
|
|
LogixNG editor will detect some situations that could result in a loop, and will issue
|
|
a warning when you close the LogixNG. <strong>Heed these warnings!</strong> A warning
|
|
doesn't mean that a loop definitely will result if you continue. The warning message is
|
|
a "wake up call" that you should study carefully what you're doing to make sure a loop
|
|
won't result.</p>
|
|
|
|
<p>A more complicated situation involving two or more LogixNGs can also result in a
|
|
"logic loop". For example, if LogixNG 1 is triggered by sensor A, and has an action
|
|
that changes turnout B, and LogixNG 2 is triggered by turnout B and changes sensor A,
|
|
the potential for a loop exists as these LogixNGs trigger each other. You can easily
|
|
extend this idea to triggering chains (loops) involving three or more LogixNGs, and
|
|
even to interactions between LogixNGs and Routes. There is no test in the program to
|
|
warn about loops involving multiple LogixNGs. (To develop such a test would be very
|
|
difficult.)</p>
|
|
</li>
|
|
|
|
<li>
|
|
<strong>What should I do if I think I have a "logic loop"?</strong>
|
|
<p>When they do occur, "logic loops" can be a bit scary to trouble shoot. Your computer
|
|
may appear to be locked up, or slowed to a crawl as the loop uses up most of the
|
|
available computer time. Fortunately JMRI provides tools to help in design and
|
|
debugging. Unchecking "Triggers Calculation" for a expression (discussed above), can
|
|
help you design around loops when you have identified the LogixNG causing the looping
|
|
problem. To get around the lock up or slow down problem, start with all your LogixNGs
|
|
disabled, (see below) then enable them one by one until you discover the loop.</p>
|
|
|
|
<p>If the panel file containing LogixNGs loads automatically when the program starts
|
|
up, press and release the shift key a few times rapidly as soon as you see the small
|
|
JMRI splash screen (the first thing you see during start up). Your panel file will be
|
|
loaded with all LogixNGs disabled.</p>
|
|
|
|
<p>If you load your panel file manually using the Panels > Open Panel... menu,
|
|
before loading your file, go to the <strong>Debug</strong> menu and select <strong>Load
|
|
LogixNGs Disabled</strong>. After responding OK to the message, load your panel file as
|
|
you normally would. Your panel file will be loaded with all LogixNGs disabled.</p>
|
|
|
|
<p>After loading your panel file, open the LogixNG Table and verify that all LogixNGs
|
|
are disabled. If you know which LogixNG is causing the trouble, you can then fix it or
|
|
delete it, re-enable the other LogixNGs, and save your panel file. If you don't know
|
|
which LogixNG is causing the problem, you can enable your LogixNGs, one by one, until
|
|
the loop occurs. When the loop starts, you know that the last LogixNG you enabled is at
|
|
least partly responsible for the problem. At this point you should restart the program
|
|
with all LogixNGs disabled, and fix or delete the LogixNG you identified.</p>
|
|
|
|
<p><strong>CAUTION:</strong> <strong>It's wise to save your panel file frequently when
|
|
entering LogixNGs.</strong> If a logic loop occurs, it may be difficult, if not
|
|
impossible, to save your panel file before shutting down the program. Remember that a
|
|
LogixNG is activated as soon as you click <strong>Done</strong> in the Edit LogixNG
|
|
window. Also, remember that hitting an <strong>Edit</strong> button in the LogixNG
|
|
Table deactivates the selected LogixNG before opening it for editing, offering a
|
|
possible way to break into a logic loop without restarting the program.</p>
|
|
</li>
|
|
</ul>
|
|
|
|
<p>The ActionForEach iterates over a comma separated list of values. It can be used with
|
|
tables by using the keywords __columns__ and __rows__ . Note that it's two underscore
|
|
characters before and after. {IQT1[__columns__]} gives a comma separated list of all the
|
|
column names in the table IQT1. {IQT1[__rows__]} gives a comma separated list of all the
|
|
row names in the table IQT1. It's also possible to write {Yard table[__columns__]} and
|
|
{Yard table[__rows__]}. You can even use this syntax in ActionMemory to assign a Memory the
|
|
list of column names or row names. Note however that column names or row names that are
|
|
empty is seen as colums or rows with a comment and therefore they are not included.</p>
|
|
|
|
<hr>
|
|
|
|
<p><a href="index.shtml">Return to the Reference TOC</a>
|
|
<!--#include virtual="/help/en/parts/Footer.shtml" --></p>
|
|
</ul>
|
|
</div>
|
|
<!-- closes #mainContent-->
|
|
</div>
|
|
<!-- closes #mBody-->
|
|
<script src="/js/help.js"></script>
|
|
</body>
|
|
</html>
|