From 035575870b577011c10206f25fc61647b1c773e1 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sat, 31 May 2014 02:24:07 +0200 Subject: [PATCH] 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 --- src/blackcore/context_simulator_impl.h | 11 ++- src/blackcore/simulator.h | 8 +- src/blacksim/fscommon/bcdconversions.cpp | 39 ++++++++++ src/blacksim/fscommon/bcdconversions.h | 42 ++++++++++ .../fsx/simconnect_datadefinition.cpp | 13 +++- .../simulator/fsx/simconnect_datadefinition.h | 18 ++++- src/plugins/simulator/fsx/simulator_fsx.cpp | 78 +++++++++++++++---- src/plugins/simulator/fsx/simulator_fsx.h | 11 +-- 8 files changed, 194 insertions(+), 26 deletions(-) create mode 100644 src/blacksim/fscommon/bcdconversions.cpp create mode 100644 src/blacksim/fscommon/bcdconversions.h diff --git a/src/blackcore/context_simulator_impl.h b/src/blackcore/context_simulator_impl.h index 79f70b3be..e934eb81f 100644 --- a/src/blackcore/context_simulator_impl.h +++ b/src/blackcore/context_simulator_impl.h @@ -80,8 +80,15 @@ namespace BlackCore } private slots: - //! \copydoc IContextSimulator::updateOwnAircraft() - virtual void updateOwnAircraft(); + //! Update own aircraft, because simulator has changed something + 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 void setConnectionStatus(ISimulator::Status status); diff --git a/src/blackcore/simulator.h b/src/blackcore/simulator.h index dbc417bef..a8578f956 100644 --- a/src/blackcore/simulator.h +++ b/src/blackcore/simulator.h @@ -23,6 +23,7 @@ namespace BlackCore class ISimulator : public QObject { Q_OBJECT + public: //! \brief Simulator connection @@ -68,15 +69,15 @@ namespace BlackCore //! Remove remote aircraft from simulator 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 virtual BlackSim::CSimulatorInfo getSimulatorInfo() const = 0; signals: //! Emitted when the connection status has changed 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 @@ -100,6 +101,7 @@ namespace BlackCore } // namespace BlackCore +// TODO: Use CProject to store this string Q_DECLARE_INTERFACE(BlackCore::ISimulatorFactory, "net.vatsim.PilotClient.BlackCore.SimulatorInterface") #endif // guard diff --git a/src/blacksim/fscommon/bcdconversions.cpp b/src/blacksim/fscommon/bcdconversions.cpp new file mode 100644 index 000000000..79ca2bd89 --- /dev/null +++ b/src/blacksim/fscommon/bcdconversions.cpp @@ -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 diff --git a/src/blacksim/fscommon/bcdconversions.h b/src/blacksim/fscommon/bcdconversions.h new file mode 100644 index 000000000..098f20f35 --- /dev/null +++ b/src/blacksim/fscommon/bcdconversions.h @@ -0,0 +1,42 @@ +#ifndef BLACKSIM_FSCOMMON_BCDCONVERSIONS_H +#define BLACKSIM_FSCOMMON_BCDCONVERSIONS_H + +#include "blackmisc/pqfrequency.h" +#include "blackmisc/aviotransponder.h" +#include + +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 diff --git a/src/plugins/simulator/fsx/simconnect_datadefinition.cpp b/src/plugins/simulator/fsx/simconnect_datadefinition.cpp index 0aac761da..a941bfd86 100644 --- a/src/plugins/simulator/fsx/simconnect_datadefinition.cpp +++ b/src/plugins/simulator/fsx/simconnect_datadefinition.cpp @@ -20,6 +20,7 @@ namespace BlackSimPlugin hr = initOwnAircraft(hSimConnect); hr = initRemoteAircraftSituation(hSimConnect); hr = initGearHandlePosition(hSimConnect); + hr = initSetCockpitEvents(hSimConnect); 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 STANDBY FREQUENCY:1", "MHz"); hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataOwnAircraft, "COM STANDBY FREQUENCY:2", "MHz"); - return hr; } @@ -56,5 +56,16 @@ namespace BlackSimPlugin hr = SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDataDefinition::DataDefinitionGearHandlePosition, "GEAR HANDLE POSITION", "BOOL", SIMCONNECT_DATATYPE_INT32); 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; + } } } diff --git a/src/plugins/simulator/fsx/simconnect_datadefinition.h b/src/plugins/simulator/fsx/simconnect_datadefinition.h index 67d32d10d..1c0758b0b 100644 --- a/src/plugins/simulator/fsx/simconnect_datadefinition.h +++ b/src/plugins/simulator/fsx/simconnect_datadefinition.h @@ -63,8 +63,18 @@ namespace BlackSimPlugin DataDefinitionGearHandlePosition }; - //! \brief SimConnect request ID's - enum Requests { + //! SimConnect Event IDs + enum Events { + EventSetCom1Active = 100, // not overlapping with DataDefinition + EventSetCom2Active, + EventSetCom1Standby, + EventSetCom2Standby, + EventSetTransponderCode + }; + + //! SimConnect request IDs + enum Requests + { RequestOwnAircraft = 1000, RequestRemoveAircraft = 2000 }; @@ -84,6 +94,10 @@ namespace BlackSimPlugin //! Initialize data definition for remote aircraft configuration static HRESULT initGearHandlePosition(const HANDLE hSimConnect); + + //! Initialize events required setting cockpit values + static HRESULT initSetCockpitEvents(const HANDLE hSimConnect); + }; } } diff --git a/src/plugins/simulator/fsx/simulator_fsx.cpp b/src/plugins/simulator/fsx/simulator_fsx.cpp index fa91eebeb..45cae5073 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.cpp +++ b/src/plugins/simulator/fsx/simulator_fsx.cpp @@ -5,9 +5,12 @@ #include "simulator_fsx.h" #include "simconnect_datadefinition.h" +#include "blacksim/fscommon/bcdconversions.h" #include "blacksim/fsx/simconnectutilities.h" #include "blacksim/fsx/fsxsimulatorsetup.h" #include "blacksim/simulatorinfo.h" +#include "blackmisc/project.h" + #include #include @@ -15,6 +18,7 @@ using namespace BlackMisc::Aviation; using namespace BlackMisc::PhysicalQuantities; using namespace BlackMisc::Geo; using namespace BlackSim; +using namespace BlackSim::FsCommon; using namespace BlackSim::Fsx; namespace BlackSimPlugin @@ -57,10 +61,10 @@ namespace BlackSimPlugin bool CSimulatorFsx::connectTo() { - if(m_isConnected) + if (m_isConnected) 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; } @@ -80,11 +84,10 @@ namespace BlackSimPlugin 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; }; - QFuture result = QtConcurrent::run( asyncConnectFunc ); + QFuture result = QtConcurrent::run(asyncConnectFunc); m_watcherConnect.setFuture(result); } @@ -114,7 +117,7 @@ namespace BlackSimPlugin if (m_isConnected) 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; } @@ -172,6 +175,53 @@ namespace BlackSimPlugin 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) { CSimulatorFsx *simulatorFsx = static_cast(pContext); @@ -217,23 +267,24 @@ namespace BlackSimPlugin else if (event->uEventID == EVENT_OBJECT_REMOVED) { } - break; } case SIMCONNECT_RECV_ID_EVENT_FRAME: { SIMCONNECT_RECV_EVENT_FRAME *event = (SIMCONNECT_RECV_EVENT_FRAME *) pData; - switch(event->uEventID) + switch (event->uEventID) { case EVENT_FRAME: simulatorFsx->onSimFrame(); break; } + break; } case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID: { SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast(pData); simulatorFsx->setSimconnectObjectID(event->dwRequestID, event->dwObjectID); + break; } case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: { @@ -243,12 +294,11 @@ namespace BlackSimPlugin case CSimConnectDataDefinition::RequestOwnAircraft: DataDefinitionOwnAircraft *ownAircaft; ownAircaft = (DataDefinitionOwnAircraft *)&pObjData->dwData; - simulatorFsx->setOwnAircraft(*ownAircaft); + simulatorFsx->updateOwnAircraftFromSim(*ownAircaft); break; } break; } - } } @@ -275,7 +325,7 @@ namespace BlackSimPlugin } - void CSimulatorFsx::setOwnAircraft(DataDefinitionOwnAircraft aircraft) + void CSimulatorFsx::updateOwnAircraftFromSim(DataDefinitionOwnAircraft aircraft) { BlackMisc::Geo::CCoordinateGeodetic position; position.setLatitude(CLatitude(aircraft.latitude, CAngleUnit::deg())); @@ -358,8 +408,8 @@ namespace BlackSimPlugin } else emit statusChanged(ConnectionFailed); - } - + } + void CSimulatorFsx::removeRemoteAircraft(const CSimConnectObject &simObject) { SimConnect_AIRemoveObject(m_hSimConnect, simObject.getObjectId(), simObject.getRequestId()); @@ -404,6 +454,8 @@ namespace BlackSimPlugin position.Bank = situation.getBank().value(); position.Heading = situation.getHeading().value(CAngleUnit::deg()); position.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts()); + + // TODO: epic fail for helicopters and VTOPs! position.OnGround = position.Airspeed < 30 ? 1 : 0; DataDefinitionRemoteAircraftSituation ddAircraftSituation; diff --git a/src/plugins/simulator/fsx/simulator_fsx.h b/src/plugins/simulator/fsx/simulator_fsx.h index 8a948748f..3922c87b6 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.h +++ b/src/plugins/simulator/fsx/simulator_fsx.h @@ -31,6 +31,7 @@ namespace BlackSimPlugin class Q_DECL_EXPORT CSimulatorFsxFactory : public QObject, public BlackCore::ISimulatorFactory { Q_OBJECT + // TODO: @RW, move this string into CProject please Q_PLUGIN_METADATA(IID "net.vatsim.PilotClient.BlackCore.SimulatorInterface") Q_INTERFACES(BlackCore::ISimulatorFactory) @@ -100,6 +101,9 @@ namespace BlackSimPlugin //! \copydoc ISimulator::getSimulatorInfo() virtual BlackSim::CSimulatorInfo getSimulatorInfo() const override; + //! \copydoc ISimulator::updateOwnCockpit + virtual bool updateOwnCockpit(const BlackMisc::Aviation::CAircraft &ownAircraft) override; + //! \brief Called when sim has started void onSimRunning(); @@ -109,11 +113,8 @@ namespace BlackSimPlugin //! \brief Slot called every visual frame void onSimFrame(); - /*! - * \brief Called when data about our own aircraft is received - * \param aircraft - */ - void setOwnAircraft(DataDefinitionOwnAircraft aircraft); + //! Called when data about our own aircraft is received + void updateOwnAircraftFromSim(DataDefinitionOwnAircraft aircraft); /*! * \brief Set ID of a SimConnect object