Class AbstractTurnout

java.lang.Object
jmri.implementation.AbstractNamedBean
jmri.implementation.AbstractTurnout
All Implemented Interfaces:
PropertyChangeListener, Comparable<NamedBean>, EventListener, PropertyChangeProvider, DigitalIO, NamedBean, Turnout, VariableControlSpanBean
Direct Known Subclasses:
AcelaTurnout, BiDiBTurnout, CbusTurnout, DCCppTurnout, EasyDccTurnout, EcosTurnout, IpocsTurnout, JMRIClientTurnout, LnTurnout, MarklinTurnout, MqttTurnout, MrcTurnout, Mx1Turnout, NceTurnout, OlcbTurnout, RaspberryPiTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SerialTurnout, SprogCSTurnout, SprogTurnout, SRCPTurnout, TamsTurnout, XBeeTurnout, XNetTurnout, XpaTurnout

public abstract class AbstractTurnout extends AbstractNamedBean implements Turnout, PropertyChangeListener
Abstract base for the Turnout interface.

Implements basic feedback modes:

  • NONE feedback, where the KnownState and CommandedState track each other.
  • ONESENSOR feedback where the state of a single sensor specifies THROWN vs CLOSED
  • TWOSENSOR feedback, where one sensor specifies THROWN and another CLOSED.
If you want to implement some other feedback, override and modify setCommandedState() here.

Implements the parameter binding support.

