001/* Merge streams according to a boolean parameter value. 002 003 Copyright (c) 1997-2016 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 Adapted from the BooleanSelect actor. 028 */ 029package ptolemy.actor.lib; 030 031import ptolemy.actor.Director; 032import ptolemy.actor.TypedAtomicActor; 033import ptolemy.actor.TypedIOPort; 034import ptolemy.data.BooleanToken; 035import ptolemy.data.IntToken; 036import ptolemy.data.expr.Parameter; 037import ptolemy.data.type.BaseType; 038import ptolemy.kernel.CompositeEntity; 039import ptolemy.kernel.util.Attribute; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.NameDuplicationException; 042import ptolemy.kernel.util.Settable; 043import ptolemy.kernel.util.Workspace; 044 045/////////////////////////////////////////////////////////////////// 046//// ConfigurationSelect 047 048/** 049 Conditionally merge the streams at two input ports 050 depending on the value of the boolean parameter. 051 The token in the <i>selector</i> parameter specifies the 052 input port that should be read from in the next firing. 053 If the <i>selector</i> parameter 054 token is false, then the <i>falseInput</i> port is used, 055 otherwise the <i>trueInput</i> port is used. In the next 056 firing, tokens are consumed from the specified 057 port and sent to the <i>output</i> port. 058 <p> 059 The actor is able to fire if the <i>selector</i> parameter 060 is either has a true or false token and there is a token on every 061 channel of the specified input port. 062 <p> 063 If the input port that is read has width greater than an output port, then 064 some input tokens will be discarded (those on input channels for which 065 there is no corresponding output channel). 066 <p> 067 Because tokens are immutable, the same Token is sent 068 to the output, rather than a copy. The <i>trueInput</i> and 069 <i>falseInput</i> port may receive Tokens of any type. 070 <p> 071 This actor is designed to be used with the DDF or PN director, 072 but it can also be used with SR, DE, and possibly other domains. 073 It should not be used with 074 SDF because the number of tokens it consumes is not fixed. 075 <p> 076 This actor is similar to the BooleanSelect actor, except that 077 it uses a parameter rather than a control port to determine which input 078 to use. 079 080 @author Charles Shelton and Edward A. Lee 081 @version $Id$ 082 @since Ptolemy II 8.0 083 @Pt.ProposedRating Green (cshelton) 084 @Pt.AcceptedRating Red (cshelton) 085 */ 086public class ConfigurationSelect extends TypedAtomicActor { 087 /** Construct an actor in the specified container with the specified 088 * name. 089 * @param container The container. 090 * @param name The name of this actor within the container. 091 * @exception IllegalActionException If the actor cannot be contained 092 * by the proposed container. 093 * @exception NameDuplicationException If the name coincides with 094 * an actor already in the container. 095 */ 096 public ConfigurationSelect(CompositeEntity container, String name) 097 throws IllegalActionException, NameDuplicationException { 098 super(container, name); 099 100 trueInput = new TypedIOPort(this, "trueInput", true, false); 101 trueInput.setMultiport(true); 102 falseInput = new TypedIOPort(this, "falseInput", true, false); 103 falseInput.setMultiport(true); 104 105 // Default selector value to false 106 selector = new Parameter(this, "selector", new BooleanToken(false)); 107 selector.setTypeEquals(BaseType.BOOLEAN); 108 109 output = new TypedIOPort(this, "output", false, true); 110 output.setTypeAtLeast(trueInput); 111 output.setTypeAtLeast(falseInput); 112 output.setMultiport(true); 113 output.setWidthEquals(trueInput, true); 114 output.setWidthEquals(falseInput, true); 115 116 // For the benefit of the DDF and SDF director, this actor sets 117 // consumption rate values. 118 trueInput_tokenConsumptionRate = new Parameter(trueInput, 119 "tokenConsumptionRate", _zero); 120 trueInput_tokenConsumptionRate.setVisibility(Settable.NOT_EDITABLE); 121 trueInput_tokenConsumptionRate.setTypeEquals(BaseType.INT); 122 123 falseInput_tokenConsumptionRate = new Parameter(falseInput, 124 "tokenConsumptionRate", _one); 125 falseInput_tokenConsumptionRate.setVisibility(Settable.NOT_EDITABLE); 126 falseInput_tokenConsumptionRate.setTypeEquals(BaseType.INT); 127 128 /** Make the icon show T and F for trueInput and falseInput. 129 */ 130 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-50\" y=\"-20\" " 131 + "width=\"100\" height=\"40\" " + "style=\"fill:white\"/>\n" 132 + "<text x=\"-47\" y=\"-3\" " + "style=\"font-size:14\">\n" 133 + "T \n" + "</text>\n" + "<text x=\"-47\" y=\"15\" " 134 + "style=\"font-size:14\">\n" + "F \n" + "</text>\n" 135 + "</svg>\n"); 136 } 137 138 /////////////////////////////////////////////////////////////////// 139 //// ports and parameters //// 140 141 /** Input for tokens on the true path. The type can be anything. 142 */ 143 public TypedIOPort trueInput; 144 145 /** Input for tokens on the false path. The type can be anything. 146 */ 147 public TypedIOPort falseInput; 148 149 /** Parameter that selects one of the two input ports. The type is 150 * BooleanToken that defaults to false. 151 */ 152 public Parameter selector; 153 154 /** The output port. The type is at least the type of 155 * <i>trueInput</i> and <i>falseInput</i> 156 */ 157 public TypedIOPort output; 158 159 /** This parameter provides token consumption rate for <i>trueInput</i>. 160 * The type is int and it defaults to zero. 161 */ 162 public Parameter trueInput_tokenConsumptionRate; 163 164 /** This parameter provides token consumption rate for <i>falseInput</i>. 165 * The type is int and it defaults to one. 166 */ 167 public Parameter falseInput_tokenConsumptionRate; 168 169 /////////////////////////////////////////////////////////////////// 170 //// public methods //// 171 172 /** React to a change in an attribute. This method is called by 173 * a contained attribute when its value changes. In this base class, 174 * the method does nothing. In derived classes, this method may 175 * throw an exception, indicating that the new attribute value 176 * is invalid. It is up to the caller to restore the attribute 177 * to a valid value if an exception is thrown. 178 * @param attribute The attribute that changed. 179 * @exception IllegalActionException If the change is not acceptable 180 * to this container (not thrown in this base class). 181 */ 182 @Override 183 public void attributeChanged(Attribute attribute) 184 throws IllegalActionException { 185 if (attribute == selector) { 186 boolean previousSelector = _selector; 187 _selector = ((BooleanToken) selector.getToken()).booleanValue(); 188 if (_selector != previousSelector) { 189 if (_selector) { 190 trueInput_tokenConsumptionRate.setToken(_one); 191 falseInput_tokenConsumptionRate.setToken(_zero); 192 } else { 193 trueInput_tokenConsumptionRate.setToken(_zero); 194 falseInput_tokenConsumptionRate.setToken(_one); 195 } 196 Director director = getDirector(); 197 if (director != null) { 198 director.invalidateSchedule(); 199 } 200 } 201 } 202 } 203 204 /** Clone this actor into the specified workspace. The new actor is 205 * <i>not</i> added to the directory of that workspace (you must do this 206 * yourself if you want it there). 207 * The result is a new actor with the same ports as the original, but 208 * no connections and no container. A container must be set before 209 * much can be done with this actor. 210 * 211 * @param workspace The workspace for the cloned object. 212 * @exception CloneNotSupportedException If cloned ports cannot have 213 * as their container the cloned entity (this should not occur), or 214 * if one of the attributes cannot be cloned. 215 * @return A new ComponentEntity. 216 */ 217 @Override 218 public Object clone(Workspace workspace) throws CloneNotSupportedException { 219 ConfigurationSelect newObject = (ConfigurationSelect) super.clone( 220 workspace); 221 newObject.output.setTypeAtLeast(newObject.trueInput); 222 newObject.output.setTypeAtLeast(newObject.falseInput); 223 newObject.output.setWidthEquals(newObject.trueInput, true); 224 newObject.output.setWidthEquals(newObject.falseInput, true); 225 226 return newObject; 227 } 228 229 /** Read a token from each input port. If the 230 * <i>selector</i> parameter is true, then output the token consumed from the 231 * <i>trueInput</i> port, otherwise output the token from the 232 * <i>falseInput</i> port. 233 * @exception IllegalActionException If there is no director. 234 */ 235 @Override 236 public void fire() throws IllegalActionException { 237 super.fire(); 238 if (_selector) { 239 for (int i = 0; i < trueInput.getWidth(); i++) { 240 if (output.getWidth() > i) { 241 output.send(i, trueInput.get(i)); 242 } 243 } 244 } else { 245 for (int i = 0; i < falseInput.getWidth(); i++) { 246 if (output.getWidth() > i) { 247 output.send(i, falseInput.get(i)); 248 } 249 } 250 } 251 } 252 253 /** Return false if there are not available tokens on the input 254 * port chosen by the current value of the selector. Otherwise, 255 * return true. 256 * @return False if there are not enough tokens to fire. 257 * @exception IllegalActionException If there is no director. 258 */ 259 @Override 260 public boolean prefire() throws IllegalActionException { 261 boolean result = super.prefire(); 262 if (_selector) { 263 for (int i = 0; i < trueInput.getWidth(); i++) { 264 if (!trueInput.hasToken(i)) { 265 return false; 266 } 267 } 268 } else { 269 for (int i = 0; i < falseInput.getWidth(); i++) { 270 if (!falseInput.hasToken(i)) { 271 return false; 272 } 273 } 274 } 275 return result; 276 } 277 278 /////////////////////////////////////////////////////////////////// 279 //// private variables //// 280 281 /** Cached value of selector. */ 282 private boolean _selector = false; 283 284 /** A final static IntToken with value 0. */ 285 private final static IntToken _zero = new IntToken(0); 286 287 /** A final static IntToken with value 1. */ 288 private final static IntToken _one = new IntToken(1); 289}