Package: BlockBossLogic

BlockBossLogic

nameinstructionbranchcomplexitylinemethod
BlockBossLogic(String)
M: 0 C: 156
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 38
100%
M: 0 C: 1
100%
defineIO()
M: 49 C: 158
76%
M: 7 C: 25
78%
M: 7 C: 10
59%
M: 14 C: 40
74%
M: 0 C: 1
100%
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: 50 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: 40 C: 124
76%
M: 19 C: 29
60%
M: 15 C: 10
40%
M: 6 C: 28
82%
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: 3
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: 24 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getExisting(String)
M: 21 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 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: 37
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 11
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%
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%
retain()
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
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: 34 C: 29
46%
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: 11
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
stopAllAndClear()
M: 0 C: 16
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
vetoableChange(PropertyChangeEvent)
M: 617 C: 0
0%
M: 142 C: 0
0%
M: 72 C: 0
0%
M: 120 C: 0
0%
M: 1 C: 0
0%

Coverage

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