001/* An actor that repeats each input sample a specified number of times.
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.domains.sdf.lib;
029
030import ptolemy.actor.parameters.PortParameter;
031import ptolemy.data.IntToken;
032import ptolemy.data.Token;
033import ptolemy.data.expr.Parameter;
034import ptolemy.kernel.CompositeEntity;
035import ptolemy.kernel.util.Attribute;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038
039///////////////////////////////////////////////////////////////////
040//// Repeat
041
042/**
043 An actor that repeats a block of input tokens the specified number of times
044 on the output.  On each firing, it reads <i>blockSize</i> tokens
045 and repeats each block <i>numberOfTimes</i> times
046 on the output.  Note that this causes a sample rate increase by
047 a factor of <i>numberOfTimes</i>,
048 and hence affects the number of invocations of downstream actors.
049 If the input does not have enough tokens, then this actor does
050 nothing. If <i>blockSize</i> or <i>numberOfTimes</i> is zero,
051 then it produces no outputs.
052
053 @author Shankar Rao, Steve Neuendorffer
054 @version $Id$
055 @since Ptolemy II 1.0
056 @Pt.ProposedRating Yellow (neuendor)
057 @Pt.AcceptedRating Yellow (neuendor)
058 */
059public class Repeat extends SDFTransformer {
060    /** Construct an actor in the specified container with the specified
061     *  name.
062     *  @param container The container.
063     *  @param name The name of this Repeat actor within the container.
064     *  @exception IllegalActionException If the actor cannot be contained
065     *   by the proposed container.
066     *  @exception NameDuplicationException If the name coincides with
067     *   an actor already in the container.
068     */
069    public Repeat(CompositeEntity container, String name)
070            throws IllegalActionException, NameDuplicationException {
071        super(container, name);
072
073        // parameters
074        numberOfTimes = new PortParameter(this, "numberOfTimes",
075                new IntToken(2));
076
077        blockSize = new Parameter(this, "blockSize", new IntToken(1));
078
079        input_tokenConsumptionRate.setExpression("blockSize");
080        output_tokenProductionRate.setExpression("numberOfTimes*blockSize");
081    }
082
083    ///////////////////////////////////////////////////////////////////
084    ////                     ports and parameters                  ////
085
086    /** The repetition factor.  It is of type integer and has a default
087     *  value of 2.  It must be greater than zero.
088     */
089    public PortParameter numberOfTimes;
090
091    /** The number of tokens in a block.  It is of type integer and has a
092     *  default value of 1.  It must be greater than zero.
093     */
094    public Parameter blockSize;
095
096    ///////////////////////////////////////////////////////////////////
097    ////                         public methods                    ////
098
099    /** Ensure that the numberOfTimes parameter and the blockSize
100     *  parameter are both positive.
101     *  @param attribute The attribute that has changed.
102     *  @exception IllegalActionException If the parameters are out of range.
103     */
104    @Override
105    public void attributeChanged(Attribute attribute)
106            throws IllegalActionException {
107
108        if (attribute == numberOfTimes || attribute == blockSize) {
109            int repetitions = ((IntToken) numberOfTimes.getToken()).intValue();
110            int count = ((IntToken) blockSize.getToken()).intValue();
111
112            if (repetitions < 0) {
113                throw new IllegalActionException(numberOfTimes,
114                        "The value of numberOfTimes must be positive, but "
115                                + "was set to " + repetitions);
116            }
117
118            if (count < 1) {
119                throw new IllegalActionException(blockSize,
120                        "The value of blockSize must be positive, but "
121                                + "was set to " + count);
122            }
123        } else {
124            super.attributeChanged(attribute);
125        }
126    }
127
128    /** Consume <i>blockSize</i> input tokens from the input port.
129     *  Produce <i>blockSize*numberOfTimes</i>
130     *  tokens on the output port, consisting of <i>numberOfTimes</i>
131     *  repetitions of the input.  For example, if <i>blockSize</i> = 3 and
132     *  <i>numberOfTimes</i> = 2, then on the following input:<br>
133     *  <pre>  1 2 3 4 5 6</pre><br>
134     *  two invocations of this method will send the following output:<br>
135     *  <pre>  1 2 3 1 2 3 4 5 6 4 5 6</pre><br>
136     *  @exception IllegalActionException If there is no director.
137     */
138    @Override
139    public void fire() throws IllegalActionException {
140        super.fire();
141
142        numberOfTimes.update();
143        int repetitions = ((IntToken) numberOfTimes.getToken()).intValue();
144        int count = ((IntToken) blockSize.getToken()).intValue();
145        if (input.hasToken(0, count)) {
146            Token[] inputBlock = input.get(0, count);
147
148            for (int i = 0; i < repetitions; i += 1) {
149                output.send(0, inputBlock, count);
150            }
151        }
152    }
153}