1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SoTimerQueueSensor SoTimerQueueSensor.h Inventor/sensors/SoTimerQueueSensor.h
35   \brief The SoTimerQueueSensor class is the abstract base class for sensors triggering on certain timer events.
36 
37   \ingroup sensors
38 
39   Timer sensors triggers upon specific points in time.
40 
41   This class is an abstract superclass which collects the common
42   interface of the various non-abstract timer sensor classes. See the
43   documentation of the subclasses for information on what ways there
44   are to specify base times, intervals, alarm-style single triggering,
45   repeated triggers, etc.
46 
47   Note that Coin timer sensors should in no way be considered "hard
48   real-time". That is, you can \e not expect a timer to always trigger
49   at the exact moment it was set up for. Delays in triggering could be
50   due to other activities in Coin, a task suspended, or heavy load
51   from other applications on the system. These situations could all
52   cause the processing of sensor queues (from SoQt / SoWin / SoXt /
53   whatever) to be slightly delayed, thereby causing delays in timer
54   sensor triggering.
55 
56   On modern systems, a timer will usually trigger within a few
57   milliseconds of it's designated time, though.
58 
59   If a timer sensor can not trigger at the exact moment it has been
60   scheduled, it will be triggered at the first opportunity after the
61   scheduled time has passed.
62 
63   Here's a simple usage example. It's a stand-alone example, which
64   only demonstrates how to set up a repeating timer sensor with a
65   callback:
66 
67   \code
68   #include <Inventor/Xt/SoXt.h>
69   #include <Inventor/sensors/SoTimerSensor.h>
70   #include <cstdio>
71 
72   static void
73   timeSensorCallback(void * data, SoSensor * sensor)
74   {
75     SbTime time = SbTime::getTimeOfDay();
76     SbString string = time.format("%S.%i");
77     (void)printf("%s\n", string.getString());
78   }
79 
80 
81   int
82   main(int argc, char ** argv)
83   {
84     SoXt::init("test");
85 
86     SoTimerSensor * timeSensor = new SoTimerSensor;
87     timeSensor->setFunction(timeSensorCallback);
88     timeSensor->setBaseTime(SbTime::getTimeOfDay());
89     timeSensor->setInterval(1.0f);
90     timeSensor->schedule();
91 
92     SoXt::mainLoop();
93     return 0;
94   }
95   \endcode
96 */
97 
98 #include <Inventor/sensors/SoTimerQueueSensor.h>
99 #include <Inventor/SoDB.h>
100 #include <cassert>
101 
102 #if COIN_DEBUG
103 #include <Inventor/errors/SoDebugError.h>
104 #endif // COIN_DEBUG
105 
106 /*!
107   \var SbBool SoTimerQueueSensor::scheduled
108   \c TRUE if the sensor is currently scheduled.
109 */
110 
111 
112 /*!
113   Default constructor.
114  */
SoTimerQueueSensor(void)115 SoTimerQueueSensor::SoTimerQueueSensor(void)
116   : scheduled(FALSE)
117 {
118 }
119 
120 /*!
121   Constructor taking as arguments the sensor callback function and the
122   userdata which will be passed the callback.
123 
124   \sa setFunction(), setData()
125  */
SoTimerQueueSensor(SoSensorCB * func,void * data)126 SoTimerQueueSensor::SoTimerQueueSensor(SoSensorCB * func, void * data)
127   : inherited(func, data), scheduled(FALSE)
128 {
129 }
130 
131 /*!
132   Destructor.
133 */
~SoTimerQueueSensor(void)134 SoTimerQueueSensor::~SoTimerQueueSensor(void)
135 {
136   // Note: it won't work to move this to the SoSensor destructor
137   // (where it really belongs), because you can't use pure virtual
138   // methods from a destructor.
139   if (this->isScheduled()) this->unschedule();
140 }
141 
142 /*!
143   Returns the time at which the sensor will trigger.
144 
145   \sa setTriggerTime()
146  */
147 const SbTime &
getTriggerTime(void) const148 SoTimerQueueSensor::getTriggerTime(void) const
149 {
150   return this->triggertime;
151 }
152 
153 /*!
154   Set absolute time at which to trigger sensor.
155 
156   \sa getTriggerTime()
157  */
158 void
setTriggerTime(const SbTime & time)159 SoTimerQueueSensor::setTriggerTime(const SbTime & time)
160 {
161   if (time != this->triggertime) {
162     this->triggertime = time;
163     if (this->isScheduled()) {
164       SoSensorManager * sm = SoDB::getSensorManager();
165       sm->removeTimerSensor(this);
166       sm->insertTimerSensor(this);
167     }
168   }
169 }
170 
171 // Documented in superclass.
172 void
trigger(void)173 SoTimerQueueSensor::trigger(void)
174 {
175   this->scheduled = FALSE;
176   inherited::trigger();
177 }
178 
179 /*!
180   Put the sensor in the global timer queue.
181 
182   \sa unschedule(), isScheduled()
183  */
184 void
schedule(void)185 SoTimerQueueSensor::schedule(void)
186 {
187 #if COIN_DEBUG
188   assert(this->scheduled == TRUE || this->scheduled == FALSE);
189   if (this->isScheduled()) {
190     SoDebugError::postWarning("SoTimerQueueSensor::schedule",
191                               "already scheduled!");
192     return;
193   }
194 #endif // COIN_DEBUG
195 
196   SoDB::getSensorManager()->insertTimerSensor(this);
197   this->scheduled = TRUE;
198 }
199 
200 /*!
201   Remove sensor from the timer queue, without triggering it first.
202 
203   \sa schedule(), isScheduled()
204  */
205 void
unschedule(void)206 SoTimerQueueSensor::unschedule(void)
207 {
208 #if COIN_DEBUG
209   assert(this->scheduled == TRUE || this->scheduled == FALSE);
210   if (!this->isScheduled()) {
211     SoDebugError::postWarning("SoTimerQueueSensor::unschedule",
212                               "not scheduled!");
213     return;
214   }
215 #endif // COIN_DEBUG
216   SoDB::getSensorManager()->removeTimerSensor(this);
217   this->scheduled = FALSE;
218 }
219 
220 /*!
221   Check if this sensor is scheduled for triggering.
222 
223   \sa schedule(), unschedule()
224  */
225 SbBool
isScheduled(void) const226 SoTimerQueueSensor::isScheduled(void) const
227 {
228   return this->scheduled;
229 }
230 
231 SbBool
isBefore(const SoSensor * s) const232 SoTimerQueueSensor::isBefore(const SoSensor * s) const
233 {
234   return (this->triggertime < ((SoTimerQueueSensor *)s)->triggertime);
235 }
236