001/* Descramble the input bit sequence using a feedback shift register.
002
003 Copyright (c) 2003-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.comm;
029
030import ptolemy.actor.lib.Transformer;
031import ptolemy.data.BooleanToken;
032import ptolemy.data.IntToken;
033import ptolemy.data.expr.Parameter;
034import ptolemy.data.type.BaseType;
035import ptolemy.kernel.CompositeEntity;
036import ptolemy.kernel.util.Attribute;
037import ptolemy.kernel.util.IllegalActionException;
038import ptolemy.kernel.util.NameDuplicationException;
039
040///////////////////////////////////////////////////////////////////
041//// DeScrambler
042
043/**
044 Descramble the input bit sequence using a feedback shift register.
045 The taps of the feedback shift register are given by the <i>polynomial</i>
046 parameter. The initial state of the shift register is given by the
047 <i>initialState</i> parameter. This is a self-synchronizing descrambler that
048 will exactly reverse the operation of the Scrambler if the polynomials
049 are the same. The low-order bit of the polynomial should always be set.
050 For more information, see the documentation for the Scrambler actor
051 and Lee and Messerschmitt, Digital Communication, Second Edition,
052 Kluwer Academic Publishers, 1994, pp. 595-603.
053 <p>
054 @author Edward A. Lee and Ye Zhou
055 @version $Id$
056 @since Ptolemy II 3.0
057 @Pt.ProposedRating Red (eal)
058 @Pt.AcceptedRating Red (cxh)
059 */
060public class DeScrambler extends Transformer {
061    /** Construct an actor with the given container and name.
062     *  The output and trigger ports are also constructed.
063     *  @param container The container.
064     *  @param name The name of this actor.
065     *  @exception IllegalActionException If the entity cannot be contained
066     *   by the proposed container.
067     *  @exception NameDuplicationException If the container already has an
068     *   actor with this name.
069     */
070    public DeScrambler(CompositeEntity container, String name)
071            throws NameDuplicationException, IllegalActionException {
072        super(container, name);
073
074        polynomial = new Parameter(this, "polynomial");
075        polynomial.setTypeEquals(BaseType.INT);
076        polynomial.setExpression("0440001");
077
078        initialState = new Parameter(this, "initialState");
079        initialState.setTypeEquals(BaseType.INT);
080        initialState.setExpression("1");
081
082        // Declare input data type.
083        input.setTypeEquals(BaseType.BOOLEAN);
084
085        // Declare output data type.
086        output.setTypeEquals(BaseType.BOOLEAN);
087    }
088
089    ///////////////////////////////////////////////////////////////////
090    ////                     ports and parameters                  ////
091
092    /** Integer defining a polynomial with binary coefficients.
093     *  The coefficients indicate the presence (1) or absence (0)
094     *  of a tap in a feedback shift register. This parameter should
095     *  contain a positive integer with the lower-order bit being 1.
096     *  Its default value is the integer 0440001.
097     */
098    public Parameter polynomial;
099
100    /** Integer defining the initial state of the shift register.
101     *  The n-th bit of the integer indicates the value of the
102     *  n-th register. This parameter should be a non-negative
103     *  integer. Its default value is the integer 1.
104     */
105    public Parameter initialState;
106
107    ///////////////////////////////////////////////////////////////////
108    ////                         public methods                    ////
109
110    /** If the attribute being changed is <i>polynomial</i>, then
111     *  verify that is a positive integer and the lower-order bit is 1.
112     *  @param attribute The attribute that changed.
113     *  @exception IllegalActionException If <i>polynomial</i> is
114     *  non-positive or the lower-order bit is not 1.
115     */
116    @Override
117    public void attributeChanged(Attribute attribute)
118            throws IllegalActionException {
119        if (attribute == polynomial) {
120            int mask = ((IntToken) polynomial.getToken()).intValue();
121
122            if (mask <= 0) {
123                throw new IllegalActionException(this,
124                        "Polynomial is required to be strictly positive.");
125            }
126
127            if ((mask & 1) == 0) {
128                throw new IllegalActionException(this,
129                        "The low-order bit of the the polynomial is not set.");
130            }
131        } else {
132            super.attributeChanged(attribute);
133        }
134    }
135
136    /** Read bit from the input port and fill it into the shift register
137     *  to descramble. Compute the parity and send it to the output port.
138     */
139    @Override
140    public void fire() throws IllegalActionException {
141        super.fire();
142        _latestShiftReg = _shiftReg;
143
144        int mask = ((IntToken) polynomial.getToken()).intValue();
145        BooleanToken inputToken = (BooleanToken) input.get(0);
146        boolean inputTokenValue = inputToken.booleanValue();
147        int reg = _latestShiftReg << 1;
148
149        // Put the input in the low-order bit.
150        reg = reg ^ (inputTokenValue ? 1 : 0);
151
152        // Find the parity of "masked".
153        int masked = mask & reg;
154        int parity = 0;
155
156        // Calculate the parity of the masked word.
157        while (masked > 0) {
158            parity = parity ^ masked & 1;
159            masked = masked >> 1;
160        }
161
162        _latestShiftReg = reg;
163
164        if (parity == 1) {
165            output.broadcast(BooleanToken.TRUE);
166        } else {
167            output.broadcast(BooleanToken.FALSE);
168        }
169    }
170
171    /** Initialize the actor by resetting the shift register state
172     *  equal to the value of <i>initialState</i>.
173     *  @exception IllegalActionException If the parent class throws it.
174     */
175    @Override
176    public void initialize() throws IllegalActionException {
177        super.initialize();
178        _latestShiftReg = _shiftReg = ((IntToken) initialState.getToken())
179                .intValue();
180    }
181
182    /** Record the most recent shift register state as the new
183     *  initial state for the next iteration.
184     *  @exception IllegalActionException If the base class throws it.
185     */
186    @Override
187    public boolean postfire() throws IllegalActionException {
188        _shiftReg = _latestShiftReg;
189        return super.postfire();
190    }
191
192    ///////////////////////////////////////////////////////////////////
193    ////                         private variables                 ////
194    // Record the state of the shift register.
195    private int _shiftReg;
196
197    // Updated state of the shift register.
198    private int _latestShiftReg;
199}