1
0
Fork 0

Swift: initial support

This commit is contained in:
Lars Toenning 2019-03-04 22:18:15 +01:00 committed by James Turner
parent 8e1e6c8254
commit 85acefab95
33 changed files with 3476 additions and 1 deletions

View file

@ -202,6 +202,7 @@ option(ENABLE_DEMCONVERT "Set to ON to build the dem conversion tool (default)"
option(ENABLE_HID_INPUT "Set to ON to build HID-based input code" OFF) option(ENABLE_HID_INPUT "Set to ON to build HID-based input code" OFF)
option(ENABLE_PLIB_JOYSTICK "Set to ON to enable legacy joystick code (default)" ON) option(ENABLE_PLIB_JOYSTICK "Set to ON to enable legacy joystick code (default)" ON)
option(ENABLE_COMPOSITOR "Set to ON to enable the Compositor-based Viewer" OFF) option(ENABLE_COMPOSITOR "Set to ON to enable the Compositor-based Viewer" OFF)
option(ENABLE_SWIFT "Set to ON to build the swift module" OFF)
# Test-suite options. # Test-suite options.
@ -263,6 +264,21 @@ if(EVENT_INPUT)
endif() endif()
endif(EVENT_INPUT) endif(EVENT_INPUT)
if (ENABLE_SWIFT)
message(STATUS "SWIFT support requested, checking for DBus/libEvent")
# DBUS
find_package(DBus REQUIRED)
list(APPEND PLATFORM_LIBS ${DBUS_LIBRARIES})
#libevent
find_package(LibEvent REQUIRED)
list(APPEND PLATFORM_LIBS ${LIBEVENT_LIB})
if (NOT DBUS_LIBRARIES OR NOT LIBEVENT_LIB)
message(FATAL_ERROR "SWIFT support requested, please ensure DBus/libEvent are available")
endif()
endif()
# check required dependencies # check required dependencies
find_package(Boost REQUIRED) find_package(Boost REQUIRED)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
@ -497,7 +513,9 @@ include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${OPENGL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR}
${SIMGEAR_INCLUDE_DIRS} ${SIMGEAR_INCLUDE_DIRS}
${PLIB_INCLUDE_DIR} ${PLIB_INCLUDE_DIR}
${SQLITE3_INCLUDED_DIR} ) ${SQLITE3_INCLUDED_DIR}
${DBUS_INCLUDE_DIRS}
${LIBEVENT_INCLUDE_DIR} )
if (USE_AEONWAVE) if (USE_AEONWAVE)
find_package(AAX REQUIRED) find_package(AAX REQUIRED)

View file

@ -0,0 +1,59 @@
# - Try to find DBus
# Once done, this will define
#
# DBUS_FOUND - system has DBus
# DBUS_INCLUDE_DIRS - the DBus include directories
# DBUS_LIBRARIES - link these to use DBus
#
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PC_DBUS QUIET dbus-1)
FIND_LIBRARY(DBUS_LIBRARIES
NAMES dbus-1
HINTS ${PC_DBUS_LIBDIR}
${PC_DBUS_LIBRARY_DIRS}
)
FIND_PATH(DBUS_INCLUDE_DIR
NAMES dbus/dbus.h
HINTS ${PC_DBUS_INCLUDEDIR}
${PC_DBUS_INCLUDE_DIRS}
)
GET_FILENAME_COMPONENT(_DBUS_LIBRARY_DIR ${DBUS_LIBRARIES} PATH)
FIND_PATH(DBUS_ARCH_INCLUDE_DIR
NAMES dbus/dbus-arch-deps.h
HINTS ${PC_DBUS_INCLUDEDIR}
${PC_DBUS_INCLUDE_DIRS}
${_DBUS_LIBRARY_DIR}
${DBUS_INCLUDE_DIR}
PATH_SUFFIXES include
)
SET(DBUS_INCLUDE_DIRS ${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DBUS REQUIRED_VARS DBUS_INCLUDE_DIRS DBUS_LIBRARIES)

View file

@ -0,0 +1,11 @@
# Finding LibEvent (https://libevent.org/)
# Defining:
# LIBEVENT_LIB
# LIBEVENT_INCLUDE_DIR
find_path(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS})
find_library(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS})
if(LIBEVENT_INCLUDE_DIR AND LIBEVENT_LIB)
message(STATUS "LibEvent found.")
endif()

View file

@ -69,3 +69,5 @@
#cmakedefine HAVE_QRC_TRANSLATIONS #cmakedefine HAVE_QRC_TRANSLATIONS
#cmakedefine ENABLE_COMPOSITOR #cmakedefine ENABLE_COMPOSITOR
#cmakedefine ENABLE_SWIFT

View file

