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}