# This script runs a loco around the track, controlling the speed # according to signals and following the blocks. # # Author: Ken Cameron, copyright 2009,2010 # Part of the JMRI distribution # # The start button is inactive until data has been entered. # # The test button is to force re-evaluation of all block and signal values. # # If the loco id isn't showing in the block table, do a 'stop'/'start the # run' to reestablish the loco position. # # Notes: # 1. This script expects a fully developed set of blocks and signals # to exist. # 2. Best way for that is using the 'Layout Editor' to develop the # configuration. # 3. However, on turnouts, the non-throat (frog) ends of the turnout should # not have a track segment attached, the block boundary must be the # turnout anchor point. The throat end (points) may have additional # track segments in the same block as the turnout. # 4. The layout must be laid out like a CTC type panel, meaning string line # left to right across the panel. If you need to have multiple lines # to build the whole layout place a track segment of the same block # at the end of the first line and the start of the next line and # use a 'hidden' track segment (same block) to connect # those track segments. # 5. The script keys off the loco id being passed from block to block # by the block manager. If you have detector issues and the blocks # falsely cycle, this may not work. You may have to add internal # sensors to 'buffer' these false cycles using Logix to clean # things up. # 6. FIXED: You no longer need usernames for everything. It will use # system or user names depending on what you have in your panel. # 7. If you create memory values and memory labels on your panel and # tie them to the blocks, you will always see the loco id displayed. # That is the block value that the script is looking for when # tracking the loco. # NEW FOR Version 2 # 8. It now has options for a rate of speed (still needs the matching # throttle setting) for speeds to compute stopping. But it only uses # this for stopping on approach to a red signal. When this is added as # an 'autopilot' to the throttle interface, it will consider more of # these inputs. A zero in the rate will cause it to ignore it. # 9. If the blocks have the length set (and the rate above) it will try # to delay stopping in a red block until 80% into the block. # NEW FOR Version 3 # 10. Requires the length of blocks be known. In turn it computes the # fastest speed that will stop within the next two blocks based # on the most restrictive speeds that may be in the next blocks. # # Still needing work: # 1. Improve the method for 'findNextBlock' as it currently uses the # direction from the current block. To work for 'physically designed' # panels, it would need to focus on the connectivity of the blocks # more and less on the direction attributes. It currently fails # if a block transitioned more than 90 degrees within a single # block. # 2. Add option to delay halting if it looses sight of the loco. # This may help some layouts where the detection 'blinks' out # for a few seconds due to dirt etc... # Currently you must use something like 'DebounceSensor.py' if you # have sensors that don't hold due to the above. # 3. Learn about the neat features the 'operations' data is adding. # This would help with knowing lengths of trains, grades of track, # etc to aid in controlling how to stop within a block. # # Changes: # 07/23/2009 - Added a Halt button that tries to -1 the throttle to # stop now and not be smooth. Plus a few other fixes # like the system vs user name thing. # # 08/30/2009 - Added methods so this can be run from a master script # for running mulitple throttles. Also improved many # reliblity issues in the code. # # Much thanks go to the Medina Railroad Museum who was asked for # something to help out when they have larger number of visitors # and few staff but want the trains to run around without taking # staff to keep them from running into each other. What started # as a simple request grew into this script. I am planning on # turning it into real code as a next step. # http://railroadmuseum.net/ # # Portions of this script are taken from a number of scripts # by Bob Jacobsen # # A AbstractAutomaton is used to get a throttle and run the loco. # # A PropertyChangeListener is used to report block information. # It could have been with AbstractAutomaton but this allows for # independent action with a block change. # # Same thing for also watching signals. # # A WindowListener is used to report when the window is closing and # allow for the removal of the PropertyChangeListener. # import jmri import java import java.awt import java.awt.event import java.beans import java.util import javax.swing import java.util.Calendar HighDebug = 3 MediumDebug = 2 LowDebug = 1 NoneDebug = 0 # set up a throttle with the loco address class LocoThrot(jmri.jmrit.automat.AbstractAutomaton) : # initialize variables locoAddress = None currentBlock = None currentDirection = jmri.Path.NONE currentBlocks = [] currentNextBlocks = [] next1Block = None next2Block = None next3Block = None priorBlocks = [] priornext1Blocks = [] priorSignal = None priorSignalAspect = None currentSignal = None currentSignalAspect = None nearSignal = None nearSignalAspect = None next1Signal = None next1SignalAspect = None next2Signal = None next2SignalAspect = None isRunning = False isStarting = False isAborting = True currentThrottle = None scriptFrame = None scriptFrameOldX = None scriptFarmeOldY = None listenerBlocks = [] listenerBlockListeners = [] listenerSignals = [] listenerSignalListeners = [] greenSignalIcon = None greenFlashSignalIcon = None yellowSignalIcon = None yellowFlashSignalIcon = None redSignalIcon = None redFlashSignalIcon = None darkSignalIcon = None unknownSignalIcon = None speedChangeTimer = None speedChangeListener = None shrinkGrow = True fullScrollRows = 15 speedPane = None rosterInstance = None oldLocoAddress = None didWeMoveCounter = 0 holdMoving = False stopBlock = None hornDelayTimer = None hornDelayListener = None throttleManager = None askChangeThrottle = False askFinishStartButton = False methodLocoAddress = None methodBlockDirection = None methodLocoDirection = None methodLocoHeadlight = None methodShortHorn = None methodLongHorn = None methodBlockStart = None methodPushShrink = None methodPushStart = None methodPushStop = None methodPushTest = None methodBlockStop = None methodlocoDistRed = None haltOnSignalHeadAppearance = YELLOW debugLevel = LowDebug movementDetected = False def init(self): #print("start begin:.\n") self.setName("RT3: no loco") self.setup() #print("start end:.\n") return def handle(self): if (self.isAborting == True) : return 0 #self.msgText("handle begin:.") self.waitMsec(100) if (self.askChangeThrottle) : self.getNewThrottle() self.askChangeThrottle = False if (self.askFinishStartButton) : self.doFinishStartButton() self.askFinishStartButton = False if (self.methodLocoAddress != None) : self.locoAddress.text = self.methodLocoAddress self.methodLocoAddress = None self.whenLocoChanged(self) if (self.methodBlockDirection != None) : if (self.methodBlockDirection == True) : self.blockDirection.setSelected(True) else : self.blockDirection.setSelected(False) self.methodBlockDirection = None self.whenLocoChanged(self) if (self.methodLocoDirection != None) : if (self.methodLocoDirection == True) : self.locoForward.setSelected(True) else : self.locoForward.setSelected(False) self.methodLocoDirection = None self.whenLocoChanged(self) if (self.methodLocoHeadlight != None) : if (self.methodLocoHeadlight == True) : self.locoHeadlight.setSelected(True) else : self.locoHeadlight.setSelected(False) self.methodLocoHeadlight = None self.whenLocoHeadlight(self) if (self.methodShortHorn != None) : self.methodShortHorn = None self.doShortHorn() if (self.methodLongHorn != None) : self.methodLongHorn = None self.doLongHorn() if (self.methodBlockStart != None) : self.blockStart.text = self.methodBlockStart self.methodBlockStart = None self.whenLocoChanged(self) if (self.methodPushShrink != None) : self.methodPushShrink = None self.whenShrinkButtonClicked(self) if (self.stopButton.isEnabled() == True and self.methodPushStop != None) : self.methodPushStop = None self.whenStopButtonClicked(self) if (self.testButton.isEnabled() == True and self.methodPushTest != None) : self.methodPushTest = None self.callBackForDidWeMove(self) if (self.startButton.isEnabled() == True and self.methodPushStart != None) : self.methodPushStart = None self.whenStartButtonClicked(self) if (self.methodBlockStop != None) : self.blockStop.text = self.methodBlockStop self.methodBlockStop = None self.whenStopBlockChanged(self) if (self.methodlocoDistRed != None) : self.locoDistRed.text = self.methodlocoDistRed self.methodlocoDistRed = None self.whenLocoChanged(self) # This handles tracking how many overlapping events happened # and insures we run the didWeMove the right number of times if ((self.didWeMoveCounter > 0 and self.holdMoving == False) or self.isStarting == True) : #self.msgText("didWeMoveCounterCheck: " + str(self.didWeMoveCounter) + " - calling didWeMove") self.didWeMove() self.didWeMoveCounter = 0 #self.msgText("didWeMoveCounterCheck: decremented counter down to " + str(self.didWeMoveCounter)) #self.msgText("handle done") return 1 #continue if 1, run once if 0 # allow changes of a signal dropping on the appearance to trigger halting def setSignalAppearanceHalt(self, signalIndication) : self.haltOnSignalHeadAppearance = signalIndication return # show what level of signal appearance causes a halt on dropping signal def returnSignalAppearanceHalt(self) : return(str(self.haltOnSignalHeadAppearance)) def getNewThrottle(self) : self.holdMoving = True if (self.currentThrottle != None) : oldId = self.currentThrottle.getLocoAddress() if (self.debugLevel >= LowDebug) : self.msgText("stop and release the current loco: " + str(oldId)) self.doStop(); self.currentThrottle.release(None) self.currentThrottle = None if (self.debugLevel >= LowDebug) : self.msgText("Throttle " + str(oldId) + " released") if (self.debugLevel >= LowDebug) : self.msgText("Getting throttle") #add text to scroll field id = int(self.locoAddress.text) if (self.throttleManager.addressTypeUnique() == True) : if (self.debugLevel >= HighDebug) : self.msgText("id values are not ambiguous") isLong = self.throttleManager.canBeLongAddress(id) else : if (self.debugLevel >= LowDebug) : self.msgText("id values are ambiguous") isLong = True if (self.throttleManager.canBeShortAddress(id)) : if (self.debugLevel >= LowDebug) : self.msgText("id could be a short.") if (self.locoLong.isSelected() == False) : isLong = False if (self.debugLevel >= LowDebug) : self.msgText("Getting throttle " + str(id) + " " + str(isLong)) throttle = self.getThrottle(id, isLong) self.currentThrottle = throttle if (self.currentThrottle == None) : if (self.debugLevel >= LowDebug) : self.msgText("Couldn't assign throttle! - Run stopped") self.doHalt() else : if (self.debugLevel >= LowDebug) : self.msgText("got throttle: " + str(self.currentThrottle.getLocoAddress())) self.currentThrottle.setIsForward(self.locoForward.isSelected()) self.currentThrottle.setF0(self.locoHeadlight.isSelected()) self.currentThrottle.setF1(self.locoBell.isSelected()) self.holdMoving = False return # return userName if available, else systemName def giveBlockName(self, block) : if (block == None) : return 'None' else : if ((block.getUserName() == None) or (block.getUserName() == '')) : return block.getSystemName() else : return block.getUserName() # return userName if available, else systemName def giveSignalName(self, sig) : if (sig == None) : return 'None' else : if ((sig.getUserName() == None) or (sig.getUserName() == '')) : return sig.getSystemName() else : return sig.getUserName() # return userName if available, else systemName def giveTurnoutName(self, to) : if (to == None) : return 'None' else : if ((to.getUserName() == None) or (to.getUserName() == '')) : return to.getSystemName() else : return to.getUserName() # return userName if available, else systemName def giveSensorName(self, sen) : if (sen == None) : return 'None' else : if ((sen.getUserName() == None) or (sen.getUserName() == '')) : return sen.getSystemName() else : return sen.getUserName() # Isolate the callback handling from the didWeMove processing # this makes dealing with multiple events simpler def callBackForDidWeMove(self, event) : self.didWeMoveCounter = self.didWeMoveCounter + 1 if (self.debugLevel >= HighDebug) : self.msgText("callBackForDidWeMove(" + str(event) + ")") self.msgText("counter = " + str(self.didWeMoveCounter)) # the handle() will invoke the didWeMove() as needed return # figure out if we moved and where def didWeMove(self) : self.movementDetected = False if (self.debugLevel >= HighDebug) : self.msgText("didWeMove start: " + self.giveBlockName(self.currentBlock) + ":" + self.giveBlockName(self.next1Block)) if (self.currentThrottle == None) : if (self.debugLevel >= LowDebug) : self.msgText("didWeMove called while currentThrottle was None") return # allow for a 2nd try. In case the id in block didn't move, but we hit the next signal # try reading the blocks one more time in case we now see that we did move. tryCount = 0 tryCountLimit = 2 while (tryCount < tryCountLimit) : tryCount = tryCount + 1 if (self.debugLevel >= HighDebug) : if (self.currentBlock != None) : self.msgText("Current block: " + self.giveBlockName(self.currentBlock)) newCurrentBlocks = self.findCurrentBlocks() if (len(newCurrentBlocks) == 0) : self.msgText("Can't find loco!! Doing halt!!") self.doHalt() # new current block must be farthest connected to current block in current direction chain oldCurrent = self.currentBlock oldSignal = self.currentSignal oldnext1Signal = self.next1Signal oldnext2Signal = self.next2Signal oldAspect = self.currentSignalAspect oldFarAspect = self.next1SignalAspect oldnext2Block = self.next1Block tryBlock = self.currentBlock nearSignal = None next1Signal = None next2Signal = None newCurrent = None watchSignal = None giveUpTimer = 0 while (giveUpTimer < 10) : giveUpTimer = giveUpTimer + 1 newCurrent = self.findNewCurrentBlock(tryBlock, newCurrentBlocks, self.currentDirection) if (newCurrent == None) : newBlockText = "None" else : newBlockText = self.giveBlockName(newCurrent) #self.msgText("try " + str(giveUpTimer) + " " + self.giveBlockName(tryBlock) + " " + newBlockText) if ((newCurrent == tryBlock) or (newCurrent == None)) : break else : tryBlock = newCurrent if (self.debugLevel >= MediumDebug) : self.msgText("tryBlock: " + self.giveBlockName(tryBlock) + " oldCurrent: " + self.giveBlockName(oldCurrent) + " isStarting: " + str(self.isStarting)) if (tryBlock != oldCurrent or self.isStarting == True) : # we did move somewhere self.blockNow.text = " " self.blockNowLength.text = " " self.blockNext.text = " " self.blockNextLength.text = " " self.blockBeyond.text = " " self.blockBeyondLength.text = " " self.stopDistance.text = "0" self.stopDistanceForSpeed.text = "0" self.currentBlock = tryBlock self.blockStart.text = self.giveBlockName(self.currentBlock) self.blockNow.text = self.giveBlockName(self.currentBlock) self.blockNowLength.text = str(self.currentBlock.getLengthIn()) self.next1Block = self.findNextBlock(self.currentBlock) self.next2Block = None self.next3Block = None self.testAddBlockListener(self.currentBlock) if (self.next1Block != None) : self.blockNext.text = self.giveBlockName(self.next1Block) self.blockNextLength.text = str(self.next1Block.getLengthIn()) self.stopDistance.text = str(float(self.stopDistance.text) + self.next1Block.getLengthIn()) self.testAddBlockListener(self.next1Block) self.next2Block = self.findNextBlock(self.next1Block) if (self.next2Block != None) : self.blockBeyond.text = self.giveBlockName(self.next2Block) self.blockBeyondLength.text = str(self.next2Block.getLengthIn()) self.stopDistance.text = str(float(self.stopDistance.text) + self.next2Block.getLengthIn()) self.testAddBlockListener(self.next2Block) self.next3Block = self.findNextBlock(self.next2Block) self.priorBlock = oldCurrent self.priorBlocks = self.currentBlocks # find signals from currentBlock if (self.currentBlock != None and self.next1Block != None) : nearSignal = jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager).getFacingSignalHead(self.currentBlock, self.next1Block) if (nearSignal != None) : self.testAddSignalListener(nearSignal) if (self.debugLevel >= MediumDebug) : self.msgText("finding nearSignal between " + self.giveBlockName(self.currentBlock) + " and " + self.giveBlockName(self.next1Block) + " found " + self.giveSignalName(nearSignal)) if (self.next1Block != None and self.next2Block != None) : next1Signal = jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager).getFacingSignalHead(self.next1Block, self.next2Block) if (next1Signal != None) : self.testAddSignalListener(next1Signal) if (self.debugLevel >= MediumDebug) : self.msgText("finding next1Signal between " + self.giveBlockName(self.next1Block) + " and " + self.giveBlockName(self.next2Block) + " found " + self.giveSignalName(next1Signal)) if (self.next2Block != None and self.next3Block != None) : next2Signal = jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager).getFacingSignalHead(self.next2Block, self.next3Block) if (next2Signal != None) : self.testAddSignalListener(next2Signal) if (self.debugLevel >= MediumDebug) : self.msgText("finding next2Signal between " + self.giveBlockName(self.next2Block) + " and " + self.giveBlockName(self.next3Block) + " found " + self.giveSignalName(next2Signal)) if (self.blockAhead2.isSelected() == False) : if (self.debugLevel >= HighDebug) : self.msgText("3 block test: " + self.giveBlockName(self.currentBlock)) if (nearSignal != None) : watchSignal = nearSignal else : if (next1Signal != None) : watchSignal = next1Signal else : if (next2Signal != None) : watchSignal = next2Signal else : if (self.debugLevel >= MediumDebug) : self.msgText("4 block test: " + self.giveBlockName(self.next1Block)) if (next1Signal != None) : watchSignal = next1Signal else : if (next2Signal != None) : watchSignal = next2Signal # if we didn't find a signal, treat as RED if (watchSignal == None) : watchAspect = RED else : watchAspect = watchSignal.getAppearance() # if we moved or the signal head changed or the aspect changed if (self.debugLevel >= MediumDebug) : self.msgText("test blocks: " + self.giveBlockName(oldCurrent) + ":" + self.giveBlockName(self.currentBlock) + ":" + self.giveBlockName(self.next1Block)) self.msgText("test signals: " + self.giveSignalName(oldSignal) + ":" + self.giveSignalName(watchSignal)) self.msgText("test aspects: " + self.textSignalAspect(oldAspect) + ":" + self.textSignalAspect(watchAspect)) # set flag is we just moved, needed for some timer controls if oldCurrent != self.currentBlock : self.movementDetected = True if (self.movementDetected or oldSignal != watchSignal or oldAspect != watchAspect or self.isStarting == True) : # something changed, we calc the new speed if (oldCurrent == self.currentBlock and oldSignal == watchSignal and self.compareSignalAspects(oldAspect, watchAspect) < 0 and self.isStarting == False) : # signal dropped, that's bad if (self.debugLevel >= LowDebug) : self.msgText("signal dropped, same signal being watched.") if (self.compareSignalAspects(self.haltOnSignalHeadAppearance, watchAspect) >= 0) : # Only stop on dropping below this self.findNewSpeed(self.currentBlock, self.next1Block, watchSignal) else : self.msgText("Signal dropped in front of train. Halting!!") if (tryCount < tryCountLimit) : if (self.debugLevel >= LowDebug) : self.msgText("Doing change retry: " + str(tryCount)) continue else : self.doHalt() else : if (self.debugLevel >= LowDebug) : self.msgText("We moved, signal or aspect changed.") self.findNewSpeed(self.currentBlock, self.next1Block, watchSignal) else : if (self.debugLevel >= MediumDebug) : self.msgText("nothing changed to effect speed") # this is for display updates if (nearSignal != None) : self.signalNext.setIcon(self.cvtAppearanceIcon(nearSignal)) self.signalNextText.text = self.giveSignalName(nearSignal) else : self.signalNext.setIcon(None) self.signalNextText.text = "" if (next1Signal != None) : self.signalBeyond.setIcon(self.cvtAppearanceIcon(next1Signal)) self.signalBeyondText.text = self.giveSignalName(next1Signal) self.next1SignalAspect = next1Signal.getAppearance() else : self.signalBeyond.setIcon(None) self.signalBeyondText.text = "" if (next2Signal != None) : self.next2SignalAspect = next2Signal.getAppearance() self.nearSignal = nearSignal self.next1Signal = next1Signal self.next2Signal = next2Signal # we passed normal, so don't repeat tryCount = tryCountLimit # if we have a stop block if (self.stopBlock != None and self.currentBlock == self.stopBlock) : if (self.currentThrottle.getSpeedSetting() == 0) : if (self.debugLevel >= LowDebug) : self.msgText("Found stop block, doing stop.") self.doStop() self.isStarting = False self.releaseExtraListeners() #self.msgText("didMove: done") return # check lists of block and signal listeners and release ones not needed def releaseExtraListeners(self) : numBlocksL = len(self.listenerBlockListeners) numBlocks = len(self.listenerBlocks) #self.msgText("start with Blocks: " + str(numBlocks) + " Listeners: " + str(numBlocksL)) if (numBlocksL != numBlocks or numBlocksL <= 0 or numBlocks <= 0) : # blocks out of sync, stop and take it from the top if (self.debugLevel >= LowDebug) : self.msgText("Block lists out of sync! Blocks: " + str(numBlocks) + " Listeners: " + str(numBlocksL)) self.doHalt() self.releaseBlockListParts() else : while (numBlocks > 0) : numBlocks = numBlocks - 1 testBlock = self.listenerBlocks[numBlocks] #self.msgText("testing block: " + self.giveBlockName(testBlock)) if (testBlock != None) : if (testBlock != self.currentBlock) : if (testBlock != self.next1Block) : if (testBlock != self.next2Block) : #self.msgText("we don't need block: " + self.giveBlockName(testBlock)) l = self.listenerBlockListeners[numBlocks] testBlock.removePropertyChangeListener(l) self.listenerBlockListeners.pop(numBlocks) self.listenerBlocks.pop(numBlocks) numSignals = len(self.listenerSignals) numSignalsL = len(self.listenerSignalListeners) #self.msgText("starting Signals: " + str(numSignals) + " Listeners:" + str(numSignalsL)) if (numSignals != numSignalsL or numSignalsL <= 0 or numSignals <= 0) : if (self.debugLevel >= LowDebug) : self.msgText("Signal lists out of sync! Signals: " + str(numSignals) + " Listeners:" + str(numSignalsL)) self.doHalt() self.releaseSignalListParts() else : while (numSignals > 0) : numSignals = numSignals - 1 testSignal = self.listenerSignals[numSignals] #self.msgText("releaseExtraListeners() testing signal: " + self.giveSignalName(testSignal)) if (testSignal != self.currentSignal and testSignal != self.nearSignal and testSignal != self.next1Signal and testSignal != self.next2Signal) : if (self.debugLevel >= MediumDebug) : self.msgText("releaseExtraListeners() releasing: " + self.giveSignalName(testSignal)) l = self.listenerSignalListeners[numSignals] testSignal.removePropertyChangeListener(l) self.listenerSignalListeners.pop(numSignals) self.listenerSignals.pop(numSignals) #self.msgText("num signalListeners: " + str(len(self.listenerSignalListeners)) + " " + str(len(self.listenerSignals))) return # return true if thing is in thingList def isInList(self, thing, thingList) : found = False for b in thingList : if (b == thing) : found = True return found # see if block is in the listenerBlocks, add listener if not def testAddBlockListener(self, bk) : if (self.isInList(bk, self.listenerBlocks) == False) : # isn't in list, setup listener and add to list bl = self.BlockListener() bl.setCallBack(self.callBackForDidWeMove) bk.addPropertyChangeListener(bl) self.listenerBlocks.append(bk) self.listenerBlockListeners.append(bl) return # see if signal is in the listenerSignals, add listener if not def testAddSignalListener(self, sig) : if (self.isInList(sig, self.listenerSignals) == False) : # isn't in list, setup listener and add to list sl = self.SignalListener() sl.setCallBack(self.callBackForDidWeMove) sig.addPropertyChangeListener(sl) self.listenerSignals.append(sig) self.listenerSignalListeners.append(sl) if (self.debugLevel >= MediumDebug) : self.msgText("testAddSignalListener(" + self.giveSignalName(sig) + ")") return # release signal listeners and clean lists def releaseSignalListParts(self) : while(len(self.listenerSignals) > 0) : s = self.listenerSignals.pop(0) l = self.listenerSignalListeners.pop(0) if (self.debugLevel >= MediumDebug) : self.msgText("releasing listener for signal " + self.giveSignalName(s)) s.removePropertyChangeListener(l) return # release block listeners and clean lists def releaseBlockListParts(self) : while(len(self.listenerBlocks) > 0) : b = self.listenerBlocks.pop(0) l = self.listenerBlockListeners.pop(0) #self.msgText("releasing listener for block " + self.giveBlockName(b)) b.removePropertyChangeListener(l) return # release all listeners, part of the exit cleanup def releaseAllListeners(self, event) : self.releaseSignalListParts() self.releaseBlockListParts() if (self.speedChangeTimer != None) : for i in self.speedChangeTimer.getActionListeners() : self.speedChangeTimer.removeActionListener(i) if (self.hornDelayTimer != None) : for i in self.hornDelayTimer.getActionListeners() : self.hornDelayTimer.removeActionListener(i) if (self.currentThrottle != None) : #self.msgText("releasing throttle") self.currentThrottle.setSpeedSetting(0) self.currentThrottle.release(None) self.isAborting = True return # take list of new current blocks, a current block, and a current direction # return new current block at edge of current blocks def findNewCurrentBlock(self, cBlock, cList, cDir) : nBlock = None dMask = jmri.Path.EAST | jmri.Path.WEST if (self.debugLevel >= HighDebug) : self.msgText("dmask: " + str(dMask) + " orig cDir: " + str(cDir)) cDir = cDir & dMask # only looking for east/west if (self.debugLevel >= HighDebug) : self.msgText(" filtered cDir: " + str(cDir) + " currentDirection: " + str(self.currentDirection)) if (cDir == jmri.Path.NONE) : if (self.blockDirection.isSelected() == True) : cDir = jmri.Path.EAST else : cDir = jmri.Path.WEST if (cBlock == None) : if (self.debugLevel >= LowDebug) : self.msgText("findNewCurrentBlock: bad current block passed!") return None if (len(cList) <= 0) : if (self.debugLevel >= LowDebug) : self.msgText("findNewCurrentBlock: empty cList") else : pList = cBlock.getPaths() for p in pList : pB = p.getBlock() if (p.checkPathSet()) : dirTest = p.getToBlockDirection() & dMask if (self.debugLevel >= MediumDebug) : self.msgText("findNewCurrentBlock: testing for " + jmri.Path.decodeDirection(cDir) + " from " + self.giveBlockName(cBlock) + " to " + self.giveBlockName(pB) + " pointing " + jmri.Path.decodeDirection(dirTest)) if ((cDir & dirTest) == cDir) : for c in cList : if (c == pB) : nBlock = pB if (self.debugLevel >= MediumDebug) : self.msgText("findNewCurrentBlock found " + self.giveBlockName(pB)) break else : if (self.debugLevel >= MediumDebug) : self.msgText("findNewCurrentBlock not in cList: " + self.giveBlockName(c)) if (nBlock != None) : break else : if (self.debugLevel >= MediumDebug) : self.msgText("findNewCurrentBlock path not traversable: " + self.giveBlockName(cBlock) + " to " + self.giveBlockName(pB)) return nBlock # figure out signal names and decide speeds def findNewSpeed(self, cBlock, nBlock, wSig) : if (self.isRunning) : if (cBlock == None) : if (nBlock == None) : if (self.debugLevel >= LowDebug) : self.msgText("Failed to find either blocks") self.doHalt() else : if (self.debugLevel >= LowDebug) : self.msgText("Failed to find current block") self.doHalt() else : if (nBlock == None) : if (self.debugLevel >= LowDebug) : self.msgText("next block doesn't exist, treating as red.") self.speedFromAppearance(RED) self.priorSignal = self.currentSignal self.priorSignalAspect = self.currentSignalAspect self.currentSignal = None self.currentSignalAspect = RED self.next1Signal = None self.next1SignalAspect = RED else : useAspect = RED if (wSig != None) : if (self.debugLevel >= LowDebug) : self.msgText("Found currentSignal: " + self.giveSignalName(wSig) + " displaying: " + self.cvtAppearanceText(wSig)) useAspect = wSig.getAppearance() if (self.useStopFromDistance.isSelected() == True) : stopDistAspect = self.speedFromStopDistance() signalRank = self.rankSignalAspect(signalAspect) stopDistRank = self.rankSignalAspect(stopDistAspect) if (stopDistRank >= signalRank) : useAspect = signalAspect else : useAspect = stopDistAspect self.speedFromAppearance(useAspect) self.priorSignal = self.currentSignal self.priorSignalAspect = self.currentSignalAspect self.currentSignal = wSig self.currentSignalAspect = wSig.getAppearance() else : self.msgText("Failed finding signal!") self.doHalt() return # return rate from signal aspect def rateFromSignalAspect(self, sigAspect) : ret = 0 txt = "UNKNOWN" try : if (sigAspect & RED != 0) : txt = "RED" ret = float(self.locoRateRed.text) elif (sigAspect & FLASHRED != 0) : txt = "FLASHRED" ret = float(self.locoRateRedFlash.text) elif (sigAspect & YELLOW != 0) : txt = "YELLOW" ret = float(self.locoRateYellow.text) elif (sigAspect & FLASHYELLOW != 0) : txt = "FLASHYELLOW" ret = float(self.locoRateYellowFlash.text) elif (sigAspect & GREEN != 0) : txt = "GREEN" ret = float(self.locoRateGreen.text) elif (sigAspect & FLASHGREEN != 0) : txt = "FLASHGREEN" ret = float(self.locoRateGreenFlash.text) except ValueError : if (self.debugLevel >= LowDebug) : self.msgText("rateFromSignalAspect: no value for aspect " + txt) if (self.debugLevel >= MediumDebug) : self.msgText("rateFromSignalAspect(" + self.textSignalAspect(sigAspect) + "): " + str(ret)) return ret # convert signal appearance to a ranked value def rankSignalAspect(self, sigAspect) : ret = 0 if (sigAspect & RED != 0) : ret = 1 elif (sigAspect & FLASHRED != 0) : ret = 2 elif (sigAspect & YELLOW != 0) : ret = 3 elif (sigAspect & FLASHYELLOW != 0) : ret = 4 elif (sigAspect & GREEN != 0) : ret = 5 elif (sigAspect & FLASHGREEN != 0) : ret = 6 return ret # return speed change distance sum for rank change def rankSpeedChangeDistance(self, rankOld, rankNew) : ret = 0 if (rankOld >= 1 and rankNew <= 1) : ret = ret + float(self.locoDistRed.text) if (rankOld >= 2 and rankNew <= 2) : ret = ret + float(self.locoDistRedFlash.text) if (rankOld >= 3 and rankNew <= 3) : ret = ret + float(self.locoDistYellow.text) if (rankOld >= 4 and rankNew <= 4) : ret = ret + float(self.locoDistYellowFlash.text) if (rankOld >= 5 and rankNew <= 5) : ret = ret + float(self.locoDistGreen.text) if (rankOld >= 6 and rankNew <= 6) : ret = ret + float(self.locoDistGreenFlash.text) if (self.debugLevel >= MediumDebug) : self.msgText("rankSpeedChangeDistance(" + str(rankOld) + ", " + str(rankNew) + "): " + str(ret)) return ret # convert signal appearance to text def textSignalAspect(self, sigAspect) : ret = "???" if (sigAspect == None) : ret = "None" elif (sigAspect & RED != 0) : ret = "RED" elif (sigAspect & FLASHRED != 0) : ret = "FLASHRED" elif (sigAspect & YELLOW != 0) : ret = "YELLOW" elif (sigAspect & FLASHYELLOW != 0) : ret = "FLASHYELLOW" elif (sigAspect & GREEN != 0) : ret = "GREEN" elif (sigAspect & FLASHGREEN != 0) : ret = "FLASHGREEN" return ret # compare two signal appearances def compareSignalAspects(self, oldSigState, newSigState) : ret = "0" if (newSigState == None) : # this is wrong if (self.debugLevel >= LowDebug) : self.msgText("compare signals got a None for new signal state") self.doHalt() return if (oldSigState == None) : # startup case ret = 1 else : newSigValue = self.rankSignalAspect(newSigState) oldSigValue = self.rankSignalAspect(oldSigState) #self.msgText("compareSignalAspects: " + self.textSignalAspect(oldSigState) + " went " + self.textSignalAspect(newSigState)) if (newSigValue < oldSigValue) : ret = -1 elif (newSigValue > oldSigValue) : ret = 1 return ret # set speed from signal appearance. update stopDistanceForSpeed with distance and return aspect to match. def speedFromStopDistance(self) : distLimit = float(self.stopDistance.text) speedAspect = RED stopDistance = 0 next = float(self.locoDistRed.text) distLimit = distLimit - next if (distLimit >= 0) : stopDistance = stopDistance + next speedAspect = RED next = float(self.locoDistRedFlash.text) distLimit = distLimit - next if (distLimit >= 0) : stopDistance = stopDistance + next speedAspect = FLASHRED next = float(self.locoDistYellow.text) distLimit = distLimit - next if (distLimit >= 0) : stopDistance = stopDistance + next speedAspect = YELLOW next = float(self.locoDistYellowFlash.text) distLimit = distLimit - next if (distLimit >= 0) : stopDistance = stopDistance + next speedAspect = FLASHYELLOW next = float(self.locoDistGreen.text) distLimit = distLimit - next if (distLimit >= 0) : stopDistance = stopDistance + next speedAspect = GREEN next = float(self.locoDistGreenFlash.text) distLimit = distLimit - next if (distLimit >= 0) : stopDistance = stopDistance + next speedAspect = FLASHGREEN if (self.debugLevel >= MediumDebug) : self.msgText("speedFromStopDistance() " + str(stopDistance) + " " + self.cvtAspectToText(speedAspect)) self.stopDistanceForSpeed.text = str(stopDistance) return speedAspect # set speed from signal appearance def speedFromAppearance(self, sigState) : rep = "" if (sigState == RED or self.currentBlock == self.stopBlock) : rep = rep + "doRed " self.doSpeedRed() elif (sigState == FLASHRED) : rep = rep + "doRedFlash " self.doSpeedRedFlash() elif (sigState == YELLOW or self.next1Block == self.stopBlock) : rep = rep + "doYellow " self.doSpeedYellow() elif (sigState == FLASHYELLOW) : rep = rep + "doYellowFlash " self.doSpeedYellowFlash() elif (sigState == GREEN) : rep = rep + "doGreen " self.doSpeedGreen() elif (sigState == FLASHGREEN) : rep = rep + "doGreenFlash " self.doSpeedGreenFlash() else : rep = rep + "unknown " self.msgText("speedFromAppearance, unknown value! " + str(sigState)) self.doHalt() #self.msgText("speedFromAppearance: " + self.giveSignalName(sig) + " displaying: " + self.cvtAppearanceText(sig) + " so we did: " + rep) return # convert signal appearance to english def cvtAppearanceText(self, sig) : rep = "" if (sig.getHeld()) : rep = rep + "Held " if (sig.getLit()) : rep = rep + "Lit " rep = rep + self.cvtAspectToText(sig.getAppearance()) #self.msgText("cvtAppearanceText: " + self.giveSignalName(sig) + " displaying: " + rep) return rep # convert signal appearance to english def cvtAspectToText(self, sigState) : rep = "" if (sigState == RED) : rep = rep + "Red " elif (sigState == FLASHRED) : rep = rep + "Flashing Red " elif (sigState == YELLOW) : rep = rep + "Yellow " elif (sigState == FLASHYELLOW) : rep = rep + "Flashing Yellow " elif (sigState == GREEN) : rep = rep + "Green " elif (sigState == FLASHGREEN) : rep = rep + "Flashing Green " elif (sigState == DARK) : rep = rep + "Dark " else : rep = rep + "Unknown " #self.msgText("cvtAppearanceText: " + self.giveSignalName(sig) + " displaying: " + rep) return rep # convert signal appearance to icon def cvtAppearanceIcon(self, sig) : rep = self.darkSignalIcon if (sig.getLit()) : sigState = sig.getAppearance() if (sigState == RED) : rep = self.redSignalIcon elif (sigState == FLASHRED) : rep = self.redFlashSignalIcon elif (sigState == YELLOW) : rep = self.yellowSignalIcon elif (sigState == FLASHYELLOW) : rep = self.yellowFlashSignalIcon elif (sigState == GREEN) : rep = self.greenSignalIcon elif (sigState == FLASHGREEN) : rep = self.greenFlashSignalIcon else : rep = self.unknownSignalIcon #self.msgText("cvtAppearanceIcon: " + self.giveSignalName(sig) + " displaying: " + rep) return rep # compare two lists, reply true or false def compareLists(self, aList, bList) : if (self.debugLevel >= HighDebug) : self.msgText("comparing lists") doesMatchA = True doesMatchB = True for a in aList : try : i = bList.index(a) except : doesMatchA = False if (doesMatchA) : if (self.debugLevel >= HighDebug) : self.msgText("comparing lists: all of a in b") for b in bList : try : i = aList.index(b) except : doesMatchB = False if (doesMatchB) : if (self.debugLevel >= HighDebug) : self.msgText("comparing lists: all of b in a") return doesMatchA and doesMatchB def doSpeedGreenFlash(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None) : i = 0 try : i = int(self.locoSpeedGreenFlash.text) * 0.01 except : if (self.debugLevel >= NoneDebug) : self.msgText("doSpeedGreenFlash: Invalid value! " + self.locoSpeedGreenFlash.text) self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= LowDebug) : self.msgText("doSpeedGreenFlash: " + str(i)) self.locoSpeed.text = str(100 * i) return def doSpeedGreen(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None) : i = 0 try : i = int(self.locoSpeedGreen.text) * 0.01 except : if (self.debugLevel >= NoneDebug) : self.msgText("doSpeedGreen: Invalid value! " + self.locoSpeedGreen.text) self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= LowDebug) : self.msgText("doSpeedGreen: " + str(i)) self.locoSpeed.text = str(100 * i) return def doSpeedYellowFlash(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None) : i = 0 try : i = int(self.locoSpeedYellowFlash.text) * 0.01 except : if (self.debugLevel >= NoneDebug) : self.msgText("doSpeedYellowFlash: Invalid value! " + self.locoSpeedYellowFlash.text) self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= LowDebug) : self.msgText("doSpeedYellowFlash: " + str(i)) self.locoSpeed.text = str(100 * i) return def doSpeedYellow(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None) : doYellowNow = True if (self.movementDetected) : # compute how long to delay speed change dist = self.currentBlock.getLengthIn() rate = self.rateFromSignalAspect(FLASHGREEN) speedChgDist = self.rankSpeedChangeDistance(self.rankSignalAspect(FLASHGREEN), self.rankSignalAspect(FLASHYELLOW)) if (self.priorSignalAspect != None) : rate = self.rateFromSignalAspect(self.priorSignalAspect) speedChgDist = self.rankSpeedChangeDistance(self.rankSignalAspect(self.priorSignalAspect), self.rankSignalAspect(FLASHYELLOW)) if (dist > 0 and rate > 0) : # the delay distance is the reserved space plus 10% from far end of block # the less one covers the delay of the handle() routine delay = (((dist* 0.90) - speedChgDist) / rate ) - 1 if (self.debugLevel >= LowDebug) : self.msgText("doSpeedYellow: dist: " + str(dist) + " rate: " + str(rate) + " speedChgDist: " + str(speedChgDist) + " delay: " + str(delay)) if (delay > 1) : currentDelay = 0 if (self.speedChangeTimer == None) : if (self.speedChangeListener == None) : self.speedChangeListener = self.SpeedChangeTimeoutReceiver() self.speedChangeTimer = javax.swing.Timer(int(delay * 0), self.speedChangeListener) self.speedChangeTimer.setInitialDelay(int(delay * 1000)) self.speedChangeTimer.setRepeats(False); self.speedChangeListener.setCallBack(self.yellowDelayHandler) self.speedChangeTimer.setInitialDelay(int(delay * 1000)) self.speedChangeTimer.start() doYellowNow = False else : if (self.debugLevel >= LowDebug) : self.msgText("yellow delay less that 1 second") if (doYellowNow) : i = 0 try : i = int(self.locoSpeedYellow.text) * 0.01 except : if (self.debugLevel >= NoneDebug) : self.msgText("doSpeedYellow: Invalid value! " + self.locoSpeedYellow.text) self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= LowDebug) : self.msgText("doSpeedYellow: " + str(i)) self.locoSpeed.text = str(100 * i) return def doSpeedRedFlash(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None) : i = 0 try : i = int(self.locoSpeedRedFlash.text) * 0.01 except : if (self.debugLevel >= NoneDebug) : self.msgText("doSpeedRedFlash: Invalid value! " + self.locoSpeedRedFlash.text) self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= LowDebug) : self.msgText("doSpeedRedFlash: " + str(i)) self.locoSpeed.text = str(100 * i) return def doSpeedRed(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None and self.currentThrottle.getSpeedSetting() != 0) : i = 0 try : i = int(self.locoSpeedRed.text) * 0.01 except : if (self.debugLevel >= NoneDebug) : self.msgText("doSpeedRed: Invalid value! " + self.locoSpeedRed.text) self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= LowDebug) : self.msgText("doSpeedRed: " + str(i)) self.locoSpeed.text = str(100 * i) # compute how long to delay stopping dist = self.currentBlock.getLengthIn() rate = float(self.locoRateRed.text) stopDist = float(self.locoDistRed.text) if (self.priorSignalAspect != None) : stopDist = self.rankSpeedChangeDistance(self.rankSignalAspect(self.priorSignalAspect), self.rankSignalAspect(RED)) if (self.movementDetected == True and dist != 0 and rate != 0) : # the stop distance is the reserved space plus 10% from far end of block # the less one covers the delay of the handle() routine delay = ((dist - stopDist) / rate * 0.90) - 1 if (self.debugLevel >= LowDebug) : self.msgText("doSpeedRed: dist: " + str(dist) + " rate: " + str(rate) + " stopDist: " + str(stopDist) + " delay: " + str(delay)) if (delay > 1) : currentDelay = 0 if (self.speedChangeTimer == None) : if (self.speedChangeListener == None) : self.speedChangeListener = self.SpeedChangeTimeoutReceiver() self.speedChangeTimer = javax.swing.Timer(int(delay * 0), self.speedChangeListener) self.speedChangeTimer.setInitialDelay(int(delay * 1000)) self.speedChangeTimer.setRepeats(False); self.speedChangeListener.setCallBack(self.redDelayHandler) self.speedChangeTimer.setInitialDelay(int(delay * 1000)) self.speedChangeTimer.start() else : if (self.debugLevel >= LowDebug) : self.msgText("stop delay less that 1 second") self.doStop() else : self.doStop() return # handle the timeout for slowing to yellow def yellowDelayHandler(self, event) : if (self.debugLevel >= MediumDebug) : self.msgText("yellowDelayHandler: slow to yellow now!") self.speedChangeTimer.stop() if (self.currentThrottle != None) : i = int(self.locoSpeedYellow.text) * 0.01 self.currentThrottle.setSpeedSetting(i) if (self.debugLevel >= MediumDebug) : self.msgText("yellowDelayHandler: " + str(i)) self.locoSpeed.text = self.locoSpeedYellow.text return # handle the timeout for stopping on red def redDelayHandler(self, event) : if (self.debugLevel >= MediumDebug) : self.msgText("redDelayHandler, stopping now!") self.speedChangeTimer.stop() self.doStop() return # stopping for normal issues, allows for restarting automaticly def doStop(self): if (self.speedChangeTimer != None) : self.speedChangeTimer.stop() if (self.currentThrottle != None) : self.currentThrottle.setSpeedSetting(0) if (self.debugLevel >= LowDebug) : self.msgText("doStop") self.locoSpeed.text = "0" if (self.currentBlock != None) : self.blockStart.text = self.giveBlockName(self.currentBlock) if (self.stopBlock != None and self.currentBlock == self.stopBlock) : self.handleHalting() return # doHalt is for stopping due to error conditions, won't restart def doHalt(self) : if (self.currentThrottle != None) : self.currentThrottle.setSpeedSetting(-1) self.msgText("doHalt, something was in error!!") self.locoSpeed.text = "0" if (self.currentBlock != None) : self.blockStart.text = self.giveBlockName(self.currentBlock) self.handleHalting() self.msgText("*** Run halted ***") return # deal with the buttons and stuff when we wait for humans def handleHalting(self) : self.stopButton.setEnabled(False) self.haltButton.setEnabled(False) self.startButton.setEnabled(True) self.isRunning = False return # process the stop block def whenStopBlockChanged(self, event) : self.blockStop.text = self.blockStop.text.strip() if (self.blockStop.text == "") : self.stopBlock = None else : self.stopBlock = blocks.getBlock(self.blockStop.text) return # validate loco values def whenLocoFieldChanged(self, event) : isBad = False ptr = event.getSource() msg = "whenLocoFieldChanged: " + ptr.getName() + " - " try : i = int(ptr.text) if (i < 0 or i > 9999) : msg = msg + "Loco id out of range: " + ptr.text ptr.text = str(i) msg = msg + ptr.text except : isBad = True msg = msg + "Invalid loco value: " + ptr.text ptr.text = "" if (isBad) or (self.debugLevel >= MediumDebug) : self.msgText(msg) return # validate speed values def whenSpeedFieldChanged(self, event) : isBad = False ptr = event.getSource() msg = "whenSpeedFieldChanged: " + ptr.getName() + " - " i = 0 try : i = int(ptr.text) ptr.text = str(i) msg = msg + ptr.text except ValueError : isBad = True msg = msg + "Invalid speed value: " + ptr.text ptr.text = "" if (i < 0) : isBad = True msg = msg + "Negitive value for speed: " + ptr.text ptr.text = "" if (i > 100) : isBad = True msg = msg + "Too large value for speed: " + ptr.text ptr.text = "" if (isBad) or (self.debugLevel >= MediumDebug) : self.msgText(msg) return # validate distance values def whenDistanceFieldChanged(self, event) : isBad = False ptr = event.getSource() msg = "whenDistanceFieldChanged: " + ptr.getName() + " - " f = 0 try : f = float(round(float(ptr.text) * 100) / 100.00) ptr.text = str(f) msg = msg + ptr.text except ValueError : isBad = True msg = msg + "Invalid distance value: " + ptr.text ptr.text = "" if (f < 0) : isBad = True msg = msg + "Negitive value for distance: " + ptr.text ptr.text = "" if (isBad) or (self.debugLevel >= MediumDebug) : self.msgText(msg) return # enable the button when OK def whenLocoChanged(self, event) : # keep track of whether both fields have been changed if (self.isRunning) : self.doStop() if (self.debugLevel >= LowDebug) : self.msgText("whenLocoChanged: was running, now stopped") isOk = True startBlock = None self.locoAddress.text = self.locoAddress.text.strip() if (self.locoAddress.text == "") : isOk = False else : self.scriptFrame.setTitle("Run Loco " + self.locoAddress.text) self.setName("RT3: " + self.locoAddress.text) if (self.locoAddress.text != self.oldLocoAddress) : # clear old block assignments self.clearLocoFromBlocks(self.oldLocoAddress) self.oldLocoAddress = self.locoAddress.text if (self.loadFromRoster.isSelected() == True) : # take the loco id and try looking up values in roster if (self.rosterInstance == None) : self.rosterInstance = jmri.jmrit.roster.Roster.getDefault() if (self.debugLevel >= MediumDebug) : self.msgText("got roster instance") rosterEntries = self.rosterInstance.matchingList(None, None, self.locoAddress.text, None, None, None, None) if (self.debugLevel >= MediumDebug) : self.msgText("found " + str(rosterEntries.size()) + " entries matching |" + str(id) + "|") for ent in rosterEntries : if (self.debugLevel >= LowDebug) : self.msgText("posible entries: " + ent.fileName) if (rosterEntries.size() == 1) : ent = rosterEntries.get(0) if (self.debugLevel >= LowDebug) : self.msgText("Reading roster: " + ent.fileName) v = ent.getAttribute('RT_locoSpeedGreenFlash') if (v != None and v.strip() != "") : self.locoSpeedGreenFlash.text = v.strip() v = ent.getAttribute('RT_locoRateGreenFlash') if (v != None and v.strip() != "") : self.locoRateGreenFlash.text = v.strip() v = ent.getAttribute('RT_locoDistGreenFlash') if (v != None and v.strip() != "") : self.locoDistGreenFlash.text = v.strip() v = ent.getAttribute('RT_locoSpeedGreen') if (v != None and v.strip() != "") : self.locoSpeedGreen.text = v.strip() v = ent.getAttribute('RT_locoRateGreen') if (v != None and v.strip() != "") : self.locoRateGreen.text = v.strip() v = ent.getAttribute('RT_locoDistGreen') if (v != None and v.strip() != "") : self.locoDistGreen.text = v.strip() v = ent.getAttribute('RT_locoSpeedYellowFlash') if (v != None and v.strip() != "") : self.locoSpeedYellowFlash.text = v.strip() v = ent.getAttribute('RT_locoRateYellowFlash') if (v != None and v.strip() != "") : self.locoRateYellowFlash.text = v.strip() v = ent.getAttribute('RT_locoDistYellowFlash') if (v != None and v.strip() != "") : self.locoDistYellowFlash.text = v.strip() v = ent.getAttribute('RT_locoSpeedYellow') if (v != None and v.strip() != "") : self.locoSpeedYellow.text = v.strip() v = ent.getAttribute('RT_locoRateYellow') if (v != None and v.strip() != "") : self.locoRateYellow.text = v.strip() v = ent.getAttribute('RT_locoDistYellow') if (v != None and v.strip() != "") : self.locoDistYellow.text = v.strip() v = ent.getAttribute('RT_locoSpeedRedFlash') if (v != None and v.strip() != "") : self.locoSpeedRedFlash.text = v.strip() v = ent.getAttribute('RT_locoRateRedFlash') if (v != None and v.strip() != "") : self.locoRateRedFlash.text = v.strip() v = ent.getAttribute('RT_locoDistRedFlash') if (v != None and v.strip() != "") : self.locoDistRedFlash.text = v.strip() v = ent.getAttribute('RT_locoSpeedRed') if (v != None and v.strip() != "") : self.locoSpeedRed.text = v.strip() v = ent.getAttribute('RT_locoRateRed') if (v != None and v.strip() != "") : self.locoRateRed.text = v.strip() v = ent.getAttribute('RT_locoDistRed') if (v != None and v.strip() != "") : self.locoDistRed.text = v.strip() self.locoLong.setSelected(ent.isLongAddress()) if (self.debugLevel >= LowDebug) : self.msgText("Read completed: " + ent.fileName) self.oldLocoAddress = self.locoAddress.text if (self.locoSpeedRed.text == "") : isOk = False if (self.locoSpeedRedFlash.text == "") : isOk = False if (self.locoSpeedYellow.text == "") : isOk = False if (self.locoSpeedYellowFlash.text == "") : isOk = False if (self.locoSpeedGreen.text == "") : isOk = False if (self.locoSpeedGreenFlash.text == "") : isOk = False self.blockStart.text = self.blockStart.text.strip() if (self.blockStart.text == "") : isOk = False else : startBlock = blocks.getBlock(self.blockStart.text) if (self.testIfBlockNameValid(self.blockStart.text) == False) : if (self.debugLevel >= LowDebug) : self.msgText("Invalid block name: " + self.blockStart.text + " please try again") isOk = False else: if (startBlock.getState() != ACTIVE) : if (self.debugLevel >= LowDebug) : self.msgText("Block: " + self.blockStart.text + " is not occupied!") isOk = False if (isOk) : # clear id from any existing blocks for b in blocks.getNamedBeanSet() : if (b != blocks.getBlock(self.blockStart.text) and b.getValue() == self.locoAddress.text) : b.setValue("") if (self.blockDirection.isSelected()) : self.currentDirection = jmri.Path.EAST else : self.currentDirecion = jmri.Path.WEST self.startButton.setEnabled(True) self.haltButton.setEnabled(True) self.testAddBlockListener(blocks.getBlock(self.blockStart.text)) if (self.debugLevel >= LowDebug) : self.msgText("Enabled Start") return # handle the Move Green button on def whenLocoMoveOnGreen(self, event) : self.doLocoMove(event, int(self.locoSpeedGreen.text) * 0.01) return # handle the Move Yellow button on def whenLocoMoveOnYellow(self, event) : self.doLocoMove(event, int(self.locoSpeedYellow.text) * 0.01) return # handle the Move Red button on def whenLocoMoveOnRed(self, event) : self.doLocoMove(event, int(self.locoSpeedRed.text) * 0.01) return # handle the Move button off def whenLocoMoveOff(self, event) : self.doLocoMove(event, 0) return def doLocoMove(self, event, state) : if (self.currentThrottle != None) : wasState = self.currentThrottle.getSpeedSetting() self.currentThrottle.setSpeedSetting(state) if (self.debugLevel >= LowDebug) and (state != wasState) : self.msgText("changed speed to: " + str(state) + " was " + str(wasState)) return # handle the horn button on def whenLocoHornOn(self, event) : self.doLocoHorn(event, True) return # handle the horn button off def whenLocoHornOff(self, event) : self.doLocoHorn(event, False) return def doLocoHorn(self, event, state) : if (self.currentThrottle != None) : wasState = self.currentThrottle.getF2() self.currentThrottle.setF2(state) if (self.debugLevel >= HighDebug) : self.msgText("changed horn to: " + str(state) + " was " + str(wasState)) return def doShortHorn(self) : self.doTimedHorn(1*1000) return def doLongHorn(self) : self.doTimedHorn(2*1000) return def doTimedHorn(self, delay) : if (self.currentThrottle != None) : self.currentThrottle.setF2(True) if (self.hornDelayTimer == None) : self.hornDelayListener = self.HornTimeoutReceiver() self.hornDelayListener.setCallBack(self.hornDelayHandler) self.hornDelayTimer = javax.swing.Timer(int(delay), self.hornDelayListener) self.hornDelayTimer.setInitialDelay(int(delay)) self.hornDelayTimer.setRepeats(False); self.hornDelayTimer.setInitialDelay(int(delay)) self.hornDelayTimer.start() if (self.debugLevel >= HighDebug) : self.msgText("Started Timed Horn") return def hornDelayHandler(self, event) : if (self.hornDelayTimer != None) : self.hornDelayTimer.stop() if (self.currentThrottle != None) : self.currentThrottle.setF2(False) if (self.debugLevel >= HighDebug) : self.msgText("Stopped Timed Horn") return # handle the Headlight button def whenLocoHeadlight(self, event) : if (self.currentThrottle != None) : wasState = self.currentThrottle.getF0() state = self.locoHeadlight.isSelected() self.currentThrottle.setF0(state) if (self.debugLevel >= HighDebug) : self.msgText("changed light to: " + str(state) + " was " +str( wasState)) return # handle the Bell button def whenLocoBell(self, event) : if (self.currentThrottle != None) : wasState = self.currentThrottle.getF1() state = self.locoBell.isSelected() self.currentThrottle.setF1(state) if (self.debugLevel >= HighDebug) : self.msgText("changed bell to: " + str(state) + " was " + str(wasState)) return # test for block name def testIfBlockNameValid(self, userName) : foundStart = False b = blocks.getByUserName(userName) if (b != None and self.giveBlockName(b) == userName) : foundStart = True return foundStart # define what button does when clicked and attach that routine to the button def whenStartButtonClicked(self, event) : self.msgText("Run started") # add text if (self.testIfBlockNameValid(self.blockStart.text) == False) : if (self.debugLevel >= LowDebug) : self.msgText("Invalid block name: " + self.blockStart.text + " please try again") else : c = blocks.getBlock(self.blockStart.text) if (c == None) : if (self.debugLevel >= LowDebug) : self.msgText("Invalid block name: " + self.blockStart.text + " please try again") else : # clear any prior block entries self.clearLocoFromBlocks(self.locoAddress.text) c.setValue(self.locoAddress.text) self.currentBlock = c self.priorSignal = None self.priorSignalAspect = None self.currentSignal = None self.currentSignalAspect = None self.next1Block = None self.next1Signal = None self.next1SignalAspect = None # set flags so things get done from handle() routine self.askChangeThrottle = True self.askFinishStartButton = True if (self.debugLevel >= MediumDebug) : self.msgText("whenStartButtonClicked, done") # add text return # split out so it can happen from the handle() routine def doFinishStartButton(self) : if (self.debugLevel >= MediumDebug) : self.msgText("Change button states") # add text self.stopButton.setEnabled(True) self.haltButton.setEnabled(True) self.startButton.setEnabled(False) self.isRunning = True self.isStarting = True self.currentBlocks = None self.priorBlocks = None if (self.blockDirection.isSelected() == True) : self.currentDirection = jmri.Path.EAST self.currentBlock.setDirection(jmri.Path.EAST) else : self.currentDirection = jmri.Path.WEST self.currentBlock.setDirection(jmri.Path.WEST) self.didWeMoveCounter = self.didWeMoveCounter + 1 if (self.isRunning) : if (self.debugLevel >= LowDebug) : self.msgText("Starting current:" + self.giveBlockName(self.currentBlock)) return def whenStopButtonClicked(self, event): if (self.debugLevel >= MediumDebug) : self.msgText("Slow loco to stop") # add text self.doStop() if (self.debugLevel >= LowDebug) : self.msgText("*** Run stopped ***") self.stopButton.setEnabled(False) self.handleHalting() self.whenLocoChanged(event) return def whenHaltButtonClicked(self, event): if (self.debugLevel >= LowDebug) : self.msgText("Button Halt loco NOW!") # add text self.doHalt() if (self.debugLevel >= LowDebug) : self.msgText("*** Run halted ***") self.handleHalting() self.whenLocoChanged(event) return def whenLocoDirectionButtonClicked(self, event) : if (self.debugLevel >= MediumDebug) : self.msgText("Button Loco Direction clicked") if (self.currentThrottle != None) : self.currentThrottle.setIsForward(self.locoForward.isSelected()) return def whenBlockDirectionButtonClicked(self, event) : if (self.debugLevel >= MediumDebug) : self.msgText("Button Block Direction clicked") self.methodBlockDirection = self.blockDirection.isSelected() return def whenShrinkButtonClicked(self, event): if (self.shrinkGrow == True) : if (self.debugLevel >= HighDebug) : self.msgText("Shrink Display!") # add text self.speedPane.setVisible(False) self.shrinkGrow = False self.fullScrollRows = self.scrollArea.getRows() self.scrollArea.setRows(self.fullScrollRows / 2) self.scriptFrame.pack() else : if (self.debugLevel >= HighDebug) : self.msgText("Grow Display!") self.speedPane.setVisible(True) self.shrinkGrow = True self.scrollArea.setRows(self.fullScrollRows) self.scriptFrame.pack() return def whenSaveToRosterButtonClicked(self, event): if (self.locoAddress.text != "") : if (self.rosterInstance == None) : self.rosterInstance = jmri.jmrit.roster.Roster.getDefault() if (self.debugLevel >= MediumDebug) : self.msgText("got roster instance") id = int(self.locoAddress.text) rosterEntries = self.rosterInstance.matchingList(None, None, str(id), None, None, None, None) if (self.debugLevel >= HighDebug) : self.msgText("found " + str(rosterEntries.size()) + " entries matching |" + str(id) + "|") for ent in rosterEntries : if (self.debugLevel >= LowDebug) : self.msgText("posible entries: " + ent.fileName) if (rosterEntries.size() == 1) : ent = rosterEntries.get(0) if (self.debugLevel >= LowDebug) : self.msgText("Saving to roster: " + ent.fileName) ent.putAttribute('RT_locoSpeedGreenFlash', self.locoSpeedGreenFlash.text) ent.putAttribute('RT_locoRateGreenFlash', self.locoRateGreenFlash.text) ent.putAttribute('RT_locoDistGreenFlash', self.locoDistGreenFlash.text) ent.putAttribute('RT_locoSpeedGreen', self.locoSpeedGreen.text) ent.putAttribute('RT_locoRateGreen', self.locoRateGreen.text) ent.putAttribute('RT_locoDistGreen', self.locoDistGreen.text) ent.putAttribute('RT_locoSpeedYellowFlash', self.locoSpeedYellowFlash.text) ent.putAttribute('RT_locoRateYellowFlash', self.locoRateYellowFlash.text) ent.putAttribute('RT_locoDistYellowFlash', self.locoDistYellowFlash.text) ent.putAttribute('RT_locoSpeedYellow', self.locoSpeedYellow.text) ent.putAttribute('RT_locoRateYellow', self.locoRateYellow.text) ent.putAttribute('RT_locoDistYellow', self.locoDistYellow.text) ent.putAttribute('RT_locoSpeedRedFlash', self.locoSpeedRedFlash.text) ent.putAttribute('RT_locoRateRedFlash', self.locoRateRedFlash.text) ent.putAttribute('RT_locoDistRedFlash', self.locoDistRedFlash.text) ent.putAttribute('RT_locoSpeedRed', self.locoSpeedRed.text) ent.putAttribute('RT_locoRateRed', self.locoRateRed.text) ent.putAttribute('RT_locoDistRed', self.locoDistRed.text) ent.updateFile() self.rosterInstance.writeRosterFile() if (self.debugLevel >= LowDebug) : self.msgText("Save completed: " + ent.fileName) return def findCurrentBlocks(self) : # search the block list for the matching loco blockList = [] for b in blocks.getNamedBeanSet() : if (b.getValue() == self.locoAddress.text and b.getState() == ACTIVE) : blockList.append(b) return blockList def clearLocoFromBlocks(self, oldId) : # search the block list for the matching loco blockList = [] for b in blocks.getNamedBeanSet() : if (b.getValue() == oldId) : b.setValue(None) return def findNextBlock(self, cB) : # look down list of getToBlockDirection for match # use 'suggestion' flag if current block doesn't have direction bTrav = None bNoTrav = None dirFlag = cB.getDirection() if (dirFlag == jmri.Path.NONE) : if (self.currentDirection == None) : if (self.blockDirection.isSelected() == True) : dirFlag = jmri.Path.EAST self.currentDirection = jmri.Path.EAST else : dirFlag = jmri.Path.WEST self.currentDirection = jmri.Path.WEST else : dirFlag = self.currentDirection pathList = cB.getPaths() if (self.debugLevel >= HighDebug) : self.msgText("searching " + str(len(pathList)) + " paths from " + self.giveBlockName(cB)) for p in pathList : blockTest = p.getBlock() dirTest = p.getToBlockDirection() if (dirTest & dirFlag != 0) : if (p.checkPathSet()) : if (self.debugLevel >= MediumDebug) : self.msgText("findNextBlock path traversable: " + self.giveBlockName(cB) + " to " + self.giveBlockName(blockTest) + " dirTest: " + jmri.Path.decodeDirection(dirTest) + ":" + str(dirTest) + " dirFlag: " + jmri.Path.decodeDirection(dirFlag) + ":" + str(dirFlag) + " result: " + str(dirTest & dirFlag)) bTrav = blockTest else : if (self.debugLevel >= MediumDebug) : self.msgText("findNextBlock path not traversable: " + self.giveBlockName(cB) + " to " + self.giveBlockName(blockTest)) bNoTrav = blockTest if (self.debugLevel >= LowDebug) : self.msgText("findNextBlock Found " + self.giveBlockName(blockTest)) if (bTrav == None) : return bNoTrav return bTrav # ActionListener - used for the stop timeout class SpeedChangeTimeoutReceiver(java.awt.event.ActionListener): cb = None def actionPerformed(self, event) : if (self.cb != None) : self.cb(event) return def setCallBack(self, cbf) : self.cb = cbf return # ActionListener - used for the horn timeout class HornTimeoutReceiver(java.awt.event.ActionListener): cb = None def actionPerformed(self, event) : if (self.cb != None) : self.cb(event) return def setCallBack(self, cbf) : self.cb = cbf return # WindowListener is a interface class and therefore all of it's # methods should be implemented even if not used to avoid AttributeErrors class WinListener(java.awt.event.WindowListener): f = None cleanUp = None def setCallBack(self, fr, c): self.f = fr self.cleanUp = c return def windowClosing(self, event): if (self.cleanUp != None) : self.cleanUp(event) self.f.dispose() # close the pane (window) return def windowActivated(self,event): return def windowDeactivated(self,event): return def windowOpened(self,event): return def windowClosed(self,event): return def windowIconified(self, event): return def windowDeiconified(self, event): return #To detect block status, first define the listener. class BlockListener(java.beans.PropertyChangeListener): cb = None def setCallBack(self, ptr) : self.cb = ptr return def propertyChange(self, event): if (self.cb != None) : self.cb(event) return #To detect block status, first define the listener. class SignalListener(java.beans.PropertyChangeListener): cb = None def setCallBack(self, ptr) : self.cb = ptr return def propertyChange(self, event): if (self.cb != None) : self.cb(event) return # method for creating a TimeStamp. def formatTime(self, ts): ptHrs = str(ts.get(java.util.Calendar.HOUR_OF_DAY)) if len(ptHrs) == 1 : ptHrs = "0" + ptHrs ptMins = str(ts.get(java.util.Calendar.MINUTE)) if len(ptMins) == 1 : ptMins = "0" + ptMins ptSecs = str(ts.get(java.util.Calendar.SECOND)) if len(ptSecs) == 1 : ptSecs = "0" + ptSecs ptMs = str(ts.get(java.util.Calendar.MILLISECOND)) pTime = ptHrs + ":" + ptMins + ":" + ptSecs + "." + ptMs return pTime # method for creating a DateStamp. def formatDate(self, ts): ptDays = str(ts.get(java.util.Calendar.DATE)) if len(ptDays) == 1 : ptDays = "0" + ptDays ptMonths = str(ts.get(java.util.Calendar.MONTH) + 1) if len(ptMonths) == 1 : ptMonths = "0" + ptMonths ptYears = str(ts.get(java.util.Calendar.YEAR)) pDate = ptMonths + "/" + ptDays + "/" + ptYears return pDate # handle adding to message window def msgText(self, txt) : if (self.scrollTimeStamp.isSelected() == True) : ts = java.util.Calendar.getInstance() self.scrollArea.append(self.formatTime(ts) + ": " + txt + "\n") else : self.scrollArea.append(txt + "\n") if (self.autoScroll.isSelected() == True) : self.scrollArea.setCaretPosition(self.scrollArea.getDocument().getLength()) return # setup the user interface def setup(self) : # get other setup things self.greenSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-green-short.gif", "GreenCabSignal") self.greenFlashSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-flashgreen-short.gif", "GreenFlashCabSignal") self.yellowSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-yellow-short.gif", "YellowCabSignal") self.yellowFlashSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-flashyellow-short.gif", "YellowFlashCabSignal") self.redSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-red-short.gif", "RedCabSignal") self.redFlashSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-flashred-short.gif", "RedFlashCabSignal") self.darkSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/searchlights/right-dark-short.gif", "DarkCabSignal") self.unknownSignalIcon = jmri.jmrit.catalog.NamedIcon("resources/icons/misc/Question-black.gif", "UnknownCabSignal") self.throttleManager = jmri.InstanceManager.getDefault(jmri.ThrottleManager) if (self.throttleManager == None) : print("No command station found!!\nRT has no way to control the trains.\n") return # start to initialise the GUI sizeRateField = 4 sizeSpeedField = 3 # create buttons and define action self.startButton = javax.swing.JButton("Start") self.startButton.setEnabled(False) # button starts as grayed out (disabled) self.startButton.actionPerformed = self.whenStartButtonClicked self.stopButton = javax.swing.JButton("Stop") self.stopButton.setEnabled(False) # button starts as grayed out (disabled) self.stopButton.setToolTipText("Stops the run - there is a delay as the loco slows") self.stopButton.actionPerformed = self.whenStopButtonClicked self.haltButton = javax.swing.JButton("Halt") self.haltButton.setEnabled(False) # button starts as grayed out (disabled) self.haltButton.setToolTipText("Emergency halt the run - should be an abrupt stop") self.haltButton.actionPerformed = self.whenHaltButtonClicked self.shrinkButton = javax.swing.JButton("Shrink") self.shrinkButton.setEnabled(True) self.shrinkButton.setToolTipText("Shrink/Grow the window") self.shrinkButton.actionPerformed = self.whenShrinkButtonClicked self.testButton = javax.swing.JButton("Test") self.testButton.setEnabled(True) # button starts as grayed out (disabled) self.testButton.setToolTipText("run the didWeMove test") self.testButton.actionPerformed = self.callBackForDidWeMove self.saveToRosterButton = javax.swing.JButton("Save Settings") self.saveToRosterButton.setEnabled(True) self.saveToRosterButton.setToolTipText("Saves setting in roster, if found.") self.saveToRosterButton.actionPerformed = self.whenSaveToRosterButtonClicked # address of the loco self.locoAddress = javax.swing.JTextField(5) # sized to hold 5 characters, initially empty self.locoAddress.actionPerformed = self.whenLocoChanged # if user hit return or enter self.locoAddress.focusLost = self.whenLocoChanged # if user tabs away self.locoAddress.requestFocusInWindow() # long/short address flag self.locoLong = javax.swing.JCheckBox() self.locoLong.setToolTipText("Check to use long address") self.locoLong.setSelected(True) if (self.throttleManager.addressTypeUnique() == True) : self.locoLong.setEnabled(False) self.locoLong.actionPerformed = self.whenLocoChanged self.locoLong.focusLost = self.whenLocoChanged # loco direction flag self.locoForward = javax.swing.JCheckBox() self.locoForward.setToolTipText("Sets forward loco direction") self.locoForward.setSelected(True) self.locoForward.actionPerformed = self.whenLocoDirectionButtonClicked self.locoForward.focusLost = self.whenLocoDirectionButtonClicked # loco headlight flag self.locoHeadlight = javax.swing.JCheckBox() self.locoHeadlight.setToolTipText("Controls loco hightlight") self.locoHeadlight.actionPerformed = self.whenLocoHeadlight self.locoHeadlight.focusLost = self.whenLocoHeadlight # loco bell flag self.locoBell = javax.swing.JCheckBox() self.locoBell.setToolTipText("Controls loco bell") self.locoBell.actionPerformed = self.whenLocoBell self.locoBell.focusLost = self.whenLocoBell # loco horn/whistle flag self.locoHorn = javax.swing.JButton("Horn") self.locoHorn.setToolTipText("Controls loco horn") self.locoHorn.mousePressed = self.whenLocoHornOn self.locoHorn.mouseReleased = self.whenLocoHornOff # loco move buttons self.locoMoveGreen = javax.swing.JButton("Move @ Clear") self.locoMoveGreen.setToolTipText("Moves loco at Clear speed") self.locoMoveGreen.mousePressed = self.whenLocoMoveOnGreen self.locoMoveGreen.mouseReleased = self.whenLocoMoveOff self.locoMoveYellow = javax.swing.JButton("Move @ Limited") self.locoMoveYellow.setToolTipText("Moves loco at Limited speed") self.locoMoveYellow.mousePressed = self.whenLocoMoveOnYellow self.locoMoveYellow.mouseReleased = self.whenLocoMoveOff self.locoMoveRed = javax.swing.JButton("Move @ Restricted") self.locoMoveRed.setToolTipText("Moves loco at Restricted speed") self.locoMoveRed.mousePressed = self.whenLocoMoveOnRed self.locoMoveRed.mouseReleased = self.whenLocoMoveOff # create the speed fields for a Green Flash Signal self.locoSpeedGreenFlash = javax.swing.JTextField(sizeSpeedField) # sized to hold 5 characters self.locoSpeedGreenFlash.setToolTipText("Green Flash Speed is a number from 1 to 100%") self.locoSpeedGreenFlash.actionPerformed = self.whenSpeedFieldChanged self.locoSpeedGreenFlash.focusLost = self.whenSpeedFieldChanged self.locoSpeedGreenFlash.text = "70" self.locoSpeedGreenFlash.setName("locoSpeedGreenFlash") # create the physical speed field for a Green Flash Signal self.locoRateGreenFlash = javax.swing.JTextField(sizeRateField) # sized to hold 5 characters self.locoRateGreenFlash.setToolTipText("Throttle as Distance/Second, approaching green flash signal") self.locoRateGreenFlash.actionPerformed = self.whenDistanceFieldChanged self.locoRateGreenFlash.focusLost = self.whenDistanceFieldChanged self.locoRateGreenFlash.text = "0" self.locoRateGreenFlash.setName("locoRateGreenFlash") # create the distance field for a Green Flash Signal self.locoDistGreenFlash = javax.swing.JTextField(5) # sized to hold 5 characters self.locoDistGreenFlash.setToolTipText("Distance to Green Speed from Green Flash signal speed, inches") self.locoDistGreenFlash.actionPerformed = self.whenDistanceFieldChanged self.locoDistGreenFlash.focusLost = self.whenDistanceFieldChanged self.locoDistGreenFlash.text = "6" self.locoDistGreenFlash.setName("locoDistGreenFlash") # create the speed fields for a Green Signal self.locoSpeedGreen = javax.swing.JTextField(sizeSpeedField) # sized to hold 5 characters self.locoSpeedGreen.setToolTipText("Green Speed is a number from 1 to 100%") self.locoSpeedGreen.actionPerformed = self.whenSpeedFieldChanged self.locoSpeedGreen.focusLost = self.whenSpeedFieldChanged self.locoSpeedGreen.text = "45" self.locoSpeedGreen.setName("locoSpeedGreen") # create the physical speed field for a Green Signal self.locoRateGreen = javax.swing.JTextField(sizeRateField) # sized to hold 5 characters self.locoRateGreen.setToolTipText("Throttle as Distance/Second, approaching Green signal") self.locoRateGreen.actionPerformed = self.whenDistanceFieldChanged self.locoRateGreen.focusLost = self.whenDistanceFieldChanged self.locoRateGreen.text = "9" self.locoRateGreen.setName("locoRateGreen") # create the distance field for a Green Signal self.locoDistGreen = javax.swing.JTextField(5) # sized to hold 5 characters self.locoDistGreen.setToolTipText("Distance to Yellow Flash Speed from Green signal speed, inches") self.locoDistGreen.actionPerformed = self.whenDistanceFieldChanged self.locoDistGreen.focusLost = self.whenDistanceFieldChanged self.locoDistGreen.text = "6" self.locoDistGreen.setName("locoDistGreen") # create the speed fields for a Yellow Flash Signal self.locoSpeedYellowFlash = javax.swing.JTextField(sizeSpeedField) # sized to hold 5 characters self.locoSpeedYellowFlash.setToolTipText("Yellow Flash Speed is a number from 1 to 100%") self.locoSpeedYellowFlash.actionPerformed = self.whenSpeedFieldChanged self.locoSpeedYellowFlash.focusLost = self.whenSpeedFieldChanged self.locoSpeedYellowFlash.text = "45" self.locoSpeedYellowFlash.setName("locoSpeedYellowFlash") # create the physical speed field for a Yellow Flash Signal self.locoRateYellowFlash = javax.swing.JTextField(sizeRateField) # sized to hold 5 characters self.locoRateYellowFlash.setToolTipText("Throttle as Distance/Second, approaching yello flash signal") self.locoRateYellowFlash.actionPerformed = self.whenDistanceFieldChanged self.locoRateYellowFlash.focusLost = self.whenDistanceFieldChanged self.locoRateYellowFlash.text = "0" self.locoRateYellowFlash.setName("locoRateYellowFlash") # create the distance field for a Yellow Flash Signal self.locoDistYellowFlash = javax.swing.JTextField(5) # sized to hold 5 characters self.locoDistYellowFlash.setToolTipText("Distance to Yellow Speed from Yellow Flash signal speed, inches") self.locoDistYellowFlash.actionPerformed = self.whenDistanceFieldChanged self.locoDistYellowFlash.focusLost = self.whenDistanceFieldChanged self.locoDistYellowFlash.text = "6" self.locoDistYellowFlash.setName("locoDistYellowFlash") # create the speed fields for a Yellow Signal self.locoSpeedYellow = javax.swing.JTextField(sizeSpeedField) # sized to hold 5 characters self.locoSpeedYellow.setToolTipText("Yellow Speed is a number from 1 to 100%") self.locoSpeedYellow.actionPerformed = self.whenSpeedFieldChanged self.locoSpeedYellow.focusLost = self.whenSpeedFieldChanged self.locoSpeedYellow.text = "30" self.locoSpeedYellow.setName("locoSpeedYellow") # create the physical speed field for a Yellow Signal self.locoRateYellow = javax.swing.JTextField(sizeRateField) # sized to hold 5 characters self.locoRateYellow.setToolTipText("Throttle as Distance/Second, approaching yellow signal") self.locoRateYellow.actionPerformed = self.whenDistanceFieldChanged self.locoRateYellow.focusLost = self.whenDistanceFieldChanged self.locoRateYellow.text = "6" self.locoRateYellow.setName("locoRateYellow") # create the distance field for a Yellow Signal self.locoDistYellow = javax.swing.JTextField(5) # sized to hold 5 characters self.locoDistYellow.setToolTipText("Distance to Red Flash Speed from Yellow signal speed, inches") self.locoDistYellow.actionPerformed = self.whenDistanceFieldChanged self.locoDistYellow.focusLost = self.whenDistanceFieldChanged self.locoDistYellow.text = "6" self.locoDistYellow.setName("locoDistYellow") # create the speed fields for a Red Flash Signal self.locoSpeedRedFlash = javax.swing.JTextField(sizeSpeedField) # sized to hold 5 characters self.locoSpeedRedFlash.setToolTipText("Red Flash Speed is a number from 1 to 100%") self.locoSpeedRedFlash.actionPerformed = self.whenSpeedFieldChanged self.locoSpeedRedFlash.focusLost = self.whenSpeedFieldChanged self.locoSpeedRedFlash.text = "20" self.locoSpeedRedFlash.setName("locoSpeedRedFlash") # create the physical speed field for a Red Flash Signal self.locoRateRedFlash = javax.swing.JTextField(sizeRateField) # sized to hold 5 characters self.locoRateRedFlash.setToolTipText("Throttle as Distance/Second, approaching red flash signal") self.locoRateRedFlash.actionPerformed = self.whenDistanceFieldChanged self.locoRateRedFlash.focusLost = self.whenDistanceFieldChanged self.locoRateRedFlash.text = "0" self.locoRateRedFlash.setName("locoRateRedFlash") # create the distance field for a Red Flash Signal self.locoDistRedFlash = javax.swing.JTextField(5) # sized to hold 5 characters self.locoDistRedFlash.setToolTipText("Distance to Red Speed from Red Flash signal speed, inches") self.locoDistRedFlash.actionPerformed = self.whenDistanceFieldChanged self.locoDistRedFlash.focusLost = self.whenDistanceFieldChanged self.locoDistRedFlash.text = "0" self.locoDistRedFlash.setName("locoDistRedFlash") # create the speed fields for a Red Signal self.locoSpeedRed = javax.swing.JTextField(sizeSpeedField) # sized to hold 5 characters self.locoSpeedRed.setToolTipText("Red Speed is a number from 1 to 100%, creep to Red Signal") self.locoSpeedRed.actionPerformed = self.whenSpeedFieldChanged self.locoSpeedRed.focusLost = self.whenSpeedFieldChanged self.locoSpeedRed.text = "15" self.locoSpeedRed.setName("locoSpeedRed") # create the physical speed field for a Red Signal self.locoRateRed = javax.swing.JTextField(sizeRateField) # sized to hold 5 characters self.locoRateRed.setToolTipText("Throttle as Distance/Second, approaching red signal") self.locoRateRed.actionPerformed = self.whenDistanceFieldChanged self.locoRateRed.focusLost = self.whenDistanceFieldChanged self.locoRateRed.text = "3" self.locoRateRed.setName("locoRateRed") # create the distance field for a Red Signal self.locoDistRed = javax.swing.JTextField(5) # sized to hold 5 characters self.locoDistRed.setToolTipText("Distance to stop from Red signal speed, inches") self.locoDistRed.actionPerformed = self.whenDistanceFieldChanged self.locoDistRed.focusLost = self.whenDistanceFieldChanged self.locoDistRed.text = "10" self.locoDistRed.setName("locoDistRed") # create current speed display self.locoSpeed = javax.swing.JLabel() self.locoSpeed.text = "0" # create the starting block field self.blockStart = javax.swing.JTextField(10) self.blockStart.setToolTipText("Starting Block Name") self.blockStart.actionPerformed = self.whenLocoChanged self.blockStart.focusLost = self.whenLocoChanged self.blockStart.setName("blockStart") # create the starting block direction self.blockDirection = javax.swing.JCheckBox() self.blockDirection.setToolTipText("Starting Block Direction") self.blockDirection.actionPerformed = self.whenBlockDirectionButtonClicked self.blockDirection.focusLost = self.whenBlockDirectionButtonClicked self.blockDirection.setSelected(True) # create flag for looking any extra block ahead self.blockAhead2 = javax.swing.JCheckBox() self.blockAhead2.setSelected(False) self.blockAhead2.setToolTipText("for 4 block mode") # create flag for enable lookahead stopping self.useStopFromDistance = javax.swing.JCheckBox() self.useStopFromDistance.setSelected(False) self.useStopFromDistance.setToolTipText("reduce current signal viewed due to distant stop") # create the stopping block field self.blockStop = javax.swing.JTextField(10) self.blockStop.setToolTipText("Stopping Block Name") self.blockStop.actionPerformed = self.whenStopBlockChanged self.blockStop.focusLost = self.whenStopBlockChanged # create the current block field self.blockNow = javax.swing.JLabel() self.blockNowLength = javax.swing.JLabel() # create the current/next signal field self.signalNext = javax.swing.JLabel() self.signalNextText = javax.swing.JLabel() # create the next block field self.blockNext = javax.swing.JLabel() self.blockNextLength = javax.swing.JLabel() # create the next/beyond signal field self.signalBeyond = javax.swing.JLabel() self.signalBeyondText = javax.swing.JLabel() # create the beyond block field self.blockBeyond = javax.swing.JLabel() self.blockBeyondLength = javax.swing.JLabel() # create the stop distance field self.stopDistance = javax.swing.JLabel() self.stopDistanceForSpeed = javax.swing.JLabel() # load from roster flag self.loadFromRoster = javax.swing.JCheckBox() self.loadFromRoster.setToolTipText("Load settings from roster entry if found.") self.loadFromRoster.setSelected(True) # auto-scroll message window flag self.autoScroll = javax.swing.JCheckBox() self.autoScroll.setToolTipText("Sets message window to auto-scroll") self.autoScroll.setSelected(True) # time stamp message window flag self.scrollTimeStamp = javax.swing.JCheckBox() self.scrollTimeStamp.setToolTipText("Insert time stamp on message window") self.scrollTimeStamp.setSelected(True) # create a text area self.scrollArea = javax.swing.JTextArea(15, 70) # define a text area with it's size if (self.debugLevel >= LowDebug) : self.msgText("Enter the loco number, direction and addr mode") self.msgText("Set min and max speed") self.msgText("Enter block name loco is in") srcollField = javax.swing.JScrollPane(self.scrollArea) # put text area in scroll field # create a frame to hold the buttons and fields # also create a window listener. This is used mainly to remove the property change listener # when the window is closed by clicking on the window close button w = self.WinListener() self.scriptFrame = javax.swing.JFrame("Run Loco") # argument is the frames title self.scriptFrame.contentPane.setLayout(javax.swing.BoxLayout(self.scriptFrame.contentPane, javax.swing.BoxLayout.Y_AXIS)) self.scriptFrame.addWindowListener(w) w.setCallBack(self.scriptFrame, self.releaseAllListeners) # put the text field on a line preceded by a label temppanel1 = javax.swing.JPanel() temppanel1.add(javax.swing.JLabel("Loco Address:")) temppanel1.add(self.locoAddress) temppanel1.add(javax.swing.JLabel(" LongAddr?")) temppanel1.add(self.locoLong) temppanel1.add(javax.swing.JLabel(" Forward?")) temppanel1.add(self.locoForward) temppanel1a = javax.swing.JPanel() temppanel1a.add(javax.swing.JLabel("Headlight:")) temppanel1a.add(self.locoHeadlight) temppanel1a.add(javax.swing.JLabel("Bell:")) temppanel1a.add(self.locoBell) temppanel1a.add(self.locoHorn) temppanel1a.add(self.locoMoveGreen) temppanel1a.add(self.locoMoveYellow) temppanel1a.add(self.locoMoveRed) # build speed table gLayout = java.awt.GridBagLayout() gConstraints = java.awt.GridBagConstraints() self.speedPane = javax.swing.JPanel() pane2Border = javax.swing.BorderFactory.createEtchedBorder() pane2Titled = javax.swing.BorderFactory.createTitledBorder(pane2Border, "Speed Settings") self.speedPane.setBorder(pane2Titled) self.speedPane.setLayout(gLayout) gConstraints.gridx = 0 gConstraints.gridy = 0 gConstraints.gridwidth = 1 gConstraints.gridheight = 1 gConstraints.ipadx = 12 gConstraints.ipady = 3 gConstraints.insets = java.awt.Insets(3, 3, 3, 3) self.speedPane.add(javax.swing.JLabel("locoDistRed"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("Throttle"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel(" "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("Inch/Sec"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("Speed Chg Distance"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel(" "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("Indication"), gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(javax.swing.JLabel("Throttle"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel(" "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("Inch/Sec"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("Speed Chg Distance"), gConstraints) gConstraints.gridx = 0 gConstraints.gridy = gConstraints.gridy + 1 self.speedPane.add(javax.swing.JLabel(self.greenFlashSignalIcon), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoSpeedGreenFlash, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("%"), gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(self.locoRateGreenFlash, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(self.locoDistGreenFlash, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(javax.swing.JLabel(" "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel(self.greenSignalIcon), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoSpeedGreen, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("%"), gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(self.locoRateGreen, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(self.locoDistGreen, gConstraints) gConstraints.gridx = 0 gConstraints.gridy = gConstraints.gridy + 1 self.speedPane.add(javax.swing.JLabel(self.yellowFlashSignalIcon), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoSpeedYellowFlash, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("%"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoRateYellowFlash, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoDistYellowFlash, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(javax.swing.JLabel(" "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel(self.yellowSignalIcon), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoSpeedYellow, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("%"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoRateYellow, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(self.locoDistYellow, gConstraints) gConstraints.gridx = 0 gConstraints.gridy = gConstraints.gridy + 1 self.speedPane.add(javax.swing.JLabel(self.redFlashSignalIcon), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoSpeedRedFlash, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("%"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoRateRedFlash, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoDistRedFlash, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(javax.swing.JLabel(" "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel(self.redSignalIcon), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoSpeedRed, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(javax.swing.JLabel("%"), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.locoRateRed, gConstraints) gConstraints.gridx = gConstraints.gridx+ 1 self.speedPane.add(self.locoDistRed, gConstraints) gConstraints.gridx = 0 gConstraints.gridy = gConstraints.gridy + 1 self.speedPane.add(javax.swing.JLabel("Load From Roster: "), gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.loadFromRoster, gConstraints) gConstraints.gridx = gConstraints.gridx + 1 self.speedPane.add(self.saveToRosterButton, gConstraints) # build block info temppanel3 = javax.swing.JPanel() temppanel3.add(javax.swing.JLabel("Block Starting: ")) temppanel3.add(self.blockStart) temppanel3.add(javax.swing.JLabel(" Eastbound: ")) temppanel3.add(self.blockDirection) temppanel3.add(javax.swing.JLabel(" Check block ahead: ")) temppanel3.add(self.blockAhead2) temppanel3.add(javax.swing.JLabel(" Lookahead for Stop: ")) temppanel3.add(self.useStopFromDistance) temppanel3.add(javax.swing.JLabel(" Stopping Block: ")) temppanel3.add(self.blockStop) temppanel3.add(javax.swing.JLabel(" AutoScroll Messages: ")) temppanel3.add(self.autoScroll) temppanel3.add(javax.swing.JLabel(" Time Stamp Messages: ")) temppanel3.add(self.scrollTimeStamp) temppanel4 = javax.swing.JPanel() temppanel4.add(javax.swing.JLabel("Speed: "), gConstraints) temppanel4.add(self.locoSpeed, gConstraints) temppanel4.add(javax.swing.JLabel("% "), gConstraints) temppanel4.add(javax.swing.JLabel(" Now:")) temppanel4.add(self.blockNow) temppanel4.add(javax.swing.JLabel(" ")) temppanel4.add(self.signalNext) temppanel4.add(self.signalNextText) temppanel4.add(javax.swing.JLabel(" ")) temppanel4.add(self.blockNowLength) temppanel4.add(javax.swing.JLabel("in Next:")) temppanel4.add(self.blockNext) temppanel4.add(javax.swing.JLabel(" ")) temppanel4.add(self.signalBeyond) temppanel4.add(self.signalBeyondText) temppanel4.add(javax.swing.JLabel(" ")) temppanel4.add(self.blockNextLength) temppanel4.add(javax.swing.JLabel("in Beyond:")) temppanel4.add(self.blockBeyond) temppanel4.add(javax.swing.JLabel(" ")) temppanel4.add(self.blockBeyondLength) temppanel4.add(javax.swing.JLabel(" in ")) temppanel4.add(javax.swing.JLabel("Min Stop Dist: ")) temppanel4.add(self.stopDistance) temppanel4.add(javax.swing.JLabel(" : ")) temppanel4.add(self.stopDistanceForSpeed) self.greenFlashSignalIcon.setRotation(1, temppanel4) self.greenSignalIcon.setRotation(1, temppanel4) self.yellowFlashSignalIcon.setRotation(1, temppanel4) self.yellowSignalIcon.setRotation(1, temppanel4) self.redFlashSignalIcon.setRotation(1, temppanel4) self.redSignalIcon.setRotation(1, temppanel4) self.darkSignalIcon.setRotation(1, temppanel4) butPanel = javax.swing.JPanel() butPanel.add(self.startButton) butPanel.add(self.stopButton) butPanel.add(self.testButton) butPanel.add(self.haltButton) butPanel.add(self.shrinkButton) # Put contents in frame and display self.scriptFrame.contentPane.add(temppanel1) self.scriptFrame.contentPane.add(temppanel1a) self.scriptFrame.contentPane.add(self.speedPane) self.scriptFrame.contentPane.add(temppanel3) self.scriptFrame.contentPane.add(temppanel4) self.scriptFrame.contentPane.add(srcollField) self.scriptFrame.contentPane.add(butPanel) self.scriptFrame.pack() self.scriptFrame.show() self.isAborting = False return def setLoco(self, locoId) : self.methodLocoAddress = locoId return def setLocoEast(self) : self.methodBlockDirection = True return def setLocoWest(self) : self.methodBlockDirection = False return def setLocoForward(self) : self.methodLocoForward = True return def setLocoReverse(self) : self.methodLocoForward = False return def locoHeadlightOn(self) : self.methodLocoHeadlight = True return def locoHeadlightOff(self) : self.methodLocoHeadlight = False return def soundShortHorn(self) : self.methodShortHorn = True return def soundLongHorn(self) : self.methodLongHorn = True return def pushShrink(self) : self.methodPushShrink = True return def setStartBlock(self, blockId) : self.methodBlockStart = blockId return def pushStart(self) : self.methodPushStart = True return def pushStop(self) : self.methodPushStop = True return def pushTest(self) : self.methodPushTest = True return def setStopBlock(self, blockId) : self.methodBlockStop = blockId return def setStopDistance(self, dist) : self.methodlocoDistRed = dist return def updateMemoryWithCurrentSpeed(self, memoryId) : mem = jmri.InstanceManager.memoryManagerInstance().provideMemory(memoryId) if (mem != None) : if (self.currentThrottle != None) : mem.setValue(str((int)(round(self.currentThrottle.getSpeedSetting() * 100, 0)))) else : mem.setValue("0") return def returnCurrentSpeed(self) : if (self.currentThrottle != None) : v = str((int)(round(self.currentThrottle.getSpeedSetting() * 100, 0))) else : v = "0" return(v) def updateMemoryWithCurrentBlock(self, memoryId) : mem = jmri.InstanceManager.memoryManagerInstance().provideMemory(memoryId) if (mem != None) : if (self.currentBlock != None) : mem.setValue(self.giveBlockName(self.currentBlock)) else : mem.setValue("") return def returnCurrentBlock(self) : if (self.currentBlock != None) : v = self.giveBlockName(self.currentBlock) else : v = "" return(v) def setDebugNone(self) : self.debugLevel = NoneDebug return() def setDebugLow(self) : self.debugLevel = LowDebug return() def setDebugMedium(self) : self.debugLevel = MediumDebug return() def setDebugHigh(self) : self.debugLevel = HighDebug return() # if you are running the RobotThrottle completely interactive, # the following two lines are all you need rb1 = LocoThrot() rb1.start() #rb1.setSignalAppearanceHalt(GREEN) # However, if you are automating the automation, then ## Options for doing more via scripts or Logix Jython command line option ## this will set the loco number, if a matching roster entry is found, it will load the values ## rb1.setLoco("111") ## rb1.setLocoEast() ## rb1.setLocoWest() ## rb1.locoHeadlightOn() ## rb1.locoHeadlightOff() ## rb1.soundShortHorn() ## rb1.soundLongHorn() ## this will set the starting block ## rb1.setStartBlock("LB25") ## this will enable the loco to move according to the signals ## rb1.pushStart() ## rb1.pushStop() ## this sets a block to stop at ## rb1.setStopBlock("LB27") ## shrink the display size ## rb1.pushShrink() ## turn off all debug messages ## rb1.setDebugNone() ## turn on all debug messages ## rb1.setDebugHigh()