@ -30,6 +30,7 @@
#include <cstring> // strcmp() #include <cstring> // strcmp()
#if defined(SG_WINDOWS) #if defined(SG_WINDOWS)
#define _WINSOCKAPI_
# include <io.h> // isatty() # include <io.h> // isatty()
# include <process.h> // _getpid() # include <process.h> // _getpid()
# include <Windows.h> # include <Windows.h>
@ -117,6 +118,9 @@
#include <Traffic/TrafficMgr.hxx> #include <Traffic/TrafficMgr.hxx>
#include <MultiPlayer/multiplaymgr.hxx> #include <MultiPlayer/multiplaymgr.hxx>
#if defined(ENABLE_SWIFT)
#include <Network/Swift/swift_connection.hxx>
#endif
#include <FDM/fdm_shell.hxx> #include <FDM/fdm_shell.hxx>
#include <Environment/ephemeris.hxx> #include <Environment/ephemeris.hxx>
#include <Environment/environment_mgr.hxx> #include <Environment/environment_mgr.hxx>
@ -572,6 +576,12 @@ int fgInitConfig ( int argc, char **argv, bool reinit )
fgSetBool("/sim/developer-mode", developerMode); fgSetBool("/sim/developer-mode", developerMode);
sglog().setDeveloperMode(developerMode); sglog().setDeveloperMode(developerMode);
#ifdef ENABLE_SWIFT
//Set standard settings for swift connection
fgSetString("/sim/swift/adress","127.0.0.1");
fgSetString("/sim/swift/port","45003");
#endif
// Read global defaults from $FG_ROOT/defaults // Read global defaults from $FG_ROOT/defaults
SG_LOG(SG_GENERAL, SG_INFO, "Reading global defaults"); SG_LOG(SG_GENERAL, SG_INFO, "Reading global defaults");
SGPath defaultsXML = globals->get_fg_root() / "defaults.xml"; SGPath defaultsXML = globals->get_fg_root() / "defaults.xml";
@ -937,6 +947,14 @@ void fgCreateSubsystems(bool duringReset) {
globals->add_subsystem("mp", new FGMultiplayMgr, SGSubsystemMgr::POST_FDM); globals->add_subsystem("mp", new FGMultiplayMgr, SGSubsystemMgr::POST_FDM);
#ifdef ENABLE_SWIFT
////////////////////////////////////////////////////////////////////
// Initialize Swift subsystem
////////////////////////////////////////////////////////////////////
globals->add_subsystem("swift", new SwiftConnection, SGSubsystemMgr::POST_FDM);
#endif
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Initialise the AI Model Manager // Initialise the AI Model Manager
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View file

@ -54,6 +54,9 @@
#include <ATC/atc_mgr.hxx> #include <ATC/atc_mgr.hxx>
#include <AIModel/AIManager.hxx> #include <AIModel/AIManager.hxx>
#include <MultiPlayer/multiplaymgr.hxx> #include <MultiPlayer/multiplaymgr.hxx>
#if defined(ENABLE_SWIFT)
# include <Network/Swift/swift_connection.hxx>
#endif
#include <AIModel/submodel.hxx> #include <AIModel/submodel.hxx>
#include <Aircraft/controls.hxx> #include <Aircraft/controls.hxx>
#include <Input/input.hxx> #include <Input/input.hxx>
@ -107,6 +110,9 @@ SGSubsystem* createSubsystemByName(const std::string& name)
#endif #endif
#ifdef ENABLE_IAX #ifdef ENABLE_IAX
MAKE_SUB(FGCom, "fgcom"); MAKE_SUB(FGCom, "fgcom");
#endif
#ifdef ENABLE_SWIFT
MAKE_SUB(SwiftConnection, "swift");
#endif #endif
MAKE_SUB(FGLight, "lighting"); MAKE_SUB(FGLight, "lighting");
MAKE_SUB(FGAircraftModel, "aircraft-model"); MAKE_SUB(FGAircraftModel, "aircraft-model");

View file

@ -73,3 +73,6 @@ endif()
add_subdirectory(http) add_subdirectory(http)
if(ENABLE_SWIFT)
add_subdirectory(Swift)
endif()

View file

@ -0,0 +1,34 @@
include(FlightGearComponent)
set(SOURCES
swift_connection.cxx
dbusconnection.cpp
dbusobject.cpp
dbusmessage.cpp
dbusdispatcher.cpp
dbuserror.cpp
dbusserver.cpp
plugin.cpp
service.cpp
traffic.cpp
swiftaircraft.cpp
SwiftAircraftManager.cpp
)
set(HEADERS
swift_connection.hxx
dbusconnection.h
dbusobject.h
dbusmessage.h
dbuscallbacks.h
dbusdispatcher.h
dbuserror.h
dbusserver.h
plugin.h
service.h
traffic.h
swiftaircraft.h
SwiftAircraftManager.h
)
flightgear_component(Swift "${SOURCES}" "${HEADERS}")

View file

@ -0,0 +1,102 @@
// SwiftAircraft.cpp - Class representing an aircraft generated by swift
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include <string.h>
#include <simgear/compiler.h>
#include <boost/foreach.hpp>
#include <string>
#include <osg/Node>
#include <osg/ref_ptr>
#include <osgDB/FileUtils>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/scene/model/modellib.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include "SwiftAircraft.h"
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Scripting/NasalModelData.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/fg_fx.hxx>
FGSwiftAircraft::FGSwiftAircraft(std::string callsign, std::string modelpath)
{
using namespace simgear;
_model = SGModelLib::loadModel(modelpath);
_model->setName(callsign);
if (_model.valid()) {
aip.init(_model);
aip.setVisible(true);
aip.update();
globals->get_scenery()->get_models_branch()->addChild(aip.getSceneGraph());
}
}
bool FGSwiftAircraft::updatePosition(SGGeod newPosition, SGVec3d orientation)
{
position = newPosition;
aip.setPosition(position);
aip.setPitchDeg(orientation.x());
aip.setRollDeg(orientation.y());
aip.setHeadingDeg(orientation.z());
aip.update();
return true;
}
FGSwiftAircraft::~FGSwiftAircraft()
{
aip.setVisible(false);
}
double FGSwiftAircraft::getLatDeg()
{
return position.getLatitudeDeg();
}
double FGSwiftAircraft::getLongDeg()
{
return position.getLongitudeDeg();
}
double FGSwiftAircraft::getFudgeFactor()
{
return 0;
}
inline bool FGSwiftAircraft::operator<(std::string extCallsign)
{
return _model->getName().compare(extCallsign);
}
double FGSwiftAircraft::getGroundElevation()
{
double alt;
globals->get_scenery()->get_elevation_m(position,alt,0);
return alt;
}

View file

@ -0,0 +1,59 @@
// SwiftAircraft.h - Class representing an aircraft generated by swift
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 FGSWIFTAIRCRAFT_H
#define FGSWIFTAIRCRAFT_H
#pragma once
#include <osg/ref_ptr>
#include <string>
#include <simgear/constants.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/tiedpropertylist.hxx>
#include <simgear/scene/model/placement.hxx>
#include <simgear/sg_inlines.h>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/sg_geodesy.hxx>
namespace osg {
class PagedLOD;
}
class FGSwiftAircraft
{
public:
FGSwiftAircraft(std::string callsign, std::string modelpath);
bool updatePosition(SGGeod newPosition, SGVec3d orientation);
~FGSwiftAircraft();
std::string getName() { return _model->getName(); };
double getLatDeg();
double getLongDeg();
double getGroundElevation();
double getFudgeFactor();
private:
SGGeod position;
osg::ref_ptr<osg::Node> _model;
SGModelPlacement aip;
inline bool operator<(std::string extCallsign);
};
#endif

View file

@ -0,0 +1,94 @@
// SwiftAircraftManager.cpp - Manager class for aircrafts generated by swift
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "SwiftAircraftManager.h"
#include "SwiftAircraft.h"
FGSwiftAircraftManager::FGSwiftAircraftManager()
{
}
FGSwiftAircraftManager::~FGSwiftAircraftManager()
{
}
bool FGSwiftAircraftManager::addPlane(std::string callsign, std::string modelString)
{
if (aircraftByCallsign.find(callsign) != aircraftByCallsign.end())
return false;
FGSwiftAircraft* curAircraft = new FGSwiftAircraft(callsign, modelString);
aircraftByCallsign.insert(std::pair<std::string, FGSwiftAircraft*>(callsign, curAircraft));
return true;
}
void FGSwiftAircraftManager::updatePlanes(std::vector<std::string> callsigns, std::vector<SGGeod> positions, std::vector<SGVec3d> orientations, std::vector<bool> onGrounds)
{
for (int i = 0; i < callsigns.size(); i++) {
auto it = aircraftByCallsign.find(callsigns.at(i));
if (it != aircraftByCallsign.end()) {
it->second->updatePosition(positions.at(i), orientations.at(i));
}
}
}
void FGSwiftAircraftManager::getRemoteAircraftData(std::vector<std::string>& callsigns, std::vector<double>& latitudesDeg, std::vector<double>& longitudesDeg, std::vector<double>& elevationsM, std::vector<double>& verticalOffsets) const
{
const auto requestedCallsigns = callsigns;
callsigns.clear();
latitudesDeg.clear();
longitudesDeg.clear();
elevationsM.clear();
verticalOffsets.clear();
for (int i = 0; i < requestedCallsigns.size(); i++) {
auto it = aircraftByCallsign.find(requestedCallsigns.at(i));
if (it != aircraftByCallsign.end()) {
double latDeg = it->second->getLatDeg();
double lonDeg = it->second->getLongDeg();
double groundElevation = it->second->getGroundElevation();
double fudgeFactor = it->second->getFudgeFactor();
callsigns.push_back(requestedCallsigns.at(i));
latitudesDeg.push_back(latDeg);
longitudesDeg.push_back(lonDeg);
elevationsM.push_back(groundElevation);
verticalOffsets.push_back(0);
}
}
}
void FGSwiftAircraftManager::removePlane(std::string callsign)
{
auto it = aircraftByCallsign.find(callsign);
if (it != aircraftByCallsign.end()) {
delete it->second;
aircraftByCallsign.erase(it);
}
}
void FGSwiftAircraftManager::removeAllPlanes()
{
for (auto it = aircraftByCallsign.begin(); it != aircraftByCallsign.end(); ++it) {
delete it->second;
aircraftByCallsign.erase(it);
}
}

View file

@ -0,0 +1,39 @@
// SwiftAircraftManager.h - Manger class for aircrafts generated for swift
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "SwiftAircraft.h"
#include <vector>
#ifndef FGSWIFTAIRCRAFTMANAGER_H
#define FGSWIFTAIRCRAFTMANAGER_H
class FGSwiftAircraftManager
{
public:
FGSwiftAircraftManager();
~FGSwiftAircraftManager();
std::map<std::string, FGSwiftAircraft*> aircraftByCallsign;
bool addPlane(std::string callsign, std::string modelString);
void updatePlanes(std::vector<std::string> callsigns, std::vector<SGGeod> positions, std::vector<SGVec3d> orientations, std::vector<bool> onGrounds);
void getRemoteAircraftData(std::vector<std::string>& callsigns, std::vector<double>& latitudesDeg, std::vector<double>& longitudesDeg,
std::vector<double>& elevationsM, std::vector<double>& verticalOffsets) const;
void removePlane(std::string callsign);
void removeAllPlanes();
};
#endif

View file

@ -0,0 +1,64 @@
// dbuscallbacks.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSASYNCCALLBACKS_H
#define BLACKSIM_FGSWIFTBUS_DBUSASYNCCALLBACKS_H
#include <dbus/dbus.h>
#include <functional>
namespace FGSwiftBus
{
//! \cond PRIVATE
template <typename T>
class DBusAsyncCallbacks
{
public:
DBusAsyncCallbacks() = default;
DBusAsyncCallbacks(const std::function<dbus_bool_t(T *)> &add,
const std::function<void(T *)> &remove,
const std::function<void(T *)> &toggled)
: m_addHandler(add), m_removeHandler(remove), m_toggledHandler(toggled)
{ }
static dbus_bool_t add(T *watch, void *refcon)
{
return static_cast<DBusAsyncCallbacks *>(refcon)->m_addHandler(watch);
}
static void remove(T *watch, void *refcon)
{
return static_cast<DBusAsyncCallbacks *>(refcon)->m_removeHandler(watch);
}
static void toggled(T *watch, void *refcon)
{
return static_cast<DBusAsyncCallbacks *>(refcon)->m_toggledHandler(watch);
}
private:
std::function<dbus_bool_t(T *)> m_addHandler;
std::function<void(T *)> m_removeHandler;
std::function<void(T *)> m_toggledHandler;
};
//! \endcond
}
#endif // guard

View file

@ -0,0 +1,195 @@
#include <utility>
// dbusconnection.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "dbusconnection.h"
#include "dbusobject.h"
#include <algorithm>
#include <cassert>
#include <memory>
namespace FGSwiftBus
{
CDBusConnection::CDBusConnection()
{
dbus_threads_init_default();
}
CDBusConnection::CDBusConnection(DBusConnection *connection)
{
m_connection.reset(connection);
dbus_connection_ref(connection);
// Don't exit application, if the connection is disconnected
dbus_connection_set_exit_on_disconnect(connection, false);
dbus_connection_add_filter(connection, filterDisconnectedFunction, this, nullptr);
}
CDBusConnection::~CDBusConnection()
{
close();
if (m_connection) { dispatch(); } // dispatch is virtual, but safe to call in dtor, as it's declared final
if (m_dispatcher) { m_dispatcher->remove(this); }
}
bool CDBusConnection::connect(BusType type)
{
assert(type == SessionBus);
DBusError error;
dbus_error_init(&error);
DBusBusType dbusBusType;
switch (type)
{
case SessionBus: dbusBusType = DBUS_BUS_SESSION; break;
}
m_connection.reset(dbus_bus_get_private(dbusBusType, &error));
if (dbus_error_is_set(&error))
{
m_lastError = CDBusError(&error);
return false;
}
// Don't exit application, if the connection is disconnected
dbus_connection_set_exit_on_disconnect(m_connection.get(), false);
return true;
}
void CDBusConnection::setDispatcher(CDBusDispatcher *dispatcher)
{
assert(dispatcher);
m_dispatcher = dispatcher;
m_dispatcher->add(this);
dbus_connection_set_watch_functions(
m_connection.get(),
dispatcher->m_watchCallbacks.add,
dispatcher->m_watchCallbacks.remove,
dispatcher->m_watchCallbacks.toggled,
&dispatcher->m_watchCallbacks, nullptr);
dbus_connection_set_timeout_functions(
m_connection.get(),
dispatcher->m_timeoutCallbacks.add,
dispatcher->m_timeoutCallbacks.remove,
dispatcher->m_timeoutCallbacks.toggled,
&dispatcher->m_timeoutCallbacks, nullptr);
}
void CDBusConnection::requestName(const std::string &name)
{
DBusError error;
dbus_error_init(&error);
dbus_bus_request_name(m_connection.get(), name.c_str(), 0, &error);
}
bool CDBusConnection::isConnected() const
{
return m_connection && dbus_connection_get_is_connected(m_connection.get());
}
void CDBusConnection::registerDisconnectedCallback(CDBusObject *obj, DisconnectedCallback func)
{
m_disconnectedCallbacks[obj] = func;
}
void CDBusConnection::unregisterDisconnectedCallback(CDBusObject *obj)
{
auto it = m_disconnectedCallbacks.find(obj);
if (it == m_disconnectedCallbacks.end()) { return; }
m_disconnectedCallbacks.erase(it);
}
void CDBusConnection::registerObjectPath(CDBusObject *object, const std::string &interfaceName, const std::string &objectPath, const DBusObjectPathVTable &dbusObjectPathVTable)
{
(void) interfaceName;
if (!m_connection) { return; }
dbus_connection_try_register_object_path(m_connection.get(), objectPath.c_str(), &dbusObjectPathVTable, object, nullptr);
}
void CDBusConnection::sendMessage(const CDBusMessage &message)
{
if (!isConnected()) { return; }
dbus_uint32_t serial = message.getSerial();
dbus_connection_send(m_connection.get(), message.m_message, &serial);
}
void CDBusConnection::close()
{
if (m_connection) { dbus_connection_close(m_connection.get()); }
}
void CDBusConnection::dispatch()
{
dbus_connection_ref(m_connection.get());
if (dbus_connection_get_dispatch_status(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS)
{
while (dbus_connection_dispatch(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS);
}
dbus_connection_unref(m_connection.get());
}
void CDBusConnection::setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status)
{
if (dbus_connection_get_is_connected(connection) == FALSE) { return; }
switch (status)
{
case DBUS_DISPATCH_DATA_REMAINS:
//m_dispatcher->add(this);
break;
case DBUS_DISPATCH_COMPLETE:
case DBUS_DISPATCH_NEED_MEMORY:
break;
}
}
void CDBusConnection::setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status, void *data)
{
auto *obj = static_cast<CDBusConnection *>(data);
obj->setDispatchStatus(connection, status);
}
DBusHandlerResult CDBusConnection::filterDisconnectedFunction(DBusConnection *connection, DBusMessage *message, void *data)
{
(void)connection; // unused
auto *obj = static_cast<CDBusConnection *>(data);
DBusError err;
dbus_error_init(&err);
if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
{
for (auto it = obj->m_disconnectedCallbacks.begin(); it != obj->m_disconnectedCallbacks.end(); ++it)
{
it->second();
}
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}

View file

@ -0,0 +1,119 @@
// dbusconnection.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSCONNECTION_H
#define BLACKSIM_FGSWIFTBUS_DBUSCONNECTION_H
#include "dbusmessage.h"
#include "dbuserror.h"
#include "dbuscallbacks.h"
#include "dbusdispatcher.h"
#include <event2/event.h>
#include <dbus/dbus.h>
#include <string>
#include <unordered_map>
#include <memory>
namespace FGSwiftBus
{
class CDBusObject;
//! DBus connection
class CDBusConnection : public IDispatchable
{
public:
//! Bus type
enum BusType { SessionBus };
//! Disconnect Callback
using DisconnectedCallback = std::function<void()>;
//! Default constructor
CDBusConnection();
//! Constructor
CDBusConnection(DBusConnection *connection);
//! Destructor
~CDBusConnection() override;
// The ones below are not implemented yet.
// If you need them, make sure that connection reference count is correct
CDBusConnection(const CDBusConnection &) = delete;
CDBusConnection &operator=(const CDBusConnection &) = delete;
//! Connect to bus
bool connect(BusType type);
//! Set dispatcher
void setDispatcher(CDBusDispatcher *dispatcher);
//! Request name to the bus
void requestName(const std::string &name);
//! Is connected?
bool isConnected() const;
//! Register a disconnected callback
void registerDisconnectedCallback(CDBusObject *obj, DisconnectedCallback func);
//! Register a disconnected callback
void unregisterDisconnectedCallback(CDBusObject *obj);
//! Register DBus object with interfaceName and objectPath.
//! \param object
//! \param interfaceName
//! \param objectPath
//! \param dbusObjectPathVTable Virtual table handling DBus messages
void registerObjectPath(CDBusObject *object, const std::string &interfaceName, const std::string &objectPath, const DBusObjectPathVTable &dbusObjectPathVTable);
//! Send message to bus
void sendMessage(const CDBusMessage &message);
//! Close connection
void close();
//! Get the last error
CDBusError lastError() const { return m_lastError; }
protected:
// cppcheck-suppress virtualCallInConstructor
virtual void dispatch() override final;
private:
void setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status);
static void setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status, void *data);
static DBusHandlerResult filterDisconnectedFunction(DBusConnection *connection, DBusMessage *message, void *data);
struct DBusConnectionDeleter
{
void operator()(DBusConnection *obj) const { dbus_connection_unref(obj); }
};
CDBusDispatcher *m_dispatcher = nullptr;
std::unique_ptr<DBusConnection, DBusConnectionDeleter> m_connection;
CDBusError m_lastError;
std::unordered_map<CDBusObject *, DisconnectedCallback> m_disconnectedCallbacks;
};
}
#endif // guard

View file

@ -0,0 +1,245 @@
// dbus-dispatcher.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "dbusdispatcher.h"
#include "dbusconnection.h"
#include <algorithm>
namespace FGSwiftBus
{
//! Functor struct deleteing an event
struct EventDeleter
{
//! Delete functor
void operator()(event *obj) const
{
event_del(obj);
event_free(obj);
}
};
//! DBus watch handler
class WatchHandler
{
public:
//! Constructor
WatchHandler(event_base *base, DBusWatch *watch)
: m_base(base), m_watch(watch)
{
const unsigned int flags = dbus_watch_get_flags(watch);
short monitoredEvents = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE) { monitoredEvents |= EV_READ; }
if (flags & DBUS_WATCH_WRITABLE) { monitoredEvents |= EV_WRITE; }
const int fd = dbus_watch_get_unix_fd(watch);
m_event.reset(event_new(m_base, fd, monitoredEvents, callback, this));
event_add(m_event.get(), nullptr);
}
//! Get DBus watch
DBusWatch *getWatch() { return m_watch; }
//! Get DBus watch
const DBusWatch *getWatch() const { return m_watch; }
private:
//! Event callback
static void callback(evutil_socket_t fd, short event, void *data)
{
(void) fd; // Not really unused, but GCC/Clang still complain about it.
auto *watchHandler = static_cast<WatchHandler *>(data);
unsigned int flags = 0;
if (event & EV_READ) { flags |= DBUS_WATCH_READABLE; }
if (event & EV_WRITE) { flags |= DBUS_WATCH_WRITABLE; }
dbus_watch_handle(watchHandler->m_watch, flags);
}
event_base *m_base = nullptr;
std::unique_ptr<event, EventDeleter> m_event;
DBusWatch *m_watch = nullptr;
};
//! DBus timeout handler
class TimeoutHandler
{
public:
//! Constructor
TimeoutHandler(event_base *base, DBusTimeout *timeout)
: m_base(base), m_timeout(timeout)
{
timeval timer;
const int interval = dbus_timeout_get_interval(timeout);
timer.tv_sec = interval / 1000;
timer.tv_usec = (interval % 1000) * 1000;
m_event.reset(evtimer_new(m_base, callback, this));
evtimer_add(m_event.get(), &timer);
}
//! Get DBus timeout
const DBusTimeout *getTimeout() const { return m_timeout; }
private:
//! Event callback
static void callback(evutil_socket_t fd, short event, void *data)
{
(void) fd; // unused
(void) event; // unused
auto *timeoutHandler = static_cast<TimeoutHandler *>(data);
dbus_timeout_handle(timeoutHandler->m_timeout);
}
event_base *m_base = nullptr;
std::unique_ptr<event, EventDeleter> m_event;
DBusTimeout *m_timeout = nullptr;
};
//! Generic Timer
class Timer
{
public:
Timer() = default;
//! Constructor
Timer(event_base *base, const timeval &timeout, const std::function<void()> &func)
: m_base(base), m_func(func)
{
m_event.reset(evtimer_new(m_base, callback, this));
evtimer_add(m_event.get(), &timeout);
}
private:
//! Event callback
static void callback(evutil_socket_t fd, short event, void *data)
{
(void) fd; // unused
(void) event; // unused
auto *timer = static_cast<Timer *>(data);
timer->m_func();
delete timer;
}
event_base *m_base = nullptr;
std::unique_ptr<event, EventDeleter> m_event;
std::function<void()> m_func;
};
CDBusDispatcher::CDBusDispatcher() :
m_eventBase(event_base_new())
{
using namespace std::placeholders;
m_watchCallbacks = WatchCallbacks(std::bind(&CDBusDispatcher::dbusAddWatch, this, _1),
std::bind(&CDBusDispatcher::dbusRemoveWatch, this, _1),
std::bind(&CDBusDispatcher::dbusWatchToggled, this, _1));
m_timeoutCallbacks = TimeoutCallbacks(std::bind(&CDBusDispatcher::dbusAddTimeout, this, _1),
std::bind(&CDBusDispatcher::dbusRemoveTimeout, this, _1),
std::bind(&CDBusDispatcher::dbusTimeoutToggled, this, _1));
}
CDBusDispatcher::~CDBusDispatcher()
{
}
void CDBusDispatcher::add(IDispatchable *dispatchable)
{
m_dispatchList.push_back(dispatchable);
}
void CDBusDispatcher::remove(IDispatchable *dispatchable)
{
auto it = std::find(m_dispatchList.begin(), m_dispatchList.end(), dispatchable);
if (it != m_dispatchList.end()) { m_dispatchList.erase(it); }
}
void CDBusDispatcher::waitAndRun()
{
if (!m_eventBase) { return; }
event_base_dispatch(m_eventBase.get());
}
void CDBusDispatcher::runOnce()
{
if (!m_eventBase) { return; }
event_base_loop(m_eventBase.get(), EVLOOP_NONBLOCK);
dispatch();
}
void CDBusDispatcher::dispatch()
{
if (m_dispatchList.empty()) { return; }
for (IDispatchable *dispatchable : m_dispatchList)
{
dispatchable->dispatch();
}
}
dbus_bool_t CDBusDispatcher::dbusAddWatch(DBusWatch *watch)
{
if (dbus_watch_get_enabled(watch) == FALSE) { return true; }
int fd = dbus_watch_get_unix_fd(watch);
m_watchers.emplace(fd, new WatchHandler(m_eventBase.get(), watch));
return true;
}
void CDBusDispatcher::dbusRemoveWatch(DBusWatch *watch)
{
for (auto it = m_watchers.begin(); it != m_watchers.end();)
{
if (it->second->getWatch() == watch) { it = m_watchers.erase(it); }
else { ++it; }
}
}
void CDBusDispatcher::dbusWatchToggled(DBusWatch *watch)
{
if (dbus_watch_get_enabled(watch) == TRUE) { dbusAddWatch(watch); }
else { dbusRemoveWatch(watch); }
}
dbus_bool_t CDBusDispatcher::dbusAddTimeout(DBusTimeout *timeout)
{
if (dbus_timeout_get_enabled(timeout) == FALSE) { return TRUE; }
m_timeouts.emplace_back(new TimeoutHandler(m_eventBase.get(), timeout));
return true;
}
void CDBusDispatcher::dbusRemoveTimeout(DBusTimeout *timeout)
{
auto predicate = [timeout](const std::unique_ptr<TimeoutHandler> &ptr)
{
return ptr->getTimeout() == timeout;
};
m_timeouts.erase(std::remove_if(m_timeouts.begin(), m_timeouts.end(), predicate), m_timeouts.end());
}
void CDBusDispatcher::dbusTimeoutToggled(DBusTimeout *timeout)
{
if (dbus_timeout_get_enabled(timeout) == TRUE)
dbusAddTimeout(timeout);
else
dbusRemoveTimeout(timeout);
}
}

