Background information of the logic used to control simple signals
This page describes the logic used by the JMRI Simple Signal panel to control signals.
We display the actual code, so there's no ambiguity about what it's doing. This is from JMRI test release 2.9.1.
This signal protects one end of a straight through block, with no signaled turnouts.
void doSingleBlock() {
int appearance = SignalHead.GREEN;
int oldAppearance = ((SignalHead)outputs[0]).getAppearance();
// check for yellow, flashing yellow overriding green
if (protectWithFlashing && fastestColor1()==SignalHead.YELLOW)
appearance = SignalHead.FLASHYELLOW;
if (fastestColor1()==SignalHead.RED || fastestColor1()==SignalHead.FLASHRED)
appearance = SignalHead.YELLOW;
// if distant signal, show exactly what the home signal does
if (distantSignal)
appearance = fastestColor1();
// if limited speed and green, reduce to yellow
if (limitSpeed1)
appearance = slowerOf(appearance, SignalHead.YELLOW);
// check for red overriding yellow or green
if (watchSensor1!=null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor2!=null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor3!=null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor4!=null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
// check if signal if held, forcing a red aspect by this calculation
if (((SignalHead)outputs[0]).getHeld())
appearance = SignalHead.RED;
// handle approach lighting
doApproach();
// show result if changed
if (appearance != oldAppearance) {
((SignalHead)outputs[0]).setAppearance(appearance);
if (log.isDebugEnabled()) log.debug("Change appearance of "+name+" to "+appearance);
}
}
This signal is along the main route through a turnout, which is defined as the direction taken by trains when the turnout is closed. It's protecting the frog of the turnout so that trains will stop before running through a turnout set against them.
void doTrailingMain() {
int appearance = SignalHead.GREEN;
int oldAppearance = ((SignalHead)outputs[0]).getAppearance();
// check for yellow, flashing yellow overriding green
if (protectWithFlashing && fastestColor1()==SignalHead.YELLOW)
appearance = SignalHead.FLASHYELLOW;
if (fastestColor1()==SignalHead.RED || fastestColor1()==SignalHead.FLASHRED)
appearance = SignalHead.YELLOW;
// if distant signal, show exactly what the home signal does
if (distantSignal)
appearance = fastestColor1();
// if limited speed and green, reduce to yellow
if (limitSpeed1)
appearance = slowerOf(appearance, SignalHead.YELLOW);
// check for red overriding yellow or green
if (watchSensor1!=null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor2!=null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor3!=null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor4!=null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchTurnout!=null && watchTurnout.getBean().getKnownState() != Turnout.CLOSED)
appearance = SignalHead.RED;
if (watchTurnout!=null && watchTurnout.getBean().getCommandedState() != Turnout.CLOSED)
appearance = SignalHead.RED;
// check if signal if held, forcing a red aspect by this calculation
if (((SignalHead)outputs[0]).getHeld())
appearance = SignalHead.RED;
// handle approach lighting
doApproach();
// show result if changed
if (appearance != oldAppearance) {
((SignalHead)outputs[0]).setAppearance(appearance);
log.debug("Change appearance of {} to {}", name, appearance);
}
}
This signal is along the diverging route through a turnout, which is defined as the direction taken by trains when the turnout is set to "thrown". It's protecting the frog of the turnout so that trains will stop before running through a turnout set against them.
void doTrailingDiverging() {
int appearance = SignalHead.GREEN;
int oldAppearance = ((SignalHead)outputs[0]).getAppearance();
// check for yellow, flashing yellow overriding green
if (protectWithFlashing && fastestColor1()==SignalHead.YELLOW)
appearance = SignalHead.FLASHYELLOW;
if (fastestColor1()==SignalHead.RED || fastestColor1()==SignalHead.FLASHRED)
appearance = SignalHead.YELLOW;
// if distant signal, show exactly what the home signal does
if (distantSignal)
appearance = fastestColor1();
// if limited speed and green, reduce to yellow
if (limitSpeed2)
appearance = slowerOf(appearance, SignalHead.YELLOW);
// check for red overriding yellow or green
if (watchSensor1!=null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor2!=null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor3!=null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor4!=null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchTurnout!=null && watchTurnout.getBean().getKnownState() != Turnout.THROWN)
appearance = SignalHead.RED;
if (watchTurnout!=null && watchTurnout.getBean().getCommandedState() != Turnout.THROWN)
appearance = SignalHead.RED;
// check if signal if held, forcing a red aspect by this calculation
if (((SignalHead)outputs[0]).getHeld())
appearance = SignalHead.RED;
// handle approach lighting
doApproach();
// show result if changed
if (appearance != oldAppearance) {
((SignalHead)outputs[0]).setAppearance(appearance);
if (log.isDebugEnabled()) log.debug("Change appearance of "+name+" to "+appearance);
}
}
This signal is protecting the points-end of a turnout. Depending on whether the turnout is thrown or closed, the train will take two different routes, and the signal will protect different next blocks.
void doFacing() {
int appearance = SignalHead.GREEN;
int oldAppearance = ((SignalHead)outputs[0]).getAppearance();
// find downstream appearance, being pessimistic if we're not sure of the state
int s = SignalHead.GREEN;
if (watchTurnout!=null && watchTurnout.getBean().getKnownState() != Turnout.THROWN)
s = slowerOf(s, fastestColor1());
if (watchTurnout!=null && watchTurnout.getBean().getKnownState() != Turnout.CLOSED)
s = slowerOf(s, fastestColor2());
// check for yellow, flashing yellow overriding green
if (protectWithFlashing && s==SignalHead.YELLOW)
appearance = SignalHead.FLASHYELLOW;
if (s==SignalHead.RED || s==SignalHead.FLASHRED)
appearance = SignalHead.YELLOW;
// if distant signal, show exactly what the home signal does
if (distantSignal)
appearance = s;
// if limited speed and green or flashing yellow, reduce to yellow
if (watchTurnout!=null && limitSpeed1 && watchTurnout.getBean().getKnownState()!=Turnout.THROWN)
appearance = slowerOf(appearance, SignalHead.YELLOW);
if (watchTurnout!=null && limitSpeed2 && watchTurnout.getBean().getKnownState()!=Turnout.CLOSED)
appearance = slowerOf(appearance, SignalHead.YELLOW);
// check for red overriding yellow or green
if (watchSensor1!=null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor2!=null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor3!=null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if (watchSensor4!=null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE)
appearance = SignalHead.RED;
if ((watchTurnout!=null && watchTurnout.getBean().getKnownState() == Turnout.CLOSED)
&& ((watchedSensor1!=null && watchedSensor1.getBean().getKnownState() != Sensor.INACTIVE)))
appearance = SignalHead.RED;
if ((watchTurnout!=null && watchTurnout.getBean().getKnownState() == Turnout.CLOSED) && ((watchedSensor1Alt!=null && watchedSensor1Alt.getBean().getKnownState() != Sensor.INACTIVE)))
appearance = SignalHead.RED;
if ((watchTurnout!=null && watchTurnout.getBean().getKnownState() == Turnout.THROWN) && ((watchedSensor2!=null && watchedSensor2.getBean().getKnownState() != Sensor.INACTIVE)))
appearance = SignalHead.RED;
if ((watchTurnout!=null && watchTurnout.getBean().getKnownState() == Turnout.THROWN) && ((watchedSensor2Alt!=null && watchedSensor2Alt.getBean().getKnownState() != Sensor.INACTIVE)))
appearance = SignalHead.RED;
// check if turnout in motion, if so force red
if (watchTurnout!=null && (watchTurnout.getBean().getKnownState() != watchTurnout.getBean().getCommandedState()) )
appearance = SignalHead.RED;
if (watchTurnout!=null && (watchTurnout.getBean().getKnownState() != Turnout.THROWN) && (watchTurnout.getBean().getKnownState() != Turnout.CLOSED) ) // checking for other states
appearance = SignalHead.RED;
// check if signal if held, forcing a red aspect by this calculation
if (((SignalHead)outputs[0]).getHeld())
appearance = SignalHead.RED;
// handle approach lighting
doApproach();
// show result if changed
if (appearance != oldAppearance)
((SignalHead)outputs[0]).setAppearance(appearance);
}