JMRI: Adding A New System
Author: Bob Jacobsen
Keywords: JMRI technical system add

# JMRI Code: Adding A New System

This page describes the steps to add a new data-type, e.g. Powerline devices, to JMRI.

It uses as an example the addition of the "powerline" type in January 2008. This was before several important migrations (SVN to Git; changes to the internal support for multiple connections; changes to how the Preferences mechanism works; etc) so this may need significant updating.

Some parts may also be useful if you're adding a new connection (e.g. through a network link) to an existing system. If you do that, please mark those sections here for the next person to come along.

Note that we don't do this very often, and the specifics are more important than the generalities here. You should should make sure you understand the intended system connection structure which is documented on another page.

We list the files that are modified and created in the order they were done in this case; other orders may also work, and you might not need to do all these.

In this particular case, we started by copying an existing system implementation (SECSI). This effects how we ordered this, and made the basic process move pretty quickly.

### Duplicate an existing system

Create a duplicate file tree

  Using whatever tool that useful to you, duplicate the src/jmri/jmrix subtree corresponding to the existing system you want to copy.

Change the package name information

  Using your favorite editor, change all the package names in the new files to their new location. In this example, that was a bulk replace of "jmri.jmrix.secsi" with "jmri.jmrix.powerline".

  At this point, make sure you can compile. This code isn't consistent yet, but it should compile.

Check copyright dates

  Because you've copied a system that might not have been touched for a while, go through and add the current year (and if need be, your name) to the copyright notices in all the files.

Create Git structure

  In this step, we put the basic Git structure in place.

  - Add all the directories you've created to Git. In the example, this was:
    `git add powerline powerline/serialdriver powerline/serialmon
    git add powerline/configurexml powerline/serialdriver/configurexml`
  - Add all the COPYING files:
    `git add powerline/COPYING powerline/*/COPYING powerline/*/*/COPYING`
  - Finally, commmit those files (but only those files):
    `git commit -m"usual file" powerline`

  At this point, make sure you can compile.

### Do Basic Migration

Migrate names

  Using your favorite editor, change all occurances of the old system name into the new one.

  `bbedit `grep -irl secsi powerline/``

  Then search for and replace, perhaps not literally, all the occurances.

  At this point, make sure you can compile.

Register system for preferences

  Add the line `@ServiceProvider(service = ConnectionTypeList)` just before the class definition so that the preferences system sees your new connection types. You may also need to add the following import statements:
  `import org.openide.util.lookup.ServiceProvider;`
  `import jmri.jmrix.ConnectionTypeList;`

Update the documentation
  - Most important, make an entry in the Names.shtml page for the system letter.
  - Add at least one page of documentation to the help/en/html/hardware area.
  - Link that from the help/en/html/hardware/index.shtml hardware home page. Include a link to the manufacturer's website if possible.
Create Basic JUnit Tests

  For more information on this, see the testing page.