View file

@ -0,0 +1,114 @@
// dbusdispatcher.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSDISPATCHER_H
#define BLACKSIM_FGSWIFTBUS_DBUSDISPATCHER_H
#include "dbuscallbacks.h"
#include <event2/event.h>
#include <dbus/dbus.h>
#include <unordered_map>
#include <vector>
#include <memory>
namespace FGSwiftBus
{
class WatchHandler;
class TimeoutHandler;
class CDBusConnection;
class CDBusDispatcher;
//! Dispatchable Interface
class IDispatchable
{
public:
//! Default constructor
IDispatchable() = default;
//! Default destructor
virtual ~IDispatchable() = default;
//! Dispatch execution method
virtual void dispatch() = 0;
private:
friend CDBusDispatcher;
};
//! DBus Dispatcher
class CDBusDispatcher
{
public:
//! Constructor
CDBusDispatcher();
//! Destructor
virtual ~CDBusDispatcher();
//! Add dispatchable object
void add(IDispatchable *dispatchable);
//! Remove dispatchable object
void remove(IDispatchable *dispatchable);
//! Waits for events to be dispatched and handles them
void waitAndRun();
//! Dispatches ready handlers and returns without waiting
void runOnce();
private:
friend class WatchHandler;
friend class TimeoutHandler;
friend class Timer;
friend class CDBusConnection;
friend class CDBusServer;
struct EventBaseDeleter
{
void operator()(event_base *obj) const { event_base_free(obj); }
};
using WatchCallbacks = DBusAsyncCallbacks<DBusWatch>;
using TimeoutCallbacks = DBusAsyncCallbacks<DBusTimeout>;
void dispatch();
dbus_bool_t dbusAddWatch(DBusWatch *watch);
void dbusRemoveWatch(DBusWatch *watch);
void dbusWatchToggled(DBusWatch *watch);
dbus_bool_t dbusAddTimeout(DBusTimeout *timeout);
void dbusRemoveTimeout(DBusTimeout *timeout);
void dbusTimeoutToggled(DBusTimeout *timeout);
WatchCallbacks m_watchCallbacks;
TimeoutCallbacks m_timeoutCallbacks;
std::unordered_multimap<evutil_socket_t, std::unique_ptr<WatchHandler>> m_watchers;
std::vector<std::unique_ptr<TimeoutHandler>> m_timeouts;
std::unique_ptr<event_base, EventBaseDeleter> m_eventBase;
std::vector<IDispatchable*> m_dispatchList;
};
}
#endif

