]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.hxx
c759e7901ada9fbe2f4c5f8b5d6c69621d9ea51b
[simgear.git] / simgear / structure / subsystem_mgr.hxx
1 // Written by David Megginson, started 2000-12
2 //
3 // Copyright (C) 2000  David Megginson, david@megginson.com
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 // $Id$
20
21
22 #ifndef __SUBSYSTEM_MGR_HXX
23 #define __SUBSYSTEM_MGR_HXX 1
24
25
26 #include <simgear/compiler.h>
27
28 #include <string>
29 #include <map>
30 #include <vector>
31
32 using std::map;
33 using std::vector;
34 using std::string;
35
36 #include <simgear/props/props.hxx>
37 #include <simgear/timing/timestamp.hxx>
38 #include "SGSmplstat.hxx"
39
40
41 class TimingInfo
42 {
43 private:
44     string eventName;
45     SGTimeStamp time;
46
47 public: 
48     TimingInfo(string name, SGTimeStamp &t) { eventName = name; time = t;};
49     string getName() { return eventName; };
50     SGTimeStamp getTime() { return time; };
51 };
52
53 typedef vector<TimingInfo> eventTimeVec;
54 typedef vector<TimingInfo>::iterator eventTimeVecIterator;
55
56
57 \f
58 /**
59  * Basic interface for all FlightGear subsystems.
60  *
61  * <p>This is an abstract interface that all FlightGear subsystems
62  * will eventually implement.  It defines the basic operations for
63  * each subsystem: initialization, property binding and unbinding, and
64  * updating.  Interfaces may define additional methods, but the
65  * preferred way of exchanging information with other subsystems is
66  * through the property tree.</p>
67  *
68  * <p>To publish information through a property, a subsystem should
69  * bind it to a variable or (if necessary) a getter/setter pair in the
70  * bind() method, and release the property in the unbind() method:</p>
71  *
72  * <pre>
73  * void MySubsystem::bind ()
74  * {
75  *   fgTie("/controls/flight/elevator", &_elevator);
76  *   fgSetArchivable("/controls/flight/elevator");
77  * }
78  *
79  * void MySubsystem::unbind ()
80  * {
81  *   fgUntie("/controls/flight/elevator");
82  * }
83  * </pre>
84  *
85  * <p>To reference a property (possibly) from another subsystem, there
86  * are two alternatives.  If the property will be referenced only
87  * infrequently (say, in the init() method), then the fgGet* methods
88  * declared in fg_props.hxx are the simplest:</p>
89  *
90  * <pre>
91  * void MySubsystem::init ()
92  * {
93  *   _errorMargin = fgGetFloat("/display/error-margin-pct");
94  * }
95  * </pre>
96  *
97  * <p>On the other hand, if the property will be referenced frequently
98  * (say, in the update() method), then the hash-table lookup required
99  * by the fgGet* methods might be too expensive; instead, the
100  * subsystem should obtain a reference to the actual property node in
101  * its init() function and use that reference in the main loop:</p>
102  *
103  * <pre>
104  * void MySubsystem::init ()
105  * {
106  *   _errorNode = fgGetNode("/display/error-margin-pct", true);
107  * }
108  *
109  * void MySubsystem::update (double delta_time_sec)
110  * {
111  *   do_something(_errorNode.getFloatValue());
112  * }
113  * </pre>
114  *
115  * <p>The node returned will always be a pointer to SGPropertyNode,
116  * and the subsystem should <em>not</em> delete it in its destructor
117  * (the pointer belongs to the property tree, not the subsystem).</p>
118  *
119  * <p>The program may ask the subsystem to suspend or resume
120  * sim-time-dependent operations; by default, the suspend() and
121  * resume() methods set the protected variable <var>_suspended</var>,
122  * which the subsystem can reference in its update() method, but
123  * subsystems may also override the suspend() and resume() methods to
124  * take different actions.</p>
125  */
126 class SGSubsystem : public SGReferenced
127 {
128 public:
129
130   /**
131    * Default constructor.
132    */
133   SGSubsystem ();
134
135   /**
136    * Virtual destructor to ensure that subclass destructors are called.
137    */
138   virtual ~SGSubsystem ();
139
140
141   /**
142    * Initialize the subsystem.
143    *
144    * <p>This method should set up the state of the subsystem, but
145    * should not bind any properties.  Note that any dependencies on
146    * the state of other subsystems should be placed here rather than
147    * in the constructor, so that FlightGear can control the
148    * initialization order.</p>
149    */
150   virtual void init ();
151
152
153   /**
154    * Initialize parts that depend on other subsystems having been initialized.
155    *
156    * <p>This method should set up all parts that depend on other
157    * subsystems. One example is the scripting/Nasal subsystem, which
158    * is initialized last. So, if a subsystem wants to execute Nasal
159    * code in subsystem-specific configuration files, it has to do that
160    * in its postinit() method.</p>
161    */
162   virtual void postinit ();
163
164
165   /**
166    * Reinitialize the subsystem.
167    *
168    * <p>This method should cause the subsystem to reinitialize itself,
169    * and (normally) to reload any configuration files.</p>
170    */
171   virtual void reinit ();
172
173
174   /**
175    * Acquire the subsystem's property bindings.
176    *
177    * <p>This method should bind all properties that the subsystem
178    * publishes.  It will be invoked after init, but before any
179    * invocations of update.</p>
180    */
181   virtual void bind ();
182
183
184   /**
185    * Release the subsystem's property bindings.
186    *
187    * <p>This method should release all properties that the subsystem
188    * publishes.  It will be invoked by FlightGear (not the destructor)
189    * just before the subsystem is removed.</p>
190    */
191   virtual void unbind ();
192
193
194   /**
195    * Update the subsystem.
196    *
197    * <p>FlightGear invokes this method every time the subsystem should
198    * update its state.</p>
199    *
200    * @param delta_time_sec The delta time, in seconds, since the last
201    * update.  On first update, delta time will be 0.
202    */
203   virtual void update (double delta_time_sec) = 0;
204
205
206   /**
207    * Suspend operation of this subsystem.
208    *
209    * <p>This method instructs the subsystem to suspend
210    * sim-time-dependent operations until asked to resume.  The update
211    * method will still be invoked so that the subsystem can take any
212    * non-time-dependent actions, such as updating the display.</p>
213    *
214    * <p>It is not an error for the suspend method to be invoked when
215    * the subsystem is already suspended; the invocation should simply
216    * be ignored.</p>
217    */
218   virtual void suspend ();
219
220
221   /**
222    * Suspend or resum operation of this subsystem.
223    *
224    * @param suspended true if the subsystem should be suspended, false
225    * otherwise.
226    */
227   virtual void suspend (bool suspended);
228
229
230   /**
231    * Resume operation of this subsystem.
232    *
233    * <p>This method instructs the subsystem to resume
234    * sim-time-depended operations.  It is not an error for the resume
235    * method to be invoked when the subsystem is not suspended; the
236    * invocation should simply be ignored.</p>
237    */
238   virtual void resume ();
239
240
241   /**
242    * Test whether this subsystem is suspended.
243    *
244    * @return true if the subsystem is suspended, false if it is not.
245    */
246   virtual bool is_suspended () const;
247
248
249   /**
250    * Keep track of execution time.
251    *
252    * <p>This method keeps track of timing statistics for each subsystem.</p>
253    * 
254    * @param time execution time in ms of last call.
255    */
256   void updateExecutionTime(double time);
257
258   /**
259    * Print details of execution time.
260    *
261    * <p>For debugging purposes, developers can place stamp() calls
262    * at strategic points in the update() function of each subsystem, which 
263    * record the time between the successive calls to stamp. This method,
264    * printExecutionTime() is called after exectution of the subsystem
265    * update function itself to conduct a post-hoc analysis of excecution
266    * time</p>
267    */ 
268   void printTimingInformation();
269
270   /**
271    * Place time stamps at strategic points in the execution of subsystems 
272    * update() member functions. Predominantly for debugging purposes.
273    */
274   void stamp(string name);
275   
276
277
278 protected:
279
280   bool _suspended;
281
282   eventTimeVec timingInfo;
283   //int test;
284
285 };
286
287
288 \f
289 /**
290  * A group of FlightGear subsystems.
291  */
292 class SGSubsystemGroup : public SGSubsystem
293 {
294 public:
295
296     SGSubsystemGroup ();
297     virtual ~SGSubsystemGroup ();
298
299     virtual void init ();
300     virtual void postinit ();
301     virtual void reinit ();
302     virtual void bind ();
303     virtual void unbind ();
304     virtual void update (double delta_time_sec);
305     virtual void suspend ();
306     virtual void resume ();
307     virtual bool is_suspended () const;
308
309     virtual void set_subsystem (const string &name,
310                                 SGSubsystem * subsystem,
311                                 double min_step_sec = 0);
312     virtual SGSubsystem * get_subsystem (const string &name);
313     virtual void remove_subsystem (const string &name);
314     virtual bool has_subsystem (const string &name) const;
315
316     void collectDebugTiming(bool collect);
317
318 private:
319
320     struct Member {
321
322         Member ();
323         Member (const Member &member);
324         virtual ~Member ();
325
326         virtual void update (double delta_time_sec);
327         void printTimingInformation(double time);
328         void printTimingStatistics();
329         void updateExecutionTime(double time);
330         double getTimeWarningThreshold();
331         void collectDebugTiming (bool collect) { collectTimeStats = collect; };
332
333         SampleStatistic timeStat;
334         string name;
335         SGSubsystem * subsystem;
336         double min_step_sec;
337         double elapsed_sec;
338         bool collectTimeStats;
339     };
340
341     Member * get_member (const string &name, bool create = false);
342
343     vector<Member *> _members;
344 };
345
346
347 \f
348 /**
349  * Manage subsystems for FlightGear.
350  *
351  * This top-level subsystem will eventually manage all of the
352  * subsystems in FlightGear: it broadcasts its life-cycle events
353  * (init, bind, etc.) to all of the subsystems it manages.  Subsystems
354  * are grouped to guarantee order of initialization and execution --
355  * currently, the only two groups are INIT and GENERAL, but others
356  * will appear in the future.
357  *
358  * All subsystems are named as well as grouped, and subsystems can be
359  * looked up by name and cast to the appropriate subtype when another
360  * subsystem needs to invoke specialized methods.
361  *
362  * The subsystem manager owns the pointers to all the subsystems in
363  * it.
364  */
365 class SGSubsystemMgr : public SGSubsystem
366 {
367 public:
368
369     /**
370      * Types of subsystem groups.
371      */
372     enum GroupType {
373         INIT = 0,
374         GENERAL,
375         MAX_GROUPS
376     };
377
378     SGSubsystemMgr ();
379     virtual ~SGSubsystemMgr ();
380
381     virtual void init ();
382     virtual void postinit ();
383     virtual void reinit ();
384     virtual void bind ();
385     virtual void unbind ();
386     virtual void update (double delta_time_sec);
387     virtual void suspend ();
388     virtual void resume ();
389     virtual bool is_suspended () const;
390
391     virtual void add (const char * name,
392                       SGSubsystem * subsystem,
393                       GroupType group = GENERAL, 
394                       double min_time_sec = 0);
395
396     virtual SGSubsystemGroup * get_group (GroupType group);
397
398     virtual SGSubsystem * get_subsystem(const string &name);
399
400    void collectDebugTiming(bool collect);
401
402 private:
403
404     SGSubsystemGroup _groups[MAX_GROUPS];
405     map<string,SGSubsystem *> _subsystem_map;
406
407 };
408
409
410
411 #endif // __SUBSYSTEM_MGR_HXX
412