Class Block
- All Implemented Interfaces:
Comparable<NamedBean>
,PropertyChangeProvider
,NamedBean
,PhysicalLocationReporter
- Direct Known Subclasses:
OBlock
public class Block extends AbstractNamedBean implements PhysicalLocationReporter
A Block (at least in this implementation) corresponds exactly to the track covered by at most one sensor. That could be generalized in the future.
As trains move around the layout, a set of Block objects that are attached to sensors can interact to keep track of which train is where, going in which direction. As a result of this, the set of Block objects pass around "token" (value) Objects representing the trains. This could be e.g. a Throttle to control the train, or something else.
A block maintains a "direction" flag that is set from the direction of the incoming train. When an arriving train is detected via the connected sensor and the Block's status information is sufficient to determine that it is arriving via a particular Path, that Path's getFromBlockDirection becomes the direction of the train in this Block. This only works
Optionally, a Block can be associated with a Reporter. In this case, the Reporter will provide the Block with the "token" (value). This could be e.g an RFID reader reading an ID tag attached to a locomotive. Depending on the specific Reporter implementation, either the current reported value or the last reported value will be relevant - this can be configured
Objects of this class are Named Beans, so can be manipulated through tables, have listeners, etc.
There is no functional requirement for a type letter in the System Name, but by convention we use 'B' for 'Block'. The default implementation is not system-specific, so a system letter of 'I' is appropriate. This leads to system names like "IB201".
Issues:
- The tracking doesn't handle a train pulling in behind another well:
- When the 2nd train arrives, the Sensor is already active, so the value is unchanged (but the value can only be a single object anyway)
- When the 1st train leaves, the Sensor stays active, so the value remains that of the 1st train
- The assumption is that a train will only go through a set turnout. For example, a train could come into the turnout block from the main even if the turnout is set to the siding. (Ignoring those layouts where this would cause a short; it doesn't do so on all layouts)
- Does not handle closely-following trains where there is only one electrical block per signal. To do this, it probably needs some type of "assume a train doesn't back up" logic. A better solution is to have multiple sensors and Block objects between each signal head.
- If a train reverses in a block and goes back the way it came (e.g. b1 to b2 to b1), the block that's re-entered will get an updated direction, but the direction of this block (b2 in the example) is not updated. In other words, we're not noticing that the train must have reversed to go back out.
Do not assume that a Block object uniquely represents a piece of track. To allow independent development, it must be possible for multiple Block objects to take care of a particular section of track.
Possible state values:
- UNKNOWN - The sensor shows UNKNOWN, so this block doesn't know if it's occupied or not.
- INCONSISTENT - The sensor shows INCONSISTENT, so this block doesn't know if it's occupied or not.
- OCCUPIED - This sensor went active. Note that OCCUPIED will be set even if the logic is unable to figure out which value to take.
- UNOCCUPIED - No content, because the sensor has determined this block is unoccupied.
- UNDETECTED - No sensor configured.
Possible Curvature attributes (optional) User can set the curvature if desired. For use in automatic running of trains, to indicate where slow down is required.
- NONE - No curvature in Block track, or Not entered.
- GRADUAL - Gradual curve - no action by engineer is warranted - full speed OK
- TIGHT - Tight curve in Block track - Train should slow down some
- SEVERE - Severe curve in Block track - Train should slow down a lot
The length of the block may also optionally be entered if desired. This attribute is for use in automatic running of trains. Length should be the actual length of model railroad track in the block. It is always stored here in millimeter units. A length of 0.0 indicates no entry of length by the user.
-
Nested Class Summary
Nested classes/interfaces inherited from interface jmri.NamedBean
NamedBean.BadNameException, NamedBean.BadSystemNameException, NamedBean.BadUserNameException, NamedBean.DisplayOptions, NamedBean.DuplicateSystemNameException
Nested classes/interfaces inherited from interface jmri.PhysicalLocationReporter
PhysicalLocationReporter.Direction
-
Field Summary
Fields Modifier and Type Field Description (package private) ArrayList<NamedBeanHandle<Block>>
blockDenyList
static int
GRADUAL
static int
NONE
static int
OCCUPIED
(package private) ArrayList<Path>
paths
static int
SEVERE
static int
TIGHT
static int
UNDETECTED
static int
UNOCCUPIED
Fields inherited from class jmri.implementation.AbstractNamedBean
listenerRefs, mSystemName, register
Fields inherited from interface jmri.NamedBean
DISPLAY_NAME_FORMAT, INCONSISTENT, PROPERTY_STATE, QUOTED_NAME_FORMAT, UNKNOWN
-
Constructor Summary
-
Method Summary
Modifier and Type Method Description void
addBlockDenyList(String pName)
The block deny list, is used by higher level code, to determine if traffic/trains should be allowed to enter from an attached block, the list only deals with blocks that access should be denied from.void
addBlockDenyList(Block blk)
void
addPath(Path p)
boolean
equals(Object obj)
Note: this has to make choices about identity values (always the same) and operation values (can change as the block works).Path
findFromPath()
Find which path this Block became Active, without actually modifying the state of this block.String
getBeanType()
For instances in the code where we are dealing with just a bean and a message needs to be passed to the user or in a log.String
getBlockSpeed()
int
getCurvature()
List<String>
getDeniedBlocks()
int
getDirection()
PhysicalLocationReporter.Direction
getDirection(String rep)
Parses out a (possibly old) LnReporter-generated report string to extract the direction from within it based on this object's protocol.float
getLengthCm()
float
getLengthIn()
float
getLengthMm()
LocoAddress
getLocoAddress(String rep)
Parse a given string and return the LocoAddress value that is presumed stored within it based on this object's protocol.NamedBeanHandle<Sensor>
getNamedSensor()
List<Path>
getPaths()
Get a copy of the list of Paths.boolean
getPermissiveWorking()
PhysicalLocation
getPhysicalLocation()
Return this Block's physical location, if it exists.PhysicalLocation
getPhysicalLocation(String s)
Return this Block's physical location, if it exists.Reporter
getReporter()
Retrieve the Reporter that is linked to this BlockSensor
getSensor()
float
getSpeedLimit()
int
getState()
Provide generic access to internal state.List<NamedBeanUsageReport>
getUsageReport(NamedBean bean)
Get a list of references for the specified bean.Object
getValue()
void
goingActive()
Handles Block sensor going ACTIVE: this block is now occupied, figure out from who and copy their value.void
goingInactive()
Handles Block sensor going INACTIVE: this block is emptyvoid
goingInconsistent()
void
goingUnknown()
(package private) void
handleReporterChange(PropertyChangeEvent e)
Handle change in Reporter value.(package private) void
handleSensorChange(PropertyChangeEvent e)
Handle change in sensor state.int
hashCode()
boolean
hasPath(Path p)
boolean
isBlockDenied(String deny)
boolean
isBlockDenied(Block deny)
boolean
isReportingCurrent()
Determine if the Block's value is being populated from thecurrent report
or from thelast report
.void
removeBlockDenyList(String blk)
void
removeBlockDenyList(Block blk)
void
removePath(Path p)
(package private) void
resetCandidateEntrancePaths()
void
setAllocated(Boolean boo)
(package private) boolean
setAsEntryBlockIfPossible(Block b)
void
setBlockSpeed(String s)
void
setBlockSpeedName(String s)
void
setCurvature(int c)
void
setDirection(int direction)
void
setLength(float l)
Set length in millimeters.void
setNamedSensor(NamedBeanHandle<Sensor> s)
void
setPermissiveWorking(boolean w)
void
setReporter(Reporter reporter)
Set the Reporter that should provide the data value for this block.void
setReportingCurrent(boolean reportingCurrent)
Define if the Block's value should be populated from thecurrent report
or from thelast report
.boolean
setSensor(String pName)
Set the sensor by name.void
setState(int v)
Provide a general method for updating the report.void
setValue(Object value)
Set the value retained by this Block.String
toDebugString()
void
vetoableChange(PropertyChangeEvent evt)
Methods inherited from class jmri.implementation.AbstractNamedBean
addPropertyChangeListener, addPropertyChangeListener, addPropertyChangeListener, addPropertyChangeListener, compareSystemNameSuffix, describeState, dispose, firePropertyChange, getComment, getDisplayName, getDisplayName, getFullyFormattedDisplayName, getFullyFormattedDisplayName, getListenerRef, getListenerRefs, getNumPropertyChangeListeners, getProperty, getPropertyChangeListeners, getPropertyChangeListeners, getPropertyChangeListenersByReference, getPropertyKeys, getSystemName, getUserName, removeProperty, removePropertyChangeListener, removePropertyChangeListener, setComment, setProperty, setUserName, toString, toStringSuffix, updateListenerRef
-
Field Details
-
OCCUPIED
- See Also:
- Constant Field Values
-
UNOCCUPIED
- See Also:
- Constant Field Values
-
UNDETECTED
- See Also:
- Constant Field Values
-
NONE
- See Also:
- Constant Field Values
-
GRADUAL
- See Also:
- Constant Field Values
-
TIGHT
- See Also:
- Constant Field Values
-
SEVERE
- See Also:
- Constant Field Values
-
paths
-
blockDenyList
-
-
Constructor Details
-
Method Details
-
toDebugString
-
setSensor
Set the sensor by name.- Parameters:
pName
- the name of the Sensor to set- Returns:
- true if a Sensor is set and is not null; false otherwise
-
setNamedSensor
-
getSensor
-
getNamedSensor
-
setReporter
Set the Reporter that should provide the data value for this block.- Parameters:
reporter
- Reporter object to link, or null to clear- See Also:
Reporter
-
getReporter
Retrieve the Reporter that is linked to this Block- Returns:
- linked Reporter object, or null if not linked
- See Also:
Reporter
-
setReportingCurrent
Define if the Block's value should be populated from thecurrent report
or from thelast report
.- Parameters:
reportingCurrent
- true if to use current report; false if to use last report- See Also:
Reporter
-
isReportingCurrent
Determine if the Block's value is being populated from thecurrent report
or from thelast report
.- Returns:
- true if populated by
current report
; false if fromlast report
. - See Also:
Reporter
-
getState
Description copied from interface:NamedBean
Provide generic access to internal state.This generally shouldn't be used by Java code; use the class-specific form instead (e.g. getCommandedState in Turnout). This is provided to make scripts easier to read.
-
addPath
-
removePath
-
hasPath
-
getPaths
Get a copy of the list of Paths.- Returns:
- the paths or an empty list
-
setState
Provide a general method for updating the report. -
setValue
Set the value retained by this Block. Also used when the Block itself gathers a value from an adjacent Block. This can be overridden in a subclass if e.g. you want to keep track of Blocks elsewhere, but make sure you also eventually invoke the super.setValue() here.- Parameters:
value
- The new Object resident in this block, or null if none
-
getValue
-
setDirection
-
getDirection
-
addBlockDenyList
The block deny list, is used by higher level code, to determine if traffic/trains should be allowed to enter from an attached block, the list only deals with blocks that access should be denied from. If we want to prevent traffic from following from this block to another then this block must be added to the deny list of the other block. By default no block is barred, so traffic flow is bi-directional.- Parameters:
pName
- name of the block to add, which must exist
-
addBlockDenyList
-
removeBlockDenyList
-
removeBlockDenyList
-
getDeniedBlocks
-
isBlockDenied
-
isBlockDenied
-
getPermissiveWorking
-
setPermissiveWorking
-
getSpeedLimit
-
getBlockSpeed
-
setBlockSpeedName
-
setBlockSpeed
- Throws:
JmriException
-
setCurvature
-
getCurvature
-
setLength
Set length in millimeters.Paths will inherit this length, if their length is not specifically set. This length is the maximum length of any Path in the block. Path lengths exceeding this will be set to the default length.
- Parameters:
l
- length in millimeters
-
getLengthMm
-
getLengthCm
-
getLengthIn
-
equals
Note: this has to make choices about identity values (always the same) and operation values (can change as the block works). Might be missing some identity values.- Overrides:
equals
in classAbstractNamedBean
- Parameters:
obj
- the reference object with which to compare.- Returns:
true
if this object is the same as the obj argument;false
otherwise.
-
hashCode
Description copied from class:AbstractNamedBean
- Overrides:
hashCode
in classAbstractNamedBean
- Returns:
- hash code value is based on sthe ystem name.
-
resetCandidateEntrancePaths
void resetCandidateEntrancePaths() -
setAsEntryBlockIfPossible
-
handleSensorChange
Handle change in sensor state.Defers real work to goingActive, goingInactive methods.
- Parameters:
e
- the event
-
goingUnknown
-
goingInconsistent
-
handleReporterChange
Handle change in Reporter value.- Parameters:
e
- PropertyChangeEvent
-
goingInactive
Handles Block sensor going INACTIVE: this block is empty -
goingActive
Handles Block sensor going ACTIVE: this block is now occupied, figure out from who and copy their value. -
findFromPath
Find which path this Block became Active, without actually modifying the state of this block.(this is largely a copy of the 'Search' part of the logic from goingActive())
- Returns:
- the next path
-
setAllocated
-
getLocoAddress
Parse a given string and return the LocoAddress value that is presumed stored within it based on this object's protocol. The Class Block implementation defers to its associated Reporter, if it exists.- Specified by:
getLocoAddress
in interfacePhysicalLocationReporter
- Parameters:
rep
- String to be parsed- Returns:
- LocoAddress address parsed from string, or null if this Block isn't associated with a Reporter, or is associated with a Reporter that is not also a PhysicalLocationReporter
-
getDirection
Parses out a (possibly old) LnReporter-generated report string to extract the direction from within it based on this object's protocol. The Class Block implementationd defers to its associated Reporter, if it exists.- Specified by:
getDirection
in interfacePhysicalLocationReporter
- Parameters:
rep
- String to be parsed- Returns:
- PhysicalLocationReporter.Direction direction parsed from string, or null if this Block isn't associated with a Reporter, or is associated with a Reporter that is not also a PhysicalLocationReporter
-
getPhysicalLocation
Return this Block's physical location, if it exists. Defers actual work to the helper methods in class PhysicalLocation- Specified by:
getPhysicalLocation
in interfacePhysicalLocationReporter
- Returns:
- PhysicalLocation : this Block's location.
-
getPhysicalLocation
Return this Block's physical location, if it exists. Does not use the parameter s Defers actual work to the helper methods in class PhysicalLocation- Specified by:
getPhysicalLocation
in interfacePhysicalLocationReporter
- Parameters:
s
- (this parameter is ignored)- Returns:
- PhysicalLocation : this Block's location.
-
vetoableChange
- Specified by:
vetoableChange
in interfaceNamedBean
- Overrides:
vetoableChange
in classAbstractNamedBean
- Throws:
PropertyVetoException
-
getUsageReport
Description copied from interface:NamedBean
Get a list of references for the specified bean.- Specified by:
getUsageReport
in interfaceNamedBean
- Parameters:
bean
- The bean to be checked.- Returns:
- a list of NamedBeanUsageReports or an empty ArrayList.
-
getBeanType
Description copied from interface:NamedBean
For instances in the code where we are dealing with just a bean and a message needs to be passed to the user or in a log.- Specified by:
getBeanType
in interfaceNamedBean
- Returns:
- a string of the bean type, eg Turnout, Sensor etc
-