001/* A polymorphic multiplexor.
002
003 Copyright (c) 1997-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.lib;
029
030import ptolemy.actor.TypedIOPort;
031import ptolemy.data.IntToken;
032import ptolemy.data.Token;
033import ptolemy.data.type.BaseType;
034import ptolemy.kernel.CompositeEntity;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.kernel.util.NameDuplicationException;
037import ptolemy.kernel.util.StringAttribute;
038
039///////////////////////////////////////////////////////////////////
040//// Multiplexor
041
042/**
043 This actor selects from the channels on the
044 <i>input</i> port, copying the input from one channel to the output,
045 based on the most recently received value on the <i>select</i> input.
046 If the selected channel has no token, then no output is produced.
047 The <i>select</i> input is required to be an integer between 0 and
048 <i>n</i>-1, where <i>n</i> is the width of the <i>input</i> port.
049 If no token has been received on the <i>select</i> port, then null
050 is sent to the output.  The <i>input</i> port may
051 receive Tokens of any type, but all channels must have the same type.
052 <p>
053 One token is consumed from each input channel that has a token.
054 Compare this with the Select actor, which only consumes a token on
055 the selected channel.
056
057 @author Jeff Tsay, Edward A. Lee, Stavros Tripakis
058 @version $Id$
059 @since Ptolemy II 1.0
060 @Pt.ProposedRating Yellow (ctsay)
061 @Pt.AcceptedRating Yellow (cxh)
062 @see ptolemy.actor.lib.Select
063 */
064public class Multiplexor extends Transformer {
065    /** Construct an actor in the specified container with the specified
066     *  name.
067     *  @param container The container.
068     *  @param name The name of this actor within the container.
069     *  @exception IllegalActionException If the actor cannot be contained
070     *   by the proposed container.
071     *  @exception NameDuplicationException If the name coincides with
072     *   an actor already in the container.
073     */
074    public Multiplexor(CompositeEntity container, String name)
075            throws IllegalActionException, NameDuplicationException {
076        super(container, name);
077
078        input.setMultiport(true);
079
080        select = new TypedIOPort(this, "select", true, false);
081        select.setTypeEquals(BaseType.INT);
082        new StringAttribute(select, "_cardinal").setExpression("SOUTH");
083    }
084
085    ///////////////////////////////////////////////////////////////////
086    ////                     ports and parameters                  ////
087
088    /** Input for the index of the port to select. The type is IntToken. */
089    public TypedIOPort select;
090
091    ///////////////////////////////////////////////////////////////////
092    ////                         public methods                    ////
093
094    /** Read a token from the <i>select</i> port and from each channel
095     *  of the <i>input</i> port, and output a token on the selected
096     *  channel.  This method will throw a NoTokenException if any
097     *  input channel does not have a token.
098     *
099     *  @exception IllegalActionException If there is no director, or if
100     *   the <i>select</i> input is out of range.
101     */
102    @Override
103    public void fire() throws IllegalActionException {
104        super.fire();
105
106        // Be sure to not use _channel if the select input
107        // is not known. That would be non-monotonic.
108        if (select.isKnown(0)) {
109            if (select.hasToken(0)) {
110                _selectChannel = (IntToken) select.get(0);
111
112                // Perform the in-range test here, where a new channel value is obtained:
113                int c = _selectChannel.intValue();
114                if (c < 0 || c >= input.getWidth()) {
115                    throw new IllegalActionException(this,
116                            "Select input is out of range: " + c + ".");
117                }
118            }
119
120            // Be sure to read all inputs that are present, even
121            // if they aren't required in order to produce output.
122            // Tokens need to be consumed in dataflow and DE domains.
123            for (int i = 0; i < input.getWidth(); i++) {
124                if (input.isKnown(i)) {
125                    Token token = null;
126                    if (input.hasToken(i)) {
127                        token = input.get(i);
128                    }
129                    if (_selectChannel != null
130                            && _selectChannel.intValue() == i) {
131                        // Note that if the input is known to be absent,
132                        // then the following sends null. Dataflow receivers
133                        // interpret this as sending nothing (nothing is queued).
134                        // Fixed-point receivers (SR and Continuous) interpret
135                        // this as an assertion that the output is absent.
136                        output.send(0, token);
137                    }
138                }
139            }
140
141            // If no select value has been seen, then we can
142            // assert that the output is empty. Note that this is only
143            // safe if the select input is known.
144            if (_selectChannel == null) {
145                output.send(0, null);
146            }
147        }
148    }
149
150    /** Initialize to the default, which is to use channel zero.
151     *  @exception IllegalActionException If a derived class throws it.
152     */
153    @Override
154    public void initialize() throws IllegalActionException {
155        super.initialize();
156        _selectChannel = null;
157    }
158
159    /** Return false.
160     *  @return False.
161     */
162    @Override
163    public boolean isStrict() {
164        return false;
165    }
166
167    ///////////////////////////////////////////////////////////////////
168    ////                         private variables                 ////
169
170    /** The most recently read select input. */
171    private IntToken _selectChannel;
172}