001/* An actor that produces an event at the specified time. 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.actor.lib; 029 030import ptolemy.actor.Director; 031import ptolemy.actor.SuperdenseTimeDirector; 032import ptolemy.actor.TypedAtomicActor; 033import ptolemy.actor.TypedIOPort; 034import ptolemy.actor.util.Time; 035import ptolemy.data.BooleanToken; 036import ptolemy.data.DoubleToken; 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//// SingleEvent 046 047/** 048 This actor produces an event with the specified value at the 049 specified time. In its initialize() method, it requests a firing 050 at the specified time. If the <i>time</i> 051 parameter changes before that time is reached, then the event is 052 effectively canceled. No event will be produced. 053 <p> 054 If used with a director that implements SuperdenseTimeDirector, then 055 this actor will produce its output event at microstep 1. 056 If it is fired at microstep 0 at the specified model time, 057 then it requests a refiring at the current time. 058 This ensures piecewise continuity. 059 <p> 060 Note that you do not really need this actor. The 061 {@link DiscreteClock} actor can produce any finite sequence of 062 events by setting is <i>period</i> to Infinity. 063 064 @author Edward A. Lee 065 @version $Id$ 066 @since Ptolemy II 10.0 067 @Pt.ProposedRating Yellow (eal) 068 @Pt.AcceptedRating Red (liuj) 069 */ 070public class SingleEvent extends TypedAtomicActor { 071 /** Construct an actor with the specified container and name. 072 * @param container The container. 073 * @param name The name of this actor. 074 * @exception IllegalActionException If the entity cannot be contained 075 * by the proposed container. 076 * @exception NameDuplicationException If the container already has an 077 * actor with this name. 078 */ 079 public SingleEvent(CompositeEntity container, String name) 080 throws NameDuplicationException, IllegalActionException { 081 super(container, name); 082 output = new TypedIOPort(this, "output", false, true); 083 time = new Parameter(this, "time", new DoubleToken(0.0)); 084 time.setTypeEquals(BaseType.DOUBLE); 085 value = new Parameter(this, "value", new BooleanToken(true)); 086 output.setTypeSameAs(value); 087 } 088 089 /////////////////////////////////////////////////////////////////// 090 //// ports and parameters //// 091 092 /** The output port. The type of this port is linked to the type 093 * of the <i>value</i> parameter. 094 */ 095 public TypedIOPort output = null; 096 097 /** The time at which to produce the output. This has type double, 098 * with default value 0.0. 099 * If the value is negative, then no output will be produced. 100 */ 101 public Parameter time; 102 103 /** The value produced at the output. This can have any type, 104 * and it defaults to a boolean token with value <i>true</i>. 105 */ 106 public Parameter value; 107 108 /////////////////////////////////////////////////////////////////// 109 //// public methods //// 110 111 /** Clone the actor into the specified workspace. This calls the 112 * base class and then links the type of the <i>value</i> parameter 113 * to the output. 114 * @param workspace The workspace for the new object. 115 * @return A new actor. 116 * @exception CloneNotSupportedException If a derived class has 117 * has an attribute that cannot be cloned. 118 */ 119 @Override 120 public Object clone(Workspace workspace) throws CloneNotSupportedException { 121 SingleEvent newObject = (SingleEvent) super.clone(workspace); 122 newObject.output.setTypeSameAs(newObject.value); 123 return newObject; 124 } 125 126 /** If the current time matches the value of the <i>time</i> parameter, 127 * then produce an output token with value given by the <i>value</i> 128 * parameter. 129 */ 130 @Override 131 public void fire() throws IllegalActionException { 132 double eventTimeValue = ((DoubleToken) time.getToken()).doubleValue(); 133 Director director = getDirector(); 134 int microstep = 1; 135 if (director instanceof SuperdenseTimeDirector) { 136 microstep = ((SuperdenseTimeDirector) director).getIndex(); 137 } 138 Time eventTime = new Time(director, eventTimeValue); 139 Time currentTime = director.getModelTime(); 140 if (currentTime.equals(eventTime)) { 141 if (microstep >= 1) { 142 // If an output has been produced previously, then 143 // produce it again only if the microstep matches. 144 if (_outputProduced < 0 || _outputProduced == microstep) { 145 output.send(0, value.getToken()); 146 _outputProduced = microstep; 147 } else { 148 output.sendClear(0); 149 } 150 } else { 151 // Request a refiring at the next microstep. 152 // This ensures that the output is piecewise continuous. 153 // This doesn't really need to be postponed to postfire() 154 // because it is generally harmless to make this request more 155 // than once. 156 _fireAt(currentTime); 157 // Send clear to the output, since we know it is absent. 158 output.sendClear(0); 159 } 160 } else { 161 // Send clear to the output, since we know it is absent. 162 output.sendClear(0); 163 } 164 165 super.fire(); 166 } 167 168 /** Request firing at the time given by the <i>time</i> parameter. 169 * If the time is negative, then do nothing. 170 * @exception IllegalActionException If there is no director. 171 */ 172 @Override 173 public void initialize() throws IllegalActionException { 174 super.initialize(); 175 176 _outputProduced = -1; 177 178 double eventTime = ((DoubleToken) time.getToken()).doubleValue(); 179 180 if (eventTime >= 0.0) { 181 _fireAt(eventTime); 182 } 183 } 184 185 /////////////////////////////////////////////////////////////////// 186 //// private variables //// 187 188 /** Indicator that the event has been produced at a microstep. */ 189 private int _outputProduced; 190}