DecoderPro®

Advanced

Other Apps

Tools

JMRI provides powerful tools for working with your layout.

Layout Automation

JMRI can be used to automate parts of your layout, from simply controlling a crossing gate to running trains in the background.

JMRI: DecoderPro User Guide

Advanced Decoder Definitions

This page provides information on advanced features in the decoder definition files for the DecoderPro Symbolic Programmer.

Formatting on the page

You can do limited formatting on the display using HTML formatting tags.

You can embed HTML in pane text, but it must be enclosed in <html>...</html> tags.

This is made a bit tricky because of overlap between "tags as part of XML structure of decoder file" and "HTML tags included in the decoder file". All of the HTML tags need to be quoted, with their < and > characters replaced by the &lt; and &gt; strings and any embedded double quotes being replaced by &quot;.

For example:

   <label label="&lt;html&gt;&lt;strong&gt;JMRI 3.7.2 or later is required to use this definition.&lt;/strong&gt;&lt;/html&gt;"/>
After the XML is read, the contents of that label will be displayed from the text in the "label" attribute, which is:
   <html><strong>JMRI 3.7.2 or later is required to use this definition.</strong></html>
and will appear on the screen as

JMRI 3.7.2 or later is required to use this definition.

For more examples see xml/decoders/esu/v4readMePane.xml.

This provides only HTML5 support, so if something isn't displaying as you expect, see if an approach using simpler HTML will work.

Identification

When "Read Type from Decoder" is used to determine the correct decoder definition file, several pieces of information are read from the decoder and used to attempt a match to a family and model:
Manufacturer:
Numerical value from CV8, which is then matched to a name using the entries in the xml/decoderIndex.xml file.
Version code:
Numerical value from CV7, which is then matched to model name(s) using the lowVersionID and highVersionID values on model elements within all decoder definitions for the specific manufacturer. This is a complex process that doesn't always go well due to duplicate values, etc.
Product ID code:
Originally a numerical value read from a manufacturer-specific CV or CVs; this only works for certain manufacturers. The read process is handled in the code (the jmri.jmrit.decoderdefn.IdentifyDecoder class) and has to be updated each time a manufacturer starts providing values in one or more new CVs. When the product code is present, it should break any degeneracy between overlapping CV7 values within a decoder family. For example:
  <decoder>
    <family name="My Decoder Family" mfg="NMRA">
      <model model="Model A" lowVersionID="16" highVersionID="23" productID="400" />
      </model>
      <model model="Model B" lowVersionID="21" highVersionID="27" productID="401" />
      </model>
    </family>
    …
  </decoder>

Some decoders can have multiple possible stored Product IDs for otherwise-identical decoders. In this case multiple comma-separated values can be specified in the Product ID field and a match to any value in the list will identify the decoder uniquely. For example, the ESU series usesthe RailCom® Product ID CVs, but the Product ID is updated for various production batches of the same model:

  <decoder>
    <family name="ESU LokSound V4.0" mfg="Electronic Solutions Ulm GmbH" lowVersionID="255" highVersionID="255">
      <model model="LokSound V4.0" numOuts="92" numFns="40" extFnsESU="yes" productID="33554493,33554503,33554538">
      </model>
      <model model="LokSound V4.0 M4" numOuts="92" numFns="40" extFnsESU="yes" productID="33554500,33554536">
      </model>
    </family>
    …
  </decoder>

Warning: Do not use multiple possible stored Product IDs for similar decoders that need different conditional expansion. It will not work, for reasons explained in a section below. In this case, each Product ID must be assigned a different model name, as in the first example above.

Support is also being added to find this value using the LocoNet SV2 protocol some time during the JMRI 4.1 release series. See the release notes for more info on the progress.

Since the product code works with the include/exclude operations described below, you can also use it in cases where there's no CV or CVs that contain it. In that case, no automated ID is done, but the value from the productID attribute of the user-selected model is used during later processing and expansion of the decoder definition. Alphanumeric productID values are sometimes used for this to avoid conflicts with the numeric ones found in CVs.

When a decoder model is selected, either manually or as the result of the identification process, the family and model names are stored in the roster entry being created and are used for future linkage of a roster entry to a decoder definition.

It is important to note that the Manufacturer, Version Code or Product ID are not stored in the roster entry, as the values are not reliably determined in some instances (e.g. manual selection, firmware update by manufacturer-supplied software, updated ID information from vendor). This has implications for when the decoder definition is expanded for programming (Conditional Decoder Definitions) or updated (Updates and Migration).

Public-domain and DIY decoders

Since JMRI 4.11.5

