001/* A source of a sequence of events. 002 003 Copyright (c) 2004-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.ArrayToken; 033import ptolemy.data.BooleanToken; 034import ptolemy.data.expr.Parameter; 035import ptolemy.data.type.ArrayType; 036import ptolemy.data.type.BaseType; 037import ptolemy.kernel.CompositeEntity; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.InternalErrorException; 040import ptolemy.kernel.util.NameDuplicationException; 041import ptolemy.kernel.util.Workspace; 042 043/////////////////////////////////////////////////////////////////// 044//// Sequence 045 046/** 047 * This actor produces a sequence of values, optionally periodically repeating 048 * them. The <i>values</i> parameter contains an ArrayToken that specifies the 049 * sequence of values to produce at the output. If the <i>enable</i> input 050 * port is connected, then it provides a boolean sequence that specifies 051 * whether to produce an output. If the <i>enable</i> is present and 052 * true, then the actor will produce the next output. Otherwise, it 053 * produces no output and will produce the next in the sequence 054 * on the next firing (if enable is true). If the <i>holdLastOutput</i> 055 * parameter is true, then the sequence is infinite, with the last 056 * value being repeated forever. 057 * <p> 058 * Compared with the Pulse actor, this actor can be enabled or disabled 059 * on each firing by providing a true or false input on the <i>enable</i> 060 * port. 061 * 062 * @author Edward A. Lee 063 * @version $Id$ 064 @since Ptolemy II 4.1 065 * @see Pulse 066 * @Pt.ProposedRating Yellow (eal) 067 * @Pt.AcceptedRating Red (cxh) 068 */ 069public class Sequence extends TypedAtomicActor { 070 /** Construct an actor in the specified container with the specified 071 * name. 072 * @param container The container. 073 * @param name The name of this actor within the container. 074 * @exception IllegalActionException If the actor cannot be contained 075 * by the proposed container. 076 * @exception NameDuplicationException If the name coincides with 077 * an actor already in the container. 078 */ 079 public Sequence(CompositeEntity container, String name) 080 throws IllegalActionException, NameDuplicationException { 081 super(container, name); 082 083 // set values parameter 084 values = new Parameter(this, "values"); 085 values.setExpression("{1}"); 086 087 // Set the Repeat Flag. 088 repeat = new Parameter(this, "repeat", BooleanToken.FALSE); 089 repeat.setTypeEquals(BaseType.BOOLEAN); 090 091 holdLastOutput = new Parameter(this, "holdLastOutput", 092 BooleanToken.FALSE); 093 holdLastOutput.setTypeEquals(BaseType.BOOLEAN); 094 095 enable = new TypedIOPort(this, "enable", true, false); 096 enable.setTypeEquals(BaseType.BOOLEAN); 097 098 output = new TypedIOPort(this, "output", false, true); 099 100 // set type constraint 101 output.setTypeAtLeast(ArrayType.elementType(values)); 102 } 103 104 /////////////////////////////////////////////////////////////////// 105 //// ports and parameters //// 106 107 /** The enable input port. If this port is connected, then its 108 * input will determine whether an output is produced in any 109 * given firing. The type is boolean. 110 */ 111 public TypedIOPort enable; 112 113 /** A flag indicating whether to interpret the <i>values</i> 114 * as an infinite sequence where the last value is repeated 115 * forever. This is a boolean that defaults to false. 116 */ 117 public Parameter holdLastOutput; 118 119 /** The output port. The type is greater than or equal to the 120 * types of the two input ports. 121 */ 122 public TypedIOPort output; 123 124 /** The flag that indicates whether the sequence needs to be 125 * repeated. If this is false, then either the last value of the 126 * sequence is repeatedly produced after the entire sequence 127 * has been produced, or the actor stops producing output, 128 * depending on the value of <i>holdLastOutput</i>. 129 * This is a boolean, and defaults to false. 130 */ 131 public Parameter repeat; 132 133 /** The values that will be produced on the output. 134 * This parameter is an array, with default value {1}. 135 */ 136 public Parameter values; 137 138 /////////////////////////////////////////////////////////////////// 139 //// public methods //// 140 141 /** Clone the actor into the specified workspace. This overrides the 142 * base class to handle type constraints. 143 * @param workspace The workspace for the new object. 144 * @return A new actor. 145 * @exception CloneNotSupportedException If a derived class contains 146 * an attribute that cannot be cloned. 147 */ 148 @Override 149 public Object clone(Workspace workspace) throws CloneNotSupportedException { 150 Sequence newObject = (Sequence) super.clone(workspace); 151 try { 152 newObject.output 153 .setTypeAtLeast(ArrayType.elementType(newObject.values)); 154 } catch (IllegalActionException e) { 155 throw new InternalErrorException(e); 156 } 157 return newObject; 158 } 159 160 /** If the <i>enable</i> input is connected, then if it has a true 161 * token, produce the next output. If it is not connected, produce 162 * the next output unconditionally. Whether it is connected is 163 * determined by checking the width of the port. 164 * @exception IllegalActionException If there is no director. 165 */ 166 @Override 167 public void fire() throws IllegalActionException { 168 super.fire(); 169 if (!enable.isOutsideConnected() || enable.hasToken(0) 170 && ((BooleanToken) enable.get(0)).booleanValue()) { 171 ArrayToken valuesArray = (ArrayToken) values.getToken(); 172 173 if (_currentIndex < valuesArray.length()) { 174 output.send(0, valuesArray.getElement(_currentIndex)); 175 _outputProduced = true; 176 } 177 } 178 } 179 180 /** Initialize the actor by resetting to the first output value. 181 * @exception IllegalActionException If there is no director. 182 */ 183 @Override 184 public void initialize() throws IllegalActionException { 185 // Note that this will default to null if there is no initialValue set. 186 _currentIndex = 0; 187 _outputProduced = false; 188 super.initialize(); 189 } 190 191 /** Update the state of the actor by moving to the next value 192 * in the <i>values</i> array. 193 * @exception IllegalActionException If there is no director. 194 */ 195 @Override 196 public boolean postfire() throws IllegalActionException { 197 boolean result = super.postfire(); 198 if (_outputProduced) { 199 _outputProduced = false; 200 _currentIndex += 1; 201 202 ArrayToken valuesArray = (ArrayToken) values.getToken(); 203 204 if (_currentIndex >= valuesArray.length()) { 205 boolean repeatValue = ((BooleanToken) repeat.getToken()) 206 .booleanValue(); 207 208 if (repeatValue) { 209 _currentIndex = 0; 210 } else { 211 boolean holdLastOutputValue = ((BooleanToken) holdLastOutput 212 .getToken()).booleanValue(); 213 if (holdLastOutputValue) { 214 // To repeatedly produce the last output. 215 _currentIndex = valuesArray.length() - 1; 216 } else { 217 // To prevent overflow. 218 _currentIndex = valuesArray.length(); 219 // No more outputs to produce. 220 result = false; 221 } 222 } 223 } 224 } 225 226 return result; 227 } 228 229 /////////////////////////////////////////////////////////////////// 230 //// private variables //// 231 // The index of the next value to be produced. 232 private int _currentIndex; 233 234 // Indicator that an output was produced. 235 private boolean _outputProduced; 236}