Move FGEventMgr and FGSubsystemMgr over to SimGear, add SGEventMgr to FlightGear's globals structre and some small code cleanups

This commit is contained in:
ehofman
2003-09-24 17:19:22 +00:00
parent f3eeeb760f
commit d22640ef4e
18 changed files with 1322 additions and 11 deletions
+3
View File
@@ -0,0 +1,3 @@
.deps
Makefile
Makefile.in
+20
View File
@@ -0,0 +1,20 @@
includedir = @includedir@/structure
lib_LIBRARIES = libsgstructure.a
include_HEADERS = \
callback.hxx \
commands.hxx \
exception.hxx \
event_mgr.hxx \
subsystem_mgr.hxx
libsgstructure_a_SOURCES = \
commands.cxx \
exception.cxx \
event_mgr.cxx\
subsystem_mgr.cxx
INCLUDES = -I$(top_srcdir)
+148
View File
@@ -0,0 +1,148 @@
/**************************************************************************
* callback.hxx -- Wrapper classes to treat function and method pointers
* as objects.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
**************************************************************************/
#ifndef _SG_CALLBACK_HXX
#define _SG_CALLBACK_HXX
/**
* Abstract base class for all callbacks.
*/
class SGCallback
{
public:
/**
*
*/
virtual ~SGCallback() {}
/**
*
*/
virtual SGCallback* clone() const = 0;
/**
* Execute the callback function.
*/
virtual void operator()() = 0;
protected:
/**
*
*/
SGCallback() {}
private:
// Not implemented.
void operator=( const SGCallback& );
};
/**
* Callback for invoking a file scope function.
*/
template< typename Fun >
class SGFunctionCallback : public SGCallback
{
public:
/**
*
*/
SGFunctionCallback( const Fun& fun )
: SGCallback(), f_(fun) {}
SGCallback* clone() const
{
return new SGFunctionCallback( *this );
}
void operator()() { f_(); }
private:
// Not defined.
SGFunctionCallback();
private:
Fun f_;
};
/**
* Callback for invoking a member function.
*/
template< class ObjPtr, typename MemFn >
class SGMethodCallback : public SGCallback
{
public:
/**
*
*/
SGMethodCallback( const ObjPtr& pObj, MemFn pMemFn )
: SGCallback(),
pObj_(pObj),
pMemFn_(pMemFn)
{
}
/**
*
*/
SGCallback* clone() const
{
return new SGMethodCallback( *this );
}
/**
*
*/
void operator()()
{
((*pObj_).*pMemFn_)();
}
private:
// Not defined.
SGMethodCallback();
private:
ObjPtr pObj_;
MemFn pMemFn_;
};
/**
* Helper template functions.
*/
template< typename Fun >
SGCallback*
make_callback( const Fun& fun )
{
return new SGFunctionCallback<Fun>(fun);
}
template< class ObjPtr, typename MemFn >
SGCallback*
make_callback( const ObjPtr& pObj, MemFn pMemFn )
{
return new SGMethodCallback<ObjPtr,MemFn>(pObj, pMemFn );
}
#endif // _SG_CALLBACK_HXX
+64
View File
@@ -0,0 +1,64 @@
// commands.cxx - encapsulated commands.
// Started Spring 2001 by David Megginson, david@megginson.com
// This code is released into the Public Domain.
//
// $Id$
#include <simgear/props/props_io.hxx>
#include "commands.hxx"
////////////////////////////////////////////////////////////////////////
// Implementation of SGCommandMgr class.
////////////////////////////////////////////////////////////////////////
SGCommandMgr::SGCommandMgr ()
{
// no-op
}
SGCommandMgr::~SGCommandMgr ()
{
// no-op
}
void
SGCommandMgr::addCommand (const string &name, command_t command)
{
_commands[name] = command;
}
SGCommandMgr::command_t
SGCommandMgr::getCommand (const string &name) const
{
const command_map::const_iterator it = _commands.find(name);
return (it != _commands.end() ? it->second : 0);
}
vector<string>
SGCommandMgr::getCommandNames () const
{
vector<string> names;
command_map::const_iterator it = _commands.begin();
command_map::const_iterator last = _commands.end();
while (it != last) {
names.push_back(it->first);
it++;
}
return names;
}
bool
SGCommandMgr::execute (const string &name, const SGPropertyNode * arg) const
{
command_t command = getCommand(name);
if (command == 0)
return false;
else
return (*command)(arg);
}
// end of commands.cxx
+111
View File
@@ -0,0 +1,111 @@
/**
* \file commands.hxx
* Interface definition for encapsulated commands.
* Started Spring 2001 by David Megginson, david@megginson.com
* This code is released into the Public Domain.
*
* $Id$
*/
#ifndef __COMMANDS_HXX
#define __COMMANDS_HXX
#include <simgear/compiler.h>
#include STL_STRING
#include <map>
#include <vector>
#include <simgear/props/props.hxx>
SG_USING_STD(string);
SG_USING_STD(map);
SG_USING_STD(vector);
/**
* Manage commands.
*
* <p>This class allows the application to register and unregister
* commands, and provides shortcuts for executing them. Commands are
* simple functions that take a const pointer to an SGPropertyNode:
* the function may use the nodes children as parameters.</p>
*
* @author David Megginson, david@megginson.com
*/
class SGCommandMgr
{
public:
/**
* Type for a command function.
*/
typedef bool (*command_t) (const SGPropertyNode * arg);
/**
* Default constructor.
*/
SGCommandMgr ();
/**
* Destructor.
*/
virtual ~SGCommandMgr ();
/**
* Register a new command with the manager.
*
* @param name The command name. Any existing command with
* the same name will silently be overwritten.
* @param command A pointer to a one-arg function returning
* a bool result. The argument is always a const pointer to
* an SGPropertyNode (which may contain multiple values).
*/
virtual void addCommand (const string &name, command_t command);
/**
* Look up an existing command.
*
* @param name The command name.
* @return A pointer to the command, or 0 if there is no registered
* command with the name specified.
*/
virtual command_t getCommand (const string &name) const;
/**
* Get a list of all existing command names.
*
* @return A (possibly empty) vector of the names of all registered
* commands.
*/
virtual vector<string> getCommandNames () const;
/**
* Execute a command.
*
* @param name The name of the command.
* @param arg A const pointer to an SGPropertyNode. The node
* may have a value and/or children, etc., so that it is possible
* to pass an arbitrarily complex data structure to a command.
* @return true if the command is present and executes successfully,
* false otherwise.
*/
virtual bool execute (const string &name, const SGPropertyNode * arg) const;
private:
typedef map<string,command_t> command_map;
command_map _commands;
};
#endif // __COMMANDS_HXX
// end of commands.hxx
+258
View File
@@ -0,0 +1,258 @@
//
// SGEventMgr.cxx -- Event Manager
//
// Written by Bernie Bright, started April 2002.
//
// Copyright (C) 2002 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include "event_mgr.hxx"
SGEvent::SGEvent()
: _name(""),
_callback(0),
_subsystem(0),
_repeat_value(0),
_initial_value(0),
_ms_to_go(0),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
{
}
SGEvent::SGEvent( const char* name,
SGCallback* cb,
interval_type repeat_value,
interval_type initial_value )
: _name(name),
_callback(cb),
_subsystem(NULL),
_repeat_value(repeat_value),
_initial_value(initial_value),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
{
if (_initial_value < 0)
{
this->run();
_ms_to_go = _repeat_value;
}
else
{
_ms_to_go = _initial_value;
}
}
SGEvent::SGEvent( const char* name,
const SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value )
: _name(name),
_callback(NULL),
_subsystem((SGSubsystem*)&subsystem),
_repeat_value(repeat_value),
_initial_value(initial_value),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
{
if (_initial_value < 0)
{
this->run();
_ms_to_go = _repeat_value;
}
else
{
_ms_to_go = _initial_value;
}
}
SGEvent::~SGEvent()
{
//delete callback_;
}
void
SGEvent::run()
{
SGTimeStamp start_time;
SGTimeStamp finish_time;
start_time.stamp();
// run the event
if (_callback)
{
(*_callback)();
} else if (_subsystem)
{
_subsystem->update(_repeat_value);
}
finish_time.stamp();
++_count;
unsigned long duration = finish_time - start_time;
_cum_time += duration;
if ( duration < _min_time ) {
_min_time = duration;
}
if ( duration > _max_time ) {
_max_time = duration;
}
}
void
SGEvent::print_stats() const
{
SG_LOG( SG_EVENT, SG_INFO,
" " << _name
<< " int=" << _repeat_value / 1000.0
<< " cum=" << _cum_time
<< " min=" << _min_time
<< " max=" << _max_time
<< " count=" << _count
<< " ave=" << _cum_time / (double)_count );
}
SGEventMgr::SGEventMgr()
{
}
SGEventMgr::~SGEventMgr()
{
}
void
SGEventMgr::init()
{
SG_LOG( SG_EVENT, SG_INFO, "Initializing event manager" );
event_table.clear();
}
void
SGEventMgr::reinit()
{
}
void
SGEventMgr::bind()
{
}
void
SGEventMgr::unbind()
{
}
void
SGEventMgr::update( double dt )
{
int dt_ms = int(dt * 1000);
if (dt_ms < 0)
{
SG_LOG( SG_GENERAL, SG_ALERT,
"SGEventMgr::update() called with negative delta T" );
return;
}
int min_value = 0;
event_container_type::iterator first = event_table.begin();
event_container_type::iterator last = event_table.end();
event_container_type::iterator event = event_table.end();
// Scan all events. Run one whose interval has expired.
while (first != last)
{
if (first->update( dt_ms ))
{
if (first->value() < min_value)
{
// Select event with largest negative value.
// Its been waiting longest.
min_value = first->value();
event = first;
}
}
++first;
}
if (event != last)
{
event->run();
if (event->repeat_value() > 0)
{
event->reset();
}
else
{
SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting event " << event->name() );
event_table.erase( event );
}
}
}
void
SGEventMgr::add( const SGEvent& event )
{
event_table.push_back( event );
SG_LOG( SG_EVENT, SG_INFO, "registered event " << event.name()
<< " to run every " << event.repeat_value() << "ms" );
}
void
SGEventMgr::print_stats() const
{
SG_LOG( SG_EVENT, SG_INFO, "" );
SG_LOG( SG_EVENT, SG_INFO, "Event Stats" );
SG_LOG( SG_EVENT, SG_INFO, "-----------" );
event_container_type::const_iterator first = event_table.begin();
event_container_type::const_iterator last = event_table.end();
for (; first != last; ++first)
{
first->print_stats();
}
SG_LOG( SG_EVENT, SG_INFO, "" );
}
+209
View File
@@ -0,0 +1,209 @@
// eventmMgr.hxx -- periodic event scheduler
//
// Written by Curtis Olson, started December 1997.
// Modified by Bernie Bright, April 2002.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifndef SG_EVENT_MGR_HXX
#define SG_EVENT_MGR_HXX 1
#include <simgear/compiler.h>
#include <simgear/structure/callback.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/timestamp.hxx>
#include <vector>
#include <string>
SG_USING_STD(vector);
SG_USING_STD(string);
class SGEvent
{
public:
typedef int interval_type;
private:
string _name;
SGCallback* _callback;
SGSubsystem* _subsystem;
interval_type _repeat_value;
interval_type _initial_value;
int _ms_to_go;
unsigned long _cum_time; // cumulative processor time of this event
unsigned long _min_time; // time of quickest execution
unsigned long _max_time; // time of slowest execution
unsigned long _count; // number of times executed
public:
/**
*
*/
SGEvent();
SGEvent( const char* desc,
SGCallback* cb,
interval_type repeat_value,
interval_type initial_value );
SGEvent( const char* desc,
const SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value );
/**
*
*/
~SGEvent();
/**
*
*/
inline void reset()
{
_ms_to_go = _repeat_value;
}
/**
* Execute this event's callback.
*/
void run();
inline string name() const { return _name; }
inline interval_type repeat_value() const { return _repeat_value; }
inline int value() const { return _ms_to_go; }
/**
* Display event statistics.
*/
void print_stats() const;
/**
* Update the elapsed time for this event.
* @param dt_ms elapsed time in milliseconds.
* @return true if elapsed time has expired.
*/
inline bool update( int dt_ms )
{
return (_ms_to_go -= dt_ms) <= 0;
}
};
class SGEventMgr : public SGSubsystem
{
private:
typedef SGEvent::interval_type interval_type;
typedef vector< SGEvent > event_container_type;
void add( const SGEvent& event );
// registered events.
event_container_type event_table;
public:
SGEventMgr();
~SGEventMgr();
/**
* Initialize the scheduling subsystem.
*/
void init();
void reinit();
void bind();
void unbind();
/*
* Update the elapsed time for all events.
* @param dt elapsed time in seconds.
*/
void update( double dt );
/**
* register a free standing function to be executed some time in the future.
* @param desc A brief description of this callback for logging.
* @param cb The callback function to be executed.
* @param repeat_value repetition rate in milliseconds.
* @param initial_value initial delay value in milliseconds. A value of
* -1 means run immediately.
*/
template< typename Fun >
inline void add( const char* name,
const Fun& f,
interval_type repeat_value,
interval_type initial_value = -1 )
{
this->add( SGEvent( name,
make_callback(f),
repeat_value,
initial_value ) );
}
/**
* register a subsystem of which the update function will be executed some
* time in the future.
* @param desc A brief description of this callback for logging.
* @param subsystem The subsystem of which the update function will be
* executed.
* @param repeat_value repetition rate in milliseconds.
* @param initial_value initial delay value in milliseconds. A value of
* -1 means run immediately.
*/
inline void add( const char* name,
const SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value = -1 )
{
this->add( SGEvent( name,
subsystem,
repeat_value,
initial_value ) );
}
template< class ObjPtr, typename MemFn >
inline void add( const char* name,
const ObjPtr& p,
MemFn pmf,
interval_type repeat_value,
interval_type initial_value = -1 )
{
this->add( SGEvent( name,
make_callback(p,pmf),
repeat_value,
initial_value ) );
}
/**
* Display statistics for all registered events.
*/
void print_stats() const;
};
#endif //SG_EVENT_MGR_HXX
+307
View File
@@ -0,0 +1,307 @@
// exception.cxx - implementation of SimGear base exceptions.
// Started Summer 2001 by David Megginson, david@megginson.com
// This code is released into the Public Domain.
//
// $Id$
#include "exception.hxx"
#include <stdio.h>
////////////////////////////////////////////////////////////////////////
// Implementation of sg_location class.
////////////////////////////////////////////////////////////////////////
sg_location::sg_location ()
: _path(""),
_line(-1),
_column(-1),
_byte(-1)
{
}
sg_location::sg_location (const string &path, int line, int column)
: _path(path),
_line(line),
_column(column),
_byte(-1)
{
}
sg_location::~sg_location ()
{
}
const string &
sg_location::getPath () const
{
return _path;
}
void
sg_location::setPath (const string &path)
{
_path = path;
}
int
sg_location::getLine () const
{
return _line;
}
void
sg_location::setLine (int line)
{
_line = line;
}
int
sg_location::getColumn () const
{
return _column;
}
void
sg_location::setColumn (int column)
{
_column = column;
}
int
sg_location::getByte () const
{
return _byte;
}
void
sg_location::setByte (int byte)
{
_byte = byte;
}
string
sg_location::asString () const
{
char buf[128];
string out = "";
if (_path != (string)"") {
out += _path;
if (_line != -1 || _column != -1)
out += ",\n";
}
if (_line != -1) {
sprintf(buf, "line %d", _line);
out += buf;
if (_column != -1)
out += ", ";
}
if (_column != -1) {
sprintf(buf, "column %d", _column);
out += buf;
}
return out;
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_throwable class.
////////////////////////////////////////////////////////////////////////
sg_throwable::sg_throwable ()
: _message(""),
_origin("")
{
}
sg_throwable::sg_throwable (const string &message, const string &origin)
: _message(message),
_origin(origin)
{
}
sg_throwable::~sg_throwable ()
{
}
const string &
sg_throwable::getMessage () const
{
return _message;
}
const string
sg_throwable::getFormattedMessage () const
{
return getMessage();
}
void
sg_throwable::setMessage (const string &message)
{
_message = message;
}
const string &
sg_throwable::getOrigin () const
{
return _origin;
}
void
sg_throwable::setOrigin (const string &origin)
{
_origin = origin;
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_error class.
////////////////////////////////////////////////////////////////////////
sg_error::sg_error ()
: sg_throwable ()
{
}
sg_error::sg_error (const string &message, const string &origin)
: sg_throwable(message, origin)
{
}
sg_error::~sg_error ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_exception class.
////////////////////////////////////////////////////////////////////////
sg_exception::sg_exception ()
: sg_throwable ()
{
}
sg_exception::sg_exception (const string &message, const string &origin)
: sg_throwable(message, origin)
{
}
sg_exception::~sg_exception ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_io_exception.
////////////////////////////////////////////////////////////////////////
sg_io_exception::sg_io_exception ()
: sg_exception()
{
}
sg_io_exception::sg_io_exception (const string &message, const string &origin)
: sg_exception(message, origin)
{
}
sg_io_exception::sg_io_exception (const string &message,
const sg_location &location,
const string &origin)
: sg_exception(message, origin),
_location(location)
{
}
sg_io_exception::~sg_io_exception ()
{
}
const string
sg_io_exception::getFormattedMessage () const
{
string ret = getMessage();
ret += "\n at ";
ret += getLocation().asString();
return ret;
}
const sg_location &
sg_io_exception::getLocation () const
{
return _location;
}
void
sg_io_exception::setLocation (const sg_location &location)
{
_location = location;
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_format_exception.
////////////////////////////////////////////////////////////////////////
sg_format_exception::sg_format_exception ()
: sg_exception(),
_text("")
{
}
sg_format_exception::sg_format_exception (const string &message,
const string &text,
const string &origin)
: sg_exception(message, origin),
_text(text)
{
}
sg_format_exception::~sg_format_exception ()
{
}
const string &
sg_format_exception::getText () const
{
return _text;
}
void
sg_format_exception::setText (const string &text)
{
_text = text;
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_range_exception.
////////////////////////////////////////////////////////////////////////
sg_range_exception::sg_range_exception ()
: sg_exception()
{
}
sg_range_exception::sg_range_exception (const string &message,
const string &origin)
: sg_exception(message, origin)
{
}
sg_range_exception::~sg_range_exception ()
{
}
// end of exception.cxx
+182
View File
@@ -0,0 +1,182 @@
/**
* \file exception.hxx
* Interface definition for SimGear base exceptions.
* Started Spring 2001 by David Megginson, david@megginson.com
* This code is released into the Public Domain.
*
* $Id$
*/
#ifndef __SIMGEAR_MISC_EXCEPTION_HXX
#define __SIMGEAR_MISC_EXCEPTION_HXX 1
#include <simgear/compiler.h>
#include STL_STRING
SG_USING_STD(string);
/**
* Information encapsulating a single location in an external resource
*
* A position in the resource my optionally be provided, either by
* line number, line number and column number, or byte offset from the
* beginning of the resource.
*/
class sg_location
{
public:
sg_location ();
sg_location (const string &path, int line = -1, int column = -1);
virtual ~sg_location ();
virtual const string &getPath () const;
virtual void setPath (const string &path);
virtual int getLine () const;
virtual void setLine (int line);
virtual int getColumn () const;
virtual void setColumn (int column);
virtual int getByte () const;
virtual void setByte (int byte);
virtual string asString () const;
private:
string _path;
int _line;
int _column;
int _byte;
};
/**
* Abstract base class for all throwables.
*/
class sg_throwable
{
public:
sg_throwable ();
sg_throwable (const string &message, const string &origin = "");
virtual ~sg_throwable ();
virtual const string &getMessage () const;
virtual const string getFormattedMessage () const;
virtual void setMessage (const string &message);
virtual const string &getOrigin () const;
virtual void setOrigin (const string &origin);
private:
string _message;
string _origin;
};
/**
* An unexpected fatal error.
*
* Methods and functions show throw this exception when something
* very bad has happened (such as memory corruption or
* a totally unexpected internal value). Applications should catch
* this exception only at the top level if at all, and should
* normally terminate execution soon afterwards.
*/
class sg_error : public sg_throwable
{
public:
sg_error ();
sg_error (const string &message, const string &origin = "");
virtual ~sg_error ();
};
/**
* Base class for all SimGear exceptions.
*
* SimGear-based code should throw this exception only when no
* more specific exception applies. It may not be caught until
* higher up in the application, where it is not possible to
* resume normal operations if desired.
*
* A caller can catch sg_exception by default to ensure that
* all exceptions are caught. Every SimGear exception can contain
* a human-readable error message and a human-readable string
* indicating the part of the application causing the exception
* (as an aid to debugging, only).
*/
class sg_exception : public sg_throwable
{
public:
sg_exception ();
sg_exception (const string &message, const string &origin = "");
virtual ~sg_exception ();
};
/**
* An I/O-related SimGear exception.
*
* SimGear-based code should throw this exception when it fails
* to read from or write to an external resource, such as a file,
* socket, URL, or database.
*
* In addition to the functionality of sg_exception, an
* sg_io_exception may contain location information, such as the name
* of a file or URL, and possible also a location in that file or URL.
*/
class sg_io_exception : public sg_exception
{
public:
sg_io_exception ();
sg_io_exception (const string &message, const string &origin = "");
sg_io_exception (const string &message, const sg_location &location,
const string &origin = "");
virtual ~sg_io_exception ();
virtual const string getFormattedMessage () const;
virtual const sg_location &getLocation () const;
virtual void setLocation (const sg_location &location);
private:
sg_location _location;
};
/**
* A format-related SimGear exception.
*
* SimGear-based code should throw this exception when a string
* does not appear in the expected format (for example, a date
* string does not conform to ISO 8601).
*
* In addition to the functionality of sg_exception, an
* sg_format_exception can contain a copy of the original malformated
* text.
*/
class sg_format_exception : public sg_exception
{
public:
sg_format_exception ();
sg_format_exception (const string &message, const string &text,
const string &origin = "");
virtual ~sg_format_exception ();
virtual const string &getText () const;
virtual void setText (const string &text);
private:
string _text;
};
/**
* A range-related SimGear exception.
*
* SimGear-based code should throw this exception when a value falls
* outside the range where it can reasonably be handled; examples
* include longitude outside the range -180:180, unrealistically high
* forces or velocities, an illegal airport code, etc. A range
* exception usually means that something has gone wrong internally.
*/
class sg_range_exception : public sg_exception
{
public:
sg_range_exception ();
sg_range_exception (const string &message, const string &origin = "");
virtual ~sg_range_exception ();
};
#endif
// end of exception.hxx
+333
View File
@@ -0,0 +1,333 @@
#include <simgear/debug/logstream.hxx>
#include "exception.hxx"
#include "subsystem_mgr.hxx"
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystem
////////////////////////////////////////////////////////////////////////
SGSubsystem::SGSubsystem ()
: _suspended(false)
{
}
SGSubsystem::~SGSubsystem ()
{
}
void
SGSubsystem::init ()
{
}
void
SGSubsystem::reinit ()
{
}
void
SGSubsystem::bind ()
{
}
void
SGSubsystem::unbind ()
{
}
void
SGSubsystem::suspend ()
{
_suspended = true;
}
void
SGSubsystem::suspend (bool suspended)
{
_suspended = suspended;
}
void
SGSubsystem::resume ()
{
_suspended = false;
}
bool
SGSubsystem::is_suspended () const
{
return _suspended;
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystemGroup.
////////////////////////////////////////////////////////////////////////
SGSubsystemGroup::SGSubsystemGroup ()
{
}
SGSubsystemGroup::~SGSubsystemGroup ()
{
for (unsigned int i = 0; i < _members.size(); i++)
delete _members[i];
}
void
SGSubsystemGroup::init ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->init();
}
void
SGSubsystemGroup::reinit ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->reinit();
}
void
SGSubsystemGroup::bind ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->bind();
}
void
SGSubsystemGroup::unbind ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->unbind();
}
void
SGSubsystemGroup::update (double delta_time_sec)
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->update(delta_time_sec); // indirect call
}
void
SGSubsystemGroup::suspend ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->suspend();
}
void
SGSubsystemGroup::resume ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->resume();
}
bool
SGSubsystemGroup::is_suspended () const
{
return false;
}
void
SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
double min_step_sec)
{
Member * member = get_member(name, true);
if (member->subsystem != 0)
delete member->subsystem;
member->name = name;
member->subsystem = subsystem;
member->min_step_sec = min_step_sec;
}
SGSubsystem *
SGSubsystemGroup::get_subsystem (const string &name)
{
Member * member = get_member(name);
if (member != 0)
return member->subsystem;
else
return 0;
}
void
SGSubsystemGroup::remove_subsystem (const string &name)
{
for (unsigned int i = 0; i < _members.size(); i++) {
if (name == _members[i]->name) {
_members.erase(_members.begin() + i);
return;
}
}
}
bool
SGSubsystemGroup::has_subsystem (const string &name) const
{
return (((SGSubsystemGroup *)this)->get_member(name) != 0);
}
SGSubsystemGroup::Member *
SGSubsystemGroup::get_member (const string &name, bool create)
{
for (unsigned int i = 0; i < _members.size(); i++) {
if (_members[i]->name == name)
return _members[i];
}
if (create) {
Member * member = new Member;
_members.push_back(member);
return member;
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystemGroup::Member
////////////////////////////////////////////////////////////////////////
SGSubsystemGroup::Member::Member ()
: name(""),
subsystem(0),
min_step_sec(0),
elapsed_sec(0)
{
}
SGSubsystemGroup::Member::Member (const Member &)
{
Member();
}
SGSubsystemGroup::Member::~Member ()
{
// FIXME: causes a crash
// delete subsystem;
}
void
SGSubsystemGroup::Member::update (double delta_time_sec)
{
elapsed_sec += delta_time_sec;
if (elapsed_sec >= min_step_sec) {
if (!subsystem->is_suspended()) {
subsystem->update(elapsed_sec);
elapsed_sec = 0;
}
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystemMgr.
////////////////////////////////////////////////////////////////////////
SGSubsystemMgr::SGSubsystemMgr ()
{
}
SGSubsystemMgr::~SGSubsystemMgr ()
{
}
void
SGSubsystemMgr::init ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].init();
}
void
SGSubsystemMgr::reinit ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].reinit();
}
void
SGSubsystemMgr::bind ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].bind();
}
void
SGSubsystemMgr::unbind ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].unbind();
}
void
SGSubsystemMgr::update (double delta_time_sec)
{
for (int i = 0; i < MAX_GROUPS; i++) {
_groups[i].update(delta_time_sec);
}
}
void
SGSubsystemMgr::suspend ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].suspend();
}
void
SGSubsystemMgr::resume ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].resume();
}
bool
SGSubsystemMgr::is_suspended () const
{
return false;
}
void
SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
GroupType group, double min_time_sec)
{
SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
get_group(group)->set_subsystem(name, subsystem, min_time_sec);
if (_subsystem_map.find(name) != _subsystem_map.end()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
throw sg_exception("duplicate subsystem");
}
_subsystem_map[name] = subsystem;
}
SGSubsystemGroup *
SGSubsystemMgr::get_group (GroupType group)
{
return &(_groups[group]);
}
SGSubsystem *
SGSubsystemMgr::get_subsystem (const string &name)
{
map<string,SGSubsystem *>::iterator s =_subsystem_map.find(name);
if (s == _subsystem_map.end())
return 0;
else
return s->second;
}
// end of fgfs.cxx
+345
View File
@@ -0,0 +1,345 @@
// Written by David Megginson, started 2000-12
//
// Copyright (C) 2000 David Megginson, david@megginson.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifndef __SUBSYSTEM_MGR_HXX
#define __SUBSYSTEM_MGR_HXX 1
#include <simgear/compiler.h>
#if 0
#ifdef HAVE_WINDOWS_H
# include <windows.h>
# include <float.h>
#endif
#include STL_STRING
SG_USING_STD(string);
#include <vector>
SG_USING_STD(vector);
#endif
#include <map>
SG_USING_STD(map);
#include <simgear/props/props.hxx>
/**
* Basic interface for all FlightGear subsystems.
*
* <p>This is an abstract interface that all FlightGear subsystems
* will eventually implement. It defines the basic operations for
* each subsystem: initialization, property binding and unbinding, and
* updating. Interfaces may define additional methods, but the
* preferred way of exchanging information with other subsystems is
* through the property tree.</p>
*
* <p>To publish information through a property, a subsystem should
* bind it to a variable or (if necessary) a getter/setter pair in the
* bind() method, and release the property in the unbind() method:</p>
*
* <pre>
* void MySubsystem::bind ()
* {
* fgTie("/controls/flight/elevator", &_elevator);
* fgSetArchivable("/controls/flight/elevator");
* }
*
* void MySubsystem::unbind ()
* {
* fgUntie("/controls/flight/elevator");
* }
* </pre>
*
* <p>To reference a property (possibly) from another subsystem, there
* are two alternatives. If the property will be referenced only
* infrequently (say, in the init() method), then the fgGet* methods
* declared in fg_props.hxx are the simplest:</p>
*
* <pre>
* void MySubsystem::init ()
* {
* _errorMargin = fgGetFloat("/display/error-margin-pct");
* }
* </pre>
*
* <p>On the other hand, if the property will be referenced frequently
* (say, in the update() method), then the hash-table lookup required
* by the fgGet* methods might be too expensive; instead, the
* subsystem should obtain a reference to the actual property node in
* its init() function and use that reference in the main loop:</p>
*
* <pre>
* void MySubsystem::init ()
* {
* _errorNode = fgGetNode("/display/error-margin-pct", true);
* }
*
* void MySubsystem::update (double delta_time_sec)
* {
* do_something(_errorNode.getFloatValue());
* }
* </pre>
*
* <p>The node returned will always be a pointer to SGPropertyNode,
* and the subsystem should <em>not</em> delete it in its destructor
* (the pointer belongs to the property tree, not the subsystem).</p>
*
* <p>The program may ask the subsystem to suspend or resume
* sim-time-dependent operations; by default, the suspend() and
* resume() methods set the protected variable <var>_suspended</var>,
* which the subsystem can reference in its update() method, but
* subsystems may also override the suspend() and resume() methods to
* take different actions.</p>
*/
class SGSubsystem
{
public:
/**
* Default constructor.
*/
SGSubsystem ();
/**
* Virtual destructor to ensure that subclass destructors are called.
*/
virtual ~SGSubsystem ();
/**
* Initialize the subsystem.
*
* <p>This method should set up the state of the subsystem, but
* should not bind any properties. Note that any dependencies on
* the state of other subsystems should be placed here rather than
* in the constructor, so that FlightGear can control the
* initialization order.</p>
*/
virtual void init ();
/**
* Reinitialize the subsystem.
*
* <p>This method should cause the subsystem to reinitialize itself,
* and (normally) to reload any configuration files.</p>
*/
virtual void reinit ();
/**
* Acquire the subsystem's property bindings.
*
* <p>This method should bind all properties that the subsystem
* publishes. It will be invoked after init, but before any
* invocations of update.</p>
*/
virtual void bind ();
/**
* Release the subsystem's property bindings.
*
* <p>This method should release all properties that the subsystem
* publishes. It will be invoked by FlightGear (not the destructor)
* just before the subsystem is removed.</p>
*/
virtual void unbind ();
/**
* Update the subsystem.
*
* <p>FlightGear invokes this method every time the subsystem should
* update its state.</p>
*
* @param delta_time_sec The delta time, in seconds, since the last
* update. On first update, delta time will be 0.
*/
virtual void update (double delta_time_sec) = 0;
/**
* Suspend operation of this subsystem.
*
* <p>This method instructs the subsystem to suspend
* sim-time-dependent operations until asked to resume. The update
* method will still be invoked so that the subsystem can take any
* non-time-dependent actions, such as updating the display.</p>
*
* <p>It is not an error for the suspend method to be invoked when
* the subsystem is already suspended; the invocation should simply
* be ignored.</p>
*/
virtual void suspend ();
/**
* Suspend or resum operation of this subsystem.
*
* @param suspended true if the subsystem should be suspended, false
* otherwise.
*/
virtual void suspend (bool suspended);
/**
* Resume operation of this subsystem.
*
* <p>This method instructs the subsystem to resume
* sim-time-depended operations. It is not an error for the resume
* method to be invoked when the subsystem is not suspended; the
* invocation should simply be ignored.</p>
*/
virtual void resume ();
/**
* Test whether this subsystem is suspended.
*
* @return true if the subsystem is suspended, false if it is not.
*/
virtual bool is_suspended () const;
protected:
bool _suspended;
};
/**
* A group of FlightGear subsystems.
*/
class SGSubsystemGroup : public SGSubsystem
{
public:
SGSubsystemGroup ();
virtual ~SGSubsystemGroup ();
virtual void init ();
virtual void reinit ();
virtual void bind ();
virtual void unbind ();
virtual void update (double delta_time_sec);
virtual void suspend ();
virtual void resume ();
virtual bool is_suspended () const;
virtual void set_subsystem (const string &name,
SGSubsystem * subsystem,
double min_step_sec = 0);
virtual SGSubsystem * get_subsystem (const string &name);
virtual void remove_subsystem (const string &name);
virtual bool has_subsystem (const string &name) const;
private:
struct Member {
Member ();
Member (const Member &member);
virtual ~Member ();
virtual void update (double delta_time_sec);
string name;
SGSubsystem * subsystem;
double min_step_sec;
double elapsed_sec;
};
Member * get_member (const string &name, bool create = false);
vector<Member *> _members;
};
/**
* Manage subsystems for FlightGear.
*
* This top-level subsystem will eventually manage all of the
* subsystems in FlightGear: it broadcasts its life-cycle events
* (init, bind, etc.) to all of the subsystems it manages. Subsystems
* are grouped to guarantee order of initialization and execution --
* currently, the only two groups are INIT and GENERAL, but others
* will appear in the future.
*
* All subsystems are named as well as grouped, and subsystems can be
* looked up by name and cast to the appropriate subtype when another
* subsystem needs to invoke specialized methods.
*
* The subsystem manager owns the pointers to all the subsystems in
* it.
*/
class SGSubsystemMgr : public SGSubsystem
{
public:
/**
* Types of subsystem groups.
*/
enum GroupType {
INIT = 0,
GENERAL,
MAX_GROUPS
};
SGSubsystemMgr ();
virtual ~SGSubsystemMgr ();
virtual void init ();
virtual void reinit ();
virtual void bind ();
virtual void unbind ();
virtual void update (double delta_time_sec);
virtual void suspend ();
virtual void resume ();
virtual bool is_suspended () const;
virtual void add (const char * name,
SGSubsystem * subsystem,
GroupType group = GENERAL,
double min_time_sec = 0);
virtual SGSubsystemGroup * get_group (GroupType group);
virtual SGSubsystem * get_subsystem(const string &name);
private:
SGSubsystemGroup _groups[MAX_GROUPS];
map<string,SGSubsystem *> _subsystem_map;
};
#endif // __SUBSYSTEM_MGR_HXX