refs #242, allows to change FSX cockpit from context

* Data definitions for FSX events
* BCD conversion for COM and transponder
* Update Cockpit method in context
* Renamed setOwnAircraft -> updateOwnAircraftFromSim
This commit is contained in:
Klaus Basan
2014-05-31 02:24:07 +02:00
parent ba217fed57
commit 035575870b
8 changed files with 194 additions and 26 deletions

View File

@@ -80,8 +80,15 @@ namespace BlackCore
} }
private slots: private slots:
//! \copydoc IContextSimulator::updateOwnAircraft() //! Update own aircraft, because simulator has changed something
virtual void updateOwnAircraft(); void updateOwnAircraft();
//! \copydoc ISimulator::addAircraftSituation
void addAircraftSituation(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &initialSituation);
//! Update cockpit from context, because someone else has changed cockpit (e.g. GUI, 3rd party)
//! \remarks set by runtime, only locally
void updateCockpitFromContext(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator);
//! Set new connection status //! Set new connection status
void setConnectionStatus(ISimulator::Status status); void setConnectionStatus(ISimulator::Status status);

View File

@@ -23,6 +23,7 @@ namespace BlackCore
class ISimulator : public QObject class ISimulator : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
//! \brief Simulator connection //! \brief Simulator connection
@@ -68,15 +69,15 @@ namespace BlackCore
//! Remove remote aircraft from simulator //! Remove remote aircraft from simulator
virtual void removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0; virtual void removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0;
//! Update own aircraft cockpit (usually from context)
virtual bool updateOwnCockpit(const BlackMisc::Aviation::CAircraft &aircraft) = 0;
//! Simulator info //! Simulator info
virtual BlackSim::CSimulatorInfo getSimulatorInfo() const = 0; virtual BlackSim::CSimulatorInfo getSimulatorInfo() const = 0;
signals: signals:
//! Emitted when the connection status has changed //! Emitted when the connection status has changed
void statusChanged(ISimulator::Status status); void statusChanged(ISimulator::Status status);
//! Emitted when new a new data object of the user aircraft is received
void ownAircraftReceived(BlackMisc::Aviation::CAircraft aircraft);
}; };
//! Factory pattern class to create instances of ISimulator //! Factory pattern class to create instances of ISimulator
@@ -100,6 +101,7 @@ namespace BlackCore
} // namespace BlackCore } // namespace BlackCore
// TODO: Use CProject to store this string
Q_DECLARE_INTERFACE(BlackCore::ISimulatorFactory, "net.vatsim.PilotClient.BlackCore.SimulatorInterface") Q_DECLARE_INTERFACE(BlackCore::ISimulatorFactory, "net.vatsim.PilotClient.BlackCore.SimulatorInterface")
#endif // guard #endif // guard

View File

@@ -0,0 +1,39 @@
#include "bcdconversions.h"
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
namespace BlackSim
{
namespace FsCommon
{
quint32 CBcdConversions::comFrequencyToBcdHz(const BlackMisc::PhysicalQuantities::CFrequency &comFrequency)
{
// FSX documentation is wrong, we need to use kHz + 2 digits, not Hz
quint32 f = comFrequency.valueRounded(CFrequencyUnit::kHz(), 0) / 10;
f = dec2Bcd(f);
return f;
}
quint32 CBcdConversions::transponderCodeToBcd(const BlackMisc::Aviation::CTransponder &transponder)
{
// FSX documentation is wrong, we need to use kHz + 2 digits, not Hz
quint32 t = transponder.getTransponderCode();
t = dec2Bcd(t);
return t;
}
quint32 CBcdConversions::hornerScheme(quint32 num, quint32 divider, quint32 factor)
{
quint32 remainder = 0, quotient = 0, result = 0;
remainder = num % divider;
quotient = num / divider;
if (!(quotient == 0 && remainder == 0))
result += hornerScheme(quotient, divider, factor) * factor + remainder;
return result;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,42 @@
#ifndef BLACKSIM_FSCOMMON_BCDCONVERSIONS_H
#define BLACKSIM_FSCOMMON_BCDCONVERSIONS_H
#include "blackmisc/pqfrequency.h"
#include "blackmisc/aviotransponder.h"
#include <QtGlobal>
namespace BlackSim
{
namespace FsCommon
{
/*!
* \brief BCD conversions for FS
*/
class CBcdConversions
{
public:
//! BCD -> decimal
static quint32 bcd2Dec(quint32 bcdNum) { return hornerScheme(bcdNum, 0x10, 10); }
//! Decimal -> BCD
static quint32 dec2Bcd(quint32 decNum) { return hornerScheme(decNum, 10, 0x10); }
//! COM Frequency to BCD
static quint32 comFrequencyToBcdHz(const BlackMisc::PhysicalQuantities::CFrequency &comFrequency);
//! Transponder code to BCD
static quint32 transponderCodeToBcd(const BlackMisc::Aviation::CTransponder &transponder);
private:
//! Constructor, only static methods
CBcdConversions() {}
//! Horner scheme
static quint32 hornerScheme(quint32 num, quint32 divider, quint32 factor);
};
}
}
#endif // guard

View File

@@ -20,6 +20,7 @@ namespace BlackSimPlugin
hr = initOwnAircraft(hSimConnect); hr = initOwnAircraft(hSimConnect);
hr = initRemoteAircraftSituation(hSimConnect); hr = initRemoteAircraftSituation(hSimConnect);
hr = initGearHandlePosition(hSimConnect); hr = initGearHandlePosition(hSimConnect);
hr = initSetCockpitEvents(hSimConnect);
return hr; return hr;
} }
@@ -39,7 +40,6 @@ namespace BlackSimPlugin
hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM ACTIVE FREQUENCY:2", "MHz"); hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM ACTIVE FREQUENCY:2", "MHz");
hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM STANDBY FREQUENCY:1", "MHz"); hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM STANDBY FREQUENCY:1", "MHz");
hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM STANDBY FREQUENCY:2", "MHz"); hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM STANDBY FREQUENCY:2", "MHz");
return hr; return hr;
} }
@@ -56,5 +56,16 @@ namespace BlackSimPlugin
hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataDefinitionGearHandlePosition, "GEAR HANDLE POSITION", "BOOL", SIMCONNECT_DATATYPE_INT32); hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataDefinitionGearHandlePosition, "GEAR HANDLE POSITION", "BOOL", SIMCONNECT_DATATYPE_INT32);
return hr; return hr;
} }
HRESULT CSimConnectDataDefinition::initSetCockpitEvents(const HANDLE hSimConnect) {
HRESULT hr = S_OK;
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EventSetCom1Active, "COM_RADIO_SET");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EventSetCom1Standby, "COM_STBY_RADIO_SET");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EventSetCom2Active, "COM2_RADIO_SET");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EventSetCom2Standby, "COM2_STBY_RADIO_SET");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EventSetTransponderCode, "XPNDR_SET");
return hr;
}
} }
} }

View File

@@ -63,8 +63,18 @@ namespace BlackSimPlugin
DataDefinitionGearHandlePosition DataDefinitionGearHandlePosition
}; };
//! \brief SimConnect request ID's //! SimConnect Event IDs
enum Requests { enum Events {
EventSetCom1Active = 100, // not overlapping with DataDefinition
EventSetCom2Active,
EventSetCom1Standby,
EventSetCom2Standby,
EventSetTransponderCode
};
//! SimConnect request IDs
enum Requests
{
RequestOwnAircraft = 1000, RequestOwnAircraft = 1000,
RequestRemoveAircraft = 2000 RequestRemoveAircraft = 2000
}; };
@@ -84,6 +94,10 @@ namespace BlackSimPlugin
//! Initialize data definition for remote aircraft configuration //! Initialize data definition for remote aircraft configuration
static HRESULT initGearHandlePosition(const HANDLE hSimConnect); static HRESULT initGearHandlePosition(const HANDLE hSimConnect);
//! Initialize events required setting cockpit values
static HRESULT initSetCockpitEvents(const HANDLE hSimConnect);
}; };
} }
} }

