Nasal and event manager updates from Andy Ross.

This commit is contained in:
curt 2003-11-25 21:26:01 +00:00
parent 1786692406
commit 34e2a9dc37
5 changed files with 220 additions and 403 deletions

View File

@ -356,6 +356,7 @@ AC_CONFIG_FILES([ \
simgear/math/Makefile \
simgear/metar/Makefile \
simgear/misc/Makefile \
simgear/nasal/Makefile \
simgear/props/Makefile \
simgear/route/Makefile \
simgear/scene/Makefile \

View File

@ -24,6 +24,7 @@ SUBDIRS = \
magvar \
math \
$(METAR_DIRS) \
nasal \
props \
route \
scene \

View File

@ -24,7 +24,8 @@ typedef enum {
SG_CLIPPER = 0x00002000,
SG_NETWORK = 0x00004000,
SG_ATC = 0x00008000,
SG_UNDEFD = 0x00010000, // For range checking
SG_NASAL = 0x00010000,
SG_UNDEFD = 0x00020000, // For range checking
SG_ALL = 0xFFFFFFFF
} sgDebugClass;

View File

@ -1,258 +1,160 @@
//
// 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)
void SGEventMgr::add(SGCallback* cb,
double interval, double delay,
bool repeat, bool simtime)
{
SGTimer* t = new SGTimer;
t->interval = interval;
t->callback = cb;
t->mgr = this;
t->repeat = repeat;
t->simtime = simtime;
SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue;
q->insert(t, delay);
}
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)
void SGTimer::run()
{
if (_initial_value < 0)
{
this->run();
_ms_to_go = _repeat_value;
}
else
{
_ms_to_go = _initial_value;
(*callback)();
if(repeat) {
SGTimerQueue* q = simtime ? &mgr->_simQueue : &mgr->_rtQueue;
q->insert(this, interval);
} else {
delete callback;
delete this;
}
}
SGEvent::SGEvent( const char* name,
SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value )
: _name(name),
_callback(NULL),
_subsystem(subsystem),
_repeat_value(repeat_value),
_initial_value(initial_value),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
void SGEventMgr::update(double delta_time_sec)
{
if (_initial_value < 0)
{
this->run();
_ms_to_go = _repeat_value;
}
else
{
_ms_to_go = _initial_value;
_rtQueue.update(delta_time_sec);
if(!_freezeProp || _freezeProp->getBoolValue() == false)
_simQueue.update(delta_time_sec);
}
////////////////////////////////////////////////////////////////////////
// SGTimerQueue
// This is the priority queue implementation:
////////////////////////////////////////////////////////////////////////
SGTimerQueue::SGTimerQueue(int size)
{
_now = 0;
_numEntries = 0;
_tableSize = 1;
while(size > _tableSize)
_tableSize = ((_tableSize + 1)<<1) - 1;
_table = new HeapEntry[_tableSize];
for(int i=0; i<_tableSize; i++) {
_table[i].pri = 0;
_table[i].timer = 0;
}
}
SGEvent::~SGEvent()
SGTimerQueue::~SGTimerQueue()
{
//delete callback_;
delete[] _table;
}
void
SGEvent::run()
void SGTimerQueue::update(double deltaSecs)
{
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;
_now += deltaSecs;
while(_numEntries && nextTime() <= _now) {
SGTimer* t = remove();
t->run();
}
}
void
SGEvent::print_stats() const
void SGTimerQueue::insert(SGTimer* timer, double time)
{
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 );
if(time < 0) *(int*)0=0;
if(_numEntries >= _tableSize)
growArray();
_numEntries++;
_table[_numEntries-1].pri = -(_now + time);
_table[_numEntries-1].timer = timer;
siftUp(_numEntries-1);
}
SGEventMgr::SGEventMgr()
SGTimer* SGTimerQueue::remove(SGTimer* t)
{
int entry;
for(entry=0; entry<_numEntries; entry++)
if(_table[entry].timer == t)
break;
if(entry == _numEntries)
return 0;
// Swap in the last item in the table, and sift down
swap(entry, _numEntries-1);
_numEntries--;
siftDown(entry);
return t;
}
SGEventMgr::~SGEventMgr()
SGTimer* SGTimerQueue::remove()
{
}
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;
if(_numEntries == 0) {
return 0;
} else if(_numEntries == 1) {
_numEntries = 0;
return _table[0].timer;
}
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();
SGTimer *result = _table[0].timer;
_table[0] = _table[_numEntries - 1];
_numEntries--;
siftDown(0);
return result;
}
// Scan all events. Run one whose interval has expired.
while (first != last)
void SGTimerQueue::siftDown(int n)
{
// While we have a child bigger than us:
while(((lchild(n) < (_numEntries-1))
&& (_table[n].pri < _table[lchild(n)].pri))
||
((rchild(n) < (_numEntries-1))
&& (_table[n].pri < _table[rchild(n)].pri)))
{
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 );
// Swap us with the biggest child
if(_table[lchild(n)].pri > _table[rchild(n)].pri) {
swap(n, lchild(n));
n = lchild(n);
} else {
swap(n, rchild(n));
n = rchild(n);
}
}
}
void
SGEventMgr::add( const SGEvent& event )
void SGTimerQueue::siftUp(int n)
{
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();
while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) {
swap(n, parent(n));
n = parent(n);
}
SG_LOG( SG_EVENT, SG_INFO, "" );
siftDown(n);
}
void SGTimerQueue::growArray()
{
_tableSize = ((_tableSize+1)<<1) - 1;
HeapEntry *newTable = new HeapEntry[_tableSize];
for(int i=0; i<_numEntries; i++) {
newTable[i].pri = _table[i].pri;
newTable[i].timer = _table[i].timer;
}
delete[] _table;
_table = newTable;
}

