Class AbstractMRTrafficController
- java.lang.Object
-
- jmri.jmrix.AbstractMRTrafficController
-
- Direct Known Subclasses:
AbstractCanTrafficController
,AbstractMRNodeTrafficController
,Dcc4PcTrafficController
,DCCppTrafficController
,EasyDccTrafficController
,EcosTrafficController
,JMRIClientTrafficController
,MarklinTrafficController
,NceTrafficController
,RfidTrafficController
,SerialTrafficController
,SerialTrafficController
,SRCPTrafficController
,TamsTrafficController
,XNetTrafficController
,Z21TrafficController
public abstract class AbstractMRTrafficController extends java.lang.Object
Abstract base for TrafficControllers in a Message/Reply protocol.Two threads are used for the actual communication. The "Transmit" thread handles pushing characters to the port, and also changing the mode. The "Receive" thread converts characters from the input stream into replies.
The constructor registers a shutdown task to trigger the necessary cleanup code
The internal state machine handles changes of mode, automatic retry of certain messages, time outs, and sending poll messages when otherwise idle.
"Mode" refers to the state of the command station communications. "Normal" and "Programming" are the two modes, used if the command station requires messages to go back and forth between them.
The key methods for the basic operation are:
- If needed for formatting outbound messages,
addHeaderToOutput(byte[], AbstractMRMessage)
andaddTrailerToOutput(byte[], int, AbstractMRMessage)
-
newReply()
creates an empty reply message (of the proper concrete type) to fill with incoming data - The
endOfMessage(AbstractMRReply)
method is used to parse incoming messages. If it needs information on e.g. the last message sent, that can be stored in member variables byforwardToPort(AbstractMRMessage, AbstractMRListener)
. forwardMessage(AbstractMRListener, AbstractMRMessage)
andforwardReply(AbstractMRListener, AbstractMRReply)
handle forwarding of specific types of objects
If your command station requires messages to go in and out of "programming mode", those should be provided by
enterProgMode()
andenterNormalMode()
.If you want to poll for information when the line is otherwise idle, implement
pollMessage()
andpollReplyHandler()
.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description protected static class
AbstractMRTrafficController.RcvNotifier
Internal class to remember the Reply object and destination listener with a reply is received.protected static class
AbstractMRTrafficController.XmtNotifier
Internal class to remember the Message object and destination listener when a message is queued for notification.
-
Field Summary
Fields Modifier and Type Field Description protected boolean
allowUnexpectedReply
static int
AUTORETRYSTATE
protected java.util.Vector<AbstractMRListener>
cmdListeners
protected boolean
connectionError
AbstractPortController
controller
protected boolean
flushReceiveChars
static int
IDLESTATE
protected java.io.DataInputStream
istream
protected java.util.LinkedList<AbstractMRListener>
listenerQueue
protected int
maxRcvExceptionCount
protected int
mCurrentMode
protected int
mCurrentState
protected AbstractMRListener
mLastSender
protected java.util.LinkedList<AbstractMRMessage>
msgQueue
Messages to be transmitted.protected int
mWaitBeforePoll
static int
NORMALMODE
static int
NOTIFIEDSTATE
static int
OKSENDMSGSTATE
protected java.io.OutputStream
ostream
static int
POLLSTATE
static int
PROGRAMINGMODE
protected boolean
rcvException
protected java.lang.Thread
rcvThread
protected boolean
replyInDispatch
protected boolean
threadStopRequest
Flag that threads should terminate as soon as they can.protected boolean
timeoutFlag
protected int
timeouts
static int
WAITMSGREPLYSTATE
static int
WAITREPLYINNORMMODESTATE
static int
WAITREPLYINPROGMODESTATE
protected long
waitTimePoll
protected boolean
xmtException
protected java.lang.Runnable
xmtRunnable
protected java.lang.Thread
xmtThread
-
Constructor Summary
Constructors Constructor Description AbstractMRTrafficController()
Create a new unnamed MRTrafficController.
-
Method Summary
All Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description protected void
addConsoleListener(AbstractMRListener l)
Add a Listener to start of the Listener list.protected int
addHeaderToOutput(byte[] msg, AbstractMRMessage m)
Add header to the outgoing byte stream.protected void
addListener(AbstractMRListener l)
Add a Listener to the Listener list.protected void
addTrailerToOutput(byte[] msg, int offset, AbstractMRMessage m)
Add trailer to the outgoing byte stream.protected boolean
canReceive()
Override in the system specific code if necessaryprotected void
connectionWarn()
void
connectPort(AbstractPortController p)
Make connection to an existing PortController object.void
disconnectPort(AbstractPortController p)
Break connection to existing PortController object.protected void
distributeReply(java.lang.Runnable r)
Executes a reply distribution action on the appropriate thread for JMRI.protected abstract boolean
endOfMessage(AbstractMRReply r)
protected abstract AbstractMRMessage
enterNormalMode()
Sets the system to normal mode during programming while in IDLESTATE.protected abstract AbstractMRMessage
enterProgMode()
Set the system to programming mode.protected int
enterProgModeDelayTime()
Get the delay (wait time) after enabling the programming track.protected abstract void
forwardMessage(AbstractMRListener client, AbstractMRMessage m)
Implement this to forward a specific message type to a protocol-specific listener interface.protected abstract void
forwardReply(AbstractMRListener client, AbstractMRReply m)
protected void
forwardToPort(AbstractMRMessage m, AbstractMRListener reply)
Actually transmit the next message to the port.AbstractMRListener
getLastSender()
for testing purposes, let us be able to find out what the last sender was.java.lang.String
getPortName()
Get the port name for this connection from the TrafficController.protected boolean
getSynchronizeRx()
void
handleOneIncomingReply()
Handle each reply when complete.protected void
handleTimeout(AbstractMRMessage msg, AbstractMRListener l)
boolean
hasTimeouts()
Determine if the interface is down.protected int
lengthOfByteStream(AbstractMRMessage m)
Determine how many bytes the entire message will take, including space for header and trailer.protected void
loadChars(AbstractMRReply msg, java.io.DataInputStream istream)
Get characters from the input source, and file a message.protected AbstractMRTrafficController.RcvNotifier
newRcvNotifier(AbstractMRReply pMsg, AbstractMRListener pDest, AbstractMRTrafficController pTc)
protected abstract AbstractMRReply
newReply()
protected void
notifyMessage(AbstractMRMessage m, AbstractMRListener notMe)
Forward a Message to registered listeners.protected void
notifyReply(AbstractMRReply r, AbstractMRListener dest)
Forward a "Reply" from layout to registered listeners.protected abstract AbstractMRMessage
pollMessage()
Invoked if it's appropriate to do low-priority polling of the command station, this should return the next message to send, or null if the TrafficController should just sleep.protected abstract AbstractMRListener
pollReplyHandler()
boolean
portReadyToSend(AbstractPortController p)
Check if PortController object can be sent to.protected void
portWarn(java.lang.Exception e)
protected void
portWarnTCP(java.lang.Exception e)
protected boolean
programmerIdle()
Check if the programmer is idle.protected byte
readByteProtected(java.io.DataInputStream istream)
Read a single byte, protecting against various timeouts, etc.void
receiveLoop()
Handle incoming characters.protected void
recovery()
Disconnect and reset the current PortController.protected void
removeListener(AbstractMRListener l)
Remove a Listener from the Listener list.protected void
reportReceiveLoopException(java.lang.Exception e)
Report an error on the receive loop.protected void
resetTimeout(AbstractMRMessage msg)
protected void
sendMessage(AbstractMRMessage m, AbstractMRListener reply)
Forward message to the port.protected void
setAllowUnexpectedReply(boolean expected)
Set whether the command station may send messages without a request sent to it.protected void
setSynchronizeRx(boolean val)
boolean
status()
protected void
terminate()
void
terminateThreads()
Terminate the receive and transmit threads.protected void
transmitLoop()
Permanent loop for the transmit thread.protected void
transmitWait(int waitTime, int state, java.lang.String interruptMessage)
protected void
unexpectedReplyStateError(int State, java.lang.String msgString)
Log an error message for a message received in an unexpected state.protected void
waitForStartOfReply(java.io.DataInputStream istream)
Dummy routine, to be filled by protocols that have to skip some start-of-message characters.protected void
warnOnTimeout(AbstractMRMessage msg, AbstractMRListener l)
-
-
-
Field Detail
-
cmdListeners
protected final java.util.Vector<AbstractMRListener> cmdListeners
-
mLastSender
protected AbstractMRListener mLastSender
-
mCurrentMode
protected volatile int mCurrentMode
-
NORMALMODE
public static final int NORMALMODE
- See Also:
- Constant Field Values
-
PROGRAMINGMODE
public static final int PROGRAMINGMODE
- See Also:
- Constant Field Values
-
mCurrentState
protected volatile int mCurrentState
-
IDLESTATE
public static final int IDLESTATE
- See Also:
- Constant Field Values
-
NOTIFIEDSTATE
public static final int NOTIFIEDSTATE
- See Also:
- Constant Field Values
-
WAITMSGREPLYSTATE
public static final int WAITMSGREPLYSTATE
- See Also:
- Constant Field Values
-
WAITREPLYINPROGMODESTATE
public static final int WAITREPLYINPROGMODESTATE
- See Also:
- Constant Field Values
-
WAITREPLYINNORMMODESTATE
public static final int WAITREPLYINNORMMODESTATE
- See Also:
- Constant Field Values
-
OKSENDMSGSTATE
public static final int OKSENDMSGSTATE
- See Also:
- Constant Field Values
-
AUTORETRYSTATE
public static final int AUTORETRYSTATE
- See Also:
- Constant Field Values
-
POLLSTATE
public static final int POLLSTATE
- See Also:
- Constant Field Values
-
allowUnexpectedReply
protected boolean allowUnexpectedReply
-
msgQueue
protected java.util.LinkedList<AbstractMRMessage> msgQueue
Messages to be transmitted.
-
listenerQueue
protected java.util.LinkedList<AbstractMRListener> listenerQueue
-
replyInDispatch
protected boolean replyInDispatch
-
timeoutFlag
protected boolean timeoutFlag
-
timeouts
protected int timeouts
-
flushReceiveChars
protected boolean flushReceiveChars
-
mWaitBeforePoll
protected int mWaitBeforePoll
-
waitTimePoll
protected long waitTimePoll
-
xmtException
protected boolean xmtException
-
connectionError
protected boolean connectionError
-
controller
public AbstractPortController controller
-
xmtThread
protected volatile java.lang.Thread xmtThread
-
rcvThread
protected volatile java.lang.Thread rcvThread
-
xmtRunnable
protected volatile java.lang.Runnable xmtRunnable
-
istream
protected java.io.DataInputStream istream
-
ostream
protected java.io.OutputStream ostream
-
rcvException
protected boolean rcvException
-
maxRcvExceptionCount
protected int maxRcvExceptionCount
-
threadStopRequest
protected volatile boolean threadStopRequest
Flag that threads should terminate as soon as they can.
-
-
Constructor Detail
-
AbstractMRTrafficController
public AbstractMRTrafficController()
Create a new unnamed MRTrafficController.
-
-
Method Detail
-
setSynchronizeRx
protected void setSynchronizeRx(boolean val)
-
getSynchronizeRx
protected boolean getSynchronizeRx()
-
addListener
protected void addListener(AbstractMRListener l)
Add a Listener to the Listener list.- Parameters:
l
- The Listener to be added, not null.
-
addConsoleListener
protected void addConsoleListener(@Nonnull AbstractMRListener l)
Add a Listener to start of the Listener list. Intended for use only by system Consoles which may prefer notification before other objects have processed a Message and sent a Reply.- Parameters:
l
- The Listener to be added, not null.
-
removeListener
protected void removeListener(AbstractMRListener l)
Remove a Listener from the Listener list. The Listener will receive no further notifications.- Parameters:
l
- The Listener to be removed.
-
notifyMessage
protected void notifyMessage(AbstractMRMessage m, AbstractMRListener notMe)
Forward a Message to registered listeners.- Parameters:
m
- Message to be forwarded intactnotMe
- One (optional) listener to be skipped, usually because it's the originating object.
-
forwardMessage
protected abstract void forwardMessage(AbstractMRListener client, AbstractMRMessage m)
Implement this to forward a specific message type to a protocol-specific listener interface. This puts the casting into the concrete class.- Parameters:
client
- abstract listener.m
- message to forward.
-
pollMessage
protected abstract AbstractMRMessage pollMessage()
Invoked if it's appropriate to do low-priority polling of the command station, this should return the next message to send, or null if the TrafficController should just sleep.- Returns:
- Formatted poll message
-
pollReplyHandler
protected abstract AbstractMRListener pollReplyHandler()
-
enterProgMode
protected abstract AbstractMRMessage enterProgMode()
Set the system to programming mode.- Returns:
- any message that needs to be returned to the Command Station to change modes. If no message is needed, returns null.
- See Also:
enterNormalMode()
-
enterNormalMode
protected abstract AbstractMRMessage enterNormalMode()
Sets the system to normal mode during programming while in IDLESTATE. IfprogrammerIdle()
returns true, enterNormalMode() is called after a timeout.- Returns:
- any message that needs to be returned to the Command Station to change modes. If no message is needed, returns null.
- See Also:
enterProgMode()
-
programmerIdle
protected boolean programmerIdle()
Check if the programmer is idle. Override in the system specific code if necessary (see notes forenterNormalMode()
.- Returns:
- true if not busy programming
-
enterProgModeDelayTime
protected int enterProgModeDelayTime()
Get the delay (wait time) after enabling the programming track. Override in subclass to add a longer delay.- Returns:
- 0 as default delay
-
setAllowUnexpectedReply
protected void setAllowUnexpectedReply(boolean expected)
Set whether the command station may send messages without a request sent to it.- Parameters:
expected
- true to allow messages without a prior request
-
notifyReply
protected void notifyReply(AbstractMRReply r, AbstractMRListener dest)
Forward a "Reply" from layout to registered listeners.- Parameters:
r
- Reply to be forwarded intactdest
- One (optional) listener to be skipped, usually because it's the originating object.
-
forwardReply
protected abstract void forwardReply(AbstractMRListener client, AbstractMRReply m)
-
sendMessage
protected void sendMessage(AbstractMRMessage m, AbstractMRListener reply)
Forward message to the port. Messages are queued and then the transmission thread is notified.- Parameters:
m
- the message to sendreply
- the Listener sending the message, often provided as 'this'- See Also:
forwardToPort(AbstractMRMessage, AbstractMRListener)
-
transmitLoop
protected void transmitLoop()
Permanent loop for the transmit thread.
-
transmitWait
protected void transmitWait(int waitTime, int state, java.lang.String interruptMessage)
-
hasTimeouts
public boolean hasTimeouts()
Determine if the interface is down.- Returns:
- timeoutFlag
-
handleTimeout
protected void handleTimeout(AbstractMRMessage msg, AbstractMRListener l)
-
warnOnTimeout
protected void warnOnTimeout(AbstractMRMessage msg, AbstractMRListener l)
-
resetTimeout
protected void resetTimeout(AbstractMRMessage msg)
-
addHeaderToOutput
protected int addHeaderToOutput(byte[] msg, AbstractMRMessage m)
Add header to the outgoing byte stream.- Parameters:
msg
- the output byte streamm
- Message results- Returns:
- next location in the stream to fill
-
addTrailerToOutput
protected void addTrailerToOutput(byte[] msg, int offset, AbstractMRMessage m)
Add trailer to the outgoing byte stream.- Parameters:
msg
- the output byte streamoffset
- the first byte not yet usedm
- output message to extend
-
lengthOfByteStream
protected int lengthOfByteStream(AbstractMRMessage m)
Determine how many bytes the entire message will take, including space for header and trailer.- Parameters:
m
- the message to be sent- Returns:
- number of bytes
-
forwardToPort
protected void forwardToPort(AbstractMRMessage m, AbstractMRListener reply)
Actually transmit the next message to the port.- Parameters:
m
- the message to sendreply
- the Listener sending the message, often provided as 'this'- See Also:
sendMessage(AbstractMRMessage, AbstractMRListener)
-
connectionWarn
protected void connectionWarn()
-
portWarn
protected void portWarn(java.lang.Exception e)
-
portWarnTCP
protected void portWarnTCP(java.lang.Exception e)
-
status
public boolean status()
-
connectPort
public void connectPort(AbstractPortController p)
Make connection to an existing PortController object.- Parameters:
p
- the PortController
-
getPortName
public java.lang.String getPortName()
Get the port name for this connection from the TrafficController.- Returns:
- the name of the port
-
disconnectPort
public void disconnectPort(AbstractPortController p)
Break connection to existing PortController object. Once broken, attempts to send via "message" member will fail.- Parameters:
p
- the PortController
-
portReadyToSend
public boolean portReadyToSend(AbstractPortController p)
Check if PortController object can be sent to.- Parameters:
p
- the PortController- Returns:
- true if ready, false otherwise May throw an Exception.
-
receiveLoop
public void receiveLoop()
Handle incoming characters. This is a permanent loop, looking for input messages in character form on the stream connected to the PortController viaconnectPort(AbstractPortController)
.Each turn of the loop is the receipt of a single message.
-
recovery
protected final void recovery()
Disconnect and reset the current PortController. Invoked at abnormal ending of receiveLoop.
-
reportReceiveLoopException
protected void reportReceiveLoopException(java.lang.Exception e)
Report an error on the receive loop. Separated so tests can suppress, even though message is asynchronous.- Parameters:
e
- Exception encountered at lower level to trigger error, or null
-
newReply
protected abstract AbstractMRReply newReply()
-
endOfMessage
protected abstract boolean endOfMessage(AbstractMRReply r)
-
waitForStartOfReply
protected void waitForStartOfReply(java.io.DataInputStream istream) throws java.io.IOException
Dummy routine, to be filled by protocols that have to skip some start-of-message characters.- Parameters:
istream
- input source- Throws:
java.io.IOException
- from underlying operations
-
readByteProtected
protected byte readByteProtected(java.io.DataInputStream istream) throws java.io.IOException
Read a single byte, protecting against various timeouts, etc.When a port is set to have a receive timeout, some will return zero bytes, an EOFException or a InterruptedIOException at the end of the timeout. In that case, the read() should be repeated to get the next real character.
- Parameters:
istream
- stream to read- Returns:
- the byte read
- Throws:
java.io.IOException
- if unable to read
-
loadChars
protected void loadChars(AbstractMRReply msg, java.io.DataInputStream istream) throws java.io.IOException
Get characters from the input source, and file a message.Returns only when the message is complete.
Only used in the Receive thread.
Handles timeouts on read by ignoring zero-length reads.
- Parameters:
msg
- message to fillistream
- character source.- Throws:
java.io.IOException
- when presented by the input source.
-
canReceive
protected boolean canReceive()
Override in the system specific code if necessary- Returns:
- true if it is okay to buffer receive characters into a reply message. When false, discard char received
-
distributeReply
protected void distributeReply(java.lang.Runnable r)
Executes a reply distribution action on the appropriate thread for JMRI.- Parameters:
r
- a runnable typically encapsulating a MRReply and the iteration code needed to send it to all the listeners.
-
handleOneIncomingReply
public void handleOneIncomingReply() throws java.io.IOException
Handle each reply when complete.(This is public for testing purposes) Runs in the "Receive" thread.
- Throws:
java.io.IOException
- on error.
-
unexpectedReplyStateError
protected void unexpectedReplyStateError(int State, java.lang.String msgString)
Log an error message for a message received in an unexpected state.- Parameters:
State
- message state.msgString
- message string.
-
getLastSender
public AbstractMRListener getLastSender()
for testing purposes, let us be able to find out what the last sender was.- Returns:
- last sender, mLastSender.
-
terminate
protected void terminate()
-
newRcvNotifier
protected AbstractMRTrafficController.RcvNotifier newRcvNotifier(AbstractMRReply pMsg, AbstractMRListener pDest, AbstractMRTrafficController pTc)
-
terminateThreads
public void terminateThreads()
Terminate the receive and transmit threads.This is intended to be used only by testing subclasses.
-
-