001/* An actor that performs a specified logic operation on the input.
002
003 Copyright (c) 1998-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.logic;
029
030import java.util.Locale;
031
032import ptolemy.actor.lib.Transformer;
033import ptolemy.data.BooleanToken;
034import ptolemy.data.Token;
035import ptolemy.data.expr.StringParameter;
036import ptolemy.data.type.BaseType;
037import ptolemy.kernel.CompositeEntity;
038import ptolemy.kernel.util.Attribute;
039import ptolemy.kernel.util.IllegalActionException;
040import ptolemy.kernel.util.InternalErrorException;
041import ptolemy.kernel.util.NameDuplicationException;
042
043// NOTE: If you update the list of functions, then you will want
044// to update the list in actor/lib/logic/logic.xml.
045///////////////////////////////////////////////////////////////////
046//// LogicGate
047
048/**
049 <p>Produce an output token on each firing with a value that is
050 equal to the specified logic operator of the input(s).
051 The functions are:</p>
052 <ul>
053 <li> <b>and</b>: The logical and operator.
054 This is the default function for this actor.</li>
055 <li> <b>or</b>: The logical or operator.</li>
056 <li> <b>xor</b>: The logical xor operator.</li>
057 <li> <b>nand</b>: The logical nand operator.
058 Equivalent to the negation of <i>and</i>.</li>
059 <li> <b>nor</b>: The logical nor operator.
060 Equivalent to the negation of <i>or</i>.</li>
061 <li> <b>xnor</b>: The logical xnor operator.
062 Equivalent to the negation of <i>xor</i>.</li>
063 </ul>
064 <p>
065 NOTE: All operators have
066 a single input port, which is a multiport, and a single output port, which
067 is not a multiport.  All ports have type boolean.</p>
068 <p>
069 This actor does not require that each input
070 channel have a token upon firing.  As long as one channel contains a
071 token, output will be produced.  If no input tokens are available at
072 all, then no output is produced.  At most one token is consumed
073 on each input channel.</p>
074
075 @author Paul Whitaker
076 @version $Id$
077 @since Ptolemy II 10.0
078 @Pt.ProposedRating Green (pwhitake)
079 @Pt.AcceptedRating Green (pwhitake)
080 */
081public class LogicGate extends Transformer {
082    /** Construct an actor with the given container and name.  Set the
083     *  logic function to the default ("and").  Set the types of the ports
084     *  to boolean.
085     *  @param container The container.
086     *  @param name The name of this actor.
087     *  @exception IllegalActionException If the actor cannot be contained
088     *   by the proposed container.
089     *  @exception NameDuplicationException If the container already has an
090     *   actor with this name.
091     */
092    public LogicGate(CompositeEntity container, String name)
093            throws NameDuplicationException, IllegalActionException {
094        super(container, name);
095
096        // Parameters
097        logic = new StringParameter(this, "logic");
098        logic.setExpression("and");
099        logic.addChoice("and");
100        logic.addChoice("or");
101        logic.addChoice("xor");
102        logic.addChoice("nand");
103        logic.addChoice("nor");
104        logic.addChoice("xnor");
105        _function = _AND;
106        _negate = false;
107
108        // Ports
109        input.setMultiport(true);
110        output.setMultiport(false);
111        input.setTypeEquals(BaseType.BOOLEAN);
112        output.setTypeEquals(BaseType.BOOLEAN);
113
114        _attachText("_iconDescription",
115                "<svg>\n" + "<rect x=\"-30\" y=\"-15\" "
116                        + "width=\"60\" height=\"30\" "
117                        + "style=\"fill:white\"/>\n" + "</svg>\n");
118    }
119
120    ///////////////////////////////////////////////////////////////////
121    ////                     ports and parameters                  ////
122
123    /** The function to compute.  This is a string-valued attribute
124     *  that defaults to "and".
125     */
126    public StringParameter logic;
127
128    ///////////////////////////////////////////////////////////////////
129    ////                         public methods                    ////
130
131    /** Override the base class to determine which function is being
132     *  specified.  Read the value of the function attribute and set
133     *  the cached value appropriately.
134     *  @param attribute The attribute that changed.
135     *  @exception IllegalActionException If the function is not recognized.
136     */
137    @Override
138    public void attributeChanged(Attribute attribute)
139            throws IllegalActionException {
140        if (attribute == logic) {
141            String functionName = logic.getExpression().trim()
142                    .toLowerCase(Locale.getDefault());
143
144            if (functionName.equals("and")) {
145                _function = _AND;
146                _negate = false;
147            } else if (functionName.equals("or")) {
148                _function = _OR;
149                _negate = false;
150            } else if (functionName.equals("xor")) {
151                _function = _XOR;
152                _negate = false;
153            } else if (functionName.equals("nand")) {
154                _function = _AND;
155                _negate = true;
156            } else if (functionName.equals("nor")) {
157                _function = _OR;
158                _negate = true;
159            } else if (functionName.equals("xnor")) {
160                _function = _XOR;
161                _negate = true;
162            } else {
163                throw new IllegalActionException(this,
164                        "Unrecognized logic function: " + functionName
165                                + ".  Valid functions are 'and', 'or', 'xor', "
166                                + "'nand', 'nor', and 'xnor'.");
167            }
168        } else {
169            super.attributeChanged(attribute);
170        }
171    }
172
173    /** Consume at most one input token from each input channel,
174     *  and produce a token on the output port.  If there is no
175     *  input on any channel, then produce no output.
176     *  @exception IllegalActionException If there is no director.
177     */
178    @Override
179    public void fire() throws IllegalActionException {
180        super.fire();
181        BooleanToken value = null;
182        BooleanToken in = null;
183
184        for (int i = 0; i < input.getWidth(); i++) {
185            if (input.hasToken(i)) {
186                in = (BooleanToken) input.get(i);
187
188                if (in != null) {
189                    value = _updateFunction(in, value);
190                }
191            }
192        }
193
194        if (value != null) {
195            if (_negate) {
196                value = value.not();
197            }
198
199            output.send(0, value);
200        }
201    }
202
203    ///////////////////////////////////////////////////////////////////
204    ////                         protected methods                 ////
205
206    /** Calculate the function on the given arguments.
207     *  @param in The new input value.  Should never be null.
208     *  @param old The old result value, or null if there is none.
209     *  @return The result of applying the function.
210     *  @exception IllegalActionException If thrown by BooleanToken operations.
211     */
212    protected BooleanToken _updateFunction(BooleanToken in, BooleanToken old)
213            throws IllegalActionException {
214        Token result;
215
216        if (old == null) {
217            result = in;
218        } else {
219            switch (_function) {
220            case _AND:
221                result = old.and(in);
222                break;
223
224            case _OR:
225                result = old.or(in);
226                break;
227
228            case _XOR:
229                result = old.xor(in);
230                break;
231
232            default:
233                throw new InternalErrorException(
234                        "Invalid value for _function private variable. "
235                                + "LogicGate actor (" + getFullName() + ")"
236                                + " on function type " + _function);
237            }
238        }
239
240        return (BooleanToken) result;
241    }
242
243    ///////////////////////////////////////////////////////////////////
244    ////                         protected variables               ////
245
246    /** An indicator for the function to compute.
247     *  Valid values are {@link #_AND}, {@link #_OR}, and {@link #_XOR}.
248     */
249    protected int _function;
250
251    /** True if the intermediate results should be negated. */
252    protected boolean _negate;
253
254    /** Perform a logical AND. */
255    protected static final int _AND = 0;
256
257    /** Perform a logical OR. */
258    protected static final int _OR = 1;
259
260    /** Perform a logical XOR. */
261    protected static final int _XOR = 2;
262}