Duplicate directory

  Following the steps above, duplicate the directory for the previous systems tests, creating a new directory in test/jmri/jmrix to contain the tests. Change the package names, check the copyright dates, create the Git structure, and migrate the names.

  At this point, make sure you can compile both the main code (which wasn't changed in this step) and the tests.

  You should also be able to successfully run the tests in your new system (although they were created for the old system's functionality): `ant tests &&./runtest.csh jmri.jmrix.powerline.SerialTest`

  There is also a PowerShell script available, see the JUnit page for more information

### Connect Basics to Rest of System

Connect to configuration menus

  Edit the jmri/jmrix/ActiveSystemsMenu.java file (two places), src/jmri/jmrix/JmrixConfigPane.java (one place) and src/jmri/jmrix/SystemsMenu.java (one place) files to add the new system.

  Don't commit this to Git yet!

  At this point, make sure you can compile and run DecoderPro, and that your new system appears in the preferences panel.

Connect to test tree

  Edit the test/jmri/jmrix/JmrixTest.java file to invoke your new system tests.

  Don't commit this to Git yet!

  At this point, when you "ant alltest", your new system's test should be run.

### Migrate to Basic Functionality

Update connection options

  Speeds, etc, in powerline/serialdriver/SerialDriverAdapter.java.

Get send/receive communications working

  The first step is to get communications working so that you can send a message from the "Send Command" window, and see it and the response in the "Monitor" window.

### Make It Easy to Use

Add Possible Startup Items

  Create a new system-specific `ActionListBundle.properties` file (src/jmri/jmrix/powerline/PowerlineActionListBundle.properties) to add appropriate action items. Make sure to update the `getActionModelResourceBundle()` method of the SystemConnectionMemo to reference this newly created ActionListBundle.

### Complete the documentation

Create The Help Tree

  Start by duplicating, then edit, don't forget to update the index.

  You'll also have to change the locations on the various frames

ant javadoc

  Create the Javadocs, and fix any new (or old) problems.

Add the system to the "hardware" web pages

  Edit help/en/html/hardware/index.shtml

## Adding a TCP/IP connection to an existing system

These are rough notes from adding a TCP/IP connection to the RFID type, by copying the architecture of the C/MRI system.

1. Create a "networkdriver" directory in parallel to the "serialdriver" directory.
   `cp java/src/jmri/jmrix/cmri/serial/networkdriver/ java/src/jmri/jmrix/rfid/`
2. Edit the package and import statements, all files. ".cmri.serial." to ".rfid.", then ".cmri." to ".rfid.".
3. Change the "setManufacturer" call in NetworkDriverAdapter.
4. C/MRI might not have been the best starting point, but it's what we've got. Some specific edits needed:
   - Change CMRISystemConnectionMemo to RfidSystemConnectionMemo
   - Remove the reference to NodeConfigAction in ConnectionConfig (or use this as the base for any special configuration you need; it was adding a "Configure Nodes" button)
   - Change the name of SerialSensorManager throughout
   - Remove the SerialTurnoutManager SerialLightManager references (there aren't any in RFID)
   - Add RfidReporterManager
5. Needs a network driver:
   `cp java/src/jmri/jmrix/cmri/serial/SerialNetworkPortController.java java/src/jmri/jmrix/rfid/RfidNetworkPortController.java`
   and edit as above.
6. java/src/jmri/jmrix/rfid/networkdriver/configurexml/ConnectionConfigXml.java contains dead code for configuring the C/MRI nodes (again, maybe not the right system to copy from). Leave that for later by commenting out the body of extendElement(Element e) and unpackElement(Element e).
7. Change references to SerialTrafficController to RfidTrafficController.
8. Another problem with C/MRI as a prototype is that it still has an instance() call in NetworkDriverAdapter. Go to the RFID (multi-system capable) SerialDriverAdapter and copy the structure there.

               // connect to the traffic controller
               this.getSystemConnectionMemo().setRfidTrafficController(control);
               control.setAdapterMemo(this.getSystemConnectionMemo());
               control.connectPort(this);
               control.sendInitString();

               // declare up
               jmri.jmrix.rfid.ActiveFlag.setActive();

   (There's also a bunch of stuff before this in the configure() method that should just be copied over, because the RFID connections also need some complicated configuration); the ctor also needs some parts copied over.
9. Add jmri.jmrix.rfid.networkdriver.ConnectionConfig to java/src/jmri/jmrix/rfid//RfidConnectionTypeList.java
10. Change "RFID Device Connection" to "Direct Serial Connection" in ConnectionConfig.name() The network connection will default to "Network Connection".
11. Check that configure/save/restart brings back all the configuration options. It should, you copied the necessary code above, but check.

## Connections with Complicated Setup

Some connection types need more configuration and/or setup than you can get with the usual option1/option2/option3 mechanism. Tools available are:

- loadDetails() in ConnectionConfig. This is invoked when setting up the preferences window, and can be used to add additional controls. C/MRI uses this to add a "Configure Nodes" button. RFID uses it to add listeners that control which combinations of options are available.
- extendElement(Element e) and unpackElement(Element e) in ConnectionConfigXml can be used to store additional information and reload it, respectively. C/MRI uses this to store its node information.