001/* A commutator that processes a single token per iteration, used in DDF doamin. 002 003 Copyright (c) 1997-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.ddf.lib; 029 030import ptolemy.actor.lib.SingleTokenCommutator; 031import ptolemy.data.ArrayToken; 032import ptolemy.data.IntToken; 033import ptolemy.data.expr.Parameter; 034import ptolemy.data.type.ArrayType; 035import ptolemy.data.type.BaseType; 036import ptolemy.kernel.CompositeEntity; 037import ptolemy.kernel.Port; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.InternalErrorException; 040import ptolemy.kernel.util.NameDuplicationException; 041import ptolemy.kernel.util.Settable; 042 043/////////////////////////////////////////////////////////////////// 044//// DDFSingleTokenCommutator 045 046/** 047 The DDFSingleTokenCommutator has a multiport input port and an output 048 port. The types of the ports are undeclared and will be resolved by 049 the type resolution mechanism, with the constraint that the output 050 type must be greater than or equal to the input type. On each call to 051 the fire() method, the actor reads one token from the current input 052 channel, and writes the token to the output port. Then in the postfire() 053 method, it will update token consumption rate of the input port so that 054 it will read token from the next channel in the next iteration. 055 056 @author Gang Zhou 057 @version $Id$ 058 @since Ptolemy II 4.1 059 @Pt.ProposedRating Yellow (zgang) 060 @Pt.AcceptedRating Yellow (cxh) 061 */ 062public class DDFSingleTokenCommutator extends SingleTokenCommutator { 063 064 // FIXME: This actor extends sr.lib.SingleTokenCommutator which is 065 // really wrong because it means that if we ship DDF, then we _must_ 066 // ship SR. One solution would be to move this actor elsewhere, 067 // say actor/lib. It would be interesting to see what happens when 068 // this actor is used with SDF, perhaps we should throw an error 069 // automatically. 070 071 /** Construct an actor in the specified container with the specified name. 072 * @param container The container. 073 * @param name This is the name of this distributor within the container. 074 * @exception NameDuplicationException If an actor 075 * with an identical name already exists in the container. 076 * @exception IllegalActionException If the actor cannot be contained 077 * by the proposed container. 078 */ 079 public DDFSingleTokenCommutator(CompositeEntity container, String name) 080 throws NameDuplicationException, IllegalActionException { 081 super(container, name); 082 083 input_tokenConsumptionRate = new Parameter(input, 084 "tokenConsumptionRate"); 085 input_tokenConsumptionRate.setVisibility(Settable.NOT_EDITABLE); 086 input_tokenConsumptionRate.setTypeEquals(new ArrayType(BaseType.INT)); 087 } 088 089 /////////////////////////////////////////////////////////////////// 090 //// parameters //// 091 092 /** This parameter provides token consumption rate for each input 093 * channel. The type is array of ints. 094 */ 095 public Parameter input_tokenConsumptionRate; 096 097 /////////////////////////////////////////////////////////////////// 098 //// public methods //// 099 100 /** Pre-calculate the rates to be set in the rate parameter of the 101 * <i>input</i> port. Initialize the private variable _rateArray, 102 * each element of which indicates the <i>input</i> port needs to 103 * consume one token from a corresponding channel and no token from 104 * the rest of the channels. 105 * @param port The port that has connection changes. 106 */ 107 @Override 108 public void connectionsChanged(Port port) { 109 super.connectionsChanged(port); 110 111 if (port == input) { 112 try { 113 _rateArray = new ArrayToken[input.getWidth()]; 114 115 IntToken[] rate = new IntToken[input.getWidth()]; 116 117 for (int i = 0; i < input.getWidth(); i++) { 118 rate[i] = _zero; 119 } 120 121 for (int i = 0; i < input.getWidth(); i++) { 122 rate[i] = _one; 123 _rateArray[i] = new ArrayToken(BaseType.INT, rate); 124 rate[i] = _zero; 125 } 126 } catch (IllegalActionException ex) { 127 throw new InternalErrorException(this, ex, 128 "At this time IllegalActionExceptions are not allowed to happen.\n" 129 + "Width inference should already have been done."); 130 } 131 } 132 } 133 134 /** Begin execution by setting rate parameter indicating it will 135 * read the zeroth input channel. 136 * @exception IllegalActionException If there is no director. 137 */ 138 @Override 139 public void initialize() throws IllegalActionException { 140 super.initialize(); 141 142 input_tokenConsumptionRate.setToken(_rateArray[0]); 143 } 144 145 /** Update rate parameter indicating the next input channel. 146 * @return True if execution can continue into the next iteration. 147 * @exception IllegalActionException If any called method throws 148 * IllegalActionException. 149 */ 150 @Override 151 public boolean postfire() throws IllegalActionException { 152 // Call postfire first so that current input position is updated. 153 boolean postfireReturn = super.postfire(); 154 155 input_tokenConsumptionRate 156 .setToken(_rateArray[_getCurrentInputPosition()]); 157 158 return postfireReturn; 159 } 160 161 /////////////////////////////////////////////////////////////////// 162 //// private variables //// 163 164 /** A final static IntToken with value 1. 165 */ 166 private final static IntToken _one = new IntToken(1); 167 168 /** A final static IntToken with value 0. 169 */ 170 private final static IntToken _zero = new IntToken(0); 171 172 /** An array of ArrayTokens to be used to set tokenConsumptionRate 173 * of the input port. Each ArrayToken indicates the <i>input</i> 174 * port needs to consume one token from a corresponding channel and 175 * no token from the rest of the channels. The array is initialized 176 * in the method connectionsChanged(). 177 */ 178 private ArrayToken[] _rateArray; 179}