The "Read Type from Decoder" feature is available for Public-domain and DIY decoders.

Three identifiers are used to identify the decoder:

Manufacturer:
Numeric value CV8 = 13 according to the NMRA standard S-9.2.2. file.
Version code:
The numeric value from CV7 where the software version is stored.
Product ID code:
Numeric value stored in CV47, CV48, CV49 and CV50 according to NMRA standard S-9.2.2 file and reserved for use by the manufacturer.

Product ID is calculated using the following formula:

  • Product ID = (((CV47 * 256) + CV48) * 256 + CV49) * 256 + CV50

Individual CVs have the following meaning:

  • CV47 - country code, for example CV47 = 1 for the Czech Republic
  • CV48 - developer or group of developers code, such as CV48 = 1 for dccdoma.cz
  • CV49 - third ProductID for further identification
  • CV50 - fourth ProductID for further identification

The corresponding decoder definition xml file has a filled <family> element. Example:

  <decoder>
    <family name="dccdoma.cz" mfg="Public-domain and DIY" >
      <model model="UNI16ARD-NAV" lowVersionID="41" productID="16843010" …  />
    </family>
    …
  </decoder>

The individual attributes of this element must be filled in as follows:

The name of the xml file with the definition of the decoder should have the following structure:

Public_Domain_family-name_model-model.xml

Where each part of a file name has the following meaning:

Example of a definition decoder file for signal decoder UNI16ARD-NAV.xml from the developers group dccdoma.cz who are from the Czech Republic Public_Domain_dccdoma_UNI16ARD_NAV.xml.

For the new country code and new developer code, please contact Groups.io jmriusers https://groups.io/g/jmriusers.

Pane Considerations

Programmer panes are used to split and organise decoder variables into convenient named categories.

Pane Replacement

Custom panes are usually added to definition files for one of the following reasons:
  1. The items to be shown do not fall into any of the categories defined by the standard pane names.
    • In this case the pane <name> element should be different from any existing standard names.
    • The new custom pane will be added at the end of the pane list.
  2. The applicable standard pane category does not have the correct layout or number of variables.
    • In this case the pane <name> element should exactly match the existing standard pane <name> element.
    • The new custom pane will replace the existing same-named standard pane.

Empty Panes

Empty panes are defined as those with no active variable elements to display for the selected decoder. They may still contain text content.

Pane Visibility

Pane visibility is governed by a complex set of rules:

Best Pactice

Advanced users may choose to hide empty panes, but Show Empty Tabs is enabled by default so beginner users need to see why panes are empty or where to find items not on the expected panes.

The recommended best practice is:

In some cases, e.g. a non-locomotive decoder for servos where none of the locomotive-decoder panes make sense so the decoder definition contains lots of custom panes, it's a simplification to put a showEmptyPanes="no" attribute in the <decoder-config> element of the definition XML and just hide all those empty panes by default.

Including Fragment Files

Common parts of decoder definitions can be placed into "fragment files", which can then be included into multiple decoder definition files. This makes it easier to maintain and update those common definitions, e.g. to translate them into other languages.

By convention, we these fragment files in subdirectories:

xml/decoders/nmra
The NMRA definitions for CVs, used by many decoder types
xml/decoders/(mfg)
Manufacturer-specific variables, for example xml/decoders/esu
The format for an include is:
     <xi:include href="http://jmri.org/xml/decoders/nmra/shortAndLongAddress.xml"/>
The program searches for those fragment files first in the preferences directory, then in the program directory. The full path must be present, e.g. you need an xml directory that contains a decoders directory in your preferences directory for the fragment file to be found.

Use an existing file as an example for the top elements & format needed.

Updates and Migration

Sometimes, we replace a decoder definition with a better one. The old one is in use, but we'd like to move those users to the new one eventually. There are model-level attributes that can be added to the old (not the new) definition to facilitate that:
    <model show="no" model="A4X" replacementModel="A4X" replacementFamily="Jan 2012">
      
When the user selects "Update Decoder Definitions" from the Debug menu on PanelPro window or the Action menu in DecoderPro, all their existing roster entries that use a decoder definition with replacementModel and/or replacementFamily defined will be updated to the specified replacement decoder definition instead. This lets people keep using their old, comfortable decoder definition (the old file remains in JMRI) until they decide to move forward to a new one.

Note that an update defined this way is unconditional; if the family and model attributes match a roster entry, it will be updated to the new family/model. Automated conditional updates based on versionID or productID are not possible as these values are not stored in the roster entry. An interactive update process is now available in these cases and uses a special syntax: Since JMRI 4.9.5

    <model show="no" model="DP2X" numOuts="2" numFns="2" replacementFamily="query:Jan 2000|June 2007|Jan 2012">
      

