Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+154
View File
@@ -0,0 +1,154 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(xml_FILE gna_service.xml)
#
# --- Library svcGnaCommon --------------------------------------------------------------------------------
#
SET(SRCS_common
gna_export.h
logger.cpp
logger.h
)
# Generate gna_enums.idl / gna.idl
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
# Generate gna_db_impl.cpp/.h, gna_db.h
CODEGEN_DATABASE(SRCS_common ${xml_FILE})
# Generate *.cpp/*.hpp from idl
RTIDDSGEN(SRCS_common gna_enums.idl)
RTIDDSGEN(SRCS_common gna.idl)
# Generate gna_dt[s,c]_types.h, gna_ft[s,c]_types.h
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
# generate gna_[d|f]tc.h
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
NGL_ADD_LIBRARY(AAR SV WS svcGnaCommon SHARED ${SRCS_common})
NGL_TARGET_INCLUDE_DIRECTORIES(svcGnaCommon
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(svcGnaCommon
PRIVATE
RTI::nddscpp2
PUBLIC
Qt5::Core
ngldb
ddscore
NGLLogger
)
NGL_INSTALL_TARGET(svcGnaCommon)
#
# --- Library svcGnaClient --------------------------------------------------------------------------------
#
SET(SRCS_client
gna_export.h
)
# generate gna_[d|f]tc_impl.[cpp|h]
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE})
NGL_ADD_LIBRARY(AAR SV WS svcGnaClient SHARED ${SRCS_client})
NGL_TARGET_INCLUDE_DIRECTORIES(svcGnaClient
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(svcGnaClient
PRIVATE
RTI::nddscpp2
ddsconnector
PUBLIC
svcGnaCommon
ddsftc
)
NGL_INSTALL_TARGET(svcGnaClient)
#
# --- Library svcGnaServer -------------------------------------------------
#
SET(SRCS_server
abstract_socket_handler.cpp
abstract_socket_handler.h
dds_handler.cpp
dds_handler.h
gna_export.h
guez_nasat_telegrams.cpp
guez_nasat_telegrams.h
initialization.cpp
initialization.h
handler_nasat_aircraft.cpp
handler_nasat_aircraft.h
handler_nasat_aircraft_participant.cpp
handler_nasat_aircraft_participant.h
handler_nasat_impact.cpp
handler_nasat_impact.h
handler_nasat_nine_liner.cpp
handler_nasat_nine_liner.h
handler_participant.cpp
handler_participant.h
settings.cpp
settings.h
tcp_socket_handler.cpp
tcp_socket_handler.h
web_socket_handler.cpp
web_socket_handler.h
${xml_FILE}
)
# generate gna_[d|f]ts.h, gna_[d|f]ts_impl.[cpp|h]
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE})
# Generate gna.sql, gna.xml
CODEGEN_SQL(SRCS_server ${xml_FILE})
NGL_ADD_LIBRARY(AAR SV svcGnaServer SHARED ${SRCS_server})
NGL_TARGET_LINK_LIBRARIES(svcGnaServer
PRIVATE
ddsfts
Qt5::Core
Qt5::Network
Qt5::WebSockets
LtsCoordTrans
NGLLogger
nglsettings
ngltools
svcExmClient
svcGnaCommon
svcAesClient
svcPdmClient
svcPpmClient
svcTabServer
PUBLIC
ddsconnector
ngldb
)
NGL_TARGET_INCLUDE_DIRECTORIES(svcGnaServer
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_INSTALL_TARGET(svcGnaServer)
#
# --- Topic Type Plugin --------------------------------------------------------------
#
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
#
# --- RecordReplayPlugin --------------------------------------------------------------
#
CREATE_RECORD_REPLAY_PLUGIN(${xml_FILE} _srcs_not_needed)
# Uncomment if necessary
#ADD_SUBDIRECTORY(UnitTests)
#ADD_SUBDIRECTORY(ModuleTests)
+177
View File
@@ -0,0 +1,177 @@
------------------------------------------------------------------------------------
$Id$
$HeadURL$
$Author$
------------------------------------------------------------------------------------
LOGGER:
Log-File: ctc_mdm.log
------------------------------------------------------------------------------------
NLDEVCTRL-844: NASAT: Weiterleitung der Luftunterstützung sporadisch ausser Funktion
------------------------------------------------------------------------------------
##########################################################################################
## ##
## Das hier geschilderte Phänomen sollte seit dem FTC Umbau nicht mehr auftreten! -MW ##
## ##
##########################################################################################
NASAT-Telegramme von Flugzeug sind:
1) position
-> TrainingAreaBase::Interface::Dts::publish(pos);
2) NineLiner
-> GuezNasat::Interface::Dts::publish(nl);
3) WeaponRelease
-> AreaEffectSimulation::Interface::Ftc::airSupportImpactModifyRequest(req, handler);
Auffällig ist, das nur 3) sporadisch hängen blieb.
Unterschiede:
Für 1) und 2) gilt:
- Dts DataTopic
- erfordern KEINE Antwort
- sind übergeordnet (TAB, GNA)
Für 3) gilt:
- Fts FunctionTopic
- erfordert eine Antwort (2. Parameter)
- muss in mehrere Exercises gesendet werden.
- In der Ausgangslage existiert ein NasatAircraftParticpant pro ex _> 2 Stück;
=> es werden in 2 WORKER-Threads quasi zeitgleich 'new connext::Requester' aufgerufen, also Requester erstellt.
Fazit:
- Das Öffnen des WebSockets für eingehende Telegramm wird um 30Sec verzögert, damit
sich GNA erstmal richtig initialisieren kann. Damit ist die Eintrittswahrscheinlichkeit des Hängers
wohl reduziert, aber nicht null - schade.
- Ein try catch im WorkerThread von generic_ftc_impl.h brachte keine Erkenntnis
- Warum 'new connext::Requester' hängen bleibt? Leider keine Erkenntnis
-> 'new connext::Requester' in mainThread verschieben (vorziehen, nicht gleichzeitig)
------------------------------------------------------------------------------------
Durch Provzieren (unter Zuhilfenahme von nasat_simulator.py, ./simulate_weapon_release.sh) ergab sich:
Zwei exercises (35, 42) ; jeweils ein NasatAircraftParticpant:
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] GNA::WebSocketHandler |#| incoming telegram: {"type": "NasatWeaponRelease", "data": {"releaseMode": 0, "munition": 2, "timestamp": 1612363838.368936, "fuseType": 1, "impactPosition": {"lat": 53.061, "lon": 8.9711}, "aircraftId": 1, "flightTime": 5.1234}, "uuid": "NasatWeaponRelease-UUID"} (/Lts/Proxies/GuezNasat/abstract_socket_handler.cpp:53)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| void GuezNasat::HandlerNasatImpact::nasatImpact(int, const Core::GeoPosition&, qint64, int, int) START, nasatId=1, pos=[[lon: 0.156575232525663, lat: 0.926089154400711]z: 0], impactTimeMsec=1612363843492 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:59)
EX_42 this=0x2c43570
Request wird vom mainThread per std::queue<Request> m_requests an den WorkerThread (WT) übergeben
WT nimmt den Req auf und erzeugt 'WHILE LOOP.. new connext::Requester..., this=0x2c43570'
danach ist von dem Thread nicht mehr zu sehen :-(
EX_35
Request wird vom mainThread per std::queue<Request> m_requests an den WorkerThread (WT) übergeben
WT nimmt den Req auf und erzeugt 'WHILE LOOP.. new connext::Requester..., this=0x2c45380'
Danach sehen wir 3 mal '#sendRequest:...
Nachdem die whileLoop von vorn beginnt, ist die queue leer und der Thread endet:
'No more requests -> leaving thread, this=0x2c45380'
:-)
Ca. 30 Sek. später (so das shell script) wird erneut eine NasatWeaponRelease gesendet, dies wird dann für EX_42 aber nur noch in die queue gesteckt... Es hängt :-(
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Sending air support impact: number of participant= 2 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:81)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| Qos for dataReader: (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:234)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| resourceLimit.max_samples 8000 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:235)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| policy dds.data_reader.history.memory_manager.fast_pool.pool_buffer_max_size: 2048 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:255)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| Default Qos for dataWriter: (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:242)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| ReliabilityKind: 1 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:243)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| Publish mode: 1 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:244)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| policy dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size: 2048 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:255)
2021-02-03 15:50:38.369 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| => Static request using request/reply topic names: LTS_AirSupportImpactModifyRequest, reply: LTS_AirSupportImpactModifyReply (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:96)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=0, this=0x2c43570, threadId=139905918381760, m_terminate=0 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:157)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData - fill m_requests and start new thread., this=0x2c43570, threadId=139905918381760, m_requests=0x2c43f68, m_requests.size()=0), request.uniqueId=1 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:189)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=1, this=0x2c43570, threadId=139905918381760, m_terminate=0 done (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:200)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Sending air support impact create request: [id: 0, name: NASAT_1_2_03 15:50:38, effectStart: 1612363843492, chargeTypeId: 472, impactPosition: [lon: 0.156575232525663, lat: 0.926089154400711], partyId: 3, participantId: 90, flightTime: 5123, externalId: null] to exercise 42, nap=[id: 1, nasatAircraftId: 1, exerciseId: 42, participantId: 90] -> success = 1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:88)
2021-02-03 15:50:38.370 INFO [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| requestCounter = 1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:97)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| Qos for dataReader: (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:234)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| resourceLimit.max_samples 8000 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:235)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| policy dds.data_reader.history.memory_manager.fast_pool.pool_buffer_max_size: 2048 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:255)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| Default Qos for dataWriter: (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:242)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| ReliabilityKind: 1 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:243)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| Publish mode: 1 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:244)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| policy dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size: 2048 (S/TDS-source/Lts/DDS/QosProfile/DDS_DefaultQos.cpp:255)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| => Static request using request/reply topic names: LTS_AirSupportImpactModifyRequest, reply: LTS_AirSupportImpactModifyReply (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:96)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=0, this=0x2c45380, threadId=139905918381760, m_terminate=0 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:157)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData - fill m_requests and start new thread., this=0x2c45380, threadId=139905918381760, m_requests=0x2c45d78, m_requests.size()=0), request.uniqueId=1 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:189)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=1, this=0x2c45380, threadId=139905918381760, m_terminate=0 done (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:200)
2021-02-03 15:50:38.370 DEBUG [0x00007f3da4000f20] DDS::FTC::AirSupportImpactModify |#| START WHILE LOOP.., this=0x2c43570, threadId=139902809986816, m_requests=0x2c43f68, m_requests.size()=1 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:225)
2021-02-03 15:50:38.370 DEBUG [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| START WHILE LOOP.., this=0x2c45380, threadId=139902801594112, m_requests=0x2c45d78, m_requests.size()=1 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:225)
2021-02-03 15:50:38.370 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Sending air support impact create request: [id: 0, name: NASAT_1_2_03 15:50:38, effectStart: 1612363843492, chargeTypeId: 472, impactPosition: [lon: 0.156575232525663, lat: 0.926089154400711], partyId: 3, participantId: 62, flightTime: 5123, externalId: null] to exercise 35, nap=[id: 8, nasatAircraftId: 1, exerciseId: 35, participantId: 62] -> success = 1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:88)
2021-02-03 15:50:38.370 DEBUG [0x00007f3da4000f20] DDS::FTC::AirSupportImpactModify |#| IN waitForEvents, this=0x2c43570, request.uniqueId=1, threadId=139902809986816 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:245)
2021-02-03 15:50:38.370 DEBUG [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| IN waitForEvents, this=0x2c45380, request.uniqueId=1, threadId=139902801594112 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:245)
2021-02-03 15:50:38.370 INFO [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| requestCounter = 2 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:97)
lazy init von connext::Requester, (noch) im jeweiligen WORKER-Thread:
2021-02-03 15:50:38.370 DEBUG [0x00007f3da4000f20] DDS::FTC::AirSupportImpactModify |#| WHILE LOOP.. new connext::Requester..., this=0x2c43570, request.uniqueId=1, threadId=139902809986816 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:254)
2021-02-03 15:50:38.371 DEBUG [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| WHILE LOOP.. new connext::Requester..., this=0x2c45380, request.uniqueId=1, threadId=139902801594112 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:254)
2021-02-03 15:50:38.371 FATAL [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| bOk= 1, requestCounter = 2, replyCounter = 0 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:102)
2021-02-03 15:50:38.371 DEBUG [0x0000000001dfc6f0] GNA::WebSocketHandler |#| Websocket connection closed, ptr: 0x2c1ba10 (ource/Lts/Proxies/GuezNasat/web_socket_handler.cpp:155)
2021-02-03 15:50:38.371 DEBUG [0x00007f3d9c000f20] connext::requester |#| connext::Requester<REQUEST, REPLY>::Requester(const connext::RequesterParams&) [with REQUEST = AreaEffectSimulation::AirSupportImpactModifyRequest; REPLY = Core::FunctionReply] START (-source/Lts/DDS/QosProfile/../../DDS/FTS/connext.h:292)
2021-02-03 15:50:38.371 DEBUG [0x00007f3d9c000f20] connext::requester |#| connext::Requester<REQUEST, REPLY>::Requester(const connext::RequesterParams&) [with REQUEST = AreaEffectSimulation::AirSupportImpactModifyRequest; REPLY = Core::FunctionReply] END (-source/Lts/DDS/QosProfile/../../DDS/FTS/connext.h:293)
2021-02-03 15:50:38.371 INFO [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| #sendRequest: SeqNumber: -1, this=0x2c45380, request.uniqueId=1, threadId=139902801594112 ... (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:261)
2021-02-03 15:50:38.373 DEBUG [0x00007f3d9c000f20] connext::requester |#| content filter for topic LTS_AirSupportImpactModifyRequest - related_sample_identity should be: 0101aaeead199ead8d523da780006303 (-source/Lts/DDS/QosProfile/../../DDS/FTS/connext.h:322)
2021-02-03 15:50:38.373 DEBUG [0x00007f3d9c000f20] connext::requester |#| send_request for topic LTS_AirSupportImpactModifyRequest, m_currentSampleIdentity: SeqNo: 1, Guid-DW: 0101aaeead199ead8d523da780006303 (-source/Lts/DDS/QosProfile/../../DDS/FTS/connext.h:359)
2021-02-03 15:50:38.373 INFO [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| #sendRequest: SeqNumber: 1, this=0x2c45380, request.uniqueId=1, threadId=139902801594112 ... done (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:268)
2021-02-03 15:50:38.373 DEBUG [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| Waiting for reply (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:331)
2021-02-03 15:50:38.373 DEBUG [0x000000000232ee10] DDS::DTC::SubscriberListener |#| on_liveliness_changed: 1, 0, 1, 0 for type Core::FunctionReply (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:130)
2021-02-03 15:50:38.399 DEBUG [0x0000000002413aa0] DDS::DTC::SubscriberListener |#| Data available for LTS_AirSupportImpactModifyReply 0101aaeead199ead8d523da780006303, type Core::FunctionReply, this 0x1ece220 (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:99)
2021-02-03 15:50:38.400 DEBUG [0x00007f3d9c000f20] connext::requester |#| receive_reply for topic LTS_AirSupportImpactModifyRequest, SampleIdentity - original publication virtual: SeqNo: 30, Guid-DW: 0101c38b58f3acefce8ec8c480000003 (-source/Lts/DDS/QosProfile/../../DDS/FTS/connext.h:379)
2021-02-03 15:50:38.400 DEBUG [0x00007f3d9c000f20] connext::requester |#| receive_reply for topic LTS_AirSupportImpactModifyRequest, SampleIdentity - related original: SeqNo: 1, Guid-DW: 0101aaeead199ead8d523da780006303 (-source/Lts/DDS/QosProfile/../../DDS/FTS/connext.h:384)
2021-02-03 15:50:38.400 INFO [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| #receiveReply for AreaEffectSimulation::AirSupportImpactModifyReply (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:362)
2021-02-03 15:50:38.400 INFO [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| #sendRequest: SeqNumber: 1, this=0x2c45380, request.uniqueId=1, threadId=139902801594112 ... getRequestedData done (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:279)
2021-02-03 15:50:38.400 INFO [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Got create reply: (id=291), this=0x2aa18f0 - replyCounter=1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:39)
2021-02-03 15:50:38.400 DEBUG [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| START WHILE LOOP.., this=0x2c45380, threadId=139902801594112, m_requests=0x2c45d78, m_requests.size()=0 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:225)
2021-02-03 15:50:38.400 DEBUG [0x00007f3d9c000f20] DDS::FTC::AirSupportImpactModify |#| No more requests -> leaving thread, this=0x2c45380, threadId=139902801594112 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:237)
2021-02-03 15:50:38.404 DEBUG [0x00000000024dbc40] DDS::DTS::Core::CurrentRunningState |#| IN write (Core::CurrentRunningState) (urce/Lts/DDS/Core/../../DDS/DTS/generic_dts_impl.h:44)
2021-02-03 15:50:38.404 DEBUG [0x00000000024dbc40] DDS::DataWriter::Core::CurrentRunningState |#| IN write (Core::CurrentRunningState) (s/DDS/Core/../../DDS/Generic/generic_data_writer.h:102)
2021-02-03 15:50:38.404 DEBUG [0x00000000024dbc40] DDS::DTS::Core::CurrentRunningState |#| TopicData (Core::CurrentRunningState) written (urce/Lts/DDS/Core/../../DDS/DTS/generic_dts_impl.h:57)
2021-02-03 15:50:38.905 DEBUG [0x0000000002413aa0] DDS::DTC::SubscriberListener |#| Data available for LTS_PartitionTime, type Core::PartitionTime, this 0x21f0f80 (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:99)
2021-02-03 15:50:38.906 DEBUG [0x0000000002413aa0] DDS::DTC::SubscriberListener |#| Data available for LTS_PartitionTime, type Core::PartitionTime, this 0x21f0f80 (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:99)
2021-02-03 15:50:38.906 DEBUG [0x0000000002413aa0] DDS::DTC::SubscriberListener |#| Data available for LTS_PartitionTime, type Core::PartitionTime, this 0x21f0f80 (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:99)
2021-02-03 15:50:38.907 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| sampleSize = 1 (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:122)
2021-02-03 15:50:38.907 DEBUG [0x0000000001dfc6f0] DDS::DTC::Core::PartitionTime |#| IN droDataAvailable(), topic name: LTS_PartitionTime, type name Core::PartitionTime, this: 0x24d4580, m_dataReaderObject: 0x24ec320, hasSamples: 1 (urce/Lts/DDS/Core/../../DDS/DTC/generic_dtc_impl.h:210)
2021-02-03 15:50:38.907 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| IN read (Core::PartitionTime), this: 0x24ec320, instance handle 0101aaeead199ead8d523da780000004 (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:167)
2021-02-03 15:50:38.907 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| got 1 samples from reader for Core::PartitionTime (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:197)
2021-02-03 15:50:39.903 DEBUG [0x0000000002413aa0] DDS::DTC::SubscriberListener |#| Data available for LTS_PartitionTime, type Core::PartitionTime, this 0x21f0f80 (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:99)
2021-02-03 15:50:39.903 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| sampleSize = 1 (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:122)
2021-02-03 15:50:39.903 DEBUG [0x0000000001dfc6f0] DDS::DTC::Core::PartitionTime |#| IN droDataAvailable(), topic name: LTS_PartitionTime, type name Core::PartitionTime, this: 0x24d4580, m_dataReaderObject: 0x24ec320, hasSamples: 1 (urce/Lts/DDS/Core/../../DDS/DTC/generic_dtc_impl.h:210)
2021-02-03 15:50:39.903 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| IN read (Core::PartitionTime), this: 0x24ec320, instance handle 0101aaeead199ead8d523da780000004 (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:167)
2021-02-03 15:50:39.903 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| got 1 samples from reader for Core::PartitionTime (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:197)
2021-02-03 15:50:39.904 DEBUG [0x0000000002413aa0] DDS::DTC::SubscriberListener |#| Data available for LTS_PartitionTime, type Core::PartitionTime, this 0x21f0f80 (TDS-source/Lts/DDS/Generic/subscriber_listener.cpp:99)
2021-02-03 15:50:39.904 DEBUG [0x0000000001dfc6f0] DDS::DataReader::Core::PartitionTime |#| sampleSize = 1 (s/DDS/Core/../../DDS/Generic/generic_data_reader.h:122)
2021-02-03 15:50:39.905 DEBUG [0x0000000001dfc6f0] DDS::DTC::Core::PartitionTime |#| IN droDataAvailable(), topic name: LTS_PartitionTime, type name Core::PartitionTime, this: 0x24d4580, m_dataReaderObject: 0x24ec320, hasSamples: 1 (urce/Lts/DDS/Core/../../DDS/DTC/generic_dtc_impl.h:210)
...
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] GNA::WebSocketHandler |#| incoming telegram: {"type": "NasatWeaponRelease", "data": {"releaseMode": 0, "munition": 2, "timestamp": 1612363870.398409, "fuseType": 1, "impactPosition": {"lat": 53.061, "lon": 8.9711}, "aircraftId": 1, "flightTime": 5.1234}, "uuid": "NasatWeaponRelease-UUID"} (/Lts/Proxies/GuezNasat/abstract_socket_handler.cpp:53)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| void GuezNasat::HandlerNasatImpact::nasatImpact(int, const Core::GeoPosition&, qint64, int, int) START, nasatId=1, pos=[[lon: 0.156575232525663, lat: 0.926089154400711]z: 0], impactTimeMsec=1612363875522 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:59)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Sending air support impact: number of participant= 2 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:81)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=1, this=0x2c43570, threadId=139905918381760, m_terminate=0 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:157)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| thread is still running - just fill m_requests., this=0x2c43570, threadId=139905918381760, m_requests=0x2c43f68, m_requests.size()=0), request.uniqueId=2 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:174)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Sending air support impact create request: [id: 0, name: NASAT_1_2_03 15:51:10, effectStart: 1612363875522, chargeTypeId: 472, impactPosition: [lon: 0.156575232525663, lat: 0.926089154400711], partyId: 3, participantId: 90, flightTime: 5123, externalId: null] to exercise 42, nap=[id: 1, nasatAircraftId: 1, exerciseId: 42, participantId: 90] -> success = 1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:88)
2021-02-03 15:51:10.398 INFO [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| requestCounter = 3 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:97)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=1, this=0x2c45380, threadId=139905918381760, m_terminate=2 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:157)
2021-02-03 15:51:10.398 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData - fill m_requests and start new thread., this=0x2c45380, threadId=139905918381760, m_requests=0x2c45d78, m_requests.size()=0), request.uniqueId=2 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:189)
2021-02-03 15:51:10.399 DEBUG [0x0000000001dfc6f0] DDS::FTC::AirSupportImpactModify |#| requestData m_future.valid()=1, this=0x2c45380, threadId=139905918381760, m_terminate=0 done (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:200)
2021-02-03 15:51:10.399 DEBUG [0x00007f3d9c007080] DDS::FTC::AirSupportImpactModify |#| START WHILE LOOP.., this=0x2c45380, threadId=139902712801024, m_requests=0x2c45d78, m_requests.size()=1 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:225)
2021-02-03 15:51:10.399 DEBUG [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| Sending air support impact create request: [id: 0, name: NASAT_1_2_03 15:51:10, effectStart: 1612363875522, chargeTypeId: 472, impactPosition: [lon: 0.156575232525663, lat: 0.926089154400711], partyId: 3, participantId: 62, flightTime: 5123, externalId: null] to exercise 35, nap=[id: 8, nasatAircraftId: 1, exerciseId: 35, participantId: 62] -> success = 1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:88)
2021-02-03 15:51:10.399 DEBUG [0x00007f3d9c007080] DDS::FTC::AirSupportImpactModify |#| IN waitForEvents, this=0x2c45380, request.uniqueId=2, threadId=139902712801024 (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:245)
2021-02-03 15:51:10.399 INFO [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| requestCounter = 4 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:97)
2021-02-03 15:51:10.399 INFO [0x00007f3d9c007080] DDS::FTC::AirSupportImpactModify |#| #sendRequest: SeqNumber: -1, this=0x2c45380, request.uniqueId=2, threadId=139902712801024 ... (ts/DDS/QosProfile/../../DDS/FTC/generic_ftc_impl.h:261)
2021-02-03 15:51:10.399 FATAL [0x0000000001dfc6f0] GNA::HandlerNasatImpact |#| bOk= 0, requestCounter = 4, replyCounter = 1 (rce/Lts/Proxies/GuezNasat/handler_nasat_impact.cpp:102)
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 110,
"headingLow": 130
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 133.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 300,
"initialPoint":
{
"lat": 53.06,
"lon": 8.97
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.06,
"lon": 8.97
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 110,
"headingLow": 130
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 133.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 301,
"initialPoint":
{
"lat": 53.061,
"lon": 8.971
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.061,
"lon": 8.971
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 110,
"headingLow": 130
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 133.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 302,
"initialPoint":
{
"lat": 53.062,
"lon": 8.972
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.062,
"lon": 8.972
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 110,
"headingLow": 130
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 133.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 303,
"initialPoint":
{
"lat": 53.0633,
"lon": 8.9733
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.0633,
"lon": 8.9733
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 110,
"headingLow": 130
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 133.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 304,
"initialPoint":
{
"lat": 53.0644,
"lon": 8.9744
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.0644,
"lon": 8.9744
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 110,
"headingLow": 130
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 133.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 305,
"initialPoint":
{
"lat": 53.0655,
"lon": 8.9755
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.0655,
"lon": 8.97455
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
+66
View File
@@ -0,0 +1,66 @@
# GUEZ NASAT Simulator
GUEZ NASAT Simulator is a Python script to simulate input telegrams from the GUEZ NASAT interface.
It has to be started on the same machine as the GuezNasatProxy (inside MeteoDataManagement)
Author: Filip Biedziak, SLTE (filip.biedziak@rheinmetall.com)
Date: 14 Dec 2020
## Open help / manual
python3 nasat_simulator.py -h
//if there is no pyhton3 available python2 works too
python2 nasat_simulator.py -h
## Prerequisites
On the Workstation:
You will need to create an aircraft first to send an associated telegram. This is how you do it:
1. Open the OperatorApplication
2. Go to ->Planning->Participants->Edit Participant and Add a new participant of Class Aircraft
3. Open a new Situation and choose Superordinate Config / Administation as exercise
4. Go to ->Planning->Participants / Aircraft->NASAT Aircrafts and Add a new aircraft
5. Make sure to set NASAT-Id to a value greater than 0
6. Go back to the Situation with the running exercise
7. Go to ->Planning->Participants / Aicraft->Assign NASAT Aircraft and Add a new one
8. Assign the participant and the aircraft you created to each other using the ComboBoxes
9. Now you can use the GUEZ NASAT Simulator
On the Server:
You need to enable the GNA Websocket interface:
1. Open the lts-cc.conf
2. Find the entry [GNA]
3. Enable websockets with: useWebSocket = true
a. If there is no [GNA] just add both lines to it
4. Restart the Server /or the svcMeteoDataManagement
Important
The software requires the python websocket-client library
NOT THE "websockets" package!
zypper in python3-websocket-client
#Using the Simulator
there are two modes for the Simulator:
Filebased which supports both; WeaponRelease and 9-Liner
#Connection Problems
##Check, if Port is listening
*ss -tuln | grep 8420*
tcp LISTEN 0 50 *:8420 *:*
##Disable proxy
**Disable Proxy**
*env|grep -in proxy*
*export http_proxy==""*
*export https_proxy==""*
#Open Logfile NASAT-Service
*tail -f ctc_mdm.log*
#Changelog
[2024.09.12]
Update with Server Prerequisites and new simulator style
P. Karwat, ESZS (patric.karwat@rheinmetall.com
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Dec 11 13:41:22 2020
@author: Filip Biedziak
"""
NASATPOSITION = "NasatPosition"
NASAT9LINER = "NasatNineLiner"
NASATWEAPONRELEASE = "NasatWeaponRelease"
NASAT_TELEGRAM_TYPES = [NASATPOSITION, NASAT9LINER, NASATWEAPONRELEASE]
HOST = "ws://127.0.0.1"
PORT = 8420
LAT_BRE = 53.0694
LON_BRE = 8.89542
LAT_LTZ = 52.4879
LON_LTZ = 11.60961
R = 0.045
class Colors:
RESET = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
RED ='\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
+166
View File
@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
"""
GUEZ NASAT Simulator
Via this script it is possible to communicate with the GUEZ NASAT Proxy Server
to send individual messages or make an aircraft fly in a circle.
@author: Filip Biedziak
"""
import sys
import argparse
from nasat_socket import NasatSocket
from signal_handler import SignalHandler
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="GUEZ NASAT Simulator - This script can be used to send messages to the GUEZ NASAT Proxy over a " +
"WebSocket. Using this method simulates the real life workflow with a real aircraft or by use of the " +
"simulator. The following telegram types a currently supported: NasatPosition and NasatNineLiner. If you " +
"want a new telegram type to be added to this script, feel free to contact Filip Biedziak " +
"(SLTE, filip.biedziak@rheinmetall.com)."
)
parser.add_argument(
"-a", "--aircraft",
action="store",
dest="aircraft",
type=int,
help="Aircraft ID (required for telegram type NasatPosition)"
)
parser.add_argument(
"-f", "--fname",
action="store",
dest="fname",
type=str,
help="JSON file with data for NasatNineLiner/WeaponRelease telegram"
)
parser.add_argument(
"-n", "--lon",
action="store",
dest="lon",
type=float,
help="replaces lon value in WeaponRelease Telegream"
)
parser.add_argument(
"-g", "--lat",
action="store",
dest="lat",
type=float,
help="replaces lat value in WeaponRelease Telegream"
)
parser.add_argument(
"-l", "--location",
action="store",
dest="location",
default="Bremen",
type=str,
help="Location used to send NasatPosition telegrams (either Bremen or Letzlingen, default=Bremen)"
)
parser.add_argument(
"-u", "--fusetype",
action="store",
dest="fusetype",
type=int,
help="replaces fusetype value in WeaponRelease Telegream 0=Unkwon, 1=Instand, 2=Delay, 3=Burst"
)
parser.add_argument(
"-i", "--flighttime",
action="store",
dest="flightTime",
type=float,
help="replaces flightTime value in WeaponRelease Telegream"
)
parser.add_argument(
"-m", "--munition",
action="store",
dest="mun",
type=int,
help="replaces munnition Code value in WeaponRelease Telegream ( 1-41)"
)
parser.add_argument(
"-t", "--type",
action="store",
dest="type",
default="NasatWeaponRelease",
type=str,
help="NASAT telegram type (default=NasatWeaponRelease). NasatPosition will send the given aircraft on an elliptical path " +
"around the training area. Requires options -a and -l to be specified."+
"NasatNineLiner sends the specified JSON file as NineLiner Telegram " +
"NasatWeaponRelease if -f specified it sends the given JSON file otherwise it used the default file and replaces gived attibutes (-m -i -u -g -n)"+
"Default = NasatWeaponRelease"
)
parser.add_argument(
"-v", "--verbose",
action="store",
dest="verbose",
default=1,
type=int,
help="Increase output verbosity (default=1)"
)
args = parser.parse_args(sys.argv[1:])
aircraft = args.aircraft
location = args.location
telegramType = args.type
verbose = args.verbose
lon = args.lon
lat = args.lat
fuseType = args.fusetype
muncode = args.mun
flightTime = args.flightTime
kwargs = {}
kwargs["fname"] = "nasat_weapon_release_template.json"
if args.fname is not None:
kwargs["fname"] = args.fname
print("================================ GUEZ NASAT Simulator ================================")
if telegramType != "NasatPosition":
if location is not None and verbose > 0:
print("Ignoring option -l/--location with value: ", location)
#aircraft = 0
else:
stop = False
if aircraft is None:
print("Please specify an aircraft ID.")
stop = True
if location is None:
print("Please specify a location (Bremen or Letzlingen).")
stop = True
elif location not in ("Bremen", "Letzlingen"):
print("Unknown location: %s" % location)
stop = True
if stop:
sys.exit(0)
socket = NasatSocket(telegramType, verbose)
if (lon is not None and lat is not None):
socket.setPosition(lon, lat)
print("SET LON " , lon)
print("SET LAT " , lat)
else:
print("NO LON LAT")
if (muncode is not None):
socket.setMunition(muncode)
print("our fusetype", fuseType)
if (fuseType is not None):
socket.setFuseType(fuseType)
if (flightTime is not None):
socket.setFlightTime(flightTime)
signalHandler = SignalHandler(socket)
if socket.telegramType() == "NasatPosition":
socket.setAircraftId(aircraft)
socket.setLocation(location)
elif aircraft is not None:
socket.setAircraftId(aircraft)
socket.connect()
socket.start(**kwargs)
@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
"""
GUEZ NASAT Simulator
Via this script it is possible to communicate with the GUEZ NASAT Proxy Server
to send individual messages or make an aircraft fly in a circle.
@author: Filip Biedziak
"""
import sys
import argparse
from nasat_socket import NasatSocket
from signal_handler import SignalHandler
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="GUEZ NASAT Simulator - This script can be used to send messages to the GUEZ NASAT Proxy over a " +
"WebSocket. Using this method simulates the real life workflow with a real aircraft or by use of the " +
"simulator. The following telegram types a currently supported: NasatPosition and NasatNineLiner. If you " +
"want a new telegram type to be added to this script, feel free to contact Filip Biedziak " +
"(SLTE, filip.biedziak@rheinmetall.com)."
)
parser.add_argument(
"-a", "--aircraft",
action="store",
dest="aircraft",
type=int,
help="Aircraft ID (required for telegram type NasatPosition)"
)
parser.add_argument(
"-f", "--fname",
action="store",
dest="fname",
type=str,
help="JSON file with data for NasatNineLiner/WeaponRelease telegram"
)
parser.add_argument(
"-n", "--lon",
action="store",
dest="lon",
type=float,
help="replaces lon value in WeaponRelease Telegream"
)
parser.add_argument(
"-g", "--lat",
action="store",
dest="lat",
type=float,
help="replaces lat value in WeaponRelease Telegream"
)
parser.add_argument(
"-l", "--location",
action="store",
dest="location",
default="Letzlingen",
type=str,
help="Location used to send NasatPosition telegrams (either Bremen or Letzlingen, default=Letzlingen)"
)
parser.add_argument(
"-u", "--fusetype",
action="store",
dest="fusetype",
type=int,
help="replaces fusetype value in WeaponRelease Telegream 0=Unkwon, 1=Instand, 2=Delay, 3=Burst"
)
parser.add_argument(
"-i", "--flighttime",
action="store",
dest="flightTime",
type=float,
help="replaces flightTime value in WeaponRelease Telegream"
)
parser.add_argument(
"-m", "--munition",
action="store",
dest="mun",
type=int,
help="replaces munnition Code value in WeaponRelease Telegream ( 1-41)"
)
parser.add_argument(
"-t", "--type",
action="store",
dest="type",
default="NasatWeaponRelease",
type=str,
help="NASAT telegram type (default=NasatWeaponRelease). NasatPosition will send the given aircraft on an elliptical path " +
"around the training area. Requires options -a and -l to be specified."+
"NasatNineLiner sends the specified JSON file as NineLiner Telegram " +
"NasatWeaponRelease if -f specified it sends the given JSON file otherwise it used the default file and replaces gived attibutes (-m -i -u -g -n)"+
"Default = NasatWeaponRelease"
)
parser.add_argument(
"-v", "--verbose",
action="store",
dest="verbose",
default=1,
type=int,
help="Increase output verbosity (default=1)"
)
args = parser.parse_args(sys.argv[1:])
aircraft = args.aircraft
location = args.location
telegramType = args.type
verbose = args.verbose
lon = args.lon
lat = args.lat
fuseType = args.fusetype
muncode = args.mun
flightTime = args.flightTime
kwargs = {}
kwargs["fname"] = "nasat_weapon_release_template.json"
if args.fname is not None:
kwargs["fname"] = args.fname
print("================================ GUEZ NASAT Simulator ================================")
if telegramType != "NasatPosition":
if location is not None and verbose > 0:
print("Ignoring option -l/--location with value: ", location)
#aircraft = 0
else:
stop = False
if aircraft is None:
print("Please specify an aircraft ID.")
stop = True
if location is None:
print("Please specify a location (Bremen or Letzlingen).")
stop = True
elif location not in ("Bremen", "Letzlingen"):
print("Unknown location: %s" % location)
stop = True
if stop:
sys.exit(0)
socket = NasatSocket(telegramType, verbose)
if (lon is not None and lat is not None):
socket.setPosition(lon, lat)
print("SET LON " , lon)
print("SET LAT " , lat)
else:
print("NO LON LAT")
if (muncode is not None):
socket.setMunition(muncode)
print("our fusetype", fuseType)
if (fuseType is not None):
socket.setFuseType(fuseType)
if (flightTime is not None):
socket.setFlightTime(flightTime)
signalHandler = SignalHandler(socket)
if socket.telegramType() == "NasatPosition":
socket.setAircraftId(aircraft)
socket.setLocation(location)
elif aircraft is not None:
socket.setAircraftId(aircraft)
socket.connect()
socket.start(**kwargs)
+337
View File
@@ -0,0 +1,337 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Dec 11 13:40:11 2020
@author: Filip Biedziak
"""
import os
import sys
import websocket
import threading
import time
import math
import json
from collections import OrderedDict
from constants import HOST, PORT, NASAT_TELEGRAM_TYPES, LAT_BRE, LON_BRE, LAT_LTZ, LON_LTZ, R, Colors
class NasatSocket(object):
_websocket = None
_host = HOST
_port = PORT
_status = False
_statusThread = None
_checkStatus = True
_interrupt = True
_verbose = 0
_telegram = OrderedDict()
_buffer = []
_aircraftId = None
_location = None
_telegramType = None
_timestamp = 0
_position = OrderedDict()
_phi = 0.0
_dPhi = 6.0 * math.pi / 360.0
_lon = None
_lat = None
_fuseType = None
_muncode = None
_flightTime = None
def __init__(self, telegramType, verbose):
"""Constructor."""
assert isinstance(telegramType, str)
assert isinstance(verbose, int)
if telegramType not in NASAT_TELEGRAM_TYPES:
self.error("Unknown telegram type: %s" % telegramType)
self._telegramType = telegramType
self._telegram["type"] = self._telegramType
self._telegram["data"] = OrderedDict()
self._telegram["data"]["aircraftId"] = self._aircraftId
self._verbose = verbose
def error(self, msg):
print("%s%sERROR%s: %s" % (Colors.BOLD, Colors.RED, Colors.RESET, msg))
self.close()
sys.exit(0)
def host(self):
return self._host
def setHost(self, host=None):
assert isinstance(host, str)
self._host = host
def port(self):
return self._port
def setPort(self, port=None):
assert isinstance(port, int)
self._port = port
def status(self):
return self._status
def checkStatus(self):
return self._checkStatus
def setCheckStatus(self, check):
assert isinstance(check, bool)
self._checkStatus = check
def interrupt(self):
return self._interrupt
def setInterrupt(self, interrupt):
assert isinstance(interrupt, bool)
self._interrupt = interrupt
def aircraftId(self):
return self._aircraftId
def setAircraftId(self, aircraftId):
assert isinstance(aircraftId, int)
if aircraftId < 0:
self.error("Invalid aircraft ID: %d" % aircraftId)
self._aircraftId = aircraftId
self._telegram["data"]["aircraftId"] = self._aircraftId
def telegramType(self):
return self._telegramType
def setPosition(self, lon, lat):
self._lon = lon
self._lat = lat
def setMunition(self, muncode):
self._muncode = muncode
def setFuseType(self, fuseType):
self._fuseType = fuseType
def setFlightTime(self, flightTime):
self._flightTime = flightTime
def location(self):
return self._location
def setLocation(self, location):
assert isinstance(location, str)
if location not in ["Bremen", "Letzlingen"]:
self.error("Unknown location: %s" % location)
self._location = location
# ==================================================== EXCON Connection ====================================================
def checkConnectionStatus(self):
startTime = time.time()
while self._checkStatus:
changed = False
# check if still connected
if self._status:
try:
self._websocket.send("") # send an empty message
except:
self._status = False
changed = True
# attempt to reconnect
else:
if self._verbose > 1:
print("Connecting to %s:%d" % (self._host, self._port))
try:
self._websocket = websocket.create_connection("%s:%d" % (self._host, self._port))
self._status = True
changed = True
except:
pass
# only show when status changes
if changed and self._verbose > 0:
color = Colors.GREEN if self._status else Colors.RED
status = "OK" if self._status else "not connected"
print("Connection status: %s%s%s%s" % (Colors.BOLD, color, status, Colors.RESET))
# check every second
time.sleep(1.0 - ((time.time() - startTime) % 1.0))
def connect(self):
self._statusThread = threading.Thread(target=self.checkConnectionStatus)
self._statusThread.start()
def close(self):
if self._verbose > 0:
print("Closing connection.")
self._checkStatus = False
self._status = False
if self._statusThread is not None:
self._statusThread.do_run = False
if self._websocket is not None:
self._websocket.close()
# ===================================================== NASAT Telegrams ====================================================
def start(self, **kwargs):
if self._verbose > 1:
print("Sending telegram of type: %s" % self._telegramType)
if self._telegramType == "NasatPosition":
if self._aircraftId is None:
self.error("Aircraft ID has not been set.")
elif self._location is None:
self.error("Location has not been set.")
self.simulateNasatPosition()
elif self._telegramType == "NasatNineLiner":
self.simulateNineLiner(**kwargs)
elif self._telegramType == "NasatWeaponRelease":
self.simulateWeaponRelease(**kwargs)
else:
self.error("Unknown telegram type: %s" % self._telegramType)
def send(self):
self._timestamp = time.time()
self._telegram["data"]["timestamp"] = self._timestamp
# print("send Telegram: %s" % self._telegram)
telegram = json.dumps(self._telegram)
if self._status:
try:
if self._verbose > 1:
print("Sending telegram: %s" % telegram)
self._websocket.send(telegram)
except:
self._buffer.append(telegram) # just in case of timing issues
else:
self._buffer.append(telegram)
def sendBuffer(self):
bufferCopy = [telegram for telegram in self._buffer]
for telegram in bufferCopy:
try:
self._websocket.send(telegram)
self._buffer = self._buffer[1:]
time.sleep(0.1)
except:
break
# ====================================================== NasatPosition =====================================================
def calculatePosition(self):
lat = LAT_BRE if self._location == "Bremen" else LAT_LTZ if self._location == "Letzlingen" else 0
lon = LON_BRE if self._location == "Bremen" else LON_LTZ if self._location == "Letzlingen" else 0
self._position["lat"] = lat + R * math.cos(self._phi)
self._position["lon"] = lon + R * math.sin(self._phi) * 1.7 # roughly a circle
self._position["height"] = 1000
self._telegram["data"]["position"] = self._position
self._phi += self._dPhi
def simulateNasatPosition(self):
startTime = time.time()
count = 0
while True:
if self._status and len(self._buffer) > 0:
self.sendBuffer()
self.calculatePosition() # update current telegram
self.send()
time.sleep(1.0 - ((time.time() - startTime) % 1.0))
if self._interrupt:
if count == 10:
self.close()
elif count == 20:
self.setCheckStatus(True)
self.connect()
count += 1
# ===================================================== NasatNineLiner =====================================================
def readNineLinerData(self, fname):
assert isinstance(fname, str)
if not os.path.exists(fname):
self.error("NasatNineLiner telegrams requires a JSON file with additional data.")
try:
with open(fname, 'r') as f:
data = json.load(f)
except:
self.error("Unable to read Nine Liner data from JSON file: %s" % fname)
if data["data"]["timestamp"] == -1:
data["data"]["timestamp"] = time.time()
return data
def simulateNineLiner(self, **kwargs):
if "fname" not in kwargs.keys():
self.error("Missing argument 'fname' with path to Nine Liner data.")
self._telegram = self.readNineLinerData(kwargs["fname"])
startTime = time.time()
while not self._status:
time.sleep(1.0 - ((time.time() - startTime) % 1.0)) # wait until connection has been established
self.send()
self.close()
# ================================================= NasatWeaponRelease =================================================
def readWeaponReleaseData(self, fname):
assert isinstance(fname, str)
if not os.path.exists(fname):
self.error("NasatWeaponRelease telegrams requires a JSON file with additional data. %s" % fname)
try:
with open(fname, 'r') as f:
data = json.load(f)
except:
self.error("Unable to read NasatWeaponRelease data from JSON file: %s" % fname)
if data["data"]["timestamp"] == -1:
data["data"]["timestamp"] = time.time()
return data
def simulateWeaponRelease(self, **kwargs):
if "fname" not in kwargs.keys():
self.error("Missing argument 'fname' with path to Weapon Release data.")
self._telegram = self.readWeaponReleaseData(kwargs["fname"])
if (self._lon is not None and self._lat is not None):
print("REPLACE pos")
self._telegram["data"]["impactPosition"]["lat"] = self._lat
self._telegram["data"]["impactPosition"]["lon"] = self._lon
if (self._muncode is not None):
print("Replace muncode")
self._telegram["data"]["munition"] = self._muncode
if (self._fuseType is not None):
print("Replace fusetype")
self._telegram["data"]["fuseType"] = self._fuseType
if (self._flightTime is not None):
print("Replace flightTime")
self._telegram["data"]["flightTime"] = self._flightTime
if (self._aircraftId is not None):
print("Replace aircraft")
self._telegram["data"]["aircraftId"] = self._aircraftId
startTime = time.time()
while not self._status:
time.sleep(1.0 - ((time.time() - startTime) % 1.0)) # wait until connection has been established
print("send NasatWeaponRelease with timestamp: %s" % self._telegram)
self.send()
self.close()
@@ -0,0 +1,2 @@
{"data":{"aircraftId":1,"flightTime":20.866775512695312,"fuseType":3,"impactPosition":{"lat":52.496913048935859,"lon":11.584327375871482},"munition":22,"releaseMode":0,"timestamp":-1},"type":"NasatWeaponRelease","uuid":"a70be051-4063-45db-8c3d-2a6d9ade02d4"}
+42
View File
@@ -0,0 +1,42 @@
{
"data":
{
"aircraftId": 1,
"altitudeTarget": 56,
"altitudeTargetMode": 1,
"distance2InitialPointMode": 1,
"distanceInitialPoint2Target": 925.9,
"finalAttackHeading":
{
"heading": 120,
"headingHigh": 270,
"headingLow": 10
},
"finalAttackHeadingMode": 2,
"friendlies":
{
"bearing": 88,
"distance": 333.6
},
"heading2InitialPointMode": 2,
"headingInitialPoint2Target": 315,
"initialPoint":
{
"lat": 53.06,
"lon": 8.97
},
"initialPointMode": 1,
"modeFriendlies": 1,
"targetPosition":
{
"lat": 53.06,
"lon": 8.971
},
"targetPositionMode": 1,
"timeForTarget": 57600,
"timeForTargetMode": 2,
"timestamp": -1
},
"type": "NasatNineLiner",
"uuid": "blasdbasd-kjladjaslasdklj"
}
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Dec 11 13:44:45 2020
@author: Filip Biedziak
"""
import sys
import signal
class SignalHandler(object):
def __init__(self, socket):
self._socket = socket
signal.signal(signal.SIGINT, self.onSigint)
def onSigint(self, s, f):
"""Handler to gracefully exit on Ctrl+C."""
print("\nCtrl+C pressed")
self._socket.close()
sys.exit(0)
@@ -0,0 +1,15 @@
#! /bin/bash
#
# Dieses Script startet eine Abfolge von
# Es dient zur Prüfung der DDS-Telegramme, insbesondere in Hinblick auf Replay
#
# Ein Evtl. Wechsel der Zuorndung NasatAircraft zu Participant (NAP)
# kann während der Pausen manuell durchgeführt werden.
#
#python3 nasat_simulator.py -a1 -t NasatPositon
python3 nasat_simulator.py -a1 -l Letzlingen -t NasatPosition
echo "Ende"
+31
View File
@@ -0,0 +1,31 @@
#! /bin/bash
#
# Dieses Script startet eine Abfolge von NineLinern
# Es dient zur Prüfung der DDS-Telegramme, insbesondere in Hinblick auf Replay
#
# Ein Evtl. Wechsel der Zuorndung NasatAircraft zu Participant (NAP)
# kann während der Pausen manuell durchgeführt werden.
#
echo "Zuorndung NasatAircraft zu Participant (NAP) in Ordnung? Marke setzen? Weiter mit Eingabe..."
read
python2 nasat_simulator.py -a1 -t NasatNineLiner -f ./NineLiner/nine_liner_template_300.json
sleep 10
python2 nasat_simulator.py -a1 -t NasatNineLiner -f ./NineLiner/nine_liner_template_301.json
echo "Wechsel der Zuorndung NasatAircraft zu Participant (NAP)? Weiter mit Eingabe..."
read
python2 nasat_simulator.py -a1 -t NasatNineLiner -f ./NineLiner/nine_liner_template_302.json
sleep 10
python2 nasat_simulator.py -a1 -t NasatNineLiner -f ./NineLiner/nine_liner_template_303.json
echo "Wechsel der Zuorndung NasatAircraft zu Participant (NAP)? Weiter mit Eingabe..."
read
python2 nasat_simulator.py -a1 -t NasatNineLiner -f ./NineLiner/nine_liner_template_304.json
sleep 10
python2 nasat_simulator.py -a1 -t NasatNineLiner -f ./NineLiner/nine_liner_template_305.json
echo "Ende"
+24
View File
@@ -0,0 +1,24 @@
#! /bin/bash
#
# Dieses Script startet eine Abfolge von
# Es dient zur Prüfung der DDS-Telegramme, insbesondere in Hinblick auf Replay
#
# Ein Evtl. Wechsel der Zuorndung NasatAircraft zu Participant (NAP)
# kann während der Pausen manuell durchgeführt werden.
#
while [ 1 ]
do
python3 nasat_simulator.py -a1 -t NasatWeaponRelease -f nasat_weapon_release_template_1.json -v2
python3 nasat_simulator.py -a2 -t NasatWeaponRelease -f nasat_weapon_release_template_2.json -v2
python3 nasat_simulator.py -a3 -t NasatWeaponRelease -f nasat_weapon_release_template_3.json -v2
python3 nasat_simulator.py -a4 -t NasatWeaponRelease -f nasat_weapon_release_template_4.json -v2
sleep 30
done
echo "Ende"
+83
View File
@@ -0,0 +1,83 @@
/**
* Websocket interface for building control unit
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-30
*/
#include "abstract_socket_handler.h"
#include "guez_nasat_telegrams.h"
#include "settings.h"
#include <QDateTime>
#include <QJsonDocument>
namespace GuezNasat
{
AbstractSocketHandler::AbstractSocketHandler(const char *loggerName, QObject *parent)
: QObject(parent)
, m_logger(getLogger(loggerName))
{}
void AbstractSocketHandler::setSimulationStatus(int nasatId, bool bActivateSimulation)
{
NasatSimulationRequest req;
req.aircraftId = nasatId;
req.timestamp = QDateTime::currentSecsSinceEpoch();
req.enableSimulation = bActivateSimulation;
const QPointF pos = Settings::simulationPositionDegree();
req.position.lon = pos.x();
req.position.lat = pos.y();
sendTelegram(&req);
}
bool AbstractSocketHandler::sendTelegram(const NasatBase *tele)
{
if (!isConnected() || !tele)
return false;
QJsonObject obj;
obj[QStringLiteral("data")] = tele->toJson();
obj[QStringLiteral("type")] = tele->type();
return sendTelegramInternal(QJsonDocument(obj).toJson(QJsonDocument::Compact));
}
void AbstractSocketHandler::textMessageReceived(const QByteArray &msg)
{
if (msg.isEmpty())
{
ERROR_LOG(m_logger) << "Empty message received";
return;
}
const QJsonObject obj = QJsonDocument::fromJson(msg).object();
DEBUG_LOG(m_logger) << "incoming telegram: " << msg;
const QJsonValue type = obj.value(QStringLiteral("type"));
if (!type.isString())
{
ERROR_LOG(m_logger) << "Can not read type id: " << msg;
return;
}
const QString typeStr = type.toString();
const QJsonObject data = obj.value(QStringLiteral("data")).toObject();
try
{
if (typeStr.compare(Constraints<NasatPosition>::type(), Qt::CaseInsensitive) == 0)
emit positionReceived(NasatPosition::fromJson(data));
else if (typeStr.compare(Constraints<NasatWeaponRelease>::type(), Qt::CaseInsensitive) == 0)
emit weaponReleaseReceived(NasatWeaponRelease::fromJson(data));
else if (typeStr.compare(Constraints<NasatNineLiner>::type(), Qt::CaseInsensitive) == 0)
emit nineLinerReceived(NasatNineLiner::fromJson(data));
else if (typeStr.compare(Constraints<NasatSimulationStatus>::type(), Qt::CaseInsensitive) == 0)
emit simulationStatusReceived(NasatSimulationStatus::fromJson(data));
else
ERROR_LOG(m_logger) << "Got unknown json telegram: " << msg;
}
catch (const JsonException &ex)
{
ERROR_LOG(m_logger) << "Could not parse json telegram: " << msg
<< ", error: " << ex.what();
}
}
} // namespace GuezNasat
+46
View File
@@ -0,0 +1,46 @@
/**
* Websocket interface for building control unit
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-30
*/
#pragma once
#include <QObject>
#include <QWebSocketServer>
#include <logger.h>
#include "guez_nasat_telegrams.h"
namespace GuezNasat
{
class AbstractSocketHandler : public QObject
{
Q_OBJECT
public:
explicit AbstractSocketHandler(const char *loggerName, QObject *parent = nullptr);
virtual bool init(quint16 listenPort) = 0;
virtual bool isConnected() const = 0;
public Q_SLOTS:
void setSimulationStatus(int nasatId, bool bActivateSimulation);
Q_SIGNALS:
void positionReceived(const NasatPosition &data);
void weaponReleaseReceived(const NasatWeaponRelease &data);
void nineLinerReceived(const NasatNineLiner &data);
void simulationStatusReceived(const NasatSimulationStatus &data);
protected:
void textMessageReceived(const QByteArray &msg);
bool sendTelegram(const NasatBase *tele);
virtual bool sendTelegramInternal(const QByteArray &tele) = 0;
protected:
LOGGER_T m_logger;
};
} // namespace GuezNasat
+204
View File
@@ -0,0 +1,204 @@
/**
* DDS Handler for GuezNasat
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-11-14
*/
#include "dds_handler.h"
#include <TrainingAreaBase/tab_dts.h>
#include <DDS/DTS/generic_dts.h>
namespace GuezNasat
{
//-----------------------------------------------------------------------------
// ParticipantDds
//-----------------------------------------------------------------------------
Participant2Dds::Participant2Dds(const dds::domain::DomainParticipant &domainParticipant, int exerciseId)
: m_ddsConnector(new DDSConnector::DdsConnector(domainParticipant, IDL::PartitionType::Exercise, exerciseId))
, m_logger(getLogger("Participant2Dds"))
{
m_ddsConnector->initPublisherSubscriber();
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsConnector);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
this, &Participant2Dds::onParticipantChanged);
m_ppmDtc->enableParticipant();
// related to NLDEVCTRL-844: NASAT: Weiterleitung der Luftunterstützung sporadisch ausser Funktion
// Um die Erzeugung von DDS-Objecten weiter zu entzerren, wird bereits hier
// ein enableAirSupportImpactModify durchgeführt:
// (Hier ist die Zugehörigkeit zu einer Exercise gegeben)
// AES FTC
DEBUG_LOG(m_logger) << LOGFUNCTION << " create FTC..." << " exerciseId=" << exerciseId;
m_aesFtc = AreaEffectSimulation::Interface::Ftc::create(m_ddsConnector);
if (!m_aesFtc->enableAirSupportImpactModify())
{
ERROR_LOG(m_logger) << "Could not enable AES AirSupportImpactModify FTC for"
<< " exerciseId=" << exerciseId;
m_aesFtc = nullptr;
}
if (!m_aesFtc->enableExplosionClusterModify())
{
ERROR_LOG(m_logger) << "Could not enable AES enableExplosionClusterModify FTC for"
<< " exerciseId=" << exerciseId;
m_aesFtc = nullptr;
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " create FTC..." << " exerciseId=" << exerciseId << " Done: " << m_aesFtc.get();
}
bool Participant2Dds::publish(const TrainingAreaBase::EquipmentPosition &pos)
{
if (!m_tabDts)
{
m_tabDts = TrainingAreaBase::Interface::Dts::create(m_ddsConnector);
if (!m_tabDts->enableEquipmentPosition())
{
ERROR_LOG(m_logger) << "Could not enable TAB equipment position DTS for "
<< m_ddsConnector->getDefaultPartition();
m_tabDts = nullptr;
return false;
}
}
return m_tabDts->publish(pos);
}
bool Participant2Dds::publish(const AreaEffectSimulation::AirSupportImpactModifyRequest &req,
AreaEffectSimulation::Interface::Ftc::AirSupportImpactModifyReplyHandler *handler)
{
return m_aesFtc->airSupportImpactModifyRequest(req, handler);
}
bool Participant2Dds::publish(const AreaEffectSimulation::ExplosionClusterModifyRequest &req,
AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler *handler)
{
return m_aesFtc->explosionClusterModifyRequest(req, handler);
}
bool Participant2Dds::publish(const GuezNasat::Nasat9Liner &nl)
{
if (!m_gnaDts)
{
m_gnaDts = GuezNasat::Interface::Dts::create(m_ddsConnector);
if (!m_gnaDts->enableNasat9Liner())
{
ERROR_LOG(m_logger) << "Could not enable GNA Nasat9Liner DTS for "
<< m_ddsConnector->getDefaultPartition();
m_gnaDts = nullptr;
return false;
}
}
return m_gnaDts->publish(nl);
}
void Participant2Dds::addParticipantToWatch(int participantId)
{
DEBUG_LOG(m_logger) << "addParticipantToWatch: " << participantId;
m_participantsToWatch += participantId;
}
void Participant2Dds::removeParticipantToWatch(int participantId)
{
DEBUG_LOG(m_logger) << "removeParticipantToWatch: " << participantId;
m_participantsToWatch -= participantId;
}
int Participant2Dds::partyId(int participantId) const
{
auto ret = -1;
std::function<bool(const ParticipantManagement::Participant&)> cb = [participantId, &ret](const ParticipantManagement::Participant &p)
{
if (p.id() != participantId)
return false;
ret = p.partyId();
return true;
};
m_ppmDtc->participants(cb);
return ret;
}
void Participant2Dds::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
DEBUG_LOG(m_logger) << "onParticipantChanged: " << data.id()
<< ", " << m_participantsToWatch.contains(data.id())
<< ", " << m_participantsToWatch.size()
<< ", " << m_participantsToWatch.contains(data.id())
<< ", " << data.isDeleted();
if (!m_participantsToWatch.contains(data.id()))
return;
if (data.isDeleted())
emit participantRemoved(m_ddsConnector->getPartitionId(), data.id());
}
//-----------------------------------------------------------------------------
// DdsHandler
//-----------------------------------------------------------------------------
DdsHandler::DdsHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
: m_ddsConnector(std::make_shared<DDSConnector::DdsConnector>(ddsConnector->getDomainParticipant(), IDL::PartitionType::AllExercises))
, m_logger(getLogger("DdsHandler"))
{
DEBUG_LOG(m_logger) << "DdsHandler(" << m_ddsConnector->getDomainId() << ") for partition: " << m_ddsConnector->getDefaultPartition();
}
bool DdsHandler::init(const QStringList &qosFileList)
{
INFO_LOG(m_logger) << "--- Start GuezNasat DDSHandler.";
if (!m_ddsConnector->init(qosFileList))
{
ERROR_LOG(m_logger) << "Error initializing dds connections - aborting";
return false;
}
// default initialize Publisher and Subscriber
m_ddsConnector->initPublisherSubscriber();
// DTS
m_ddsDts = GuezNasat::Interface::Dts::create(m_ddsConnector);
bool bRet = m_ddsDts->enableNasatAircraft() &&
m_ddsDts->enableNasatAircraftParticipant();
INFO_LOG(m_logger) << "Dts initialised: " << bRet;
// FTS
m_ddsFts = GuezNasat::Interface::Fts::create(m_ddsConnector);
bRet &= m_ddsFts->enableAll();
INFO_LOG(m_logger) << "Fts initialised: " << bRet;
// EXM DTC
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_ddsConnector);
bRet &= m_exmDtc->enableExercise();
INFO_LOG(m_logger) << "EXM Dtc initialised: " << bRet;
// PDM DTC
m_pdmDtc = ProjectDataManagement::Interface::Dtc::create(m_ddsConnector);
bRet &= m_pdmDtc->enableChargeType();
INFO_LOG(m_logger) << "PDM Dtc initialised: " << bRet;
return bRet;
} // end of init()
std::shared_ptr<Participant2Dds> DdsHandler::ddsParticipant(int exerciseId)
{
auto it = m_nasatParticipant2Dds.find(exerciseId);
if (it != m_nasatParticipant2Dds.end())
{
auto ret = it.value().lock();
if (ret)
return ret;
m_nasatParticipant2Dds.erase(it);
}
auto ret = std::make_shared<Participant2Dds>(m_ddsConnector->getDomainParticipant(), exerciseId);
m_nasatParticipant2Dds[exerciseId] = ret;
return ret;
}
} // namespace GuezNasat
+82
View File
@@ -0,0 +1,82 @@
/**
* DDS Handler for GuezNasat
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-11-14
*/
#pragma once
#include <DDS/DDSConnector/dds_connector.h>
#include <GuezNasat/gna_dts.h>
#include <GuezNasat/gna_fts.h>
#include <ExerciseManagement/exm_dtc.h>
#include <AreaEffectSimulation/aes_ftc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ProjectDataManagement/pdm_dtc.h>
#include <TrainingAreaBase/tab_dts.h>
#include <QHash>
#include <QSet>
#include "logger.h"
namespace GuezNasat
{
class Participant2Dds final : public QObject
{
Q_OBJECT
public:
Participant2Dds(const dds::domain::DomainParticipant &domainParticipant, int exerciseId);
bool publish(const TrainingAreaBase::EquipmentPosition &pos);
bool publish(const AreaEffectSimulation::AirSupportImpactModifyRequest &req,
AreaEffectSimulation::Interface::Ftc::AirSupportImpactModifyReplyHandler *handler);
bool publish(const AreaEffectSimulation::ExplosionClusterModifyRequest &req,
AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler *handler);
bool publish(const GuezNasat::Nasat9Liner &nl);
void addParticipantToWatch(int participantId);
void removeParticipantToWatch(int participantId);
int partyId(int participantId) const;
Q_SIGNALS:
void participantRemoved(int exerciseId, int participantId);
private:
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
private:
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<TrainingAreaBase::Interface::Dts> m_tabDts;
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<GuezNasat::Interface::Dts> m_gnaDts;
QSet<int> m_participantsToWatch;
NGL::INGLLogger &m_logger;
};
class DdsHandler final
{
public:
explicit DdsHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
bool init(const QStringList &qosFileList = QStringList());
std::shared_ptr<GuezNasat::Interface::Dts> dts() const { return m_ddsDts; }
std::shared_ptr<GuezNasat::Interface::Fts> fts() const { return m_ddsFts; }
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc() const { return m_exmDtc; }
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const { return m_pdmDtc; }
std::shared_ptr<Participant2Dds> ddsParticipant(int exerciseId);
private:
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
std::shared_ptr<GuezNasat::Interface::Dts> m_ddsDts;
std::shared_ptr<GuezNasat::Interface::Fts> m_ddsFts;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
QHash<int, std::weak_ptr<Participant2Dds>> m_nasatParticipant2Dds;
NGL::INGLLogger &m_logger;
};
} // namespace GuezNasat
+52
View File
@@ -0,0 +1,52 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLSE, 2015-08-04
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef GNA_COMMON_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define GNA_COMMON_EXPORT
# else
# if defined(MAKE_SVCGNACOMMON_LIB)
# define GNA_COMMON_EXPORT Q_DECL_EXPORT
# ifndef WIN32
# ifdef NDDSUSERDllExport
# undef NDDSUSERDllExport
# endif
# define NDDSUSERDllExport Q_DECL_EXPORT
# endif
# else
# define GNA_COMMON_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
#ifndef GNA_CLIENT_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define GNA_CLIENT_EXPORT
# else
# if defined(MAKE_SVCGNACLIENT_LIB)
# define GNA_CLIENT_EXPORT Q_DECL_EXPORT
# else
# define GNA_CLIENT_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
#ifndef GNA_SERVER_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define GNA_SERVER_EXPORT
# else
# if defined(MAKE_SVCGNASERVER_LIB)
# define GNA_SERVER_EXPORT Q_DECL_EXPORT
# else
# define GNA_SERVER_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
+98
View File
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<service namespace="GuezNasat" abbreviation="GNA" procNames="GuezNasat" exerciseDependency="Global,Exercise" groups="Core">
<rcs>
<Id Id="$Id: ea_export_script.txt 41311 2018-04-23 09:43:45Z ehrlicher $"/>
<HeadURL HeadURL="$HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Common/CodeGen/ea_export_script.txt $"/>
<Author Author="$Author: ehrlicher $"/>
</rcs>
<operatorRights offset="51">
<guiPlugin name="GuezNasat" offset="1">
<operatorRightGroup name="GuezNasatConfiguration" description="Configure NASAT aircrafts">
<operatorRight right="GuezNasatConfigurationShow" value="1" description="Show Guez Nasat Configuration"/>
<operatorRight right="GuezNasatConfigurationEdit" value="2" description="Edit Guez Nasat Configuration"/>
</operatorRightGroup>
</guiPlugin>
</operatorRights>
<topicTypes>
<topicType name="Nasat9Liner" isDataObject="1" routeToClient="1" routeToServer="0" routeInReplay="0" recordTopic="1" baseValueType="Core::BaseEntityWithSampleTime">
<column name="participantId" idlType="long"/>
<column name="initialPoint" idlType="Core::GeoPosition2D"/>
<column name="hdgInitialPoint2Target" idlType="long" comment="[degree], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="hdg2InitialPointMode" idlType="Hdg2InitialPointMode"/>
<column name="distanceInitialPoint2Target" idlType="double" comment="[m], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="targetPosition" idlType="Core::GeoPosition"/>
<column name="friendliesBearing" idlType="long" comment="[degree], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="friendliesDistance" idlType="double" comment="[m], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="finalAttackHeading" idlType="long" comment="[degree], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="finalAttackHeadingLow" idlType="long" comment="[degree], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="finalAttackHeadingHigh" idlType="long" comment="[degree], &amp;lt; 0 -&amp;gt; invalid"/>
<column name="timeForTarget" idlType="long" comment="[s], &amp;lt;0 -&amp;gt; timeToTarget, 0 -&amp;gt; invalid, &amp;gt; 0 -&amp;gt; timeOverTarget"/>
<column name="isCurrent" idlType="boolean" comment="true when this is the most recent nineliner for this participant"/>
</topicType>
<topicType name="NasatAircraft" isDataObject="1" routeToClient="1" routeToServer="0" routeInReplay="0">
<column name="id" idlType="long" isKey="1"/>
<column name="nasatId" idlType="long"/>
<column name="simulationActive" idlType="boolean"/>
<column name="name" idlType="string"/>
</topicType>
<topicType name="NasatAircraftParticipant" isDataObject="1" routeToClient="1" routeToServer="0" routeInReplay="0">
<column name="id" idlType="long" isKey="1"/>
<column name="nasatAircraftId" idlType="long"/>
<column name="exerciseId" idlType="long"/>
<column name="participantId" idlType="long"/>
</topicType>
</topicTypes>
<functionTopics>
<functionTopic name="ModifyNasatAircraft" requestTopicType="NasatAircraft" replyTopicType="Core::FunctionReply" requestTopicName="ModifyNasatAircraftRequest" replyTopicName="ModifyNasatAircraftReply" routeInReplay="0"/>
<functionTopic name="ModifyNasatAircraftParticipant" requestTopicType="NasatAircraftParticipant" replyTopicType="Core::FunctionReply" requestTopicName="ModifyNasatAircraftParticipantRequest" replyTopicName="ModifyNasatAircraftParticipantReply" routeInReplay="0"/>
</functionTopics>
<tables>
<table name="nasat_aircraft">
<column name="id" datatype="integer" isPrimaryKey="1">
<sequence start="1" increment="1"/>
</column>
<column name="name" datatype="text"/>
<column name="nasat_id" datatype="integer"/>
<column name="simulation_active" datatype="boolean"/>
<constraint name="UQ_nasat_aircraft_id" type="unique">
<column name="id"/>
</constraint>
<constraint name="UQ_nasat_aircraft_nasat_id" type="unique">
<column name="nasat_id"/>
</constraint>
</table>
<table name="nasat_aircraft_participant">
<column name="id" datatype="integer" isPrimaryKey="1">
<sequence start="1" increment="1"/>
</column>
<column name="nasat_aircraft_id" datatype="integer" isForeignKey="1"/>
<column name="exercise_id" datatype="integer"/>
<column name="participant_id" datatype="integer"/>
<constraint name="UQ_aircraft_participant_id" type="unique">
<column name="id"/>
</constraint>
<foreignKey name="FK_aircraft_participant_nasat_aircraft">
<source table="nasat_aircraft_participant" column="nasat_aircraft_id"/>
<destination table="nasat_aircraft" column="id"/>
</foreignKey>
</table>
</tables>
<views/>
<dbServiceStructs>
<serviceStruct name="NasatAircraft" table="nasat_aircraft"/>
<serviceStruct name="NasatAircraftParticipant" table="nasat_aircraft_participant"/>
<table name="nasat_aircraft"/>
<table name="nasat_aircraft_participant"/>
</dbServiceStructs>
<enumerations>
<enumeration name="Hdg2InitialPointMode">
<attribute key="Undefined" value="0"/>
<attribute key="UseHdgIP2Target_1" value="1"/>
<attribute key="UseHdgIP2Target_2" value="2"/>
<attribute key="KeyholeA" value="11"/>
<attribute key="KeyholeB" value="12"/>
<attribute key="KeyholeC" value="13"/>
<attribute key="KeyholeD" value="14"/>
</enumeration>
</enumerations>
</service>
+455
View File
@@ -0,0 +1,455 @@
/**
* Telegrams between NASAT and GUEZ
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLE, 2019-09-18
*/
#include "guez_nasat_telegrams.h"
#include <QJsonDocument>
#include <QJsonObject>
namespace GuezNasat
{
//
// Helpers
//
JsonException::JsonException(const QJsonObject &obj, const QString &key)
: m_obj(obj)
, m_key(key)
, m_what("Could not find key '" + key.toUtf8() + "' in json ('" + QJsonDocument(obj).toJson(QJsonDocument::Compact) + "')")
{}
template <typename E>
QJsonValue enumToJson(E e)
{
static_assert (std::is_enum<E>::value, "Only useable with enumerations");
return static_cast<int>(e);
}
template <typename T>
bool get(const QJsonObject &obj, const QString &key, T &val, bool bOptional = false)
{
if (bOptional)
{
try
{
val = T::fromJson(obj[key].toObject());
}
catch (const JsonException &e)
{
Q_UNUSED(e);
return false;
}
}
else
val = T::fromJson(obj[key].toObject());
return true;
}
// POD getter
template <>
bool get(const QJsonObject &obj, const QString &key, bool &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isBool())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toBool();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, int &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isDouble())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toInt();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, double &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isDouble())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toDouble();
return true;
}
//
// enum getter
//
// FinalAttackHeadingMode
template <>
bool get(const QJsonObject &obj, const QString &key, FinalAttackHeadingMode &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<FinalAttackHeadingMode>(iVal))
{
case FinalAttackHeadingMode::None:
case FinalAttackHeadingMode::HeadingOnly:
case FinalAttackHeadingMode::HeadingWithSector:
val = static_cast<FinalAttackHeadingMode>(iVal);
return true;
}
throw JsonException(obj, key);
}
// FuseType
template <>
bool get(const QJsonObject &obj, const QString &key, FuseType &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<FuseType>(iVal))
{
case FuseType::Undefined:
case FuseType::Instant:
case FuseType::Delay:
case FuseType::AirBurst:
val = static_cast<FuseType>(iVal);
return true;
}
throw JsonException(obj, key);
}
// Heading2InitialPointMode
template <>
bool get(const QJsonObject &obj, const QString &key, Heading2InitialPointMode &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<Heading2InitialPointMode>(iVal))
{
case Heading2InitialPointMode::Undefined:
case Heading2InitialPointMode::UseHdgIP2Target_1:
case Heading2InitialPointMode::UseHdgIP2Target_2:
case Heading2InitialPointMode::KeyholeA:
case Heading2InitialPointMode::KeyholeB:
case Heading2InitialPointMode::KeyholeC:
case Heading2InitialPointMode::KeyholeD:
val = static_cast<Heading2InitialPointMode>(iVal);
return true;
}
throw JsonException(obj, key);
}
// Heading2InitialPointMode
template <>
bool get(const QJsonObject &obj, const QString &key, Munition &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<Munition>(iVal))
{
case Munition::Undefined:
case Munition::Gun:
case Munition::Missile_AGM114:
case Munition::Missile_AGM65:
case Munition::Missile_MK151:
case Munition::Missile_MK24:
case Munition::Bomb_MK82LD:
case Munition::Bomb_MK83LD:
case Munition::Bomb_MK84LD:
case Munition::Bomb_MK82HD:
case Munition::Bomb_MK83HD:
case Munition::Bomb_MK84HD:
case Munition::PGM_500lb:
case Munition::PGM_1000lb:
case Munition::PGM_2000lb:
case Munition::Bomb_MK82_Unguided:
case Munition::Bomb_MK83_Unguided:
case Munition::Bomb_MK84_Unguided:
case Munition::PGM_GBU12:
case Munition::PGM_GBU24:
case Munition::PGM_GBU31:
case Munition::PGM_GBU32:
case Munition::PGM_GBU35:
case Munition::PGM_GBU38:
case Munition::PGM_GBU49:
case Munition::PGM_GBU54:
case Munition::PGM_BLU109:
case Munition::MSL_AGM_114K:
case Munition::MSL_AGM_114M:
case Munition::MSL_AGM_114N:
case Munition::MSL_AGM_114FA:
case Munition::MSL_AGM_65:
case Munition::GUN_FW20:
case Munition::GUN_FW25:
case Munition::GUN_20mm:
case Munition::Missile_MK_151:
case Munition::Missile_MK229:
case Munition::Missile_MK261:
case Munition::Missile_MK151LowALT:
case Munition::Missile_MK229LowALT:
case Munition::Missile_MK261LowALT:
case Munition::Missile_MK_24:
val = static_cast<Munition>(iVal);
return true;
}
throw JsonException(obj, key);
}
// Heading2InitialPointMode
template <>
bool get(const QJsonObject &obj, const QString &key, ReleaseMode &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<ReleaseMode>(iVal))
{
case ReleaseMode::Undefined:
case ReleaseMode::Manual:
case ReleaseMode::Automatic:
val = static_cast<ReleaseMode>(iVal);
return true;
}
throw JsonException(obj, key);
}
// Heading2InitialPointMode
template <>
bool get(const QJsonObject &obj, const QString &key, TimeForTargetMode &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<TimeForTargetMode>(iVal))
{
case TimeForTargetMode::None:
case TimeForTargetMode::TimeToTarget:
case TimeForTargetMode::TimeOverTarget:
val = static_cast<TimeForTargetMode>(iVal);
return true;
}
throw JsonException(obj, key);
}
//
// GeoPosition2D
//
QJsonObject GeoPosition2D::toJson() const
{
return QJsonObject({{QStringLiteral("lat"), lat},
{QStringLiteral("lon"), lon},
});
}
GeoPosition2D GeoPosition2D::fromJson(const QJsonObject &obj)
{
GeoPosition2D ret;
get(obj, QStringLiteral("lat"), ret.lat);
get(obj, QStringLiteral("lon"), ret.lon);
return ret;
}
//
// GeoPosition3D
//
QJsonObject GeoPosition3D::toJson() const
{
return QJsonObject({{QStringLiteral("lat"), lat},
{QStringLiteral("lon"), lon},
{QStringLiteral("height"), height},
});
}
GeoPosition3D GeoPosition3D::fromJson(const QJsonObject &obj)
{
GeoPosition3D ret;
get(obj, QStringLiteral("lat"), ret.lat);
get(obj, QStringLiteral("lon"), ret.lon);
get(obj, QStringLiteral("height"), ret.height);
return ret;
}
//
// NasatSimulationRequest
//
QJsonObject NasatSimulationRequest::toJson() const
{
return QJsonObject({{QStringLiteral("aircraftId"), aircraftId},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("position"), position.toJson()},
{QStringLiteral("enableSimulation"), enableSimulation},
});
}
NasatSimulationRequest NasatSimulationRequest::fromJson(const QJsonObject &obj)
{
NasatSimulationRequest ret;
get(obj, QStringLiteral("aircraftId"), ret.aircraftId);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("position"), ret.position);
get(obj, QStringLiteral("enableSimulation"), ret.enableSimulation);
return ret;
}
//
// NasatSimulationStatus
//
QJsonObject NasatSimulationStatus::toJson() const
{
return QJsonObject({{QStringLiteral("aircraftId"), aircraftId},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("simulationEnabled"), simulationEnabled},
});
}
NasatSimulationStatus NasatSimulationStatus::fromJson(const QJsonObject &obj)
{
NasatSimulationStatus ret;
get(obj, QStringLiteral("aircraftId"), ret.aircraftId);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("simulationEnabled"), ret.simulationEnabled);
return ret;
}
//
// NasatPosition
//
QJsonObject NasatPosition::toJson() const
{
return QJsonObject({{QStringLiteral("aircraftId"), aircraftId},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("position"), position.toJson()},
});
}
NasatPosition NasatPosition::fromJson(const QJsonObject &obj)
{
NasatPosition ret;
get(obj, QStringLiteral("aircraftId"), ret.aircraftId);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("position"), ret.position);
return ret;
}
//
// NasatWeaponRelease
//
QJsonObject NasatWeaponRelease::toJson() const
{
return QJsonObject({{QStringLiteral("aircraftId"), aircraftId},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("impactPosition"), impactPosition.toJson()},
{QStringLiteral("flightTime"), flightTime},
{QStringLiteral("munition"), enumToJson(munition)},
{QStringLiteral("fuseType"), enumToJson(fuseType)},
{QStringLiteral("releaseMode"), enumToJson(releaseMode)},
});
}
NasatWeaponRelease NasatWeaponRelease::fromJson(const QJsonObject &obj)
{
NasatWeaponRelease ret;
get(obj, QStringLiteral("aircraftId"), ret.aircraftId);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("impactPosition"), ret.impactPosition);
get(obj, QStringLiteral("flightTime"), ret.flightTime);
get(obj, QStringLiteral("munition"), ret.munition);
get(obj, QStringLiteral("fuseType"), ret.fuseType);
get(obj, QStringLiteral("releaseMode"), ret.releaseMode);
return ret;
}
//
// NasatNineLiner
//
QJsonObject NasatNineLiner::Friendlies::toJson() const
{
return QJsonObject({{QStringLiteral("bearing"), bearing},
{QStringLiteral("distance"), distance},
});
}
NasatNineLiner::Friendlies NasatNineLiner::Friendlies::fromJson(const QJsonObject &obj)
{
Friendlies ret;
get(obj, QStringLiteral("bearing"), ret.bearing);
get(obj, QStringLiteral("distance"), ret.distance);
return ret;
}
QJsonObject NasatNineLiner::FinalAttackHeading::toJson() const
{
return QJsonObject({{QStringLiteral("heading"), heading},
{QStringLiteral("headingLow"), headingLow},
{QStringLiteral("headingHigh"), headingHigh},
});
}
NasatNineLiner::FinalAttackHeading NasatNineLiner::FinalAttackHeading::fromJson(const QJsonObject &obj)
{
FinalAttackHeading ret;
get(obj, QStringLiteral("heading"), ret.heading);
get(obj, QStringLiteral("headingLow"), ret.headingLow);
get(obj, QStringLiteral("headingHigh"), ret.headingHigh);
return ret;
}
QJsonObject NasatNineLiner::toJson() const
{
return QJsonObject({{QStringLiteral("aircraftId"), aircraftId},
{QStringLiteral("timestamp"), timestamp},
{QStringLiteral("initialPoint"), initialPoint.toJson()},
{QStringLiteral("initialPointMode"), initialPointMode},
{QStringLiteral("headingInitialPoint2Target"), headingInitialPoint2Target},
{QStringLiteral("heading2InitialPointMode"), enumToJson(heading2InitialPointMode)},
{QStringLiteral("distanceInitialPoint2Target"), distanceInitialPoint2Target},
{QStringLiteral("distance2InitialPointMode"), distance2InitialPointMode},
{QStringLiteral("targetPosition"), targetPosition.toJson()},
{QStringLiteral("targetPositionMode"), targetPositionMode},
{QStringLiteral("altitudeTarget"), altitudeTarget},
{QStringLiteral("altitudeTargetMode"), altitudeTargetMode},
{QStringLiteral("friendlies"), friendlies.toJson()},
{QStringLiteral("modeFriendlies"), modeFriendlies},
{QStringLiteral("finalAttackHeading"), finalAttackHeading.toJson()},
{QStringLiteral("finalAttackHeadingMode"), enumToJson(finalAttackHeadingMode)},
{QStringLiteral("timeForTarget"), timeForTarget},
{QStringLiteral("timeForTargetMode"), enumToJson(timeForTargetMode)},
});
}
NasatNineLiner NasatNineLiner::fromJson(const QJsonObject &obj)
{
NasatNineLiner ret;
get(obj, QStringLiteral("aircraftId"), ret.aircraftId);
get(obj, QStringLiteral("timestamp"), ret.timestamp);
get(obj, QStringLiteral("initialPoint"), ret.initialPoint, true);
get(obj, QStringLiteral("initialPointMode"), ret.initialPointMode, true);
get(obj, QStringLiteral("headingInitialPoint2Target"), ret.headingInitialPoint2Target);
get(obj, QStringLiteral("heading2InitialPointMode"), ret.heading2InitialPointMode);
get(obj, QStringLiteral("distanceInitialPoint2Target"), ret.distanceInitialPoint2Target, true);
get(obj, QStringLiteral("distance2InitialPointMode"), ret.distance2InitialPointMode, true);
get(obj, QStringLiteral("targetPosition"), ret.targetPosition, true);
get(obj, QStringLiteral("targetPositionMode"), ret.targetPositionMode, true);
get(obj, QStringLiteral("altitudeTarget"), ret.altitudeTarget, true);
get(obj, QStringLiteral("altitudeTargetMode"), ret.altitudeTargetMode, true);
get(obj, QStringLiteral("friendlies"), ret.friendlies, true);
get(obj, QStringLiteral("modeFriendlies"), ret.modeFriendlies, true);
get(obj, QStringLiteral("finalAttackHeading"), ret.finalAttackHeading);
get(obj, QStringLiteral("finalAttackHeadingMode"), ret.finalAttackHeadingMode);
get(obj, QStringLiteral("timeForTarget"), ret.timeForTarget);
get(obj, QStringLiteral("timeForTargetMode"), ret.timeForTargetMode);
return ret;
}
} // namespace GuezNasat
+282
View File
@@ -0,0 +1,282 @@
/**
* Telegrams between NASAT and GUEZ
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLE, 2019-09-18
*/
#pragma once
#include <cstdint>
#include <exception>
#include <QJsonObject>
#include <QString>
namespace GuezNasat
{
class JsonException final : public std::exception
{
public:
JsonException(const QJsonObject &obj, const QString &key);
const char *what() const noexcept override { return m_what.data(); }
private:
QJsonObject m_obj;
QString m_key;
QByteArray m_what;
};
template <typename T>
struct Constraints;
//
// Enumerations
//
enum class FinalAttackHeadingMode
{
None = 0,
HeadingOnly = 1,
HeadingWithSector = 2,
};
enum class FuseType
{
Undefined = 0,
Instant = 1,
Delay = 2,
AirBurst = 3,
};
enum class Heading2InitialPointMode
{
Undefined = 0,
UseHdgIP2Target_1 = 1,
UseHdgIP2Target_2 = 2,
KeyholeA = 11,
KeyholeB = 12,
KeyholeC = 13,
KeyholeD = 14,
};
enum class Munition
{
Undefined = 0,
Gun = 1,
Missile_AGM114 = 2,
Missile_AGM65 = 3,
Missile_MK151 = 4,
Missile_MK24 = 5,
Bomb_MK82LD = 6,
Bomb_MK83LD = 7,
Bomb_MK84LD = 8,
Bomb_MK82HD = 9,
Bomb_MK83HD = 10,
Bomb_MK84HD = 11,
PGM_500lb = 12,
PGM_1000lb = 13,
PGM_2000lb = 14,
Bomb_MK82_Unguided = 15,
Bomb_MK83_Unguided = 16,
Bomb_MK84_Unguided = 17,
PGM_GBU12 = 18,
PGM_GBU24 = 19,
PGM_GBU31 = 20,
PGM_GBU32 = 21,
PGM_GBU35 = 22,
PGM_GBU38 = 23,
PGM_GBU49 = 24,
PGM_GBU54 = 25,
PGM_BLU109 = 26,
MSL_AGM_114K = 27,
MSL_AGM_114M = 28,
MSL_AGM_114N = 29,
MSL_AGM_114FA = 30,
MSL_AGM_65 = 31,
GUN_FW20 = 32,
GUN_FW25 = 33,
GUN_20mm = 34,
Missile_MK_151 = 35, // impact radius 125
Missile_MK229 = 36,
Missile_MK261 = 37,
Missile_MK151LowALT = 38,
Missile_MK229LowALT = 39,
Missile_MK261LowALT = 40,
Missile_MK_24 = 41 // impact radius 125
};
enum class ReleaseMode
{
Undefined = 0,
Manual = 1,
Automatic = 2,
};
enum class TimeForTargetMode
{
None = 0,
TimeToTarget = 1,
TimeOverTarget = 2,
};
//
// Structs
//
// ------------------------------------------------------------------
struct GeoPosition2D
{
double lat = 0; // in degree, WGS-84
double lon = 0; // in degree, WGS-84
static GeoPosition2D fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
// ------------------------------------------------------------------
struct GeoPosition3D final : public GeoPosition2D
{
double height = 0; // above MSL
static GeoPosition3D fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
// ------------------------------------------------------------------
struct NasatBase
{
int aircraftId = 0;
double timestamp = 0; // in sec since 01.01.1970
virtual ~NasatBase() = default;
virtual QJsonObject toJson() const = 0;
virtual QString type() const = 0;
};
// ------------------------------------------------------------------
template <typename T>
struct NasatBaseTmpl : NasatBase
{
QString type() const override final { return Constraints<T>::type(); }
};
// ------------------------------------------------------------------
struct NasatSimulationRequest final : public NasatBaseTmpl<NasatSimulationRequest>
{
GeoPosition2D position;
bool enableSimulation = false;
// conversion functions
static NasatSimulationRequest fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<NasatSimulationRequest>
{
static QString type() { return QStringLiteral("NasatSimulationRequest"); }
};
// ------------------------------------------------------------------
struct NasatSimulationStatus final : public NasatBaseTmpl<NasatSimulationStatus>
{
bool simulationEnabled = false;
// conversion functions
static NasatSimulationStatus fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<NasatSimulationStatus>
{
static QString type() { return QStringLiteral("NasatSimulationStatus"); }
};
// ------------------------------------------------------------------
struct NasatPosition final : public NasatBaseTmpl<NasatPosition>
{
GeoPosition3D position;
// conversion functions
static NasatPosition fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<NasatPosition>
{
static QString type() { return QStringLiteral("NasatPosition"); }
};
// ------------------------------------------------------------------
struct NasatWeaponRelease final : public NasatBaseTmpl<NasatWeaponRelease>
{
GeoPosition2D impactPosition;
double flightTime = 0;
Munition munition = Munition::Undefined;
FuseType fuseType = FuseType::Undefined;
ReleaseMode releaseMode = ReleaseMode::Undefined;
// conversion functions
static NasatWeaponRelease fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<NasatWeaponRelease>
{
static QString type() { return QStringLiteral("NasatWeaponRelease"); }
};
// ------------------------------------------------------------------
struct NasatNineLiner final : public NasatBaseTmpl<NasatNineLiner>
{
struct Friendlies
{
int bearing = 0; // [degree], 0 <= bearing <= 360
double distance = 0; // [m]
// conversion functions
static Friendlies fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
struct FinalAttackHeading
{
int heading = 0; // [degree], 0 <= bearing <= 360
int headingLow = 0; // sector right, delta to heading
int headingHigh = 0; // sector left, delta to heading
// conversion functions
static FinalAttackHeading fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
};
GeoPosition2D initialPoint;
int initialPointMode = 0; // 0 if not defined in 9Liner
int headingInitialPoint2Target = 0; // [degree], 0 <= headingInitialPoint2Target <= 360
Heading2InitialPointMode heading2InitialPointMode = Heading2InitialPointMode::Undefined;
double distanceInitialPoint2Target = 0; // [m]
int distance2InitialPointMode = 0; // 0 if not defined in 9Liner
GeoPosition2D targetPosition;
int targetPositionMode = 0; // 0 if not defined in 9Liner
double altitudeTarget = 0; // [m], above MSL
int altitudeTargetMode = 0; // 0 if not defined in 9Liner
Friendlies friendlies;
int modeFriendlies = 0; // 0 if not defined in 9Liner
FinalAttackHeading finalAttackHeading;
FinalAttackHeadingMode finalAttackHeadingMode = FinalAttackHeadingMode::None;
int timeForTarget = 0; // relative [s] (TimeToTarget) / absolute since midnight (TimeOverTarget)
TimeForTargetMode timeForTargetMode = TimeForTargetMode::None;
// conversion functions
static NasatNineLiner fromJson(const QJsonObject &obj);
QJsonObject toJson() const override;
};
template <> struct Constraints<NasatNineLiner>
{
static QString type() { return QStringLiteral("NasatNineLiner"); }
};
}
+166
View File
@@ -0,0 +1,166 @@
/**
* Handle the mapping real aircraft <-> nasat configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-02
*/
#include "handler_nasat_aircraft.h"
#include "initialization.h"
#include "dds_handler.h"
#include "handler_nasat_aircraft_participant.h"
#include <GuezNasat/gna_db.h>
namespace GuezNasat
{
Database::NasatAircraft toDb(const NasatAircraft &dds)
{
Database::NasatAircraft ret;
ret.id = dds.id();
ret.nasatId = dds.nasatId();
ret.simulationActive = dds.simulationActive();
ret.name = QString::fromStdString(dds.name());
return ret;
}
NasatAircraft fromDb(const Database::NasatAircraft &db)
{
NasatAircraft ret;
ret.id(db.id);
ret.nasatId(db.nasatId);
ret.simulationActive(db.simulationActive);
ret.name(db.name.toStdString());
return ret;
}
HandlerNasatAircraft::HandlerNasatAircraft(Initialization *mainHandler)
: QObject()
, Interface::Fts::ModifyNasatAircraftRequestHandler(mainHandler->dds()->fts())
, m_mainHandler(mainHandler)
, m_dts(mainHandler->dds()->dts())
, m_fts(mainHandler->dds()->fts())
, m_db(mainHandler->db())
, m_logger(getLogger("HandlerNasatAircraft"))
{}
HandlerNasatAircraft::~HandlerNasatAircraft()
{
for (const auto &data : qAsConst(m_nasatAircrafts))
m_dts->removeNasatAircraftByKey(data.id());
}
bool HandlerNasatAircraft::init()
{
auto cb = [this](const Database::NasatAircraft & data)
{
auto dds(fromDb(data));
dds.simulationActive(false); // initial
emit activateNasatAircraftSimulation(data.nasatId, false);
m_nasatAircrafts[dds.id()] = dds;
m_dts->publish(dds);
};
m_db->select(cb);
return true;
}
int HandlerNasatAircraft::nasatIdFromNasatAircraftId(int nasatAircraftId) const
{
auto it = m_nasatAircrafts.find(nasatAircraftId);
if (it == m_nasatAircrafts.end())
return -1;
return it.value().nasatId();
}
void HandlerNasatAircraft::simulationStatusChanged(const NasatSimulationStatus &data)
{
flaFluSimulationChanged(data.aircraftId, data.simulationEnabled);
}
void HandlerNasatAircraft::flaFluSimulationChanged(int nasatId, bool bSimulationActive)
{
for (NasatAircraft &na : m_nasatAircrafts)
{
if (na.nasatId() != nasatId)
continue;
if (na.simulationActive() == bSimulationActive)
return;
na.simulationActive(bSimulationActive);
m_dts->publish(na);
return;
}
WARNING_LOG(m_logger) << "Got a flaFluSimulationChanged information but aircraft with id " << nasatId << " is not available";
}
void HandlerNasatAircraft::onModifyNasatAircraftRequest(const rti::core::SampleIdentity &cookie,
const NasatAircraft &request)
{
DEBUG_LOG(m_logger) << "onModifyNasatAircraftRequest: " << request;
auto ret = request.id() > 0 ? modifyNasatAircraftRequest(request) : createNasatAircraftRequest(request);
if (ret.error())
WARNING_LOG(m_logger) << ret();
m_fts->modifyNasatAircraftReply(cookie, ret);
}
Core::FunctionReplyObject HandlerNasatAircraft::createNasatAircraftRequest(const NasatAircraft &request)
{
// create
Database::NasatAircraft naDb(toDb(request));
naDb.id = 0;
if (!m_db->insert(naDb))
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not create Aircraft information - error inserting values in database"));
emit activateNasatAircraftSimulation(naDb.nasatId, naDb.simulationActive);
// Success, Send Topic to DDS
const auto nasatAircraftData(fromDb(naDb));
m_dts->publish(nasatAircraftData);
m_nasatAircrafts[naDb.id] = nasatAircraftData;
return Core::FunctionReplyObject(request.id());
}
Core::FunctionReplyObject HandlerNasatAircraft::modifyNasatAircraftRequest(const NasatAircraft &request)
{
auto it = m_nasatAircrafts.find(request.id());
if (it == m_nasatAircrafts.end())
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not modify Aircraft information - id %1 not found")).arg(request.id());
if (request.nasatId() == 0 && request.name().size() == 0)
{
// empty -> remove
if (!m_db->removeNasatAircraft(request.id()))
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not remove Aircraft information - error removing values from database"));
m_nasatAircrafts.erase(it);
m_mainHandler->nasatAircraftParticipant()->aircraftRemoved(request.id());
m_dts->removeNasatAircraftByKey(request.id());
if (it.value().simulationActive())
emit activateNasatAircraftSimulation(request.nasatId(), false);
return Core::FunctionReplyObject(request.id());
}
const int oldNasatId = it.value().nasatId();
// modify
Database::NasatAircraft naDb(toDb(request));
if (!m_db->update(naDb))
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not modify Aircraft information - error updating values in database"));
const bool simulationChanged = it.value().simulationActive() != request.simulationActive();
// Success, Send Topic to DDS
const auto nasatAircraftData(fromDb(naDb));
m_dts->publish(nasatAircraftData);
it.value() = nasatAircraftData;
if (request.nasatId() != oldNasatId)
emit nasatIdChanged(oldNasatId, naDb.nasatId);
if (simulationChanged)
emit activateNasatAircraftSimulation(naDb.nasatId, request.simulationActive());
return Core::FunctionReplyObject(request.id());
}
} // namespace GuezNasat
+54
View File
@@ -0,0 +1,54 @@
/**
* Handle the mapping real aircraft <-> nasat configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-02
*/
#pragma once
#include <QObject>
#include <QHash>
#include <GuezNasat/gna_dts.h>
#include <GuezNasat/gna_fts.h>
#include <GuezNasat/gna_db.h>
#include "logger.h"
#include "guez_nasat_telegrams.h"
namespace GuezNasat
{
class DatabaseInterface;
class Initialization;
class HandlerNasatAircraft final : public QObject
, protected Interface::Fts::ModifyNasatAircraftRequestHandler
{
Q_OBJECT
public:
explicit HandlerNasatAircraft(Initialization *mainHandler);
~HandlerNasatAircraft();
bool init();
int nasatIdFromNasatAircraftId(int nasatAircraftId) const;
public Q_SLOTS:
void simulationStatusChanged(const NasatSimulationStatus &data);
void flaFluSimulationChanged(int nasatId, bool bSimulationActive);
Q_SIGNALS:
void activateNasatAircraftSimulation(int nasatId, bool bActivateSimulation);
void nasatIdChanged(int oldNasatId, int newNasatId);
protected:
void onModifyNasatAircraftRequest(const rti::core::SampleIdentity &cookie,
const NasatAircraft &request) override;
Core::FunctionReplyObject createNasatAircraftRequest(const NasatAircraft &request);
Core::FunctionReplyObject modifyNasatAircraftRequest(const NasatAircraft &request);
private:
Initialization *m_mainHandler;
std::shared_ptr<GuezNasat::Interface::Dts> m_dts;
std::shared_ptr<GuezNasat::Interface::Fts> m_fts;
std::shared_ptr<DatabaseInterface> m_db;
QHash<int, NasatAircraft> m_nasatAircrafts;
NGL::INGLLogger &m_logger;
};
} // namespace GuezNasat
@@ -0,0 +1,334 @@
/**
* Handle the mapping real aircraft <-> participant in exercise
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-02
*/
#include "handler_nasat_aircraft_participant.h"
#include "handler_nasat_aircraft.h"
#include "initialization.h"
#include "dds_handler.h"
#include "handler_participant.h"
#include <GuezNasat/gna_db.h>
#include <QTimer>
namespace GuezNasat
{
Database::NasatAircraftParticipant toDb(const NasatAircraftParticipant &dds)
{
Database::NasatAircraftParticipant ret;
ret.id = dds.id();
ret.nasatAircraftId = dds.nasatAircraftId();
ret.exerciseId = dds.exerciseId();
ret.participantId = dds.participantId();
return ret;
}
NasatAircraftParticipant fromDb(const Database::NasatAircraftParticipant &db)
{
NasatAircraftParticipant ret;
ret.id(db.id);
ret.nasatAircraftId(db.nasatAircraftId);
ret.exerciseId(db.exerciseId);
ret.participantId(db.participantId);
return ret;
}
HandlerNasatAircraftParticipant::HandlerNasatAircraftParticipant(Initialization *mainHandler)
: QObject()
, Interface::Fts::ModifyNasatAircraftParticipantRequestHandler(mainHandler->dds()->fts())
, m_mainHandler(mainHandler)
, m_dts(mainHandler->dds()->dts())
, m_fts(mainHandler->dds()->fts())
, m_db(mainHandler->db())
, m_logger(getLogger("HandlerNasatAircraftParticipant"))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
HandlerNasatAircraftParticipant::~HandlerNasatAircraftParticipant()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
for (const auto &data : qAsConst(m_nasatAircraftParticipants))
m_dts->removeNasatAircraftByKey(data.id());
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
bool HandlerNasatAircraftParticipant::init()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
auto cb = [this](const Database::NasatAircraftParticipant & data)
{
const auto dds(fromDb(data));
DEBUG_LOG(m_logger) << "m_nasatAircraftParticipants.insert(" << dds.id() << ")";
m_nasatAircraftParticipants.insert(dds.id(), dds);
m_dts->publish(dds);
m_mainHandler->handlerParticipant()->onNasatAircraftParticipantCreated(dds);
};
m_db->select(cb);
// Most likely, the exercises are empty on normal startup of serviceManagement
// since ExerciseManagement is started later...
auto exmDtc = m_mainHandler->dds()->exmDtc();
connect(exmDtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged,
this, &HandlerNasatAircraftParticipant::onExerciseChanged, Qt::UniqueConnection);
exmDtc->exercises([this](const ExerciseManagement::Exercise &exercise) {
onExerciseChanged(exercise, DataModification::eAdded);
});
dumpNasatAircraftParticipants();
dumpExercises();
// exercises are started one by one. So try 30
QTimer::singleShot(30000, this, [this]() { // 30000 -> 30sec
dumpNasatAircraftParticipants();
dumpExercises();
});
DEBUG_LOG(m_logger) << "HandlerNasatAircraftParticipant init done";
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
return true;
}
void HandlerNasatAircraftParticipant::dumpNasatAircraftParticipants()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, size=" << m_nasatAircraftParticipants.size();
DEBUG_LOG(m_logger) << LOGFUNCTION << " --------------------------------------";
auto it = m_nasatAircraftParticipants.begin();
while (it != m_nasatAircraftParticipants.end())
{
const auto &id = it.key();
const auto &nap = it.value();
DEBUG_LOG(m_logger) << LOGFUNCTION << " id=" << id << " - nap=" << nap;
++it;
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " --------------------------------------";
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, size=" << m_nasatAircraftParticipants.size();
}
void HandlerNasatAircraftParticipant::dumpExercises()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, size=" << m_exercises.size();
DEBUG_LOG(m_logger) << LOGFUNCTION << " --------------------------------------";
auto it = m_exercises.begin();
while (it != m_exercises.end())
{
const auto &id = it.key();
const auto &nasatAircraftParticipant = it.value();
DEBUG_LOG(m_logger) << LOGFUNCTION << " id=" << id << " - nasatAircraftParticipant=" << nasatAircraftParticipant;
++it;
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " --------------------------------------";
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, size=" << m_exercises.size();
}
void HandlerNasatAircraftParticipant::aircraftRemoved(int nasatAircraftId)
{
auto it = m_nasatAircraftParticipants.begin();
while (it != m_nasatAircraftParticipants.end())
{
const auto &val = it.value();
if (val.nasatAircraftId() == nasatAircraftId)
{
removeNasatAircraftParticipant(val);
it = m_nasatAircraftParticipants.erase(it);
}
else
++it;
}
}
void HandlerNasatAircraftParticipant::participantRemoved(int exerciseId, int participantId)
{
DEBUG_LOG(m_logger) << "participantRemoved: " << exerciseId << ", " << participantId;
auto it = m_nasatAircraftParticipants.begin();
while (it != m_nasatAircraftParticipants.end())
{
const auto &val = it.value();
if (val.participantId() == participantId &&
val.exerciseId() == exerciseId)
{
removeNasatAircraftParticipant(val);
it = m_nasatAircraftParticipants.erase(it);
}
else
++it;
}
}
bool isExerciseStateValid(ExerciseManagement::ExerciseState_def::type state)
{
switch (state)
{
case ExerciseManagement::ExerciseState_def::Created:
case ExerciseManagement::ExerciseState_def::Paused:
case ExerciseManagement::ExerciseState_def::Started:
case ExerciseManagement::ExerciseState_def::Stopped:
return true;
case ExerciseManagement::ExerciseState_def::Unknown:
case ExerciseManagement::ExerciseState_def::Terminated:
return false;
}
return false;
}
void HandlerNasatAircraftParticipant::onExerciseChanged(const ExerciseManagement::Exercise &exercise, DataModification modType)
{
INFO_LOG(m_logger) << LOGFUNCTION << " START" << " , exercise" << exercise << " , modType" << modType;
const int exId = exercise.id();
switch (modType)
{
case DataModification::eAdded:
{
m_exercises[exId] = exercise;
const bool valid = isExerciseStateValid(exercise.state().underlying());
if (!valid)
{
INFO_LOG(m_logger) << LOGFUNCTION << " STATE of exId=" << exId
<< " , state=" << exercise.state();
int cnt = removeNapsOfExercise(exId);
INFO_LOG(m_logger) << LOGFUNCTION << " STATE of exId=" << exId << " not valid : counter of removed naps=" << cnt;
}
}
break;
case DataModification::eModified:
{
const ExerciseManagement::Exercise &exerciseRef = m_exercises[exId];
if (exerciseRef.state() != exercise.state())
{
const bool valid = isExerciseStateValid(exercise.state().underlying());
if (!valid)
{
INFO_LOG(m_logger) << LOGFUNCTION << " STATE change of exId=" << exId
<< " , old state=" << exerciseRef.state()
<< " , new state=" << exercise.state();
int cnt = removeNapsOfExercise(exId);
INFO_LOG(m_logger) << LOGFUNCTION << " STATE change of exId=" << exId << " : counter of removed naps=" << cnt;
}
}
m_exercises[exId] = exercise;
}
break;
case DataModification::eRemoved:
{
int cnt = removeNapsOfExercise(exId);
INFO_LOG(m_logger) << LOGFUNCTION << " STATE change of Exercise, counter of removed naps=" << cnt;
m_exercises.remove(exId);
}
break;
}
INFO_LOG(m_logger) << LOGFUNCTION << " END" << " , exercise" << exercise << " , modType" << modType;
}
void HandlerNasatAircraftParticipant::removeNasatAircraftParticipant(const NasatAircraftParticipant &val)
{
m_mainHandler->handlerParticipant()->onNasatAircraftParticipantRemoved(val);
// empty -> remove
m_db->removeNasatAircraftParticipant(val.id());
m_dts->removeNasatAircraftParticipantByKey(val.id());
}
void HandlerNasatAircraftParticipant::onModifyNasatAircraftParticipantRequest(const rti::core::SampleIdentity &cookie,
const NasatAircraftParticipant &request)
{
DEBUG_LOG(m_logger) << "onModifyNasatAircraftParticipantRequest: " << request;
auto ret = request.id() <= 0 ? createNasatAircraftParticipantRequest(request) : modifyNasatAircraftParticipantRequest(request);
if (ret.error())
WARNING_LOG(m_logger) << ret();
m_fts->modifyNasatAircraftParticipantReply(cookie, ret);
}
Core::FunctionReplyObject HandlerNasatAircraftParticipant::createNasatAircraftParticipantRequest(const NasatAircraftParticipant &request)
{
// create
Database::NasatAircraftParticipant napDb(toDb(request));
napDb.id = 0;
if (!m_db->insert(napDb))
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not create Aircraft Participant connection - error inserting values in database"));
// Success, Send Topic to DDS
const auto dds(fromDb(napDb));
m_dts->publish(dds);
m_nasatAircraftParticipants.insert(dds.id(), dds);
m_mainHandler->handlerParticipant()->onNasatAircraftParticipantCreated(request);
return Core::FunctionReplyObject(request.id());
}
Core::FunctionReplyObject HandlerNasatAircraftParticipant::modifyNasatAircraftParticipantRequest(const NasatAircraftParticipant &request)
{
auto it = m_nasatAircraftParticipants.find(request.id());
if (it == m_nasatAircraftParticipants.end())
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not modify Aircraft Participant connection - id %1 not found")).arg(request.id());
if (request == *it)
return Core::FunctionReplyObject(request.id());
if ((request.exerciseId() == 0 && request.participantId() == 0) ||
request.nasatAircraftId() == 0)
{
removeNasatAircraftParticipant(it.value());
m_nasatAircraftParticipants.erase(it);
return Core::FunctionReplyObject(request.id());
}
// modify
Database::NasatAircraftParticipant napDb(toDb(request));
if (!m_db->update(napDb))
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Can not modify Aircraft Participant connection - error updating values in database"));
// remove old subscriber
m_mainHandler->handlerParticipant()->onNasatAircraftParticipantRemoved(*it);
const auto dds(fromDb(napDb));
m_dts->publish(dds);
m_nasatAircraftParticipants.insert(dds.id(), dds);
// Success, Send Topic to DDS
m_dts->publish(fromDb(napDb));
// add new subscriber
m_mainHandler->handlerParticipant()->onNasatAircraftParticipantCreated(request);
return Core::FunctionReplyObject(request.id());
}
int HandlerNasatAircraftParticipant::removeNapsOfExercise(int exerciseId)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, exerciseId=" << exerciseId
<< ", m_nasatAircraftParticipants.size()" << m_nasatAircraftParticipants.size();
int count = 0;
QHash<int, NasatAircraftParticipant> napsCopy = m_nasatAircraftParticipants;
for (const NasatAircraftParticipant &nap : qAsConst(napsCopy))
{
if (nap.exerciseId() == exerciseId)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " nap has to be removed: nap=" << nap;
NasatAircraftParticipant napToTriggerRemoving;
napToTriggerRemoving.id(nap.id()); // to trigger removing
napToTriggerRemoving.exerciseId(0); // to trigger removing
napToTriggerRemoving.participantId(0); // to trigger removing
napToTriggerRemoving.nasatAircraftId(0); // to trigger removing
modifyNasatAircraftParticipantRequest(napToTriggerRemoving);
++count;
}
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, exerciseId=" << exerciseId
<< ", m_nasatAircraftParticipants.size()" << m_nasatAircraftParticipants.size()
<< ", counter=" << count;
return count;
}
} // namespace GuezNasat
+71
View File
@@ -0,0 +1,71 @@
/**
* Handle the mapping real aircraft <-> participant in exercise
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-02
*/
#pragma once
#include <QObject>
#include <QHash>
#include <GuezNasat/gna_dts.h>
#include <GuezNasat/gna_fts.h>
#include <ExerciseManagement/exm_dtc.h>
#include "logger.h"
namespace GuezNasat
{
class DatabaseInterface;
class Initialization;
/*!
* \brief The HandlerNasatAircraftParticipant class
* This class implements the create and mofify operation for association
* between NasatAircraft and Participant
* During exercise the user can link NasatAircraft and Participant.
* If the exercise is terminated a cleanup is done.
*/
class HandlerNasatAircraftParticipant final : public QObject
, protected Interface::Fts::ModifyNasatAircraftParticipantRequestHandler
{
Q_OBJECT
public:
explicit HandlerNasatAircraftParticipant(Initialization *mainHandler);
~HandlerNasatAircraftParticipant();
bool init();
public Q_SLOTS:
void aircraftRemoved(int nasatAircraftId);
void participantRemoved(int exerciseId, int participantId);
void onExerciseChanged(const ExerciseManagement::Exercise &exercise, DataModification modType);
void dumpNasatAircraftParticipants();
void dumpExercises();
protected:
void removeNasatAircraftParticipant(const NasatAircraftParticipant &val);
void onModifyNasatAircraftParticipantRequest(const rti::core::SampleIdentity &cookie,
const NasatAircraftParticipant &request) override;
Core::FunctionReplyObject createNasatAircraftParticipantRequest(const NasatAircraftParticipant &request);
Core::FunctionReplyObject modifyNasatAircraftParticipantRequest(const NasatAircraftParticipant &request);
// context Exercise:
int removeNapsOfExercise(int exerciseId);
private:
Initialization *m_mainHandler;
std::shared_ptr<GuezNasat::Interface::Dts> m_dts;
std::shared_ptr<GuezNasat::Interface::Fts> m_fts;
std::shared_ptr<DatabaseInterface> m_db;
QHash<int, NasatAircraftParticipant> m_nasatAircraftParticipants;
QHash<int, ExerciseManagement::Exercise> m_exercises;
NGL::INGLLogger &m_logger;
};
} // namespace GuezNasat
+297
View File
@@ -0,0 +1,297 @@
/**
* Handle an impact from nasat aircraft and create single explosion
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-30
*/
#include "handler_nasat_impact.h"
#include "initialization.h"
#include "dds_handler.h"
#include "handler_participant.h"
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include <ParticipantManagement/ppm_dtc.h>
#include <LtsCoordTrans/lts_coord_trans.h>
// #define TRIGGER_DUMMY_IMPACT
#ifdef TRIGGER_DUMMY_IMPACT
# include <QTimer>
#endif // TRIGGER_DUMMY_IMPACT
namespace GuezNasat
{
HandlerNasatImpact::HandlerNasatImpact(Initialization *mainHandler)
: AreaEffectSimulation::Interface::Ftc::AirSupportImpactModifyReplyHandler()
, m_mainHandler(mainHandler)
, m_logger(getLogger("HandlerNasatImpact"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
auto pdmDtc = m_mainHandler->dds()->pdmDtc();
connect(pdmDtc.get(), &ProjectDataManagement::Interface::Dtc::chargeTypeChanged,
this, &HandlerNasatImpact::onChargeTypeChanged);
pdmDtc->chargeTypes([this](const ProjectDataManagement::ChargeType &ct) { onChargeTypeChanged(ct);});
#ifdef TRIGGER_DUMMY_IMPACT
FATAL_LOG(m_logger) << LOGFUNCTION << " prepare singleShot...";
QTimer *timer = new QTimer;
timer->setInterval(30000);
connect(timer, &QTimer::timeout, [this] () {
FATAL_LOG(m_logger) << LOGFUNCTION << " singleShot...";
NasatWeaponRelease wr;
wr.aircraftId = 1;
GeoPosition2D geoPos;
geoPos.lon = 11.56; // degree
geoPos.lat = 52.46; // degree
wr.impactPosition = geoPos;
wr.flightTime = 5;
wr.munition = Munition::MSL_AGM_114K; // MSL_AGM_114K : 29 -> 499
// wr.munition = Munition::Missile_MK_24; // Missile_MK_24: 41 -> 511
wr.fuseType = FuseType::Instant;
wr.releaseMode = ReleaseMode::Undefined;
this->nasatWeaponRelease(wr);
FATAL_LOG(m_logger) << LOGFUNCTION << " singleShot...DONE";
});
timer->start();
#endif // TRIGGER_DUMMY_IMPACT
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void HandlerNasatImpact::onAirSupportImpactModifyReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
WARNING_LOG(m_logger) << "Could not create single explosion for nasat impact: " << reply();
#ifdef NLDEVCTRL_844
testing.replyCounter++;
INFO_LOG(m_logger) << "Got create reply: " << reply() << "(id=" << reply.id() << ")"
<< ", this=" << this
<< " - replyCounter=" << testing.replyCounter;
#else
INFO_LOG(m_logger) << "Got create reply: " << reply() << "(id=" << reply.id() << ")"
<< ", this=" << this;
#endif // NLDEVCTRL_844
}
void HandlerNasatImpact::onExplosionClusterModifyReply(const Core::FunctionReplyObject &reply)
{
INFO_LOG(m_logger) << "Got create reply: " << reply() << "(id=" << reply.id() << ")"
<< ", this=" << this
<< ", reply.error()=" << reply.error();
if (reply.error())
ERROR_LOG(m_logger) << "onExplosionClusterModifyReply: Got reply: " << reply() << "(id=" << reply.id() << ")"
<< " '" << reply.translated() << "'";
}
void HandlerNasatImpact::nasatWeaponRelease(const GuezNasat::NasatWeaponRelease &weaponRelease)
{
const Core::GeoPosition geoPos(weaponRelease.impactPosition.lon * LtsCoordTrans::deg2rad(),
weaponRelease.impactPosition.lat * LtsCoordTrans::deg2rad(),
0); // z == 0? Ground... TODO
double tsWeaponRelease = weaponRelease.timestamp < 0 ? QDateTime::currentSecsSinceEpoch() : weaponRelease.timestamp;
// AES needs time to execute a) calculations of trajectory and b) intersections ('preStartTimer')
// add 5sec, an additional period of time:
tsWeaponRelease += 5;
qint64 impactTimeMsec = qRound64((tsWeaponRelease + weaponRelease.flightTime) * 1000);
qint64 weaponReleaseMsec = qRound64(weaponRelease.flightTime * 1000);
nasatImpact(weaponRelease.aircraftId, geoPos, weaponReleaseMsec, impactTimeMsec, static_cast<int>(weaponRelease.munition), weaponRelease.fuseType);
}
void HandlerNasatImpact::nasatImpact(int nasatId, const Core::GeoPosition &pos, qint64 flightTimeMsec, qint64 impactTimeMsec, int munitionCode, FuseType fuseType)
{
#ifdef NLDEVCTRL_844
static bool bEnable = true;
if (!bEnable)
return;
#endif // NLDEVCTRL_844
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, nasatId=" << nasatId
<< ", pos=" << pos
<< ", flightTimeMsec = " << flightTimeMsec
<< ", impactTimeMsec = " << impactTimeMsec;
const auto participants = m_mainHandler->handlerParticipant()->participantsForNasatId(nasatId);
if (participants.isEmpty())
{
WARNING_LOG(m_logger) << "Can not find a valid participant for nasat aircraft with id " << nasatId;
return;
}
const int chargeTypeIdVal = chargeTypeFromMunitionCode(munitionCode);
if (chargeTypeIdVal < 0)
return;
const QDateTime dtNow = QDateTime::currentDateTime();
const qint64 tNow = dtNow.toMSecsSinceEpoch() + 5000; // 5s for Tetra - really needed?
AreaEffectSimulation::ExplosionClusterSingleEffectOnlyRequest ecReq;
ecReq.id(0);
ecReq.effectStart(impactTimeMsec > tNow ? impactTimeMsec : tNow); // msec
ecReq.name(QStringLiteral("NASAT_%1_%2_%3").arg(nasatId).arg(munitionCode).arg(dtNow.toString(QStringLiteral("dd hh:mm:ss"))).toStdString());
ecReq.element(ecReq.name());
ecReq.impactPosition(Core::GeoPosition2D(pos.lon(), pos.lat()));
ecReq.chargeTypeId(chargeTypeIdVal);
// ecReq.externalId(815);
// ecReq.flightTime(flightTime);
if (m_logger.isDebugEnabled())
{
const Core::GeoPosition &nasatPos = m_mainHandler->handlerParticipant()->nasatPosition(nasatId);
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, nasatId=" << nasatId
<< ", pos=" << nasatPos
<< ", flightTimeMsec = " << flightTimeMsec
<< ", impactTimeMsec=" << impactTimeMsec;
}
AreaEffectSimulation::ExplosionClusterModifyRequest ecCommonModifyRequest;
ecCommonModifyRequest.id(0);
ecCommonModifyRequest.effectStart(impactTimeMsec > tNow ? impactTimeMsec : tNow); // msec
ecCommonModifyRequest.effectDuration(1000);
ecCommonModifyRequest.effectSourceId(ProjectDataManagement::EffectSource::ES_Internal);
// charge and geometry:
ecCommonModifyRequest.explosionGeometry(AreaEffectSimulation::AesExplosionGeometry_def::EgPoint);
// ecCommonModifyRequest.zog(0);
ecCommonModifyRequest.chargeStruct().chargeTypeId(chargeTypeIdVal);
ecCommonModifyRequest.chargeStruct().igniterTypeId(fuseTypeToPdmIgniterType(fuseType));
ecCommonModifyRequest.area().cornerBottomLeft(Core::GeoPosition2D(pos.lon(), pos.lat()));
ecCommonModifyRequest.name(QStringLiteral("NASAT_%1_%2_%3").arg(nasatId).arg(munitionCode).arg(dtNow.toString(QStringLiteral("dd hh:mm:ss"))).toStdString());
ecCommonModifyRequest.element(ecReq.name());
ecCommonModifyRequest.mhpCount(1);
ecCommonModifyRequest.impactCount(1);
// ecCommonModifyRequest.partyId(request.partyId());
// ecCommonModifyRequest.participantId(-1); // -1 -> avoid trajectory
ecCommonModifyRequest.flightDuration(flightTimeMsec); // request.flightDuration in msec
// AreaEffectSimulation::AirSupportImpactModifyRequest asi;
// asi.name(QStringLiteral("NASAT_a%1_m%2_t%3").arg(nasatId).arg(munitionCode).arg(dtNow.toString(QStringLiteral("dd hh:mm:ss"))).toStdString());
// asi.effectStart(impactTimeMsec > tNow ? impactTimeMsec : tNow);
// asi.chargeTypeId(chargeTypeFromMunitionCode(munitionCode));
// if (asi.chargeTypeId() < 0)
// return;
// asi.impactPosition(Core::GeoPosition2D(pos.lon(), pos.lat()));
// asi.flightTime(flightTime);
DEBUG_LOG(m_logger) << " Sending air support impact: number of participant= " << participants.size();
for (const NasatAircraftParticipantEx *nap : participants)
{
// asi.partyId(nap->partyId());
// asi.participantId(nap->participantId());
ecReq.partyId(nap->partyId());
ecCommonModifyRequest.partyId(nap->partyId());
ecCommonModifyRequest.participantId(nap->participantId());
// ecCommonModifyRequest.externalId(nap->participantId()); // externalId -> would be like like HLA and means no trajectory
int success = nap->publisher()->publish(ecCommonModifyRequest, this);
if (success)
DEBUG_LOG(m_logger) << "Sending air support impact create request: " << ecReq << " to exercise " << nap->exerciseId()
<< ", nap=" << nap->participant()
<< " -> success = " << success;
else
ERROR_LOG(m_logger) << "Error on Sending air support impact create request: " << ecReq << " to exercise " << nap->exerciseId()
<< ", nap=" << nap->participant()
<< " -> success = " << success;
#ifdef NLDEVCTRL_844
testing.requestCounter++;
INFO_LOG(m_logger) << " requestCounter = " << testing.requestCounter;
#endif // NLDEVCTRL_844
}
#ifdef NLDEVCTRL_844
bool bOk = (testing.requestCounter - testing.replyCounter) < 23;
FATAL_LOG(m_logger) << " bOk= " << bOk
<< ", requestCounter = " << testing.requestCounter
<< ", replyCounter = " << testing.replyCounter;
if (!bOk)
{
FATAL_LOG(m_logger) << " bOk= " << bOk
<< ", requestCounter = " << testing.requestCounter
<< " -> DISABLE";
bEnable = false;
abort();
}
if (testing.requestCounter > 70)
{
FATAL_LOG(m_logger) << " bOk= " << bOk
<< ", requestCounter = " << testing.requestCounter
<< " -> RESTART";
exit(42); // trigger restart
}
#endif // NLDEVCTRL_844
}
void HandlerNasatImpact::onChargeTypeChanged(const ProjectDataManagement::ChargeType &ct)
{
const QJsonDocument doc(QJsonDocument::fromJson(QByteArray::fromRawData(ct.properties().c_str(), ct.properties().size())));
const QJsonObject obj(doc.object());
if (!obj.contains(QLatin1String("nasatId")))
return;
int nasatId = obj.value(QLatin1String("nasatId")).toInt();
if (nasatId == 0)
{
WARNING_LOG(m_logger) << "Found charge with an invalid property 'nasatId', id: " << ct.id();
return;
}
m_chargeMapping.insert(nasatId, ct.id());
}
int HandlerNasatImpact::chargeTypeFromMunitionCode(int nasatChargeCode) const
{
auto it = m_chargeMapping.find(nasatChargeCode);
if (it != m_chargeMapping.end())
return it.value();
WARNING_LOG(m_logger) << "Got unmapped nasat charge code " << nasatChargeCode;
Q_ASSERT(false);
return -1;
}
int HandlerNasatImpact::fuseTypeToPdmIgniterType(FuseType fusetype) const
{
// return = igniterTypeId from table pdm_igniter_type
switch (fusetype) {
case FuseType::Instant:
return 102; // Impact Default
case FuseType::Delay:
return 103; // Delay Default
case GuezNasat::FuseType::AirBurst:
return 101; // Proxmimity Default
default:
return 102;
}
}
} // namespace GuezNasat
+56
View File
@@ -0,0 +1,56 @@
/**
* Handle an impact from nasat aircraft and create single explosion
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-08-30
*/
#pragma once
#include <QHash>
#include <QObject>
#include <AreaEffectSimulation/aes_ftc.h>
#include <ProjectDataManagement/pdm.hpp>
#include "guez_nasat_telegrams.h"
#include "logger.h"
namespace GuezNasat
{
class Initialization;
class HandlerNasatImpact final : public QObject
, protected AreaEffectSimulation::Interface::Ftc::AirSupportImpactModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler
{
Q_OBJECT
public:
explicit HandlerNasatImpact(Initialization *mainHandler);
bool init() const { return true; }
void onAirSupportImpactModifyReply(const Core::FunctionReplyObject &reply) override;
void onExplosionClusterModifyReply(const Core::FunctionReplyObject &reply) override;
public Q_SLOTS:
void nasatWeaponRelease(const GuezNasat::NasatWeaponRelease &weaponRelease);
void nasatImpact(int nasatId, const Core::GeoPosition &pos, qint64 flightTimeMsec, qint64 impactTimeMsec, int munitionCode, FuseType fuseType = FuseType::Instant);
void onChargeTypeChanged(const ProjectDataManagement::ChargeType &ct);
private:
int chargeTypeFromMunitionCode(int nasatChargeCode) const;
int fuseTypeToPdmIgniterType(FuseType fusetype) const;
private:
Initialization *m_mainHandler;
QHash<int, int> m_chargeMapping; // nasatId -> chargeId
NGL::INGLLogger &m_logger;
//#define NLDEVCTRL_844
#ifdef NLDEVCTRL_844
struct ForTesting
{
int requestCounter{0};
int replyCounter{0};
};
ForTesting testing;
#endif // NLDEVCTRL_844
};
} // namespace GuezNasat
+224
View File
@@ -0,0 +1,224 @@
/**
* Handle a nine-liner from a nasat aircraft and publish them
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2019-12-01
*/
#include "handler_nasat_nine_liner.h"
#include "handler_nasat_aircraft.h"
#include "handler_nasat_aircraft_participant.h"
#include "handler_participant.h"
#include "initialization.h"
#include "dds_handler.h"
#include <QDateTime>
#include <LtsCoordTrans/lts_coord_trans.h>
namespace GuezNasat
{
HandlerNasatNineLiner::HandlerNasatNineLiner(Initialization *mainHandler)
: m_mainHandler(mainHandler)
, m_logger(getLogger("HandlerNasatNineLiner"))
{}
bool HandlerNasatNineLiner::init() const
{
// if an association between nasatAircraftId and participant) is removed
// Planning | Assign NASAT Aircrafts) the associated NineLiner should also be removed:
connect(m_mainHandler->handlerParticipant().get(), &HandlerParticipant::nasatAircraftParticipantRemoved,
this, &HandlerNasatNineLiner::onNasatAircraftParticipantRemoved, Qt::DirectConnection);
DEBUG_LOG(m_logger) << "HandlerNasatNineLiner init done";
// currently we don't read old 9-liner data from the database to publish
// them again on restart - too much work without any real gain.
return true;
}
static Nasat9Liner createDds9Liner(const NasatNineLiner &nasatNineLiner)
{
Nasat9Liner nl;
const qint64 tsMSec = nasatNineLiner.timestamp <= 0 ? QDateTime::currentMSecsSinceEpoch() : qRound64(nasatNineLiner.timestamp * 1000);
nl.sampleTime(tsMSec);
if (nasatNineLiner.initialPointMode != 0)
nl.initialPoint(Core::GeoPosition2D(LtsCoordTrans::deg2rad() * nasatNineLiner.initialPoint.lon,
LtsCoordTrans::deg2rad() * nasatNineLiner.initialPoint.lat));
if (nasatNineLiner.heading2InitialPointMode != Heading2InitialPointMode::Undefined)
{
nl.hdg2InitialPointMode(static_cast<Hdg2InitialPointMode::inner_enum>(nasatNineLiner.heading2InitialPointMode));
nl.hdgInitialPoint2Target(nasatNineLiner.headingInitialPoint2Target);
}
else
{
nl.hdg2InitialPointMode(Hdg2InitialPointMode_def::Undefined);
nl.hdgInitialPoint2Target(-1);
}
if (nasatNineLiner.distance2InitialPointMode != 0)
nl.distanceInitialPoint2Target(nasatNineLiner.distanceInitialPoint2Target);
else
nl.distanceInitialPoint2Target(-1);
if (nasatNineLiner.targetPositionMode != 0)
{
const auto z = nasatNineLiner.altitudeTargetMode != 0 ? nasatNineLiner.altitudeTarget : -1;
nl.targetPosition(Core::GeoPosition(LtsCoordTrans::deg2rad() * nasatNineLiner.targetPosition.lon,
LtsCoordTrans::deg2rad() * nasatNineLiner.targetPosition.lat,
z));
}
else
{
nl.targetPosition(Core::GeoPosition(std::nan(""), std::nan(""), std::nan("")));
}
if (nasatNineLiner.modeFriendlies != 0)
{
nl.friendliesBearing(nasatNineLiner.friendlies.bearing);
nl.friendliesDistance(nasatNineLiner.friendlies.distance);
}
else
{
nl.friendliesBearing(-1);
nl.friendliesDistance(-1);
}
if (nasatNineLiner.finalAttackHeadingMode != FinalAttackHeadingMode::None)
{
nl.finalAttackHeading(nasatNineLiner.finalAttackHeading.heading);
if (nasatNineLiner.finalAttackHeadingMode == FinalAttackHeadingMode::HeadingWithSector)
{
nl.finalAttackHeadingLow(nasatNineLiner.finalAttackHeading.headingLow);
nl.finalAttackHeadingHigh(nasatNineLiner.finalAttackHeading.headingHigh);
}
else
{
nl.finalAttackHeadingLow(-1);
nl.finalAttackHeadingHigh(-1);
}
}
else
nl.finalAttackHeading(-1);
if (nasatNineLiner.timeForTargetMode != TimeForTargetMode::None)
nl.timeForTarget(nasatNineLiner.timeForTargetMode == TimeForTargetMode::TimeToTarget ? -nl.timeForTarget() : nl.timeForTarget());
else
nl.timeForTarget(0);
return nl;
}
void HandlerNasatNineLiner::nineLinerReceived(const NasatNineLiner &nasatNineLiner)
{
// QHash<ExerciseParticipantKey, NasatAircraftParticipantEx>>
DEBUG_LOG(m_logger) << "nineLinerReceived, aircraftId=" << nasatNineLiner.aircraftId
<< " - nasatNineLiner.aircraftId is aka nasatId";
const auto participants = m_mainHandler->handlerParticipant()->participantsForNasatId(nasatNineLiner.aircraftId);
if (participants.isEmpty())
{
INFO_LOG(m_logger) << "No exercise participants found to publish 9-liner for nasat aircraft with id "
<< nasatNineLiner.aircraftId;
return;
}
DEBUG_LOG(m_logger) << "nineLinerReceived, publishing to exercises";
static int s_id = 1;
Nasat9Liner nl = createDds9Liner(nasatNineLiner);
for (auto it = participants.begin(); it != participants.end(); ++it)
{
nl.id(s_id++);
const auto &exerciseParticipantId = it.key();
auto nape = it.value();
DEBUG_LOG(m_logger) << "nineLinerReceived, publishing to exercises, s_id=" << s_id
<< ", exerciseParticipantId.exerciseId=" << exerciseParticipantId.exerciseId
<< ", exerciseParticipantId.participantId=" << exerciseParticipantId.participantId;
auto &nineLinerParticipant = m_nineLiner[exerciseParticipantId];
nl.isCurrent(true);
nl.participantId(exerciseParticipantId.participantId);
nineLinerParticipant.push_back(nl);
// GUEZE-1676: Nineliner sollen zeitlich wie Trefferlinien angezeigt werden
// isCurrent is outdated
// if (nineLinerParticipant.size() > 1)
// {
// auto &oldLast = nineLinerParticipant[nineLinerParticipant.size() - 2];
// if (oldLast.sampleTime() > nl.sampleTime())
// {
// nineLinerParticipant.last().isCurrent(false); // in vector
// nl.isCurrent(false); // for publishing
// std::sort(nineLinerParticipant.begin(), nineLinerParticipant.end(),
// [](const Nasat9Liner & a, const Nasat9Liner & b) { return a.sampleTime() < b.sampleTime();});
// }
// else
// {
// // outdated
// oldLast.isCurrent(false); // in vector + for publishing
// oldLast.sampleTime(QDateTime::currentMSecsSinceEpoch()); // update sample_time for proper replay
// nape->publisher()->publish(oldLast);
// }
// }
nape->publisher()->publish(nl);
}
}
void HandlerNasatNineLiner::onNasatAircraftParticipantRemoved(const NasatAircraftParticipant &nap)
{
// don´t know, how to remove the samples from dds.
// -> set to isCurrent(false)...
const int nasatId = m_mainHandler->nasatAircraft()->nasatIdFromNasatAircraftId(nap.nasatAircraftId());
INFO_LOG(m_logger) << " onNasatAircraftParticipantRemoved, nap = " << nap << ", nasatId = " << nasatId;
if (nasatId < 0)
{
WARNING_LOG(m_logger) << " nasatIdFromNasatAircraftId failed, nap=" << nap;
return;
}
const auto participants = m_mainHandler->handlerParticipant()->participantsForNasatId(nasatId);
if (participants.isEmpty())
{
INFO_LOG(m_logger) << "No exercise participants found to publish 9-liner for nasat aircraft with id "
<< nap.nasatAircraftId();
return;
}
for (auto it = participants.begin(); it != participants.end(); ++it)
{
const auto &exerciseParticipantId = it.key();
auto nape = it.value();
auto &nineLinerParticipant = m_nineLiner[exerciseParticipantId];
DEBUG_LOG(m_logger) << LOGFUNCTION << " updating for removing "
<< ", exerciseParticipantId.exerciseId=" << exerciseParticipantId.exerciseId
<< ", exerciseParticipantId.participantId=" << exerciseParticipantId.participantId
<< ", nineLinerParticipant.isEmpty()=" << nineLinerParticipant.isEmpty();
if (!nineLinerParticipant.isEmpty())
{
auto &oldLast = nineLinerParticipant.last();
if (oldLast.isCurrent())
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " updating for removing "
<< ", exerciseParticipantId.exerciseId=" << exerciseParticipantId.exerciseId
<< ", exerciseParticipantId.participantId=" << exerciseParticipantId.participantId;
oldLast.sampleTime(QDateTime::currentMSecsSinceEpoch()); // update sample_time for proper replay
oldLast.isCurrent(false); // in vector - will suppress the according situation map object
nape->publisher()->publish(oldLast);
}
}
} // for
}
} // namespace GuezNasat
+38
View File
@@ -0,0 +1,38 @@
/**
* Handle a nine-liner from a nasat aircraft and publish them
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2019-12-01
*/
#pragma once
#include "guez_nasat_telegrams.h"
#include "handler_participant.h"
#include "logger.h"
#include <GuezNasat/gna_dtc.h>
#include <QHash>
#include <QObject>
namespace GuezNasat
{
class Initialization;
class HandlerNasatNineLiner final : public QObject
{
Q_OBJECT
public:
explicit HandlerNasatNineLiner(Initialization *mainHandler);
bool init() const;
public Q_SLOTS:
void nineLinerReceived(const NasatNineLiner &nasatNineLiner);
void onNasatAircraftParticipantRemoved(const NasatAircraftParticipant &nap);
private:
QHash<ExerciseParticipantKey, QVector<Nasat9Liner>> m_nineLiner;
Initialization *m_mainHandler;
NGL::INGLLogger &m_logger;
};
} // namespace GuezNasat
+199
View File
@@ -0,0 +1,199 @@
/**
* Handle the mapping real aircraft <-> nasat configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLSE, 2018-08-16
*/
#include "handler_participant.h"
#include "handler_nasat_aircraft.h"
#include "handler_nasat_aircraft_participant.h"
#include "initialization.h"
#include "dds_handler.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QTimer>
namespace GuezNasat
{
// ----------------------------------------------------------------
// NasatAircraftParticipantEx
// ----------------------------------------------------------------
NasatAircraftParticipantEx::NasatAircraftParticipantEx()
: m_logger(getLogger("NasatAircraftParticipantEx"))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
NasatAircraftParticipantEx::NasatAircraftParticipantEx(const NasatAircraftParticipant &nap, const std::shared_ptr<Participant2Dds> &publisher)
: m_nap(nap)
, m_publisher(publisher)
, m_logger(getLogger("NasatAircraftParticipantEx"))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
m_publisher->addParticipantToWatch(m_nap.participantId());
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
NasatAircraftParticipantEx::~NasatAircraftParticipantEx()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
m_publisher->removeParticipantToWatch(m_nap.participantId());
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
int NasatAircraftParticipantEx::partyId() const
{
return m_publisher ? m_publisher->partyId(participantId()) : -1;
}
// ----------------------------------------------------------------
// HandlerParticipant
// ----------------------------------------------------------------
HandlerParticipant::HandlerParticipant(Initialization *mainHandler)
: m_mainHandler(mainHandler)
, m_logger(getLogger("ParticipantPositionPublisher"))
{}
HandlerParticipant::~HandlerParticipant()
{
for (const auto &ex : qAsConst(m_activePublisher))
qDeleteAll(ex);
}
QHash<ExerciseParticipantKey, NasatAircraftParticipantEx *> HandlerParticipant::participantsForNasatId(int nasatId) const
{
return m_activePublisher.value(nasatId);
}
void HandlerParticipant::onNasatAircraftParticipantCreated(const NasatAircraftParticipant &nap)
{
const int nasatId = m_mainHandler->nasatAircraft()->nasatIdFromNasatAircraftId(nap.nasatAircraftId());
auto it = m_activePublisher.find(nasatId);
if (it == m_activePublisher.end())
return createNasatAircraftParticipant(nap, nasatId);
auto itParticipants = it.value().find(ExerciseParticipantKey(nap.exerciseId(), nap.participantId()));
if (itParticipants == it.value().end())
return createNasatAircraftParticipant(nap, nasatId);
}
void HandlerParticipant::onNasatAircraftParticipantRemoved(const NasatAircraftParticipant &nap)
{
const int nasatId = m_mainHandler->nasatAircraft()->nasatIdFromNasatAircraftId(nap.nasatAircraftId());
auto it = m_activePublisher.find(nasatId);
if (it == m_activePublisher.end())
{
WARNING_LOG(m_logger) << "No publisher for NasatAircraftParticipant " << nasatId << "(" << nap.nasatAircraftId() << ") found !?";
return;
}
auto itParticipants = it.value().find(ExerciseParticipantKey(nap.exerciseId(), nap.participantId()));
if (itParticipants == it.value().end())
{
WARNING_LOG(m_logger) << "No participant entry for NasatAircraftParticipant " << nasatId << "("
<< nap.exerciseId() << "," << nap.participantId() << ") found !?";
return;
}
// to enable removing of according Nasat9Liner:
DEBUG_LOG(m_logger) << " emit nasatAircraftParticipantRemoved, nap = " << nap;
emit nasatAircraftParticipantRemoved(nap);
DEBUG_LOG(m_logger) << "Remove position publisher for " << nap;
// spent time for samples to publish (UI: change link between aircraft and participant)
NasatAircraftParticipantEx* napeCopy= itParticipants.value();
if (napeCopy && napeCopy->publisher())
{
// do cleanup as like ~NasatAircraftParticipantEx
napeCopy->publisher()->removeParticipantToWatch(napeCopy->participantId());
}
QTimer::singleShot(2000, this, [napeCopy]() {
delete napeCopy;
});
it.value().erase(itParticipants);
if (it.value().isEmpty())
m_activePublisher.erase(it);
}
Core::GeoPosition HandlerParticipant::nasatPosition(int nasatId) const
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, nasatId=" << nasatId;
auto it = m_lastNasatPositionsAsCoreGeoposition.find(nasatId);
if (it == m_lastNasatPositionsAsCoreGeoposition.end())
{
INFO_LOG(m_logger) << "No NasatPosition for nasat id " << nasatId << " found";
return {};
}
return *it;
}
void HandlerParticipant::onNasatPosition(const NasatPosition &position)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, position.aircraftId=" << position.aircraftId;
const Core::GeoPosition geoPos(position.position.lon * LtsCoordTrans::deg2rad(),
position.position.lat * LtsCoordTrans::deg2rad(),
position.position.height); // heigth == aboveGround!?! (normally, 'height' is relative to ground)
const qint64 tsMSec = position.timestamp <= 0 ? QDateTime::currentMSecsSinceEpoch() : qRound64(position.timestamp * 1000);
onNasatAircraftPosition(position.aircraftId, geoPos, tsMSec);
m_lastNasatPositionsAsCoreGeoposition[position.aircraftId] = geoPos;
}
void HandlerParticipant::onNasatAircraftPosition(int nasatId, const Core::GeoPosition &pos, qint64 ts)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, nasatId=" << nasatId;
auto it = m_activePublisher.find(nasatId);
if (it == m_activePublisher.end())
{
INFO_LOG(m_logger) << "No position publisher for nasat id " << nasatId << " found - ignoring " << m_activePublisher.size();
return;
}
const auto &h = it.value();
TrainingAreaBase::EquipmentPosition tabPos;
tabPos.position().position(pos);
tabPos.sampleTime(ts);
for (const NasatAircraftParticipantEx *napEx : h)
{
tabPos.equipmentNumber(-napEx->participantId());
int success = napEx->publisher()->publish(tabPos);
if (success)
DEBUG_LOG(m_logger) << "Publishing positon: " << tabPos << " to exercise " << napEx->exerciseId()
<< ", napEx: " << napEx->participant()
<< " -> success = " << success;
else
ERROR_LOG(m_logger) << "Error on Publishing positon: " << tabPos << " to exercise " << napEx->exerciseId()
<< ", napEx: " << napEx->participant()
<< " -> success = " << success;
}
}
void HandlerParticipant::onNasatIdChanged(int oldNasatId, int newNasatId)
{
m_activePublisher[newNasatId] = m_activePublisher[oldNasatId];
m_activePublisher.remove(oldNasatId);
}
void HandlerParticipant::createNasatAircraftParticipant(const NasatAircraftParticipant &nap, int nasatId)
{
DEBUG_LOG(m_logger) << "Creating position publisher for " << nap
<< ", nasatId=" << nasatId;
auto *napEx = new NasatAircraftParticipantEx(nap,
m_mainHandler->dds()->ddsParticipant(nap.exerciseId()));
m_activePublisher[nasatId][ExerciseParticipantKey(nap.exerciseId(), nap.participantId())] = napEx;
connect(napEx->publisher().get(), &Participant2Dds::participantRemoved,
m_mainHandler->nasatAircraftParticipant().get(), &HandlerNasatAircraftParticipant::participantRemoved,
Qt::QueuedConnection);
}
} // namespace GuezNasat
+97
View File
@@ -0,0 +1,97 @@
/**
* Handle the mapping real aircraft <-> nasat configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLSE, 2018-08-16
*/
#pragma once
#include <QObject>
#include <QHash>
#include <GuezNasat/gna.hpp>
#include <ParticipantManagement/ppm_dtc_types.h>
#include "guez_nasat_telegrams.h"
#include "logger.h"
namespace GuezNasat
{
class Initialization;
class Participant2Dds;
struct NasatAircraftParticipantEx final
{
NasatAircraftParticipantEx();
explicit NasatAircraftParticipantEx(const NasatAircraftParticipant &nap,
const std::shared_ptr<Participant2Dds> &publisher);
~NasatAircraftParticipantEx();
std::shared_ptr<Participant2Dds> publisher() const { return m_publisher; }
int exerciseId() const { return m_nap.exerciseId(); }
int partyId() const;
int participantId() const { return m_nap.participantId(); }
const NasatAircraftParticipant &participant() const { return m_nap; }
Q_DISABLE_COPY(NasatAircraftParticipantEx)
private:
NasatAircraftParticipant m_nap;
std::shared_ptr<Participant2Dds> m_publisher;
NGL::INGLLogger &m_logger;
};
struct ExerciseParticipantKey
{
int exerciseId = 0;
int participantId = 0;
ExerciseParticipantKey() = default;
ExerciseParticipantKey(int e, int p)
: exerciseId(e), participantId(p) {}
bool operator ==(const ExerciseParticipantKey &o) const
{
return exerciseId == o.exerciseId && participantId == o.participantId;
}
};
inline uint qHash(ExerciseParticipantKey key, uint seed = 0)
{
return ::qHash((key.exerciseId << 16) + key.participantId, seed);
}
class HandlerParticipant : public QObject
{
Q_OBJECT
public:
explicit HandlerParticipant(Initialization *mainHandler);
~HandlerParticipant();
bool init() const { return true; }
// QHash<ExerciseParticipantKey, NasatAircraftParticipantEx>
QHash<ExerciseParticipantKey, NasatAircraftParticipantEx*> participantsForNasatId(int nasatId) const;
void onNasatAircraftParticipantCreated(const NasatAircraftParticipant &nap);
void onNasatAircraftParticipantRemoved(const NasatAircraftParticipant &nap);
Core::GeoPosition nasatPosition(int nasatId) const;
Q_SIGNALS:
void nasatAircraftParticipantRemoved(const NasatAircraftParticipant &nap);
public Q_SLOTS:
void onNasatPosition(const NasatPosition &position);
void onNasatAircraftPosition(int nasatId, const Core::GeoPosition &pos, qint64 ts);
void onNasatIdChanged(int oldNasatId, int newNasatId);
private:
void createNasatAircraftParticipant(const NasatAircraftParticipant &nap, int nasatId);
// QHash<nasatId, QHash<ExerciseParticipantKey, NasatAircraftParticipantEx>>
QHash<int, QHash<ExerciseParticipantKey, NasatAircraftParticipantEx*>> m_activePublisher;
// NasatId/AircraftId , GeoPosition
QHash<int, Core::GeoPosition> m_lastNasatPositionsAsCoreGeoposition;
Initialization *m_mainHandler;
NGL::INGLLogger &m_logger;
};
} // namespace GuezNasat
+188
View File
@@ -0,0 +1,188 @@
/**
* Initialization for GuezNasat
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-11-14
*/
#include "initialization.h"
#include "settings.h"
#include "dds_handler.h"
#include "handler_nasat_aircraft.h"
#include "handler_nasat_aircraft_participant.h"
#include "handler_nasat_impact.h"
#include "handler_nasat_nine_liner.h"
#include "handler_participant.h"
#include "tcp_socket_handler.h"
#include "web_socket_handler.h"
#include <GuezNasat/gna_db.h>
#include <DDS/DDSConnector/dds_connector.h>
#include <DDS/Core/pacemaker.h>
#include <QTimer>
namespace GuezNasat
{
Initialization::Initialization()
: m_logger(getLogger("Initialization"))
{
} // end of ctor()
//-----------------------------------------------------------------------------
Initialization::~Initialization()
{
m_jsonSocketHandler = nullptr;
m_handlerNasatAircraft = nullptr;
m_handlerNasatAircraftParticipant = nullptr;
m_handlerNasatImpact = nullptr;
m_handlerNasatNineLiner = nullptr;
m_handlerParticipant = nullptr;
m_ddsHandler = nullptr;
m_dbHandler = nullptr;
} // end of dtor()
//-----------------------------------------------------------------------------
bool Initialization::initialize(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
const QSqlDatabase &)
{
INFO_LOG(m_logger) << "Start GuezNasat Initialization.";
// initialize DDS
m_ddsHandler = std::make_shared<DdsHandler>(ddsConnector);
if (!m_ddsHandler->init())
{
ERROR_LOG(m_logger) << "Initialisation DdsHandler failed.";
return false;
}
// initialize database, we need an own DB connection
m_dbHandler = std::make_shared<DbHandler>();
if (!m_dbHandler->init(ddsConnector->getPartitionId(), Settings::settings()))
// if (!m_dbHandler->init(ddsConnector->getPartitionId(), sqlDb))
{
ERROR_LOG(m_logger) << "Initialisation DbHandler failed.";
return false;
}
// create HandlerNasatAircraft
m_handlerNasatAircraft.reset(new HandlerNasatAircraft(this));
// create HandlerNasatAircraftParticipant
m_handlerNasatAircraftParticipant.reset(new HandlerNasatAircraftParticipant(this));
// create HandlerNasatNineLiner
m_handlerNasatNineLiner.reset(new HandlerNasatNineLiner(this));
// create HandlerNasatAircraftParticipant
m_handlerNasatImpact.reset(new HandlerNasatImpact(this));
// create ParticipantPositionPublisher
m_handlerParticipant.reset(new HandlerParticipant(this));
// Connection to NASAT
if (Settings::useWebSocket())
{
INFO_LOG(m_logger) << "Using WebSocket";
m_jsonSocketHandler.reset(new WebSocketHandler);
}
else
{
INFO_LOG(m_logger) << "Using TcpSocket";
m_jsonSocketHandler.reset(new TcpSocketHandler);
}
INFO_LOG(m_logger) << "GuezNasat Initialization initialized";
return true;
} // end of init()
//-----------------------------------------------------------------------------
bool Initialization::loadFromDatabase()
{
TRACE_LOG(m_logger) << LOGFUNCTION << "START";
if (!m_ddsHandler ||
!m_dbHandler ||
!m_handlerNasatAircraft ||
!m_handlerNasatAircraftParticipant ||
!m_handlerNasatImpact ||
!m_handlerNasatNineLiner ||
!m_handlerParticipant ||
!m_jsonSocketHandler)
return false;
if (!m_handlerNasatAircraft->init())
{
ERROR_LOG(m_logger) << "Initialisation HandlerNasatAircraft failed.";
return false;
}
if (!m_handlerNasatAircraftParticipant->init())
{
ERROR_LOG(m_logger) << "Initialisation HandlerNasatAircraftParticipant failed.";
return false;
}
if (!m_handlerNasatImpact->init())
{
ERROR_LOG(m_logger) << "Initialisation HandlerNasatImpact failed.";
return false;
}
if (!m_handlerNasatNineLiner->init())
{
ERROR_LOG(m_logger) << "Initialisation HandlerNasatNineLiner failed.";
return false;
}
if (!m_handlerParticipant->init())
{
ERROR_LOG(m_logger) << "Initialisation ParticipantPositionPublisher failed.";
return false;
}
// related to NLDEVCTRL-844: NASAT: Weiterleitung der Luftunterstützung sporadisch ausser Funktion
// Waiting for all (relevant) exercises (AES) to be started, sounds better
// But it´s complicated (some ServiceManagement topics would have to be considered)
// 'AES process is started' is not enough, but when is the FTS available???
// So accept a bailing out (in case of (re-)starting GNA while NASAT is sending data)
// and keep it simple:
#define START_DELAYED
#ifdef START_DELAYED
QTimer::singleShot(31000, m_jsonSocketHandler.get(), [this]() {
NOTICE_LOG(m_logger) << "Initialisation SocketHandler ....";
if (!m_jsonSocketHandler->init(Settings::socketListenPort()))
{
ERROR_LOG(m_logger) << "Initialisation WebSocketHandler failed.";
}
});
#else
if (!m_jsonSocketHandler->init(Settings::socketListenPort()))
{
ERROR_LOG(m_logger) << "Initialisation WebSocketHandler failed.";
return false;
}
#endif // START_DELAYED
QObject::connect(m_jsonSocketHandler.get(), &AbstractSocketHandler::simulationStatusReceived,
m_handlerNasatAircraft.get(), &HandlerNasatAircraft::simulationStatusChanged);
QObject::connect(m_handlerNasatAircraft.get(), &HandlerNasatAircraft::activateNasatAircraftSimulation,
m_jsonSocketHandler.get(), &AbstractSocketHandler::setSimulationStatus);
QObject::connect(m_handlerNasatAircraft.get(), &HandlerNasatAircraft::nasatIdChanged,
m_handlerParticipant.get(), &HandlerParticipant::onNasatIdChanged);
QObject::connect(m_jsonSocketHandler.get(), &AbstractSocketHandler::positionReceived,
m_handlerParticipant.get(), &HandlerParticipant::onNasatPosition);
QObject::connect(m_jsonSocketHandler.get(), &AbstractSocketHandler::weaponReleaseReceived,
m_handlerNasatImpact.get(), &HandlerNasatImpact::nasatWeaponRelease);
QObject::connect(m_jsonSocketHandler.get(), &AbstractSocketHandler::nineLinerReceived,
m_handlerNasatNineLiner.get(), &HandlerNasatNineLiner::nineLinerReceived);
TRACE_LOG(m_logger) << LOGFUNCTION << "END";
return true;
}
std::shared_ptr<DatabaseInterface> Initialization::db() const
{
return m_dbHandler->db();
}
} // namespace GuezNasat
+58
View File
@@ -0,0 +1,58 @@
/**
* Initialization for GuezNasat
* $Id$
* $HeadURL$
* $Author$
* Created by hjl, SLSE, 2016-11-14
*/
#pragma once
#include <DDS/DDSConnector/dds_connector.h>
#include <ngldb/db_service_handler.h>
#include <GuezNasat/gna_export.h>
#include <GuezNasat/logger.h>
class QSqlDatabase;
namespace GuezNasat
{
class DdsHandler;
class DatabaseInterface;
class HandlerNasatAircraft;
class HandlerNasatAircraftParticipant;
class HandlerNasatImpact;
class HandlerNasatNineLiner;
class HandlerParticipant;
class AbstractSocketHandler;
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
class HandlerCodificationData;
class GNA_SERVER_EXPORT Initialization final
{
public:
Initialization();
~Initialization();
bool initialize(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, const QSqlDatabase &);
bool loadFromDatabase();
std::shared_ptr<DdsHandler> dds() const { return m_ddsHandler; }
std::shared_ptr<DatabaseInterface> db() const;
std::shared_ptr<HandlerNasatAircraft> nasatAircraft() const { return m_handlerNasatAircraft; }
std::shared_ptr<HandlerNasatAircraftParticipant> nasatAircraftParticipant() const { return m_handlerNasatAircraftParticipant; }
std::shared_ptr<HandlerParticipant> handlerParticipant() const { return m_handlerParticipant; }
private: // attributes
std::shared_ptr<DdsHandler> m_ddsHandler; ///< Pointer to DDS handler
std::shared_ptr<DbHandler> m_dbHandler; ///< Pointer to DB handler
std::shared_ptr<HandlerNasatAircraft> m_handlerNasatAircraft;
std::shared_ptr<HandlerNasatAircraftParticipant> m_handlerNasatAircraftParticipant;
std::shared_ptr<HandlerNasatImpact> m_handlerNasatImpact;
std::shared_ptr<HandlerNasatNineLiner> m_handlerNasatNineLiner;
std::shared_ptr<HandlerParticipant> m_handlerParticipant;
std::shared_ptr<AbstractSocketHandler> m_jsonSocketHandler;
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
};
} // namespace GuezNasat
+37
View File
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Logging for GuezNasat
* $Id$
* $HeadURL$
* $Author$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace GuezNasat
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "GNA.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace GuezNasat
+23
View File
@@ -0,0 +1,23 @@
/**
* @RDE_HEADER@
* Logging for GuezNasat
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
#include "gna_export.h"
namespace GuezNasat
{
using LOGGER_T = NGL::INGLLogger &;
GNA_COMMON_EXPORT LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace GuezNasat
+62
View File
@@ -0,0 +1,62 @@
/**
* Settings for GuezNasat
* $Id$
* $HeadURL$
* $Author$
*/
#include "settings.h"
#include <QtCore/QSettings>
#include <nglsettings/nglsettings_settings.h>
#include <ngltools/ngltools_filesystem.h>
namespace GuezNasat
{
class NGLSettingsClass : public NGL::Settings
{
public:
NGLSettingsClass()
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
{}
static void setIniFile(const QString &fn)
{
s_iniFile = fn;
}
static QString s_iniFile;
};
QString NGLSettingsClass::s_iniFile;
Q_GLOBAL_STATIC(NGLSettingsClass, s)
//-----------------------------------------------------------------------------
NGL::Settings *Settings::settings()
{
return s();
}
//-----------------------------------------------------------------------------
void Settings::setIniFile(const QString &ini)
{
NGLSettingsClass::setIniFile(ini);
}
//-----------------------------------------------------------------------------
quint16 Settings::socketListenPort()
{
return s()->settings()->value(QStringLiteral("GNA/socketListenPort"), 8420).toUInt();
}
//-----------------------------------------------------------------------------
bool Settings::useWebSocket()
{
return s()->settings()->value(QStringLiteral("GNA/useWebSocket"), false).toBool();
}
QPointF Settings::simulationPositionDegree()
{
double lon = s()->settings()->value(QStringLiteral("GNA/simulationPosLatDegree"), 11.560).toDouble();
double lat = s()->settings()->value(QStringLiteral("GNA/simulationPosLonDegree"), 52.457).toDouble();
return {lon, lat};
}
} // namespace GuezNasat
+29
View File
@@ -0,0 +1,29 @@
/**
* Settings for GuezNasat
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QPointF>
#include <QString>
#include <GuezNasat/gna_export.h>
namespace NGL
{
class Settings;
}
namespace GuezNasat
{
namespace Settings
{
GNA_SERVER_EXPORT void setIniFile(const QString &ini);
NGL::Settings *settings();
quint16 socketListenPort();
bool useWebSocket();
QPointF simulationPositionDegree();
}
} // namespace GuezNasat
+160
View File
@@ -0,0 +1,160 @@
/**
* Websocket interface for building control unit
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-30
*/
#include "tcp_socket_handler.h"
#include "guez_nasat_telegrams.h"
namespace GuezNasat
{
static constexpr unsigned char s_startMark = 0x02;
static constexpr unsigned char s_endMark = 0x03;
static inline QByteArray escapeData(const QByteArray &bufferData)
{
QByteArray ret;
ret.reserve(bufferData.size() * 6 / 5);
for (const unsigned char c : bufferData)
{
if (c >= 0x20 && c < 0x7f)
ret += c;
else
ret += "\\x" + QByteArray::number(static_cast<unsigned char>(c), 16);
}
return ret;
}
TcpSocketHandler::TcpSocketHandler(QObject *parent)
: AbstractSocketHandler("TcpSocketHandler", parent)
, m_tcpSocketServer(new QTcpServer(this))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool TcpSocketHandler::init(quint16 listenPort)
{
if (!m_tcpSocketServer->listen(QHostAddress::Any, listenPort))
{
WARNING_LOG(m_logger) << "Can not listen on port " << listenPort << " - aborting";
return false;
}
connect(m_tcpSocketServer, &QTcpServer::newConnection,
this, &TcpSocketHandler::onNewConnection);
return true;
}
void TcpSocketHandler::onNewConnection()
{
QTcpSocket *ts = m_tcpSocketServer->nextPendingConnection();
if (!ts)
return;
DEBUG_LOG(m_logger) << "New TCP socket connection from " << ts->peerAddress().toString()
<< ":" << ts->peerPort() << ", ptr: " << ts;
connect(ts, &QTcpSocket::readyRead,
this, &TcpSocketHandler::onReadyRead);
connect(ts, &QTcpSocket::disconnected,
this, &TcpSocketHandler::onTcpSocketDisconnected);
m_tcpSockets.insert(ts, QByteArray());
}
bool TcpSocketHandler::sendTelegramInternal(const QByteArray &tele)
{
if (tele.size() > std::numeric_limits<unsigned short>::max())
return false;
const unsigned short len = tele.size();
// add framing
QByteArray data(len + 4, Qt::Uninitialized); // s_startMark, len, s_endMark
data[0] = s_startMark;
// big endian
data[1] = (len & 0x00FFU);
data[2] = (len & 0xFF00U) >> 16;
char *dst = data.data() + 3;
memcpy(dst, tele.data(), tele.size());
data[data.size() - 1] = s_endMark;
bool bOk = false;
DEBUG_LOG(m_logger) << "Sending: " << escapeData(data);
for (auto it = m_tcpSockets.cbegin(); it != m_tcpSockets.cend(); ++it)
{
QTcpSocket *ws = it.key();
if (ws->write(data) <= 0)
bOk = true;
}
return bOk;
}
void TcpSocketHandler::onReadyRead()
{
QTcpSocket *s = qobject_cast<QTcpSocket *>(sender());
if (!s)
{
Q_ASSERT(false);
return;
}
auto &tcpBuffer = m_tcpSockets[s];
const QByteArray bufferData = tcpBuffer + s->readAll();
TRACE_LOG(m_logger) << "TcpSocketHandler::onReadyRead bufferData='" << escapeData(bufferData) << "'";
// returns the unparsed part of the buffer
tcpBuffer = parseBuffer(bufferData);
}
QByteArray TcpSocketHandler::parseBuffer(const QByteArray &buffer)
{
int iEndPos = 0;
int iCurReadPos = 0;
while (findNextSyncStartByte(buffer, iCurReadPos))
{
const int iStartPos = iCurReadPos;
if (!findNextSyncEndByte(buffer, iCurReadPos))
break;
iEndPos = iCurReadPos;
// after s_startMark there are two bytes with len, we currently don't care about them
textMessageReceived(buffer.mid(iStartPos + 3, iEndPos - iStartPos - 3));
}
return buffer.mid(iEndPos);
}
bool TcpSocketHandler::findNextSyncStartByte(const QByteArray &buffer, int &iCurReadPos)
{
// Suchen nach s_startMark
while (iCurReadPos < buffer.size())
{
const unsigned char data = buffer.at(iCurReadPos);
if (data == s_startMark)
return true;
++iCurReadPos;
}
return false;
}
bool TcpSocketHandler::findNextSyncEndByte(const QByteArray &buffer, int &iCurReadPos)
{
// Suchen nach s_endMark
while (iCurReadPos < buffer.size())
{
const unsigned char data = buffer.at(iCurReadPos);
if (data == s_endMark)
return true;
++iCurReadPos;
}
return false;
}
void TcpSocketHandler::onTcpSocketDisconnected()
{
QTcpSocket *ws = qobject_cast<QTcpSocket *>(sender());
if (!ws)
return;
DEBUG_LOG(m_logger) << "TCP socket connection closed, ptr: " << ws;
m_tcpSockets.remove(ws);
ws->deleteLater();
}
} // namespace GuezNasat
+43
View File
@@ -0,0 +1,43 @@
/**
* Websocket interface for building control unit
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-30
*/
#pragma once
#include <QTcpServer>
#include "logger.h"
#include "abstract_socket_handler.h"
namespace GuezNasat
{
class TcpSocketHandler : public AbstractSocketHandler
{
Q_OBJECT
public:
explicit TcpSocketHandler(QObject *parent = nullptr);
bool init(quint16 listenPort) override;
bool isConnected() const override
{
return !m_tcpSockets.isEmpty();
}
protected:
bool sendTelegramInternal(const QByteArray &tele) override;
QByteArray parseBuffer(const QByteArray &buffer);
static bool findNextSyncStartByte(const QByteArray &buffer, int &iCurReadPos);
static bool findNextSyncEndByte(const QByteArray &buffer, int &iCurReadPos);
private Q_SLOTS:
void onNewConnection();
void onTcpSocketDisconnected();
void onReadyRead();
private:
QTcpServer *m_tcpSocketServer;
QHash<QTcpSocket *, QByteArray> m_tcpSockets;
};
} // namespace GuezNasat
+161
View File
@@ -0,0 +1,161 @@
/**
* Websocket interface for building control unit
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-30
*/
#include "web_socket_handler.h"
#include "guez_nasat_telegrams.h"
#include <QWebSocket>
/*
python:
import websocket
import json
import time
ws = websocket.create_connection("ws://127.0.0.1:8420")
ws.recv()
ws.recv()
aircraftId == NasatId
uuid, wird wohl ignoriert
d = { 'type' : 'NasatPosition', 'data': {'aircraftId': 1, 'timestamp': -1, 'position': { 'lat': 53.0654, 'lon': 8.9804, 'height': 1000 } } }
d = { 'type' : 'NasatPosition', 'data': {'aircraftId': 1234, 'timestamp': -1, 'position': { 'lat': 53.0000, 'lon': 8.9704, 'height': 1000 } } }
d = { 'type' : 'NasatWeaponRelease', 'data': {'aircraftId': 1234, 'timestamp': -1, 'impactPosition': { 'lat': 53.1000, 'lon': 8.9704 }, 'flightTime': 50, 'munition': 1, 'fuseType': 1, 'releaseMode': 1 } }
// May 2020:
d = { 'type' : 'NasatPosition', 'data': {'aircraftId': 1, 'timestamp': -1, 'position': { 'lat': 53.0653, 'lon': 8.9704, 'height': 1000 } } }
// org
d = {'data':{'aircraftId':6,'altitudeTarget':55,'altitudeTargetMode':1, 'distance2InitialPointMode':1,'distanceInitialPoint2Target':925.9999956432568,'finalAttackHeading':{'heading':120,'headingHigh':270,'headingLow':10},'finalAttackHeadingMode':2,'friendlies':{'bearing':88,'distance':333.6000442504983}, 'heading2InitialPointMode':2,'headingInitialPoint2Target':315,'initialPoint':{'lat':52.477682630051689,'lon':11.597559126751433}, 'initialPointMode':1,'modeFriendlies':1,'targetPosition':{'lat':33.47476840055018,'lon':11.589788466760311},'targetPositionMode':1,'timeForTarget':57600,'timeForTargetMode':2,'timestamp':1589384815.5303969},'type':'NasatNineLiner','uuid':'blasdbasd-kjladjaslasdklj'}
d = {'data':{'aircraftId':4711,'altitudeTarget':55,'altitudeTargetMode':1, 'distance2InitialPointMode':1,'distanceInitialPoint2Target':925.9999956432568,'finalAttackHeading':{'heading':120,'headingHigh':270,'headingLow':10},'finalAttackHeadingMode':2,'friendlies':{'bearing':88,'distance':333.6000442504983}, 'heading2InitialPointMode':2,'headingInitialPoint2Target':315,'initialPoint':{'lat':52.477682630051689,'lon':11.597559126751433}, 'initialPointMode':1,'modeFriendlies':1,'targetPosition':{'lat':33.47476840055018,'lon':11.589788466760311},'targetPositionMode':1,'timeForTarget':57600,'timeForTargetMode':2,'timestamp':1589384815.5303969},'type':'NasatNineLiner','uuid':'blasdbasd-kjladjaslasdklj'}
// Bremen
d = {'data':{'aircraftId':1,'altitudeTarget':55,'altitudeTargetMode':1, 'distance2InitialPointMode':1,'distanceInitialPoint2Target':925.9999956432568,'finalAttackHeading':{'heading':120,'headingHigh':270,'headingLow':10},'finalAttackHeadingMode':2,'friendlies':{'bearing':88,'distance':333.6000442504983}, 'heading2InitialPointMode':2,'headingInitialPoint2Target':315,'initialPoint':{'lat':52.477682630051689,'lon':11.597559126751433}, 'initialPointMode':1,'modeFriendlies':1,'targetPosition':{'lat':33.47476840055018,'lon':11.589788466760311},'targetPositionMode':1,'timeForTarget':57600,'timeForTargetMode':2,'timestamp':1589384815.5303969},'type':'NasatNineLiner','uuid':'blasdbasd-kjladjaslasdklj'}
d = {'data':{'aircraftId':1,'altitudeTarget':55,'altitudeTargetMode':1, 'distance2InitialPointMode':1,'distanceInitialPoint2Target':925.9,'finalAttackHeading':{'heading':120,'headingHigh':270,'headingLow':10},'finalAttackHeadingMode':2,'friendlies':{'bearing':88,'distance':333.6}, 'heading2InitialPointMode':2,'headingInitialPoint2Target':315,'initialPoint':{'lat':53.06,'lon':8.97}, 'initialPointMode':1,'modeFriendlies':1,'targetPosition':{'lat':53.06,'lon':8.971},'targetPositionMode':1,'timeForTarget':57600,'timeForTargetMode':2,'timestamp':-1},'type':'NasatNineLiner','uuid':'blasdbasd-kjladjaslasdklj'}
d = {'data':{'aircraftId':1,'altitudeTarget':55,'altitudeTargetMode':1, 'distance2InitialPointMode':1,'distanceInitialPoint2Target':725.9999956432568,'finalAttackHeading':{'heading':120,'headingHigh':270,'headingLow':10},'finalAttackHeadingMode':2,'friendlies':{'bearing':88,'distance':333.6000442504983}, 'heading2InitialPointMode':2,'headingInitialPoint2Target':315,'initialPoint':{'lat':52.477682630051689,'lon':11.597559126751433}, 'initialPointMode':1,'modeFriendlies':1,'targetPosition':{'lat':33.47476840055018,'lon':11.589788466760311},'targetPositionMode':1,'timeForTarget':57600,'timeForTargetMode':2,'timestamp':1589384815.5303969},'type':'NasatNineLiner','uuid':'blasdbasd-kjladjaslasdklj'}
d = {'data':{'aircraftId':1,'altitudeTarget':56,'altitudeTargetMode':1, 'distance2InitialPointMode':1,'distanceInitialPoint2Target':925.9,'finalAttackHeading':{'heading':120,'headingHigh':270,'headingLow':10},'finalAttackHeadingMode':2,'friendlies':{'bearing':88,'distance':333.6}, 'heading2InitialPointMode':2,'headingInitialPoint2Target':315,'initialPoint':{'lat':53.06,'lon':8.97}, 'initialPointMode':1,'modeFriendlies':1,'targetPosition':{'lat':53.06,'lon':8.971},'targetPositionMode':1,'timeForTarget':57600,'timeForTargetMode':2,'timestamp':-1},'type':'NasatNineLiner','uuid':'blasdbasd-kjladjaslasdklj'}
// 2021-01-15 12:13:33.027 DEBUG GNA::TcpSocketHandler |#| incoming telegram: {"data":{"aircraftId":99,"flightTime":5.3000001907348633,"fuseType":1,"impactPosition":{"lat":52.473540999999997,"lon":11.582856},"munition":2,"releaseMode":0,"timestamp":1610712812.968688},"type":"NasatWeaponRelease","uuid":"3d564e8c-b3a0-4687-a365-0893cf84c26e"} (/Lts/Proxies/GuezNasat/abstract_socket_handler.cpp:53)
// flightTime -> Flugzeit des Geschosses vom AusklingPunkt bis zum Einschlag!?!
d = {'data':{'aircraftId':99,'flightTime':5.3000001907348633,'fuseType':1,'impactPosition':{'lat':52.473540999999997,'lon':11.582856},'munition':2,'releaseMode':0,'timestamp':-1},'type':'NasatWeaponRelease','uuid':'Blalaa'}
d = f"Hallo"
ws.send(json.dumps(d))
ws.close()
*/
/*
switch tp Filips simulator:
-- simulate movement:
python nasat_simulator.py -a1
^ aircraft Id
-- simulate NineLiner:
-- uses nine_liner_template.json and the embedded tele. But teleTYPE has to be specified explicit:
python nasat_simulator.py -a1 -f nine_liner_template.json -t NasatNineLiner
-- simulate NasatWeaponRelease:
uses XY.json and the embedded tele. But teleTYPE has to be specified explicit:
(small distance of NineLiner and Impact of NasatWeaponRelease is intended)
python nasat_simulator.py -a1 -f nasat_weapon_release_template.json -t NasatWeaponRelease
*/
namespace GuezNasat
{
WebSocketHandler::WebSocketHandler(QObject *parent)
: AbstractSocketHandler("WebSocketHandler", parent)
, m_webSocketServer(new QWebSocketServer(QStringLiteral("GNA"), QWebSocketServer::NonSecureMode, this))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
WebSocketHandler::~WebSocketHandler()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
for (auto s : qAsConst(m_webSockets))
{
s->disconnect(this);
s->close();
}
qDeleteAll(m_webSockets);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool WebSocketHandler::init(quint16 listenPort)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, listenPort=" << listenPort;
if (!m_webSocketServer->listen(QHostAddress::Any, listenPort))
{
WARNING_LOG(m_logger) << "Cannot listen on port " << listenPort << " - aborting";
return false;
}
DEBUG_LOG(m_logger) << "Listening on port " << listenPort;
connect(m_webSocketServer, &QWebSocketServer::newConnection,
this, &WebSocketHandler::onNewConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, listenPort=" << listenPort;
return true;
}
void WebSocketHandler::onNewConnection()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
QWebSocket *ws = m_webSocketServer->nextPendingConnection();
if (!ws)
return;
NOTICE_LOG(m_logger) << "New websocket connection from " << ws->peerAddress().toString()
<< ":" << ws->peerPort() << ", ptr: " << ws;
connect(ws, &QWebSocket::textMessageReceived,
this, &WebSocketHandler::onTextMessageReceived);
connect(ws, &QWebSocket::disconnected,
this, &WebSocketHandler::onWebSocketDisconnected);
m_webSockets += ws;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool WebSocketHandler::sendTelegramInternal(const QByteArray &tele)
{
const QString msg = QString::fromUtf8(tele);
bool bOk = false;
for (QWebSocket *ws : qAsConst(m_webSockets))
{
if (ws->sendTextMessage(msg))
bOk = true;
}
return bOk;
}
void WebSocketHandler::onTextMessageReceived(const QString &msg)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, msg='" << msg << "'";
const QByteArray baJson = msg.toUtf8();
textMessageReceived(baJson);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, msg='" << msg << "'";
}
void WebSocketHandler::onWebSocketDisconnected()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
QWebSocket *ws = qobject_cast<QWebSocket *>(sender());
if (!ws)
return;
NOTICE_LOG(m_logger) << "Websocket connection closed, ptr: " << ws;
m_webSockets.remove(ws);
ws->deleteLater();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
} // namespace GuezNasat
+41
View File
@@ -0,0 +1,41 @@
/**
* Websocket interface for building control unit
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-30
*/
#pragma once
#include <QWebSocketServer>
#include "logger.h"
#include "abstract_socket_handler.h"
namespace GuezNasat
{
class WebSocketHandler : public AbstractSocketHandler
{
Q_OBJECT
public:
explicit WebSocketHandler(QObject *parent = nullptr);
~WebSocketHandler();
bool init(quint16 listenPort) override;
bool isConnected() const override
{
return !m_webSockets.isEmpty();
}
protected:
bool sendTelegramInternal(const QByteArray &tele) override;
private Q_SLOTS:
void onNewConnection();
void onWebSocketDisconnected();
void onTextMessageReceived(const QString &msg);
private:
QWebSocketServer *m_webSocketServer;
QSet<QWebSocket *> m_webSockets;
};
} // namespace GuezNasat