001/* Split a stream into two according to a boolean control signal. 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 Switch and could be design/code reviewed at the same time. 028 */ 029package ptolemy.actor.lib; 030 031import ptolemy.actor.TypedAtomicActor; 032import ptolemy.actor.TypedIOPort; 033import ptolemy.data.BooleanToken; 034import ptolemy.data.Token; 035import ptolemy.data.type.BaseType; 036import ptolemy.kernel.CompositeEntity; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NameDuplicationException; 039import ptolemy.kernel.util.StringAttribute; 040import ptolemy.kernel.util.Workspace; 041 042/////////////////////////////////////////////////////////////////// 043//// BooleanSwitch 044 045/** 046 Split an input stream onto two output ports depending on a 047 boolean control input. In an 048 iteration, if an input token is available at the <i>control</i> input, 049 that token is read, and its value is noted. Its value specifies the 050 output port that should be written to in this and subsequent iterations, 051 until another <i>control</i> input is provided. If no <i>control</i> 052 input is provided, then the inputs are routed to the <i>falseOutput</i> port. 053 In each iteration, at most one token on each channel of the <i>input</i> port 054 is read and sent to the corresponding channel of the 055 <i>trueOutput</i> port or the <i>falseOutput</i> port, depending on the 056 most recently received <i>control</i> input. 057 If the input has width greater than an output port, then 058 some input tokens will be discarded (those on input channels for which 059 there is no corresponding output channel). 060 Because tokens are 061 immutable, the same Token is sent to the output, rather than a copy. 062 The <i>input</i> port may receive Tokens of any type. 063 064 <p>Note that the this actor may be used in Synchronous Dataflow (SDF) 065 models, but only under certain circumstances. Specifically, downstream 066 actors will be fired whether a token is sent to them or not. 067 This will only work if the downstream actors specifically check to 068 see whether input tokens are available. 069 070 @author Steve Neuendorffer 071 @version $Id$ 072 @since Ptolemy II 2.0 073 @Pt.ProposedRating Green (neuendor) 074 @Pt.AcceptedRating Red (neuendor) 075 */ 076public class BooleanSwitch extends TypedAtomicActor { 077 /** Construct an actor in the specified container with the specified 078 * name. 079 * @param container The container. 080 * @param name The name of this actor within the container. 081 * @exception IllegalActionException If the actor cannot be contained 082 * by the proposed container. 083 * @exception NameDuplicationException If the name coincides with 084 * an actor already in the container. 085 */ 086 public BooleanSwitch(CompositeEntity container, String name) 087 throws IllegalActionException, NameDuplicationException { 088 super(container, name); 089 090 input = new TypedIOPort(this, "input", true, false); 091 input.setMultiport(true); 092 093 control = new TypedIOPort(this, "control", true, false); 094 control.setTypeEquals(BaseType.BOOLEAN); 095 trueOutput = new TypedIOPort(this, "trueOutput", false, true); 096 falseOutput = new TypedIOPort(this, "falseOutput", false, true); 097 trueOutput.setTypeAtLeast(input); 098 falseOutput.setTypeAtLeast(input); 099 trueOutput.setMultiport(true); 100 falseOutput.setMultiport(true); 101 trueOutput.setWidthEquals(input, true); 102 falseOutput.setWidthEquals(input, true); 103 104 // Put the control input on the bottom of the actor. 105 StringAttribute controlCardinal = new StringAttribute(control, 106 "_cardinal"); 107 controlCardinal.setExpression("SOUTH"); 108 } 109 110 /////////////////////////////////////////////////////////////////// 111 //// ports and parameters //// 112 113 /** Input that selects one of the other input ports. The type is 114 * boolean. 115 */ 116 public TypedIOPort control; 117 118 /** The input port. The type can be anything. This is a multiport, 119 * and input tokens on all channels are routed to corresponding 120 * channels on the output port, if there are such channels. 121 */ 122 public TypedIOPort input; 123 124 /** Output for tokens on the true path. The type is at least the 125 * type of the input. 126 */ 127 public TypedIOPort trueOutput; 128 129 /** Output for tokens on the false path. The type is at least the 130 * type of the input. 131 */ 132 public TypedIOPort falseOutput; 133 134 /////////////////////////////////////////////////////////////////// 135 //// public methods //// 136 137 /** Clone this actor into the specified workspace. The new actor is 138 * <i>not</i> added to the directory of that workspace (you must do this 139 * yourself if you want it there). 140 * The result is a new actor with the same ports as the original, but 141 * no connections and no container. A container must be set before 142 * much can be done with this actor. 143 * 144 * @param workspace The workspace for the cloned object. 145 * @exception CloneNotSupportedException If cloned ports cannot have 146 * as their container the cloned entity (this should not occur), or 147 * if one of the attributes cannot be cloned. 148 * @return A new ComponentEntity. 149 */ 150 @Override 151 public Object clone(Workspace workspace) throws CloneNotSupportedException { 152 BooleanSwitch newObject = (BooleanSwitch) super.clone(workspace); 153 newObject.trueOutput.setTypeAtLeast(newObject.input); 154 newObject.falseOutput.setTypeAtLeast(newObject.input); 155 newObject.trueOutput.setWidthEquals(newObject.input, true); 156 newObject.falseOutput.setWidthEquals(newObject.input, true); 157 158 return newObject; 159 } 160 161 /** Read a token from each input port. If the token from the 162 * <i>control</i> input is true, then output the token consumed from the 163 * <i>input</i> port on the <i>trueOutput</i> port, 164 * otherwise output the token on the <i>falseOutput</i> port. 165 * 166 * @exception IllegalActionException If there is no director. 167 */ 168 @Override 169 public void fire() throws IllegalActionException { 170 super.fire(); 171 if (control.hasToken(0)) { 172 _control = ((BooleanToken) control.get(0)).booleanValue(); 173 } 174 175 for (int i = 0; i < input.getWidth(); i++) { 176 if (input.hasToken(i)) { 177 Token token = input.get(i); 178 179 if (_control) { 180 if (i < trueOutput.getWidth()) { 181 trueOutput.send(i, token); 182 } 183 } else { 184 if (i < falseOutput.getWidth()) { 185 falseOutput.send(i, token); 186 } 187 } 188 } 189 } 190 } 191 192 /** Initialize this actor so that the <i>falseOutput</i> is written 193 * to until a token arrives on the <i>control</i> input. 194 * @exception IllegalActionException If the parent class throws it. 195 */ 196 @Override 197 public void initialize() throws IllegalActionException { 198 super.initialize(); 199 _control = false; 200 } 201 202 /////////////////////////////////////////////////////////////////// 203 //// private variables //// 204 // The most recently read control token. 205 private boolean _control = false; 206}