View file

@ -0,0 +1,29 @@
// dbuserror.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "dbuserror.h"
namespace FGSwiftBus
{
CDBusError::CDBusError(const DBusError *error)
: m_name(error->name), m_message(error->message)
{ }
}

View file

@ -0,0 +1,57 @@
// dbuserror.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSERROR_H
#define BLACKSIM_FGSWIFTBUS_DBUSERROR_H
#include <dbus/dbus.h>
#include <string>
namespace FGSwiftBus
{
//! DBus error
class CDBusError
{
public:
//! Error type
enum ErrorType
{
NoError,
Other
};
//! Default constructur
CDBusError() = default;
//! Constructor
explicit CDBusError(const DBusError *error);
//! Get error type
ErrorType getType() const { return m_errorType; }
private:
ErrorType m_errorType = NoError;
std::string m_name;
std::string m_message;
};
}
#endif // guard

View file

@ -0,0 +1,263 @@
// dbusmessage.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "dbusmessage.h"
namespace FGSwiftBus
{
CDBusMessage::CDBusMessage(DBusMessage *message)
{
m_message = dbus_message_ref(message);
}
CDBusMessage::CDBusMessage(const CDBusMessage &other)
{
m_message = dbus_message_ref(other.m_message);
m_serial = other.m_serial;
}
CDBusMessage::CDBusMessage(DBusMessage *message, dbus_uint32_t serial)
{
m_message = dbus_message_ref(message);
m_serial = serial;
}
CDBusMessage::~CDBusMessage()
{
dbus_message_unref(m_message);
}
CDBusMessage &CDBusMessage::operator =(CDBusMessage other)
{
std::swap(m_serial, other.m_serial);
m_message = dbus_message_ref(other.m_message);
return *this;
}
bool CDBusMessage::isMethodCall() const
{
return dbus_message_get_type(m_message) == DBUS_MESSAGE_TYPE_METHOD_CALL;
}
bool CDBusMessage::wantsReply() const
{
return !dbus_message_get_no_reply(m_message);
}
std::string CDBusMessage::getSender() const
{
const char *sender = dbus_message_get_sender(m_message);
return sender ? std::string(sender) : std::string();
}
dbus_uint32_t CDBusMessage::getSerial() const
{
return dbus_message_get_serial(m_message);
}
std::string CDBusMessage::getInterfaceName() const
{
return dbus_message_get_interface(m_message);
}
std::string CDBusMessage::getObjectPath() const
{
return dbus_message_get_path(m_message);
}
std::string CDBusMessage::getMethodName() const
{
return dbus_message_get_member(m_message);
}
void CDBusMessage::beginArgumentWrite()
{
dbus_message_iter_init_append(m_message, &m_messageIterator);
}
void CDBusMessage::appendArgument(bool value)
{
dbus_bool_t boolean = value ? 1 : 0;
dbus_message_iter_append_basic(&m_messageIterator, DBUS_TYPE_BOOLEAN, &boolean);
}
void CDBusMessage::appendArgument(const char *value)
{
dbus_message_iter_append_basic(&m_messageIterator, DBUS_TYPE_STRING, &value);
}
void CDBusMessage::appendArgument(const std::string &value)
{
const char *ptr = value.c_str();
dbus_message_iter_append_basic(&m_messageIterator, DBUS_TYPE_STRING, &ptr);
}
void CDBusMessage::appendArgument(int value)
{
dbus_int32_t i = value;
dbus_message_iter_append_basic(&m_messageIterator, DBUS_TYPE_INT32, &i);
}
void CDBusMessage::appendArgument(double value)
{
dbus_message_iter_append_basic(&m_messageIterator, DBUS_TYPE_DOUBLE, &value);
}
void CDBusMessage::appendArgument(const std::vector<double> &array)
{
DBusMessageIter arrayIterator;
dbus_message_iter_open_container(&m_messageIterator, DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE_AS_STRING, &arrayIterator);
const double *ptr = array.data();
dbus_message_iter_append_fixed_array(&arrayIterator, DBUS_TYPE_DOUBLE, &ptr, static_cast<int>(array.size()));
dbus_message_iter_close_container(&m_messageIterator, &arrayIterator);
}
void CDBusMessage::appendArgument(const std::vector<std::string> &array)
{
DBusMessageIter arrayIterator;
dbus_message_iter_open_container(&m_messageIterator, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &arrayIterator);
for (const auto &i : array)
{
const char *ptr = i.c_str();
dbus_message_iter_append_basic(&arrayIterator, DBUS_TYPE_STRING, &ptr);
}
dbus_message_iter_close_container(&m_messageIterator, &arrayIterator);
}
void CDBusMessage::beginArgumentRead()
{
dbus_message_iter_init(m_message, &m_messageIterator);
}
void CDBusMessage::getArgument(int &value)
{
if (dbus_message_iter_get_arg_type(&m_messageIterator) != DBUS_TYPE_INT32) { return; }
dbus_int32_t i;
dbus_message_iter_get_basic(&m_messageIterator, &i);
value = i;
dbus_message_iter_next(&m_messageIterator);
}
void CDBusMessage::getArgument(bool &value)
{
if (dbus_message_iter_get_arg_type(&m_messageIterator) != DBUS_TYPE_BOOLEAN) { return; }
dbus_bool_t v;
dbus_message_iter_get_basic(&m_messageIterator, &v);
if (v == TRUE) { value = true; }
else { value = false; }
dbus_message_iter_next(&m_messageIterator);
}
void CDBusMessage::getArgument(double &value)
{
if (dbus_message_iter_get_arg_type(&m_messageIterator) != DBUS_TYPE_DOUBLE) { return; }
dbus_message_iter_get_basic(&m_messageIterator, &value);
dbus_message_iter_next(&m_messageIterator);
}
void CDBusMessage::getArgument(std::string &value)
{
const char *str = nullptr;
if (dbus_message_iter_get_arg_type(&m_messageIterator) != DBUS_TYPE_STRING) { return; }
dbus_message_iter_get_basic(&m_messageIterator, &str);
dbus_message_iter_next(&m_messageIterator);
value = std::string(str);
}
void CDBusMessage::getArgument(std::vector<int> &value)
{
DBusMessageIter arrayIterator;
dbus_message_iter_recurse(&m_messageIterator, &arrayIterator);
do
{
if (dbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_INT32) { return; }
dbus_int32_t i;
dbus_message_iter_get_basic(&arrayIterator, &i);
value.push_back(i);
}
while (dbus_message_iter_next(&arrayIterator));
dbus_message_iter_next(&m_messageIterator);
}
void CDBusMessage::getArgument(std::vector<bool> &value)
{
if (dbus_message_iter_get_arg_type(&m_messageIterator) != DBUS_TYPE_ARRAY) { return; }
DBusMessageIter arrayIterator;
dbus_message_iter_recurse(&m_messageIterator, &arrayIterator);
do
{
if (dbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_BOOLEAN) { return; }
dbus_bool_t b;
dbus_message_iter_get_basic(&arrayIterator, &b);
if (b == TRUE) { value.push_back(true); }
else { value.push_back(false); }
}
while (dbus_message_iter_next(&arrayIterator));
dbus_message_iter_next(&m_messageIterator);
}
void CDBusMessage::getArgument(std::vector<double> &value)
{
DBusMessageIter arrayIterator;
dbus_message_iter_recurse(&m_messageIterator, &arrayIterator);
do
{
if (dbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DOUBLE) { return; }
double d;
dbus_message_iter_get_basic(&arrayIterator, &d);
value.push_back(d);
}
while (dbus_message_iter_next(&arrayIterator));
dbus_message_iter_next(&m_messageIterator);
}
void CDBusMessage::getArgument(std::vector<std::string> &value)
{
DBusMessageIter arrayIterator;
dbus_message_iter_recurse(&m_messageIterator, &arrayIterator);
do
{
if (dbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING) { return; }
const char *str = nullptr;
dbus_message_iter_get_basic(&arrayIterator, &str);
value.push_back(std::string(str));
}
while (dbus_message_iter_next(&arrayIterator));
dbus_message_iter_next(&m_messageIterator);
}
CDBusMessage CDBusMessage::createSignal(const std::string &path, const std::string &interfaceName, const std::string &signalName)
{
DBusMessage *signal = dbus_message_new_signal(path.c_str(), interfaceName.c_str(), signalName.c_str());
return CDBusMessage(signal);
}
CDBusMessage CDBusMessage::createReply(const std::string &destination, dbus_uint32_t serial)
{
DBusMessage *reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_set_no_reply(reply, TRUE);
if (! destination.empty()) { dbus_message_set_destination(reply, destination.c_str()); }
dbus_message_set_reply_serial(reply, serial);
CDBusMessage msg(reply);
dbus_message_unref(reply);
return msg;
}
}

View file

