001package jmri.jmrit.tracker; 002 003import jmri.Block; 004import jmri.SignalHead; 005import jmri.Throttle; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008 009/** 010 * Stop a train in a block if required. 011 * <p> 012 * Watches a Block object that is passing around a Throttle object as its 013 * value. When the Block goes OCCUPIED, check whether a signal is telling the 014 * train to stop; if so, force the Throttle to zero speed. 015 * <p> 016 * This contains multiple SignalHead objects, each associated with a Path that 017 * contains one or more BeanSettings (e.g. Turnout positions) and directions. 018 * When needed, this consults the paths to see which one is active (has its 019 * Turnouts set) and corresponds to the current direction of the block. There 020 * should be exactly one of these, which will then identify which signal to 021 * monitor. 022 * <p> 023 * Limitations: 024 * <ul> 025 * <li>Current implementation does not protect against changing direction and 026 * backing out of the block 027 * <li>Should track speed at time of stop and restore it on restart (or should 028 * it not restart? Optional restart?) 029 * </ul> 030 * 031 * @author Bob Jacobsen Copyright (C) 2006 032 */ 033public class StoppingBlock { 034 035 public StoppingBlock(Block b) { 036 block = b; 037 038 // set a listener in the block 039 block.addPropertyChangeListener(new java.beans.PropertyChangeListener() { 040 @Override 041 public void propertyChange(java.beans.PropertyChangeEvent e) { 042 handleBlockChange(e); 043 } 044 }); 045 } 046 047 void handleBlockChange(java.beans.PropertyChangeEvent e) { 048 // check for going occupied 049 if (e.getPropertyName().equals("state") && e.getNewValue().equals(Integer.valueOf(Block.OCCUPIED))) { 050 if (sig1 == null) { 051 return; 052 } 053 054 if (direction != block.getDirection()) { 055 return; // no interesting 056 } 057 int val = fastestAppearance(); 058 if (log.isDebugEnabled()) { 059 log.debug("Block {} occupied with {}", block.getSystemName(), val); 060 } 061 062 if (val == SignalHead.RED) { 063 doStop(); 064 } 065 if (val == SignalHead.YELLOW) { 066 doSlow(); 067 } 068 } 069 } 070 071 void handleSignalChange(java.beans.PropertyChangeEvent e) { 072 // if currently have a loco present and stopped, 073 // consider changing speed 074 if ((block.getValue() != null) && block.getState() == (Block.OCCUPIED)) { 075 076 if (sig1 == null) { 077 return; 078 } 079 080 if (direction != block.getDirection()) { 081 return; // not interesting 082 } 083 int val = fastestAppearance(); 084 if (log.isDebugEnabled()) { 085 log.debug("Block {} signal change to {}", block.getSystemName(), val); 086 } 087 088 if (val == SignalHead.YELLOW) { 089 doSlow(); 090 } 091 if (val == SignalHead.GREEN) { 092 doRestart(); 093 } 094 } 095 } 096 097 public void addSignal(SignalHead s, int dir) { 098 sig1 = s; 099 direction = dir; 100 101 sig1.addPropertyChangeListener(new java.beans.PropertyChangeListener() { 102 @Override 103 public void propertyChange(java.beans.PropertyChangeEvent e) { 104 handleSignalChange(e); 105 } 106 }); 107 } 108 109 public void addSignal(SignalHead s1, SignalHead s2, int dir) { 110 addSignal(s1, dir); 111 sig2 = s2; 112 sig2.addPropertyChangeListener(new java.beans.PropertyChangeListener() { 113 @Override 114 public void propertyChange(java.beans.PropertyChangeEvent e) { 115 handleSignalChange(e); 116 } 117 }); 118 } 119 120 int fastestAppearance() { 121 if (sig1 == null) { 122 log.error("Should not get null in fastestAppearance"); 123 return 0; 124 } 125 if (sig2 == null) { 126 return sig1.getAppearance(); 127 } else { 128 return Math.max(sig1.getAppearance(), sig2.getAppearance()); 129 } 130 } 131 132 /** 133 * Perform the stop operation 134 */ 135 void doStop() { 136 if (log.isDebugEnabled()) { 137 log.debug("Block {} speed being set to stop", block.getSystemName()); 138 } 139 setSpeed(0.0f, false, false, false); // bell on 140 } 141 142 void doSlow() { 143 if (log.isDebugEnabled()) { 144 log.debug("Block {} speed being set to slow", block.getSystemName()); 145 } 146 setSpeed(slow, false, false, false); // bell off 147 } 148 149 void doRestart() { 150 if (log.isDebugEnabled()) { 151 log.debug("Block {} speed being set to run", block.getSystemName()); 152 } 153 setSpeed(fast, false, false, false); // bell off 154 } 155 156 void setSpeed(float speed, boolean f1, boolean f2, boolean f3) { 157 Object o = block.getValue(); 158 if (o == null) { 159 log.error("Block {} contained no Throttle object", block.getSystemName()); 160 return; 161 } 162 try { 163 Throttle t = (Throttle) block.getValue(); 164 t.setSpeedSetting(speed); 165 t.setFunction(1, f1); 166 t.setFunction(2, f2); 167 } catch (ClassCastException e) { 168 log.error("Block {} did not contain object of Throttle type", block.getSystemName(), e); 169 } 170 } 171 172 public void setSpeeds(float s, float f) { 173 slow = s; 174 fast = f; 175 } 176 177 // data members 178 Block block; 179 SignalHead sig1; 180 SignalHead sig2; 181 int direction; 182 float slow = 0.3f; 183 float fast = 0.6f; 184 185 private final static Logger log = LoggerFactory.getLogger(StoppingBlock.class); 186 187}