# Script to assist Zimo function mapping using CV61=98 method # works in a few Zimo decoders, allowing more complex function maps # than normally possible. For MX620, MX64, etc. # # # # Consult Zimo Manuals before use !!! # # Requires loco on main line, uses ops mode programming # # Script will step through each of the 13 pairs of function keys (F0-F12) in # Forward and Reverse directions, allowing any of 13 outputs to be selected. # Main purpose is to keep track of which Fn key is being set at which time, and gives on-screen # indication of which output(s) are selected against that key (see next paragraph!) # # Note unusual behaviour of Fo0; this will toggle the outputs Fl(F) and # Fl(R) through four combinations: none, Fl(F), Fl(R), both. This is the same as Zimo manual # description. The software tracks this, but it is strongly recommend that decoder has lights # attached to outputs Fl(F) and Fl(R) (white and yellow wires) to make it possible to see status of Fo0, # and to see confirmation of both lights on at end of programming sequence. # # # Version 1.0, tested on one MX620 with v9 firmware, seeking comments from others ! # Version 1.1 adds function F0 toggle status indicator and initialisation of loco. # Version 1.2 temporary changes to deal with NCE bug report # Version 1.3 improve text and button layout to aid usability, change Fo0 to "change" button to # toggle through the four states of front/rear lamps. Removed NCE changes; user with bug had old version of JMRI, and fixed with 2.8. # Version 1.4 adds new FrontLamp and RearLamp check boxes, with script which toggles the F0 output # through four states; this should make the UI better as the user can select the combinations required # and leave the script to toggle through output states in the decoder # Version 1.5, general tidy up and added Roster Drop-Box to select loco. # # Nigel Cliffe, copyright February 2010 # # Components based on Bob Jacobsen's scripts in JMRI distribution. # # The next line is maintained by CVS, please don't change it # $Revision: 19019 $ import java import javax.swing import jarray import jmri class LocoZimoProg(jmri.jmrit.automat.AbstractAutomaton) : # define how long to wait between settings (seconds) delay = 2 # dirCount is used to determine how many changes of direction dirCount = 0 # flStatus is used to record whether it is Fl(F) or Fl(R), or both, etc. flStatus = 0 # init() is called exactly once at the beginning to do # any necessary configuration. def init(self): self.status.text = "Getting throttle" number = int(self.address.text) if (number > 100) : long = True else : long = False self.throttle = self.getThrottle(number, long) self.waitMsec(self.delay*1000) if (self.throttle == None) : print "Couldn't assign throttle!" # setup a programmer for ops-mode self.programmer = programmers.getAddressedProgrammer(long, number) return # handle() will only execute once here, to run a single test # # Modify this to do your calculation. def handle(self): # prevent running twice by hiding start button. self.startButton.enabled = False self.box.enabled = False # self.automaticBox.enabled = False # Set throttle to forward and all functions off: self.status.text = "Setting loco forward and all functions to off" self.throttle.setIsForward(True) self.throttle.setF0(False) self.throttle.setF1(False) self.throttle.setF2(False) self.throttle.setF3(False) self.throttle.setF4(False) self.throttle.setF5(False) self.throttle.setF6(False) self.throttle.setF7(False) self.throttle.setF8(False) self.throttle.setF9(False) self.throttle.setF10(False) self.throttle.setF11(False) self.throttle.setF12(False) self.waitMsec(1000) # setup ops mode self.status.text = "writing ops mode" self.programmer.writeCV(61, 98, None) self.waitMsec(1000) # make UI visible self.address.enabled = False self.Flfbox.enabled = True self.Flrbox.enabled = True self.F1box.enabled = True self.F2box.enabled = True self.F3box.enabled = True self.F4box.enabled = True self.F5box.enabled = True self.F6box.enabled = True self.F7box.enabled = True self.F8box.enabled = True self.F9box.enabled = True self.F10box.enabled = True self.F11box.enabled = True self.F12box.enabled = True self.fwdButton.enabled = True self.status.text = "setting outputs for Function Key F" + str(self.dirCount) + " in Forward Direction" return 0 # use return 1 for an infinite loop, or return 0 for once through ! # define what button does when clicked and attach that routine to the button def whenMyButtonClicked(self,event) : self.start() return def whenFlfrChanged(self, event) : # New version 1.4 routine, cycles through the four states for Flf/Flr to give # correct output behaviour, yet allow user to have simple check-box UI to select # front/rear light combinations. self.Flfbox.enabled = False self.Flrbox.enabled = False # print "flf or flr pressed " newStatus = 0 if (self.Flfbox.isSelected() == True) : newStatus = newStatus + 1 if (self.Flrbox.isSelected() == True) : newStatus = newStatus + 2 # print newStatus, self.flStatus while (newStatus != self.flStatus) : self.flStatus = self.flStatus + 1 if (self.flStatus == 4) : self.flStatus = 0 if ((self.flStatus == 0) or (self.flStatus ==2)) : self.throttle.setF0(False) self.waitMsec(1000) # print "set F0 off" if ((self.flStatus == 1) or (self.flStatus ==3)) : self.throttle.setF0(True) self.waitMsec(1000) # print "set F0 on" # print self.flStatus self.Flfbox.enabled = True self.Flrbox.enabled = True return def whenF0Changed(self,event) : # do nothing, F0 is now controlled by "whenToggleF0ButtonClicked" self.waitMsec(1000) return def whenF1Changed(self,event) : if (self.F1box.isSelected() ) : self.throttle.setF1(True) else : self.throttle.setF1(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF2Changed(self,event) : if (self.F2box.isSelected() ) : self.throttle.setF2(True) else : self.throttle.setF2(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF3Changed(self,event) : if (self.F3box.isSelected() ) : self.throttle.setF3(True) else : self.throttle.setF3(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF4Changed(self,event) : if (self.F4box.isSelected() ) : self.throttle.setF4(True) else : self.throttle.setF4(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF5Changed(self,event) : if (self.F5box.isSelected() ) : self.throttle.setF5(True) else : self.throttle.setF5(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF6Changed(self,event) : if (self.F6box.isSelected() ) : self.throttle.setF6(True) else : self.throttle.setF6(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF7Changed(self,event) : if (self.F7box.isSelected() ) : self.throttle.setF7(True) else : self.throttle.setF7(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF8Changed(self,event) : if (self.F8box.isSelected() ) : self.throttle.setF8(True) else : self.throttle.setF8(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF9Changed(self,event) : if (self.F9box.isSelected() ) : self.throttle.setF9(True) else : self.throttle.setF9(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF10Changed(self,event) : if (self.F10box.isSelected() ) : self.throttle.setF10(True) else : self.throttle.setF10(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF11Changed(self,event) : if (self.F11box.isSelected() ) : self.throttle.setF11(True) else : self.throttle.setF11(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenF12Changed(self,event) : if (self.F12box.isSelected() ) : self.throttle.setF12(True) else : self.throttle.setF12(False) # pause a second to give the command station a chance ! self.waitMsec(1000) return def whenFwdButtonClicked(self, event) : # hide button self.fwdButton.enabled = False # put throttle into reverse self.throttle.setIsForward(False) statusText = self.status.text # reveal other button if (self.dirCount < 13) : self.revButton.enabled = True statusText = "setting outputs for Function Key F" + str(self.dirCount) + " in Reverse Direction" else: # end of operations, release the throttle... self.throttle.release() self.status.text = statusText return def whenRevButtonClicked(self, event) : # hide button self.revButton.enabled = False # increment dirCount self.dirCount = self.dirCount + 1 if (self.dirCount < 13) : statusText = "setting outputs for Function Key F" + str(self.dirCount) + " in Forward Direction" else: statusText = "Done all Fn keys. Loco shows two lamps. Press Commit Fwd to finish, then close script" self.status.text = statusText # put throttle into Forward self.throttle.setIsForward(True) # reveal other button self.fwdButton.enabled = True return def rosterBoxChange(self, event) : #print "roster changing in rosterBoxChange" entry = self.roster.entryFromTitle(self.box.getSelectedItem()) #print entry theDccAddress = entry.getDccAddress() # print theDccAddress self.address.text = theDccAddress return 0 # routine to show the panel, starting the whole process def setup(self): # create a frame to hold the button, set up for nice layout f = javax.swing.JFrame("Zimo Fn Programmer v1.5") # argument is the frames title f.contentPane.setLayout(javax.swing.BoxLayout(f.contentPane, javax.swing.BoxLayout.Y_AXIS)) # top explanatory panel, text only temppanel0 = javax.swing.JPanel() temppanel0.add(javax.swing.JLabel("Zimo CV61=98 function mapping tool, using Ops Mode programming. Consult Zimo manuals before use.
The script assists the user by remembering which step has been reached, and providing visual display
of selections.
The script also ensures the loco is in correct state before starting.
Select your locomotive from the roster, or type in the address in the box.")) # put the text field on a line preceded by a label temppanel1 = javax.swing.JPanel() temppanel1.add(javax.swing.JLabel("Locomotive ")) # create the text field self.address = javax.swing.JTextField(5) # sized to hold 10 characters, initially empty self.startButton = javax.swing.JButton("Start") self.startButton.actionPerformed = self.whenMyButtonClicked self.roster = jmri.jmrit.roster.Roster.instance() self.box = jmri.jmrit.roster.swing.GlobalRosterEntryComboBox() self.box.itemStateChanged = self.rosterBoxChange temppanel1.add(self.box) temppanel1.add(self.address) temppanel1.add(self.startButton) self.address.text = "3" entry = self.roster.entryFromTitle(self.box.getSelectedItem()) theDccAddress = entry.getDccAddress() self.address.text = theDccAddress # top explanatory panel, text only temppanel1a = javax.swing.JPanel() temppanel1a.add(javax.swing.JLabel("Automatic will setup loco for you, and program decoder with CV61=98.
Manual requires you to set loco forward, all functions to off, and then set CV61=98 before pressing 'Start'")) temppanel1b = javax.swing.JPanel() temppanel1b.add(javax.swing.JLabel("Tick box for automatic, un-tick for manual")) self.automaticBox = javax.swing.JCheckBox("Automatic") self.automaticBox.selected = True temppanel1b.add(self.automaticBox) temppanel1c = javax.swing.JPanel() temppanel1c.add(javax.swing.JLabel("Script steps through each Function Key (F0-F12), allowing the user to set the Decoder Outputs required
in each Direction. The status line (bottom line of window) reports which Function Key is being set.