@ -0,0 +1,113 @@
// dbusmessage.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSMESSAGE_H
#define BLACKSIM_FGSWIFTBUS_DBUSMESSAGE_H
#include "dbus/dbus.h"
#include <string>
#include <vector>
namespace FGSwiftBus
{
//! DBus Message
class CDBusMessage
{
public:
//! Constructor
//! @{
CDBusMessage(DBusMessage *message);
CDBusMessage(const CDBusMessage &other);
//! @}
//! Destructor
~CDBusMessage();
//! Assignment operator
CDBusMessage &operator=(CDBusMessage other);
//! Is this message a method call?
bool isMethodCall() const;
//! Does this message want a reply?
bool wantsReply() const;
//! Get the message sender
std::string getSender() const;
//! Get the message serial. This is usally required for reply message.
dbus_uint32_t getSerial() const;
//! Get the called interface name
std::string getInterfaceName() const;
//! Get the called object path
std::string getObjectPath() const;
//! Get the called method name
std::string getMethodName() const;
//! Begin writing argument
void beginArgumentWrite();
//! Append argument. Make sure to call \sa beginArgumentWrite() before.
//! @{
void appendArgument(bool value);
void appendArgument(const char *value);
void appendArgument(const std::string &value);
void appendArgument(int value);
void appendArgument(double value);
void appendArgument(const std::vector<double> &array);
void appendArgument(const std::vector<std::string> &array);
//! @}
//! Begin reading arguments
void beginArgumentRead();
//! Read single argument. Make sure to call \sa beginArgumentRead() before.
//! @{
void getArgument(int &value);
void getArgument(bool &value);
void getArgument(double &value);
void getArgument(std::string &value);
void getArgument(std::vector<int> &value);
void getArgument(std::vector<bool> &value);
void getArgument(std::vector<double> &value);
void getArgument(std::vector<std::string> &value);
//! @}
//! Creates a DBus message containing a DBus signal
static CDBusMessage createSignal(const std::string &path, const std::string &interfaceName, const std::string &signalName);
//! Creates a DBus message containing a DBus reply
static CDBusMessage createReply(const std::string &destination, dbus_uint32_t serial);
private:
friend class CDBusConnection;
DBusMessage *m_message = nullptr;
DBusMessageIter m_messageIterator;
CDBusMessage(DBusMessage *message, dbus_uint32_t serial);
dbus_uint32_t m_serial = 0;
};
}
#endif // guard

View file

@ -0,0 +1,106 @@
// dbusobject.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "dbusobject.h"
#include <cassert>
namespace FGSwiftBus
{
CDBusObject::CDBusObject()
{ }
CDBusObject::~CDBusObject()
{
if (m_dbusConnection) { m_dbusConnection->unregisterDisconnectedCallback(this); }
};
void CDBusObject::setDBusConnection(const std::shared_ptr<CDBusConnection> &dbusConnection)
{
m_dbusConnection = dbusConnection;
dbusConnectedHandler();
CDBusConnection::DisconnectedCallback disconnectedHandler = std::bind(&CDBusObject::dbusDisconnectedHandler, this);
m_dbusConnection->registerDisconnectedCallback(this, disconnectedHandler);
}
void CDBusObject::registerDBusObjectPath(const std::string &interfaceName, const std::string &objectPath)
{
assert(m_dbusConnection);
m_interfaceName = interfaceName;
m_objectPath = objectPath;
m_dbusConnection->registerObjectPath(this, interfaceName, objectPath, m_dbusObjectPathVTable);
}
void CDBusObject::sendDBusSignal(const std::string &name)
{
if (! m_dbusConnection) { return; }
CDBusMessage signal = CDBusMessage::createSignal(m_objectPath, m_interfaceName, name);
m_dbusConnection->sendMessage(signal);
}
void CDBusObject::sendDBusMessage(const CDBusMessage &message)
{
if (! m_dbusConnection) { return; }
m_dbusConnection->sendMessage(message);
}
void CDBusObject::maybeSendEmptyDBusReply(bool wantsReply, const std::string &destination, dbus_uint32_t serial)
{
if (wantsReply)
{
CDBusMessage reply = CDBusMessage::createReply(destination, serial);
m_dbusConnection->sendMessage(reply);
}
}
void CDBusObject::queueDBusCall(const std::function<void ()> &func)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_qeuedDBusCalls.push_back(func);
}
void CDBusObject::invokeQueuedDBusCalls()
{
std::lock_guard<std::mutex> lock(m_mutex);
while (m_qeuedDBusCalls.size() > 0)
{
m_qeuedDBusCalls.front()();
m_qeuedDBusCalls.pop_front();
}
}
void CDBusObject::dbusObjectPathUnregisterFunction(DBusConnection *connection, void *data)
{
(void)connection; // unused
(void)data; // unused
}
DBusHandlerResult CDBusObject::dbusObjectPathMessageFunction(DBusConnection *connection, DBusMessage *message, void *data)
{
(void)connection; // unused
auto *obj = static_cast<CDBusObject *>(data);
DBusError err;
dbus_error_init(&err);
CDBusMessage dbusMessage(message);
return obj->dbusMessageHandler(dbusMessage);
}
}

View file

@ -0,0 +1,108 @@
// dbusobject.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSOBJECT_H
#define BLACKSIM_FGSWIFTBUS_DBUSOBJECT_H
#include "dbusconnection.h"
#include <mutex>
#include <deque>
namespace FGSwiftBus
{
//! DBus base object
class CDBusObject
{
public:
//! Constructor
CDBusObject();
//! Destructor
virtual ~CDBusObject();
//! Set the assigned DBus connection.
//! \remark Currently one object can only manage one connection at a time
void setDBusConnection(const std::shared_ptr<CDBusConnection> &dbusConnection);
//! Register itself with interfaceName and objectPath
//! \warning Before calling this method, make sure that a valid DBus connection was set.
void registerDBusObjectPath(const std::string &interfaceName, const std::string &objectPath);
protected:
//! Handler which is called when DBusCconnection is established
virtual void dbusConnectedHandler() {}
//! DBus message handler
virtual DBusHandlerResult dbusMessageHandler(const CDBusMessage &message) = 0;
//! Handler which is called when DBusConnection disconnected
virtual void dbusDisconnectedHandler() {}
//! Send DBus signal
void sendDBusSignal(const std::string &name);
//! Send DBus message
void sendDBusMessage(const CDBusMessage &message);
//! Maybe sends an empty DBus reply (acknowledgement)
void maybeSendEmptyDBusReply(bool wantsReply, const std::string &destination, dbus_uint32_t serial);
//! Send DBus reply
template <typename T>
void sendDBusReply(const std::string &destination, dbus_uint32_t serial, const T &argument)
{
CDBusMessage reply = CDBusMessage::createReply(destination, serial);
reply.beginArgumentWrite();
reply.appendArgument(argument);
m_dbusConnection->sendMessage(reply);
}
//! Send DBus reply
template <typename T>
void sendDBusReply(const std::string &destination, dbus_uint32_t serial, const std::vector<T> &array)
{
CDBusMessage reply = CDBusMessage::createReply(destination, serial);
reply.beginArgumentWrite();
reply.appendArgument(array);
m_dbusConnection->sendMessage(reply);
}
//! Queue a DBus call to be executed in a different thread
void queueDBusCall(const std::function<void()> &func);
//! Invoke all pending DBus calls. They will be executed in the calling thread.
void invokeQueuedDBusCalls();
private:
static void dbusObjectPathUnregisterFunction(DBusConnection *connection, void *data);
static DBusHandlerResult dbusObjectPathMessageFunction(DBusConnection *connection, DBusMessage *message, void *data);
std::shared_ptr<CDBusConnection> m_dbusConnection;
std::string m_interfaceName;
std::string m_objectPath;
std::mutex m_mutex;
std::deque<std::function<void()>> m_qeuedDBusCalls;
const DBusObjectPathVTable m_dbusObjectPathVTable = { dbusObjectPathUnregisterFunction, dbusObjectPathMessageFunction, nullptr, nullptr, nullptr, nullptr };
};
}
#endif // guard

View file

@ -0,0 +1,101 @@
#include <utility>
// dbusserver.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "dbusserver.h"
#include "dbusobject.h"
#include <algorithm>
#include <cassert>
#include <memory>
namespace FGSwiftBus
{
CDBusServer::CDBusServer()
{
dbus_threads_init_default();
}
CDBusServer::~CDBusServer()
{
close();
}
bool CDBusServer::listen(const std::string &address)
{
DBusError error;
dbus_error_init(&error);
m_server.reset(dbus_server_listen(address.c_str(), &error));
if (! m_server)
{
return false;
}
dbus_server_set_new_connection_function(m_server.get(), onNewConnection, this, nullptr);
return true;
}
bool CDBusServer::isConnected() const
{
return m_server ? dbus_server_get_is_connected(m_server.get()) : false;
}
void CDBusServer::close()
{
if (m_server) { dbus_server_disconnect(m_server.get()); }
}
void CDBusServer::setDispatcher(CDBusDispatcher *dispatcher)
{
assert(dispatcher);
assert(m_server);
m_dispatcher = dispatcher;
dbus_server_set_watch_functions(
m_server.get(),
dispatcher->m_watchCallbacks.add,
dispatcher->m_watchCallbacks.remove,
dispatcher->m_watchCallbacks.toggled,
&dispatcher->m_watchCallbacks, nullptr);
dbus_server_set_timeout_functions(
m_server.get(),
dispatcher->m_timeoutCallbacks.add,
dispatcher->m_timeoutCallbacks.remove,
dispatcher->m_timeoutCallbacks.toggled,
&dispatcher->m_timeoutCallbacks, nullptr);
}
void CDBusServer::onNewConnection(DBusServer *, DBusConnection *conn)
{
auto dbusConnection = std::make_shared<CDBusConnection>(conn);
m_newConnectionFunc(dbusConnection);
}
void CDBusServer::onNewConnection(DBusServer *server, DBusConnection *conn, void *data)
{
auto *obj = static_cast<CDBusServer *>(data);
obj->onNewConnection(server, conn);
}
}

View file

@ -0,0 +1,94 @@
// dbusserver.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_DBUSSERVER_H
#define BLACKSIM_FGSWIFTBUS_DBUSSERVER_H
#include "dbusmessage.h"
#include "dbuserror.h"
#include "dbuscallbacks.h"
#include "dbusdispatcher.h"
#include <event2/event.h>
#include <dbus/dbus.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
#include <functional>
namespace FGSwiftBus
{
class CDBusObject;
//! DBus connection
class CDBusServer : public IDispatchable
{
public:
//! New connection handler function
using NewConnectionFunc = std::function<void(std::shared_ptr<CDBusConnection>)>;
//! Constructor
CDBusServer();
//! Destructor
~CDBusServer();
//! Set the dispatcher
void setDispatcher(CDBusDispatcher *dispatcher);
//! Connect to bus
bool listen(const std::string &address);
//! Is connected?
bool isConnected() const;
void dispatch() override {}
//! Close connection
void close();
//! Get the last error
CDBusError lastError() const { return m_lastError; }
//! Set the function to be used for handling new connections.
void setNewConnectionFunc(const NewConnectionFunc &func)
{
m_newConnectionFunc = func;
}
private:
void onNewConnection(DBusServer *server, DBusConnection *conn);
static void onNewConnection(DBusServer *server, DBusConnection *conn, void *data);
struct DBusServerDeleter
{
void operator()(DBusServer *obj) const { dbus_server_unref(obj); }
};
CDBusDispatcher *m_dispatcher = nullptr;
std::unique_ptr<DBusServer, DBusServerDeleter> m_server;
CDBusError m_lastError;
NewConnectionFunc m_newConnectionFunc;
};
}
#endif // guard

View file

