001/* Assemble input port channels into output bus. 002 003 Copyright (c) 2002-2014 The Regents of the University of California and 004 Research in Motion Limited. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA OR RESEARCH IN MOTION 013 LIMITED BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, 014 INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS 015 SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA 016 OR RESEARCH IN MOTION LIMITED HAVE BEEN ADVISED OF THE POSSIBILITY OF 017 SUCH DAMAGE. 018 019 THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION LIMITED 020 SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 022 PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 023 BASIS, AND THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION 024 LIMITED HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 025 ENHANCEMENTS, OR MODIFICATIONS. 026 PT_COPYRIGHT_VERSION_2 027 COPYRIGHTENDKEY 028 029 */ 030package ptolemy.actor.lib; 031 032import java.util.Iterator; 033import java.util.List; 034 035import ptolemy.actor.TypedAtomicActor; 036import ptolemy.actor.TypedIOPort; 037import ptolemy.actor.TypedIORelation; 038import ptolemy.data.Token; 039import ptolemy.kernel.CompositeEntity; 040import ptolemy.kernel.Port; 041import ptolemy.kernel.util.IllegalActionException; 042import ptolemy.kernel.util.NameDuplicationException; 043 044/////////////////////////////////////////////////////////////////// 045//// BusAssembler 046 047/** 048 Aggregate all input relation channels into one output "bus" relation. 049 The width of the output port (bus relation) is set to the sum of the 050 input port widths. During the fire method, the input port channels are 051 scanned sequentially for tokens with the output channel index 052 incremented for each input channel scanned. If an input channel has a 053 token, it is copied to the corresponding output channel.<p> 054 055 Note: The width of a single relation (e.g. connected to an input port) 056 may be controlled by adding a <em>width</em> parameter with an IntToken 057 value 058 representing the desired relation width<p> 059 060 @author Zoltan Kemenczy, Research in Motion Limited 061 @version $Id$ 062 @since Ptolemy II 2.1 063 @Pt.ProposedRating Red (zkemenczy) 064 @Pt.AcceptedRating Red (cxh) 065 @see ptolemy.actor.IORelation 066 */ 067public class BusAssembler extends TypedAtomicActor { 068 /** Construct a BusAssembler with the given container and name. 069 * @param container The container. 070 * @param name The name of this actor. 071 * @exception IllegalActionException If this actor cannot be contained 072 * by the proposed container. 073 * @exception NameDuplicationException If the container already has an 074 * actor with this name. 075 */ 076 public BusAssembler(CompositeEntity container, String name) 077 throws NameDuplicationException, IllegalActionException { 078 super(container, name); 079 output = new TypedIOPort(this, "output", false, true); 080 output.setMultiport(true); 081 _attachText("_iconDescription", 082 "<svg>\n" + "<rect x=\"0\" y=\"0\" width=\"6\" " 083 + "height=\"40\" style=\"fill:black\"/>\n" 084 + "</svg>\n"); 085 } 086 087 /////////////////////////////////////////////////////////////////// 088 //// ports and parameters //// 089 090 /** The input port. */ 091 public TypedIOPort output; 092 093 /////////////////////////////////////////////////////////////////// 094 //// public methods //// 095 096 /** React to a change in an input port width. */ 097 @Override 098 public void connectionsChanged(Port p) { 099 super.connectionsChanged(p); 100 101 if (p == output) { 102 return; 103 } 104 105 try { 106 _recalculateOutputWidth(); 107 } catch (IllegalActionException ex) { 108 } 109 } 110 111 /** Iterate through input ports and transfer data sequentially from 112 * input channels to output channels, maintaining input to output 113 * channel mapping. 114 * @exception IllegalActionException If calling send() or super.fire() 115 * throws it. 116 */ 117 @Override 118 public void fire() throws IllegalActionException { 119 super.fire(); 120 Iterator inputPorts = inputPortList().iterator(); 121 TypedIOPort inputPort = (TypedIOPort) (inputPorts.hasNext() 122 ? inputPorts.next() 123 : null); 124 int inputWidth = inputPort != null ? inputPort.getWidth() : 0; 125 int i = 0; 126 int j = 0; 127 128 while (inputPort != null) { 129 if (i < inputWidth && inputPort.hasToken(i)) { 130 Token t = inputPort.get(i); 131 132 if (j < _outputWidth) { 133 output.send(j, t); 134 } 135 } 136 137 j++; 138 139 if (++i >= inputWidth) { 140 inputPort = (TypedIOPort) (inputPorts.hasNext() 141 ? inputPorts.next() 142 : null); 143 inputWidth = inputPort != null ? inputPort.getWidth() : 0; 144 i = 0; 145 } 146 } 147 } 148 149 /** Makes sure that there is only one relation connected to the 150 output port and recalculates its width. */ 151 @Override 152 public void preinitialize() throws IllegalActionException { 153 if (outputPortList().size() > 1) { 154 throw new IllegalActionException(this, 155 "can have only one output port."); 156 } 157 158 if (output.linkedRelationList().size() > 1) { 159 throw new IllegalActionException(this, 160 "can have only one output relation linked."); 161 } 162 163 _recalculateOutputWidth(); 164 super.preinitialize(); 165 } 166 167 /////////////////////////////////////////////////////////////////// 168 //// private methods //// 169 170 /** Recalculate the output relation width. */ 171 private void _recalculateOutputWidth() throws IllegalActionException { 172 List outputRelations = output.linkedRelationList(); 173 _outputWidth = 0; 174 175 if (outputRelations.isEmpty()) { 176 return; 177 } 178 179 TypedIORelation outputRelation = (TypedIORelation) outputRelations 180 .get(0); 181 Iterator inputPorts = inputPortList().iterator(); 182 183 while (inputPorts.hasNext()) { 184 TypedIOPort port = (TypedIOPort) inputPorts.next(); 185 _outputWidth += port.getWidth(); // includes all linked relations 186 } 187 188 outputRelation.setWidth(_outputWidth); 189 190 // TODO: figure out how to obey if the output relation width is 191 // set (if isWidthFixed() would return a reliable true...) 192 } 193 194 /////////////////////////////////////////////////////////////////// 195 //// private variables //// 196 int _outputWidth = 0; 197}