From 8608a480736651999c5ea31a489343ee097ee915 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 30 Sep 2012 16:34:51 +0100 Subject: [PATCH] Initial work on dynamic subsystem creation. Make subsystems create-able and removable from commands. Only some subsystems are supported so far, since many have non-default constructors or other complexities. With this, change, it's possible to dynamically add and remove the traffic-manager at runtime, for example: fgcommand("add-subsystem", props.Node.new({ "subsystem": "traffic-manager", "name":"traffic-manager", "do-bind-init":1})); --- src/Main/CMakeLists.txt | 2 + src/Main/fg_commands.cxx | 92 ------------ src/Main/main.cxx | 3 + src/Main/subsystemFactory.cxx | 260 ++++++++++++++++++++++++++++++++++ src/Main/subsystemFactory.hxx | 44 ++++++ 5 files changed, 309 insertions(+), 92 deletions(-) create mode 100644 src/Main/subsystemFactory.cxx create mode 100644 src/Main/subsystemFactory.hxx diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt index 8a8769cd3..507c7beb5 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES options.cxx util.cxx positioninit.cxx + subsystemFactory.cxx ${RESOURCE_FILE} ) @@ -36,6 +37,7 @@ set(HEADERS options.hxx util.hxx positioninit.hxx + subsystemFactory.hxx ) get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES) diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index 5611cbf10..92bdea7c0 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -206,95 +206,6 @@ do_reset (const SGPropertyNode * arg) return true; } - -/** - * Built-in command: reinitialize one or more subsystems. - * - * subsystem[*]: the name(s) of the subsystem(s) to reinitialize; if - * none is specified, reinitialize all of them. - */ -static bool -do_reinit (const SGPropertyNode * arg) -{ - bool result = true; - - vector subsystems = arg->getChildren("subsystem"); - if (subsystems.size() == 0) { - globals->get_subsystem_mgr()->reinit(); - } else { - for ( unsigned int i = 0; i < subsystems.size(); i++ ) { - const char * name = subsystems[i]->getStringValue(); - SGSubsystem * subsystem = globals->get_subsystem(name); - if (subsystem == 0) { - result = false; - SG_LOG( SG_GENERAL, SG_ALERT, - "Subsystem " << name << " not found" ); - } else { - subsystem->reinit(); - } - } - } - - globals->get_event_mgr()->reinit(); - - return result; -} - -#if 0 - // - // these routines look useful ??? but are never used in the code ??? - // - -/** - * Built-in command: suspend one or more subsystems. - * - * subsystem[*] - the name(s) of the subsystem(s) to suspend. - */ -static bool -do_suspend (const SGPropertyNode * arg) -{ - bool result = true; - - vector subsystems = arg->getChildren("subsystem"); - for ( unsigned int i = 0; i < subsystems.size(); i++ ) { - const char * name = subsystems[i]->getStringValue(); - SGSubsystem * subsystem = globals->get_subsystem(name); - if (subsystem == 0) { - result = false; - SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found"); - } else { - subsystem->suspend(); - } - } - return result; -} - -/** - * Built-in command: suspend one or more subsystems. - * - * subsystem[*] - the name(s) of the subsystem(s) to suspend. - */ -static bool -do_resume (const SGPropertyNode * arg) -{ - bool result = true; - - vector subsystems = arg->getChildren("subsystem"); - for ( unsigned int i = 0; i < subsystems.size(); i++ ) { - const char * name = subsystems[i]->getStringValue(); - SGSubsystem * subsystem = globals->get_subsystem(name); - if (subsystem == 0) { - result = false; - SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found"); - } else { - subsystem->resume(); - } - } - return result; -} - -#endif - /** * Built-in command: replay the FDR buffer */ @@ -1526,9 +1437,6 @@ static struct { { "nasal", do_nasal }, { "exit", do_exit }, { "reset", do_reset }, - { "reinit", do_reinit }, - { "suspend", do_reinit }, - { "resume", do_reinit }, { "pause", do_pause }, { "load", do_load }, { "save", do_save }, diff --git a/src/Main/main.cxx b/src/Main/main.cxx index 8bbb45648..c7d2a0db2 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -62,6 +62,7 @@ #include "fg_os.hxx" #include "fg_props.hxx" #include "positioninit.hxx" +#include "subsystemFactory.hxx" using namespace flightgear; @@ -156,6 +157,8 @@ static void fgIdleFunction ( void ) { //////////////////////////////////////////////////////////////////// fgInitCommands(); + flightgear::registerSubsystemCommands(globals->get_commands()); + //////////////////////////////////////////////////////////////////// // Initialize the material manager //////////////////////////////////////////////////////////////////// diff --git a/src/Main/subsystemFactory.cxx b/src/Main/subsystemFactory.cxx new file mode 100644 index 000000000..3e6377906 --- /dev/null +++ b/src/Main/subsystemFactory.cxx @@ -0,0 +1,260 @@ +// subsystemFactory.cxx - factory for subsystems +// +// Copyright (C) 2012 James Turner zakalawe@mac.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "subsystemFactory.hxx" + +#include +#include +#include +#include +#include + +#include
+#include + +// subsystem includes +#include +#include +#include
+#include
+#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::vector; + +namespace flightgear +{ + +SGSubsystem* createSubsystemByName(const std::string& name) +{ +#define MAKE_SUB(cl, n) \ + if (name == n) return new cl; + + MAKE_SUB(FGControls, "controls"); + MAKE_SUB(FGSoundManager, "sound"); + MAKE_SUB(SGInterpolator, "interpolator"); + MAKE_SUB(FGProperties, "properties"); + MAKE_SUB(FDMShell, "fdm"); + MAKE_SUB(FGEnvironmentMgr, "environment"); + MAKE_SUB(Ephemeris, "ephemeris"); + MAKE_SUB(FGSystemMgr, "aircraft-systems"); + MAKE_SUB(FGInstrumentMgr, "instruments"); + MAKE_SUB(HUD, "hud"); + MAKE_SUB(FGIO, "io"); + MAKE_SUB(FGRouteMgr, "route-manager"); + + MAKE_SUB(FGTrafficManager, "traffic-manager"); + +#undef MAKE_SUB + + throw sg_range_exception("unknown subsystem:" + name); +} + +SGSubsystemMgr::GroupType mapGroupNameToType(const std::string& s) +{ + if (s == "init") return SGSubsystemMgr::INIT; + if (s == "general") return SGSubsystemMgr::GENERAL; + if (s == "fdm") return SGSubsystemMgr::FDM; + if (s == "post-fdm") return SGSubsystemMgr::POST_FDM; + if (s == "display") return SGSubsystemMgr::DISPLAY; + if (s == "sound") return SGSubsystemMgr::SOUND; + + SG_LOG(SG_GENERAL, SG_ALERT, "unrecognized subsystem group:" << s); + return SGSubsystemMgr::GENERAL; +} + +static bool +do_add_subsystem (const SGPropertyNode * arg) +{ + std::string subsystem(arg->getStringValue("subsystem")); + std::string name = arg->getStringValue("name"); + if (subsystem.empty() || name.empty()) { + SG_LOG(SG_GENERAL, SG_ALERT, "do_add_subsystem:" + << "no subsystem/name supplied"); + return false; + } + + if (globals->get_subsystem_mgr()->get_subsystem(name)) { + SG_LOG(SG_GENERAL, SG_ALERT, "do_add_subsystem:" + << "duplicate subsystem name:" << name); + return false; + } + + std::string groupname = arg->getStringValue("group"); + SGSubsystemMgr::GroupType group = SGSubsystemMgr::GENERAL; + if (!groupname.empty()) { + group = mapGroupNameToType(groupname); + } + + SGSubsystem* instance = NULL; + try { + instance = createSubsystemByName(subsystem); + } catch (sg_exception& e) { + SG_LOG(SG_GENERAL, SG_ALERT, "subsystem creation failed:" << + name << ":" << e.getFormattedMessage()); + return false; + } + + bool doInit = arg->getBoolValue("do-bind-init", false); + if (doInit) { + instance->bind(); + instance->init(); + } + + double minTime = arg->getDoubleValue("min-time-sec", 0.0); + globals->get_subsystem_mgr()->add(name.c_str(), instance, + group, minTime); + + return true; +} + +static bool do_remove_subsystem(const SGPropertyNode * arg) +{ + std::string name = arg->getStringValue("subsystem"); + + SGSubsystem* instance = globals->get_subsystem_mgr()->get_subsystem(name); + if (!instance) { + SG_LOG(SG_GENERAL, SG_ALERT, "do_remove_subsystem: unknown subsytem:" << name); + return false; + } + + // is it safe to always call these? let's assume so! + instance->shutdown(); + instance->unbind(); + + // unplug from the manager + globals->get_subsystem_mgr()->remove(name.c_str()); + + // and finally kill off the instance. + delete instance; + + return true; +} + +/** + * Built-in command: reinitialize one or more subsystems. + * + * subsystem[*]: the name(s) of the subsystem(s) to reinitialize; if + * none is specified, reinitialize all of them. + */ +static bool +do_reinit (const SGPropertyNode * arg) +{ + bool result = true; + + vector subsystems = arg->getChildren("subsystem"); + if (subsystems.size() == 0) { + globals->get_subsystem_mgr()->reinit(); + } else { + for ( unsigned int i = 0; i < subsystems.size(); i++ ) { + const char * name = subsystems[i]->getStringValue(); + SGSubsystem * subsystem = globals->get_subsystem(name); + if (subsystem == 0) { + result = false; + SG_LOG( SG_GENERAL, SG_ALERT, + "Subsystem " << name << " not found" ); + } else { + subsystem->reinit(); + } + } + } + + globals->get_event_mgr()->reinit(); + + return result; +} + +/** + * Built-in command: suspend one or more subsystems. + * + * subsystem[*] - the name(s) of the subsystem(s) to suspend. + */ +static bool +do_suspend (const SGPropertyNode * arg) +{ + bool result = true; + + vector subsystems = arg->getChildren("subsystem"); + for ( unsigned int i = 0; i < subsystems.size(); i++ ) { + const char * name = subsystems[i]->getStringValue(); + SGSubsystem * subsystem = globals->get_subsystem(name); + if (subsystem == 0) { + result = false; + SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found"); + } else { + subsystem->suspend(); + } + } + return result; +} + +/** + * Built-in command: suspend one or more subsystems. + * + * subsystem[*] - the name(s) of the subsystem(s) to suspend. + */ +static bool +do_resume (const SGPropertyNode * arg) +{ + bool result = true; + + vector subsystems = arg->getChildren("subsystem"); + for ( unsigned int i = 0; i < subsystems.size(); i++ ) { + const char * name = subsystems[i]->getStringValue(); + SGSubsystem * subsystem = globals->get_subsystem(name); + if (subsystem == 0) { + result = false; + SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found"); + } else { + subsystem->resume(); + } + } + return result; +} + +static struct { + const char * name; + SGCommandMgr::command_t command; +} built_ins [] = { + { "add-subsystem", do_add_subsystem }, + { "remove-subsystem", do_remove_subsystem }, + { "reinit", do_reinit }, + { "suspend", do_suspend }, + { "resume", do_resume }, + { 0, 0 } // zero-terminated +}; + +void registerSubsystemCommands(SGCommandMgr* cmdMgr) +{ + for (int i = 0; built_ins[i].name != 0; i++) { + cmdMgr->addCommand(built_ins[i].name, built_ins[i].command); + } +} + +} // of namepace flightgear diff --git a/src/Main/subsystemFactory.hxx b/src/Main/subsystemFactory.hxx new file mode 100644 index 000000000..cba14abed --- /dev/null +++ b/src/Main/subsystemFactory.hxx @@ -0,0 +1,44 @@ +// subsystemFactory.hxx - factory for subsystems +// +// Copyright (C) 2012 James Turner zakalawe@mac.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#ifndef FG_SUBSYSTEM_FACTORY_HXX +#define FG_SUBSYSTEM_FACTORY_HXX + +#include + +// forward decls +class SGCommandMgr; +class SGSubsystem; + +namespace flightgear +{ + +/** + * create a subsystem by name, and return it. + * Will throw an exception if the subsytem name is invalid, or + * if the subsytem could not be created for some other reason. + * ownership of the subsystem passes to the caller + */ +SGSubsystem* createSubsystemByName(const std::string& name); + +void registerSubsystemCommands(SGCommandMgr* cmdMgr); + +} // of namespace flightgear + +#endif // of FG_POSITION_INIT_HXX -- 2.39.5