1
0
Fork 0

Allow add/remove of IO channels at runtime

Commands:

	add-io-channel
	remove-io-channel
This commit is contained in:
James Turner 2019-12-19 00:00:41 +00:00
parent f76709a853
commit be628b36b7
4 changed files with 95 additions and 18 deletions

View file

@ -40,6 +40,7 @@
#include <simgear/math/sg_types.hxx> #include <simgear/math/sg_types.hxx>
#include <simgear/timing/timestamp.hxx> #include <simgear/timing/timestamp.hxx>
#include <simgear/misc/strutils.hxx> #include <simgear/misc/strutils.hxx>
#include <simgear/structure/commands.hxx>
#include <Network/protocol.hxx> #include <Network/protocol.hxx>
#include <Network/ATC-Main.hxx> #include <Network/ATC-Main.hxx>
@ -87,24 +88,29 @@ FGIO::~FGIO()
// configure a port based on the config string // configure a port based on the config string
FGProtocol* FGProtocol*
FGIO::parse_port_config( const string& config ) FGIO::parse_port_config( const string& config )
{ {
SG_LOG( SG_IO, SG_INFO, "Parse I/O channel request: " << config ); SG_LOG( SG_IO, SG_INFO, "Parse I/O channel request: " << config );
string_list tokens = simgear::strutils::split( config, "," ); string_list tokens = simgear::strutils::split( config, "," );
if (tokens.empty()) if (tokens.empty())
{ {
SG_LOG( SG_IO, SG_ALERT, SG_LOG( SG_IO, SG_ALERT,
"Port configuration error: empty config string" ); "Port configuration error: empty config string" );
return NULL; return nullptr;
} }
string protocol = tokens[0]; return parse_port_config(tokens);
}
FGProtocol*
FGIO::parse_port_config( const string_list& tokens )
{
const string protocol = tokens[0];
SG_LOG( SG_IO, SG_INFO, " protocol = " << protocol ); SG_LOG( SG_IO, SG_INFO, " protocol = " << protocol );
FGProtocol *io = NULL; FGProtocol *io = nullptr;
try try
{ {
if ( protocol == "atcsim" ) { if ( protocol == "atcsim" ) {
@ -319,7 +325,7 @@ FGIO::parse_port_config( const string& config )
} }
else else
{ {
SG_LOG( SG_IO, SG_ALERT, "Unknown transport medium \"" << medium << "\" in \"" << config << "\""); SG_LOG( SG_IO, SG_ALERT, "Unknown transport medium \"" << medium << "\" for \"" << protocol << "\"");
delete io; delete io;
return nullptr; return nullptr;
} }
@ -342,32 +348,35 @@ FGIO::init()
// port onto the port list copies the structure and destroys the // port onto the port list copies the structure and destroys the
// original, which closes the port and frees up the fd ... doh!!! // original, which closes the port and frees up the fd ... doh!!!
string_list::iterator i = globals->get_channel_options_list()->begin(); for (const auto config : *(globals->get_channel_options_list())) {
string_list::iterator end = globals->get_channel_options_list()->end(); add_channel(config);
for (; i != end; ++i ) {
add_channel( *i );
} // of channel options iteration } // of channel options iteration
auto cmdMgr = globals->get_commands();
cmdMgr->addCommand("add-io-channel", this, &FGIO::commandAddChannel);
cmdMgr->addCommand("remove-io-channel", this, &FGIO::commandRemoveChannel);
} }
// add another I/O channel // add another I/O channel
void FGIO::add_channel(const string& config) FGProtocol* FGIO::add_channel(const string& config)
{ {
// parse the configuration string and store the results in the // parse the configuration string and store the results in the
// appropriate FGIOChannel structure // appropriate FGIOChannel structure
FGProtocol *p = parse_port_config( config ); FGProtocol *p = parse_port_config( config );
if (!p) if (!p)
{ {
return; return nullptr;
} }
p->open(); p->open();
if ( !p->is_enabled() ) { if ( !p->is_enabled() ) {
SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." ); SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." );
delete p; delete p;
return; return nullptr;
} }
io_channels.push_back( p ); io_channels.push_back( p );
return p;
} }
void void
@ -420,6 +429,10 @@ FGIO::shutdown()
} }
io_channels.clear(); io_channels.clear();
auto cmdMgr = globals->get_commands();
cmdMgr->removeCommand("add-io-channel");
cmdMgr->removeCommand("remove-io-channel");
} }
void void
@ -440,7 +453,7 @@ bool FGIO::isMultiplayerRequested()
// check the channel options list for a multiplay setting - this // check the channel options list for a multiplay setting - this
// is easier than checking the raw Options arguments, but works before // is easier than checking the raw Options arguments, but works before
// this subsytem is actuallyt created. // this subsytem is actually created.
auto channels = globals->get_channel_options_list(); auto channels = globals->get_channel_options_list();
if (!channels) if (!channels)
return false; // happens running tests return false; // happens running tests
@ -451,5 +464,56 @@ bool FGIO::isMultiplayerRequested()
return it != channels->end(); return it != channels->end();
} }
bool FGIO::commandAddChannel(const SGPropertyNode * arg, SGPropertyNode * root)
{
if (!arg->hasChild("config")) {
SG_LOG(SG_NETWORK, SG_WARN, "add-io-channel: missing 'config' argument");
return false;
}
const string name = arg->getStringValue("name");
const string config = arg->getStringValue("config");
auto protocol = add_channel(config);
if (!protocol) {
SG_LOG(SG_NETWORK, SG_WARN, "add-io-channel: adding channel failed");
return false;
}
if (!name.empty()) {
// TODO: add entry to /io/channels/<name>
// set the name so we can find the protocol again in the
// future
protocol->set_name(name);
}
return true;
}
bool FGIO::commandRemoveChannel(const SGPropertyNode * arg, SGPropertyNode * root)
{
if (!arg->hasChild("name")) {
SG_LOG(SG_NETWORK, SG_WARN, "remove-io-channel: missing 'name' argument");
}
const string name = arg->getStringValue("name");
auto it = find_if(io_channels.begin(), io_channels.end(),
[name](const FGProtocol* proto)
{ return proto->get_name() == name; });
if (it == io_channels.end()) {
SG_LOG(SG_NETWORK, SG_WARN, "remove-io-channel: no channel with name:" + name);
return false;
}
FGProtocol* p = *it;
if (p->is_enabled()) {
p->close();
}
delete p;
io_channels.erase(it);
return true;
}
// Register the subsystem. // Register the subsystem.
SGSubsystemMgr::Registrant<FGIO> registrantFGIO; SGSubsystemMgr::Registrant<FGIO> registrantFGIO;

View file

@ -59,9 +59,10 @@ public:
static bool isMultiplayerRequested(); static bool isMultiplayerRequested();
private: private:
void add_channel(const std::string& config); FGProtocol* add_channel(const std::string& config);
FGProtocol* parse_port_config( const std::string& cfgstr );
FGProtocol* parse_port_config( const std::string& cfgstr );
FGProtocol* parse_port_config( const string_list& tokens );
private: private:
// define the global I/O channel list // define the global I/O channel list
//io_container global_io_list; //io_container global_io_list;
@ -70,6 +71,9 @@ private:
ProtocolVec io_channels; ProtocolVec io_channels;
SGPropertyNode_ptr _realDeltaTime; SGPropertyNode_ptr _realDeltaTime;
bool commandAddChannel(const SGPropertyNode * arg, SGPropertyNode * root);
bool commandRemoveChannel(const SGPropertyNode * arg, SGPropertyNode * root);
}; };
#endif // _FG_IO_HXX #endif // _FG_IO_HXX

View file

@ -33,7 +33,7 @@ FGProtocol::FGProtocol() :
count(0), count(0),
dir(SG_IO_NONE), dir(SG_IO_NONE),
enabled(false), enabled(false),
io(NULL) io(nullptr)
{ {
} }
@ -42,6 +42,10 @@ FGProtocol::~FGProtocol() {
delete io; delete io;
} }
void FGProtocol::set_name(const std::string& n)
{
m_name = n;
}
// standard I/O channel open routine // standard I/O channel open routine
bool FGProtocol::open() { bool FGProtocol::open() {

View file

@ -55,6 +55,7 @@ private:
bool enabled; bool enabled;
SGIOChannel *io; SGIOChannel *io;
std::string m_name;
public: public:
@ -92,6 +93,10 @@ public:
inline SGIOChannel *get_io_channel() const { return io; } inline SGIOChannel *get_io_channel() const { return io; }
inline void set_io_channel( SGIOChannel *c ) { io = c; } inline void set_io_channel( SGIOChannel *c ) { io = c; }
// allow storing an identifying name on the Protocol instance
void set_name(const std::string& n);
std::string get_name() const { return m_name; }
}; };