1 // Written by David Megginson, started 2000-12
3 // Copyright (C) 2000 David Megginson, david@megginson.com
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.
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.
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.
22 #ifndef __SUBSYSTEM_MGR_HXX
23 #define __SUBSYSTEM_MGR_HXX 1
26 #include <simgear/compiler.h>
32 #include <simgear/timing/timestamp.hxx>
33 #include <simgear/structure/SGSharedPtr.hxx>
34 #include <simgear/misc/strutils.hxx>
39 std::string eventName;
43 TimingInfo(const std::string& name, const SGTimeStamp &t) :
44 eventName(name), time(t)
46 const std::string& getName() const { return eventName; }
47 const SGTimeStamp& getTime() const { return time; }
50 class SampleStatistic;
52 typedef std::vector<TimingInfo> eventTimeVec;
53 typedef std::vector<TimingInfo>::iterator eventTimeVecIterator;
55 typedef void (*SGSubsystemTimingCb)(void* userData, const std::string& name, SampleStatistic* pStatistic);
58 * Basic interface for all FlightGear subsystems.
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>
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>
72 * void MySubsystem::bind ()
74 * fgTie("/controls/flight/elevator", &_elevator);
75 * fgSetArchivable("/controls/flight/elevator");
78 * void MySubsystem::unbind ()
80 * fgUntie("/controls/flight/elevator");
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>
90 * void MySubsystem::init ()
92 * _errorMargin = fgGetFloat("/display/error-margin-pct");
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>
103 * void MySubsystem::init ()
105 * _errorNode = fgGetNode("/display/error-margin-pct", true);
108 * void MySubsystem::update (double delta_time_sec)
110 * do_something(_errorNode.getFloatValue());
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>
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>
125 class SGSubsystem : public SGReferenced
130 * Default constructor.
135 * Virtual destructor to ensure that subclass destructors are called.
137 virtual ~SGSubsystem ();
141 * Initialize the subsystem.
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>
149 virtual void init ();
153 INIT_DONE, ///< subsystem is fully initialised
154 INIT_CONTINUE ///< init should be called again
157 virtual InitStatus incrementalInit ();
160 * Initialize parts that depend on other subsystems having been initialized.
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>
168 virtual void postinit ();
172 * Reinitialize the subsystem.
174 * <p>This method should cause the subsystem to reinitialize itself,
175 * and (normally) to reload any configuration files.</p>
177 virtual void reinit ();
181 * Shutdown the subsystem.
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.
188 virtual void shutdown ();
191 * Acquire the subsystem's property bindings.
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>
197 virtual void bind ();
201 * Release the subsystem's property bindings.
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>
207 virtual void unbind ();
211 * Update the subsystem.
213 * <p>FlightGear invokes this method every time the subsystem should
214 * update its state.</p>
216 * @param delta_time_sec The delta time, in seconds, since the last
217 * update. On first update, delta time will be 0.
219 virtual void update (double delta_time_sec) = 0;
223 * Suspend operation of this subsystem.
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>
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
234 virtual void suspend ();
238 * Suspend or resume operation of this subsystem.
240 * @param suspended true if the subsystem should be suspended, false
243 virtual void suspend (bool suspended);
247 * Resume operation of this subsystem.
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>
254 virtual void resume ();
258 * Test whether this subsystem is suspended.
260 * @return true if the subsystem is suspended, false if it is not.
262 virtual bool is_suspended () const;
265 * Trigger the callback to report timing information for all subsystems.
267 void reportTiming(void);
270 * Place time stamps at strategic points in the execution of subsystems
271 * update() member functions. Predominantly for debugging purposes.
273 void stamp(const std::string& name);
279 eventTimeVec timingInfo;
281 static SGSubsystemTimingCb reportTimingCb;
282 static void* reportTimingUserData;
285 typedef SGSharedPtr<SGSubsystem> SGSubsystemRef;
288 * A group of FlightGear subsystems.
290 class SGSubsystemGroup : public SGSubsystem
295 virtual ~SGSubsystemGroup ();
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;
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;
317 * Remove all subsystems.
319 virtual void clearSubsystems();
321 void reportTiming(void);
326 void set_fixed_update_time(double fixed_dt);
329 * retrive list of member subsystem names
331 string_list member_names() const;
336 Member* get_member (const std::string &name, bool create = false);
338 typedef std::vector<Member *> MemberVec;
341 double _fixedUpdateTime;
342 double _updateTimeRemainder;
344 /// index of the member we are currently init-ing
345 unsigned int _initPosition;
349 * Manage subsystems for FlightGear.
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.
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.
362 * The subsystem manager owns the pointers to all the subsystems in
365 class SGSubsystemMgr : public SGSubsystem
370 * Types of subsystem groups.
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
383 virtual ~SGSubsystemMgr ();
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;
397 virtual void add (const char * name,
398 SGSubsystem * subsystem,
399 GroupType group = GENERAL,
400 double min_time_sec = 0);
403 * remove a subsystem, and return a pointer to it.
404 * returns NULL if the subsystem was not found.
406 virtual void remove(const char* name);
408 virtual SGSubsystemGroup * get_group (GroupType group);
410 virtual SGSubsystem* get_subsystem(const std::string &name) const;
413 void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;}
416 SGSubsystemGroup* _groups[MAX_GROUPS];
417 unsigned int _initPosition;
419 // non-owning reference
420 typedef std::map<std::string, SGSubsystem*> SubsystemDict;
421 SubsystemDict _subsystem_map;
424 #endif // __SUBSYSTEM_MGR_HXX