001/* A line coder, which converts a sequence of booleans into symbols.
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.domains.sdf.lib;
029
030import ptolemy.data.ArrayToken;
031import ptolemy.data.BooleanToken;
032import ptolemy.data.IntToken;
033import ptolemy.data.Token;
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//// LineCoder
045
046/**
047 A line coder, which converts a sequence of booleans into symbols.
048
049 @author Edward A. Lee, Steve Neuendorffer
050 @version $Id$
051 @since Ptolemy II 0.2
052 @Pt.ProposedRating Green (eal)
053 @Pt.AcceptedRating Yellow (cxh)
054 */
055public class LineCoder extends SDFTransformer {
056    /** Construct an actor with the given container and name.
057     *  @param container The container.
058     *  @param name The name of this actor.
059     *  @exception IllegalActionException If the actor cannot be contained
060     *   by the proposed container.
061     *  @exception NameDuplicationException If the container already has an
062     *   actor with this name.
063     */
064    public LineCoder(CompositeEntity container, String name)
065            throws NameDuplicationException, IllegalActionException {
066        super(container, name);
067
068        input.setTypeEquals(BaseType.BOOLEAN);
069
070        table = new Parameter(this, "table");
071        table.setExpression("{-1.0, 1.0}");
072        attributeChanged(table);
073
074        wordLength = new Parameter(this, "wordLength", new IntToken(1));
075        wordLength.setTypeEquals(BaseType.INT);
076
077        // Type constraints.
078        output.setTypeAtLeast(ArrayType.elementType(table));
079    }
080
081    ///////////////////////////////////////////////////////////////////
082    ////                         public variables                  ////
083
084    /** The code table.  Its value is a token of type ArrayToken.
085     *  The array provides the symbol values to produce on the output.
086     *  The number of values in this array must be at least
087     *  2<sup><i>wordLength</i></sup>, or an exception
088     *  will be thrown.  The number of tokens consumed by this actor when
089     *  it fires is log<sub>2</sub>(<i>tableSize</i>), where
090     *  <i>tableSize</i> is the length of the table.  If all of these
091     *  values are <i>false</i>, then the first array entry is produced
092     *  as an output.  If only the first one is true, then then second
093     *  array value is produced.  In general, the <i>N</i> inputs consumed
094     *  are taken to be a binary digit that indexes the array,
095     *  where the first input is taken to be the low-order bit of the array.
096     *  The default code table has two entries, -1.0
097     *  and 1.0, so that input <i>false</i> values are mapped to -1.0,
098     *  and input <i>true</i> values are mapped to +1.0.
099     */
100    public Parameter table;
101
102    /** The word length is the number of boolean inputs that are consumed
103     *  to construct an index into the table.  Its value is an IntToken,
104     *  with default value one.
105     */
106    public Parameter wordLength;
107
108    ///////////////////////////////////////////////////////////////////
109    ////                         public methods                    ////
110
111    /** Clone the actor into the specified workspace. This calls the
112     *  base class and then resets the type constraints.
113     *  @param workspace The workspace for the new object.
114     *  @return A new actor.
115     *  @exception CloneNotSupportedException If a derived class contains
116     *   an attribute that cannot be cloned.
117     */
118    @Override
119    public Object clone(Workspace workspace) throws CloneNotSupportedException {
120        LineCoder newObject = (LineCoder) super.clone(workspace);
121
122        // set the type constraints
123        try {
124            newObject.output
125                    .setTypeAtLeast(ArrayType.elementType(newObject.table));
126        } catch (IllegalActionException e) {
127            throw new InternalErrorException(e);
128        }
129
130        return newObject;
131    }
132
133    /** Consume the inputs and produce the corresponding symbol.
134     *  @exception IllegalActionException If a runtime type error occurs.
135     */
136    @Override
137    public void fire() throws IllegalActionException {
138        super.fire();
139
140        int tableAddress = 0;
141        Token[] tokens = input.get(0, _wordLength);
142
143        for (int i = 0; i < _wordLength; i++) {
144            boolean data = ((BooleanToken) tokens[i]).booleanValue();
145
146            if (data) {
147                tableAddress |= 1 << i;
148            }
149        }
150
151        output.send(0, _table[tableAddress]);
152    }
153
154    /** Set up the consumption constant.
155     *  @exception IllegalActionException If the length of the table is not
156     *   a power of two.
157     */
158    @Override
159    public void preinitialize() throws IllegalActionException {
160        super.preinitialize();
161
162        _wordLength = ((IntToken) wordLength.getToken()).intValue();
163
164        // Set the token consumption rate.
165        input_tokenConsumptionRate.setToken(new IntToken(_wordLength));
166
167        ArrayToken tableToken = (ArrayToken) table.getToken();
168        int size = (int) Math.pow(2, _wordLength);
169
170        if (tableToken.length() < size) {
171            throw new IllegalActionException(this,
172                    "Table parameter must " + "have at least " + size
173                            + " entries, but only has " + tableToken.length());
174        }
175
176        _table = tableToken.arrayValue();
177    }
178
179    ///////////////////////////////////////////////////////////////////
180    ////                         private variables                 ////
181    // Local cache of these parameter values.
182    private int _wordLength;
183
184    private Token[] _table;
185}