Package: BlockBossLogic

BlockBossLogic

nameinstructionbranchcomplexitylinemethod
BlockBossLogic(String)
M: 0 C: 157
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 38
100%
M: 0 C: 1
100%
addBeanToListIfItExists(List, NamedBeanHandle)
M: 0 C: 8
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
addMessageToHtmlList(StringBuilder, String, String, String)
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
canDeleteSensor(NamedBean, StringBuilder, boolean)
M: 134 C: 0
0%
M: 40 C: 0
0%
M: 21 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%
canDeleteSignalHead(PropertyChangeEvent, NamedBean, StringBuilder, boolean)
M: 72 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
canDeleteTurnout(NamedBean, StringBuilder, boolean)
M: 20 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
defineIO()
M: 0 C: 116
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 21
100%
M: 0 C: 1
100%
deleteSensor(NamedBean)
M: 171 C: 0
0%
M: 40 C: 0
0%
M: 21 C: 0
0%
M: 41 C: 0
0%
M: 1 C: 0
0%
deleteSignalHead(NamedBean)
M: 83 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 20 C: 0
0%
M: 1 C: 0
0%
deleteTurnout(NamedBean)
M: 18 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
doApproach()
M: 26 C: 10
28%
M: 6 C: 2
25%
M: 4 C: 1
20%
M: 3 C: 3
50%
M: 0 C: 1
100%
doFacing()
M: 335 C: 0
0%
M: 108 C: 0
0%
M: 55 C: 0
0%
M: 53 C: 0
0%
M: 1 C: 0
0%
doSingleBlock()
M: 44 C: 93
68%
M: 17 C: 21
55%
M: 12 C: 8
40%
M: 6 C: 23
79%
M: 0 C: 1
100%
doTrailingDiverging()
M: 47 C: 117
71%
M: 19 C: 29
60%
M: 15 C: 10
40%
M: 7 C: 27
79%
M: 0 C: 1
100%
doTrailingMain()
M: 44 C: 117
73%
M: 17 C: 29
63%
M: 13 C: 11
46%
M: 7 C: 26
79%
M: 0 C: 1
100%
entries()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
fasterOf(int, int)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
fastestColor1()
M: 0 C: 58
100%
M: 1 C: 15
94%
M: 1 C: 8
89%
M: 0 C: 14
100%
M: 0 C: 1
100%
fastestColor2()
M: 58 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
getApproachSensor1()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getComment()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getDistantSignal()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getDrivenSignal()
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getDrivenSignalNamedBean()
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
getExisting(SignalHead)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getExisting(String)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getHold()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getLimitSpeed1()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getLimitSpeed2()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getMode()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getRestrictingSpeed1()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getRestrictingSpeed2()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getSensor1()
M: 2 C: 7
78%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
getSensor2()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getSensor3()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getSensor4()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getSensor5()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getStoppedObject(SignalHead)
M: 0 C: 10
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getStoppedObject(String)
M: 0 C: 13
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getTurnout()
M: 2 C: 7
78%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
getUsageReport(NamedBean)
M: 176 C: 109
38%
M: 41 C: 25
38%
M: 29 C: 5
15%
M: 13 C: 23
64%
M: 0 C: 1
100%
getUseFlash()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getWatchedSensor1()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getWatchedSensor1Alt()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getWatchedSensor2()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getWatchedSensor2Alt()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getWatchedSignal1()
M: 2 C: 7
78%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
getWatchedSignal1Alt()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getWatchedSignal2()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getWatchedSignal2Alt()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
lambda$defineIO$0(PropertyChangeEvent)
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
processCanDelete(PropertyChangeEvent, NamedBean)
M: 82 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
processDoDelete(NamedBean)
M: 21 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
retain()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setApproachSensor1(String)
M: 19 C: 20
51%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 3 C: 4
57%
M: 0 C: 1
100%
setComment(String)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setDistantSignal(boolean)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setHold(boolean)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
setLimitSpeed1(boolean)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setLimitSpeed2(boolean)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setMode(int)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setOutput()
M: 38 C: 29
43%
M: 5 C: 6
55%
M: 5 C: 3
38%
M: 7 C: 11
61%
M: 0 C: 1
100%
setRestrictingSpeed1(boolean)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setRestrictingSpeed2(boolean)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setSensor1(String)
M: 27 C: 17
39%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 4 C: 4
50%
M: 0 C: 1
100%
setSensor2(String)
M: 27 C: 17
39%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 4 C: 4
50%
M: 0 C: 1
100%
setSensor3(String)
M: 27 C: 17
39%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 4 C: 4
50%
M: 0 C: 1
100%
setSensor4(String)
M: 27 C: 17
39%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 4 C: 4
50%
M: 0 C: 1
100%
setSensor5(String)
M: 27 C: 17
39%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 4 C: 4
50%
M: 0 C: 1
100%
setTurnout(String)
M: 20 C: 17
46%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 4 C: 4
50%
M: 0 C: 1
100%
setWatchedSensor1(String)
M: 30 C: 17
36%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 5 C: 4
44%
M: 0 C: 1
100%
setWatchedSensor1Alt(String)
M: 30 C: 17
36%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 5 C: 4
44%
M: 0 C: 1
100%
setWatchedSensor2(String)
M: 30 C: 17
36%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 5 C: 4
44%
M: 0 C: 1
100%
setWatchedSensor2Alt(String)
M: 30 C: 17
36%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 5 C: 4
44%
M: 0 C: 1
100%
setWatchedSignal1(String, boolean)
M: 22 C: 26
54%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 4 C: 6
60%
M: 0 C: 1
100%
setWatchedSignal1Alt(String)
M: 22 C: 23
51%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 4 C: 5
56%
M: 0 C: 1
100%
setWatchedSignal2(String)
M: 22 C: 23
51%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 4 C: 5
56%
M: 0 C: 1
100%
setWatchedSignal2Alt(String)
M: 22 C: 23
51%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 4 C: 5
56%
M: 0 C: 1
100%
slowerOf(int, int)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
stopAllAndClear()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
vetoableChange(PropertyChangeEvent)
M: 23 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%

Coverage