View File

@ -1,209 +1,121 @@
// 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
#ifndef SG_EVENT_MGR_HXX
#define SG_EVENT_MGR_HXX 1
#include <simgear/compiler.h>
#include <simgear/structure/callback.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/timestamp.hxx>
#include <vector>
#include <string>
#include "callback.hxx"
SG_USING_STD(vector);
SG_USING_STD(string);
class SGEventMgr;
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,
SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value );
/**
*
*/
~SGEvent();
/**
*
*/
inline void reset()
{
_ms_to_go = _repeat_value;
}
/**
* Execute this event's callback.
*/
struct SGTimer {
double interval;
SGCallback* callback;
SGEventMgr* mgr;
bool repeat;
bool simtime;
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 SGTimerQueue {
public:
SGTimerQueue(int preSize=1);
~SGTimerQueue();
void update(double deltaSecs);
double now() { return _now; }
void insert(SGTimer* timer, double time);
SGTimer* remove(SGTimer* timer);
SGTimer* remove();
SGTimer* nextTimer() { return _numEntries ? _table[0].timer : 0; }
double nextTime() { return -_table[0].pri; }
private:
// The "priority" is stored as a negative time. This allows the
// implemenetation to treat the "top" of the heap as the largest
// value and avoids developer mindbugs. ;)
struct HeapEntry { double pri; SGTimer* timer; };
int parent(int n) { return ((n+1)/2) - 1; }
int lchild(int n) { return ((n+1)*2) - 1; }
int rchild(int n) { return ((n+1)*2 + 1) - 1; }
void swap(int a, int b) {
HeapEntry tmp = _table[a];
_table[a] = _table[b];
_table[b] = tmp;
}
void siftDown(int n);
void siftUp(int n);
void growArray();
void check();
double _now;
HeapEntry *_table;
int _numEntries;
int _tableSize;
};
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();
SGEventMgr() { _freezeProp = 0; }
virtual void init() {}
virtual void update(double delta_time_sec);
void setFreezeProperty(SGPropertyNode* node) { _freezeProp = node; }
/**
* Initialize the scheduling subsystem.
* Add a single function callback event as a repeating task.
* ex: addTask("foo", &Function ... )
*/
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 );
template<typename FUNC>
inline void addTask(const char* name, const FUNC& f,
double interval, double delay=0, bool sim=false)
{ add(make_callback(f), interval, delay, true, sim); }
/**
* 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.
* Add a single function callback event as a one-shot event.
* ex: addEvent("foo", &Function ... )
*/
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 ) );
}
template<typename FUNC>
inline void addEvent(const char* name, const FUNC& f,
double delay, bool sim=false)
{ add(make_callback(f), 0, delay, false, sim); }
/**
* 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.
* Add a object/method pair as a repeating task.
* ex: addTask("foo", &object, &ClassName::Method, ...)
*/
inline void add( const char* name,
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 ) );
}
template<class OBJ, typename METHOD>
inline void addTask(const char* name,
const OBJ& o, METHOD m,
double interval, double delay=0, bool sim=false)
{ add(make_callback(o,m), interval, delay, true, sim); }
/**
* Display statistics for all registered events.
* Add a object/method pair as a repeating task.
* ex: addEvent("foo", &object, &ClassName::Method, ...)
*/
void print_stats() const;
template<class OBJ, typename METHOD>
inline void addEvent(const char* name,
const OBJ& o, METHOD m,
double delay, bool sim=false)
{ add(make_callback(o,m), 0, delay, false, sim); }
private:
friend class SGTimer;
void add(SGCallback* cb,
double interval, double delay,
bool repeat, bool simtime);
SGPropertyNode* _freezeProp;
SGTimerQueue _rtQueue;
SGTimerQueue _simQueue;
};
#endif //SG_EVENT_MGR_HXX
#endif // _SG_EVENT_MGR_HXX