1
0
Fork 0

Implement the start of a property server using DDS.

This commit is contained in:
Erik Hofman 2021-04-06 14:52:37 +02:00
parent e203336546
commit 202c69ad77
8 changed files with 448 additions and 1 deletions

View file

@ -62,11 +62,16 @@ set(HEADERS
rul.hxx
)
if (CycloneDDS_FOUND)
set(SOURCES ${SOURCES} dds_props.cxx)
set(HEADERS ${HEADERS} dds_props.hxx)
endif()
if(ENABLE_IAX)
list(APPEND SOURCES fgcom.cxx)
list(APPEND HEADERS fgcom.hxx)
endif()
flightgear_component(Network "${SOURCES}" "${HEADERS}")
if (CycloneDDS_FOUND)

View file

@ -4,12 +4,14 @@ set(SOURCES
dds_ctrls.c
dds_gui.c
dds_fdm.c
dds_props.c
)
set(HEADERS
dds_ctrls.h
dds_fdm.h
dds_gui.h
dds_props.h
)
add_executable(fg_dds_log

View file

@ -0,0 +1,10 @@
// dds_fwd.hxx
//
// This file is in the Public Domain, and comes with no warranty.
#pragma once
#include "dds_gui.h"
#include "dds_fdm.h"
#include "dds_ctrls.h"

View file

@ -0,0 +1,46 @@
/****************************************************************
Generated by Eclipse Cyclone DDS IDL to C Translator
File name: dds_props.c
Source: dds_props.idl
Cyclone DDS: V0.7.0
*****************************************************************/
#include "dds_props.h"
static const dds_key_descriptor_t FG_DDS_PROP_keys[1] =
{
{ "id", 0 }
};
static const uint32_t FG_DDS_PROP_ops [] =
{
DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN | DDS_OP_FLAG_KEY, offsetof (FG_DDS_PROP, id),
DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN, offsetof (FG_DDS_PROP, type),
DDS_OP_ADR | DDS_OP_TYPE_UNI | DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_SGN, offsetof (FG_DDS_PROP, val._d), 9u, (31u << 16) + 4u,
DDS_OP_JEQ | DDS_OP_TYPE_BOO | 0, FG_DDS_BOOL, offsetof (FG_DDS_PROP, val._u.Bool),
DDS_OP_JEQ | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN | 0, FG_DDS_NONE, offsetof (FG_DDS_PROP, val._u.Int32),
DDS_OP_JEQ | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN | 0, FG_DDS_INT, offsetof (FG_DDS_PROP, val._u.Int32),
DDS_OP_JEQ | DDS_OP_TYPE_8BY | DDS_OP_FLAG_SGN | 0, FG_DDS_LONG, offsetof (FG_DDS_PROP, val._u.Int64),
DDS_OP_JEQ | DDS_OP_TYPE_4BY | DDS_OP_FLAG_FP | 0, FG_DDS_FLOAT, offsetof (FG_DDS_PROP, val._u.Float32),
DDS_OP_JEQ | DDS_OP_TYPE_8BY | DDS_OP_FLAG_FP | 0, FG_DDS_DOUBLE, offsetof (FG_DDS_PROP, val._u.Float64),
DDS_OP_JEQ | DDS_OP_TYPE_STR | 0, FG_DDS_ALIAS, offsetof (FG_DDS_PROP, val._u.String),
DDS_OP_JEQ | DDS_OP_TYPE_STR | 0, FG_DDS_STRING, offsetof (FG_DDS_PROP, val._u.String),
DDS_OP_JEQ | DDS_OP_TYPE_STR | 0, FG_DDS_UNSPECIFIED, offsetof (FG_DDS_PROP, val._u.String),
DDS_OP_ADR | DDS_OP_TYPE_STR, offsetof (FG_DDS_PROP, guid),
DDS_OP_RTS
};
const dds_topic_descriptor_t FG_DDS_PROP_desc =
{
sizeof (FG_DDS_PROP),
8u,
DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE | DDS_TOPIC_CONTAINS_UNION,
1u,
"FG::DDS_PROP",
FG_DDS_PROP_keys,
14,
FG_DDS_PROP_ops,
"<MetaData version=\"1.0.0\"><Module name=\"FG\"><Enum name=\"propType\"><Element name=\"DDS_NONE\" value=\"0\"/><Element name=\"DDS_ALIAS\" value=\"1\"/><Element name=\"DDS_BOOL\" value=\"2\"/><Element name=\"DDS_INT\" value=\"3\"/><Element name=\"DDS_LONG\" value=\"4\"/><Element name=\"DDS_FLOAT\" value=\"5\"/><Element name=\"DDS_DOUBLE\" value=\"6\"/><Element name=\"DDS_STRING\" value=\"7\"/><Element name=\"DDS_UNSPECIFIED\" value=\"8\"/></Enum><Union name=\"propValue\"><SwitchType><Type name=\"propType\"/></SwitchType><Case name=\"Bool\"><Boolean/><Label value=\"DDS_BOOL\"/></Case><Case name=\"Int32\"><Long/><Label value=\"DDS_NONE\"/><Label value=\"DDS_INT\"/></Case><Case name=\"Int64\"><LongLong/><Label value=\"DDS_LONG\"/></Case><Case name=\"Float32\"><Float/><Label value=\"DDS_FLOAT\"/></Case><Case name=\"Float64\"><Double/><Label value=\"DDS_DOUBLE\"/></Case><Case name=\"String\"><String/><Label value=\"DDS_ALIAS\"/><Label value=\"DDS_STRING\"/><Label value=\"DDS_UNSPECIFIED\"/></Case></Union><Struct name=\"DDS_PROP\"><Member name=\"id\"><Long/></Member><Member name=\"type\"><Type name=\"propType\"/></Member><Member name=\"val\"><Type name=\"propValue\"/></Member><Member name=\"guid\"><String/></Member></Struct></Module></MetaData>"
};

View file

@ -0,0 +1,75 @@
/****************************************************************
Generated by Eclipse Cyclone DDS IDL to C Translator
File name: dds_props.h
Source: dds_props.idl
Cyclone DDS: V0.7.0
*****************************************************************/
#include "dds/ddsc/dds_public_impl.h"
#ifndef _DDSL_DDS_PROPS_H_
#define _DDSL_DDS_PROPS_H_
#ifdef __cplusplus
extern "C" {
#endif
#define FG_DDS_PROP_REQUEST -1
typedef enum FG_propType
{
FG_DDS_NONE,
FG_DDS_ALIAS,
FG_DDS_BOOL,
FG_DDS_INT,
FG_DDS_LONG,
FG_DDS_FLOAT,
FG_DDS_DOUBLE,
FG_DDS_STRING,
FG_DDS_UNSPECIFIED
} FG_propType;
#define FG_propType__alloc() \
((FG_propType*) dds_alloc (sizeof (FG_propType)));
typedef struct FG_propValue
{
FG_propType _d;
union
{
bool Bool;
int32_t Int32;
int64_t Int64;
float Float32;
double Float64;
char * String;
} _u;
} FG_propValue;
#define FG_propValue__alloc() \
((FG_propValue*) dds_alloc (sizeof (FG_propValue)));
typedef struct FG_DDS_PROP
{
int32_t id;
FG_propType type;
FG_propValue val;
char * guid;
} FG_DDS_PROP;
extern const dds_topic_descriptor_t FG_DDS_PROP_desc;
#define FG_DDS_PROP__alloc() \
((FG_DDS_PROP*) dds_alloc (sizeof (FG_DDS_PROP)));
#define FG_DDS_PROP_free(d,o) \
dds_sample_free ((d), &FG_DDS_PROP_desc, (o))
#ifdef __cplusplus
}
#endif
#endif /* _DDSL_DDS_PROPS_H_ */

View file

@ -0,0 +1,85 @@
// format dfescription: https://www.omg.org/spec/IDL/4.2/PDF
// Adapted from net_fdm.hxx
module FG
{
// defining it this way also generates accompanying #defines in the header file.
const short DDS_PROP_REQUEST = -1;
enum propType
{
DDS_NONE, // The node hasn't been assigned a value yet
DDS_ALIAS, // The node "points" to another node
DDS_BOOL,
DDS_INT, // 32-bit integer
DDS_LONG, // 64-bit integer
DDS_FLOAT, // 32-bit floating point number
DDS_DOUBLE, // 64-bit floating point number
DDS_STRING, // UTF-8 string
DDS_UNSPECIFIED // Resolves to STRING
};
union propValue switch ( propType )
{
case DDS_BOOL:
boolean Bool;
case DDS_NONE:
case DDS_INT:
long Int32;
case DDS_LONG:
long long Int64;
case DDS_FLOAT:
float Float32;
case DDS_DOUBLE:
double Float64;
case DDS_ALIAS:
case DDS_STRING:
case DDS_UNSPECIFIED:
string String;
};
// Initial property request sequence
// for properties where the id is not yet known:
// 1. Set id to FG_DDS_PROP_REQUEST
// 2. set guid to the 16-byte participants GUID
// 3. Set type to STRING
// 4. Set val.String to the propery path
// 5. Send the package.
//
// 6. wait for an answer
// * Check whether guid matches the participants GUID.
// * The index of the requested propery path is stored in the id variable
// which should be used by successive request as the id for that property.
// * The type variable indicates the type of the value of the property.
// * The val union holds the value of the propery.
//
// Successive property request sequence:
// 1. Set id to the id of the requested property
// 2. Send the package.
//
// 3. wait for an answer
// * Check whether id matches the requested property id.
// * The type variable indicates the type of the value of the property.
// * The val union holds the value of the propery.
//
// guid is not defined as an array of 16 unsigned characters to keep the
// sample small for successive requests. This way only a FG_DDS_PROP_REQUEST
// sample will reserve the full 16-bytes.
struct DDS_PROP
{
long id; // property index and DDS id
propType type;
propValue val;
string guid; // requesters globally unique identifier
};
#pragma keylist DDS_PROP id
}; // module FG

167
src/Network/dds_props.cxx Normal file
View file

@ -0,0 +1,167 @@
// dds_props.cxx -- FGFS "DDS" properties protocal class
//
// Written by Erik Hofman, started April 2021
//
// Copyright (C) 2021 by Erik Hofman <erik@ehofman.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.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/debug/logstream.hxx>
#include <simgear/io/iochannel.hxx>
#include <simgear/props/props.hxx>
#include <simgear/io/SGDataDistributionService.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "dds_props.hxx"
// open hailing frequencies
bool FGDDSProps::open() {
if (is_enabled()) {
SG_LOG(SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
<< "is already in use, ignoring");
return false;
}
SGIOChannel *io = get_io_channel();
SG_DDS_Topic *dds = static_cast<SG_DDS_Topic*>(io);
dds->setup<FG_DDS_PROP>(&FG_DDS_PROP_desc);
// always send and recieve.
if (! io->open(SG_IO_BI)) {
SG_LOG(SG_IO, SG_ALERT, "Error opening channel communication layer.");
return false;
}
set_enabled(true);
return true;
}
// process work for this port
bool FGDDSProps::process() {
SGIOChannel *io = get_io_channel();
FG_DDS_PROP prop;
int length = sizeof(prop);
char *buf = reinterpret_cast<char*>(&prop);
if (get_direction() == SG_IO_IN)
{
// act as a client: send a request and wait for an answer.
}
else if (get_direction() == SG_IO_OUT)
{
// act as a server: read requests and send the results.
while (io->read(buf, length) == length)
{
if (prop.id == FG_DDS_PROP_REQUEST)
{
auto it = by_path.find(prop.val._u.String);
if (it == by_path.end())
{
SGPropertyNode_ptr props = globals->get_props();
SGPropertyNode_ptr p = props->getNode(prop.val._u.String);
if (p)
{
prop.id = by_id.size();
by_id[prop.id] = p;
by_path[prop.val._u.String] = p;
}
setProp(prop, p);
}
else
{
prop.id = std::distance(by_path.begin(), it);
setProp(prop, it->second);
}
}
else
{
SGPropertyNode_ptr p = by_id[prop.id];
setProp(prop, p);
}
// send the response.
if (! io->write(buf, length)) {
SG_LOG(SG_IO, SG_ALERT, "Error writing data.");
}
} // while
}
return true;
}
// close the channel
bool FGDDSProps::close() {
SGIOChannel *io = get_io_channel();
set_enabled(false);
if (! io->close()) {
return false;
}
return true;
}
void FGDDSProps::setProp(FG_DDS_PROP& prop, SGPropertyNode_ptr p)
{
if (p)
{
simgear::props::Type type = p->getType();
if (type == simgear::props::BOOL) {
prop.type = FG_DDS_BOOL;
prop.val._u.Bool = p->getBoolValue();
} else if (type == simgear::props::INT) {
prop.type = FG_DDS_INT;
prop.val._u.Int32 = p->getIntValue();
} else if (type == simgear::props::LONG) {
prop.type = FG_DDS_LONG;
prop.val._u.Int64 = p->getLongValue();
} else if (type == simgear::props::FLOAT) {
prop.type = FG_DDS_FLOAT;
prop.val._u.Float32 = p->getFloatValue();
} else if (type == simgear::props::DOUBLE) {
prop.type = FG_DDS_DOUBLE;
prop.val._u.Float64 = p->getDoubleValue();
} else if (type == simgear::props::ALIAS) {
prop.type = FG_DDS_ALIAS;
prop.val._u.String = const_cast<char*>(p->getStringValue());
} else if (type == simgear::props::STRING) {
prop.type = FG_DDS_STRING;
prop.val._u.String = const_cast<char*>(p->getStringValue());
} else if (type == simgear::props::UNSPECIFIED) {
prop.type = FG_DDS_UNSPECIFIED;
prop.val._u.String = const_cast<char*>(p->getStringValue());
} else {
prop.type = FG_DDS_NONE;
prop.val._u.Int32 = 0;
}
}
}

57
src/Network/dds_props.hxx Normal file
View file

@ -0,0 +1,57 @@
// dds_props.hxx -- FGFS "DDS" properties protocal class
//
// Written by Erik Hofman, started April 2021
//
// Copyright (C) 2021 by Erik Hofman <erik@ehofman.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.
//
// $Id$
#pragma once
#include <string>
#include <map>
#include <simgear/compiler.h>
#include <simgear/props/propsfwd.hxx>
#include "protocol.hxx"
#include "DDS/dds_props.h"
class FGDDSProps : public FGProtocol {
std::map<uint32_t,SGPropertyNode_ptr> by_id;
std::map<std::string,SGPropertyNode_ptr> by_path;
static void setProp(FG_DDS_PROP& prop, SGPropertyNode_ptr p);
public:
FGDDSProps() = default;
~FGDDSProps() = default;
// open hailing frequencies
bool open();
// process work for this port
bool process();
// close the channel
bool close();
};