001 package edu.nrao.sss.electronics; 002 003 import java.util.ArrayList; 004 import java.util.List; 005 006 /** 007 * A special kind of switch that provides a one-to-one mapping of its 008 * N input poles to its N output poles. A given input may be connected 009 * to either its immediate clockwise or immediate counterclockwise 010 * neighbor. 011 * <p/> 012 * <table width="50%"> 013 * <tr> 014 * <td>The following is an example taken from the EVLA Antenna Block 015 * Diagram whose N value is 2:</td> 016 * <td><img src="doc-files/xferSwitch2pole.png"/></td> 017 * </tr> 018 * </table> 019 * <p> 020 * <b>Version Info:</b> 021 * <table style="margin-left:2em"> 022 * <tr><td>$Revision: 1035 $</td></tr> 023 * <tr><td>$Date: 2008-01-10 16:49:07 -0700 (Thu, 10 Jan 2008) $</td></tr> 024 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 025 * </table></p> 026 * 027 * @author David M. Harland 028 * @since 2007-11-02 029 */ 030 public class SignalTransferSwitch 031 implements SignalProcessor 032 { 033 private static final String DEFAULT_NAME = "[unnamed xfer switch]"; 034 035 private String name; 036 037 private List<SignalPipe> inputPipes; 038 private List<SignalPipe> outputPipes; 039 040 private List<SignalPipe> internalInputPipes; 041 private List<SignalPipe> internalOutputPipes; 042 043 private int size; 044 045 private boolean isClockwise; 046 047 //============================================================================ 048 // OBJECT CREATION 049 //============================================================================ 050 051 /** 052 * Creates a new transfer switch with the number of input and output poles 053 * set to {@code numInputs}. The returned switch is initially configured 054 * so that inputs are connected to their clockwise outputs. 055 * 056 * @param deviceName 057 * an optional name for this switch. If this value is <i>null</i> 058 * a default name will be used in its place. 059 * 060 * @param numInputs 061 * the number of input and output poles on this switch. 062 */ 063 public SignalTransferSwitch(String deviceName, int numInputs) 064 { 065 name = (deviceName == null) ? DEFAULT_NAME : deviceName; 066 067 inputPipes = new ArrayList<SignalPipe>(numInputs); 068 outputPipes = new ArrayList<SignalPipe>(numInputs); 069 070 internalInputPipes = new ArrayList<SignalPipe>(numInputs); 071 internalOutputPipes = new ArrayList<SignalPipe>(numInputs); 072 073 for (int p=0; p < numInputs; p++) 074 { 075 SignalPipe internalInput = new SignalPipe(); 076 internalInputPipes.add(internalInput); 077 inputPipes.add(SignalPipe.makeAndWeldOutputTo(internalInput)); 078 } 079 080 for (int p=0; p < numInputs; p++) 081 { 082 SignalPipe internalOutput = new SignalPipe(); 083 internalOutputPipes.add(internalOutput); 084 outputPipes.add(SignalPipe.makeAndWeldInputTo(internalOutput)); 085 } 086 087 size = numInputs; 088 isClockwise = false; //just to ensure setToClockwise does its job 089 090 setToClockwiseOutputs(); 091 } 092 093 //============================================================================ 094 // 095 //============================================================================ 096 097 /** 098 * Returns the name of this switch. 099 * @return the name of this switch. 100 */ 101 public String getName() 102 { 103 return name; 104 } 105 106 //============================================================================ 107 // SETTING THE SWITCH 108 //============================================================================ 109 110 /** 111 * Turns this switch so that all the inputs now use their other outputs. 112 * That is, if the inputs were sent to their clockwise outputs before this 113 * call, they will be sent to their counterclockwise outputs after this call, 114 * and vice versa. 115 */ 116 public void twist() 117 { 118 if (isClockwise) 119 setToCounterclockwiseOutputs(); 120 else 121 setToClockwiseOutputs(); 122 } 123 124 /** 125 * Sets this switch so that its inputs are connected to their clockwise 126 * outputs. 127 */ 128 public void setToClockwiseOutputs() 129 { 130 if (!isClockwise) 131 { 132 breakAllInternalConnections(); 133 134 for (int p=0; p < size; p++) 135 internalInputPipes.get(p).connectOutputTo(internalOutputPipes.get(p)); 136 137 isClockwise = true; 138 } 139 } 140 141 /** 142 * Sets this switch so that its inputs are connected to their anticlockwise 143 * outputs. 144 */ 145 public void setToCounterclockwiseOutputs() 146 { 147 if (isClockwise) 148 { 149 breakAllInternalConnections(); 150 151 internalInputPipes.get(0).connectOutputTo(internalOutputPipes.get(size-1)); 152 153 for (int p=1; p < size; p++) 154 internalInputPipes.get(p).connectOutputTo(internalOutputPipes.get(p-1)); 155 156 isClockwise = false; 157 } 158 } 159 160 /** Helps the methods that change this switch's position. */ 161 private void breakAllInternalConnections() 162 { 163 for (int p=0; p < size; p++) 164 { 165 internalInputPipes.get(p).disconnectOutput(); 166 internalOutputPipes.get(p).disconnectInput(); 167 } 168 } 169 170 /** 171 * Returns <i>true</i> if this switch is set such that the inputs are 172 * piped to the outputs in a clockwise direction. 173 * 174 * @return <i>true</i> if this switch is set to its clockwise orientation. 175 */ 176 public boolean isSetToClockwise() 177 { 178 return isClockwise; 179 } 180 181 /** 182 * Returns the {@code index}<sup>th</sup> input pipe of this device. 183 * A typical usage pattern for this method is:<pre> 184 * mySwitch.getInputPipe(p).connectInputTo(mySource);</pre> 185 * <p> 186 * Indexing begins at zero.</p> 187 * 188 * @return the {@code index}<sup>th</sup> input pipe of this device. 189 */ 190 public SignalPipe getInputPipe(int index) 191 { 192 return inputPipes.get(index); 193 } 194 195 /** 196 * Returns the {@code index}<sup>th</sup> output pipe of this device. 197 * A typical usage pattern for this method is:<pre> 198 * mySwitch.getOutputPipe(p).connectOutputTo(myProcessor);</pre> 199 * <p> 200 * Indexing begins at zero.</p> 201 * 202 * @return the {@code index}<sup>th</sup> output pipe of this device. 203 */ 204 public SignalPipe getOutputPipe(int index) 205 { 206 return outputPipes.get(index); 207 } 208 209 //============================================================================ 210 // INTERFACE SignalProcessor 211 //============================================================================ 212 213 /** 214 * Runs the inputs to this switch from their beginnings and then 215 * executes the output pipes of this device. 216 */ 217 public void execute() 218 { 219 for (SignalPipe input : inputPipes) 220 input.executeFromStartOfChainUpTo(input.output); 221 222 //Tell next elements of chain to do their work 223 for (SignalPipe output : outputPipes) 224 output.execute(); 225 } 226 227 public void executeUpTo(SignalProcessor firstUnexecutedDevice) 228 { 229 //Quick exit if execution should not occur 230 if (firstUnexecutedDevice == this) 231 return; 232 233 //Tell next elements of chain to do their work 234 for (SignalPipe output : outputPipes) 235 output.executeUpTo(firstUnexecutedDevice); 236 } 237 238 public void executeFromStartOfChainUpTo(SignalProcessor firstUnexecutedDevice) 239 { 240 //Force all the inputs to execute, but don't let their chains 241 //trigger execution of this switch yet. 242 for (SignalPipe input : inputPipes) 243 input.executeFromStartOfChainUpTo(this); 244 245 //Now that all the inputs are up to date, continue execution from here 246 executeUpTo(firstUnexecutedDevice); 247 } 248 }