@ -0,0 +1,97 @@
// plugin.cpp
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "plugin.h"
#include "service.h"
#include "traffic.h"
#include <simgear/structure/event_mgr.hxx>
#include <simgear/structure/commands.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <cmath>
#include <functional>
#include <iostream>
#include <thread>
namespace {
inline std::string fgswiftbusServiceName()
{
return std::string("org.swift-project.fgswiftbus");
}
} // namespace
namespace FGSwiftBus {
CPlugin::CPlugin()
{
startServer();
}
CPlugin::~CPlugin()
{
m_dbusConnection->close();
m_shouldStop = true;
if (m_dbusThread.joinable()) { m_dbusThread.join(); }
}
void CPlugin::startServer()
{
m_service.reset(new CService());
m_traffic.reset(new CTraffic());
m_dbusP2PServer.reset(new CDBusServer());
std::string ip = fgGetString("/sim/swift/adress");
std::string port = fgGetString("/sim/swift/port");
std::string listenAddress = "tcp:host=" + ip + ",port=" + port;
if (! m_dbusP2PServer->listen(listenAddress))
{
m_service->addTextMessage("XSwiftBus startup failed!");
return;
}
m_dbusP2PServer->setDispatcher(&m_dbusDispatcher);
m_dbusP2PServer->setNewConnectionFunc([this](const std::shared_ptr<CDBusConnection>& conn) {
m_dbusConnection = conn;
m_dbusConnection->setDispatcher(&m_dbusDispatcher);
m_service->setDBusConnection(m_dbusConnection);
m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath());
m_traffic->setDBusConnection(m_dbusConnection);
m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath());
});
SG_LOG(SG_NETWORK,SG_INFO,"FGSwiftBus started");
}
float CPlugin::startServerDeferred(float, float, int, void* refcon)
{
auto* plugin = static_cast<CPlugin*>(refcon);
if (!plugin->m_isRunning) {
plugin->startServer();
plugin->m_isRunning = true;
}
return 0;
}
void CPlugin::fastLoop()
{
this->m_dbusDispatcher.runOnce();
this->m_service->process();
this->m_traffic->process();
this->m_traffic->emitSimFrame();
}
} // namespace FGSwiftBus

View file

@ -0,0 +1,74 @@
// plugin.h
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_PLUGIN_H
#define BLACKSIM_FGSWIFTBUS_PLUGIN_H
//! \file
/*!
* \namespace FGSwiftBus
* Plugin loaded by Flightgear which publishes a DBus service
*/
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "dbusconnection.h"
#include "dbusdispatcher.h"
#include "dbusserver.h"
#include "config.h"
#include <memory>
#include <thread>
namespace FGSwiftBus
{
class CService;
class CTraffic;
class CWeather;
/*!
* Main plugin class
*/
class CPlugin
{
public:
//! Constructor
CPlugin();
void startServer();
//! Destructor
~CPlugin();
static float startServerDeferred(float, float, int, void* refcon);
void fastLoop();
private:
CDBusDispatcher m_dbusDispatcher;
std::unique_ptr<CDBusServer> m_dbusP2PServer;
std::shared_ptr<CDBusConnection> m_dbusConnection;
std::unique_ptr<CService> m_service;
std::unique_ptr<CTraffic> m_traffic;
std::thread m_dbusThread;
bool m_isRunning = false;
bool m_shouldStop = false;
};
}
#endif // guard

View file

@ -0,0 +1,516 @@
// service.cpp - Service module for swift<->FG connection
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
#include "service.h"
#include <Main/fg_props.hxx>
#include <algorithm>
#include <iostream>
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/io/raw_socket.hxx>
#include <simgear/misc/stdint.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/timestamp.hxx>
namespace FGSwiftBus {
CService::CService()
{
SG_LOG(SG_NETWORK, SG_INFO, "FGSwiftBus Service initialized");
}
const std::string& CService::InterfaceName() {
static const std::string s(FGSWIFTBUS_SERVICE_INTERFACENAME);
return s;
}
const std::string& CService::ObjectPath()
{
static const std::string s(FGSWIFTBUS_SERVICE_OBJECTPATH);
return s;
}
void CService::addTextMessage(const std::string& text)
{
if (text.empty()) { return; }
fgSetString("/sim/messages/copilot", text);
}
std::string CService::getAircraftModelPath() const
{
return fgGetString("/sim/aircraft-dir");
}
std::string CService::getAircraftLivery() const
{
return "";
}
std::string CService::getAircraftIcaoCode() const
{
return "";
}
std::string CService::getAircraftDescription() const
{
return fgGetString("/sim/description");
}
bool CService::isPaused() const
{
return fgGetBool("/sim/freeze/master");
}
double CService::getLatitude() const
{
return fgGetDouble("/position/latitude-deg");
}
double CService::getLongitude() const
{
return fgGetDouble("/position/longitude-deg");
}
double CService::getAltitudeMSL() const
{
return fgGetDouble("/position/altitude-ft");
}
double CService::getHeightAGL() const
{
return fgGetDouble("/position/altitude-agl-ft");
}
double CService::getGroundSpeed() const
{
return fgGetDouble("/velocities/groundspeed-kt");
}
double CService::getPitch() const
{
return fgGetDouble("/orientation/pitch-deg");
}
double CService::getRoll() const
{
return fgGetDouble("/orientation/roll-deg");
}
double CService::getTrueHeading() const
{
return fgGetDouble("/orientation/heading-deg");
}
bool CService::getAllWheelsOnGround() const
{
return fgGetBool("/gear/gear/wow");
}
int CService::getCom1Active() const
{
return fgGetDouble("/instrumentation/comm/frequencies/selected-mhz") * 1000;
}
int CService::getCom1Standby() const
{
return fgGetDouble("/instrumentation/comm/frequencies/standby-mhz") * 1000;
}
int CService::getCom2Active() const
{
return fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz") * 1000;
}
int CService::getCom2Standby() const
{
return fgGetDouble("/instrumentation/comm[1]/frequencies/standby-mhz") * 1000;
}
int CService::getTransponderCode() const
{
return fgGetInt("/instrumentation/transponder/id-code");
}
int CService::getTransponderMode() const
{
return fgGetInt("/instrumentation/transponder/inputs/knob-mode");
}
bool CService::getTransponderIdent() const
{
return fgGetBool("/instrumentation/transponder/ident");
}
bool CService::getBeaconLightsOn() const
{
return fgGetBool("/controls/lighting/beacon");
}
bool CService::getLandingLightsOn() const
{
return fgGetBool("/controls/lighting/landing-lights");
}
bool CService::getNavLightsOn() const
{
return fgGetBool("/controls/lighting/nav-lights");
}
bool CService::getStrobeLightsOn() const
{
return fgGetBool("/controls/lighting/strobe");
}
bool CService::getTaxiLightsOn() const
{
return fgGetBool("/controls/lighting/taxi-light");
}
double CService::getQNH() const
{
return fgGetDouble("/environment/pressure-sea-level-inhg");
}
void CService::setCom1Active(int freq)
{
fgSetDouble("/instrumentation/comm/frequencies/selected-mhz", freq / (double)1000);
}
void CService::setCom1Standby(int freq)
{
fgSetDouble("/instrumentation/comm/frequencies/standby-mhz", freq / (double)1000);
}
void CService::setCom2Active(int freq)
{
fgSetDouble("/instrumentation/comm[1]/frequencies/selected-mhz", freq / (double)1000);
}
void CService::setCom2Standby(int freq)
{
fgSetDouble("/instrumentation/comm[1]/frequencies/standby-mhz", freq / (double)1000);
}
void CService::setTransponderCode(int code)
{
fgSetInt("/instrumentation/transponder/id-code", code);
}
void CService::setTransponderMode(int mode)
{
fgSetInt("/instrumentation/transponder/inputs/knob-mode", mode);
}
double CService::getFlapsDeployRatio() const
{
return fgGetFloat("/surface-positions/flap-pos-norm");
}
double CService::getGearDeployRatio() const
{
return fgGetFloat("/gear/gear/position-norm");
}
int CService::getNumberOfEngines() const
{
return 2;
}
std::vector<double> CService::getEngineN1Percentage() const
{
std::vector<double> list;
const auto number = static_cast<unsigned int>(getNumberOfEngines());
list.reserve(number);
for (unsigned int engineNumber = 0; engineNumber < number; ++engineNumber) {
list.push_back(fgGetDouble("/engine/engine/n1"));
}
return list;
}
double CService::getSpeedBrakeRatio() const
{
return fgGetFloat("/surface-positions/speedbrake-pos-norm");
}
std::string CService::getAircraftModelFilename() const
{
std::string modelFileName = fgGetString("/sim/aircraft");
modelFileName.append("-set.xml");
return modelFileName;
}
std::string CService::getAircraftModelString() const
{
std::string modelName = fgGetString("/sim/aircraft");
std::string modelString = "FG " + modelName;
return modelString;
}
std::string CService::getAircraftName() const
{
return fgGetString("/sim/aircraft");
}
static const char* introspection_service = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE;
DBusHandlerResult CService::dbusMessageHandler(const CDBusMessage& message_)
{
CDBusMessage message(message_);
const std::string sender = message.getSender();
const dbus_uint32_t serial = message.getSerial();
const bool wantsReply = message.wantsReply();
if (message.getInterfaceName() == DBUS_INTERFACE_INTROSPECTABLE) {
if (message.getMethodName() == "Introspect") {
sendDBusReply(sender, serial, introspection_service);
}
} else if (message.getInterfaceName() == FGSWIFTBUS_SERVICE_INTERFACENAME) {
if (message.getMethodName() == "addTextMessage") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
std::string text;
message.beginArgumentRead();
message.getArgument(text);
queueDBusCall([=]() {
addTextMessage(text);
});
} else if (message.getMethodName() == "getOwnAircraftSituationData") {
queueDBusCall([=]() {
double lat = getLatitude();
double lon = getLongitude();
double alt = getAltitudeMSL();
double gs = getGroundSpeed();
double pitch = getPitch();
double roll = getRoll();
double trueHeading = getTrueHeading();
double qnh = getQNH();
CDBusMessage reply = CDBusMessage::createReply(sender, serial);
reply.beginArgumentWrite();
reply.appendArgument(lat);
reply.appendArgument(lon);
reply.appendArgument(alt);
reply.appendArgument(gs);
reply.appendArgument(pitch);
reply.appendArgument(roll);
reply.appendArgument(trueHeading);
reply.appendArgument(qnh);
sendDBusMessage(reply);
});
} else if (message.getMethodName() == "getAircraftModelPath") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftModelPath());
});
} else if (message.getMethodName() == "getAircraftModelFilename") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftModelFilename());
});
} else if (message.getMethodName() == "getAircraftModelString") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftModelString());
});
} else if (message.getMethodName() == "getAircraftName") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftName());
});
} else if (message.getMethodName() == "getAircraftLivery") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftLivery());
});
} else if (message.getMethodName() == "getAircraftIcaoCode") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftIcaoCode());
});
} else if (message.getMethodName() == "getAircraftDescription") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAircraftDescription());
});
} else if (message.getMethodName() == "isPaused") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, isPaused());
});
} else if (message.getMethodName() == "getLatitudeDeg") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getLatitude());
});
} else if (message.getMethodName() == "getLongitudeDeg") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getLongitude());
});
} else if (message.getMethodName() == "getAltitudeMslFt") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAltitudeMSL());
});
} else if (message.getMethodName() == "getHeightAglFt") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getHeightAGL());
});
} else if (message.getMethodName() == "getGroundSpeedKts") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getGroundSpeed());
});
} else if (message.getMethodName() == "getPitchDeg") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getPitch());
});
} else if (message.getMethodName() == "getRollDeg") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getRoll());
});
} else if (message.getMethodName() == "getAllWheelsOnGround") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getAllWheelsOnGround());
});
} else if (message.getMethodName() == "getCom1ActiveKhz") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getCom1Active());
});
} else if (message.getMethodName() == "getCom1StandbyKhz") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getCom1Standby());
});
} else if (message.getMethodName() == "getCom2ActiveKhz") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getCom2Active());
});
} else if (message.getMethodName() == "getCom2StandbyKhz") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getCom2Standby());
});
} else if (message.getMethodName() == "getTransponderCode") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getTransponderCode());
});
} else if (message.getMethodName() == "getTransponderMode") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getTransponderMode());
});
} else if (message.getMethodName() == "getTransponderIdent") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getTransponderIdent());
});
} else if (message.getMethodName() == "getBeaconLightsOn") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getBeaconLightsOn());
});
} else if (message.getMethodName() == "getLandingLightsOn") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getLandingLightsOn());
});
} else if (message.getMethodName() == "getNavLightsOn") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getNavLightsOn());
});
} else if (message.getMethodName() == "getStrobeLightsOn") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getStrobeLightsOn());
});
} else if (message.getMethodName() == "getTaxiLightsOn") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getTaxiLightsOn());
});
} else if (message.getMethodName() == "getQNHInHg") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getQNH());
});
} else if (message.getMethodName() == "setCom1ActiveKhz") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
int frequency = 0;
message.beginArgumentRead();
message.getArgument(frequency);
queueDBusCall([=]() {
setCom1Active(frequency);
});
} else if (message.getMethodName() == "setCom1StandbyKhz") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
int frequency = 0;
message.beginArgumentRead();
message.getArgument(frequency);
queueDBusCall([=]() {
setCom1Standby(frequency);
});
} else if (message.getMethodName() == "setCom2ActiveKhz") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
int frequency = 0;
message.beginArgumentRead();
message.getArgument(frequency);
queueDBusCall([=]() {
setCom2Active(frequency);
});
} else if (message.getMethodName() == "setCom2StandbyKhz") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
int frequency = 0;
message.beginArgumentRead();
message.getArgument(frequency);
queueDBusCall([=]() {
setCom2Standby(frequency);
});
} else if (message.getMethodName() == "setTransponderCode") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
int code = 0;
message.beginArgumentRead();
message.getArgument(code);
queueDBusCall([=]() {
setTransponderCode(code);
});
} else if (message.getMethodName() == "setTransponderMode") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
int mode = 0;
message.beginArgumentRead();
message.getArgument(mode);
queueDBusCall([=]() {
setTransponderMode(mode);
});
} else if (message.getMethodName() == "getFlapsDeployRatio") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getFlapsDeployRatio());
});
} else if (message.getMethodName() == "getGearDeployRatio") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getGearDeployRatio());
});
} else if (message.getMethodName() == "getEngineN1Percentage") {
queueDBusCall([=]() {
std::vector<double> array = getEngineN1Percentage();
sendDBusReply(sender, serial, array);
});
} else if (message.getMethodName() == "getSpeedBrakeRatio") {
queueDBusCall([=]() {
sendDBusReply(sender, serial, getSpeedBrakeRatio());
});
} else {
// Unknown message. Tell DBus that we cannot handle it
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
return DBUS_HANDLER_RESULT_HANDLED;
}
int CService::process()
{
invokeQueuedDBusCalls();
return 1;
}
} // namespace FGSwiftBus

