Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+154
@@ -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
@@ -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"
|
||||
}
|
||||
Executable
+66
@@ -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
|
||||
Executable
+30
@@ -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
@@ -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)
|
||||
+166
@@ -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
@@ -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"}
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
@@ -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
@@ -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
@@ -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
|
||||
Executable
+204
@@ -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
|
||||
Executable
+82
@@ -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
|
||||
Executable
+52
@@ -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
|
||||
Executable
+98
@@ -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], &lt; 0 -&gt; invalid"/>
|
||||
<column name="hdg2InitialPointMode" idlType="Hdg2InitialPointMode"/>
|
||||
<column name="distanceInitialPoint2Target" idlType="double" comment="[m], &lt; 0 -&gt; invalid"/>
|
||||
<column name="targetPosition" idlType="Core::GeoPosition"/>
|
||||
<column name="friendliesBearing" idlType="long" comment="[degree], &lt; 0 -&gt; invalid"/>
|
||||
<column name="friendliesDistance" idlType="double" comment="[m], &lt; 0 -&gt; invalid"/>
|
||||
<column name="finalAttackHeading" idlType="long" comment="[degree], &lt; 0 -&gt; invalid"/>
|
||||
<column name="finalAttackHeadingLow" idlType="long" comment="[degree], &lt; 0 -&gt; invalid"/>
|
||||
<column name="finalAttackHeadingHigh" idlType="long" comment="[degree], &lt; 0 -&gt; invalid"/>
|
||||
<column name="timeForTarget" idlType="long" comment="[s], &lt;0 -&gt; timeToTarget, 0 -&gt; invalid, &gt; 0 -&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
@@ -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
|
||||
Executable
+282
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
|
||||
Executable
+56
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Executable
+97
@@ -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
|
||||
Executable
+188
@@ -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
|
||||
Executable
+58
@@ -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
|
||||
Executable
+37
@@ -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
|
||||
Executable
+23
@@ -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
|
||||
Executable
+62
@@ -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
|
||||
Executable
+29
@@ -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
|
||||
Executable
+160
@@ -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
|
||||
Executable
+43
@@ -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
|
||||
Executable
+161
@@ -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
|
||||
Executable
+41
@@ -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
|
||||
Reference in new issue
Block a user