JMRI: Simple Signal Logic
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.
On Single Block
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); } }
On Main Leg ofTrailing-Point Turnout
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); if (log.isDebugEnabled()) log.debug("Change appearance of "+name+" to "+appearance); } }
On Diverging Leg of Trailing-Point Turnout
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); } }
On Facing-Point Turnout
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); }