Rename xbus to xswiftbus

Summary:
I wanted to rename xbus because its relation to //swift// is not immediately clear from the name.

xswiftbus seems reasonable.

Reviewers: #swift_pilot_client, kbasan

Reviewed By: kbasan

Subscribers: kbasan, jenkins

Tags: #swift_pilot_client

Differential Revision: https://dev.swift-project.org/D14
This commit is contained in:
Mathew Sutcliffe
2017-05-05 23:07:11 +01:00
parent 83adc66ec7
commit 4a4dea8d4d
53 changed files with 442 additions and 442 deletions

433
src/xswiftbus/traffic.cpp Normal file
View File

@@ -0,0 +1,433 @@
/* Copyright (C) 2013
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \cond PRIVATE
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "traffic.h"
#include "utils.h"
#include "blackmisc/simulation/interpolator.h"
#include "blackmisc/simulation/interpolationhints.h"
#include "blackmisc/aviation/callsign.h"
#include "XPMPMultiplayer.h"
#include <XPLM/XPLMProcessing.h>
#include <XPLM/XPLMUtilities.h>
#include <QDateTime>
#include <QStringList>
#include <cstring>
#include <cmath>
// clazy:excludeall=reserve-candidates
namespace XSwiftBus
{
CTraffic::Plane::Plane(void *id_, QString callsign_, QString aircraftIcao_, QString airlineIcao_, QString livery_)
: id(id_), callsign(callsign_), aircraftIcao(aircraftIcao_), airlineIcao(airlineIcao_), livery(livery_), interpolator(callsign)
{
std::memset(static_cast<void *>(&surfaces), 0, sizeof(surfaces));
surfaces.lights.bcnLights = surfaces.lights.landLights = surfaces.lights.navLights = surfaces.lights.strbLights = 1;
surfaces.size = sizeof(surfaces);
xpdr.size = sizeof(xpdr);
std::strncpy(label, qPrintable(callsign), sizeof(label));
surfaces.lights.timeOffset = static_cast<quint16>(qrand() % 0xffff);
}
BlackMisc::Simulation::CInterpolationHints CTraffic::Plane::hints()
{
// \todo MS 865 CInterpolationAndRenderingSetup allows to setup interpolation in the GUI, e.g.
// also to disable aircraft parts / or logging parts (log file). I wonder if you want to consider it here
// e.g. interpolator->getInterpolatorSetup().getLogCallsigns().contains(callsign)
// if the setup is needed more than once, store it here to avoid multiple locks
BlackMisc::Simulation::CInterpolationAndRenderingSetup setup;
BlackMisc::Simulation::CInterpolationHints hints;
BlackMisc::Simulation::CPartsStatus status;
hints.setAircraftParts(interpolator.getInterpolatedParts(-1, setup, status));
hints.setElevationProvider([this](const auto & situation)
{
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
const auto meters = terrainProbe.getElevation(
situation.latitude().value(CAngleUnit::deg()),
situation.longitude().value(CAngleUnit::deg()),
situation.getAltitude().value(CLengthUnit::m()));
if (std::isnan(meters)) { return CAltitude::null(); }
constexpr decltype(meters) fudgeFactor = 3.0; //! \fixme Value should be different for each plane, derived from the CSL model geometry
return CAltitude(CLength(meters + fudgeFactor, CLengthUnit::m()), CAltitude::MeanSeaLevel);
});
return hints;
}
CTraffic::CTraffic(QObject *parent) :
QObject(parent)
{
}
CTraffic::~CTraffic()
{
cleanup();
}
bool s_legacyDataOK = true;
void CTraffic::initLegacyData()
{
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
auto err = XPMPMultiplayerInitLegacyData(qPrintable(dir + "CSL"), qPrintable(dir + "related.txt"),
qPrintable(dir + "lights.png"), qPrintable(dir + "Doc8643.txt"), "C172", preferences, preferences);
if (*err) { s_legacyDataOK = false; }
}
bool CTraffic::initialize()
{
if (! s_legacyDataOK) { return false; }
auto err = XPMPMultiplayerInit(preferences, preferences);
if (*err) { cleanup(); return false; }
m_initialized = true;
err = XPMPMultiplayerEnable();
if (*err) { cleanup(); return false; }
m_enabled = true;
XPMPLoadPlanesIfNecessary();
return true;
}
void CTraffic::cleanup()
{
removeAllPlanes();
if (m_enabled)
{
m_enabled = false;
XPMPMultiplayerDisable();
}
if (m_initialized)
{
m_initialized = false;
XPMPMultiplayerCleanup();
}
}
int g_maxPlanes = 100;
float g_drawDistance = 50.0f;
int CTraffic::preferences(const char *section, const char *name, int def)
{
if (strcmp(section, "planes") == 0 && strcmp(name, "max_full_count") == 0)
{
return g_maxPlanes;
}
else if (strcmp(section, "debug") == 0 && strcmp(name, "allow_obj8_async_load") == 0)
{
return true;
}
return def;
}
float CTraffic::preferences(const char *section, const char *name, float def)
{
if (strcmp(section, "planes") == 0 && strcmp(name, "full_distance") == 0)
{
return g_drawDistance;
}
return def;
}
bool CTraffic::loadPlanesPackage(const QString &path)
{
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
auto err = XPMPLoadCSLPackage(qPrintable(path), qPrintable(dir + "related.txt"), qPrintable(dir + "Doc8643.txt"));
if (*err) { return false; }
return true;
}
void CTraffic::setDefaultIcao(const QString &defaultIcao)
{
XPMPSetDefaultPlaneICAO(qPrintable(defaultIcao));
}
void CTraffic::setDrawingLabels(bool drawing)
{
if (drawing)
{
XPMPEnableAircraftLabels();
}
else
{
XPMPDisableAircraftLabels();
}
}
bool CTraffic::isDrawingLabels() const
{
return XPMPDrawingAircraftLabels();
}
void CTraffic::updateInstalledModels()
{
int numberOfModels = XPMPGetNumberOfInstalledModels();
QStringList modelNames;
QStringList icaos;
QStringList airlines;
QStringList liveries;
for (int i = 0; i < numberOfModels; ++i)
{
const char *modelName = nullptr;
const char *icao = nullptr;
const char *airline = nullptr;
const char *livery = nullptr;
XPMPGetModelInfo(i, &modelName, &icao, &airline, &livery);
modelNames.append(QString::fromLocal8Bit(modelName));
icaos.append(QString::fromLocal8Bit(icao));
airlines.append(QString::fromLocal8Bit(airline));
liveries.append(QString::fromLocal8Bit(livery));
}
emit installedModelsUpdated(modelNames, icaos, airlines, liveries);
}
void CTraffic::setMaxPlanes(int planes)
{
g_maxPlanes = planes;
}
void CTraffic::setMaxDrawDistance(double nauticalMiles)
{
g_drawDistance = static_cast<float>(nauticalMiles);
}
void CTraffic::addPlane(const QString &callsign, const QString &modelName, const QString &aircraftIcao, const QString &airlineIcao, const QString &livery)
{
XPMPPlaneID id = nullptr;
if (modelName.isEmpty())
{
id = XPMPCreatePlane(qPrintable(aircraftIcao), qPrintable(airlineIcao), qPrintable(livery), getPlaneData, static_cast<void *>(this));
}
else
{
id = XPMPCreatePlaneWithModelName(qPrintable(modelName), qPrintable(aircraftIcao), qPrintable(airlineIcao), qPrintable(livery), getPlaneData, static_cast<void *>(this));
}
if (id)
{
auto plane = new Plane(id, callsign, aircraftIcao, airlineIcao, livery);
m_planesByCallsign[callsign] = plane;
m_planesById[id] = plane;
}
}
void CTraffic::removePlane(const QString &callsign)
{
auto plane = m_planesByCallsign.value(callsign, nullptr);
if (plane)
{
m_planesByCallsign.remove(callsign);
m_planesById.remove(plane->id);
XPMPDestroyPlane(plane->id);
delete plane;
}
}
void CTraffic::removeAllPlanes()
{
for (auto plane : BlackMisc::as_const(m_planesByCallsign))
{
XPMPDestroyPlane(plane->id);
delete plane;
}
m_planesByCallsign.clear();
m_planesById.clear();
}
void CTraffic::addPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading, qint64 relativeTime)
{
const auto plane = m_planesByCallsign.value(callsign, nullptr);
if (plane)
{
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
CAircraftSituation situation(
callsign,
BlackMisc::Geo::CCoordinateGeodetic(latitude, longitude, altitude),
CHeading(heading, CHeading::True, CAngleUnit::deg()),
CAngle(pitch, CAngleUnit::deg()),
CAngle(roll, CAngleUnit::deg()),
CSpeed(0, CSpeedUnit::kts())
);
situation.setMSecsSinceEpoch(relativeTime + QDateTime::currentMSecsSinceEpoch());
plane->interpolator.addAircraftSituation(situation);
}
}
void CTraffic::addPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround, qint64 relativeTime)
{
const auto surfaces = std::make_pair(relativeTime + QDateTime::currentMSecsSinceEpoch(), [ = ](Plane *plane)
{
plane->hasSurfaces = true;
plane->targetGearPosition = gear;
plane->surfaces.flapRatio = flap;
plane->surfaces.spoilerRatio = spoiler;
plane->surfaces.speedBrakeRatio = speedBrake;
plane->surfaces.slatRatio = slat;
plane->surfaces.wingSweep = wingSweep;
plane->surfaces.thrust = thrust;
plane->surfaces.yokePitch = elevator;
plane->surfaces.yokeHeading = rudder;
plane->surfaces.yokeRoll = aileron;
plane->surfaces.lights.landLights = landLight;
plane->surfaces.lights.bcnLights = beaconLight;
plane->surfaces.lights.strbLights = strobeLight;
plane->surfaces.lights.navLights = navLight;
plane->surfaces.lights.flashPattern = lightPattern;
});
const auto plane = m_planesByCallsign.value(callsign, nullptr);
if (plane)
{
if (plane->hasSurfaces) { plane->pendingSurfaces.push_back(surfaces); }
else { surfaces.second(plane); }
BlackMisc::Aviation::CAircraftParts parts;
parts.setOnGround(onGround);
parts.setMSecsSinceEpoch(relativeTime + QDateTime::currentMSecsSinceEpoch());
plane->interpolator.addAircraftParts(parts);
}
}
void CTraffic::setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident)
{
const auto plane = m_planesByCallsign.value(callsign, nullptr);
if (plane)
{
plane->hasXpdr = true;
plane->xpdr.code = code;
if (ident) { plane->xpdr.mode = xpmpTransponderMode_ModeC_Ident; }
else if (modeC) { plane->xpdr.mode = xpmpTransponderMode_ModeC; }
else { plane->xpdr.mode = xpmpTransponderMode_Standby; }
}
}
void CTraffic::setInterpolatorMode(const QString &callsign, bool spline)
{
const auto plane = m_planesByCallsign.value(callsign, nullptr);
if (plane)
{
plane->interpolator.setMode(spline ? BlackMisc::Simulation::CInterpolatorMulti::ModeSpline
: BlackMisc::Simulation::CInterpolatorMulti::ModeLinear);
}
else if (callsign.isEmpty())
{
for (const auto &callsign : BlackMisc::makeKeysRange(BlackMisc::as_const(m_planesByCallsign)))
{
setInterpolatorMode(callsign, spline);
}
}
}
//! memcmp function which ignores the header ("size" member) and compares only the payload (the rest of the struct)
template <typename T>
int memcmpPayload(T *dst, T *src)
{
return std::memcmp(reinterpret_cast<char *>(dst) + sizeof(dst->size),
reinterpret_cast<char *>(src) + sizeof(src->size),
sizeof(*dst) - sizeof(dst->size));
}
int CTraffic::getPlaneData(void *id, int dataType, void *io_data)
{
auto plane = m_planesById.value(id, nullptr);
if (! plane) { return xpmpData_Unavailable; }
switch (dataType)
{
case xpmpDataType_Position:
{
BlackMisc::Simulation::CInterpolationAndRenderingSetup setup;
BlackMisc::Simulation::CInterpolationStatus status;
const auto situation = plane->interpolator.getInterpolatedSituation(-1, setup, plane->hints(), status);
if (! status.didInterpolationSucceed()) { return xpmpData_Unavailable; }
if (! status.hasChangedPosition()) { return xpmpData_Unchanged; }
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
const auto io_position = static_cast<XPMPPlanePosition_t *>(io_data);
io_position->lat = situation.latitude().value(CAngleUnit::deg());
io_position->lon = situation.longitude().value(CAngleUnit::deg());
io_position->elevation = situation.getAltitude().value(CLengthUnit::ft());
io_position->pitch = static_cast<float>(situation.getPitch().value(CAngleUnit::deg()));
io_position->roll = static_cast<float>(situation.getBank().value(CAngleUnit::deg()));
io_position->heading = static_cast<float>(situation.getHeading().value(CAngleUnit::deg()));
std::strncpy(io_position->label, plane->label, sizeof(plane->label)); // fixme don't need to copy on every frame
return xpmpData_NewData;
}
case xpmpDataType_Surfaces:
if (plane->hasSurfaces)
{
const auto currentTime = QDateTime::currentMSecsSinceEpoch();
while (! plane->pendingSurfaces.isEmpty() && plane->pendingSurfaces.constFirst().first <= currentTime)
{
//! \todo if gear is currently retracted, look ahead and pull gear position from pendingSurfaces up to 5 seconds in the future
plane->pendingSurfaces.constFirst().second(plane);
plane->pendingSurfaces.pop_front();
}
if (plane->surfaces.gearPosition != plane->targetGearPosition)
{
// interpolate gear position
constexpr float gearMoveTimeMs = 5000;
const auto gearPositionDiffRemaining = plane->targetGearPosition - plane->surfaces.gearPosition;
const auto gearPositionDiffThisFrame = (currentTime - plane->prevSurfacesLerpTime) / gearMoveTimeMs;
plane->surfaces.gearPosition += std::copysign(gearPositionDiffThisFrame, gearPositionDiffRemaining);
plane->surfaces.gearPosition = qBound(0.0f, plane->surfaces.gearPosition, 1.0f);
}
plane->prevSurfacesLerpTime = currentTime;
const auto io_surfaces = static_cast<XPMPPlaneSurfaces_t *>(io_data);
if (memcmpPayload(io_surfaces, &plane->surfaces))
{
std::memcpy(io_surfaces, &plane->surfaces, sizeof(*io_surfaces));
return xpmpData_NewData;
}
else { return xpmpData_Unchanged; }
}
case xpmpDataType_Radar:
if (plane->hasXpdr)
{
const auto io_xpdr = static_cast<XPMPPlaneRadar_t *>(io_data);
if (memcmpPayload(io_xpdr, &plane->xpdr))
{
std::memcpy(io_xpdr, &plane->xpdr, sizeof(*io_xpdr));
return xpmpData_NewData;
}
else { return xpmpData_Unchanged; }
}
else { return xpmpData_Unavailable; }
default: return xpmpData_Unavailable;
}
}
}
//! \endcond