202
src/Network/Swift/service.h Normal file
View file

@ -0,0 +1,202 @@
// service.h - Service module for swift<->FG connection
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_SERVICE_H
#define BLACKSIM_FGSWIFTBUS_SERVICE_H
//! \file
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "dbusobject.h"
#include <chrono>
#include <string>
#include <Main/fg_props.hxx>
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/io/raw_socket.hxx>
#include <simgear/misc/stdint.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/timestamp.hxx>
//! \cond PRIVATE
#define FGSWIFTBUS_SERVICE_INTERFACENAME "org.swift_project.fgswiftbus.service"
#define FGSWIFTBUS_SERVICE_OBJECTPATH "/fgswiftbus/service"
//! \endcond
namespace FGSwiftBus {
/*!
* FGSwiftBus service object which is accessible through DBus
*/
class CService : public CDBusObject
{
public:
//! Constructor
CService();
//! DBus interface name
static const std::string& InterfaceName();
//! DBus object path
static const std::string& ObjectPath();
////! Add a text message to the on-screen display, with RGB components in the range [0,1]
void addTextMessage(const std::string& text);
////! Get full path to current aircraft model
std::string getAircraftModelPath() const;
////! Get base filename of current aircraft model
std::string getAircraftModelFilename() const;
////! Get canonical swift model string of current aircraft model
std::string getAircraftModelString() const;
////! Get name of current aircraft model
std::string getAircraftName() const;
////! Get path to current aircraft livery
std::string getAircraftLivery() const;
//! Get the ICAO code of the current aircraft model
std::string getAircraftIcaoCode() const;
////! Get the description of the current aircraft model
std::string getAircraftDescription() const;
//! True if sim is paused
bool isPaused() const;
//! Get aircraft latitude in degrees
double getLatitude() const;
//! Get aircraft longitude in degrees
double getLongitude() const;
//! Get aircraft altitude in feet
double getAltitudeMSL() const;
//! Get aircraft height in feet
double getHeightAGL() const;
//! Get aircraft groundspeed in knots
double getGroundSpeed() const;
//! Get aircraft pitch in degrees above horizon
double getPitch() const;
//! Get aircraft roll in degrees
double getRoll() const;
//! Get aircraft true heading in degrees
double getTrueHeading() const;
//! Get whether all wheels are on the ground
bool getAllWheelsOnGround() const;
//! Get the current COM1 active frequency in kHz
int getCom1Active() const;
//! Get the current COM1 standby frequency in kHz
int getCom1Standby() const;
//! Get the current COM2 active frequency in kHz
int getCom2Active() const;
//! Get the current COM2 standby frequency in kHz
int getCom2Standby() const;
//! Get the current transponder code in decimal
int getTransponderCode() const;
//! Get the current transponder mode (depends on the aircraft, 0-2 usually mean standby, >2 active)
int getTransponderMode() const;
//! Get whether we are currently squawking ident
bool getTransponderIdent() const;
//! Get whether beacon lights are on
bool getBeaconLightsOn() const;
//! Get whether landing lights are on
bool getLandingLightsOn() const;
//! Get whether nav lights are on
bool getNavLightsOn() const;
//! Get whether strobe lights are on
bool getStrobeLightsOn() const;
//! Get whether taxi lights are on
bool getTaxiLightsOn() const;
//! Get barometric pressure at sea level in inches of mercury.
double getQNH() const;
//! Set the current COM1 active frequency in kHz
void setCom1Active(int freq);
//! Set the current COM1 standby frequency in kHz
void setCom1Standby(int freq);
//! Set the current COM2 active frequency in kHz
void setCom2Active(int freq);
//! Set the current COM2 standby frequency in kHz
void setCom2Standby(int freq);
////! Set the current transponder code in decimal
void setTransponderCode(int code);
////! Set the current transponder mode (depends on the aircraft, 0 and 1 usually mean standby, >1 active)
void setTransponderMode(int mode);
//! Get flaps deploy ratio, where 0.0 is flaps fully retracted, and 1.0 is flaps fully extended.
double getFlapsDeployRatio() const;
//! Get gear deploy ratio, where 0 is up and 1 is down
double getGearDeployRatio() const;
//! Get the number of engines of current aircraft
int getNumberOfEngines() const;
//! Get the N1 speed as percent of max (per engine)
std::vector<double> getEngineN1Percentage() const;
//! Get the ratio how much the speedbrakes surfaces are extended (0.0 is fully retracted, and 1.0 is fully extended)
double getSpeedBrakeRatio() const;
//! Perform generic processing
int process();
protected:
DBusHandlerResult dbusMessageHandler(const CDBusMessage& message) override;
};
} // namespace FGSwiftBus
#endif // guard

View file

@ -0,0 +1,104 @@
// swift_connection.cxx
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 "plugin.h"
#include "swift_connection.hxx"
#include <Main/fg_props.hxx>
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/io/raw_socket.hxx>
#include <simgear/misc/stdint.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/timestamp.hxx>
namespace {
inline std::string fgswiftbusServiceName()
{
return std::string("org.swift-project.fgswiftbus");
}
} // namespace
bool SwiftConnection::startServer(const SGPropertyNode* arg, SGPropertyNode* root)
{
SwiftConnection::plug = new FGSwiftBus::CPlugin();
serverRunning = true;
fgSetBool("/sim/swift/serverRunning", true);
return true;
}
bool SwiftConnection::stopServer(const SGPropertyNode* arg, SGPropertyNode* root)
{
SwiftConnection::plug->~CPlugin();
fgSetBool("/sim/swift/serverRunning", false);
serverRunning = false;
return true;
}
SwiftConnection::SwiftConnection()
{
init();
}
SwiftConnection::~SwiftConnection()
{
shutdown();
}
void SwiftConnection::init(void)
{
if (initialized == false) {
globals->get_commands()->addCommand("swiftStart", this, &SwiftConnection::startServer);
globals->get_commands()->addCommand("swiftStop", this, &SwiftConnection::stopServer);
fgSetBool("/sim/swift/available", true);
initialized = true;
}
}
void SwiftConnection::update(double delta_time_sec)
{
if (serverRunning == true) {
SwiftConnection::plug->fastLoop();
}
}
void SwiftConnection::shutdown(void)
{
if (initialized == true) {
globals->get_commands()->removeCommand("swiftStart");
globals->get_commands()->removeCommand("swiftStop");
fgSetBool("/sim/swift/available", false);
initialized = false;
}
}
void SwiftConnection::reinit()
{
shutdown();
init();
}

View file

