first commit
This commit is contained in:
32
src/Network/Swift/CMakeLists.txt
Normal file
32
src/Network/Swift/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
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
|
||||
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
|
||||
SwiftAircraftManager.h
|
||||
)
|
||||
|
||||
flightgear_component(Swift "${SOURCES}" "${HEADERS}")
|
||||
129
src/Network/Swift/SwiftAircraftManager.cpp
Normal file
129
src/Network/Swift/SwiftAircraftManager.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Manger class for aircraft generated by swift
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "SwiftAircraftManager.h"
|
||||
#include <Main/globals.hxx>
|
||||
#include <utility>
|
||||
|
||||
FGSwiftAircraftManager::FGSwiftAircraftManager()
|
||||
{
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
FGSwiftAircraftManager::~FGSwiftAircraftManager()
|
||||
{
|
||||
this->removeAllPlanes();
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
bool FGSwiftAircraftManager::isInitialized() const
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool FGSwiftAircraftManager::addPlane(const std::string& callsign, const std::string& modelString)
|
||||
{
|
||||
this->removePlane(callsign); // Remove plane if already exists e.g. when rematching is done.
|
||||
auto curAircraft = FGAISwiftAircraftPtr(new FGAISwiftAircraft(callsign, modelString));
|
||||
globals->get_subsystem<FGAIManager>()->attach(curAircraft);
|
||||
// Init props after prop-root is assigned
|
||||
curAircraft->initProps();
|
||||
|
||||
aircraftByCallsign.insert(std::pair<std::string, FGAISwiftAircraftPtr>(callsign, curAircraft));
|
||||
return true;
|
||||
}
|
||||
|
||||
void FGSwiftAircraftManager::updatePlanes(const std::vector<SwiftPlaneUpdate>& updates)
|
||||
{
|
||||
for (auto& update : updates) {
|
||||
auto it = aircraftByCallsign.find(update.callsign);
|
||||
if (it != aircraftByCallsign.end()) {
|
||||
it->second->updatePosition(update.position, update.orientation, update.groundspeed, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (callsigns.empty() || aircraftByCallsign.empty()) { return; }
|
||||
|
||||
const auto requestedCallsigns = callsigns;
|
||||
callsigns.clear();
|
||||
latitudesDeg.clear();
|
||||
longitudesDeg.clear();
|
||||
elevationsM.clear();
|
||||
verticalOffsets.clear();
|
||||
|
||||
for (const auto& requestedCallsign : requestedCallsigns) {
|
||||
const auto it = aircraftByCallsign.find(requestedCallsign);
|
||||
if (it == aircraftByCallsign.end()) { continue; }
|
||||
|
||||
const FGAISwiftAircraft* aircraft = it->second;
|
||||
assert(aircraft);
|
||||
|
||||
|
||||
SGGeod pos;
|
||||
pos.setLatitudeDeg(aircraft->_getLatitude());
|
||||
pos.setLongitudeDeg(aircraft->_getLongitude());
|
||||
const double latDeg = pos.getLatitudeDeg();
|
||||
const double lonDeg = pos.getLongitudeDeg();
|
||||
double groundElevation = aircraft->getGroundElevation(pos);
|
||||
|
||||
callsigns.push_back(requestedCallsign);
|
||||
latitudesDeg.push_back(latDeg);
|
||||
longitudesDeg.push_back(lonDeg);
|
||||
elevationsM.push_back(groundElevation);
|
||||
verticalOffsets.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
void FGSwiftAircraftManager::removePlane(const std::string& callsign)
|
||||
{
|
||||
auto it = aircraftByCallsign.find(callsign);
|
||||
if (it != aircraftByCallsign.end()) {
|
||||
it->second->setDie(true);
|
||||
aircraftByCallsign.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void FGSwiftAircraftManager::removeAllPlanes()
|
||||
{
|
||||
for (auto it = aircraftByCallsign.begin(); it != aircraftByCallsign.end();) {
|
||||
it->second->setDie(true);
|
||||
it = aircraftByCallsign.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
double FGSwiftAircraftManager::getElevationAtPosition(const std::string& callsign, const SGGeod& pos) const
|
||||
{
|
||||
auto it = aircraftByCallsign.find(callsign);
|
||||
if (it != aircraftByCallsign.end()) {
|
||||
return it->second->getGroundElevation(pos);
|
||||
}
|
||||
// Aircraft not found in list
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
void FGSwiftAircraftManager::setPlanesTransponders(const std::vector<AircraftTransponder>& transponders)
|
||||
{
|
||||
for (const auto& transponder : transponders) {
|
||||
auto it = aircraftByCallsign.find(transponder.callsign);
|
||||
if (it != aircraftByCallsign.end()) {
|
||||
it->second->setPlaneTransponder(transponder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FGSwiftAircraftManager::setPlanesSurfaces(const std::vector<AircraftSurfaces>& surfaces)
|
||||
{
|
||||
for (const auto& surface : surfaces) {
|
||||
auto it = aircraftByCallsign.find(surface.callsign);
|
||||
if (it != aircraftByCallsign.end()) {
|
||||
it->second->setPlaneSurface(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Network/Swift/SwiftAircraftManager.h
Normal file
48
src/Network/Swift/SwiftAircraftManager.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Manger class for aircraft generated by swift
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <AIModel/AIManager.hxx>
|
||||
#include <AIModel/AISwiftAircraft.h>
|
||||
#include <Scenery/scenery.hxx>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifndef FGSWIFTAIRCRAFTMANAGER_H
|
||||
#define FGSWIFTAIRCRAFTMANAGER_H
|
||||
|
||||
struct SwiftPlaneUpdate {
|
||||
std::string callsign;
|
||||
SGGeod position;
|
||||
SGVec3d orientation;
|
||||
double groundspeed;
|
||||
bool onGround;
|
||||
};
|
||||
|
||||
class FGSwiftAircraftManager
|
||||
{
|
||||
using FGAISwiftAircraftPtr = SGSharedPtr<FGAISwiftAircraft>;
|
||||
|
||||
public:
|
||||
FGSwiftAircraftManager();
|
||||
~FGSwiftAircraftManager();
|
||||
bool addPlane(const std::string& callsign, const std::string& modelString);
|
||||
void updatePlanes(const std::vector<SwiftPlaneUpdate>& updates);
|
||||
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(const std::string& callsign);
|
||||
void removeAllPlanes();
|
||||
void setPlanesTransponders(const std::vector<AircraftTransponder>& transponders);
|
||||
double getElevationAtPosition(const std::string& callsign, const SGGeod& pos) const;
|
||||
bool isInitialized() const;
|
||||
void setPlanesSurfaces(const std::vector<AircraftSurfaces>& surfaces);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, FGAISwiftAircraftPtr> aircraftByCallsign;
|
||||
bool m_initialized = false;
|
||||
};
|
||||
#endif
|
||||
51
src/Network/Swift/dbuscallbacks.h
Normal file
51
src/Network/Swift/dbuscallbacks.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
174
src/Network/Swift/dbusconnection.cpp
Normal file
174
src/Network/Swift/dbusconnection.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
104
src/Network/Swift/dbusconnection.h
Normal file
104
src/Network/Swift/dbusconnection.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BLACKSIM_FGSWIFTBUS_DBUSCONNECTION_H
|
||||
#define BLACKSIM_FGSWIFTBUS_DBUSCONNECTION_H
|
||||
|
||||
#include "dbuscallbacks.h"
|
||||
#include "dbusdispatcher.h"
|
||||
#include "dbuserror.h"
|
||||
#include "dbusmessage.h"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <event2/event.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
242
src/Network/Swift/dbusdispatcher.cpp
Normal file
242
src/Network/Swift/dbusdispatcher.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "dbusdispatcher.h"
|
||||
#include "dbusconnection.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace { // anonymosu namespace
|
||||
|
||||
template <typename T, typename... Args>
|
||||
std::unique_ptr<T> our_make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
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, our_make_unique<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);
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
99
src/Network/Swift/dbusdispatcher.h
Normal file
99
src/Network/Swift/dbusdispatcher.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BLACKSIM_FGSWIFTBUS_DBUSDISPATCHER_H
|
||||
#define BLACKSIM_FGSWIFTBUS_DBUSDISPATCHER_H
|
||||
|
||||
#include "dbuscallbacks.h"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
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;
|
||||
};
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif
|
||||
16
src/Network/Swift/dbuserror.cpp
Normal file
16
src/Network/Swift/dbuserror.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "dbuserror.h"
|
||||
|
||||
namespace FGSwiftBus {
|
||||
|
||||
CDBusError::CDBusError(const DBusError* error)
|
||||
: m_name(error->name), m_message(error->message)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
42
src/Network/Swift/dbuserror.h
Normal file
42
src/Network/Swift/dbuserror.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
246
src/Network/Swift/dbusmessage.cpp
Normal file
246
src/Network/Swift/dbusmessage.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
99
src/Network/Swift/dbusmessage.h
Normal file
99
src/Network/Swift/dbusmessage.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
91
src/Network/Swift/dbusobject.cpp
Normal file
91
src/Network/Swift/dbusobject.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
94
src/Network/Swift/dbusobject.h
Normal file
94
src/Network/Swift/dbusobject.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BLACKSIM_FGSWIFTBUS_DBUSOBJECT_H
|
||||
#define BLACKSIM_FGSWIFTBUS_DBUSOBJECT_H
|
||||
|
||||
#include "dbusconnection.h"
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
||||
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};
|
||||
};
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
84
src/Network/Swift/dbusserver.cpp
Normal file
84
src/Network/Swift/dbusserver.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "dbusobject.h"
|
||||
#include "dbusserver.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);
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
79
src/Network/Swift/dbusserver.h
Normal file
79
src/Network/Swift/dbusserver.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BLACKSIM_FGSWIFTBUS_DBUSSERVER_H
|
||||
#define BLACKSIM_FGSWIFTBUS_DBUSSERVER_H
|
||||
|
||||
#include "dbuscallbacks.h"
|
||||
#include "dbusdispatcher.h"
|
||||
#include "dbuserror.h"
|
||||
#include "dbusmessage.h"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <event2/event.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
74
src/Network/Swift/plugin.cpp
Normal file
74
src/Network/Swift/plugin.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
#include "traffic.h"
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
inline std::string fgswiftbusServiceName()
|
||||
{
|
||||
return "org.swift-project.fgswiftbus";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace FGSwiftBus {
|
||||
CPlugin::CPlugin()
|
||||
{
|
||||
startServer();
|
||||
}
|
||||
|
||||
CPlugin::~CPlugin()
|
||||
{
|
||||
if (m_dbusConnection) {
|
||||
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/address", "127.0.0.1");
|
||||
std::string port = fgGetString("/sim/swift/port", "45003");
|
||||
std::string listenAddress = "tcp:host=" + ip + ",port=" + port;
|
||||
if (!m_dbusP2PServer->listen(listenAddress)) {
|
||||
m_service->addTextMessage("FGSwiftBus 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");
|
||||
}
|
||||
|
||||
void CPlugin::fastLoop()
|
||||
{
|
||||
this->m_dbusDispatcher.runOnce();
|
||||
this->m_service->process();
|
||||
this->m_traffic->process();
|
||||
this->m_traffic->emitSimFrame();
|
||||
}
|
||||
} // namespace FGSwiftBus
|
||||
58
src/Network/Swift/plugin.h
Normal file
58
src/Network/Swift/plugin.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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 "config.h"
|
||||
#include "dbusconnection.h"
|
||||
#include "dbusdispatcher.h"
|
||||
#include "dbusserver.h"
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace FGSwiftBus {
|
||||
class CService;
|
||||
class CTraffic;
|
||||
|
||||
/*!
|
||||
* Main plugin class
|
||||
*/
|
||||
class CPlugin
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
CPlugin();
|
||||
void startServer();
|
||||
//! Destructor
|
||||
~CPlugin();
|
||||
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;
|
||||
};
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // BLACKSIM_FGSWIFTBUS_PLUGIN_H
|
||||
633
src/Network/Swift/service.cpp
Normal file
633
src/Network/Swift/service.cpp
Normal file
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Service module for swift<->FG connection
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "service.h"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <iostream>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
|
||||
#define FGSWIFTBUS_API_VERSION 3;
|
||||
|
||||
namespace FGSwiftBus {
|
||||
|
||||
CService::CService()
|
||||
{
|
||||
// Initialize node pointers
|
||||
m_textMessageNode = fgGetNode("/sim/messages/copilot", true);
|
||||
m_aircraftModelPathNode = fgGetNode("/sim/aircraft-dir", true);
|
||||
m_aircraftDescriptionNode = fgGetNode("/sim/description", true);
|
||||
m_isPausedNode = fgGetNode("/sim/freeze/master", true);
|
||||
m_latitudeNode = fgGetNode("/position/latitude-deg", true);
|
||||
m_longitudeNode = fgGetNode("/position/longitude-deg", true);
|
||||
m_altitudeMSLNode = fgGetNode("/position/altitude-ft", true);
|
||||
m_heightAGLNode = fgGetNode("/position/altitude-agl-ft", true);
|
||||
m_groundSpeedNode = fgGetNode("/velocities/groundspeed-kt", true);
|
||||
m_pitchNode = fgGetNode("/orientation/pitch-deg", true);
|
||||
m_rollNode = fgGetNode("/orientation/roll-deg", true);
|
||||
m_trueHeadingNode = fgGetNode("/orientation/heading-deg", true);
|
||||
m_wheelsOnGroundNode = fgGetNode("/gear/gear/wow", true);
|
||||
m_com1ActiveNode = fgGetNode("/instrumentation/comm/frequencies/selected-mhz", true);
|
||||
m_com1StandbyNode = fgGetNode("/instrumentation/comm/frequencies/standby-mhz", true);
|
||||
m_com2ActiveNode = fgGetNode("/instrumentation/comm[1]/frequencies/selected-mhz", true);
|
||||
m_com2StandbyNode = fgGetNode("/instrumentation/comm[1]/frequencies/standby-mhz", true);
|
||||
m_transponderCodeNode = fgGetNode("/instrumentation/transponder/id-code", true);
|
||||
m_transponderModeNode = fgGetNode("/instrumentation/transponder/inputs/knob-mode", true);
|
||||
m_transponderIdentNode = fgGetNode("/instrumentation/transponder/ident", true);
|
||||
m_beaconLightsNode = fgGetNode("/controls/lighting/beacon", true);
|
||||
m_landingLightsNode = fgGetNode("/controls/lighting/landing-lights", true);
|
||||
m_navLightsNode = fgGetNode("/controls/lighting/nav-lights", true);
|
||||
m_strobeLightsNode = fgGetNode("/controls/lighting/strobe", true);
|
||||
m_taxiLightsNode = fgGetNode("/controls/lighting/taxi-light", true);
|
||||
m_altimeterServiceableNode = fgGetNode("/instrumentation/altimeter/serviceable", true);
|
||||
m_pressAltitudeFtNode = fgGetNode("/instrumentation/altimeter/pressure-alt-ft", true);
|
||||
m_flapsDeployRatioNode = fgGetNode("/surface-positions/flap-pos-norm", true);
|
||||
m_gearDeployRatioNode = fgGetNode("/gear/gear/position-norm", true);
|
||||
m_speedBrakeDeployRatioNode = fgGetNode("/surface-positions/speedbrake-pos-norm", true);
|
||||
m_aircraftNameNode = fgGetNode("/sim/aircraft", true);
|
||||
m_groundElevationNode = fgGetNode("/position/ground-elev-m", true);
|
||||
m_velocityXNode = fgGetNode("/velocities/speed-east-fps", true);
|
||||
m_velocityYNode = fgGetNode("/velocities/speed-down-fps", true);
|
||||
m_velocityZNode = fgGetNode("/velocities/speed-north-fps", true);
|
||||
m_rollRateNode = fgGetNode("/orientation/roll-rate-degps", true);
|
||||
m_pichRateNode = fgGetNode("/orientation/pitch-rate-degps", true);
|
||||
m_yawRateNode = fgGetNode("/orientation/yaw-rate-degps", true);
|
||||
m_com1VolumeNode = fgGetNode("/instrumentation/comm/volume", true);
|
||||
m_com2VolumeNode = fgGetNode("/instrumentation/comm[1]/volume", true);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Static method
|
||||
int CService::getVersionNumber()
|
||||
{
|
||||
return FGSWIFTBUS_API_VERSION;
|
||||
}
|
||||
|
||||
void CService::addTextMessage(const std::string& text)
|
||||
{
|
||||
if (text.empty()) { return; }
|
||||
m_textMessageNode->setStringValue(text);
|
||||
}
|
||||
|
||||
std::string CService::getAircraftModelPath() const
|
||||
{
|
||||
return m_aircraftModelPathNode->getStringValue();
|
||||
}
|
||||
|
||||
std::string CService::getAircraftLivery() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CService::getAircraftIcaoCode() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CService::getAircraftDescription() const
|
||||
{
|
||||
return m_aircraftDescriptionNode->getStringValue();
|
||||
}
|
||||
|
||||
bool CService::isPaused() const
|
||||
{
|
||||
return m_isPausedNode->getBoolValue();
|
||||
}
|
||||
|
||||
double CService::getLatitude() const
|
||||
{
|
||||
return m_latitudeNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getLongitude() const
|
||||
{
|
||||
return m_longitudeNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getAltitudeMSL() const
|
||||
{
|
||||
return m_altitudeMSLNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getHeightAGL() const
|
||||
{
|
||||
return m_heightAGLNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getGroundSpeed() const
|
||||
{
|
||||
return m_groundSpeedNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getPitch() const
|
||||
{
|
||||
return m_pitchNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getRoll() const
|
||||
{
|
||||
return m_rollNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getTrueHeading() const
|
||||
{
|
||||
return m_trueHeadingNode->getDoubleValue();
|
||||
}
|
||||
|
||||
bool CService::getAllWheelsOnGround() const
|
||||
{
|
||||
return m_wheelsOnGroundNode->getBoolValue();
|
||||
}
|
||||
|
||||
int CService::getCom1Active() const
|
||||
{
|
||||
return (int)(m_com1ActiveNode->getDoubleValue() * 1000);
|
||||
}
|
||||
|
||||
int CService::getCom1Standby() const
|
||||
{
|
||||
return (int)(m_com1StandbyNode->getDoubleValue() * 1000);
|
||||
}
|
||||
|
||||
int CService::getCom2Active() const
|
||||
{
|
||||
return (int)(m_com2ActiveNode->getDoubleValue() * 1000);
|
||||
}
|
||||
|
||||
int CService::getCom2Standby() const
|
||||
{
|
||||
return (int)(m_com2StandbyNode->getDoubleValue() * 1000);
|
||||
}
|
||||
|
||||
int CService::getTransponderCode() const
|
||||
{
|
||||
return m_transponderCodeNode->getIntValue();
|
||||
}
|
||||
|
||||
int CService::getTransponderMode() const
|
||||
{
|
||||
return m_transponderModeNode->getIntValue();
|
||||
}
|
||||
|
||||
bool CService::getTransponderIdent() const
|
||||
{
|
||||
return m_transponderIdentNode->getBoolValue();
|
||||
}
|
||||
|
||||
bool CService::getBeaconLightsOn() const
|
||||
{
|
||||
return m_beaconLightsNode->getBoolValue();
|
||||
}
|
||||
|
||||
bool CService::getLandingLightsOn() const
|
||||
{
|
||||
return m_landingLightsNode->getBoolValue();
|
||||
}
|
||||
|
||||
bool CService::getNavLightsOn() const
|
||||
{
|
||||
return m_navLightsNode->getBoolValue();
|
||||
}
|
||||
|
||||
|
||||
bool CService::getStrobeLightsOn() const
|
||||
{
|
||||
return m_strobeLightsNode->getBoolValue();
|
||||
}
|
||||
|
||||
bool CService::getTaxiLightsOn() const
|
||||
{
|
||||
return m_taxiLightsNode->getBoolValue();
|
||||
}
|
||||
|
||||
double CService::getPressAlt() const
|
||||
{
|
||||
if (m_altimeterServiceableNode->getBoolValue()) {
|
||||
return m_pressAltitudeFtNode->getDoubleValue();
|
||||
} else {
|
||||
return m_altitudeMSLNode->getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
void CService::setCom1Active(int freq)
|
||||
{
|
||||
m_com1ActiveNode->setDoubleValue(freq / (double)1000);
|
||||
}
|
||||
|
||||
void CService::setCom1Standby(int freq)
|
||||
{
|
||||
m_com1StandbyNode->setDoubleValue(freq / (double)1000);
|
||||
}
|
||||
|
||||
void CService::setCom2Active(int freq)
|
||||
{
|
||||
m_com2ActiveNode->setDoubleValue(freq / (double)1000);
|
||||
}
|
||||
|
||||
void CService::setCom2Standby(int freq)
|
||||
{
|
||||
m_com2StandbyNode->setDoubleValue(freq / (double)1000);
|
||||
}
|
||||
|
||||
void CService::setTransponderCode(int code)
|
||||
{
|
||||
m_transponderCodeNode->setIntValue(code);
|
||||
}
|
||||
|
||||
void CService::setTransponderMode(int mode)
|
||||
{
|
||||
m_transponderModeNode->setIntValue(mode);
|
||||
}
|
||||
|
||||
double CService::getFlapsDeployRatio() const
|
||||
{
|
||||
return m_flapsDeployRatioNode->getFloatValue();
|
||||
}
|
||||
|
||||
double CService::getGearDeployRatio() const
|
||||
{
|
||||
return m_gearDeployRatioNode->getFloatValue();
|
||||
}
|
||||
|
||||
int CService::getNumberOfEngines() const
|
||||
{
|
||||
// TODO Use correct property
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::vector<double> CService::getEngineN1Percentage() const
|
||||
{
|
||||
// TODO use correct engine numbers
|
||||
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 m_speedBrakeDeployRatioNode->getFloatValue();
|
||||
}
|
||||
|
||||
double CService::getGroundElevation() const
|
||||
{
|
||||
return m_groundElevationNode->getDoubleValue();
|
||||
}
|
||||
|
||||
std::string CService::getAircraftModelFilename() const
|
||||
{
|
||||
std::string modelFileName = getAircraftName();
|
||||
modelFileName.append("-set.xml");
|
||||
return modelFileName;
|
||||
}
|
||||
|
||||
std::string CService::getAircraftModelString() const
|
||||
{
|
||||
std::string modelName = getAircraftName();
|
||||
std::string modelString = "FG " + modelName;
|
||||
return modelString;
|
||||
}
|
||||
|
||||
std::string CService::getAircraftName() const
|
||||
{
|
||||
return m_aircraftNameNode->getStringValue();
|
||||
}
|
||||
|
||||
double CService::getVelocityX() const
|
||||
{
|
||||
return m_velocityXNode->getDoubleValue() * SG_FEET_TO_METER;
|
||||
}
|
||||
|
||||
double CService::getVelocityY() const
|
||||
{
|
||||
return m_velocityYNode->getDoubleValue() * SG_FEET_TO_METER * -1; // + (up), - (down)
|
||||
}
|
||||
|
||||
double CService::getVelocityZ() const
|
||||
{
|
||||
return m_velocityZNode->getDoubleValue() * SG_FEET_TO_METER;
|
||||
}
|
||||
|
||||
double CService::getRollRate() const
|
||||
{
|
||||
return m_rollRateNode->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
||||
}
|
||||
double CService::getPitchRate() const
|
||||
{
|
||||
return m_pichRateNode->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
||||
}
|
||||
|
||||
double CService::getYawRate() const
|
||||
{
|
||||
return m_yawRateNode->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
||||
}
|
||||
|
||||
double CService::getCom1Volume() const
|
||||
{
|
||||
return m_com1VolumeNode->getDoubleValue();
|
||||
}
|
||||
|
||||
double CService::getCom2Volume() const
|
||||
{
|
||||
return m_com2VolumeNode->getDoubleValue();
|
||||
}
|
||||
|
||||
|
||||
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 pressAlt = getPressAlt();
|
||||
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(pressAlt);
|
||||
sendDBusMessage(reply);
|
||||
});
|
||||
} else if (message.getMethodName() == "getOwnAircraftVelocityData") {
|
||||
queueDBusCall([=]() {
|
||||
double velocityX = getVelocityX();
|
||||
double velocityY = getVelocityY();
|
||||
double velocityZ = getVelocityZ();
|
||||
double pitchVelocity = getPitchRate();
|
||||
double rollVelocity = getRollRate();
|
||||
double yawVelocity = getYawRate();
|
||||
CDBusMessage reply = CDBusMessage::createReply(sender, serial);
|
||||
reply.beginArgumentWrite();
|
||||
reply.appendArgument(velocityX);
|
||||
reply.appendArgument(velocityY);
|
||||
reply.appendArgument(velocityZ);
|
||||
reply.appendArgument(pitchVelocity);
|
||||
reply.appendArgument(rollVelocity);
|
||||
reply.appendArgument(yawVelocity);
|
||||
sendDBusMessage(reply);
|
||||
});
|
||||
} else if (message.getMethodName() == "getVersionNumber") {
|
||||
queueDBusCall([=]() {
|
||||
sendDBusReply(sender, serial, getVersionNumber());
|
||||
});
|
||||
} 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() == "getPressAlt") {
|
||||
queueDBusCall([=]() {
|
||||
sendDBusReply(sender, serial, getPressAlt());
|
||||
});
|
||||
} else if (message.getMethodName() == "getGroundElevation") {
|
||||
queueDBusCall([=]() {
|
||||
sendDBusReply(sender, serial, getGroundElevation());
|
||||
});
|
||||
} 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 if (message.getMethodName() == "getCom1Volume") {
|
||||
queueDBusCall([=]() {
|
||||
sendDBusReply(sender, serial, getCom1Volume());
|
||||
});
|
||||
} else if (message.getMethodName() == "getCom2Volume") {
|
||||
queueDBusCall([=]() {
|
||||
sendDBusReply(sender, serial, getCom2Volume());
|
||||
});
|
||||
} 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
|
||||
262
src/Network/Swift/service.h
Normal file
262
src/Network/Swift/service.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Service module for swift<->FG connection
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BLACKSIM_FGSWIFTBUS_SERVICE_H
|
||||
#define BLACKSIM_FGSWIFTBUS_SERVICE_H
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
|
||||
#include "dbusobject.h"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <chrono>
|
||||
#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>
|
||||
#include <string>
|
||||
|
||||
|
||||
//! \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();
|
||||
|
||||
//! Getting flightgear version
|
||||
static int getVersionNumber();
|
||||
|
||||
////! 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 pressure altitude in ft
|
||||
double getPressAlt() 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;
|
||||
|
||||
//! Get ground elevation at aircraft current position
|
||||
double getGroundElevation() const;
|
||||
|
||||
//! Get x velocity in m/s
|
||||
double getVelocityX() const;
|
||||
|
||||
//! Get y velocity in m/s
|
||||
double getVelocityY() const;
|
||||
|
||||
//! Get z velocity in m/s
|
||||
double getVelocityZ() const;
|
||||
|
||||
//! Get roll rate in rad/sec
|
||||
double getRollRate() const;
|
||||
|
||||
//! Get pitch rate in rad/sec
|
||||
double getPitchRate() const;
|
||||
|
||||
//! Get yaw rate in rad/sec
|
||||
double getYawRate() const;
|
||||
|
||||
double getCom1Volume() const;
|
||||
double getCom2Volume() const;
|
||||
|
||||
//! Perform generic processing
|
||||
int process();
|
||||
|
||||
protected:
|
||||
DBusHandlerResult dbusMessageHandler(const CDBusMessage& message) override;
|
||||
|
||||
private:
|
||||
SGPropertyNode_ptr m_textMessageNode;
|
||||
SGPropertyNode_ptr m_aircraftModelPathNode;
|
||||
//SGPropertyNode_ptr aircraftLiveryNode;
|
||||
//SGPropertyNode_ptr aircraftIcaoCodeNode;
|
||||
SGPropertyNode_ptr m_aircraftDescriptionNode;
|
||||
SGPropertyNode_ptr m_isPausedNode;
|
||||
SGPropertyNode_ptr m_latitudeNode;
|
||||
SGPropertyNode_ptr m_longitudeNode;
|
||||
SGPropertyNode_ptr m_altitudeMSLNode;
|
||||
SGPropertyNode_ptr m_heightAGLNode;
|
||||
SGPropertyNode_ptr m_groundSpeedNode;
|
||||
SGPropertyNode_ptr m_pitchNode;
|
||||
SGPropertyNode_ptr m_rollNode;
|
||||
SGPropertyNode_ptr m_trueHeadingNode;
|
||||
SGPropertyNode_ptr m_wheelsOnGroundNode;
|
||||
SGPropertyNode_ptr m_com1ActiveNode;
|
||||
SGPropertyNode_ptr m_com1StandbyNode;
|
||||
SGPropertyNode_ptr m_com2ActiveNode;
|
||||
SGPropertyNode_ptr m_com2StandbyNode;
|
||||
SGPropertyNode_ptr m_transponderCodeNode;
|
||||
SGPropertyNode_ptr m_transponderModeNode;
|
||||
SGPropertyNode_ptr m_transponderIdentNode;
|
||||
SGPropertyNode_ptr m_beaconLightsNode;
|
||||
SGPropertyNode_ptr m_landingLightsNode;
|
||||
SGPropertyNode_ptr m_navLightsNode;
|
||||
SGPropertyNode_ptr m_strobeLightsNode;
|
||||
SGPropertyNode_ptr m_taxiLightsNode;
|
||||
SGPropertyNode_ptr m_altimeterServiceableNode;
|
||||
SGPropertyNode_ptr m_pressAltitudeFtNode;
|
||||
SGPropertyNode_ptr m_flapsDeployRatioNode;
|
||||
SGPropertyNode_ptr m_gearDeployRatioNode;
|
||||
SGPropertyNode_ptr m_speedBrakeDeployRatioNode;
|
||||
SGPropertyNode_ptr m_groundElevationNode;
|
||||
//SGPropertyNode_ptr numberEnginesNode;
|
||||
//SGPropertyNode_ptr engineN1PercentageNode;
|
||||
SGPropertyNode_ptr m_aircraftNameNode;
|
||||
SGPropertyNode_ptr m_velocityXNode;
|
||||
SGPropertyNode_ptr m_velocityYNode;
|
||||
SGPropertyNode_ptr m_velocityZNode;
|
||||
SGPropertyNode_ptr m_rollRateNode;
|
||||
SGPropertyNode_ptr m_pichRateNode;
|
||||
SGPropertyNode_ptr m_yawRateNode;
|
||||
SGPropertyNode_ptr m_com1VolumeNode;
|
||||
SGPropertyNode_ptr m_com2VolumeNode;
|
||||
};
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
97
src/Network/Swift/swift_connection.cxx
Normal file
97
src/Network/Swift/swift_connection.cxx
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "plugin.h"
|
||||
#include "swift_connection.hxx"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/commands.hxx>
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
namespace {
|
||||
inline std::string fgswiftbusServiceName()
|
||||
{
|
||||
return std::string("org.swift-project.fgswiftbus");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool SwiftConnection::startServer(const SGPropertyNode* arg, SGPropertyNode* root)
|
||||
{
|
||||
SwiftConnection::plug = std::make_unique<FGSwiftBus::CPlugin>();
|
||||
|
||||
serverRunning = true;
|
||||
fgSetBool("/sim/swift/serverRunning", true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwiftConnection::stopServer(const SGPropertyNode* arg, SGPropertyNode* root)
|
||||
{
|
||||
fgSetBool("/sim/swift/serverRunning", false);
|
||||
serverRunning = false;
|
||||
|
||||
SwiftConnection::plug.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SwiftConnection::SwiftConnection()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
SwiftConnection::~SwiftConnection()
|
||||
{
|
||||
shutdown();
|
||||
|
||||
if (serverRunning) {
|
||||
SwiftConnection::plug.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SwiftConnection::init()
|
||||
{
|
||||
if (!initialized) {
|
||||
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) {
|
||||
SwiftConnection::plug->fastLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void SwiftConnection::shutdown()
|
||||
{
|
||||
if (initialized) {
|
||||
fgSetBool("/sim/swift/available", false);
|
||||
initialized = false;
|
||||
|
||||
globals->get_commands()->removeCommand("swiftStart");
|
||||
globals->get_commands()->removeCommand("swiftStop");
|
||||
}
|
||||
}
|
||||
|
||||
void SwiftConnection::reinit()
|
||||
{
|
||||
shutdown();
|
||||
init();
|
||||
}
|
||||
|
||||
// Register the subsystem.
|
||||
SGSubsystemMgr::Registrant<SwiftConnection> registrantSwiftConnection(
|
||||
SGSubsystemMgr::POST_FDM);
|
||||
49
src/Network/Swift/swift_connection.hxx
Normal file
49
src/Network/Swift/swift_connection.hxx
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#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 "dbusconnection.h"
|
||||
#include "dbusdispatcher.h"
|
||||
#include "dbusserver.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
class SwiftConnection : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
SwiftConnection();
|
||||
~SwiftConnection();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
void reinit() override;
|
||||
void shutdown() override;
|
||||
void update(double delta_time_sec) override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "swift"; }
|
||||
|
||||
bool startServer(const SGPropertyNode* arg, SGPropertyNode* root);
|
||||
bool stopServer(const SGPropertyNode* arg, SGPropertyNode* root);
|
||||
|
||||
std::unique_ptr<FGSwiftBus::CPlugin> plug{};
|
||||
|
||||
private:
|
||||
bool serverRunning = false;
|
||||
bool initialized = false;
|
||||
};
|
||||
299
src/Network/Swift/traffic.cpp
Normal file
299
src/Network/Swift/traffic.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Traffic module for swift<->FG connection
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
//! \cond PRIVATE
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "traffic.h"
|
||||
#include "SwiftAircraftManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// clazy:excludeall=reserve-candidates
|
||||
|
||||
namespace FGSwiftBus {
|
||||
|
||||
CTraffic::CTraffic()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool CTraffic::initialize()
|
||||
{
|
||||
acm.reset(new FGSwiftAircraftManager());
|
||||
return acm->isInitialized();
|
||||
}
|
||||
|
||||
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::cleanup()
|
||||
{
|
||||
acm.reset();
|
||||
}
|
||||
|
||||
void CTraffic::dbusDisconnectedHandler()
|
||||
{
|
||||
if (acm)
|
||||
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();
|
||||
|
||||
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<double> groundspeeds;
|
||||
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(groundspeeds);
|
||||
message.getArgument(onGrounds);
|
||||
queueDBusCall([=]() {
|
||||
std::vector<SwiftPlaneUpdate> updates;
|
||||
for (long unsigned int i = 0; i < latitudes.size(); i++) {
|
||||
SGGeod pos;
|
||||
pos.setLatitudeDeg(latitudes.at(i));
|
||||
pos.setLongitudeDeg(longitudes.at(i));
|
||||
pos.setElevationFt(altitudes.at(i));
|
||||
SGVec3d orientation(pitches.at(i), rolls.at(i), headings.at(i));
|
||||
updates.push_back({callsigns.at(i), pos, orientation, groundspeeds.at(i), onGrounds.at(i)});
|
||||
}
|
||||
acm->updatePlanes(updates);
|
||||
});
|
||||
} 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 if (message.getMethodName() == "getElevationAtPosition") {
|
||||
std::string callsign;
|
||||
double latitudeDeg;
|
||||
double longitudeDeg;
|
||||
double altitudeMeters;
|
||||
message.beginArgumentRead();
|
||||
message.getArgument(callsign);
|
||||
message.getArgument(latitudeDeg);
|
||||
message.getArgument(longitudeDeg);
|
||||
message.getArgument(altitudeMeters);
|
||||
queueDBusCall([=]() {
|
||||
SGGeod pos;
|
||||
pos.setLatitudeDeg(latitudeDeg);
|
||||
pos.setLongitudeDeg(longitudeDeg);
|
||||
pos.setElevationM(altitudeMeters);
|
||||
double elevation = acm->getElevationAtPosition(callsign, pos);
|
||||
CDBusMessage reply = CDBusMessage::createReply(sender, serial);
|
||||
reply.beginArgumentWrite();
|
||||
reply.appendArgument(callsign);
|
||||
reply.appendArgument(elevation);
|
||||
sendDBusMessage(reply);
|
||||
});
|
||||
} else if (message.getMethodName() == "setPlanesTransponders") {
|
||||
maybeSendEmptyDBusReply(wantsReply, sender, serial);
|
||||
std::vector<std::string> callsigns;
|
||||
std::vector<int> codes;
|
||||
std::vector<bool> modeCs;
|
||||
std::vector<bool> idents;
|
||||
message.beginArgumentRead();
|
||||
message.getArgument(callsigns);
|
||||
message.getArgument(codes);
|
||||
message.getArgument(modeCs);
|
||||
message.getArgument(idents);
|
||||
std::vector<AircraftTransponder> transponders;
|
||||
transponders.reserve(callsigns.size());
|
||||
for (long unsigned int i = 0; i < callsigns.size(); i++) {
|
||||
transponders.emplace_back(callsigns.at(i), codes.at(i), modeCs.at(i), idents.at(i));
|
||||
}
|
||||
queueDBusCall([=]() {
|
||||
acm->setPlanesTransponders(transponders);
|
||||
});
|
||||
} else if (message.getMethodName() == "setPlanesSurfaces") {
|
||||
maybeSendEmptyDBusReply(wantsReply, sender, serial);
|
||||
std::vector<std::string> callsigns;
|
||||
std::vector<double> gears;
|
||||
std::vector<double> flaps;
|
||||
std::vector<double> spoilers;
|
||||
std::vector<double> speedBrakes;
|
||||
std::vector<double> slats;
|
||||
std::vector<double> wingSweeps;
|
||||
std::vector<double> thrusts;
|
||||
std::vector<double> elevators;
|
||||
std::vector<double> rudders;
|
||||
std::vector<double> ailerons;
|
||||
std::vector<bool> landLights;
|
||||
std::vector<bool> taxiLights;
|
||||
std::vector<bool> beaconLights;
|
||||
std::vector<bool> strobeLights;
|
||||
std::vector<bool> navLights;
|
||||
std::vector<int> lightPatterns;
|
||||
message.beginArgumentRead();
|
||||
message.getArgument(callsigns);
|
||||
message.getArgument(gears);
|
||||
message.getArgument(flaps);
|
||||
message.getArgument(spoilers);
|
||||
message.getArgument(speedBrakes);
|
||||
message.getArgument(slats);
|
||||
message.getArgument(wingSweeps);
|
||||
message.getArgument(thrusts);
|
||||
message.getArgument(elevators);
|
||||
message.getArgument(rudders);
|
||||
message.getArgument(ailerons);
|
||||
message.getArgument(landLights);
|
||||
message.getArgument(taxiLights);
|
||||
message.getArgument(beaconLights);
|
||||
message.getArgument(strobeLights);
|
||||
message.getArgument(navLights);
|
||||
message.getArgument(lightPatterns);
|
||||
std::vector<AircraftSurfaces> surfaces;
|
||||
surfaces.reserve(callsigns.size());
|
||||
for (long unsigned int i = 0; i < callsigns.size(); i++) {
|
||||
surfaces.emplace_back(callsigns.at(i), gears.at(i), flaps.at(i), spoilers.at(i), speedBrakes.at(i), slats.at(i),
|
||||
wingSweeps.at(i), thrusts.at(i), elevators.at(i), rudders.at(i), ailerons.at(i),
|
||||
landLights.at(i), taxiLights.at(i), beaconLights.at(i), strobeLights.at(i), navLights.at(i), lightPatterns.at(i));
|
||||
}
|
||||
queueDBusCall([=]() {
|
||||
acm->setPlanesSurfaces(surfaces);
|
||||
});
|
||||
} 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;
|
||||
}
|
||||
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
//! \endcond
|
||||
71
src/Network/Swift/traffic.h
Normal file
71
src/Network/Swift/traffic.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Traffic module for swift<->FG connection
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
|
||||
* SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#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();
|
||||
|
||||
//! Perform generic processing
|
||||
int process();
|
||||
|
||||
void emitSimFrame();
|
||||
|
||||
protected:
|
||||
virtual void dbusDisconnectedHandler() override;
|
||||
|
||||
DBusHandlerResult dbusMessageHandler(const CDBusMessage& message) override;
|
||||
|
||||
private:
|
||||
void emitPlaneAdded(const std::string& callsign);
|
||||
void cleanup();
|
||||
|
||||
struct Plane {
|
||||
void* id = nullptr;
|
||||
std::string callsign;
|
||||
char label[32]{};
|
||||
};
|
||||
|
||||
bool m_emitSimFrame = true;
|
||||
std::unique_ptr<FGSwiftAircraftManager> acm;
|
||||
};
|
||||
} // namespace FGSwiftBus
|
||||
|
||||
#endif // guard
|
||||
Reference in New Issue
Block a user