For each Function Key and Direction, use the Checkboxes to select the Outputs required
and then Commit your selections in that Direction.

The Script has pauses to allow the command station and decoder to catch up, please be patient!")) # Put contents in frame and display f.contentPane.add(temppanel0) f.contentPane.add(temppanel1) f.contentPane.add(temppanel1c) # create the button temppanel2a = javax.swing.JPanel() self.Flfbox = javax.swing.JCheckBox("Front Lamp (FLf)") self.Flfbox.actionPerformed = self.whenFlfrChanged self.Flrbox = javax.swing.JCheckBox("Rear Lamp (FLr)") self.Flrbox.actionPerformed = self.whenFlfrChanged self.Flfbox.enabled = False self.Flrbox.enabled = False temppanel2a.add(self.Flfbox) temppanel2a.add(self.Flrbox) self.F1box = javax.swing.JCheckBox("Fo1") self.F1box.actionPerformed = self.whenF1Changed self.F2box = javax.swing.JCheckBox("Fo2") self.F2box.actionPerformed = self.whenF2Changed self.F3box = javax.swing.JCheckBox("Fo3") self.F3box.actionPerformed = self.whenF3Changed self.F4box = javax.swing.JCheckBox("Fo4") self.F4box.actionPerformed = self.whenF4Changed self.F5box = javax.swing.JCheckBox("Fo5") self.F5box.actionPerformed = self.whenF5Changed self.F6box = javax.swing.JCheckBox("Fo6") self.F6box.actionPerformed = self.whenF6Changed self.F7box = javax.swing.JCheckBox("Fo7") self.F7box.actionPerformed = self.whenF7Changed self.F8box = javax.swing.JCheckBox("Fo8") self.F8box.actionPerformed = self.whenF8Changed self.F9box = javax.swing.JCheckBox("Fo9") self.F9box.actionPerformed = self.whenF9Changed self.F10box = javax.swing.JCheckBox("Fo10") self.F10box.actionPerformed = self.whenF10Changed self.F11box = javax.swing.JCheckBox("Fo11") self.F11box.actionPerformed = self.whenF11Changed self.F12box = javax.swing.JCheckBox("Fo12") self.F12box.actionPerformed = self.whenF12Changed # self.F0box.enabled = False self.F1box.enabled = False self.F2box.enabled = False self.F3box.enabled = False self.F4box.enabled = False self.F5box.enabled = False self.F6box.enabled = False self.F7box.enabled = False self.F8box.enabled = False self.F9box.enabled = False self.F10box.enabled = False self.F11box.enabled = False self.F12box.enabled = False self.fwdButton = javax.swing.JButton("Commit Fwd") self.fwdButton.actionPerformed = self.whenFwdButtonClicked self.fwdButton.enabled = False self.revButton = javax.swing.JButton("Commit Rev") self.revButton.actionPerformed = self.whenRevButtonClicked self.revButton.enabled = False self.status = javax.swing.JLabel("Enter address & click start ") temppanel2b = javax.swing.JPanel() temppanel2b.add(self.F1box) temppanel2b.add(self.F2box) temppanel2b.add(self.F3box) temppanel2b.add(self.F4box) temppanel2b.add(self.F5box) temppanel2b.add(self.F6box) temppanel2b1 = javax.swing.JPanel() temppanel2b1.add(self.F7box) temppanel2b1.add(self.F8box) temppanel2b1.add(self.F9box) temppanel2b1.add(self.F10box) temppanel2b1.add(self.F11box) temppanel2b1.add(self.F12box) #temppanel2b.add(self.fwdButton) #temppanel2b.add(self.revButton) temppanel2c = javax.swing.JPanel() temppanel2c.add(self.fwdButton) temppanel2c.add(self.revButton) temppanel3 = javax.swing.JPanel() temppanel3.add(self.status) f.contentPane.add(temppanel2a) f.contentPane.add(temppanel2b) f.contentPane.add(temppanel2b1) f.contentPane.add(temppanel2c) f.contentPane.add(temppanel3) f.pack() f.show() return # create one of these a = LocoZimoProg() # set the name, as a example of configuring it a.setName("Zimo Programming script") # and show the initial panel a.setup()