|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectjmri.jmrix.combi.trafficCtrl.CombiTrafficController
public class CombiTrafficController
This class is reponsible for communication with the command station via potentially different adapters such as a serial, parallel etc. For this reason, it is supposed to be adapter-independent and has to be able to handle i/o streams and a callback (perhaps on a different thread), reflecting the appearance of new data.
The only deviation from the above is that the sendCommand
method assumes that data is buffered,
in that it is possible to send a request and wait for a response
rather than receive all that character-by-character. This assumption only applies to short commands and responses, not
to the DCC data.
The main reason to use asynchronous notification when data is
available (via DataAvailable
) is to avoid polling whenever
possible. For a PIC, this is not an issue since there there is nothing for it to do anyway; a PC always has
a lot to do. Usage of a notification makes it possible to block
the receiving worker thread on a wait()
until anything is received or a timeout expires.
The communication protocol between a PC and the station is binary; every sequence of bytes is protected with a checksum. When a sequence is submitted, the station waits for its DCC transmitter to finish, makes the transmitter send the newly-received data and then sends the old one (containing the responses received by the DCC transmitter) back to the PC. This means that after submitting a request, one can only get a response to it a cycle after the one following the transmission of this request. The good thing about this protocol is that it makes it possible to use DCC to the maximum: at 38.4kbs the DCC transmitter can be kept busy all the time. With loco timeouts at 1sec, this make it possible to operate 250 locos simultaneously, as long a 80Amp can be delivered to them.
Objects wishing to send commands to the station
append requests to the queue of requests to be completed and subsequently the worker thread will pick requests
from this queue and send them to the station.
It is not known in advance how long it will take between a submission and completion, but such a
delay is assumed to be unimportant, with all time-critical tasks completed on the station itself. Requests
are processed on the first-come-first-serve basis. The controller does not know what it is sending - only a
sender and a station have a clue as to how to interpret the data being transmitted. When a request is accomplished,
the controller notifies whoever submitted it about it. Requests are never lost: either a success or an error is
always reported. Typically, no object has more than one request in the queue at the same time. This is easy
to accomplish by only submitting a new request if an old one was either cancelled or appendRequest
has thrown an exception.
The fact that there is an overhead related to transmission of a few bytes preceding a stream of data, checksums etc, certain time-critical processing had to be offloaded to the station. This particularly affects acknowledgement processing. Below a sketch is provided as to why oldack has to be done on the station: CV-writing instruction will consume 5 bytes (3.5 ms). From the end of a previous transmission till the following CV-write packet, I'll have to transmit the result of the previous stream (an empty one since for CV-writing empty ones alternate with CV-writing ones) and hence I've got
In general, Java appears to be approximately 100 times faster that the UART transmission
and hence one does not have
to consider delays with Java to affect the above calculations. It is possible to run benchmarks with the
help of the streamMirror
object. This object can be run like an application; it implements
an input and an output stream and mirrors data received on the output, in the input stream.
As long as the controller is instrumented, logs produced
can make it possible to determine the performance.
Every request (implementing the CombiCommand
) interface is supposed to be able to provide
the controller with data to be actually sent to the station and be able to process the data returned from the
station. At present, the length of data submitted and that received have to be identical; this implies that
even commands like idle have to be transmitted to the station and a response to them - back; moreover
toti-receipt commands have to transmit a buffer for a station to fill. Nevertheless, this seems a reasonable
decision because without it, the controller will have to interpret commands in order to determine how much
data to expect back and the station will have to do something in the situation where a response to a command
it is supposed to process does not fit in the space it has left in the buffer.
Requests have to implement three methods,
getLength
of CombiCommand
returns the length of a request; in principle,
it is allowed for it to return 0 to indicate that the request should not be processed, but this should not be relied upon
since getLength
is expected to be called multiple times and it is expected to return the same value. produceMessage
of CombiCommand
fills the controller's buffer with
data to be transmitted. It was decided to operate purely on arrays for performance reasons. Consequently,
a request has to ensure it does not overwrite data from other requests when filling in the buffer. In addition,
it has to ensure the validity of data: the station does not check what it receives. This is to do with the fact that
it is not clear what to do when it discovers that a request is longer than the length of its buffer, because
it could be just that one request which is wrong and the one next to it is fine; unfortunately, finding the next
good request is not possible since just any byte can start a request or be used in one.
It is expected that
produceMessage
can be called multiple times and hence this method should not modify a state of an
object implementing CombiCommand
. Moreover, this method (as well as getLength
) is expected
to complete fast, in order to avoid causing delays in preparation of a sequence of bytes to transmit to the station
and causing the station to wait for data. Waiting will not cause a substantial problem: the station will simply
keep sending preamble bits, but the aim is to ensure that there is always meaningful DCC data being sent out.
parseResponse
of CombiCommand
is called to notify whoever submitted a
request of the outcome. It is supplied with the buffer containing the data returned by the station and the offset
in it containing data of the response to this request. Technically, this is the same offset that was used previously
in the call to produceMessage
. The buffer supplied could be null, which means that the request has
been cancelled. This can happen when a user switched a mode or when an overload was detected. See below about modes
and mode changes.
parseResponse
is the only method which is allowed to modify
a state of CombiCommand
-implementing method. appendRequest
and appendRequestForMode
. The former
is designed for appending requests which should always be appended, such as those for accessories. The latter
command is designed for appending requests which should run as long as the specific mode (specified in the command)
is active. If a mode is not active, the request gets immediately cancelled (this means that parseResponse
serves as a callback of appendRequestForMode
in this situation). appendRequestForMode
is used by loco controllers which periodically append requests and do not care whether these requests gets completed
or not but simply append them once again after a period of time.
It may not be possible to submit a request
or a request may get cancelled; in the former situation, corresponding to a fatal error,
a JmriException
is thrown in response to
an attempt to submit a request. This will always happen if a length of a request is bigger than the length
of the station's buffer. In the latter case, which corresponds to a temporary error,
the request receives the parseResponse
call with the
buffer argument set to null
.
Initialisation of the controller is performed by calling its Init
method. This starts the worker
thread and requests the buffer length from the station. Afterwards, the PowerOff mode is entered. Before the
controller is initialised, it is necessary to call its setStreams
method with the input and output
streams which are to be used by it for communications. The controller implements DataAvailableListener
interface which is used to notify the controller that new data is available for receipt (this is done by calling
the DataAvailable
method). This method can be called at any time and an arbitrary number of times;
in order not to interfere with normal processing, it is made synchronized hence a caller must be prepared to
wait until it can get a lock on the controller. This is likely to be a short while, but since there are many
synchronized methods in the controller, this time cannot be guaranteed.
The controller is responsible for forwarding timeout notifications to its mode objects. The aim is to avoid
the following potential deadlock:
(1) the controller (holding a lock on itself) calls the initialise
method of a mode object
which asks its timeout object to terminate (in the process, aquiring a lock on it);
(2) the timeout object times out and calls the timeout
method of the mode object which
attempts to append a request; during a timeout call by the timeout object, such an object holds a lock
on itself and since appending a request requires a lock on the controller, deadlock ensues.
In the current implementation, mode timeouts call the controller which (in due course) calls mode's timeout
method from the controller's worker thread (holding a lock on the controller). This way, the thread of the timeout object
does not call any synchronized methods of the controller (the method it calls is not synchronized).
The controller has to skip all such notifications when changing a mode because they may come from an old mode
and should not be propagated to the new one.
The controller can operate in a few modes (implementing the CombiMode
interface).
In principle, any number of them is allowed to exist
but only one can be active at a time. While in a particular mode, the controller notifies the mode whether a
request for it was received via the appendRequestForMode
call. This is used to determine
whether any loco-related requests are being submitted. If nothing was submitted after a period of time, a mode
may choose to submit a packet to avoid locos leaving the mode. A mode is not notified when the
appendRequest
method of the controller is called because such a method is not intended for loco
commands but for those which should be completed regardless of the current mode.
A mode change occurs either when requested via the sendMessage
method of the controller
or when an overload or a loss-of-comms is detected. When a mode is changed,
initialise
method. Typically, a mode will submit a number of reset
or idle packets before deciding the mode initialisation is complete and will let the controller know about it
by calling the controller's setMode
method. initialise
and setMode
).There are three main tasks an instance of this class has to fulfill,
Property changes broadcast contain a property name, the old and the new value. Some property change notifications are used purely for "messages", in which case the old value is always null (to ensure notification) and the new one contains the message; others are notifications that a property has changed. The only genuine property change notifications are those with propery names of msg_capChargeTimeout and msg_CommsLost.
At present, msg_Download is set to msg_CombiMode so that both types of messages are displayed in the same way.
Nested Class Summary |
---|
Nested classes/interfaces inherited from interface jmri.jmrix.combi.trafficCtrl.AsynchTrafficController |
---|
AsynchTrafficController.CombiMode |
Field Summary | |
---|---|
protected java.lang.Object |
anObject
An object to receive a notification (if non-null) that a message has been processed or will be used to enter a mode. |
protected boolean |
capChargeTimeout
Stores true if the CDU capacitor is currently discharged, false if it is ok. |
protected jmri.jmrix.combi.trafficCtrl.classModeChangeMode |
combiModeChange
A mode the controller is in while initialising a new mode. |
protected AsynchTrafficController.CombiMode |
combiOpsMode
A possible mode |
protected AsynchTrafficController.CombiMode |
combiPowerOff
A possible mode |
protected AsynchTrafficController.CombiMode |
combiServiceMode
A possible mode |
protected int |
commBufferMaxLength
The maximal length of the RX/TX buffer. |
protected static int |
commBufferMiscLength
The length of miscellaneouts elements in an RX/TX buffer (i.e. 5 bytes for a reset packet, including a preamble (service mode only) + 3 bytes for a current sense 1 byte for the end of a stream, 2 bytes for length and 2 for crc). |
protected java.io.InputStream |
commInputStream
The input stream to be used for communication with a port |
protected java.io.OutputStream |
commOutputStream
The output stream to be used for communication with a port |
protected static byte[][] |
errorMessages
Error messages transmitted upon an abort. |
protected java.lang.Thread |
flashThread
The thread which is responsible to writing the firmware. |
protected boolean |
layoutOverload
Stores true if the layout is experiencing an overload. |
protected int |
maxRequestListLength
The maximal length of request queue. |
protected int |
MessageCommand
Holds commands to the comm processing thread. |
protected int |
minCommBufferLength
The minimal length of the comm buffer to be able to send/receive anything useful. |
protected AsynchTrafficController.CombiMode |
mode
The current mode. |
static java.lang.String |
msg_firmwareFileName
Holds the name of the firmwareFileName property. |
protected static byte[][] |
possibleResponses
Contains possible responses by the command station. |
protected AsynchTrafficController.CombiMode |
previousMode
The current mode. |
protected int |
request_Current
Stores the position of the request which is transferred to the command station on a particular iteration through the main loop of the run() method. |
protected int |
request_First
Stores the position in the request list where the first element is stored. |
protected int |
request_New
Stores the position in the request list where the new request will be stored. |
protected int |
request_Submitted
Stores the position of the request which was previously send to the command station (i.e. on a previous iteration through the main loop of the run() method. |
protected CombiCommand[] |
requestList
This is a list of requests to be processed. |
protected java.lang.Thread |
workerThread
The thread which performs all the work communicating with the station. |
Fields inherited from interface jmri.PowerManager |
---|
OFF, ON, UNKNOWN |
Constructor Summary | |
---|---|
CombiTrafficController()
The constructor - does nothing since initialisation is deferred to the Init method and the worker thread. |
Method Summary | |
---|---|
protected void |
abortRequests()
Aborts all the requests from the request list, between request_Submitted and request_New . |
void |
addPropertyChangeListener(java.beans.PropertyChangeListener l)
Adds a supplied listener to the list of listeners. |
void |
appendRequest(CombiCommand what)
Appends a supplied command to the request list. |
void |
appendRequestForMode(CombiCommand what,
AsynchTrafficController.CombiMode newMode)
Appends a supplied command to the request list expecting a particular mode to be in place (null means `no mode'). |
protected int |
buildTransaction(byte[] buffer,
boolean newmode)
This function populates the list of requests, lists of lengths and the TX buffer. |
static java.lang.StringBuffer |
byteToString(byte[] data)
Converts a sequence of bytes into a string which can be shown to a user, for instance. |
void |
DataAvailable()
This method is called if any data is available for reception from a communications port. |
void |
dispose()
Disposes with this controller. |
void |
firePropertyChange(java.lang.String message,
java.lang.Object oldValue,
java.lang.Object newValue)
Fires a property change notification. |
boolean |
getCapChargeTimeout()
Makes it possible to determine whether cap charge has timed out or not. |
boolean |
getCommsLost()
Provides information as to whether communication with the command station has been lost or not. |
protected int |
getCurrentListLength()
Returns the length of the list of those requests which should be submitted to the command station in the current iteration through the main loop of the run() method. |
java.lang.String |
getFirmwareFileName()
Retrieves the value of the firmwareFileName variable |
AsynchTrafficController.CombiMode |
getMode()
Returns the current mode |
AsynchTrafficController.CombiMode |
getOpsMode()
Returns the mode name of the opreational mode change class |
boolean |
getOverload()
Determines whether the command station has got an overload on its DCC output. |
int |
getPower()
Returns whether power is on or off. |
AsynchTrafficController.CombiMode |
getPowerOffMode()
Returns the mode name of the Power-off mode change class |
protected int |
getRequestListLength()
Returns the length of the list of requests, discounting requests which are null (i.e. have been removed). |
int |
getRxTimeout()
Retrieves the value of the rxTimeout variable. |
AsynchTrafficController.CombiMode |
getServiceMode()
Returns the mode name of the service mode change class |
CombiTrafficStatistics |
getStatistics()
Returns the traffic statistics for this controller. |
int |
getYmRetransmitNumber()
Retrieves the value of the ymRetransmitNumber variable |
void |
Init()
Initialises the traffic controller and retrieves the stream length from the station. |
void |
makeResponse(ProgListener whomToRespond,
int value,
int status)
This is a helper method to respond to anyone who implements the ProgListener interface, via the gui thread. |
int |
match(byte[] whatToMatch)
Matches a single string with data received in a stream. |
protected int |
match(byte[][] exBuffers)
Matches a number of strings with data received in a stream. |
protected int |
moveToHoldingBuffer()
Goes through the list of requests with the aim of picking as many of them as possible as long as the total length of requests picked does not exceed the length of comm buffers. |
protected int |
populateTXBuffer(byte[] buffer)
Fills the transmission buffer with data to be sent out, starting from request_Current and up to (but not including) request_First. |
protected int |
recv(int expectedResponseLength)
This function is responsible for receiving data into the rx buffer and checking that the checksum matches. |
protected int |
recvAscii(int commLength,
java.lang.StringBuffer message)
This function is similar to recv but works on ASCII strings and expects
the length of the response to be supplied as a parameter. |
void |
removePropertyChangeListener(java.beans.PropertyChangeListener l)
Removes a supplied listener from the list of listeners. |
boolean |
removeRequest(CombiCommand what)
Removes a supplied command from the request list. |
protected void |
resetCommandStation()
This method resets the station. |
protected void |
resynchronize(int status)
Re-establishes the synch between the command station and jmri, which gets lost each time there is a comms error. |
void |
run()
Sends data in the request buffer out. |
protected int |
sendBuffer(int bufferLength,
int commLength)
Sends the pending data and waits for a response. |
protected int |
sendBYTES(byte[] data,
int length)
Sends the buffer given to it, out. |
protected int |
sendCommand(byte[] command,
byte[] response)
This method sends a command to the station. |
void |
sendData(java.io.BufferedReader is,
java.lang.String name)
Sends the provided stream of data to the command station. |
void |
sendFile(java.io.File file)
Sends a file provided via YModem to the command station. |
void |
sendMessage(int Message,
java.lang.Object newObject)
In order to send any message, I need to ensure both the sending and the comms thread are not going to modify the same chunk of data at the same time. |
void |
sendPacket(byte[] packet,
int repeats)
Sends DCC packets out as per the CommandStation interface. |
protected boolean |
sendStream(java.io.BufferedReader is,
java.lang.String name)
Sends a stream of data to the command station via YModem. |
protected void |
setCapChargeTimeout(boolean newCapChargeTimeout)
This is the internal setter for the capChargeTimeout variable. |
void |
setFirmwareFileName(java.lang.String newFirmwareFileName)
Assigns a new value to the firmwareFileName variable. |
void |
setMode(AsynchTrafficController.CombiMode newMode)
Assigns a new mode without initialisation and fires property changes. |
protected void |
setOverload(boolean overload)
Sets or clears the overload value. |
void |
setPower(int powerMode)
Sets the power mode. |
void |
setRxTimeout(int newTimeout)
Assigns a new value to the rxTimeout variable. |
void |
setStreams(java.io.InputStream is,
java.io.OutputStream os,
testInterface whomToNotify)
Sets the two comm streams CombiTrafficController is expected to use. |
void |
setYmRetransmitNumber(int retransmitCnt)
Assigns a new value to the ymRetransmitNumber variable. |
protected byte[] |
statusData(int from,
int to)
The following function retrieves the data of the station's response to the STATUS command, resynchronizing on comms errors. |
protected int |
statusResponse(java.lang.StringBuffer response)
This function retrieves the response produced by the STATUS command. |
protected int |
submitData(int reqCurrentLength,
int reqSubmittedLength)
Sends the data in the txBuffer to the command station, resynchronizes if needed and otherwise does parseResponse on all elements of the list submitted. |
void |
timeout()
Called by timout objects to indicate that a timeout should be forwarded to the current mode
object. |
protected void |
txPacket(byte[] buffer,
byte blockNo)
Transmits a packet of data. |
protected boolean |
waitForData()
Waits for data for the specific duration. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
protected int maxRequestListLength
protected final CombiCommand[] requestList
protected static final int commBufferMiscLength
protected int minCommBufferLength
protected int commBufferMaxLength
protected java.io.InputStream commInputStream
protected java.io.OutputStream commOutputStream
protected AsynchTrafficController.CombiMode mode
protected AsynchTrafficController.CombiMode previousMode
protected AsynchTrafficController.CombiMode combiOpsMode
protected AsynchTrafficController.CombiMode combiServiceMode
protected AsynchTrafficController.CombiMode combiPowerOff
protected jmri.jmrix.combi.trafficCtrl.classModeChangeMode combiModeChange
protected int request_New
protected int request_First
protected int request_Current
run()
method.
protected int request_Submitted
run()
method.
protected java.lang.Thread workerThread
protected java.lang.Thread flashThread
protected int MessageCommand
protected java.lang.Object anObject
protected boolean capChargeTimeout
protected boolean layoutOverload
protected static final byte[][] possibleResponses
protected static final byte[][] errorMessages
public static final java.lang.String msg_firmwareFileName
Constructor Detail |
---|
public CombiTrafficController()
Init
method and the worker thread.
Method Detail |
---|
public final CombiTrafficStatistics getStatistics()
public final AsynchTrafficController.CombiMode getMode()
public void setMode(AsynchTrafficController.CombiMode newMode)
sendMessage(cmdCHANGEMODE, newMode)
. This method has to be public in order for it to be
included in the AsynchTrafficController interface. Such an inclusion is needed in order for mode-related
classes to use the interface and hence be testable through a mock implementation of it.
setMode
in interface AsynchTrafficController
newMode
- the mode to switch to.public boolean getCommsLost()
getCommsLost
in interface AsynchTrafficController
public final AsynchTrafficController.CombiMode getServiceMode()
getServiceMode
in interface AsynchTrafficController
public final AsynchTrafficController.CombiMode getOpsMode()
getOpsMode
in interface AsynchTrafficController
public final AsynchTrafficController.CombiMode getPowerOffMode()
getPowerOffMode
in interface AsynchTrafficController
public void setPower(int powerMode) throws JmriException
setPower
in interface PowerManager
powerMode
- either PowerManager.ON
or PowerManager.OFF
.
JmriException
- if either an invalide power mode is specified or the controller is not active.public int getPower()
getPower
in interface PowerManager
PowerManager.ON
if power is on, otherwise PowerManager.OFF
.public void appendRequest(CombiCommand what) throws JmriException
appendRequest
in interface AsynchTrafficController
what
- the command to send in the due course.
JmriException
- if the supplied request can never be completed,
such as when it is longer the the station's buffer. The request is cancelled if
it cannot be completed at the moment (such as when there are already too many
requests outstanding, but it could be completed if attempted later).public void appendRequestForMode(CombiCommand what, AsynchTrafficController.CombiMode newMode) throws JmriException
appendRequestForMode
in interface AsynchTrafficController
what
- the command to send in the due course.newMode
- the mode expected by request what
.
JmriException
- if the supplied request can never be completed,
such as when it is longer the the station's buffer. The request is cancelled if
it cannot be completed at the moment (such as when there are already too many
requests outstanding or the mode is wrong, but it could be completed if attempted later).public boolean removeRequest(CombiCommand what)
removeRequest
in interface AsynchTrafficController
what
- the command to remove from the request list
public void setStreams(java.io.InputStream is, java.io.OutputStream os, testInterface whomToNotify)
setStreams
in interface SetStreams
setStreams
in interface DataAvailableListener
is
- the input stream to useos
- the output stream to usewhomToNotify
- whom to notify instead of doing a wait(rxTimeout)
.public void Init() throws JmriException
If Init does not throw an exception, this means that the processing has successfully started on a separate thread. When completed, the msg_Termination property change will be thrown.
Init
in interface AsynchTrafficController
JmriException
- if an error occurs.public static final java.lang.StringBuffer byteToString(byte[] data)
data
- what to convert.
protected void resynchronize(int status) throws java.lang.InterruptedException
status
- what to re-synchronize from (either sERROR or sTIMEOUT).
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.protected void resetCommandStation() throws java.lang.InterruptedException
resynchronize
.
java.lang.InterruptedException
- if resetting was interrupted.public int match(byte[] whatToMatch) throws java.io.IOException, java.lang.InterruptedException
whatToMatch
- the string to match
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.
java.io.IOException
- if access to a serial port causes IOException
.protected int match(byte[][] exBuffers) throws java.io.IOException, java.lang.InterruptedException
The method calls commInputStream.available() (as per EasyDCC) and then processes that number of bytes. The received number of bytes is held in a buffer, hence we can consider it being received atomically and thus a timeout needs reset not after each byte but after we've gone through the available bytes. The method then does commInputStream.available() and repeats the same.
exBuffers
- the array of strings to match
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.
java.io.IOException
- if access to a serial port causes IOException
.public void DataAvailable()
notify()
here because we are not doing a
wait()
only when sending bytes out (there we do a poll
in the beginning of the
transmission). An extra notify()
will not cause
resynchronise to skip a wait for a timeout because no wait will
be in progress when notify()
runs. Finally, asynchronous notifications are considered to be no
more than advisory when not doing a wait: we use the .available on an input stream when needed.
DataAvailable
in interface DataAvailableListener
protected boolean waitForData() throws java.lang.InterruptedException, java.io.IOException
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.
java.io.IOException
- if access to a serial port causes IOException
.protected int recv(int expectedResponseLength) throws java.io.IOException, java.lang.InterruptedException
expectedResponseLength
- the expected length of the response to
receive. If not 0, this is verified against what the
command station sends, if 0 the number of bytes returned by a
station is trusted (as long as it is not above
commBufferMaxLength)
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.
java.io.IOException
- if access to a serial port causes IOException
.protected int sendBYTES(byte[] data, int length) throws java.io.IOException
data
- what to send out.length
- the length of data in the buffer (we'd like not to allocate a new buffer for each request).
java.io.IOException
- if an I/O error occurrs.protected int moveToHoldingBuffer()
protected int buildTransaction(byte[] buffer, boolean newmode) throws JmriException
buffer
- buffer to be filled with data.newmode
- true if we're processing a mode change.
JmriException
- if the length of the data to be transmitted has unexpectedly changed.protected int populateTXBuffer(byte[] buffer)
buffer
- what to populate from reqList
.
buffer
.protected int sendCommand(byte[] command, byte[] response) throws java.lang.InterruptedException
sendBYTES
in that
it expects every byte to be echoed by the station.
command
- the text of the command to send, ending with \rresponse
- the expected response to the command. This is typically command
with \n appended.
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.protected int sendBuffer(int bufferLength, int commLength) throws java.lang.InterruptedException
bufferLength
- the number of bytes from the txBuffer
to transmit.
This is expected to fit in the command station's buffer.commLength
- the expected length of the response to receive.
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.public void sendMessage(int Message, java.lang.Object newObject)
Message
- the message to send to the controller thread.newObject
- the object which will be used to enter a mode.protected void abortRequests()
request_Submitted
and request_New
.
public boolean getCapChargeTimeout()
getCapChargeTimeout
in interface AsynchTrafficController
protected void setCapChargeTimeout(boolean newCapChargeTimeout)
newCapChargeTimeout
- the new value of the capChargeTimeout variable.public boolean getOverload()
getOverload
in interface AsynchTrafficController
protected void setOverload(boolean overload)
overload
- whether there is an overload or not.protected int submitData(int reqCurrentLength, int reqSubmittedLength) throws JmriException, java.lang.InterruptedException
parseResponse
on all elements of the list submitted.
reqCurrentLength
- the number of data bytes in the txBuffer to submit (+2 bytes will be submitted).reqSubmittedLength
- the number of bytes previously submitted.
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.
JmriException
- if parseResponse
throws it.public void timeout()
mode
object.
timeout
in interface Timeout.HandleTimeout
protected int statusResponse(java.lang.StringBuffer response) throws java.lang.InterruptedException
response
- the response from STATUS.
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.protected byte[] statusData(int from, int to) throws java.lang.InterruptedException
from
- the index of the first byte of response to convert to hex.to
- the index of the last+1 byte of response to convert to hex.
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.protected int getRequestListLength()
protected int getCurrentListLength()
run()
method.
This method does not count null requests, i.e. those which have been removed.
public void run()
mode == modeChange | modechange == true | description. |
Y | Y | a new mode requested while servicing a transition to the new mode. |
Y | N | initialisation of a new mode in progress, past the TXold. |
N | Y | about to do TXold. |
N | N | normal operation |
run
in interface java.lang.Runnable
public void sendPacket(byte[] packet, int repeats)
sendPacket
in interface CommandStation
packet
- data to sendrepeats
- how many times to send the packetpublic void makeResponse(ProgListener whomToRespond, int value, int status)
testIO
method.
makeResponse
in interface ResponseMaker
whomToRespond
- whoever to respond tovalue
- the value to return, -1 has a special meaning in that while ordinary
numbers will be displayed in a dialogue (if at all), -1 will be displayed as a blank.status
- whether whatever we are reporting on was successful or not.public void addPropertyChangeListener(java.beans.PropertyChangeListener l)
addPropertyChangeListener
in interface PowerManager
PowerManager.addPropertyChangeListener(java.beans.PropertyChangeListener)
public void removePropertyChangeListener(java.beans.PropertyChangeListener l)
removePropertyChangeListener
in interface PowerManager
PowerManager.removePropertyChangeListener(java.beans.PropertyChangeListener)
public void firePropertyChange(java.lang.String message, java.lang.Object oldValue, java.lang.Object newValue)
message
- the message to send, such as a property name.oldValue
- the old value of the property.newValue
- the new value of the property.public void dispose()
rxTimeout*5/4
seconds at most.
The traffic controller does not eliminate any listeners, since we'd like to be able to initialise and terminate it at will. Nothing seems wrong even with two threads terminating it at the same time. Nothing seems obviously wrong even with one thread initialising and another one - terminating the controller at the same time.
dispose
in interface PowerManager
protected int recvAscii(int commLength, java.lang.StringBuffer message) throws java.io.IOException, java.lang.InterruptedException
recv
but works on ASCII strings and expects
the length of the response to be supplied as a parameter.
commLength
- the number of bytes (including the 4 bytes of CRC) to receive.message
- the buffer which is to be filled with the mesage.
java.lang.InterruptedException
- if the CombiTrafficController thread was asked to terminate.
java.io.IOException
- if access to a serial port causes IOException
.public void sendFile(java.io.File file) throws JmriException
sendFile
in interface Ymodem
file
- the file to send.
JmriException
- if an error occurrs anywhere. In that case, the transmission
will already be aborted.public void sendData(java.io.BufferedReader is, java.lang.String name) throws JmriException
Firmware download is similar to string-sending but does not synch for sending of every line; it synches per packet. The downloader has to load a file, convert it into binary .hex and send it out.
If it does not throw an exception, this means that the processing has successfully started on a separate thread. When completed, the msg_Termination property change will be thrown. The "new value" of this property will be set to a Boolean if transmission went successfully or the JmriException if it failed. AssertionFailedError is thrown if an assertion is thrown from within the thread (useful for testing). The boolean will be set to true if the station's program memory was modified, false if it was not.
sendData
in interface Ymodem
is
- the stream of data to send.name
- the name of the file to give to this stream. This is important since
the station will ignore any name other than the one which was wired into its firmware.
JmriException
- if something went wrong.protected boolean sendStream(java.io.BufferedReader is, java.lang.String name) throws JmriException
is
- the stream of data to send.name
- the name of the file to give to this stream. This is important
since the station will ignore any name other than the one which
was wired into its firmware.
JmriException
- if a transmission was aborted by the station.protected void txPacket(byte[] buffer, byte blockNo) throws java.io.IOException, JmriException
buffer
- what to transmit, either null (in order to transmit EOT) or of length 128 or 1024.blockNo
- the number of this block.
java.io.IOException
- if an error occurs which requires us to abort a transmission.
JmriException
- if a transmission was aborted by the command station.public int getRxTimeout()
public void setRxTimeout(int newTimeout)
newTimeout
- the new value.public int getYmRetransmitNumber()
public void setYmRetransmitNumber(int retransmitCnt)
retransmitCnt
- the new value.public java.lang.String getFirmwareFileName()
public void setFirmwareFileName(java.lang.String newFirmwareFileName)
newFirmwareFileName
- the new value.
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |