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