001/* An actor that produces a copy of the most recent input each time
002 the inhibit input does not receive an event.
003
004 Copyright (c) 2001-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.domains.de.lib;
030
031import ptolemy.actor.TypedIOPort;
032import ptolemy.actor.lib.Transformer;
033import ptolemy.data.Token;
034import ptolemy.data.type.BaseType;
035import ptolemy.kernel.CompositeEntity;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.kernel.util.StringAttribute;
039import ptolemy.kernel.util.Workspace;
040
041///////////////////////////////////////////////////////////////////
042//// Inhibit
043
044/**
045 Output a received input token, unless the <i>inhibit</i> port receives a
046 token at the same time.  If no token has been received on the <i>input</i>
047 port when a token is received on the <i>inhibit</i> port, then no output is
048 produced.  The inputs can be of any token type, and the output
049 is constrained to be of a type at least that of the input.
050 <p>
051 Both the <i>input</i> port and the <i>output</i> port are multiports.
052 Generally, their widths should match. Otherwise, if the width of the
053 <i>input</i> is greater than
054 the width of the <i>output</i>, the extra input tokens will
055 not appear on any output, although they will be consumed from
056 the input port. If the width of the <i>output</i> is greater
057 than that of the <i>input</i>, then the last few
058 channels of the <i>output</i> will never emit tokens.
059 <p>
060 This actor is similar to the Sampler actor in that it modifies a
061 stream of events based on the presence or absence of events from another
062 input.  This actor reacts to the absence of the other event, whereas
063 Sampler reacts to the presence of it.
064
065 @author Steve Neuendorffer and Edward A. Lee
066 @version $Id$
067 @since Ptolemy II 2.0
068 @Pt.ProposedRating Yellow (neuendor)
069 @Pt.AcceptedRating Yellow (neuendor)
070 @see ptolemy.domains.de.lib.MostRecent
071 */
072public class Inhibit extends Transformer {
073    /** Construct an actor with the given container and name.
074     *  @param container The container.
075     *  @param name The name of this actor.
076     *  @exception IllegalActionException If the actor cannot be contained
077     *   by the proposed container.
078     *  @exception NameDuplicationException If the container already has an
079     *   actor with this name.
080     */
081    public Inhibit(CompositeEntity container, String name)
082            throws NameDuplicationException, IllegalActionException {
083        super(container, name);
084        input.setMultiport(true);
085        output.setMultiport(true);
086        output.setTypeAtLeast(input);
087        output.setWidthEquals(input, true);
088
089        inhibit = new TypedIOPort(this, "inhibit", true, false);
090        inhibit.setMultiport(true);
091        inhibit.setTypeEquals(BaseType.GENERAL);
092        StringAttribute cardinality = new StringAttribute(inhibit, "_cardinal");
093        cardinality.setExpression("SOUTH");
094
095        _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-20\" "
096                + "width=\"60\" height=\"40\" " + "style=\"fill:white\"/>\n"
097                + "<polyline points=\"0,20 0,0\"/>\n"
098                + "<polyline points=\"-30,-0 -10,0\"/>\n"
099                + "<polyline points=\"-10,-10 10,10\" style=\"stroke:red\"/>\n"
100                + "<polyline points=\"-10,10 10,-10\" style=\"stroke:red\"/>\n"
101                + "<polyline points=\"10,0 30,0\"/>\n" + "</svg>\n");
102    }
103
104    ///////////////////////////////////////////////////////////////////
105    ////                     ports and parameters                  ////
106
107    /** The inhibit port, which has type Token. If this port
108     *  does not receive a token, then the most recent token from the
109     *  <i>input</i> port will be emitted on the <i>output</i> port.
110     */
111    public TypedIOPort inhibit;
112
113    ///////////////////////////////////////////////////////////////////
114    ////                         public methods                    ////
115
116    /** Clone the actor into the specified workspace. This calls the
117     *  base class and then sets the ports.
118     *  @param workspace The workspace for the new object.
119     *  @return A new actor.
120     *  @exception CloneNotSupportedException If a derived class has
121     *   has an attribute that cannot be cloned.
122     */
123    @Override
124    public Object clone(Workspace workspace) throws CloneNotSupportedException {
125        Inhibit newObject = (Inhibit) super.clone(workspace);
126        newObject.output.setTypeAtLeast(newObject.input);
127        return newObject;
128    }
129
130    /** Consume at most one token from each channel of the
131     *  <i>input</i> port.  If there is a token on the <i>inhibit</i>
132     *  port, then consume it and discard the input tokens.  If no
133     *  token is present on the <i>inhibit</i> port, then emit the
134     *  input tokens on the <i>output</i> port.  If there are no
135     *  input tokens then no output is produced.
136     *  @exception IllegalActionException If there is no director.
137     */
138    @Override
139    public void fire() throws IllegalActionException {
140        super.fire();
141        boolean hasInhibit = false;
142        for (int i = 0; i < inhibit.getWidth(); i++) {
143            if (inhibit.hasToken(i)) {
144                // Consume the inhibit token.
145                inhibit.get(i);
146                hasInhibit = true;
147            }
148        }
149        // Consume the inputs.
150        int outputWidth = output.getWidth();
151        for (int i = 0; i < input.getWidth(); i++) {
152            if (input.hasToken(i)) {
153                Token token = input.get(i);
154                if (!hasInhibit && i < outputWidth) {
155                    output.send(i, token);
156                }
157            }
158        }
159    }
160}