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    }