View File

@@ -5,9 +5,12 @@
#include "simulator_fsx.h" #include "simulator_fsx.h"
#include "simconnect_datadefinition.h" #include "simconnect_datadefinition.h"
#include "blacksim/fscommon/bcdconversions.h"
#include "blacksim/fsx/simconnectutilities.h" #include "blacksim/fsx/simconnectutilities.h"
#include "blacksim/fsx/fsxsimulatorsetup.h" #include "blacksim/fsx/fsxsimulatorsetup.h"
#include "blacksim/simulatorinfo.h" #include "blacksim/simulatorinfo.h"
#include "blackmisc/project.h"
#include <QTimer> #include <QTimer>
#include <QtConcurrent> #include <QtConcurrent>
@@ -15,6 +18,7 @@ using namespace BlackMisc::Aviation;
using namespace BlackMisc::PhysicalQuantities; using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Geo; using namespace BlackMisc::Geo;
using namespace BlackSim; using namespace BlackSim;
using namespace BlackSim::FsCommon;
using namespace BlackSim::Fsx; using namespace BlackSim::Fsx;
namespace BlackSimPlugin namespace BlackSimPlugin
@@ -57,10 +61,10 @@ namespace BlackSimPlugin
bool CSimulatorFsx::connectTo() bool CSimulatorFsx::connectTo()
{ {
if(m_isConnected) if (m_isConnected)
return true; return true;
if (FAILED(SimConnect_Open(&m_hSimConnect, "BlackBox", nullptr, 0, 0, 0))) if (FAILED(SimConnect_Open(&m_hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0)))
{ {
return false; return false;
} }
@@ -80,11 +84,10 @@ namespace BlackSimPlugin
auto asyncConnectFunc = [&]() -> bool auto asyncConnectFunc = [&]() -> bool
{ {
if (FAILED(SimConnect_Open(&m_hSimConnect, "BlackBox", nullptr, 0, 0, 0))) return false; if (FAILED(SimConnect_Open(&m_hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0))) return false;
return true; return true;
}; };
QFuture<bool> result = QtConcurrent::run( asyncConnectFunc ); QFuture<bool> result = QtConcurrent::run(asyncConnectFunc);
m_watcherConnect.setFuture(result); m_watcherConnect.setFuture(result);
} }
@@ -114,7 +117,7 @@ namespace BlackSimPlugin
if (m_isConnected) if (m_isConnected)
return true; return true;
if (FAILED(SimConnect_Open(&m_hSimConnect, "BlackBox", nullptr, 0, 0, 0))) if (FAILED(SimConnect_Open(&m_hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0)))
{ {
return false; return false;
} }
@@ -172,6 +175,53 @@ namespace BlackSimPlugin
return this->m_simulatorInfo; return this->m_simulatorInfo;
} }
bool CSimulatorFsx::updateOwnCockpit(const CAircraft &ownAircraft)
{
CComSystem newCom1 = ownAircraft.getCom1System();
CComSystem newCom2 = ownAircraft.getCom2System();
CTransponder newTransponder = ownAircraft.getTransponder();
bool changed = false;
if (newCom1 != this->m_ownAircraft.getCom1System())
{
if (newCom1.getFrequencyActive() != this->m_ownAircraft.getCom1System().getFrequencyActive())
SimConnect_TransmitClientEvent(m_hSimConnect, 0, CSimConnectDataDefinition::EventSetCom1Active,
CBcdConversions::comFrequencyToBcdHz(newCom1.getFrequencyActive()), SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
if (newCom1.getFrequencyStandby() != this->m_ownAircraft.getCom1System().getFrequencyStandby())
SimConnect_TransmitClientEvent(m_hSimConnect, 0, CSimConnectDataDefinition::EventSetCom1Standby,
CBcdConversions::comFrequencyToBcdHz(newCom1.getFrequencyStandby()), SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
this->m_ownAircraft.setCom1System(newCom1);
changed = true;
}
if (newCom2 != this->m_ownAircraft.getCom2System())
{
if (newCom2.getFrequencyActive() != this->m_ownAircraft.getCom2System().getFrequencyActive())
SimConnect_TransmitClientEvent(m_hSimConnect, 0, CSimConnectDataDefinition::EventSetCom2Active,
CBcdConversions::comFrequencyToBcdHz(newCom2.getFrequencyActive()), SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
if (newCom2.getFrequencyStandby() != this->m_ownAircraft.getCom2System().getFrequencyStandby())
SimConnect_TransmitClientEvent(m_hSimConnect, 0, CSimConnectDataDefinition::EventSetCom2Standby,
CBcdConversions::comFrequencyToBcdHz(newCom2.getFrequencyStandby()), SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
this->m_ownAircraft.setCom2System(newCom1);
changed = true;
}
if (newTransponder != this->m_ownAircraft.getTransponder())
{
if (newTransponder.getTransponderCode() != this->m_ownAircraft.getTransponder().getTransponderCode())
{
SimConnect_TransmitClientEvent(m_hSimConnect, 0, CSimConnectDataDefinition::EventSetTransponderCode,
CBcdConversions::transponderCodeToBcd(newTransponder), SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
changed = true;
}
this->m_ownAircraft.setTransponder(newTransponder);
}
return changed;
}
void CALLBACK CSimulatorFsx::SimConnectProc(SIMCONNECT_RECV *pData, DWORD /* cbData */, void *pContext) void CALLBACK CSimulatorFsx::SimConnectProc(SIMCONNECT_RECV *pData, DWORD /* cbData */, void *pContext)
{ {
CSimulatorFsx *simulatorFsx = static_cast<CSimulatorFsx *>(pContext); CSimulatorFsx *simulatorFsx = static_cast<CSimulatorFsx *>(pContext);
@@ -217,23 +267,24 @@ namespace BlackSimPlugin
else if (event->uEventID == EVENT_OBJECT_REMOVED) else if (event->uEventID == EVENT_OBJECT_REMOVED)
{ {
} }
break; break;
} }
case SIMCONNECT_RECV_ID_EVENT_FRAME: case SIMCONNECT_RECV_ID_EVENT_FRAME:
{ {
SIMCONNECT_RECV_EVENT_FRAME *event = (SIMCONNECT_RECV_EVENT_FRAME *) pData; SIMCONNECT_RECV_EVENT_FRAME *event = (SIMCONNECT_RECV_EVENT_FRAME *) pData;
switch(event->uEventID) switch (event->uEventID)
{ {
case EVENT_FRAME: case EVENT_FRAME:
simulatorFsx->onSimFrame(); simulatorFsx->onSimFrame();
break; break;
} }
break;
} }
case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID: case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID:
{ {
SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData); SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData);
simulatorFsx->setSimconnectObjectID(event->dwRequestID, event->dwObjectID); simulatorFsx->setSimconnectObjectID(event->dwRequestID, event->dwObjectID);
break;
} }
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
{ {
@@ -243,12 +294,11 @@ namespace BlackSimPlugin
case CSimConnectDataDefinition::RequestOwnAircraft: case CSimConnectDataDefinition::RequestOwnAircraft:
DataDefinitionOwnAircraft *ownAircaft; DataDefinitionOwnAircraft *ownAircaft;
ownAircaft = (DataDefinitionOwnAircraft *)&pObjData->dwData; ownAircaft = (DataDefinitionOwnAircraft *)&pObjData->dwData;
simulatorFsx->setOwnAircraft(*ownAircaft); simulatorFsx->updateOwnAircraftFromSim(*ownAircaft);
break; break;
} }
break; break;
} }
} }
} }
@@ -275,7 +325,7 @@ namespace BlackSimPlugin
} }
void CSimulatorFsx::setOwnAircraft(DataDefinitionOwnAircraft aircraft) void CSimulatorFsx::updateOwnAircraftFromSim(DataDefinitionOwnAircraft aircraft)
{ {
BlackMisc::Geo::CCoordinateGeodetic position; BlackMisc::Geo::CCoordinateGeodetic position;
position.setLatitude(CLatitude(aircraft.latitude, CAngleUnit::deg())); position.setLatitude(CLatitude(aircraft.latitude, CAngleUnit::deg()));
@@ -358,7 +408,7 @@ namespace BlackSimPlugin
} }
else else
emit statusChanged(ConnectionFailed); emit statusChanged(ConnectionFailed);
} }
void CSimulatorFsx::removeRemoteAircraft(const CSimConnectObject &simObject) void CSimulatorFsx::removeRemoteAircraft(const CSimConnectObject &simObject)
{ {
@@ -404,6 +454,8 @@ namespace BlackSimPlugin
position.Bank = situation.getBank().value(); position.Bank = situation.getBank().value();
position.Heading = situation.getHeading().value(CAngleUnit::deg()); position.Heading = situation.getHeading().value(CAngleUnit::deg());
position.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts()); position.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts());
// TODO: epic fail for helicopters and VTOPs!
position.OnGround = position.Airspeed < 30 ? 1 : 0; position.OnGround = position.Airspeed < 30 ? 1 : 0;
DataDefinitionRemoteAircraftSituation ddAircraftSituation; DataDefinitionRemoteAircraftSituation ddAircraftSituation;