1: package jmri.jmrit.blockboss;
2:
3: import java.beans.PropertyChangeEvent;
4: import java.util.*;
5: import javax.annotation.Nonnull;
6:
7: import jmri.InstanceManager;
8: import jmri.NamedBean;
9: import jmri.NamedBeanHandle;
10: import jmri.NamedBeanUsageReport;
11: import jmri.Sensor;
12: import jmri.SignalHead;
13: import jmri.Turnout;
14: import jmri.jmrit.automat.Siglet;
15:
16: /**
17: * Drives the "simple signal" logic for one signal.
18: * <p>
19: * Signals "protect" by telling the engineer about the conditions ahead. The
20: * engineer controls the speed of the train based on what the signals show, and
21: * the signals in turn react to whether the track ahead is occupied, what
22: * signals further down the line show, etc.
23: * <p>
24: * There are four situations that this logic can handle:
25: * <ol>
26: * <li>SINGLEBLOCK - A simple block, without a turnout.
27: * <p>
28: * In this case, there is only a single set of sensors and a single next signal
29: * to protect.
30: * <li>TRAILINGMAIN - This signal is protecting a trailing point turnout, which
31: * can only be passed when the turnout is closed. It can also be used for the
32: * upper head of a two head signal on the facing end of the turnout.
33: * <p>
34: * In this case, the signal is forced red if the specified turnout is THROWN.
35: * When the turnout is CLOSED, there is a single set of sensors and next
36: * signal(s) to protect.
37: * <li>TRAILINGDIVERGING - This signal is protecting a trailing point turnout,
38: * which can only be passed when the turnout is thrown. It can also be used for
39: * the lower head of a two head signal on the facing end of the turnout.
40: * <p>
41: * In this case, the signal is forced red if the specified turnout is CLOSED.
42: * When the turnout is THROWN, there is a single set of sensors and next
43: * signal(s) to protect.
44: * <li>FACING - This single head signal protects a facing point turnout, which
45: * may therefore have two next signals and two sets of next sensors for the
46: * closed and thrown states of the turnout.
47: * <p>
48: * If the turnout is THROWN, one set of sensors and next signal(s) is protected.
49: * If the turnout is CLOSED, another set of sensors and next signal(s) is
50: * protected.
51: * </ol>
52: * <p>
53: * Note that these four possibilities logically require that certain information
54: * be configured consistently; e.g. not specifying a turnout in TRAILINGMAIN
55: * doesn't make any sense. That's not enforced explicitly, but violating it can
56: * result in confusing behavior.
57: *
58: * <p>
59: * The protected sensors should cover the track to the next signal. If any of
60: * the protected sensors show ACTIVE, the signal will be dropped to red.
61: * Normally, the protected sensors cover the occupancy of the track to the next
62: * signal. In this case, the signal will show red to prevent trains from
63: * entering an occupied stretch of track (often called a "block"). But the
64: * actual source of the sensors can be anything useful, for example a
65: * microswitch on a local turnout, etc.
66: * <p>
67: * There are several variants to how a next signal is protected. In the simplest
68: * form, the controlled signal provides a warning to the engineer of what the
69: * signal being protected will show when it becomes visible:
70: * <ul>
71: * <li>If the next signal is red, the engineer needs to be told to slow down;
72: * this signal will be set to yellow.
73: * <li>If the next signal is green, the engineer can proceed at track speed;
74: * this signal will be set to green.
75: * </ul>
76: * If the next signal is yellow, there are two possible variants that can be
77: * configured:
78: * <ul>
79: * <li>For the common "three-aspect" signaling system, an engineer doesn't need
80: * any warning before a yellow signal. In this case, this signal is set to green
81: * when the protected signal is yellow.
82: * <li>For lines where track speed is very fast or braking distances are very
83: * long, it can be useful to give engineers warning that the next signal is
84: * yellow (and the one after that is red) so that slowing the train can start
85: * early. Usually flashing yellow preceeds the yellow signal, and the system is
86: * called "four-aspect" signaling.
87: * </ul>
88: *
89: * <p>
90: * In some cases, you want a signal to show <i>exactly</I> what the next signal
91: * shows, instead of one speed faster. E.g. if the (protected) next signal is
92: * red, this one should be red, instead of yellow. In this case, this signal is
93: * called a "distant signal", as it provides a "distant" view of the protected
94: * signal heads's appearance. Note that when in this mode, this signal still protects
95: * the interveneing track, etc.
96: * <p>
97: * The "hold" unbound parameter can be used to set this logic to show red,
98: * regardless of input. That's intended for use with CTC logic, etc.
99: * <p>
100: * "Approach lit" signaling sets the signal head to dark (off) unless the
101: * specified sensor(s) are ACTIVE. Normally, those sensors are in front of
102: * (before) the signal head. The signal heads then only light when a train is
103: * approaching. This is used to preserve bulbs and batteries (and sometimes to
104: * reduce engineer workload) on prototype railroads, but is uncommon on model
105: * railroads; once the layout owner has gone to the trouble and expense of
106: * installing signals, he usually wants them lit up.
107: * <p>
108: * Two signal heads can be protected. For example, if the next signal has two
109: * heads to control travel onto a main track or siding, then both heads should
110: * be provided here. The <i>faster</i> signal aspect will control the appearance
111: * of this head. For example, if the next signal is showing a green head and a
112: * red head, this signal will be green, because the train will be able to
113: * proceed at track speed when it reaches that next signal (along the track with
114: * the green signal).
115: *
116: * @author Bob Jacobsen Copyright (C) 2003, 2005
117: * @author Dick Bronson 2006 Revisions to add facing point sensors, approach lighting
118: * and check box to limit speed.
119: */
120: public class BlockBossLogic extends Siglet implements java.beans.VetoableChangeListener {
121:
122: public static final int SINGLEBLOCK = 1;
123: public static final int TRAILINGMAIN = 2;
124: public static final int TRAILINGDIVERGING = 3;
125: public static final int FACING = 4;
126: private static final String BEAN_X_NOT_FOUND = "BeanXNotFound";
127: private static final String BEAN_NAME_SIGNAL_HEAD = "BeanNameSignalHead";
128: private static final String BEAN_NAME_SENSOR = "BeanNameSensor";
129:
130: private int mode = 0;
131:
132: /**
133: * Create an object to drive a specific signal head.
134: *
135: * @param name System or user name of the driven signal head, which must exist
136: */
137: public BlockBossLogic(@Nonnull String name) {
138: super(name + Bundle.getMessage("_BlockBossLogic"));
139: java.util.Objects.requireNonNull(name, "BlockBossLogic name cannot be null");
140: this.name = name;
141: log.trace("Create BBL {}", name);
142:
143: jmri.InstanceManager.getDefault(jmri.SignalHeadManager.class).addVetoableChangeListener(this);
144: jmri.InstanceManager.turnoutManagerInstance().addVetoableChangeListener(this);
145: jmri.InstanceManager.sensorManagerInstance().addVetoableChangeListener(this);
146: SignalHead driveHead = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(name);
147:• if (driveHead == null) {
148: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name));
149: throw new IllegalArgumentException("SignalHead \"" + name + "\" does not exist");
150: }
151: driveSignal = nbhm.getNamedBeanHandle(name, driveHead);
152: java.util.Objects.requireNonNull(driveSignal, "driveSignal should not have been null");
153: }
154:
155: /**
156: * The "driven signal" is controlled by this element.
157: *
158: * @return system name of the driven signal head
159: */
160: public @Nonnull String getDrivenSignal() {
161: java.util.Objects.requireNonNull(driveSignal, "driveSignal should not have been null");
162: String retVal = driveSignal.getName();
163: java.util.Objects.requireNonNull(retVal, "driveSignal system name should not have been null");
164: return retVal;
165: }
166:
167: public @Nonnull NamedBeanHandle<SignalHead> getDrivenSignalNamedBean() {
168: java.util.Objects.requireNonNull(driveSignal, "driveSignal should have been null");
169: return driveSignal;
170: }
171:
172: private final jmri.NamedBeanHandleManager nbhm = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class);
173:
174: public void setSensor1(String name) {
175:• if (name == null || name.equals("")) {
176: watchSensor1 = null;
177: return;
178: }
179: try {
180: watchSensor1 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
181: } catch (IllegalArgumentException ex) {
182: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "1", name));
183: }
184: }
185:
186: public void setSensor2(String name) {
187:• if (name == null || name.equals("")) {
188: watchSensor2 = null;
189: return;
190: }
191: try {
192: watchSensor2 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
193: } catch (IllegalArgumentException ex) {
194: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "2", name));
195: }
196: }
197:
198: public void setSensor3(String name) {
199:• if (name == null || name.equals("")) {
200: watchSensor3 = null;
201: return;
202: }
203: try {
204: watchSensor3 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
205: } catch (IllegalArgumentException ex) {
206: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "3", name));
207: }
208: }
209:
210: public void setSensor4(String name) {
211:• if (name == null || name.equals("")) {
212: watchSensor4 = null;
213: return;
214: }
215: try {
216: watchSensor4 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
217: } catch (IllegalArgumentException ex) {
218: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "4", name));
219: }
220: }
221:
222: public void setSensor5(String name) {
223:• if (name == null || name.equals("")) {
224: watchSensor5 = null;
225: return;
226: }
227: try {
228: watchSensor5 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
229: } catch (IllegalArgumentException ex) {
230: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "5", name));
231: }
232: }
233:
234: /**
235: * Get the system name of the sensors 1-5 being monitored.
236: *
237: * @return system name; null if no sensor configured
238: */
239: public String getSensor1() {
240:• if (watchSensor1 == null) {
241: return null;
242: }
243: return watchSensor1.getName();
244: }
245:
246: public String getSensor2() {
247:• if (watchSensor2 == null) {
248: return null;
249: }
250: return watchSensor2.getName();
251: }
252:
253: public String getSensor3() {
254:• if (watchSensor3 == null) {
255: return null;
256: }
257: return watchSensor3.getName();
258: }
259:
260: public String getSensor4() {
261:• if (watchSensor4 == null) {
262: return null;
263: }
264: return watchSensor4.getName();
265: }
266:
267: public String getSensor5() {
268:• if (watchSensor5 == null) {
269: return null;
270: }
271: return watchSensor5.getName();
272: }
273:
274: public void setTurnout(String name) {
275:• if (name == null || name.equals("")) {
276: watchTurnout = null;
277: return;
278: }
279: try {
280: watchTurnout = nbhm.getNamedBeanHandle(name, InstanceManager.turnoutManagerInstance().provideTurnout(name));
281: } catch (IllegalArgumentException ex) {
282: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage("BeanNameTurnout"), name));
283: }
284: }
285:
286: /**
287: * Get the system name of the turnout being monitored.
288: *
289: * @return system name; null if no turnout configured
290: */
291: public String getTurnout() {
292:• if (watchTurnout == null) {
293: return null;
294: }
295: return watchTurnout.getName();
296: }
297:
298: public void setMode(int mode) {
299: this.mode = mode;
300: }
301:
302: public int getMode() {
303: return mode;
304: }
305:
306: private String comment;
307:
308: public void setComment(String comment) {
309: this.comment = comment;
310: }
311:
312: public String getComment() {
313: return this.comment;
314: }
315:
316: public void setWatchedSignal1(String name, boolean useFlash) {
317:• if (name == null || name.equals("")) {
318: watchedSignal1 = null;
319: return;
320: }
321: SignalHead head = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(name);
322:• if (head != null) {
323: watchedSignal1 = nbhm.getNamedBeanHandle(name, head);
324: } else {
325: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name));
326: watchedSignal1 = null;
327: }
328: protectWithFlashing = useFlash;
329: }
330:
331: /**
332: * Get the system name of the signal head being monitored for first route.
333: *
334: * @return system name; null if no primary signal head is configured
335: */
336: public String getWatchedSignal1() {
337:• if (watchedSignal1 == null) {
338: return null;
339: }
340: return watchedSignal1.getName();
341: }
342:
343: public void setWatchedSignal1Alt(String name) {
344:• if (name == null || name.equals("")) {
345: watchedSignal1Alt = null;
346: return;
347: }
348: SignalHead head = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(name);
349:• if (head != null) {
350: watchedSignal1Alt = nbhm.getNamedBeanHandle(name, head);
351: } else {
352: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name));
353: watchedSignal1Alt = null;
354: }
355: }
356:
357: /**
358: * Get the system name of the alternate signal head being monitored for first
359: * route.
360: *
361: * @return system name; null if no signal head is configured
362: */
363: public String getWatchedSignal1Alt() {
364:• if (watchedSignal1Alt == null) {
365: return null;
366: }
367: return watchedSignal1Alt.getName();
368: }
369:
370: public void setWatchedSignal2(String name) {
371:• if (name == null || name.equals("")) {
372: watchedSignal2 = null;
373: return;
374: }
375: SignalHead head = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(name);
376:• if (head != null) {
377: watchedSignal2 = nbhm.getNamedBeanHandle(name, head);
378: } else {
379: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name));
380: watchedSignal2 = null;
381: }
382: }
383:
384: /**
385: * Get the system name of the signal head being monitored for the 2nd route.
386: *
387: * @return system name; null if no signal head is configured
388: */
389: public String getWatchedSignal2() {
390:• if (watchedSignal2 == null) {
391: return null;
392: }
393: return watchedSignal2.getName();
394: }
395:
396: public void setWatchedSignal2Alt(String name) {
397:• if (name == null || name.equals("")) {
398: watchedSignal2Alt = null;
399: return;
400: }
401: SignalHead head = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(name);
402:• if (head != null) {
403: watchedSignal2Alt = nbhm.getNamedBeanHandle(name, head);
404: } else {
405: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name));
406: watchedSignal2Alt = null;
407: }
408: }
409:
410: /**
411: * Get the system name of the secondary signal head being monitored for the
412: * 2nd route.
413: *
414: * @return system name; null if no secondary signal head is configured
415: */
416: public String getWatchedSignal2Alt() {
417:• if (watchedSignal2Alt == null) {
418: return null;
419: }
420: return watchedSignal2Alt.getName();
421: }
422:
423: public void setWatchedSensor1(String name) {
424:• if (name == null || name.equals("")) {
425: watchedSensor1 = null;
426: return;
427: }
428: try {
429: watchedSensor1 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
430: } catch (IllegalArgumentException ex) {
431: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "1", name));
432: watchedSensor1 = null;
433: }
434: }
435:
436: /**
437: * Get the original name of the sensor1 being monitored.
438: *
439: * @return original name; null if no sensor is configured
440: */
441: public String getWatchedSensor1() {
442:• if (watchedSensor1 == null) {
443: return null;
444: }
445: return watchedSensor1.getName();
446: }
447:
448: public void setWatchedSensor1Alt(String name) {
449:• if (name == null || name.equals("")) {
450: watchedSensor1Alt = null;
451: return;
452: }
453: try {
454: watchedSensor1Alt = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
455: } catch (IllegalArgumentException ex) {
456: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "1Alt", name));
457: watchedSensor1Alt = null;
458: }
459: }
460:
461: /**
462: * Get the system name of the sensor1Alt being monitored.
463: *
464: * @return system name; null if no sensor is configured
465: */
466: public String getWatchedSensor1Alt() {
467:• if (watchedSensor1Alt == null) {
468: return null;
469: }
470: return watchedSensor1Alt.getName();
471: }
472:
473: public void setWatchedSensor2(String name) {
474:• if (name == null || name.equals("")) {
475: watchedSensor2 = null;
476: return;
477: }
478: try {
479: watchedSensor2 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
480: } catch (IllegalArgumentException ex) {
481: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "2", name));
482: watchedSensor2 = null;
483: }
484: }
485:
486: /**
487: * Get the system name of the sensor2 being monitored.
488: *
489: * @return system name; null if no sensor is configured
490: */
491: public String getWatchedSensor2() {
492:• if (watchedSensor2 == null) {
493: return null;
494: }
495: return watchedSensor2.getName();
496: }
497:
498: public void setWatchedSensor2Alt(String name) {
499:• if (name == null || name.equals("")) {
500: watchedSensor2Alt = null;
501: return;
502: }
503: try {
504: watchedSensor2Alt = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
505: } catch (IllegalArgumentException ex) {
506: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "2Alt", name));
507: watchedSensor2Alt = null;
508: }
509: }
510:
511: /**
512: * Get the system name of the sensor2Alt being monitored.
513: *
514: * @return system name; null if no sensor is configured
515: */
516: public String getWatchedSensor2Alt() {
517:• if (watchedSensor2Alt == null) {
518: return null;
519: }
520: return watchedSensor2Alt.getName();
521: }
522:
523: public void setLimitSpeed1(boolean d) {
524: limitSpeed1 = d;
525: }
526:
527: public boolean getLimitSpeed1() {
528: return limitSpeed1;
529: }
530:
531: public void setRestrictingSpeed1(boolean d) {
532: restrictingSpeed1 = d;
533: }
534:
535: public boolean getRestrictingSpeed1() {
536: return restrictingSpeed1;
537: }
538:
539: public void setLimitSpeed2(boolean d) {
540: limitSpeed2 = d;
541: }
542:
543: public boolean getLimitSpeed2() {
544: return limitSpeed2;
545: }
546:
547: public void setRestrictingSpeed2(boolean d) {
548: restrictingSpeed2 = d;
549: }
550:
551: public boolean getRestrictingSpeed2() {
552: return restrictingSpeed2;
553: }
554:
555: public boolean getUseFlash() {
556: return protectWithFlashing;
557: }
558:
559: public void setDistantSignal(boolean d) {
560: distantSignal = d;
561: }
562:
563: public boolean getDistantSignal() {
564: return distantSignal;
565: }
566:
567: private boolean mHold = false;
568:
569: /**
570: * Provide the current value of the "hold" parameter.
571: * <p>
572: * If true, the output is forced to a RED "stop" appearance.
573: * This allows CTC and other higher-level functions to control
574: * permission to enter this section of track.
575: *
576: * @return true if this Logic currently is Held
577: */
578: private boolean getHold() {
579: return mHold;
580: }
581:
582: /**
583: * Set the current value of the "hold" parameter.
584: * If true, the output is forced to a RED "stop" appearance.
585: * This allows CTC and other higher-level functions to
586: * control permission to enter this section of track.
587: *
588: * @param m true to set Logic to Held
589: */
590: public void setHold(boolean m) {
591: mHold = m;
592: setOutput(); // to invoke the new state
593: }
594:
595: private final String name;
596:
597: @Nonnull NamedBeanHandle<SignalHead> driveSignal;
598:
599: private NamedBeanHandle<Sensor> watchSensor1 = null;
600: private NamedBeanHandle<Sensor> watchSensor2 = null;
601: private NamedBeanHandle<Sensor> watchSensor3 = null;
602: private NamedBeanHandle<Sensor> watchSensor4 = null;
603: private NamedBeanHandle<Sensor> watchSensor5 = null;
604: private NamedBeanHandle<Turnout> watchTurnout = null;
605: private NamedBeanHandle<SignalHead> watchedSignal1 = null;
606: private NamedBeanHandle<SignalHead> watchedSignal1Alt = null;
607: private NamedBeanHandle<SignalHead> watchedSignal2 = null;
608: private NamedBeanHandle<SignalHead> watchedSignal2Alt = null;
609: private NamedBeanHandle<Sensor> watchedSensor1 = null;
610: private NamedBeanHandle<Sensor> watchedSensor1Alt = null;
611: private NamedBeanHandle<Sensor> watchedSensor2 = null;
612: private NamedBeanHandle<Sensor> watchedSensor2Alt = null;
613: private NamedBeanHandle<Sensor> approachSensor1 = null;
614:
615: private boolean limitSpeed1 = false;
616: private boolean restrictingSpeed1 = false;
617: private boolean limitSpeed2 = false;
618: private boolean restrictingSpeed2 = false;
619: private boolean protectWithFlashing = false;
620: private boolean distantSignal = false;
621:
622: public void setApproachSensor1(String name) {
623:• if (name == null || name.equals("")) {
624: approachSensor1 = null;
625: return;
626: }
627: approachSensor1 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name));
628:• if (approachSensor1.getBean() == null) {
629: log.warn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage("Approach_Sensor1_"), name));
630: }
631: }
632:
633: /**
634: * Get the system name of the sensor being monitored.
635: *
636: * @return system name; null if no sensor configured
637: */
638: public String getApproachSensor1() {
639:• if (approachSensor1 == null) {
640: return null;
641: }
642: return approachSensor1.getName();
643: }
644:
645: /**
646: * Define the siglet's input and output.
647: */
648: @Override
649: public void defineIO() {
650: List<NamedBean> namedBeanList = new ArrayList<>();
651:
652: addBeanToListIfItExists(namedBeanList,watchTurnout);
653: addBeanToListIfItExists(namedBeanList,watchSensor1);
654: addBeanToListIfItExists(namedBeanList,watchSensor2);
655: addBeanToListIfItExists(namedBeanList,watchSensor3);
656: addBeanToListIfItExists(namedBeanList,watchSensor4);
657: addBeanToListIfItExists(namedBeanList,watchSensor5);
658: addBeanToListIfItExists(namedBeanList,watchedSignal1);
659: addBeanToListIfItExists(namedBeanList,watchedSignal1Alt);
660: addBeanToListIfItExists(namedBeanList,watchedSignal2);
661: addBeanToListIfItExists(namedBeanList,watchedSignal2Alt);
662: addBeanToListIfItExists(namedBeanList,watchedSensor1);
663: addBeanToListIfItExists(namedBeanList,watchedSensor1Alt);
664: addBeanToListIfItExists(namedBeanList,watchedSensor2);
665: addBeanToListIfItExists(namedBeanList,watchedSensor2Alt);
666: addBeanToListIfItExists(namedBeanList,approachSensor1);
667:
668: // copy temp to definitive inputs
669: inputs = namedBeanList.toArray(new NamedBean[1]);
670:
671: outputs = new NamedBean[]{driveSignal.getBean()};
672:
673: // also need to act if the _signal's_ "held"
674: // parameter changes, but we don't want to
675: // act if the signals appearance changes (to
676: // avoid a loop, or avoid somebody changing appearance
677: // manually and having it instantly recomputed & changed back
678: driveSignal.getBean().addPropertyChangeListener(e -> {
679:• if (e.getPropertyName().equals(Bundle.getMessage("Held"))) {
680: setOutput();
681: }
682: }, driveSignal.getName(), "BlockBossLogic:" + name);
683: }
684:
685: private void addBeanToListIfItExists(List<NamedBean> namedBeanList, NamedBeanHandle<?> namedBeanHandle) {
686:• if (namedBeanHandle != null) {
687: namedBeanList.add(namedBeanHandle.getBean());
688: }
689: }
690:
691: /**
692: * Recompute new output state and apply it.
693: */
694: @Override
695: public void setOutput() {
696:
697: log.trace("setOutput for {}", name);
698:
699: // make sure init is complete
700:• if ((outputs == null) || (outputs[0] == null)) {
701: return;
702: }
703:
704: // if "hold" is true, must show red
705:• if (getHold()) {
706: ((SignalHead) outputs[0]).setAppearance(SignalHead.RED);
707: log.debug("setOutput red due to held for {}", name);
708: return;
709: }
710:
711: // otherwise, process algorithm
712:• switch (mode) {
713: case SINGLEBLOCK:
714: doSingleBlock();
715: break;
716: case TRAILINGMAIN:
717: doTrailingMain();
718: break;
719: case TRAILINGDIVERGING:
720: doTrailingDiverging();
721: break;
722: case FACING:
723: doFacing();
724: break;
725: default:
726: log.error("{}{}_Signal_{}", Bundle.getMessage("UnexpectedMode"), mode, getDrivenSignal());
727: }
728: }
729:
730: private int fastestColor1() {
731: int result = SignalHead.RED;
732: // special case: GREEN if no next signal
733:• if (watchedSignal1 == null && watchedSignal1Alt == null) {
734: result = SignalHead.GREEN;
735: }
736:
737: int val = result;
738:• if (watchedSignal1 != null) {
739: val = watchedSignal1.getBean().getAppearance();
740: }
741:• if (watchedSignal1 != null && watchedSignal1.getBean().getHeld()) {
742: val = SignalHead.RED; // if Held, act as if Red
743: }
744: int valAlt = result;
745:• if (watchedSignal1Alt != null) {
746: valAlt = watchedSignal1Alt.getBean().getAppearance();
747: }
748:• if (watchedSignal1Alt != null && watchedSignal1Alt.getBean().getHeld()) {
749: valAlt = SignalHead.RED; // if Held, act as if Red
750: }
751: return fasterOf(val, valAlt);
752: }
753:
754: private int fastestColor2() {
755: int result = SignalHead.RED;
756: // special case: GREEN if no next signal
757:• if (watchedSignal2 == null && watchedSignal2Alt == null) {
758: result = SignalHead.GREEN;
759: }
760:
761: int val = result;
762:• if (watchedSignal2 != null) {
763: val = watchedSignal2.getBean().getAppearance();
764: }
765:• if (watchedSignal2 != null && watchedSignal2.getBean().getHeld()) {
766: val = SignalHead.RED;
767: }
768:
769: int valAlt = result;
770:• if (watchedSignal2Alt != null) {
771: valAlt = watchedSignal2Alt.getBean().getAppearance();
772: }
773:• if (watchedSignal2Alt != null && watchedSignal2Alt.getBean().getHeld()) {
774: valAlt = SignalHead.RED;
775: }
776:
777: return fasterOf(val, valAlt);
778: }
779:
780: /**
781: * Given two {@link SignalHead} color constants, return the one
782: * corresponding to the slower speed.
783: *
784: * @param a color constant 1 to compare with
785: * @param b color constant 2
786: * @return the lowest of the two values entered
787: */
788: private static int slowerOf(int a, int b) {
789: // DARK is smallest, FLASHING GREEN is largest
790: return Math.min(a, b);
791: }
792:
793: /**
794: * Given two {@link SignalHead} color constants, return the one
795: * corresponding to the faster speed.
796: *
797: * @param a color constant 1 to compare with
798: * @param b color constant 2
799: * @return the highest of the two values entered
800: */
801: private static int fasterOf(int a, int b) {
802: // DARK is smallest, FLASHING GREEN is largest
803: return Math.max(a, b);
804: }
805:
806: private void doSingleBlock() {
807: int appearance = SignalHead.GREEN;
808: int oldAppearance = ((SignalHead) outputs[0]).getAppearance();
809: // check for yellow, flashing yellow overriding green
810:• if (protectWithFlashing && fastestColor1() == SignalHead.YELLOW) {
811: appearance = SignalHead.FLASHYELLOW;
812: }
813:• if (fastestColor1() == SignalHead.RED || fastestColor1() == SignalHead.FLASHRED) {
814: appearance = SignalHead.YELLOW;
815: }
816:
817: // if distant signal, show exactly what the home signal does
818:• if (distantSignal) {
819: appearance = fastestColor1();
820: }
821:
822: // if limited speed and green, reduce to yellow
823:• if (limitSpeed1) {
824: appearance = slowerOf(appearance, SignalHead.YELLOW);
825: }
826:
827: // if restricting, limit to flashing red
828:• if (restrictingSpeed1) {
829: appearance = slowerOf(appearance, SignalHead.FLASHRED);
830: }
831:
832: // check for red overriding yellow or green
833:• if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) {
834: appearance = SignalHead.RED;
835: }
836:• if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) {
837: appearance = SignalHead.RED;
838: }
839:• if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) {
840: appearance = SignalHead.RED;
841: }
842:• if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) {
843: appearance = SignalHead.RED;
844: }
845:• if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) {
846: appearance = SignalHead.RED;
847: }
848:
849: // check if signal if held, forcing a red appearance by this calculation
850:• if (((SignalHead) outputs[0]).getHeld()) {
851: appearance = SignalHead.RED;
852: }
853:
854: // handle approach lighting
855: doApproach();
856:
857: // show result if changed
858:• if (appearance != oldAppearance) {
859: ((SignalHead) outputs[0]).setAppearance(appearance);
860: log.debug("Change appearance of {} to: {}", name, appearance);
861: }
862: }
863:
864: private void doTrailingMain() {
865: int appearance = SignalHead.GREEN;
866: int oldAppearance = ((SignalHead) outputs[0]).getAppearance();
867: // check for yellow, flashing yellow overriding green
868:• if (protectWithFlashing && fastestColor1() == SignalHead.YELLOW) {
869: appearance = SignalHead.FLASHYELLOW;
870: }
871:• if (fastestColor1() == SignalHead.RED || fastestColor1() == SignalHead.FLASHRED) {
872: appearance = SignalHead.YELLOW;
873: }
874:
875: // if distant signal, show exactly what the home signal does
876:• if (distantSignal) {
877: appearance = fastestColor1();
878: }
879:
880: // if limited speed and green, reduce to yellow
881:• if (limitSpeed1) {
882: appearance = slowerOf(appearance, SignalHead.YELLOW);
883: }
884: // if restricting, limit to flashing red
885:• if (restrictingSpeed1) {
886: appearance = slowerOf(appearance, SignalHead.FLASHRED);
887: }
888:
889: // check for red overriding yellow or green
890:• if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) {
891: appearance = SignalHead.RED;
892: }
893:• if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) {
894: appearance = SignalHead.RED;
895: }
896:• if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) {
897: appearance = SignalHead.RED;
898: }
899:• if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) {
900: appearance = SignalHead.RED;
901: }
902:• if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) {
903: appearance = SignalHead.RED;
904: }
905:
906:• if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) {
907: appearance = SignalHead.RED;
908: }
909:• if (watchTurnout != null && watchTurnout.getBean().getCommandedState() != Turnout.CLOSED) {
910: appearance = SignalHead.RED;
911: }
912:
913: // check if signal if held, forcing a red appearance by this calculation
914:• if (((SignalHead) outputs[0]).getHeld()) {
915: appearance = SignalHead.RED;
916: }
917:
918: // handle approach lighting
919: doApproach();
920:
921: // show result if changed
922:• if (appearance != oldAppearance) {
923: ((SignalHead) outputs[0]).setAppearance(appearance);
924: log.debug("Change appearance of {} to:{}", name, appearance);
925: }
926: }
927:
928: private void doTrailingDiverging() {
929: int appearance = SignalHead.GREEN;
930: int oldAppearance = ((SignalHead) outputs[0]).getAppearance();
931: // check for yellow, flashing yellow overriding green
932:• if (protectWithFlashing && fastestColor1() == SignalHead.YELLOW) {
933: appearance = SignalHead.FLASHYELLOW;
934: }
935:• if (fastestColor1() == SignalHead.RED || fastestColor1() == SignalHead.FLASHRED) {
936: appearance = SignalHead.YELLOW;
937: }
938:
939: // if distant signal, show exactly what the home signal does
940:• if (distantSignal) {
941: appearance = fastestColor1();
942: }
943:
944: // if limited speed and green, reduce to yellow
945:• if (limitSpeed2) {
946: appearance = slowerOf(appearance, SignalHead.YELLOW);
947: }
948: // if restricting, limit to flashing red
949:• if (restrictingSpeed2) {
950: appearance = slowerOf(appearance, SignalHead.FLASHRED);
951: }
952:
953: // check for red overriding yellow or green
954:• if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) {
955: appearance = SignalHead.RED;
956: }
957:• if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) {
958: appearance = SignalHead.RED;
959: }
960:• if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) {
961: appearance = SignalHead.RED;
962: }
963:• if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) {
964: appearance = SignalHead.RED;
965: }
966:• if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) {
967: appearance = SignalHead.RED;
968: }
969:
970:• if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.THROWN) {
971: appearance = SignalHead.RED;
972: }
973:• if (watchTurnout != null && watchTurnout.getBean().getCommandedState() != Turnout.THROWN) {
974: appearance = SignalHead.RED;
975: }
976:
977: // check if signal if held, forcing a red appearance by this calculation
978:• if (((SignalHead) outputs[0]).getHeld()) {
979: appearance = SignalHead.RED;
980: }
981:
982: // handle approach lighting
983: doApproach();
984:
985: // show result if changed
986:• if (appearance != oldAppearance) {
987: ((SignalHead) outputs[0]).setAppearance(appearance);
988:• if (log.isDebugEnabled()) {
989: log.debug("Change appearance of {} to: {}", name, appearance);
990: }
991: }
992: }
993:
994: private void doFacing() {
995: int appearance = SignalHead.GREEN;
996: int oldAppearance = ((SignalHead) outputs[0]).getAppearance();
997:
998: // find downstream appearance, being pessimistic if we're not sure of the state
999: int s = SignalHead.GREEN;
1000:• if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.THROWN) {
1001: s = slowerOf(s, fastestColor1());
1002: }
1003:• if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) {
1004: s = slowerOf(s, fastestColor2());
1005: }
1006:
1007: // check for yellow, flashing yellow overriding green
1008:• if (protectWithFlashing && s == SignalHead.YELLOW) {
1009: appearance = SignalHead.FLASHYELLOW;
1010: }
1011:• if (s == SignalHead.RED || s == SignalHead.FLASHRED) {
1012: appearance = SignalHead.YELLOW;
1013: }
1014: // if distant signal, show exactly what the home signal does
1015:• if (distantSignal) {
1016: appearance = s;
1017: }
1018:
1019: // if limited speed and green or flashing yellow, reduce to yellow
1020:• if (watchTurnout != null && limitSpeed1 && watchTurnout.getBean().getKnownState() != Turnout.THROWN) {
1021: appearance = slowerOf(appearance, SignalHead.YELLOW);
1022: }
1023:• if (watchTurnout != null && limitSpeed2 && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) {
1024: appearance = slowerOf(appearance, SignalHead.YELLOW);
1025: }
1026: // if restricting, limit to flashing red
1027:• if (watchTurnout != null && restrictingSpeed1 && watchTurnout.getBean().getKnownState() != Turnout.THROWN) {
1028: appearance = slowerOf(appearance, SignalHead.FLASHRED);
1029: }
1030:• if (watchTurnout != null && restrictingSpeed2 && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) {
1031: appearance = slowerOf(appearance, SignalHead.FLASHRED);
1032: }
1033:
1034: // check for red overriding yellow or green
1035:• if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) {
1036: appearance = SignalHead.RED;
1037: }
1038:• if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) {
1039: appearance = SignalHead.RED;
1040: }
1041:• if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) {
1042: appearance = SignalHead.RED;
1043: }
1044:• if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) {
1045: appearance = SignalHead.RED;
1046: }
1047:• if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) {
1048: appearance = SignalHead.RED;
1049: }
1050:
1051:• if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.CLOSED)
1052:• && (watchedSensor1 != null && watchedSensor1.getBean().getKnownState() != Sensor.INACTIVE)) {
1053: appearance = SignalHead.RED;
1054: }
1055:• if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.CLOSED) &&
1056:• (watchedSensor1Alt != null && watchedSensor1Alt.getBean().getKnownState() != Sensor.INACTIVE)) {
1057: appearance = SignalHead.RED;
1058: }
1059:• if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.THROWN) &&
1060:• (watchedSensor2 != null && watchedSensor2.getBean().getKnownState() != Sensor.INACTIVE)) {
1061: appearance = SignalHead.RED;
1062: }
1063:• if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.THROWN) &&
1064:• (watchedSensor2Alt != null && watchedSensor2Alt.getBean().getKnownState() != Sensor.INACTIVE)) {
1065: appearance = SignalHead.RED;
1066: }
1067:
1068: // check if turnout in motion, if so force red
1069:• if (watchTurnout != null && (watchTurnout.getBean().getKnownState() != watchTurnout.getBean().getCommandedState())) {
1070: appearance = SignalHead.RED;
1071: }
1072:• if (watchTurnout != null && (watchTurnout.getBean().getKnownState() != Turnout.THROWN) && (watchTurnout.getBean().getKnownState() != Turnout.CLOSED)) // checking for other states
1073: {
1074: appearance = SignalHead.RED;
1075: }
1076:
1077: // check if signal if held, forcing a red appearance by this calculation
1078:• if (((SignalHead) outputs[0]).getHeld()) {
1079: appearance = SignalHead.RED;
1080: }
1081:
1082: // handle approach lighting
1083: doApproach();
1084:
1085: // show result if changed
1086:• if (appearance != oldAppearance) {
1087: ((SignalHead) outputs[0]).setAppearance(appearance);
1088: }
1089: }
1090:
1091: /**
1092: * Handle the approach lighting logic for all modes.
1093: */
1094: private void doApproach() {
1095:• if (approachSensor1 != null && approachSensor1.getBean().getKnownState() == Sensor.INACTIVE) {
1096: // should not be lit
1097:• if (driveSignal.getBean().getLit()) {
1098: driveSignal.getBean().setLit(false);
1099: }
1100: } else {
1101: // should be lit
1102:• if (!driveSignal.getBean().getLit()) {
1103: driveSignal.getBean().setLit(true);
1104: }
1105: }
1106: }
1107:
1108: /**
1109: * @return an enumeration of the collection of BlockBossLogic objects.
1110: * @deprecated Since 4.21.1 use {@link BlockBossLogicProvider#provideAll()} instead.
1111: */
1112: @Deprecated
1113: public static Enumeration<BlockBossLogic> entries() {
1114: return Collections.enumeration(InstanceManager.getDefault(BlockBossLogicProvider.class).provideAll());
1115: }
1116:
1117: /**
1118: * Ensure that this BlockBossLogic object is available for later retrieval.
1119: * @deprecated Since 4.21.1 use {@link BlockBossLogicProvider#register(BlockBossLogic)} instead.
1120: */
1121: @Deprecated
1122: public void retain() {
1123: InstanceManager.getDefault(BlockBossLogicProvider.class).register(this);
1124: }
1125:
1126: /**
1127: * Get the BlockBossLogic item governing a specific signal head by its name,
1128: * having removed it from use.
1129: *
1130: * @param signal name of the signal head object
1131: * @return never null
1132: */
1133: @Nonnull
1134: @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE",
1135: justification="enforced dynamically, too hard to prove statically")
1136: public static BlockBossLogic getStoppedObject(String signal) {
1137: // As a static requirement, the signal head must exist, but
1138: // we can't express that statically. We test it dynamically.
1139: SignalHead sh = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signal);
1140: java.util.Objects.requireNonNull(sh, "signal head must exist");
1141: return getStoppedObject(sh);
1142: }
1143:
1144: /**
1145: * Get the BlockBossLogic item governing a specific signal head, having
1146: * removed it from use.
1147: *
1148: * @param sh signal head object
1149: * @return never null
1150: */
1151: @Nonnull
1152: public static BlockBossLogic getStoppedObject(@Nonnull SignalHead sh) {
1153: BlockBossLogic b = InstanceManager.getDefault(BlockBossLogicProvider.class).provide(sh);
1154: b.stop();
1155: return b;
1156: }
1157:
1158: /**
1159: * Get the BlockBossLogic item governing a specific signal head located from its name.
1160: * <p>
1161: * Unlike {@link BlockBossLogic#getStoppedObject(String signal)} this does
1162: * not remove the object from being used.
1163: *
1164: * @param signal SignalHead system or user name
1165: * @return never null - creates new object if none exists
1166: * @deprecated Since 4.21.1 use {@link BlockBossLogicProvider#provide(String)} instead.
1167: */
1168: @Nonnull
1169: @Deprecated
1170: public static BlockBossLogic getExisting(@Nonnull String signal) {
1171: return InstanceManager.getDefault(BlockBossLogicProvider.class).provide(signal);
1172: }
1173:
1174: /**
1175: * Get the BlockBossLogic item governing a specific signal head object.
1176: * <p>
1177: * Unlike {@link BlockBossLogic#getStoppedObject(String signal)} this does
1178: * not remove the object from being used.
1179: *
1180: * @param sh Existing SignalHead object
1181: * @return never null - creates new object if none exists
1182: * @deprecated Since 4.21.1 use {@link BlockBossLogicProvider#provide(SignalHead)} instead.
1183: */
1184: @Nonnull
1185: @Deprecated
1186: public static BlockBossLogic getExisting(@Nonnull SignalHead sh) {
1187: return InstanceManager.getDefault(BlockBossLogicProvider.class).provide(sh);
1188: }
1189:
1190: @Override
1191: public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException {
1192: NamedBean nb = (NamedBean) evt.getOldValue();
1193:• if ("CanDelete".equals(evt.getPropertyName())) { // NOI18N
1194: processCanDelete(evt, nb);
1195:• } else if ("DoDelete".equals(evt.getPropertyName())) { // NOI18N
1196: processDoDelete(nb);
1197: }
1198: }
1199:
1200: private void processDoDelete(NamedBean nb) {
1201:• if (nb instanceof SignalHead) {
1202: deleteSignalHead(nb);
1203:• } else if (nb instanceof Turnout) {
1204: deleteTurnout(nb);
1205:• } else if (nb instanceof Sensor) {
1206: deleteSensor(nb);
1207: }
1208: }
1209:
1210: private void deleteSensor(NamedBean nb) {
1211:• if (watchSensor1 != null && watchSensor1.getBean().equals(nb)) {
1212: stop();
1213: setSensor1(null);
1214: start();
1215: }
1216:• if (watchSensor2 != null && watchSensor2.getBean().equals(nb)) {
1217: stop();
1218: setSensor2(null);
1219: start();
1220: }
1221:• if (watchSensor3 != null && watchSensor3.getBean().equals(nb)) {
1222: stop();
1223: setSensor3(null);
1224: start();
1225: }
1226:• if (watchSensor4 != null && watchSensor4.getBean().equals(nb)) {
1227: stop();
1228: setSensor4(null);
1229: start();
1230: }
1231:• if (watchSensor5 != null && watchSensor5.getBean().equals(nb)) {
1232: stop();
1233: setSensor5(null);
1234: start();
1235: }
1236:• if (watchedSensor1 != null && watchedSensor1.getBean().equals(nb)) {
1237: stop();
1238: setWatchedSensor1(null);
1239: start();
1240: }
1241:• if (watchedSensor2 != null && watchedSensor2.getBean().equals(nb)) {
1242: stop();
1243: setWatchedSensor2(null);
1244: start();
1245: }
1246:• if (watchedSensor1Alt != null && watchedSensor1Alt.getBean().equals(nb)) {
1247: stop();
1248: setWatchedSensor1Alt(null);
1249: start();
1250: }
1251:• if (watchedSensor2Alt != null && watchedSensor2Alt.getBean().equals(nb)) {
1252: stop();
1253: setWatchedSensor2Alt(null);
1254: start();
1255: }
1256:• if (approachSensor1 != null && approachSensor1.getBean().equals(nb)) {
1257: stop();
1258: setApproachSensor1(null);
1259: start();
1260: }
1261: }
1262:
1263: private void deleteTurnout(NamedBean nb) {
1264:• if (watchTurnout != null && watchTurnout.getBean().equals(nb)) {
1265: stop();
1266: setTurnout(null);
1267: start();
1268: }
1269: }
1270:
1271: private void deleteSignalHead(NamedBean nb) {
1272:• if (nb.equals(getDrivenSignalNamedBean().getBean())) {
1273: stop();
1274:
1275: InstanceManager.getDefault(BlockBossLogicProvider.class).remove(this);
1276: }
1277:• if (watchedSignal1 != null && watchedSignal1.getBean().equals(nb)) {
1278: stop();
1279: setWatchedSignal1(null, false);
1280: start();
1281: }
1282:• if (watchedSignal1Alt != null && watchedSignal1Alt.getBean().equals(nb)) {
1283: stop();
1284: setWatchedSignal1Alt(null);
1285: start();
1286: }
1287:• if (watchedSignal2 != null && watchedSignal2.getBean().equals(nb)) {
1288: stop();
1289: setWatchedSignal2(null);
1290: start();
1291: }
1292:• if (watchedSignal2Alt != null && watchedSignal2Alt.getBean().equals(nb)) {
1293: stop();
1294: setWatchedSignal2Alt(null);
1295: start();
1296: }
1297: }
1298:
1299: private void processCanDelete(PropertyChangeEvent evt, NamedBean nb) throws java.beans.PropertyVetoException {
1300: log.debug("name: {} got {} from {}", name, evt, evt.getSource());
1301:
1302: StringBuilder message = new StringBuilder();
1303: message.append(Bundle.getMessage("InUseBlockBossHeader", getDrivenSignal()));
1304:
1305: boolean found = false;
1306:
1307:• if (nb instanceof SignalHead) {
1308: found = canDeleteSignalHead(evt, nb, message, found);
1309:• } else if (nb instanceof Turnout) {
1310: found = canDeleteTurnout(nb, message, found);
1311:• } else if (nb instanceof Sensor) {
1312: found = canDeleteSensor(nb, message, found);
1313: }
1314:• if (found) {
1315: message.append(Bundle.getMessage("InUseBlockBossFooter")); // NOI18N
1316: throw new java.beans.PropertyVetoException(message.toString(), evt);
1317: }
1318: }
1319:
1320: private boolean canDeleteSensor(NamedBean nb, StringBuilder message, boolean found) {
1321: message.append("<ul>");
1322:• if ((watchSensor1 != null && watchSensor1.getBean().equals(nb))
1323:• || (watchSensor2 != null && watchSensor2.getBean().equals(nb))
1324:• || (watchSensor3 != null && watchSensor3.getBean().equals(nb))
1325:• || (watchSensor4 != null && watchSensor4.getBean().equals(nb))
1326:• || (watchSensor5 != null && watchSensor5.getBean().equals(nb))) {
1327: addMessageToHtmlList(message, "<li>", "InUseWatchedSensor", "</li>");
1328: found = true;
1329: }
1330:• if ((watchedSensor1 != null && watchedSensor1.getBean().equals(nb))
1331:• || (watchedSensor2 != null && watchedSensor2.getBean().equals(nb))
1332:• || (watchedSensor1Alt != null && watchedSensor1Alt.getBean().equals(nb))
1333:• || (watchedSensor2Alt != null && watchedSensor2Alt.getBean().equals(nb))) {
1334: addMessageToHtmlList(message, "<li>", "InUseWatchedSensor", "</li>");
1335: found = true;
1336:
1337: }
1338:• if (approachSensor1 != null && approachSensor1.getBean().equals(nb)) {
1339: found = true;
1340: addMessageToHtmlList(message, "<li>", "InUseApproachSensor", "</li>");
1341: }
1342:
1343: message.append("</ul>");
1344: return found;
1345: }
1346:
1347: private boolean canDeleteTurnout(NamedBean nb, StringBuilder message, boolean found) {
1348:• if (watchTurnout != null && watchTurnout.getBean().equals(nb)) {
1349: found = true;
1350: addMessageToHtmlList(message, "<ul>", "InUseWatchedTurnout", "</ul>");
1351: }
1352: return found;
1353: }
1354:
1355: private boolean canDeleteSignalHead(PropertyChangeEvent evt, NamedBean nb, StringBuilder message, boolean found) throws java.beans.PropertyVetoException {
1356:• if (nb.equals(getDrivenSignalNamedBean().getBean())) {
1357: message.append("<br><b>").append(Bundle.getMessage("InUseThisSslWillBeDeleted")).append("</b>");
1358: throw new java.beans.PropertyVetoException(message.toString(), evt);
1359: }
1360:• if ((watchedSignal1 != null && watchedSignal1.getBean().equals(nb))
1361:• || (watchedSignal1Alt != null && watchedSignal1Alt.getBean().equals(nb))
1362:• || (watchedSignal2 != null && watchedSignal2.getBean().equals(nb))
1363:• || (watchedSignal2Alt != null && watchedSignal2Alt.getBean().equals(nb))) {
1364: addMessageToHtmlList(message, "<ul>", "InUseWatchedSignal", "</ul>");
1365: found = true;
1366: }
1367: return found;
1368: }
1369:
1370: private void addMessageToHtmlList(StringBuilder message, String s, String inUseWatchedSignal, String s2) {
1371: message.append(s);
1372: message.append(Bundle.getMessage(inUseWatchedSignal));
1373: message.append(s2);
1374: }
1375:
1376: /**
1377: * Stop() all existing objects and clear the list.
1378: * <p>
1379: * Intended to be only used during testing.
1380: * @deprecated Since 4.21.1 use {@link BlockBossLogicProvider#dispose()} instead.
1381: */
1382: @Deprecated
1383: public static void stopAllAndClear() {
1384: InstanceManager.getDefault(BlockBossLogicProvider.class).dispose();
1385: }
1386:
1387: public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) {
1388: List<NamedBeanUsageReport> report = new ArrayList<>();
1389: SignalHead head = driveSignal.getBean();
1390:• if (bean != null) {
1391:• if (watchSensor1 != null && bean.equals(getDrivenSignalNamedBean().getBean())) {
1392: report.add(new NamedBeanUsageReport("SSLSignal", head)); // NOI18N
1393: }
1394:• if (watchSensor1 != null && bean.equals(watchSensor1.getBean())) {
1395: report.add(new NamedBeanUsageReport("SSLSensor1", head)); // NOI18N
1396: }
1397:• if (watchSensor2 != null && bean.equals(watchSensor2.getBean())) {
1398: report.add(new NamedBeanUsageReport("SSLSensor2", head)); // NOI18N
1399: }
1400:• if (watchSensor3 != null && bean.equals(watchSensor3.getBean())) {
1401: report.add(new NamedBeanUsageReport("SSLSensor3", head)); // NOI18N
1402: }
1403:• if (watchSensor4 != null && bean.equals(watchSensor4.getBean())) {
1404: report.add(new NamedBeanUsageReport("SSLSensor4", head)); // NOI18N
1405: }
1406:• if (watchSensor5 != null && bean.equals(watchSensor5.getBean())) {
1407: report.add(new NamedBeanUsageReport("SSLSensor5", head)); // NOI18N
1408: }
1409:• if (watchTurnout != null && bean.equals(watchTurnout.getBean())) {
1410: report.add(new NamedBeanUsageReport("SSLTurnout", head)); // NOI18N
1411: }
1412:• if (watchedSignal1 != null && bean.equals(watchedSignal1.getBean())) {
1413: report.add(new NamedBeanUsageReport("SSLSignal1", head)); // NOI18N
1414: }
1415:• if (watchedSignal1Alt != null && bean.equals(watchedSignal1Alt.getBean())) {
1416: report.add(new NamedBeanUsageReport("SSLSignal1Alt", head)); // NOI18N
1417: }
1418:• if (watchedSignal2 != null && bean.equals(watchedSignal2.getBean())) {
1419: report.add(new NamedBeanUsageReport("SSLSignal2", head)); // NOI18N
1420: }
1421:• if (watchedSignal2Alt != null && bean.equals(watchedSignal2Alt.getBean())) {
1422: report.add(new NamedBeanUsageReport("SSLSignal2Alt", head)); // NOI18N
1423: }
1424:• if (watchedSensor1 != null && bean.equals(watchedSensor1.getBean())) {
1425: report.add(new NamedBeanUsageReport("SSLSensorWatched1", head)); // NOI18N
1426: }
1427:• if (watchedSensor1Alt != null && bean.equals(watchedSensor1Alt.getBean())) {
1428: report.add(new NamedBeanUsageReport("SSLSensorWatched1Alt", head)); // NOI18N
1429: }
1430:• if (watchedSensor2 != null && bean.equals(watchedSensor2.getBean())) {
1431: report.add(new NamedBeanUsageReport("SSLSensorWatched2", head)); // NOI18N
1432: }
1433:• if (watchedSensor2Alt != null && bean.equals(watchedSensor2Alt.getBean())) {
1434: report.add(new NamedBeanUsageReport("SSLSensorWatched2Alt", head)); // NOI18N
1435: }
1436:• if (approachSensor1 != null && bean.equals(approachSensor1.getBean())) {
1437: report.add(new NamedBeanUsageReport("SSLSensorApproach", head)); // NOI18N
1438: }
1439: }
1440: return report;
1441: }
1442:
1443: private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BlockBossLogic.class);
1444:
1445: }