Class AbstractAutomaton
- java.lang.Object
-
- jmri.jmrit.automat.AbstractAutomaton
-
- All Implemented Interfaces:
java.lang.Runnable
- Direct Known Subclasses:
SampleAutomaton
,SampleAutomaton2
,SampleAutomaton3
public class AbstractAutomaton extends java.lang.Object implements java.lang.Runnable
Abstract base for user automaton classes, which provide individual bits of automation.Each individual automaton runs in a separate thread, so they can operate independently. This class handles thread creation and scheduling, and provides a number of services for the user code.
Subclasses provide a "handle()" function, which does the needed work, and optionally a "init()" function. These can use any JMRI resources for input and output. It should not spin on a condition without explicit wait requests; it is more efficient to use the explicit wait services when waiting for some specific condition.
handle() is executed repeatedly until either the Automate object is halted(), or it returns "false". Returning "true" will just cause handle() to be invoked again, so you can cleanly restart the Automaton by returning from multiple points in the function.
Since handle() executes outside the GUI thread, it is important that access to GUI (AWT, Swing) objects be scheduled through the various service routines.
Services are provided by public member functions, described below. They must only be invoked from the init and handle methods, as they must be used in a delayable thread. If invoked from the GUI thread, for example, the program will appear to hang. To help ensure this, a warning will be logged if they are used before the thread starts.
For general use, e.g. in scripts, the most useful functions are:
- Wait for a specific number of milliseconds:
waitMsec(int)
- Wait for a specific sensor to be active:
waitSensorActive(jmri.Sensor)
This is also available in a form that will wait for any of a group of sensors to be active. - Wait for a specific sensor to be inactive:
waitSensorInactive(jmri.Sensor)
This is also available in a form that will wait for any of a group of sensors to be inactive. - Wait for a specific sensor to be in a specific state:
waitSensorState(jmri.Sensor, int)
- Wait for a specific sensor to change:
waitSensorChange(int, jmri.Sensor)
- Wait for a specific signal head to show a specific appearance:
waitSignalHeadState(jmri.SignalHead, int)
- Wait for a specific signal mast to show a specific aspect:
waitSignalMastState(jmri.SignalMast, String)
- Wait for a specific warrant to change run state:
waitWarrantRunState(Warrant, int)
- Wait for a specific warrant to enter or leave a specific block:
waitWarrantBlock(Warrant, String, boolean)
- Wait for a specific warrant to enter the next block or to stop:
waitWarrantBlockChange(Warrant)
- Set a group of turnouts and wait for them to be consistent (actual
position matches desired position):
setTurnouts(jmri.Turnout[], jmri.Turnout[])
- Wait for a group of turnouts to be consistent (actually as set):
waitTurnoutConsistent(jmri.Turnout[])
- Wait for any one of a number of Sensors, Turnouts and/or other objects to
change:
waitChange(jmri.NamedBean[])
- Wait for any one of a number of Sensors, Turnouts and/or other objects to
change, up to a specified time:
waitChange(jmri.NamedBean[], int)
- Obtain a DCC throttle:
getThrottle(int, boolean, int)
- Read a CV from decoder on programming track:
readServiceModeCV(java.lang.String)
- Write a value to a CV in a decoder on the programming track:
writeServiceModeCV(java.lang.String, int)
- Write a value to a CV in a decoder on the main track:
writeOpsModeCV(java.lang.String, int, boolean, int)
Although this is named an "Abstract" class, it's actually concrete so scripts can easily use some of the methods.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description class
AbstractAutomaton.MsgFrame
Internal class to show a Frame
-
Field Summary
Fields Modifier and Type Field Description (package private) javax.swing.JFrame
debugWaitFrame
(package private) java.lang.String
message
(package private) javax.swing.JFrame
messageFrame
protected boolean
promptOnWait
Control optional debugging prompt.(package private) NamedBean[]
waitChangePrecheckBeans
(package private) int[]
waitChangePrecheckStates
(package private) java.util.concurrent.BlockingQueue<java.beans.PropertyChangeEvent>
waitChangeQueue
-
Constructor Summary
Constructors Constructor Description AbstractAutomaton()
AbstractAutomaton(java.lang.String name)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description (package private) void
defaultName()
(package private) void
done()
Part of the internal implementation; not for general use.int
getCount()
Get the number of times the handle routine has executed.java.lang.String
getName()
Get the thread name.DccThrottle
getThrottle(int address, boolean longAddress)
DccThrottle
getThrottle(int address, boolean longAddress, int waitSecs)
Obtains a DCC throttle, including waiting for the command station response.DccThrottle
getThrottle(BasicRosterEntry re)
DccThrottle
getThrottle(BasicRosterEntry re, int waitSecs)
Obtains a DCC throttle, including waiting for the command station response.protected boolean
handle()
User-provided main routine.protected void
init()
User-provided initialization routine.boolean
isRunning()
boolean
isWaiting()
Indicates that object is waiting on a waitSomething call.int
readServiceModeCV(java.lang.String cv)
Read a CV on the service track, including waiting for completion.void
run()
Part of the implementation; not for general use.void
setName(java.lang.String name)
Update the name of this object.void
setTurnouts(Turnout[] closed, Turnout[] thrown)
Convenience function to set a bunch of turnouts and wait until they are all in a consistent statevoid
start()
Start this automat processing.void
stop()
Stop the thread immediately.protected void
wait(int milliseconds)
Part of the internal implementation, not intended for users.void
waitChange(NamedBean[] mInputs)
Wait forever for one of a list of NamedBeans (sensors, signal heads and/or turnouts) to change, or for a specific time to pass.void
waitChange(NamedBean[] mInputs, int maxDelay)
Wait, up to a specified time, for one of a list of NamedBeans (sensors, signal heads and/or turnouts) to change their state.void
waitChangePrecheck(NamedBean[] mInputs)
Wait forever for one of a list of NamedBeans (sensors, signal heads and/or turnouts) to change, or for a specific time to pass.void
waitMsec(int milliseconds)
Wait for a specified time and then return control.void
waitSensorActive(Sensor mSensor)
Wait for a sensor to be active.void
waitSensorActive(Sensor[] mSensors)
Wait for one of a list of sensors to be be active.int
waitSensorChange(int mState, Sensor mSensor)
Wait for a sensor to change state.void
waitSensorChange(Sensor[] mSensors)
Wait for one of an array of sensors to change.void
waitSensorInactive(Sensor mSensor)
Wait for a sensor to be inactive.void
waitSensorInactive(Sensor[] mSensors)
Wait for one of a list of sensors to be be inactive.void
waitSensorState(Sensor[] mSensors, int state)
Wait for one of a list of sensors to be be in a selected state.void
waitSensorState(Sensor mSensor, int state)
Internal service routine to wait for one sensor to be in (or become in) a specific state.void
waitSignalHeadState(SignalHead mSignalHead, int state)
Internal service routine to wait for one SignalHead to be in (or become in) a specific state.void
waitSignalMastState(SignalMast mSignalMast, java.lang.String aspect)
Internal service routine to wait for one signal mast to be showing a specific aspectvoid
waitTurnoutConsistent(Turnout[] mTurnouts)
Wait for a list of turnouts to all be in a consistent statevoid
waitWarrantBlock(Warrant warrant, java.lang.String block, boolean occupied)
Wait for a warrant to enter a named block.java.lang.String
waitWarrantBlockChange(Warrant warrant)
Wait for a warrant to either enter a new block or to stop running.void
waitWarrantRunState(Warrant warrant, int state)
Wait for a warrant to change into or out of running state.boolean
writeOpsModeCV(java.lang.String cv, int value, boolean longAddress, int loco)
Write a CV in ops mode, including waiting for completion.boolean
writeServiceModeCV(java.lang.String cv, int value)
Write a CV on the service track, including waiting for completion.
-
-
-
Field Detail
-
promptOnWait
protected boolean promptOnWait
Control optional debugging prompt. If this is set true, each call to wait() will prompt the user whether to continue.
-
waitChangePrecheckBeans
NamedBean[] waitChangePrecheckBeans
-
waitChangePrecheckStates
int[] waitChangePrecheckStates
-
waitChangeQueue
java.util.concurrent.BlockingQueue<java.beans.PropertyChangeEvent> waitChangeQueue
-
messageFrame
javax.swing.JFrame messageFrame
-
message
java.lang.String message
-
debugWaitFrame
javax.swing.JFrame debugWaitFrame
-
-
Constructor Detail
-
AbstractAutomaton
public AbstractAutomaton()
-
AbstractAutomaton
public AbstractAutomaton(java.lang.String name)
-
-
Method Detail
-
start
public void start()
Start this automat processing.Overrides the superclass method to do local accounting.
-
isRunning
public boolean isRunning()
-
run
public void run()
Part of the implementation; not for general use.This is invoked on currentThread.
- Specified by:
run
in interfacejava.lang.Runnable
-
stop
public void stop()
Stop the thread immediately.Overrides superclass method to handle local accounting.
-
done
void done()
Part of the internal implementation; not for general use.Common internal end-time processing
-
getCount
public int getCount()
Get the number of times the handle routine has executed.Used by classes such as
jmri.jmrit.automat.monitor
to monitor progress.- Returns:
- the number of times
handle()
has been called on this AbstractAutomation
-
getName
public java.lang.String getName()
Get the thread name. Used by classes monitoring this AbstractAutomation, such asjmri.jmrit.automat.monitor
.- Returns:
- the name of this thread
-
setName
public final void setName(java.lang.String name)
Update the name of this object.name is not a bound parameter, so changes are not notified to listeners.
- Parameters:
name
- the new name- See Also:
getName()
-
defaultName
void defaultName()
-
init
protected void init()
User-provided initialization routine.This is called exactly once for each object created. This is where you put all the code that needs to be run when your object starts up: Finding sensors and turnouts, getting a throttle, etc.
-
handle
protected boolean handle()
User-provided main routine.This is run repeatedly until it signals the end by returning false. Many automata are intended to run forever, and will always return true.
- Returns:
- false to terminate the automaton, for example due to an error.
-
waitMsec
public void waitMsec(int milliseconds)
Wait for a specified time and then return control.- Parameters:
milliseconds
- the number of milliseconds to wait
-
isWaiting
public boolean isWaiting()
Indicates that object is waiting on a waitSomething call.Specifically, the wait has progressed far enough that any change to the waited-on-condition will be detected.
- Returns:
- true if waiting; false otherwise
-
wait
protected void wait(int milliseconds)
Part of the internal implementation, not intended for users.This handles exceptions internally, so they needn't clutter up the code. Note that the current implementation doesn't guarantee the time, either high or low.
Because of the way Jython access handles synchronization, this is explicitly synchronized internally.
- Parameters:
milliseconds
- the number of milliseconds to wait
-
waitSensorChange
public int waitSensorChange(int mState, Sensor mSensor)
Wait for a sensor to change state.The current (OK) state of the Sensor is passed to avoid a possible race condition. The new state is returned for a similar reason.
This works by registering a listener, which is likely to run in another thread. That listener then interrupts the automaton's thread, who confirms the change.
- Parameters:
mState
- Current state of the sensormSensor
- Sensor to watch- Returns:
- newly detected Sensor state
-
waitSensorActive
public void waitSensorActive(Sensor mSensor)
Wait for a sensor to be active. (Returns immediately if already active)- Parameters:
mSensor
- Sensor to watch
-
waitSensorInactive
public void waitSensorInactive(Sensor mSensor)
Wait for a sensor to be inactive. (Returns immediately if already inactive)- Parameters:
mSensor
- Sensor to watch
-
waitSensorState
public void waitSensorState(Sensor mSensor, int state)
Internal service routine to wait for one sensor to be in (or become in) a specific state.Used by waitSensorActive and waitSensorInactive
This works by registering a listener, which is likely to run in another thread. That listener then interrupts this thread to confirm the change.
- Parameters:
mSensor
- the sensor to wait forstate
- the expected state
-
waitSensorInactive
public void waitSensorInactive(@Nonnull Sensor[] mSensors)
Wait for one of a list of sensors to be be inactive.- Parameters:
mSensors
- sensors to wait on
-
waitSensorActive
public void waitSensorActive(@Nonnull Sensor[] mSensors)
Wait for one of a list of sensors to be be active.- Parameters:
mSensors
- sensors to wait on
-
waitSensorState
public void waitSensorState(@Nonnull Sensor[] mSensors, int state)
Wait for one of a list of sensors to be be in a selected state.This works by registering a listener, which is likely to run in another thread. That listener then interrupts the automaton's thread, who confirms the change.
- Parameters:
mSensors
- Array of sensors to watchstate
- State to check (static value from jmri.Sensors)
-
waitSignalHeadState
public void waitSignalHeadState(SignalHead mSignalHead, int state)
Internal service routine to wait for one SignalHead to be in (or become in) a specific state.This works by registering a listener, which is likely to run in another thread. That listener then interrupts this thread to confirm the change.
- Parameters:
mSignalHead
- the signal head to wait forstate
- the expected state
-
waitSignalMastState
public void waitSignalMastState(@Nonnull SignalMast mSignalMast, @Nonnull java.lang.String aspect)
Internal service routine to wait for one signal mast to be showing a specific aspectThis works by registering a listener, which is likely to run in another thread. That listener then interrupts this thread to confirm the change.
- Parameters:
mSignalMast
- the mast to wait foraspect
- the expected aspect
-
waitWarrantRunState
public void waitWarrantRunState(@Nonnull Warrant warrant, int state)
Wait for a warrant to change into or out of running state.This works by registering a listener, which is likely to run in another thread. That listener then interrupts the automaton's thread, who confirms the change.
- Parameters:
warrant
- The name of the warrant to watchstate
- State to check (static value from jmri.logix.warrant)
-
waitWarrantBlock
public void waitWarrantBlock(@Nonnull Warrant warrant, @Nonnull java.lang.String block, boolean occupied)
Wait for a warrant to enter a named block.This works by registering a listener, which is likely to run in another thread. That listener then interrupts this thread to confirm the change.
- Parameters:
warrant
- The name of the warrant to watchblock
- block to checkoccupied
- Determines whether to wait for the block to become occupied or unoccupied
-
waitWarrantBlockChange
public java.lang.String waitWarrantBlockChange(@Nonnull Warrant warrant)
Wait for a warrant to either enter a new block or to stop running.This works by registering a listener, which is likely to run in another thread. That listener then interrupts the automaton's thread, who confirms the change.
- Parameters:
warrant
- The name of the warrant to watch- Returns:
- The name of the block that was entered or null if the warrant is no longer running.
-
waitTurnoutConsistent
public void waitTurnoutConsistent(@Nonnull Turnout[] mTurnouts)
Wait for a list of turnouts to all be in a consistent stateThis works by registering a listener, which is likely to run in another thread. That listener then interrupts the automaton's thread, who confirms the change.
- Parameters:
mTurnouts
- list of turnouts to watch
-
setTurnouts
public void setTurnouts(@Nonnull Turnout[] closed, @Nonnull Turnout[] thrown)
Convenience function to set a bunch of turnouts and wait until they are all in a consistent state- Parameters:
closed
- turnouts to set to closed statethrown
- turnouts to set to thrown state
-
waitChange
public void waitChange(@Nonnull NamedBean[] mInputs, int maxDelay)
Wait, up to a specified time, for one of a list of NamedBeans (sensors, signal heads and/or turnouts) to change their state.Registers a listener on each of the NamedBeans listed. The listener is likely to run in another thread. Each fired listener then queues a check to the automaton's thread.
- Parameters:
mInputs
- Array of NamedBeans to watchmaxDelay
- maximum amount of time (milliseconds) to wait before continuing anyway. -1 means forever
-
waitChangePrecheck
public void waitChangePrecheck(NamedBean[] mInputs)
Wait forever for one of a list of NamedBeans (sensors, signal heads and/or turnouts) to change, or for a specific time to pass.- Parameters:
mInputs
- Array of NamedBeans to watch
-
waitChange
public void waitChange(NamedBean[] mInputs)
Wait forever for one of a list of NamedBeans (sensors, signal heads and/or turnouts) to change, or for a specific time to pass.- Parameters:
mInputs
- Array of NamedBeans to watch
-
waitSensorChange
public void waitSensorChange(Sensor[] mSensors)
Wait for one of an array of sensors to change.This is an older method, now superceded by waitChange, which can wait for any NamedBean.
- Parameters:
mSensors
- Array of sensors to watch
-
getThrottle
public DccThrottle getThrottle(int address, boolean longAddress, int waitSecs)
Obtains a DCC throttle, including waiting for the command station response.- Parameters:
address
- Numeric address valuelongAddress
- true if this is a long address, false for a short addresswaitSecs
- number of seconds to wait for throttle to acquire before returning null- Returns:
- A usable throttle, or null if error
-
getThrottle
public DccThrottle getThrottle(int address, boolean longAddress)
-
getThrottle
public DccThrottle getThrottle(BasicRosterEntry re, int waitSecs)
Obtains a DCC throttle, including waiting for the command station response.- Parameters:
re
- specifies the desired locomotivewaitSecs
- number of seconds to wait for throttle to acquire before returning null- Returns:
- A usable throttle, or null if error
-
getThrottle
public DccThrottle getThrottle(BasicRosterEntry re)
-
writeServiceModeCV
public boolean writeServiceModeCV(java.lang.String cv, int value)
Write a CV on the service track, including waiting for completion.- Parameters:
cv
- Number 1 through 512value
- Value 0-255 to be written- Returns:
- true if completed OK
-
readServiceModeCV
public int readServiceModeCV(java.lang.String cv)
Read a CV on the service track, including waiting for completion.- Parameters:
cv
- Number 1 through 512- Returns:
- -1 if error, else value
-
writeOpsModeCV
public boolean writeOpsModeCV(java.lang.String cv, int value, boolean longAddress, int loco)
Write a CV in ops mode, including waiting for completion.- Parameters:
cv
- Number 1 through 512value
- 0-255 value to be writtenloco
- Locomotive decoder addresslongAddress
- true is the locomotive is using a long address- Returns:
- true if completed OK
-
-