001/* A polymorphic multiplexor with boolean select.
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.TypedAtomicActor;
031import ptolemy.actor.TypedIOPort;
032import ptolemy.data.BooleanToken;
033import ptolemy.data.Token;
034import ptolemy.data.type.BaseType;
035import ptolemy.kernel.CompositeEntity;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.kernel.util.StringAttribute;
039
040///////////////////////////////////////////////////////////////////
041//// BooleanMultiplexor
042
043/**
044 A multiplexor with a boolean-valued select control signal.
045 This actor conditionally routes input values from the
046 {@link #trueInput} and {@link #falseInput} ports to the
047 output port, depending on the value of the {@link #select} input.
048 <p>
049 Upon firing, this actor reads the value at the {@link #select} input,
050 if there is one, and records its value (true or false).
051 If it has a recorded select value (from this firing or a previous
052 one), then it reads at most one token from both the
053 {@link #trueInput} and the {@link #falseInput}, chooses one
054 of those tokens depending on the recorded select value,
055 and produces that token on the output.
056 Because tokens are immutable, the same Token
057 is sent to the output, rather than a copy.
058 <p>
059 This actor is non strict. Specifically, if either
060 {@link #trueInput} or {@link #falseInput} is unknown, it may
061 nonetheless be able to produce an output. Hence, this actor can
062 be used in domains with fixed-point semantics, such as SR and Continuous.
063 <p>
064 In dataflow domains (SDF, DDF, and PN), normally all inputs will be
065 known and present when the actor fires. It consumes all inputs
066 and produces one output token. Thus, the actor behaves like an SDF
067 actor, producing and consuming a single token on all ports.
068 <p>
069 In DE, the actor will only consume those inputs that are available.
070 It does not even require a new {@link #select} input on each firing.
071 A value provided at the {@link #select} input will persist
072 and will be used in subsequent firings until a new value is provided.
073 If no value has ever been provided, then this actor will produce no output.
074 <p>
075 This actor is different from the {@link BooleanSelect} actor, which consumes
076 one token from the control input in one firing, and
077 then in the next firing consumes a token from either the
078 trueInput or the falseInput, depending on the value of the control input.
079 It is also different from the {@link Select} actor, which consumes
080 one input from the control input and, in the same firing, one token
081 from the input channel given by the value of the control input.
082 </p>
083
084 @author Steve Neuendorffer, Stavros Tripakis, Edward A. Lee
085 @version $Id$
086 @since Ptolemy II 2.0
087 @Pt.ProposedRating Green (neuendor)
088 @Pt.AcceptedRating Yellow (neuendor)
089 */
090public class BooleanMultiplexor extends TypedAtomicActor {
091    /** Construct an actor in the specified container with the specified
092     *  name.
093     *  @param container The container.
094     *  @param name The name of this actor within the container.
095     *  @exception IllegalActionException If the actor cannot be contained
096     *   by the proposed container.
097     *  @exception NameDuplicationException If the name coincides with
098     *   an actor already in the container.
099     */
100    public BooleanMultiplexor(CompositeEntity container, String name)
101            throws IllegalActionException, NameDuplicationException {
102        super(container, name);
103
104        trueInput = new TypedIOPort(this, "trueInput", true, false);
105        falseInput = new TypedIOPort(this, "falseInput", true, false);
106        select = new TypedIOPort(this, "select", true, false);
107        select.setTypeEquals(BaseType.BOOLEAN);
108        output = new TypedIOPort(this, "output", false, true);
109        output.setTypeAtLeast(trueInput);
110        output.setTypeAtLeast(falseInput);
111
112        new StringAttribute(select, "_cardinal").setExpression("SOUTH");
113    }
114
115    ///////////////////////////////////////////////////////////////////
116    ////                     ports and parameters                  ////
117
118    /** Input for tokens on the true path.  The type can be anything.
119     */
120    public TypedIOPort trueInput;
121
122    /** Input for tokens on the false path.  The type can be anything.
123     */
124    public TypedIOPort falseInput;
125
126    /** Input that selects one of the other input ports.  The type is
127     *  boolean.
128     */
129    public TypedIOPort select;
130
131    /** The output port.  The type is at least the type of
132     *  <i>trueInput</i> and <i>falseInput</i>
133     */
134    public TypedIOPort output;
135
136    ///////////////////////////////////////////////////////////////////
137    ////                         public methods                    ////
138
139    /** Read all inputs that are known, and if the <i>select</i> input
140     *  is true, then output the token consumed from the
141     *  <i>trueInput</i> port, otherwise output the token from the
142     *  <i>falseInput</i> port.
143     *  If the required input is unknown, then the output will
144     *  remain unknown.
145     *  @exception IllegalActionException If there is no director.
146     */
147    @Override
148    public void fire() throws IllegalActionException {
149        super.fire();
150        // Be sure to not use _selectValue if the select input
151        // is not known. That would be non-monotonic.
152        if (select.isKnown(0)) {
153            if (select.hasToken(0)) {
154                _selectValue = (BooleanToken) select.get(0);
155            }
156            // Be sure to read all inputs that are present, even
157            // if they aren't required in order to produce output.
158            // Tokens need to be consumed in dataflow and DE domains.
159            if (trueInput.isKnown(0)) {
160                Token trueToken = null;
161                if (trueInput.hasToken(0)) {
162                    trueToken = trueInput.get(0);
163                }
164                if (_selectValue != null && _selectValue.booleanValue()) {
165                    // Note that if the input is known to be absent,
166                    // then the following sends null. Dataflow receivers
167                    // interpret this as sending nothing (nothing is queued).
168                    // Fixed-point receivers (SR and Continuous) interpret
169                    // this as an assertion that the output is absent.
170                    output.send(0, trueToken);
171                }
172            }
173            if (falseInput.isKnown(0)) {
174                Token falseToken = null;
175                if (falseInput.hasToken(0)) {
176                    falseToken = falseInput.get(0);
177                }
178                if (_selectValue != null && !_selectValue.booleanValue()) {
179                    // Note that if the input is known to be absent,
180                    // then the following sends null. Dataflow receivers
181                    // interpret this as sending nothing (nothing is queued).
182                    // Fixed-point receivers (SR and Continuous) interpret
183                    // this as an assertion that the output is absent.
184                    output.send(0, falseToken);
185                }
186            }
187            // If no select value has been seen, then we can
188            // assert that the output is empty. Note that this is only
189            // safe if the select input is known.
190            if (_selectValue == null) {
191                output.send(0, null);
192            }
193        }
194    }
195
196    /** Initialize this actor to the state where no select
197     *  input has been read.
198     *  @exception IllegalActionException If the superclass throws it.
199     */
200    @Override
201    public void initialize() throws IllegalActionException {
202        super.initialize();
203        _selectValue = null;
204    }
205
206    /** Return false.
207     *  @return False.
208     */
209    @Override
210    public boolean isStrict() {
211        return false;
212    }
213
214    ///////////////////////////////////////////////////////////////////
215    ////                         private fields                    ////
216
217    /** Most recently read select input. */
218    private BooleanToken _selectValue;
219}