A replacement field begining with the string "query:", optionally (preferably) followed by a vertical bar "|" separated list of possible replacements, triggers interactive user dialogs, containing further explanations and guidance for the user. Click here and here for typical samples of these dialogs. Missing decoder definitions will also be detected. Click here and here for more samples.

The model element "show" attribute helps ensure that new users starts with the new definition. Its possible values are:

To create a completely new definition for an existing model:
  1. Decide where you want the new model defined. It has to have either a new model name, a new family name (new file) or both.
  2. Create your definition.
  3. Add "replacementModel" and "replacementFamily" attributes to the old definition.
  4. Generally, set the "show" attribute in the old definition to "no". The only exception to this is when some users will want to select the old definition still for a new decoder, perhaps because automatic identification can tell the uses of the old definition from the new one. (E.g. you're splitting the old definition into two parts because a new locomotive version exists)

Programming Capabilities

Some decoders can do extra programming operations, for example bypassing limitations on CV programming in the command station. "Capability" elements are used to tell DecoderPro about these.

Access to High CV addresses

Certain command stations can only access up to CV 256 or CV512. Some decoder manufacturers have built in mechanisms to bypass this. For example, some ESU decoders can use writes to various CVs to access high-address CVs. To tell DecoderPro that a decoder can do this, use an element like:
    <capability>
        <name>High Access via Double Index</name>
        <parameter name="Max Regular CV address">256</parameter>
        <parameter name="High Address CV">96</parameter>
        <parameter name="Low Address CV">97</parameter>
        <parameter name="Access Register CV">99</parameter>
        <parameter name="Modulo">100</parameter>
    </capability>

The parameters must appear in the order shown. They mean:

For example, to write 21 to CV 614 with the values shown, DecoderPro will:

For an example of where to position this capability element in the file, etc., see the xml/decoders/ESU_LokSoundV4_0.xml file.

Another approach, used by e.g. Zimo, is to provide a way to page the access. For example, to write 21 to CV614 with one of these, you need to:

This capability element will do that:
        <capability>
            <name>High Access via Partial Index</name>
            <parameter name="Max Regular CV address">100</parameter>
            <parameter name="High Address CV">7</parameter>
            <parameter name="High Address Multiplier">10</parameter>
            <parameter name="Modulo">100</parameter>
        </capability>
Note that it has a different "name" value. That's what selects the different algorithm needed here.

The parameters must appear in the order shown. They mean:

Another approach used by e.g. Zimo uses a page register that has to be reset afterwards. For example, to write 21 to CV614 with one of these, you need to:

This capability element will do that:
        <capability>
            <name>High Access via Partial Index with Reset</name>
            <parameter name="Max Regular CV address">100</parameter>
            <parameter name="High Address CV">7</parameter>
            <parameter name="High Address Multiplier">10</parameter>
            <parameter name="Modulo">100</parameter>
            <parameter name="Indicator">200</parameter>
        </capability>

The parameters must appear in the order shown. They mean:

Accessory Decoder Ops Mode

Certain accessory decoders require special programming packets to configure their CVs from the DCC track signal. The capability to do that is written:
        <capability>
            <name>Ops Mode Accessory Programming</name>
            <parameter name="Address Type">decoder</parameter>
            <parameter name="Delay">200</parameter>
        </capability>
The "Address Type" parameter is optional: The "Delay" parameter is optional and specifies a minimum delay (in milliseconds) between successive writes. Some decoders will miss commands if the delay is too short. If this is parameter is omitted, the default delay is 500 milliseconds.

Note that this only works for ops-mode writes; these particular NMRA DCC packets do not perform read operations, nor do they work in the service mode (programming track).

Note an element:
        <variable … item="Short Address" …>
            …
        </variable>
or:
        <variable … item="Long Address" …>
            …
        </variable>
is required so the Ops Mode programmer has an address to use. Either form functions identically. The "Address Type" parameter is the only way to specify whether the address is 9-bit or 11-bit.

For a working example, see the xml/decoders/ESU_SwitchPilot.xml file. In the case of this example decoder, the address is stored in CVs 1 and 9 as per NMRA standard 9.2.2.

Ops Mode Delayed Programming

Most locomotive decoders accept special programming packets to configure their CVs from the DCC track signal (Programming on Main).

However these packets take time to process and if subsequent packets are sent too soon they can be missed. The capability to do add a delay after programming each CV is written:
        <capability>
            <name>Ops Mode Delayed Programming</name>
            <parameter name="Delay">500</parameter>
        </capability>
The "Delay" parameter specifies a minimum delay (in milliseconds) between successive writes. Some decoders miss commands if the delay is too short. If this is parameter is omitted, the default delay is 500 milliseconds.

Note that this only works for ops-mode writes; these particular NMRA DCC packets do not perform read operations, nor do they work in the service mode (programming track).

Note also that this particular capability only works for multi-function decoders. Accessory decoders need to use the Accessory Decoder Ops Mode capability, which has its own "Delay" parameter.

Indexed CV Access

To access indexed CVs, include this capability element:
        <capability>
            <name>Indexed CV access</name>
            <parameter name="PI">31</parameter>
            <parameter name="SI">32</parameter>
            <parameter name="cvFirst">false</parameter>
            <parameter name="skipDupIndexWrite">true</parameter>
        </capability>

If cvFirst is true, the format is CV.PI or CV.PI.SI as used by QSI. If it's false, the format is PI.CV or PI.SI.CV as used by ESU.

If skipDupIndexWrite is true, certain writes to the PI and SI CVs can be skipped if the user selects skipping them. This speeds up access. Some decoders require that the CVs be written for each operation, in which case this should be set to false. The default is true.

If both this and the "access to high CV" capabilities are present, this one should be listed second.

For an example of where to position it etc., see the xml/decoders/ESU_LokSoundV4_0.xml file.

TCS WOW decoder access

The TCS WOW decoders use several unique (to say the least) CV access methods. JMRI accommodates them via a special capability element:
        <capability>
            <name>TCS 4 CV access</name>
        </capability>
This provides two custom CV formats: For examples of how to use these, see the TCS WOW decoder definition.

Split Variables - "long" addresses over 2 CVs

Some decoders, mostly accessory decoders, are using "long" addresses that are split over 2 CVs, contiguous or not.

CV1 and CV9 are standardized by NMRA for accessory decoders primary address, see NMRA standard 9.2.2.

Long addresses can be accessed via "splitVal" type, as in the following example:

    <variable CV="1" item="Short Address" default="1" minOut="1">
        <splitVal highCV="9" upperMask="XXXXXVVV"/>
        <label>Accessory Address</label>
    </variable>

The first declared CV is the LSB (Least Significant Byte) whereas the "high CV" is the MSB (Most Significant Byte).

splitVal actually has two parameters, a "Factor" and an "Offset":

    <splitVal highCV="9" factor="4" offset="-3"/>

For an example, see the xml/decoders/SPROG_DCC_Servo6.xml file.

For details and more advanced features, see this Javadoc page

Conditional Decoder Definitions

To reduce the number of decoder definition files needed, each file can contain definitions for multiple decoder models. JMRI provides ways of adapting the definition to specific models both when the file is being initially expanded for use, and later while the program is working on the definition. These are particularly useful when using a common fragment file that might be included by multiple decoder definition files (defining different-but-similar families)

Include/Exclude During Variable Expansion

Whether a variable element is expanded and used can be made conditional on the decoder type using "include" and "exclude" attributes on <variables>, <variable>, <enumChoice> and <enumChoiceGroup> elements.

A variable definition will not be expanded and used:

Both of these conditions must be true, and it's possible to use both include and exclude on the same element, but it's more usual to just use one.

Example:

      <variable label="My Variable" CV="72" include="ModelA,400">
        <decVal/>
      </variable>

The variable above will only appear when expanding the decoder definition for ModelA or product ID 400.

You can also put include and exclude attributes on individual choices in an enumeration-type variable. This can be used to e.g. only include specific lighting options in certain decoder families.

Attributes on a <variables> element act on all the <variable> elements within it, along with any include or exclude attributes on those individual variables.

You can also use the include mechanism to specify the default value of a variable.

Example:

      <variable label="My Variable" CV="72" default="3">
        <defaultItem default="12" include="815"/>  
        <decVal/>
      </variable>

This will set the default (initial) value of the CV to 12 if the "815" matches, and otherwise use the default-default of 3. You can have as many defaultItem elements as needed; the first one that matches is used.

Include/Exclude During Pane Creation

Whether a pane (or part of a pane) is created can be made conditional on the decoder type using "include" and "exclude" attributes on <pane> and <group> elements.

A pane will not be created:

Both of these conditions must be true, and it's possible to use both include and exclude on the same element, but it's more usual to just use one.

Example:

      <pane label="My Pane" include="ModelA,400">
        ...
      </pane>

"My Pane" will be created only when expanding the decoder definition for ModelA or product ID 400.

You can also create a <group> element with include and exclude attributes. Elements within the <group> will be created only if the <group> conditions are met. This can be used to e.g. display specific text labels only for certain decoder models.

Example:

      <group include="ModelA,400">
        <label>
          <text>These decoders are very old.</text>
        </label>
        <label>
          <text>Some features are unavailable.</text>
        </label>
      </group>

The text will be created only when expanding the decoder definition for ModelA or product ID 400.

Warning Regarding Use of Product ID in Include/Exclude

Care must be exercised when attempting to match against product ID in include or exclude attributes. The product ID is not matched against any value read from the decoder during identification but against the productID attribute specified in the decoder definition. This can particularly be a problem if the productID attribute has multiple values. For example:
  <decoder>
    <family name="My Big Family" mfg="NMRA">
      <model model="My Model" productID="400,401" />
      </model>
    </family>
    …
  </decoder>
  <pane label="My 400 Pane" include="400">
    …
  </pane>
  <pane label="My 401 Pane" include="401">
    …
  </pane>
Both panes will always be created. If the definitions need to differ between product IDs, you will need to create two models, as per the first example under Identification.

Run-time Qualification of Variables

Qualifying Variables
A "qualifier" element on a variable element allows you to enable or disable the variable depending on the current value of another variable. This can be useful if, for example, the decoder has a "mode" CV that determines the meaning of other CVs.

If a variable is qualified as inactive, it doesn't appear in any panes and is neither read nor written to the decoder when you do "All" or "Changes only" read or write operations. The value is saved to the roster and will be reloaded when the roster entry is reopened later.

In the following example, a CV is interpreted as two different variables depending on whether the decoder is set for short or long addressing.

  <variable label="Variable for Short Address" CV="11">
    <qualifier>
      <variableref>Address Format</variableref>
      <relation>eq</relation>
      <value>0</value>
    </qualifier>
    <decVal/>
  </variable>
  <variable label="Variable for Long Address" CV="11">
    <qualifier>
      <variableref>Address Format</variableref>
      <relation>eq</relation>
      <value>1</value>
    </qualifier>
    <decVal/>
  </variable>
Other available operators include "gt", "ge", "ne", "lt", "le" and "exists". The "exists" operator checks for whether a variable is defined or not; a "1" value means that it is, and a "0" means that it doesn't.

If multiple qualifier elements are present, all must be true for the variable to be active and displayed.

Qualifying Panes
A "qualifier" element on a pane element allows you to enable or disable the pane depending on the current value of a variable.

If a pane is qualified as inactive, its contents are no longer shown. This includes any labels or other decorations on the pane, in addition to the variables it contains. Depending on other options, the pane may either show as empty, or not show at all. The variables within it are still active, though, and a "Read all sheets" or "Write all sheets" will still write them. If you have overlapping variable definitions, consider carefully whether this is what you want. You might need to qualify the individual overlapping variables.

The following example enables one of two panes depending on whether the decoder is currently set for short or long addressing.

  <pane name="Short Only">
    <qualifier>
      <variableref>Address Format</variableref>
      <relation>eq</relation>
      <value>0</value>
    </qualifier>
    <column><row>
      <label label="Short Only Pane"/>
    </row></column>
  </pane>
  <pane name="Long Only">
    <qualifier>
      <variableref>Address Format</variableref>
      <relation>eq</relation>
      <value>1</value>
    </qualifier>
    <column><row>
      <label label="Long Only Pane"/>
    </row></column>
  </pane>
Other available operators include "gt", "ge", "ne", "lt" and "le".

If multiple qualifier elements are present, all must be true for the pane to be active and displayed.

Qualifying Elements on Panes
A "qualifier" element on a "label", "soundlabel", "row", "column", "grid" or "griditem" element allows you to enable or disable the display of that element on a specific pane.

The following example displays a warning label if a version-number variable has a too-low value:

    <label label="Version number too low!">
      <qualifier>
        <variableref>Version Number</variableref>
        <relation>lt</relation>
        <value>3</value>
      </qualifier>
    </label>

You can use the same qualifier for multiple elements by enclosing the elements in a "group" element and adding the qualifier to the "group" element:

    <group>
      <qualifier>
        <variableref>Version Number</variableref>
        <relation>lt</relation>
        <value>3</value>
      </qualifier>
      <label label="Version number too low!"/>
      <label label=" "/>
      <label label="Please update."/>
    </group>

Once you've read the Version Number (variable or CV) from the decoder, the label(s) will display iff that version number is too low. Note that initially, before the values are read from the decoder, this display will depend on the default value from the file, which might be misleading to the user.