001/* A register with one trigger port that accepts read requests.
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.domains.de.lib;
029
030import ptolemy.data.Token;
031import ptolemy.kernel.CompositeEntity;
032import ptolemy.kernel.util.IllegalActionException;
033import ptolemy.kernel.util.NameDuplicationException;
034
035///////////////////////////////////////////////////////////////////
036//// Register
037
038/**
039 A register is a stateful actor with a trigger port that accepts
040 read requests.
041 <p>
042 In the fire() method, if there is an event on the <i>trigger</i>
043 input port, this actor will produce an output event. The value
044 of the output event will be the previously recorded event
045 from the <i>input</i> port, or the value of the <i>initialValue</i>
046 parameter if there has been no previous input event. If, however,
047 <i>initialValue</i> contains no value, then no output will be
048 produced. In the postfire() method, if there is an input event on
049 the <i>input</i> port, then its value is recorded to be used
050 in future firings as the value of the output.
051 <p>
052 The inputs can be of any token type, but the <i>output</i> port
053 is constrained to be of a type at least that of the <i>input</i>
054 port and the <i>initialValue</i> parameter.
055 <p>
056 This class extends MostRecent. Unlike its base class, this actor
057 can be used to break dependencies in a feedback loop in that
058 the input tokens are consumed from the input ports after the outputs
059 are generated. Another difference is that the Register actor can be
060 fired when either the trigger port or the input port has a token, while
061 the Sampler can only be fired when the trigger port receives a token.
062 <p>
063 Both the <i>input</i> port and the <i>output</i> port are multiports.
064 Generally, their widths should match. Otherwise, if the width of the
065 <i>input</i> is greater than the width of the <i>output</i>, the extra
066 input tokens will not appear on any output, although they will be
067 consumed from the input port. If the width of the <i>output</i> is
068 greater than that of the <i>input</i>, then the last few channels of
069 the <i>output</i> will never emit tokens.
070 <p>
071 Note: If the width of the input changes during execution, then the
072 most recent inputs are forgotten, as if the execution of the model
073 were starting over.
074
075 @author Edward A. Lee, Haiyang Zheng
076 @version $Id$
077 @since Ptolemy II 4.1
078 @Pt.ProposedRating Yellow (eal)
079 @Pt.AcceptedRating Red (eal)
080 @see ptolemy.domains.de.lib.MostRecent
081 */
082public class Register extends MostRecent {
083    /** Construct an actor with the given container and name.
084     *  @param container The container.
085     *  @param name The name of this actor.
086     *  @exception IllegalActionException If the actor cannot be contained
087     *   by the proposed container.
088     *  @exception NameDuplicationException If the container already has an
089     *   actor with this name.
090     */
091    public Register(CompositeEntity container, String name)
092            throws NameDuplicationException, IllegalActionException {
093        super(container, name);
094
095        _attachText("_iconDescription",
096                "<svg>\n" + "<rect x=\"-10\" y=\"-20\" "
097                        + "width=\"20\" height=\"40\" "
098                        + "style=\"fill:white\"/>\n" + "</svg>\n");
099    }
100
101    ///////////////////////////////////////////////////////////////////
102    ////                         public methods                    ////
103
104    /** Declare that the <i>output</i>
105     *  does not depend on the <i>input</i> in a firing.
106     *  @exception IllegalActionException If the causality interface
107     *  cannot be computed.
108     *  @see #getCausalityInterface()
109     */
110    @Override
111    public void declareDelayDependency() throws IllegalActionException {
112        // Declare that output does not immediately depend on the input.
113        _declareDelayDependency(input, output, 0.0);
114        // Note the dependency between trigger and output port is not
115        // declared. This is because declaring a dependency
116        // of 0.0 really means (0.0, 1) (i.e., the output does not
117        // immediately depend on the trigger). However, in this case the
118        // output could immediately depend on the trigger port.
119    }
120
121    /** If there is a token in the <i>trigger</i> port, emit the previously
122     *  seen inputs from the <i>input</i> port. If there has been no
123     *  previous input tokens, but the <i>initialValue</i> parameter
124     *  has been set, emit the value of the <i>initialValue</i> parameter.
125     *  Otherwise, emit nothing.
126     *  @exception IllegalActionException If there is no director.
127     */
128    @Override
129    public void fire() throws IllegalActionException {
130        // Don't call "super.fire();", this actor extends another actor.
131        int inputWidth = input.getWidth();
132        int outputWidth = output.getWidth();
133        int commonWidth = Math.min(inputWidth, outputWidth);
134
135        // If the <i>initialValue</i> parameter was not set, or if the
136        // width of the input has changed.
137        if (_lastInputs == null || _lastInputs.length != inputWidth) {
138            _lastInputs = new Token[inputWidth];
139        }
140
141        sendOutputIfTriggered(commonWidth);
142    }
143
144    /** Indicate that this actor can fire even if the inputs are not
145     *  known. This enables the actor to be used in SR and Continuous.
146     *  @return False.
147     */
148    @Override
149    public boolean isStrict() {
150        return false;
151    }
152
153    /** Read and record the inputs.
154     *  @return What the superclass returns.
155     *  @exception IllegalActionException If the superclass throws it.
156     */
157    @Override
158    public boolean postfire() throws IllegalActionException {
159        int inputWidth = input.getWidth();
160        int outputWidth = output.getWidth();
161        int commonWidth = Math.min(inputWidth, outputWidth);
162        readInputs(commonWidth, inputWidth);
163        return super.postfire();
164    }
165
166    /** Return true if there is any token in the input or the trigger
167     *  port. This ensures that if an input is provided without a
168     *  trigger, it will get recorded.
169     *  @exception IllegalActionException If the base class throws it.
170     */
171    @Override
172    public boolean prefire() throws IllegalActionException {
173        boolean inputPresent = false;
174
175        if (input.isOutsideConnected()) {
176            for (int i = 0; i < input.getWidth(); i++) {
177                if (input.hasToken(0)) {
178                    inputPresent = true;
179                    break;
180                }
181            }
182        }
183        return inputPresent || super.prefire();
184    }
185}