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/timing/timestamp.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/structure/commands.hxx>
#include <Network/protocol.hxx>
#include <Network/ATC-Main.hxx>
@ -87,24 +88,29 @@ FGIO::~FGIO()
// configure a port based on the config string
FGProtocol*
FGIO::parse_port_config( const string& config )
{
SG_LOG( SG_IO, SG_INFO, "Parse I/O channel request: " << config );
string_list tokens = simgear::strutils::split( config, "," );
if (tokens.empty())
{
SG_LOG( SG_IO, SG_ALERT,
"Port configuration error: empty config string" );
return NULL;
return nullptr;
}
return parse_port_config(tokens);
}
string protocol = tokens[0];
FGProtocol*
FGIO::parse_port_config( const string_list& tokens )
{
const string protocol = tokens[0];
SG_LOG( SG_IO, SG_INFO, " protocol = " << protocol );
FGProtocol *io = NULL;
FGProtocol *io = nullptr;
try
{
if ( protocol == "atcsim" ) {
@ -319,7 +325,7 @@ FGIO::parse_port_config( const string& config )
}
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;
return nullptr;
}
@ -342,32 +348,35 @@ FGIO::init()
// port onto the port list copies the structure and destroys the
// original, which closes the port and frees up the fd ... doh!!!
string_list::iterator i = globals->get_channel_options_list()->begin();
string_list::iterator end = globals->get_channel_options_list()->end();
for (; i != end; ++i ) {
add_channel( *i );
for (const auto config : *(globals->get_channel_options_list())) {
add_channel(config);
} // 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
void FGIO::add_channel(const string& config)
FGProtocol* FGIO::add_channel(const string& config)
{
// parse the configuration string and store the results in the
// appropriate FGIOChannel structure
FGProtocol *p = parse_port_config( config );
if (!p)
{
return;
return nullptr;
}
p->open();
if ( !p->is_enabled() ) {
SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." );
delete p;
return;
return nullptr;
}
io_channels.push_back( p );
return p;
}
void
@ -420,6 +429,10 @@ FGIO::shutdown()
}
io_channels.clear();
auto cmdMgr = globals->get_commands();
cmdMgr->removeCommand("add-io-channel");
cmdMgr->removeCommand("remove-io-channel");
}
void
@ -440,7 +453,7 @@ bool FGIO::isMultiplayerRequested()
// check the channel options list for a multiplay setting - this
// 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();
if (!channels)
return false; // happens running tests
@ -451,5 +464,56 @@ bool FGIO::isMultiplayerRequested()
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.
SGSubsystemMgr::Registrant<FGIO> registrantFGIO;

View file

@ -59,9 +59,10 @@ public:
static bool isMultiplayerRequested();
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 string_list& tokens );
private:
// define the global I/O channel list
//io_container global_io_list;
@ -70,6 +71,9 @@ private:
ProtocolVec io_channels;
SGPropertyNode_ptr _realDeltaTime;
bool commandAddChannel(const SGPropertyNode * arg, SGPropertyNode * root);
bool commandRemoveChannel(const SGPropertyNode * arg, SGPropertyNode * root);
};
#endif // _FG_IO_HXX

View file

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

View file

@ -55,7 +55,8 @@ private:
bool enabled;
SGIOChannel *io;
std::string m_name;
public:
FGProtocol();
@ -92,6 +93,10 @@ public:
inline SGIOChannel *get_io_channel() const { return io; }
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; }
};