Allow add/remove of IO channels at runtime
Commands: add-io-channel remove-io-channel
This commit is contained in:
parent
f76709a853
commit
be628b36b7
4 changed files with 95 additions and 18 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue