001package jmri.implementation; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import java.util.Arrays; 005import jmri.NamedBeanHandle; 006import jmri.Turnout; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Drive a single searchlight signal head via three "Turnout" objects. 012 * <p> 013 * "Triple Output RGB" to differentiate from the existing RYG triple output 014 * head; The class name fits in with the quad output name which is the 015 * equivalent discrete lamp head. 016 * <p> 017 * The three Turnout objects are provided during construction, and each drives a 018 * specific color (RED, GREEN and BLUE). Normally, "THROWN" is on, and "CLOSED" 019 * is off. 020 * <p> 021 * Red = Red Green = Green Yellow = Red and Green Lunar = Red, Green and Blue 022 * <p> 023 * This class doesn't currently listen to the Turnout's to see if they've been 024 * changed via some other mechanism. 025 * 026 * @author Suzie Tall based on Bob Jacobsen's work 027 * @author Bob Jacobsen Copyright (C) 2003, 2008 028 */ 029public class TripleOutputSignalHead extends DoubleTurnoutSignalHead { 030 public TripleOutputSignalHead(String sys, String user, NamedBeanHandle<Turnout> green, NamedBeanHandle<Turnout> blue, NamedBeanHandle<Turnout> red) { 031 super(sys, user, green, red); 032 mBlue = blue; 033 } 034 035 public TripleOutputSignalHead(String sys, NamedBeanHandle<Turnout> green, NamedBeanHandle<Turnout> blue, NamedBeanHandle<Turnout> red) { 036 super(sys, green, red); 037 mBlue = blue; 038 } 039 040 @SuppressWarnings("fallthrough") 041 @SuppressFBWarnings(value = "SF_SWITCH_FALLTHROUGH") 042 @Override 043 protected void updateOutput() { 044 // assumes that writing a turnout to an existing state is cheap! 045 if (!mLit) { 046 mRed.getBean().setCommandedState(Turnout.CLOSED); 047 mBlue.getBean().setCommandedState(Turnout.CLOSED); 048 mGreen.getBean().setCommandedState(Turnout.CLOSED); 049 } else if (!mFlashOn 050 && ((mAppearance == FLASHGREEN) 051 || (mAppearance == FLASHYELLOW) 052 || (mAppearance == FLASHLUNAR) 053 || (mAppearance == FLASHRED))) { 054 // flash says to make output dark 055 mRed.getBean().setCommandedState(Turnout.CLOSED); 056 mBlue.getBean().setCommandedState(Turnout.CLOSED); 057 mGreen.getBean().setCommandedState(Turnout.CLOSED); 058 } else { 059 switch (mAppearance) { 060 case RED: 061 case FLASHRED: 062 mRed.getBean().setCommandedState(Turnout.THROWN); 063 mBlue.getBean().setCommandedState(Turnout.CLOSED); 064 mGreen.getBean().setCommandedState(Turnout.CLOSED); 065 break; 066 case YELLOW: 067 case FLASHYELLOW: 068 mRed.getBean().setCommandedState(Turnout.THROWN); 069 mBlue.getBean().setCommandedState(Turnout.CLOSED); 070 mGreen.getBean().setCommandedState(Turnout.THROWN); 071 break; 072 case GREEN: 073 case FLASHGREEN: 074 mRed.getBean().setCommandedState(Turnout.CLOSED); 075 mBlue.getBean().setCommandedState(Turnout.CLOSED); 076 mGreen.getBean().setCommandedState(Turnout.THROWN); 077 break; 078 case LUNAR: 079 case FLASHLUNAR: 080 mRed.getBean().setCommandedState(Turnout.THROWN); 081 mBlue.getBean().setCommandedState(Turnout.THROWN); 082 mGreen.getBean().setCommandedState(Turnout.THROWN); 083 break; 084 default: 085 log.warn("Unexpected new appearance: {}", mAppearance); 086 // go dark by falling through 087 case DARK: 088 mRed.getBean().setCommandedState(Turnout.CLOSED); 089 mBlue.getBean().setCommandedState(Turnout.CLOSED); 090 mGreen.getBean().setCommandedState(Turnout.CLOSED); 091 break; 092 } 093 } 094 } 095 096 /** 097 * Remove references to and from this object, so that it can eventually be 098 * garbage-collected. 099 */ 100 @Override 101 public void dispose() { 102 mBlue = null; 103 super.dispose(); 104 } 105 106 private NamedBeanHandle<Turnout> mBlue; 107 108 public NamedBeanHandle<Turnout> getBlue() { 109 return mBlue; 110 } 111 112 public void setBlue(NamedBeanHandle<Turnout> t) { 113 mBlue = t; 114 } 115 116 // claim support for Lunar aspects 117 private final static int[] validStates = new int[]{ 118 DARK, 119 RED, 120 LUNAR, 121 YELLOW, 122 GREEN, 123 FLASHRED, 124 FLASHLUNAR, 125 FLASHYELLOW, 126 FLASHGREEN 127 }; 128 private static final String[] validStateKeys = new String[]{ 129 "SignalHeadStateDark", 130 "SignalHeadStateRed", 131 "SignalHeadStateLunar", 132 "SignalHeadStateYellow", 133 "SignalHeadStateGreen", 134 "SignalHeadStateFlashingRed", 135 "SignalHeadStateFlashingLunar", 136 "SignalHeadStateFlashingYellow", 137 "SignalHeadStateFlashingGreen" 138 }; 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 public int[] getValidStates() { 145 return Arrays.copyOf(validStates, validStates.length); 146 } 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override 152 public String[] getValidStateKeys() { 153 return Arrays.copyOf(validStateKeys, validStateKeys.length); // includes int for Lunar 154 } 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public String[] getValidStateNames() { 161 String[] stateNames = new String[validStateKeys.length]; 162 int i = 0; 163 for (String stateKey : validStateKeys) { 164 stateNames[i++] = Bundle.getMessage(stateKey); 165 } 166 return stateNames; 167 } 168 169 @Override 170 public boolean isTurnoutUsed(Turnout t) { 171 if (super.isTurnoutUsed(t)) { 172 return true; 173 } 174 if (getBlue() != null && t.equals(getBlue().getBean())) { 175 return true; 176 } 177 return false; 178 } 179 180 /** 181 * Disables the feedback mechanism of the DoubleTurnoutSignalHead. 182 */ 183 @Override 184 void readOutput() { } 185 186 private final static Logger log = LoggerFactory.getLogger(TripleOutputSignalHead.class); 187 188}