View File

@@ -31,6 +31,7 @@ namespace BlackSimPlugin
class Q_DECL_EXPORT CSimulatorFsxFactory : public QObject, public BlackCore::ISimulatorFactory class Q_DECL_EXPORT CSimulatorFsxFactory : public QObject, public BlackCore::ISimulatorFactory
{ {
Q_OBJECT Q_OBJECT
// TODO: @RW, move this string into CProject please
Q_PLUGIN_METADATA(IID "net.vatsim.PilotClient.BlackCore.SimulatorInterface") Q_PLUGIN_METADATA(IID "net.vatsim.PilotClient.BlackCore.SimulatorInterface")
Q_INTERFACES(BlackCore::ISimulatorFactory) Q_INTERFACES(BlackCore::ISimulatorFactory)
@@ -100,6 +101,9 @@ namespace BlackSimPlugin
//! \copydoc ISimulator::getSimulatorInfo() //! \copydoc ISimulator::getSimulatorInfo()
virtual BlackSim::CSimulatorInfo getSimulatorInfo() const override; virtual BlackSim::CSimulatorInfo getSimulatorInfo() const override;
//! \copydoc ISimulator::updateOwnCockpit
virtual bool updateOwnCockpit(const BlackMisc::Aviation::CAircraft &ownAircraft) override;
//! \brief Called when sim has started //! \brief Called when sim has started
void onSimRunning(); void onSimRunning();
@@ -109,11 +113,8 @@ namespace BlackSimPlugin
//! \brief Slot called every visual frame //! \brief Slot called every visual frame
void onSimFrame(); void onSimFrame();
/*! //! Called when data about our own aircraft is received
* \brief Called when data about our own aircraft is received void updateOwnAircraftFromSim(DataDefinitionOwnAircraft aircraft);
* \param aircraft
*/
void setOwnAircraft(DataDefinitionOwnAircraft aircraft);
/*! /*!
* \brief Set ID of a SimConnect object * \brief Set ID of a SimConnect object