Note that we consider it an error for there to be more than one object that corresponds to a particular physical turnout on the layout.

  • Field Details

  • Constructor Details

  • Method Details

    • getBeanType

      For instances in the code where we are dealing with just a bean and a message needs to be passed to the user or in a log.
      Specified by:
      getBeanType in interface NamedBean
      Returns:
      a string of the bean type, eg Turnout, Sensor etc
    • forwardCommandChangeToLayout

      protected abstract void forwardCommandChangeToLayout(int s)
      Handle a request to change state, typically by sending a message to the layout in some child class. Public version (used by TurnoutOperator) sends the current commanded state without changing it. Implementing classes will typically check the value of s and send a system specific sendMessage command.
      Parameters:
      s - new state value
    • forwardCommandChangeToLayout

      protected void forwardCommandChangeToLayout()
    • stateChangeCheck

      public boolean stateChangeCheck(int newState) throws IllegalArgumentException
      Preprocess a Turnout state change request for forwardCommandChangeToLayout(int) Public access to allow use in tests.
      Parameters:
      newState - the Turnout state command value passed
      Returns:
      true if a Turnout.CLOSED was requested and Turnout is not set to _inverted
      Throws:
      IllegalArgumentException - when needed
    • statesOk

      protected boolean statesOk(int state)
      Look for the case in which the state is neither Closed nor Thrown, which we can't handle. Separate method to allow it to be used in stateChangeCheck(int) and Xpa/MqttTurnout.
      Parameters:
      state - the Turnout state passed
      Returns:
      false if s = Turnout.THROWN, which is what we want
    • newCommandedState

      protected void newCommandedState(int s)
      Set a new Commanded state, if need be notifying the listeners, but do NOT send the command downstream.

      This is used when a new commanded state is noticed from another command.

      Parameters:
      s - new state
    • getKnownState

      public int getKnownState()
      Query the known state. This is a bound parameter, so you can also register a listener to be informed of changes. A result is always returned; if no other feedback method is available, the commanded state will be used.
      Specified by:
      getKnownState in interface DigitalIO
      Returns:
      the known state
    • setCommandedState

      public void setCommandedState(int s)
      Public access to changing turnout state. Sets the commanded state and, if appropriate, starts a TurnoutOperator to do its thing. If there is no TurnoutOperator (not required or nothing suitable) then just tell the layout and hope for the best.
      Specified by:
      setCommandedState in interface DigitalIO
      Parameters:
      s - commanded state to set
    • setCommandedStateAtInterval

      public void setCommandedStateAtInterval(int s)
      Before setting commanded state, if required by manager, apply wait interval until outputIntervalEnds() to put less pressure on the connection.

      Used to insert a delay before calling DigitalIO.setCommandedState(int) to spread out a series of output commands, as in MatrixSignalMast.updateOutputs(char[]) and DefaultRoute class SetRouteThread#run(). Interval value is kept in the Memo per hardware connection. Used in DefaultRoute.setRoute() and MatrixSignalMast.updateOutputs(char[]).

      Specified by:
      setCommandedStateAtInterval in interface Turnout
      Parameters:
      s - turnout state to forward
    • getCommandedState

      public int getCommandedState()
      Query the commanded state. This is a bound parameter, so you can also register a listener to be informed of changes.
      Specified by:
      getCommandedState in interface DigitalIO
      Returns:
      the commanded state
    • newKnownState

      public void newKnownState(int s)
      Add a newKnownState() for use by implementations.

      Use this to update internal information when a state change is detected outside the Turnout object, e.g. via feedback from sensors on the layout.

      If the layout status of the Turnout is observed to change to THROWN or CLOSED, this also sets the commanded state, because it's assumed that somebody somewhere commanded that move. If it's observed to change to UNKNOWN or INCONSISTENT, that's perhaps either an error or a move in progress, and no change is made to the commanded state.

      This implementation sends a command to the layout for the new state if going to THROWN or CLOSED, because there may be others listening to network state.

      This method is not intended for general use, e.g. for users to set the KnownState, so it doesn't appear in the Turnout interface.

      On change, fires Property Change "KnownState".

      Parameters:
      s - New state value
    • isConsistentState

      public boolean isConsistentState()
      Show whether state is one you can safely run trains over.
      Specified by:
      isConsistentState in interface DigitalIO
      Returns:
      true if state is a valid one and the known state is the same as commanded.
    • setKnownStateToCommanded

      The name pretty much says it.

      Triggers all listeners, etc. For use by the TurnoutOperator classes.

    • setState

      public void setState(int s)
      Implement a shorter name for setCommandedState.

      This generally shouldn't be used by Java code; use setCommandedState instead. The is provided to make Jython script access easier to read.

      Note that getState() and setState(int) are not symmetric: getState is the known state, and set state modifies the commanded state.

      Specified by:
      setState in interface NamedBean
      Parameters:
      s - new state
    • getState

      public int getState()
      Implement a shorter name for getKnownState.

      This generally shouldn't be used by Java code; use getKnownState instead. The is provided to make Jython script access easier to read.

      Note that getState() and setState(int) are not symmetric: getState is the known state, and set state modifies the commanded state.

      Specified by:
      getState in interface NamedBean
      Returns:
      current state
    • describeState

      @Nonnull public String describeState(int state)
      Provide human-readable, localized version of state value.

      This method is intended for use when presenting to a human operator.

      Specified by:
      describeState in interface NamedBean
      Overrides:
      describeState in class AbstractNamedBean
      Parameters:
      state - the state to describe
      Returns:
      the state in localized form
    • getNumberControlBits

      public int getNumberControlBits()
      Type of turnout control - defaults to 0 for /'steady state/'
      Specified by:
      getNumberControlBits in interface VariableControlSpanBean
      Returns:
      the number of bits
    • setNumberControlBits

      public void setNumberControlBits(int num)
      Set number of input/output bits this bean controls.
      Specified by:
      setNumberControlBits in interface VariableControlSpanBean
      Parameters:
      num - the size of the input/output, currently 1 or 2
    • getControlType

      public int getControlType()
      Get control type.
      Specified by:
      getControlType in interface Turnout
      Returns:
      0 for steady state or the number of time units the control pulses
    • setControlType

      public void setControlType(int num)
      Set control type.
      Specified by:
      setControlType in interface Turnout
      Parameters:
      num - 0 for steady state or the number of time units the control pulses
    • getValidFeedbackModes

      Get a list of valid feedback types. The valid types depend on the implemented system.
      Specified by:
      getValidFeedbackModes in interface Turnout
      Returns:
      array of feedback types
    • getValidFeedbackTypes

      public int getValidFeedbackTypes()
      Get a representation of the feedback type. This is the OR of possible values: DIRECT, EXACT, etc. The valid combinations depend on the implemented system.
      Specified by:
      getValidFeedbackTypes in interface Turnout
      Returns:
      the ORed combination of feedback types
    • getValidFeedbackNames

      Get a human readable representation of the feedback type. The values depend on the implemented system.
      Specified by:
      getValidFeedbackNames in interface Turnout
      Returns:
      the names of the feedback types or an empty list if no feedback is available
    • setFeedbackMode

      Set the feedback mode from a human readable name. This must be one of the names defined in a previous Turnout.getValidFeedbackNames() call.
      Specified by:
      setFeedbackMode in interface Turnout
      Parameters:
      mode - the feedback type name
      Throws:
      IllegalArgumentException - if mode is not valid
    • setFeedbackMode

      public void setFeedbackMode(int mode) throws IllegalArgumentException
      On change, fires Property Change "feedbackchange". Set the feedback mode from a integer. This must be one of the bit values defined in a previous Turnout.getValidFeedbackTypes() call. Having more than one bit set is an error.
      Specified by:
      setFeedbackMode in interface Turnout
      Parameters:
      mode - the feedback type to set
      Throws:
      IllegalArgumentException - if mode is not valid
    • getFeedbackMode

      public int getFeedbackMode()
      Get the feedback mode in machine readable form. This will be one of the bits defined in a Turnout.getValidFeedbackTypes() call.
      Specified by:
      getFeedbackMode in interface Turnout
      Returns:
      the feedback type
    • getFeedbackModeName

      Get the feedback mode in human readable form. This will be one of the names defined in a Turnout.getValidFeedbackNames() call.
      Specified by:
      getFeedbackModeName in interface Turnout
      Returns:
      the feedback type
    • requestUpdateFromLayout

      public void requestUpdateFromLayout()
      Request an update from the layout soft/hardware. May not even happen, and if it does it will happen later; listen for the result.
      Specified by:
      requestUpdateFromLayout in interface DigitalIO
    • setInverted

      public void setInverted(boolean inverted)
      On change, fires Property Change "inverted". Get turnout inverted. When a turnout is inverted the Turnout.CLOSED and Turnout.THROWN states are reversed on the layout.
      Specified by:
      setInverted in interface Turnout
      Parameters:
      inverted - true if inverted; false otherwise
    • getInverted

      public final boolean getInverted()
      Get the turnout inverted state. If true, commands sent to the layout are reversed. Thrown becomes Closed, and Closed becomes Thrown.

      Used in polling loops in system-specific code, so made final to allow optimization.

      Specified by:
      getInverted in interface Turnout
      Returns:
      inverted status
    • canInvert

      public boolean canInvert()
      Determine if the turnouts can be inverted. If true, inverted turnouts are supported.
      Specified by:
      canInvert in interface Turnout
      Returns:
      invert supported
    • setLocked

      public void setLocked(int turnoutLockout, boolean locked)
      Turnouts that are locked should only respond to JMRI commands to change state. We simulate a locked turnout by monitoring the known state (turnout feedback is required) and if we detect that the known state has changed, negate it by forcing the turnout to return to the commanded state. Turnouts that have local buttons can also be locked if their decoder supports it. On change, fires Property Change "locked".
      Specified by:
      setLocked in interface Turnout
      Parameters:
      turnoutLockout - lockout state to monitor. Possible values Turnout.CABLOCKOUT, Turnout.PUSHBUTTONLOCKOUT. Can be combined to monitor both states.
      locked - true if turnout to be locked
    • getLocked

      public boolean getLocked(int turnoutLockout)
      Determine if turnout is locked. There are two types of locks: cab lockout, and pushbutton lockout.
      Specified by:
      getLocked in interface Turnout
      Parameters:
      turnoutLockout - turnout to check
      Returns:
      locked state, true if turnout is locked
    • getPossibleLockModes

      public int getPossibleLockModes()
      This implementation by itself doesn't provide locking support. Override this in subclasses that do.
      Specified by:
      getPossibleLockModes in interface Turnout
      Returns:
      One of 0 for none
    • canLock

      public boolean canLock(int turnoutLockout)
      This implementation by itself doesn't provide locking support. Override this in subclasses that do.
      Specified by:
      canLock in interface Turnout
      Parameters:
      turnoutLockout - the type of lock, one of CABLOCKOUT, PUSHBUTTONLOCKOUT or BOTH = CABLOCKOUT | PUSHBUTTONLOCKOUT
      Returns:
      false for not supported
    • enableLockOperation

      public void enableLockOperation(int turnoutLockout, boolean enabled)
      Enable turnout lock operators. A turnout can be locked to prevent it being thrown from a cab or push button on the layout if supported by the protocol. Not implemented in AbstractTurnout.
      Specified by:
      enableLockOperation in interface Turnout
      Parameters:
      turnoutLockout - the type of lock
      enabled - true if locking is enabled for the given type; false otherwise
    • setReportLocked

      public void setReportLocked(boolean reportLocked)
      When true, report to console anytime a cab attempts to change the state of a turnout on the layout. When a turnout is cab locked, only JMRI is allowed to change the state of a turnout. On setting changed, fires Property Change "reportlocked".
      Specified by:
      setReportLocked in interface Turnout
      Parameters:
      reportLocked - report locked state
    • getReportLocked

      public boolean getReportLocked()
      When true, report to console anytime a cab attempts to change the state of a turnout on the layout. When a turnout is cab locked, only JMRI is allowed to change the state of a turnout.
      Specified by:
      getReportLocked in interface Turnout
      Returns:
      report locked state
    • getValidDecoderNames

      Get a human readable representation of the decoder types.
      Specified by:
      getValidDecoderNames in interface Turnout
      Returns:
      a list of known stationary decoders that can be specified for locking
    • getDecoderName

      Get a human readable representation of the locking decoder type for this turnout. In AbstractTurnout this String defaults to PushbuttonPacket.unknown , ie "None"
      Specified by:
      getDecoderName in interface Turnout
      Returns:
      the name of the decoder type; null indicates none defined
    • setDecoderName

      public void setDecoderName(String decoderName)
      Set a human readable representation of the locking decoder type for this turnout. On change, fires Property Change "decoderNameChange".
      Specified by:
      setDecoderName in interface Turnout
      Parameters:
      decoderName - the name of the decoder type
    • turnoutPushbuttonLockout

      protected abstract void turnoutPushbuttonLockout(boolean locked)
    • turnoutPushbuttonLockout

      protected void turnoutPushbuttonLockout()
    • getCurrentOperator

    • getTurnoutOperation

      Specified by:
      getTurnoutOperation in interface Turnout
      Returns:
      current operation automation class
    • setTurnoutOperation

      set current automation class Fires Property Change "TurnoutOperationState".
      Specified by:
      setTurnoutOperation in interface Turnout
      Parameters:
      toper - TurnoutOperation subclass instance
    • operationPropertyChange

    • getInhibitOperation

      public boolean getInhibitOperation()
      Get if automatically retrying an operation is blocked for this turnout.
      Specified by:
      getInhibitOperation in interface Turnout
      Returns:
      true if retrying is disabled; false otherwise
    • setInhibitOperation

      public void setInhibitOperation(boolean io)
      Set if automatically retrying an operation is blocked for this turnout.
      Specified by:
      setInhibitOperation in interface Turnout
      Parameters:
      io - true if retrying is to be disabled; false otherwise
    • getTurnoutOperator

      Find the TurnoutOperation class for this turnout, and get an instance of the corresponding operator. Override this function if you want another way to choose the operation.
      Returns:
      newly-instantiated TurnoutOperator, or null if nothing suitable
    • getFeedbackModeForOperation

      protected int getFeedbackModeForOperation()
      Allow an actual turnout class to transform private feedback types into ones that the generic turnout operations know about.
      Returns:
      apparent feedback mode for operation lookup
    • provideFirstFeedbackSensor

      Specified by:
      provideFirstFeedbackSensor in interface Turnout
      Throws:
      JmriException
      IllegalArgumentException
    • provideFirstFeedbackNamedSensor

      On change, fires Property Change "TurnoutFeedbackFirstSensorChange".
      Parameters:
      s - the Handle for First Feedback Sensor
    • getFirstSensor

      Get the first feedback sensor.
      Specified by:
      getFirstSensor in interface Turnout
      Returns:
      the sensor or null if no Sensor set
    • getFirstNamedSensor

      Get the handle for the first feedback sensor.
      Specified by:
      getFirstNamedSensor in interface Turnout
      Returns:
      the sensor handle or null if no Sensor set
    • provideSecondFeedbackSensor

      Specified by:
      provideSecondFeedbackSensor in interface Turnout
      Throws:
      JmriException
      IllegalArgumentException
    • provideSecondFeedbackNamedSensor

      On change, fires Property Change "TurnoutFeedbackSecondSensorChange".
      Parameters:
      s - the Handle for Second Feedback Sensor
    • getSecondSensor

      Get the second feedback sensor.
      Specified by:
      getSecondSensor in interface Turnout
      Returns:
      the sensor or null if no Sensor set
    • getSecondNamedSensor

      Get the second feedback sensor handle.
      Specified by:
      getSecondNamedSensor in interface Turnout
      Returns:
      the sensor handle or null if no Sensor set
    • setInitialKnownStateFromFeedback

      Sets the initial known state (CLOSED,THROWN,UNKNOWN) from feedback information, if appropriate.

      This method is designed to be called only when Turnouts are loaded and when a new Turnout is defined in the Turnout table.

      No change to known state is made if feedback information is not available. If feedback information is inconsistent, or if sensor definition is missing in ONESENSOR and TWOSENSOR feedback, turnout state is set to UNKNOWN.

      Specified by:
      setInitialKnownStateFromFeedback in interface Turnout
    • propertyChange

      React to sensor changes by changing the KnownState if using an appropriate sensor mode.
      Specified by:
      propertyChange in interface PropertyChangeListener
    • sensorPropertyChange

    • leadingTurnoutPropertyChange

    • setBinaryOutput

      public void setBinaryOutput(boolean state)
      Use a binary output for sending commands. This appears to expose a LocoNet-specific feature.
      Specified by:
      setBinaryOutput in interface Turnout
      Parameters:
      state - true if the outputs are binary; false otherwise
    • dispose

      public void dispose()
      Deactivate this object, so that it releases as many resources as possible and no longer effects others.

      For example, if this object has listeners, after a call to this method it should no longer notify those listeners. Any native or system-wide resources it maintains should be released, including threads, files, etc.

      It is an error to invoke any other methods on this object once dispose() has been called. Note, however, that there is no guarantee about behavior in that case.

      Afterwards, references to this object may still exist elsewhere, preventing its garbage collection. But it's formally dead, and shouldn't be keeping any other objects alive. Therefore, this method should null out any references to other objects that this NamedBean contained.

      Specified by:
      dispose in interface NamedBean
      Overrides:
      dispose in class AbstractNamedBean
    • getDivergingLimit

      public float getDivergingLimit()
      Specified by:
      getDivergingLimit in interface Turnout
    • getDivergingSpeed

      Specified by:
      getDivergingSpeed in interface Turnout
    • setDivergingSpeed

      public void setDivergingSpeed(String s) throws JmriException
      On change, fires Property Change "TurnoutDivergingSpeedChange".
      Specified by:
      setDivergingSpeed in interface Turnout
      Throws:
      JmriException
    • getStraightLimit

      public float getStraightLimit()
      Specified by:
      getStraightLimit in interface Turnout
    • getStraightSpeed

      Specified by:
      getStraightSpeed in interface Turnout
    • setStraightSpeed

      public void setStraightSpeed(String s) throws JmriException
      On change, fires Property Change "TurnoutStraightSpeedChange".
      Specified by:
      setStraightSpeed in interface Turnout
      Throws:
      JmriException
    • vetoableChange

      Specified by:
      vetoableChange in interface NamedBean
      Overrides:
      vetoableChange in class AbstractNamedBean
      Throws:
      PropertyVetoException
    • getUsageReport

      Get a list of references for the specified bean.
      Specified by:
      getUsageReport in interface NamedBean
      Parameters:
      bean - The bean to be checked.
      Returns:
      a list of NamedBeanUsageReports or an empty ArrayList.
    • isCanFollow

      public boolean isCanFollow()
      Check if this Turnout can follow the state of another Turnout.
      Specified by:
      isCanFollow in interface Turnout
      Returns:
      true if this Turnout is capable of following; false otherwise
    • getLeadingTurnout

      Get the Turnout this Turnout is following.
      Specified by:
      getLeadingTurnout in interface Turnout
      Returns:
      the leading Turnout or null if none; null if Turnout.isCanFollow() is false
    • setLeadingTurnout

      public void setLeadingTurnout(@CheckForNull Turnout turnout)
      Set the Turnout this Turnout will follow.

      It is valid for two or more turnouts to follow each other in a circular pattern.

      It is recommended that a following turnout's feedback mode be Turnout.DIRECT.

      It is recommended to explicitly call Turnout.setFollowingCommandedState(boolean) after calling this method or to use Turnout.setLeadingTurnout(jmri.Turnout, boolean) to ensure this Turnout follows the leading Turnout in the expected manner.

      Specified by:
      setLeadingTurnout in interface Turnout
      Parameters:
      turnout - the leading Turnout or null if this Turnout should not follow another Turnout; silently ignored if Turnout.isCanFollow() is false
    • setLeadingTurnout

      public void setLeadingTurnout(@CheckForNull Turnout turnout, boolean followingCommandedState)
      Set both the leading Turnout and if the commanded state of the leading Turnout is followed. This is a convenience method for calling both Turnout.setLeadingTurnout(jmri.Turnout) and Turnout.setFollowingCommandedState(boolean).
      Specified by:
      setLeadingTurnout in interface Turnout
      Parameters:
      turnout - the leading Turnout or null if this Turnout should not follow another Turnout; silently ignored if Turnout.isCanFollow() is false
      followingCommandedState - true to have all states match leading turnout; false to only have non-commanded states match
    • isFollowingCommandedState

      public boolean isFollowingCommandedState()
      Check if this Turnout is following all states or only the non-commanded states of the leading Turnout.
      Specified by:
      isFollowingCommandedState in interface Turnout
      Returns:
      true if following all states; false otherwise
    • setFollowingCommandedState

      public void setFollowingCommandedState(boolean following)
      Set if this Turnout follows all states or only the non-commanded states of the leading Turnout.

      A Turnout can be commanded to be Turnout.THROWN or Turnout.CLOSED, but can also have additional states NamedBean.INCONSISTENT and NamedBean.UNKNOWN. There are some use cases where a following Turnout should match all states of the leading Turnout, in which case this should be true, but there are also use cases where the following Turnout should only match the INCONSISTENT and UNKNOWN states of the leading Turnout, but should otherwise be independently commanded, in which case this should be false.

      Specified by:
      setFollowingCommandedState in interface Turnout
      Parameters:
      following - true to have all states match leading turnout; false to only have non-commanded states match