JMRI: Names and Naming
This page discusses how JMRI objects are named, how those names are used to reference the objects (hardware and software), and how user-readable names are used.
Since JMRI 4.7.4 As of March 2017, we have changed the allowable user names: They can't have leading or trailing spaces. If leading or trailing spaces are entered, they'll be "trimmed" off.What's in a name?
Why do we need names at all, rather than just references within the code? There are several important uses:- When working with user input, e.g. typing a number in a field, the code will need to know how to map the user-provided info onto objects. Sometimes the user will want to name objects with arbitrary user names, e.g. "East Lockport Turnout". These can't be known until their mapping to hardware has been made. But other times these will be de-novo identifications that the code must understand, e.g. something that means "LocoNet Turnout 23".
- We imagine that configurations will be stored in XML files, in a symbolic form. Names are a convenient way to connect objects and object references in that kind of configuration.
Items with names
There are lots of things that might need names:- Aspects for signals
- Blocks (track segments)
- Conditionals (for logiX, although these are not entirely named beans)
- signal mast Groups
- signal Heads
- signal masts (F, for some reason)
- Lights (a type of output)
- eNtry/exit destiNation points
- Memories
- Outputs
- Power districts and subdistricts
- Reporters
- Routes (shared for historical reasons with Reporters)
- input Sensors
- Turnouts
- logiX
- Sections (Y, for some reason)
System and User Names
JMRI users both "system names" and "user names" to reference things.We want users to be able to call things what they want. Names like "p(24,23)*" are not useful. Every named item can therefore have a "user name", which is an entirely free-form string. You can put whatever you want in there, so long as it's not a duplicate of the user name given to something else. For example, you might call a Turnout "West Yard Lead" or "Turnout 32" or "Green Wire from Controller" or whatever.
At the same time, we need a shorthand name, really a unique identifier, to talk about specific objects. This doesn't have to be convenient, but does have to have a clear mapping from name to object and back. For example, we need a very specific way to identify "LocoNet Turnout 23". We call these "system names". JMRI code will map these to and from whatever information the hardware may need.
System Name Format
A system name is formed from a short "system prefix" representing the hardware system, followed by a single upper case "type letter" indicating the type of the object, followed by a system- and type-specific "suffix string" identifying a specific object.- The system prefix is a single uppercase or lowercase letter, optionally followed by one or more digits. Special characters are not allowed. This simple form allows us to always find the system prefix and type letter even if we don't know the full list of hardware systems involved.
- The type letter defines the type of model-railroad object, such as (T)urnout or (S)ensor, see below.
- The suffix string is meant to be related to the hardware addressing for the specific hardware system, but is otherwise unconstrained. Some are simple numbers, such as a device address. Others are much more complicated strings to carry more complex information.
Examples:
Note: These assume the default values of system prefix letters, but they certainly could have been defined differently.- LT23 - LocoNet Turnout 23.
- L2T23 - Turnout 23 on the second LocoNet connection.
- CS2012 - A C/MRI Sensor (input line) addressed as 2012, which means the 12th pin on on the node with address 2.
System Prefix
Originally, the "hardware prefix" was a single uppercase letter identifying a single system connection: L for LocoNet, N for NCE, etc. The default letters for those are listed below. This is still by far the most common use: Most model railroads have a single connection, and just use the default letter.The JMRI code is much more flexible than that, however. This allows it to deal with multiple system connections and overlaps of letters (such as the multiple possibilities defined for "D" or "M" below). You change the letter associated with a system connection in the preferences to any other uppercase or lowercase letter. You can call your NCE connection "P" if you want to. If you have two of them, you can call one "X" and the other "Y". You can also use an upper case letter followed by digits, e.g. "N1" and "N2".
Default System Letters
Note that some of these are placeholders, and have no underlying implementation. (Links are to JMRI pages with more information)
Also note that some older implementations used formats that don't meet the current standard, with system letters such as "DX", "DCCPP", "DP", "MR", "MC", "PI", "TM". These need to be migrated, and we have a have a process in place to do that.
- A CTI Acela, Bachrus Speedometer
- B Direct DCC control
- C C/MRI serial
- D SRCP,
Anyma DX512
DCC++ (previously written DCCpp)
DCC4PC - E EasyDCC
- F RFID tag readers
- G ProTrak Grapevine
- H
- I Internal, e.g. objects with no associated hardware
- J JMRI network connections
- K Maple Systems
- L LocoNet
- M Model railroad layout control buses, including
OpenLCB
and MERG CBUS
Model Rectifier Corp (MRC)
Marklin CS2 - N NCE (also Wangrow currently)
- O Oak Tree Systems
- P Powerline
transmission, e.g. X10 and Insteon,
Raspberry Pi native pins - Q QSI programmer interface
- R RPS system
- S SPROG
- T Lionel TMCC,
TAMS - U ESU ECoS
- V TracTronics SECSI
- W (reserved for Wangrow, but that's currently still combined with NCE)
- X XpressNet used by a number of Lenz, Atlas, Hornby and other connections
- Z ZimoMX-1, IEEE802.15.4 and Z21 connections
Device type letters
Note that some of these are placeholders, and have no underlying implementation. Also, there is no guarantee that any given hardware system will ever implement all of them.- A Audio - an internal software object that holds information about a sound sample to be placed at a specific position in 3d space
- B Block - A software object that keeps track of the contents of a specific block of track. Block system names are all upper case, have no trailing whitespace and start with IB.
- D iDentity - A software object that holds information about an identity tag that is, typically, attached to a piece of rolling stock. These objects are not system-specific but are Internal objects, hence have system names commencing with ID. The underlying hardware will use Reporter objects to communicate back to JMRI when a specific iDentity object has been seen.
- F signal mast (F is not particularly mnemonic; maybe a mast with two heads looks like an F from the side? All the good letters were taken)
- G signal Group - A set of signal heads to a main masts. For new items using IG at the start is recommended; the example name is "IG12". For historical reasons, Groups were not required to have a system prefix or type letter until late; Since JMRI 4.13.4Using only one single letter in the system name is no longer compatible with system name normalization.
- H signal Head - One part of a signal (which may have multiple heads). Also interpreted to include indicators on control panels that are acting to display signal aspects. SignalHead system names are all upper case, have no trailing whitespace and mostly, but not always, start with IH.
- M Memory - As yet, this has no real equivalent in the layout hardware, but is used as a place to store information temporarily and display it on panels, etc. Memory system names are all upper case, have no trailing whitespace and start with IM.
- L Light - another form of output, used to e.g. control lights on a layout
- N eNtry/exit destination points
- P Power manager i.e. layout, district, subdistrict; not all systems distinguish between these, so the device type letter doesn't either. The system-specific part of the name can. For example, the system specific part might be B for main layout power, e.g. LPB or S42 for subdistrict channel 2 on card 4, e.g. LPS42.
- Q LogixNG - a set of logic equations used to control the layout. LogixNG system names start with IQ.
- R Reporters - a general purpose mechanism for reporting complicated information from the layout, e.g. locomotive identification from some transponding hardware, RFID tag numbers, etc.
- R Routes - a tool for setting multiple Turnout states at once. The "R" letter is shared with Reporters for historical reasons.
- S Sensors - general purpose input sensors that can generally be either ACTIVE or INACTIVE. This is most commonly used for block occupancy detectors.
- Y Sections - holds a map of trackwork. Section system names are all upper case, have no trailing whitespace and start with IY.
- T Turnout - actually a general purpose output on the layout
- X logiX - a set of logic equations used to control the layout. Logix system names are all upper case, have no trailing whitespace and start with IX.
System-specific suffix
"Internal" objects can also be addressed and manipulated, but they don't have a strict correspondence with some hardware on the layout. For example, if a signal head is implemented as three different outputs, LT1, LT2 and LT3, the signal head object might be called IH3.
Each different hardware system can specify the "suffix string" that follows the system and type letters. Generally, these are small numbers, but their exact meaning is very system-specific. For more information, please see the specific pages for
(If you find any missing or see omissions in the following summary, please add a reference)
Adding an item to the table - Entry Format Summary
When you add an item to one of the tables, many times you only
have to enter the numbers and have JMRI construct
the complete system name.
Here's a summary of the options per Connection, split up for
outputs (eg. Turnouts) and inputs (eg. Sensors):
Connection | In/Out | Entry | Meaning | makes System Name | Mask | Equivalent | Minimum | Maximum |
---|---|---|---|---|---|---|---|---|
C/MRI | i/o | 1003 | Node 1, Input 3 | CS1003 | n digits (node) + 3 digit (pin) | 1:3 | node: 1; pin: 1 | node: 127; pin: 999 |
C/MRI | o | 3 | Node 0, Output 3 | CT3 | 1 | 999 | ||
C/MRI | i/o | 4003 | Node 4, Output 3 | CT4003 | n digits (node) + 3 digit (pin) | 4:3 | node: 1; pin: 1 | node: 127; pin: 999 |
C/MRI | i/o | 4:3 | Node 4, Output 3 | CT4:3 | 4003 | 0:1 | 127:999 | |
C/MRI | i/o | 4B3 | Node 4, Output 3 | CT4B3 | 4003 | 0B1 | 127B999 | |
DCC++ | i | 4:3 | (converts to 50) | DT50 | node : pin | 0 | ||
DCC++ | o | 12 | ID in internal DCC++ table | DT1212 | integer | 0 | 32767 | |
DigiXbee | i | 4:3 | ModuleAddress:Pin | ZS4:3 | int : int | pin: 0 | pin: 71(?) | |
DigiXbee | o | 4:3:4 | ModuleAddress:Pin1:Pin2 | ZT4:3:4 | int : int : int | pin: 0 | pin: 71(?) | |
Grapevine | i | 22016 | Sensor node 22, pin 16 | GS 22 016 | n digits (node) + 3 digit (pin) | node: 1; pin: 001 | node: 127; pin: 016 | |
Grapevine | i | 22p16 | p = parallel input | GS 22 p16 | int + p + int (pin) | p1 | p16 | |
Grapevine | i | 22a3 | a = ASD occupancy sensor | GS 22 a3 | int + a + int (pin) | 22103 | a1 | a24 |
Grapevine | i | 22103 | a = ASD occupancy sensor | GS 22023 | int + a + int (pin) | 22a3 | 101 | 124 |
Grapevine | i | 22s3 | s = old style serial occupancy sensor | GS 22 s3 | int + s + int (pin) | 22023 | s1 | s16 |
Grapevine | i | 22023 | s = old style serial occupancy sensor | GS 22 s3 | int + s + int (pin) | 22a3 | 021 | 036 |
Grapevine | i | 22m3 | m = ASD motion sensor | GS 22 m3 | int + m + int (pin) | 22203 | 1 | 24 |
Grapevine | i | 22203 | m = ASD motion sensor | GS 22 203 | 22m3 | 201 | 224 | |
Grapevine | o | 22103 | output, card/bank 1, connector 3 | GT 22 103 | 101/201/301/401 | 124/224/324/424 | ||
LocoNet | i | 34 | Sensor 34 | LS34 | integer | N/A | 1 | 4096 |
LocoNet | o | 34 | Turnout 34 | LT34 | integer | N/A | 1 | 4096 |
Maple | i | 2010 | Node 2 Input bit 10 | KS2010 | 1 | 1000 | ||
Maple | o | 1016 | Node 1 Output (Turnout) 16 | KT1016 | 1 | 8000 | ||
MERG-CBUS | io | 18 | Event 18 On; 18 Off | MT+18 | integer | +18;-18 | 01 | 65535 |
MERG-CBUS | io | +N2E18;-N2E18; | Node 2 Event 18; On Event = Active; Off Event = Inactive | MS+N2E18;-N2E18 | Node 1 Event 1 | Node 65535 Event 65535 | ||
MERG-CBUS | i | 200018M07 | listen to Events 18 .. 1F | MS200018M07 | + M + hex mask | N/A | ||
MERG-CBUS | io | X9000020012;X91FFFFFFFE | hex CAN frame msg. Active; Inactive
N2 E18 active; N65535 E65534 inactive |
MSX9000020012;X91FFFFFFFE | hex ; hex | N/A | Depends on Opscode | |
MERG-CBUS | io | +18;+21 | Event 18 On; 21 On | MT18;21 | integer ; integer | +18;+21 | 1;1 | 65535;65535 |
MERG-CBUS | io | +18;-21 | Event 18 On; 21 Off | ML+18;-21 | idem signed | N/A | 1;1 | 65535,65535 |
MERG-CBUS | io | 200018 | Node 2 Event 18; On Event = Active; Off Event = Inactive | MS+200018 | node + (5 digits) | N2E18 | 100001 | 6553565535 |
NCE | i | 4:3 | AIU Cab 4, pin 3 | NS50 | cab: 1; pin: 1 | cab: 63; pin: 14 | ||
NCE | i | 50 | AIU Cab 4, pin 3 | NS50 | cab: 1; pin: 1 | cab: 63; pin: 14 | ||
NCE | o | 16 | Output (Turnout) 16 | NT16 | 1 | 2044 | ||
TMCC (Lionel) | o | 16 | Output (Turnout) 16 | NT16 | 1 | 511 | ||
X10 | o | A3 | House code A + num device code | PTA3 | caps letter + num | house code: A; device: 1 | house code: P; device: 16 | |
X10 Insteon | o | 01.2A.B4 | Light (module) PL01.2A.B4 | PL01.2A.B4 | 3 x 2 chars | not documented | ||
XpressNet | i | 3 | Feedback module 1, input 3 | XS3 | 1 | 1024 | ||
XpressNet | i | 99:3 | Feedback module 99, input 3 | XS787 | 1 | 1024 | ||
XpressNet | o | 3 | Turnout 3 | XT3 | 1 | 1024 |
Naming Conventions For Automated Use
Some higher-level constructs create their own items. For example, a "Sensor Group" is really just a collection of Routes that implements the sensor group logic; there is no specific object in the program that implements the sensor group. Instead, when the user creates sensor group "my group", a series of routes with system names like:SENSOR GROUP:my group:LS1 SENSOR GROUP:my group:LS2are created which implements the group. The sensor group tool knows to look for routes of this name.
To make this possible, two informal rules are used:
- Users should not use the : (colon, ASCII 0x3A), " (double quote, ASCII 0x22), nor $ (dollar sign, ASCII 0x24 ) characters in their system or user names. Automatic tools should use at least one of these to make sure they don't collide with user-selected names. Quotes should always be used in pairs to allow nesting.
- Tools that use this method have their tool name in any system names they create, as "SENSOR GROUP" was used above.
The list of tools currently working this way is:
- Logix - auto-generated Logix system names are of the form IX:AUTO:0001
- SENSOR GROUPS - jmri.jmrit.sensorgroup
- SignalHeads - particularly the SE8C signal head
- USS CTC - jmri.jmrit.ussctc
Notes
- Some devices are not really named, as there's no idea of more than one yet. The DCC programmer is the first example, but there may be others.
- Conditionals are a special case. Although they have things called "System Names" and "User Names", they don't really obey the conventions here. See the ConditionalManager Javadoc for more information.
- The system name convention doesn't provide a specific way to identify more than one adapter of a given type. E.g. if you're connected to more than one LocoNet, or more than one command station of any single type, you can either give the second one a separate letter (L, then M) or you can identify the 2nd one with a modifier (L, then L2). That's a bit ambiguous, but there are proponents of both approaches so we make them both available.
- There's no provision for a single program to deal with more than one layout. If that's needed, we'll have to understand what the program is trying to do.
For Programmers
Normalized form of Names, and how to work with it
After multiple long discussions, we decided that both system and user names should be kept in a "normal" form which enforces certain restrictions. For user names, that's that leading and trailing whitespace (spaces, tabs) are not allowed. For system names, it depends on the system, but at least the system-prefix and type letter must be correct.
The code to make sure that names are in normal form
has been localized to a single routine for user names:
String userName = NamedBean.normalizeUserName(input);
Because system names may vary from type to type and manager to manager, this is manager-specific for them:
String systemName = manager.normalizeSystemName(input);
For more information, see the Javadoc for normalizeUserName and normalizeSystemName
In general, it's better to use an input method that already handles all this. Two are available now:
- JComboBox format:
import jmri.util.swing.JmriBeanComboBox; // the first argument is the manager, the 2nd is a bean to select or null // the third determines how the beans are displayed selectComboBox = new JmriBeanComboBox(InstanceManager.getDefault(SensorManager.class), currentSensor, JmriBeanComboBox.DisplayOptions.DISPLAYNAME) // to get the selected item, depending on what you want: selectComboBox.getNamedBean() selectComboBox.getSystemName() selectComboBox.getUserName() selectComboBox.getDisplayName()
- Table format:
import jmri.jmrit.picker.*; PickListModel tableModel = PickListModel.sensorPickModelInstance(); // or another type PickSinglePane panel = new PickSinglePane(tableModel); // to get the selected item as a NamedBeanHandle<T> panel.getSelectedBeanHandle(); // you can listen for a selected value by inheriting from ListSelectionListener // and registering with panel.getTable().getSelectionModel().addListSelectionListener(this) @Override public void valueChanged(ListSelectionEvent e) { System.out.println(" Selected: "+panel.getSelectedBeanHandle()); }
This allows the user to select either the system name or (non-blank) user name in a row, which then becomes the preferred name for the resulting NamedBeanHandle. For more information on NamedBeanHandle, including how to get them from the NamedBeanHandleManager see the page on code patterns page.
System Name Comparisons
System names are compared and sorted in multiple places: as labels for table rows, in selection boxes and lists, etc. We have twojava.util.Comparator<>
implementations to handle this:
SystemNameComparator
- a comparison on StringsNamedBeanComparator
- a comparison on the NamedBeans themselves
Both of them sort first by system connection prefix, to group all the objects from one system together. If there are objects of multiple types, the type letter is put in alphabetical order next. Finally, the system-specific suffix is sorted.
Because it works with String values, SystemNameComparator
can only
do a default ordering of the system-specific suffix; it can't do anything that
uses any information about the system-specific meaning of that string. It therefore
uses an alphanumeric-by-chunks sort.
Because it's comparing on the actual NamedBean objects, NamedBeanComparator
can do more specific comparisons: It knows what the C/MRI suffixes in
"CT2003" and "C2B2" mean and can take that into account.
Therefore, if you can, do the sort/comparison with NamedBeanComparator
and
then convert to Strings, rather than converting NamedBeans to Strings and using
SystemNameComparator
.
Also, if you've created a system that has complex information in the suffix,
please have your NamedBean
subclasses implement a system-specific
version of the
compareSystemNameSuffix()
method in NamedBean
.
For an example, see the bottom of jmri.jmrix.cmri.serial.SerialTurnout
and jmri.jmrix.cmri.serial.SerialTurnoutTest.