@ -0,0 +1,57 @@
// swift_conection.hxx
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 SWIFT_CONNECTION_H
#define SWIFT_CONNECTION_H
#include "dbusconnection.h"
#include "dbusdispatcher.h"
#include <Main/fg_props.hxx>
#include <simgear/compiler.h>
#include <simgear/io/raw_socket.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "plugin.h"
#include "dbusserver.h"
#include <memory>
#include <thread>
#ifndef NOMINMAX
#define NOMINMAX
#endif
class SwiftConnection : public SGSubsystem
{
public:
bool startServer(const SGPropertyNode* arg, SGPropertyNode* root);
bool stopServer(const SGPropertyNode* arg, SGPropertyNode* root);
SwiftConnection();
~SwiftConnection();
FGSwiftBus::CPlugin* plug;
virtual void init(void);
virtual void update(double delta_time_sec) override;
virtual void shutdown(void);
virtual void reinit();
private:
bool serverRunning = false;
bool initialized = false;
};
#endif

View file

@ -0,0 +1,264 @@
// traffic.cpp - Traffic module for swift<->FG connection
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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.
//! \cond PRIVATE
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "traffic.h"
#include "SwiftAircraftManager.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
// clazy:excludeall=reserve-candidates
namespace FGSwiftBus {
CTraffic::CTraffic()
{
acm = new FGSwiftAircraftManager();
SG_LOG(SG_NETWORK, SG_INFO, "FGSwiftBus Traffic started");
}
CTraffic::~CTraffic()
{
cleanup();
SG_LOG(SG_NETWORK, SG_INFO, "FGSwiftBus Traffic stopped");
}
const std::string& CTraffic::InterfaceName()
{
static std::string s(FGSWIFTBUS_TRAFFIC_INTERFACENAME);
return s;
}
const std::string& CTraffic::ObjectPath()
{
static std::string s(FGSWIFTBUS_TRAFFIC_OBJECTPATH);
return s;
}
void CTraffic::planeLoaded(void* id, bool succeeded, void* self)
{
auto* traffic = static_cast<CTraffic*>(self);
auto planeIt = traffic->m_planesById.find(id);
if (planeIt == traffic->m_planesById.end()) { return; }
if (succeeded) {
traffic->emitPlaneAdded(planeIt->second->callsign);
} else {
traffic->emitPlaneAddingFailed(planeIt->second->callsign);
}
}
bool CTraffic::initialize()
{
m_initialized = true;
m_enabled = true;
return true;
}
void CTraffic::emitSimFrame()
{
if (m_emitSimFrame) { sendDBusSignal("simFrame"); }
m_emitSimFrame = !m_emitSimFrame;
}
void CTraffic::emitPlaneAdded(const std::string& callsign)
{
CDBusMessage signalPlaneAdded = CDBusMessage::createSignal(FGSWIFTBUS_TRAFFIC_OBJECTPATH, FGSWIFTBUS_TRAFFIC_INTERFACENAME, "remoteAircraftAdded");
signalPlaneAdded.beginArgumentWrite();
signalPlaneAdded.appendArgument(callsign);
sendDBusMessage(signalPlaneAdded);
}
void CTraffic::emitPlaneAddingFailed(const std::string& callsign)
{
CDBusMessage signalPlaneAddingFailed = CDBusMessage::createSignal(FGSWIFTBUS_TRAFFIC_OBJECTPATH, FGSWIFTBUS_TRAFFIC_INTERFACENAME, "remoteAircraftAddingFailed");
signalPlaneAddingFailed.beginArgumentWrite();
signalPlaneAddingFailed.appendArgument(callsign);
sendDBusMessage(signalPlaneAddingFailed);
}
void CTraffic::cleanup()
{
acm->removeAllPlanes();
}
void CTraffic::removeAllPlanes()
{
acm->removeAllPlanes();
}
void CTraffic::dbusDisconnectedHandler()
{
acm->removeAllPlanes();
}
const char* introspection_traffic = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE;
DBusHandlerResult CTraffic::dbusMessageHandler(const CDBusMessage& message_)
{
CDBusMessage message(message_);
const std::string sender = message.getSender();
const dbus_uint32_t serial = message.getSerial();
const bool wantsReply = message.wantsReply();
std::string test = message.getMethodName();
if (message.getInterfaceName() == DBUS_INTERFACE_INTROSPECTABLE) {
if (message.getMethodName() == "Introspect") {
sendDBusReply(sender, serial, introspection_traffic);
}
} else if (message.getInterfaceName() == FGSWIFTBUS_TRAFFIC_INTERFACENAME) {
if (message.getMethodName() == "acquireMultiplayerPlanes") {
queueDBusCall([=]() {
std::string owner;
bool acquired = true;
CDBusMessage reply = CDBusMessage::createReply(sender, serial);
reply.beginArgumentWrite();
reply.appendArgument(acquired);
reply.appendArgument(owner);
sendDBusMessage(reply);
});
} else if (message.getMethodName() == "initialize") {
sendDBusReply(sender, serial, initialize());
} else if (message.getMethodName() == "cleanup") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
queueDBusCall([=]() {
cleanup();
});
} else if (message.getMethodName() == "addPlane") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
std::string callsign;
std::string modelName;
std::string aircraftIcao;
std::string airlineIcao;
std::string livery;
message.beginArgumentRead();
message.getArgument(callsign);
message.getArgument(modelName);
message.getArgument(aircraftIcao);
message.getArgument(airlineIcao);
message.getArgument(livery);
queueDBusCall([=]() {
if (acm->addPlane(callsign, modelName)) {
emitPlaneAdded(callsign);
}
});
} else if (message.getMethodName() == "removePlane") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
std::string callsign;
message.beginArgumentRead();
message.getArgument(callsign);
queueDBusCall([=]() {
acm->removePlane(callsign);
});
} else if (message.getMethodName() == "removeAllPlanes") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
queueDBusCall([=]() {
acm->removeAllPlanes();
});
} else if (message.getMethodName() == "setPlanesPositions") {
maybeSendEmptyDBusReply(wantsReply, sender, serial);
std::vector<std::string> callsigns;
std::vector<double> latitudes;
std::vector<double> longitudes;
std::vector<double> altitudes;
std::vector<double> pitches;
std::vector<double> rolls;
std::vector<double> headings;
std::vector<bool> onGrounds;
message.beginArgumentRead();
message.getArgument(callsigns);
message.getArgument(latitudes);
message.getArgument(longitudes);
message.getArgument(altitudes);
message.getArgument(pitches);
message.getArgument(rolls);
message.getArgument(headings);
message.getArgument(onGrounds);
queueDBusCall([=]() {
std::vector<SGGeod> positions;
std::vector<SGVec3d> orientations;
for (int i = 0; i < latitudes.size(); i++) {
SGGeod newPos;
newPos.setLatitudeDeg(latitudes.at(i));
newPos.setLongitudeDeg(longitudes.at(i));
newPos.setElevationFt(altitudes.at(i));
SGVec3d vec(pitches.at(i), rolls.at(i), headings.at(i));
positions.push_back(newPos);
orientations.push_back(vec);
}
acm->updatePlanes(callsigns, positions, orientations, onGrounds);
});
} else if (message.getMethodName() == "getRemoteAircraftData") {
std::vector<std::string> requestedcallsigns;
message.beginArgumentRead();
message.getArgument(requestedcallsigns);
queueDBusCall([=]() {
std::vector<std::string> callsigns = requestedcallsigns;
std::vector<double> latitudesDeg;
std::vector<double> longitudesDeg;
std::vector<double> elevationsM;
std::vector<double> verticalOffsets;
acm->getRemoteAircraftData(callsigns, latitudesDeg, longitudesDeg, elevationsM, verticalOffsets);
CDBusMessage reply = CDBusMessage::createReply(sender, serial);
reply.beginArgumentWrite();
reply.appendArgument(callsigns);
reply.appendArgument(latitudesDeg);
reply.appendArgument(longitudesDeg);
reply.appendArgument(elevationsM);
reply.appendArgument(verticalOffsets);
sendDBusMessage(reply);
});
} else {
// Unknown message. Tell DBus that we cannot handle it
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
return DBUS_HANDLER_RESULT_HANDLED;
}
int CTraffic::process()
{
invokeQueuedDBusCalls();
return 1;
}
//! memcmp function which ignores the header ("size" member) and compares only the payload (the rest of the struct)
template <typename T>
int memcmpPayload(T* dst, T* src)
{
return std::memcmp(reinterpret_cast<char*>(dst) + sizeof(dst->size),
reinterpret_cast<char*>(src) + sizeof(src->size),
sizeof(*dst) - sizeof(dst->size));
}
} // namespace FGSwiftBus
//! \endcond

108
src/Network/Swift/traffic.h Normal file
View file

@ -0,0 +1,108 @@
// traffic.h - Traffic module for swift<->FG connection
//
// Copyright (C) 2019 - swift Project Community / Contributors (http://swift-project.org/)
// Adapted to Flightgear by Lars Toenning <dev@ltoenning.de>
//
// 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 BLACKSIM_FGSWIFTBUS_TRAFFIC_H
#define BLACKSIM_FGSWIFTBUS_TRAFFIC_H
//! \file
#include "SwiftAircraftManager.h"
#include "dbusobject.h"
#include <functional>
#include <utility>
//! \cond PRIVATE
#define FGSWIFTBUS_TRAFFIC_INTERFACENAME "org.swift_project.fgswiftbus.traffic"
#define FGSWIFTBUS_TRAFFIC_OBJECTPATH "/fgswiftbus/traffic"
//! \endcond
namespace FGSwiftBus {
/*!
* FGSwiftBus service object for traffic aircraft which is accessible through DBus
*/
class CTraffic : public CDBusObject
{
public:
//! Constructor
CTraffic();
//! Destructor
~CTraffic() override;
//! DBus interface name
static const std::string& InterfaceName();
//! DBus object path
static const std::string& ObjectPath();
//! Initialize the multiplayer planes rendering and return true if successful
bool initialize();
//! Remove all traffic aircraft
void removeAllPlanes();
//! Perform generic processing
int process();
void emitSimFrame();
protected:
virtual void dbusDisconnectedHandler() override;
DBusHandlerResult dbusMessageHandler(const CDBusMessage& message) override;
private:
bool m_initialized = false;
bool m_enabled = false;
void emitPlaneAdded(const std::string& callsign);
void emitPlaneAddingFailed(const std::string& callsign);
void cleanup();
struct Plane {
void* id = nullptr;
std::string callsign;
std::string aircraftIcao;
std::string airlineIcao;
std::string livery;
std::string modelName;
bool hasSurfaces = false;
bool hasXpdr = false;
char label[32]{};
float targetGearPosition = 0;
std::chrono::system_clock::time_point prevSurfacesLerpTime;
};
std::unordered_map<std::string, Plane*> m_planesByCallsign;
std::unordered_map<void*, Plane*> m_planesById;
std::vector<std::string> m_followPlaneViewSequence;
std::chrono::system_clock::time_point m_timestampLastSimFrame = std::chrono::system_clock::now();
std::string m_followPlaneViewCallsign;
bool m_emitSimFrame = true;
FGSwiftAircraftManager* acm;
static void planeLoaded(void* id, bool succeeded, void* self);
};
} // namespace FGSwiftBus
#endif // guard