]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.hxx
Some Linux platforms need <cstdio> for snprintf.
[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 #include <simgear/timing/timestamp.hxx>
33 #include <simgear/structure/SGSharedPtr.hxx>
34 #include <simgear/misc/strutils.hxx>
35
36 class TimingInfo
37 {
38 private:
39     std::string eventName;
40     SGTimeStamp time;
41
42 public: 
43     TimingInfo(const std::string& name, const SGTimeStamp &t) :
44         eventName(name), time(t)
45     { }
46     const std::string& getName() const { return eventName; }
47     const SGTimeStamp& getTime() const { return time; }
48 };
49
50 class SampleStatistic;
51
52 typedef std::vector<TimingInfo> eventTimeVec;
53 typedef std::vector<TimingInfo>::iterator eventTimeVecIterator;
54
55 typedef void (*SGSubsystemTimingCb)(void* userData, const std::string& name, SampleStatistic* pStatistic);
56
57 /**
58  * Basic interface for all FlightGear subsystems.
59  *
60  * <p>This is an abstract interface that all FlightGear subsystems
61  * will eventually implement.  It defines the basic operations for
62  * each subsystem: initialization, property binding and unbinding, and
63  * updating.  Interfaces may define additional methods, but the
64  * preferred way of exchanging information with other subsystems is
65  * through the property tree.</p>
66  *
67  * <p>To publish information through a property, a subsystem should
68  * bind it to a variable or (if necessary) a getter/setter pair in the
69  * bind() method, and release the property in the unbind() method:</p>
70  *
71  * <pre>
72  * void MySubsystem::bind ()
73  * {
74  *   fgTie("/controls/flight/elevator", &_elevator);
75  *   fgSetArchivable("/controls/flight/elevator");
76  * }
77  *
78  * void MySubsystem::unbind ()
79  * {
80  *   fgUntie("/controls/flight/elevator");
81  * }
82  * </pre>
83  *
84  * <p>To reference a property (possibly) from another subsystem, there
85  * are two alternatives.  If the property will be referenced only
86  * infrequently (say, in the init() method), then the fgGet* methods
87  * declared in fg_props.hxx are the simplest:</p>
88  *
89  * <pre>
90  * void MySubsystem::init ()
91  * {
92  *   _errorMargin = fgGetFloat("/display/error-margin-pct");
93  * }
94  * </pre>
95  *
96  * <p>On the other hand, if the property will be referenced frequently
97  * (say, in the update() method), then the hash-table lookup required
98  * by the fgGet* methods might be too expensive; instead, the
99  * subsystem should obtain a reference to the actual property node in
100  * its init() function and use that reference in the main loop:</p>
101  *
102  * <pre>
103  * void MySubsystem::init ()
104  * {
105  *   _errorNode = fgGetNode("/display/error-margin-pct", true);
106  * }
107  *
108  * void MySubsystem::update (double delta_time_sec)
109  * {
110  *   do_something(_errorNode.getFloatValue());
111  * }
112  * </pre>
113  *
114  * <p>The node returned will always be a pointer to SGPropertyNode,
115  * and the subsystem should <em>not</em> delete it in its destructor
116  * (the pointer belongs to the property tree, not the subsystem).</p>
117  *
118  * <p>The program may ask the subsystem to suspend or resume
119  * sim-time-dependent operations; by default, the suspend() and
120  * resume() methods set the protected variable <var>_suspended</var>,
121  * which the subsystem can reference in its update() method, but
122  * subsystems may also override the suspend() and resume() methods to
123  * take different actions.</p>
124  */
125 class SGSubsystem : public SGReferenced
126 {
127 public:
128
129   /**
130    * Default constructor.
131    */
132   SGSubsystem ();
133
134   /**
135    * Virtual destructor to ensure that subclass destructors are called.
136    */
137   virtual ~SGSubsystem ();
138
139
140   /**
141    * Initialize the subsystem.
142    *
143    * <p>This method should set up the state of the subsystem, but
144    * should not bind any properties.  Note that any dependencies on
145    * the state of other subsystems should be placed here rather than
146    * in the constructor, so that FlightGear can control the
147    * initialization order.</p>
148    */
149   virtual void init ();
150
151   typedef enum
152   {
153     INIT_DONE,      ///< subsystem is fully initialised
154     INIT_CONTINUE   ///< init should be called again
155   } InitStatus;
156   
157   virtual InitStatus incrementalInit ();
158
159   /**
160    * Initialize parts that depend on other subsystems having been initialized.
161    *
162    * <p>This method should set up all parts that depend on other
163    * subsystems. One example is the scripting/Nasal subsystem, which
164    * is initialized last. So, if a subsystem wants to execute Nasal
165    * code in subsystem-specific configuration files, it has to do that
166    * in its postinit() method.</p>
167    */
168   virtual void postinit ();
169
170
171   /**
172    * Reinitialize the subsystem.
173    *
174    * <p>This method should cause the subsystem to reinitialize itself,
175    * and (normally) to reload any configuration files.</p>
176    */
177   virtual void reinit ();
178
179
180   /**
181    * Shutdown the subsystem.
182    *
183    * <p>Release any state associated with subsystem. Shutdown happens in
184    * the reverse order to init(), so this is the correct place to do
185    * shutdown that depends on other subsystems.
186    * </p>
187    */
188   virtual void shutdown ();
189    
190   /**
191    * Acquire the subsystem's property bindings.
192    *
193    * <p>This method should bind all properties that the subsystem
194    * publishes.  It will be invoked after init, but before any
195    * invocations of update.</p>
196    */
197   virtual void bind ();
198
199
200   /**
201    * Release the subsystem's property bindings.
202    *
203    * <p>This method should release all properties that the subsystem
204    * publishes.  It will be invoked by FlightGear (not the destructor)
205    * just before the subsystem is removed.</p>
206    */
207   virtual void unbind ();
208
209
210   /**
211    * Update the subsystem.
212    *
213    * <p>FlightGear invokes this method every time the subsystem should
214    * update its state.</p>
215    *
216    * @param delta_time_sec The delta time, in seconds, since the last
217    * update.  On first update, delta time will be 0.
218    */
219   virtual void update (double delta_time_sec) = 0;
220
221
222   /**
223    * Suspend operation of this subsystem.
224    *
225    * <p>This method instructs the subsystem to suspend
226    * sim-time-dependent operations until asked to resume.  The update
227    * method will still be invoked so that the subsystem can take any
228    * non-time-dependent actions, such as updating the display.</p>
229    *
230    * <p>It is not an error for the suspend method to be invoked when
231    * the subsystem is already suspended; the invocation should simply
232    * be ignored.</p>
233    */
234   virtual void suspend ();
235
236
237   /**
238    * Suspend or resume operation of this subsystem.
239    *
240    * @param suspended true if the subsystem should be suspended, false
241    * otherwise.
242    */
243   virtual void suspend (bool suspended);
244
245
246   /**
247    * Resume operation of this subsystem.
248    *
249    * <p>This method instructs the subsystem to resume
250    * sim-time-depended operations.  It is not an error for the resume
251    * method to be invoked when the subsystem is not suspended; the
252    * invocation should simply be ignored.</p>
253    */
254   virtual void resume ();
255
256
257   /**
258    * Test whether this subsystem is suspended.
259    *
260    * @return true if the subsystem is suspended, false if it is not.
261    */
262   virtual bool is_suspended () const;
263
264   /**
265    * Trigger the callback to report timing information for all subsystems.
266    */
267   void reportTiming(void);
268
269   /**
270    * Place time stamps at strategic points in the execution of subsystems 
271    * update() member functions. Predominantly for debugging purposes.
272    */
273   void stamp(const std::string& name);
274
275 protected:
276
277   bool _suspended;
278
279   eventTimeVec timingInfo;
280
281   static SGSubsystemTimingCb reportTimingCb;
282   static void* reportTimingUserData;
283 };
284
285 typedef SGSharedPtr<SGSubsystem> SGSubsystemRef;
286
287 /**
288  * A group of FlightGear subsystems.
289  */
290 class SGSubsystemGroup : public SGSubsystem
291 {
292 public:
293
294     SGSubsystemGroup ();
295     virtual ~SGSubsystemGroup ();
296
297     virtual void init();
298     virtual InitStatus incrementalInit ();
299     virtual void postinit ();
300     virtual void reinit ();
301     virtual void shutdown ();
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 std::string &name,
310                                 SGSubsystem * subsystem,
311                                 double min_step_sec = 0);
312     virtual SGSubsystem * get_subsystem (const std::string &name);
313     virtual void remove_subsystem (const std::string &name);
314     virtual bool has_subsystem (const std::string &name) const;
315
316     /**
317      * Remove all subsystems.
318      */
319     virtual void clearSubsystems();
320
321     void reportTiming(void);
322
323     /**
324      *
325      */
326     void set_fixed_update_time(double fixed_dt);
327          
328         /**
329          * retrive list of member subsystem names
330          */ 
331     string_list member_names() const;
332          
333 private:
334
335     class Member;
336     Member* get_member (const std::string &name, bool create = false);
337
338     typedef std::vector<Member *> MemberVec;
339     MemberVec _members;
340     
341     double _fixedUpdateTime;
342     double _updateTimeRemainder;
343     
344   /// index of the member we are currently init-ing
345     unsigned int _initPosition;
346 };
347
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         FDM,        ///< flight model, autopilot, instruments that run coupled
376         POST_FDM,   ///< certain subsystems depend on FDM data
377         DISPLAY,    ///< view, camera, rendering updates
378         SOUND/*I want to be last!*/,  ///< needs to run AFTER display, to allow concurrent GPU/sound processing
379         MAX_GROUPS
380     };
381
382     SGSubsystemMgr ();
383     virtual ~SGSubsystemMgr ();
384
385     virtual void init ();
386     virtual InitStatus incrementalInit ();
387     virtual void postinit ();
388     virtual void reinit ();
389     virtual void shutdown ();
390     virtual void bind ();
391     virtual void unbind ();
392     virtual void update (double delta_time_sec);
393     virtual void suspend ();
394     virtual void resume ();
395     virtual bool is_suspended () const;
396
397     virtual void add (const char * name,
398                       SGSubsystem * subsystem,
399                       GroupType group = GENERAL, 
400                       double min_time_sec = 0);
401
402     /**
403      * remove a subsystem, and return a pointer to it.
404      * returns NULL if the subsystem was not found.
405      */
406     virtual void remove(const char* name);
407
408     virtual SGSubsystemGroup * get_group (GroupType group);
409
410     virtual SGSubsystem* get_subsystem(const std::string &name) const;
411
412     void reportTiming();
413     void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;}
414
415 private:
416     SGSubsystemGroup* _groups[MAX_GROUPS];
417     unsigned int _initPosition;
418   
419     // non-owning reference
420     typedef std::map<std::string, SGSubsystem*> SubsystemDict;
421     SubsystemDict _subsystem_map;
422 };
423
424 #endif // __SUBSYSTEM_MGR_HXX