001/* A timer that produces an event with a time delay specified by 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.domains.de.lib; 029 030import ptolemy.actor.util.CalendarQueue; 031import ptolemy.actor.util.CausalityInterface; 032import ptolemy.actor.util.Time; 033import ptolemy.actor.util.TimedEvent; 034import ptolemy.data.BooleanToken; 035import ptolemy.data.DoubleToken; 036import ptolemy.data.Token; 037import ptolemy.data.expr.Parameter; 038import ptolemy.data.type.BaseType; 039import ptolemy.kernel.CompositeEntity; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.NameDuplicationException; 042import ptolemy.kernel.util.Workspace; 043 044/////////////////////////////////////////////////////////////////// 045//// Timer 046 047/** 048 A timer actor delays an event with a time delay specified by its input. 049 <p> 050 When a timer actor receives an input, if the input value is 051 bigger than 0.0, the timer schedules itself to fire again some time 052 later to generate an output. The amount of delay is specified by the 053 input value. The value of output is specified by the <i>value</i> 054 parameter of this actor. If the input value is 0.0, an output is 055 produced in the next firing with a bigger microstep. If the input is 056 less than 0.0, an exception will be thrown. 057 058 <p> This actor is different from the {@link 059 ptolemy.domains.de.lib.NonInterruptibleTimer} actor because the 060 NonInterruptibleTimer actor delays the processing of a new input if 061 it has not finished processing a previous input, while the 062 Timer actor begins processing inputs immediately upon their arrival. 063 064 @author Jie Liu, Edward A. Lee, Haiyang Zheng 065 @version $Id$ 066 @since Ptolemy II 1.0 067 @Pt.ProposedRating Yellow (hyzheng) 068 @Pt.AcceptedRating Yellow (hyzheng) 069 @deprecated Use VariableDelay instead, which is essentially identical, 070 or ResettableTimer for a more reasonable timer behavior. 071 */ 072@Deprecated 073public class Timer extends DETransformer { 074 /** Construct an actor with the specified container and name. 075 * Declare that the input can only receive double tokens and the output 076 * has a data type the same as the value parameter. 077 * @param container The container. 078 * @param name The name of this actor. 079 * @exception IllegalActionException If the entity cannot be contained 080 * by the proposed container. 081 * @exception NameDuplicationException If the container already has an 082 * actor with this name. 083 */ 084 public Timer(CompositeEntity container, String name) 085 throws NameDuplicationException, IllegalActionException { 086 super(container, name); 087 value = new Parameter(this, "value", new BooleanToken(true)); 088 input.setTypeEquals(BaseType.DOUBLE); 089 output.setTypeSameAs(value); 090 } 091 092 /////////////////////////////////////////////////////////////////// 093 //// ports and parameters //// 094 095 /** The value produced at the output. This can have any type, 096 * and it defaults to a boolean token with value <i>true</i>. 097 */ 098 public Parameter value; 099 100 /////////////////////////////////////////////////////////////////// 101 //// public methods //// 102 103 /** Clone the actor into the specified workspace. This calls the 104 * base class, links the type of the <i>value</i> parameter 105 * to the output and sets the data type of the input to be double. 106 * @param workspace The workspace for the new object. 107 * @return A new actor. 108 * @exception CloneNotSupportedException If a derived class has 109 * has an attribute that cannot be cloned. 110 */ 111 @Override 112 public Object clone(Workspace workspace) throws CloneNotSupportedException { 113 Timer newObject = (Timer) super.clone(workspace); 114 newObject.output.setTypeSameAs(newObject.value); 115 newObject.input.setTypeEquals(BaseType.DOUBLE); 116 newObject._causalityInterface = null; 117 return newObject; 118 } 119 120 /** Declare that the <i>output</i> 121 * does not depend on the <i>input</i> in a firing. 122 * @exception IllegalActionException If the causality interface 123 * cannot be computed. 124 * @see #getCausalityInterface() 125 */ 126 @Override 127 public void declareDelayDependency() throws IllegalActionException { 128 _declareDelayDependency(input, output, 0.0); 129 } 130 131 /** Read one token from the input. Send out a token that is scheduled 132 * to produce at the current time to the output. 133 * 134 * @exception IllegalActionException If there is no director, or can not 135 * send or get tokens from ports. 136 */ 137 @Override 138 public void fire() throws IllegalActionException { 139 super.fire(); 140 _delay = -1.0; 141 142 if (input.hasToken(0)) { 143 _currentInput = input.get(0); 144 145 double delayValue = ((DoubleToken) _currentInput).doubleValue(); 146 147 if (delayValue < 0) { 148 throw new IllegalActionException("Delay can not be negative."); 149 } else { 150 _delay = delayValue; 151 } 152 } else { 153 _currentInput = null; 154 } 155 156 Time currentTime = getDirector().getModelTime(); 157 _currentOutput = null; 158 159 if (_delayedOutputTokens.size() > 0) { 160 TimedEvent earliestEvent = (TimedEvent) _delayedOutputTokens.get(); 161 Time eventTime = earliestEvent.timeStamp; 162 163 if (eventTime.equals(currentTime)) { 164 _currentOutput = (Token) earliestEvent.contents; 165 output.send(0, value.getToken()); 166 return; 167 } else { 168 // no tokens to be produced at the current time. 169 } 170 } 171 } 172 173 /** Initialize the internal states of this actor. 174 * @exception IllegalActionException If a derived class throws it. 175 */ 176 @Override 177 public void initialize() throws IllegalActionException { 178 super.initialize(); 179 _currentInput = null; 180 _currentOutput = null; 181 _delayedOutputTokens = new CalendarQueue( 182 new TimedEvent.TimeComparator()); 183 } 184 185 /** Update the internal states of this actor. If the current input 186 * is not processed in the fire method, schedule a refiring of this 187 * actor to produce an output in a future time, 188 * (the current model time + delay specified by the input value). 189 * 190 * @exception IllegalActionException If scheduling to refire cannot 191 * be performed or the superclass throws it. 192 */ 193 @Override 194 public boolean postfire() throws IllegalActionException { 195 Time currentTime = getDirector().getModelTime(); 196 Time delayToTime = currentTime.add(_delay); 197 198 // Remove the token that is already sent at the current time. 199 if (_delayedOutputTokens.size() > 0) { 200 if (_currentOutput != null) { 201 _delayedOutputTokens.take(); 202 } 203 } 204 205 // handle the refiring of the multiple tokens 206 // that are scheduled to produce at the same time. 207 if (_delayedOutputTokens.size() > 0) { 208 TimedEvent earliestEvent = (TimedEvent) _delayedOutputTokens.get(); 209 Time eventTime = earliestEvent.timeStamp; 210 211 if (eventTime.equals(currentTime)) { 212 _fireAt(currentTime); 213 } 214 } 215 216 // Schedule a future firing to process the current input. 217 if (_currentInput != null) { 218 _delayedOutputTokens 219 .put(new TimedEvent(delayToTime, value.getToken())); 220 _fireAt(delayToTime); 221 } 222 223 return super.postfire(); 224 } 225 226 /////////////////////////////////////////////////////////////////// 227 //// protected variables //// 228 229 /** The causality interface, if it has been created. */ 230 protected CausalityInterface _causalityInterface; 231 232 /** The amount of delay. */ 233 protected double _delay; 234 235 /** A local queue to store the delayed tokens. */ 236 protected CalendarQueue _delayedOutputTokens; 237 238 /** Current input. */ 239 protected Token _currentInput; 240 241 /** Current output. */ 242 protected Token _currentOutput; 243}