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 classAbstractMRTrafficController.RcvNotifierInternal class to remember the Reply object and destination listener with a reply is received.protected static classAbstractMRTrafficController.XmtNotifierInternal 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 booleanallowUnexpectedReplystatic intAUTORETRYSTATEprotected java.util.Vector<AbstractMRListener>cmdListenersprotected booleanconnectionErrorAbstractPortControllercontrollerprotected booleanflushReceiveCharsstatic intIDLESTATEprotected java.io.DataInputStreamistreamprotected java.util.LinkedList<AbstractMRListener>listenerQueueprotected intmaxRcvExceptionCountprotected intmCurrentModeprotected intmCurrentStateprotected AbstractMRListenermLastSenderprotected java.util.LinkedList<AbstractMRMessage>msgQueueMessages to be transmitted.protected intmWaitBeforePollstatic intNORMALMODEstatic intNOTIFIEDSTATEstatic intOKSENDMSGSTATEprotected java.io.OutputStreamostreamstatic intPOLLSTATEstatic intPROGRAMINGMODEprotected booleanrcvExceptionprotected java.lang.ThreadrcvThreadprotected booleanreplyInDispatchprotected booleanthreadStopRequestFlag that threads should terminate as soon as they can.protected booleantimeoutFlagprotected inttimeoutsstatic intWAITMSGREPLYSTATEstatic intWAITREPLYINNORMMODESTATEstatic intWAITREPLYINPROGMODESTATEprotected longwaitTimePollprotected booleanxmtExceptionprotected java.lang.RunnablexmtRunnableprotected java.lang.ThreadxmtThread
-
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 voidaddConsoleListener(AbstractMRListener l)Add a Listener to start of the Listener list.protected intaddHeaderToOutput(byte[] msg, AbstractMRMessage m)Add header to the outgoing byte stream.protected voidaddListener(AbstractMRListener l)Add a Listener to the Listener list.protected voidaddTrailerToOutput(byte[] msg, int offset, AbstractMRMessage m)Add trailer to the outgoing byte stream.protected booleancanReceive()Override in the system specific code if necessaryprotected voidconnectionWarn()voidconnectPort(AbstractPortController p)Make connection to an existing PortController object.voiddisconnectPort(AbstractPortController p)Break connection to existing PortController object.protected voiddistributeReply(java.lang.Runnable r)Executes a reply distribution action on the appropriate thread for JMRI.protected abstract booleanendOfMessage(AbstractMRReply r)protected abstract AbstractMRMessageenterNormalMode()Sets the system to normal mode during programming while in IDLESTATE.protected abstract AbstractMRMessageenterProgMode()Set the system to programming mode.protected intenterProgModeDelayTime()Get the delay (wait time) after enabling the programming track.protected abstract voidforwardMessage(AbstractMRListener client, AbstractMRMessage m)Implement this to forward a specific message type to a protocol-specific listener interface.protected abstract voidforwardReply(AbstractMRListener client, AbstractMRReply m)protected voidforwardToPort(AbstractMRMessage m, AbstractMRListener reply)Actually transmit the next message to the port.AbstractMRListenergetLastSender()for testing purposes, let us be able to find out what the last sender was.java.lang.StringgetPortName()Get the port name for this connection from the TrafficController.protected booleangetSynchronizeRx()voidhandleOneIncomingReply()Handle each reply when complete.protected voidhandleTimeout(AbstractMRMessage msg, AbstractMRListener l)booleanhasTimeouts()Determine if the interface is down.protected intlengthOfByteStream(AbstractMRMessage m)Determine how many bytes the entire message will take, including space for header and trailer.protected voidloadChars(AbstractMRReply msg, java.io.DataInputStream istream)Get characters from the input source, and file a message.protected AbstractMRTrafficController.RcvNotifiernewRcvNotifier(AbstractMRReply pMsg, AbstractMRListener pDest, AbstractMRTrafficController pTc)protected abstract AbstractMRReplynewReply()protected voidnotifyMessage(AbstractMRMessage m, AbstractMRListener notMe)Forward a Message to registered listeners.protected voidnotifyReply(AbstractMRReply r, AbstractMRListener dest)Forward a "Reply" from layout to registered listeners.protected abstract AbstractMRMessagepollMessage()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 AbstractMRListenerpollReplyHandler()booleanportReadyToSend(AbstractPortController p)Check if PortController object can be sent to.protected voidportWarn(java.lang.Exception e)protected voidportWarnTCP(java.lang.Exception e)protected booleanprogrammerIdle()Check if the programmer is idle.protected bytereadByteProtected(java.io.DataInputStream istream)Read a single byte, protecting against various timeouts, etc.voidreceiveLoop()Handle incoming characters.protected voidrecovery()Disconnect and reset the current PortController.protected voidremoveListener(AbstractMRListener l)Remove a Listener from the Listener list.protected voidreportReceiveLoopException(java.lang.Exception e)Report an error on the receive loop.protected voidresetTimeout(AbstractMRMessage msg)protected voidsendMessage(AbstractMRMessage m, AbstractMRListener reply)Forward message to the port.protected voidsetAllowUnexpectedReply(boolean expected)Set whether the command station may send messages without a request sent to it.protected voidsetSynchronizeRx(boolean val)booleanstatus()protected voidterminate()voidterminateThreads()Terminate the receive and transmit threads.protected voidtransmitLoop()Permanent loop for the transmit thread.protected voidtransmitWait(int waitTime, int state, java.lang.String interruptMessage)protected voidunexpectedReplyStateError(int State, java.lang.String msgString)Log an error message for a message received in an unexpected state.protected voidwaitForStartOfReply(java.io.DataInputStream istream)Dummy routine, to be filled by protocols that have to skip some start-of-message characters.protected voidwarnOnTimeout(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.
-
-