/** * @RDE_HEADER@ * Handler for incoming data from minelayer trialer/thrower and thier lane data * $Id$ * $HeadURL$ * $Author$ * created by Philipp Dassow, SLEA, 2017-04-06 */ #include "handler_minelayer_data.h" #include #include #include #include "dds_handler.h" #include "zssi_wi_Minenfeld_Interpreter.h" #include namespace GuezMinelayerProcessing { HandlerMinelayerData::HandlerMinelayerData(const std::shared_ptr &ddsHandler, QObject *parent) : QObject(parent) , m_ddsHandler(ddsHandler) , m_tabDtc(nullptr) , m_ppmDtc(nullptr) , m_aesFtc(nullptr) , m_minefieldInterpreter(new ZSSI_WI_Minenfeld_Interpreter(this)) , m_minefieldInterpreterTimer(new QTimer(this)) , m_logger(getLogger("HandlerMinelayerData")) {} HandlerMinelayerData::~HandlerMinelayerData() {} bool HandlerMinelayerData::init() { // AES-Ftc m_aesFtc = AreaEffectSimulation::Interface::Ftc::create(m_ddsHandler->ddsConnector()); bool ret = m_aesFtc->enableMineAreaModifyFromCtaData(); if (!ret) { ERROR_LOG(m_logger) << "AesFtc Can not enable MineAreaCreateFromCtaData()"; return false; } // Data from training area base m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_ddsHandler->ddsConnector()); ret &= m_tabDtc->enableSpecialSensorData(); ret &= m_tabDtc->enableMinelayerTrailerData(); ret &= m_tabDtc->enableMinelayerThrowerData(); if (!ret) { ERROR_LOG(m_logger) << "TabDtc Can not ebale Data"; return false; } connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::specialSensorDataChanged, this, &HandlerMinelayerData::onSpecialSensorDataChanged); connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::minelayerTrailerDataChanged, this, &HandlerMinelayerData::onMinelayerTrailerData); connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::minelayerThrowerDataChanged, this, &HandlerMinelayerData::onMinelayerThrowerData); // PPM for partyId Mapping m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector()); ret &= m_ppmDtc->enableParticipant(); if (!ret) { ERROR_LOG(m_logger) << "PpmDtc Can not enable Participant Data"; return false; } // connect to minefield generator connect(m_minefieldInterpreter, &ZSSI_WI_Minenfeld_Interpreter::sendeWirkfeld, this, &HandlerMinelayerData::onSendMinefield); // start Interpreter connect(m_minefieldInterpreterTimer, &QTimer::timeout, this, &HandlerMinelayerData::onStartMinefieldInterpreter); m_minefieldInterpreterTimer->start(m_minefieldInterpreter->triggerIntervall * 1000); return ret; } void HandlerMinelayerData::onSpecialSensorDataChanged(const TrainingAreaBase::SpecialSensorData &data, DataModification modType) { if (modType != DataModification::eAdded && modType != DataModification::eModified) return; if (data.operationalState != MV_VERLEGEN && data.operationalState != WMV_VERLEGEN) return; if (!data.position.is_set()) return; { // convert TrainingAreaBase::LaneData back to sondersensorik_fahrspur_rt FAHRSPUR_INTERN daten_intern; //Interpretationsstatus auf 0 setzen daten_intern.intstat = 0; daten_intern.daten.header.identitaet = data.equipmentNumber; daten_intern.daten.gps_zeit.gps_zeit = data.sampleTime / 1000; daten_intern.daten.gps_position = relativeFromGeographic(data.position.get().lon, data.position.get().lat); daten_intern.daten.ss_betriebszustand = data.operationalState; // old code copied from zssi_wi_Empfaenger.cpp /* if ( checkeTelegrammZeit(telegramm_rt.gps_zeit.gps_zeit) ) { ERROR_LOG(m_logger) << QStringLiteral("Keine plausible gps_zeit !! gps_zeit=%1").arg(telegramm_rt.gps_zeit.gps_zeit); return; } if ( checkeKoordinaten(telegramm_rt.gps_pos)!=0 ) { ERROR_LOG(m_logger) << QStringLiteral("Keine plausible gps_pos !! pos_x=%1 Keine plausible gps_pos !! pos_y=%2").arg(telegramm_rt.gps_pos.utm_ostwert).arg(telegramm_rt.gps_pos.utm_nordwert); return; } */ VERLEGEDATEN_KEY key_intern; key_intern.fz_id = daten_intern.daten.header.identitaet; key_intern.zeitpunkt.gps_zeit = daten_intern.daten.gps_zeit.gps_zeit; interne_datenbasis_Fahrspur.eintrag_container(key_intern, daten_intern); INFO_LOG(m_logger) << "Inserted new lane data into old interne_datenbasis_Fahrspur succesfully! Lane data:" << data; // end old code } } template void HandlerMinelayerData::convertMinelayerDataToXdrData(const TrainingAreaBase::MinelayerTrailerData &inData, T &outData) { outData.header.identitaet = inData.equipmentNumber; outData.gps_zeit.gps_zeit = inData.sampleTime / 1000; // derived from Tetra telegram outData.gps_position = relativeFromGeographic(inData.position.lon, inData.position.lat); outData.verlegedaten.sperren_id = inData.barrierId; outData.verlegedaten.verlegedichte = inData.layingDensity; outData.verlegedaten.wirkbeginn.gps_zeit = inData.effectStart / 1000; // derived from Tetra telegram outData.verlegedaten.wirkzeit = inData.effectDuration; outData.verlegedaten.minentyp = inData.chargeTypeId; outData.verlegedaten.anzahl_verlegter_minen = inData.mineCount; } void HandlerMinelayerData::onMinelayerTrailerData(const TrainingAreaBase::MinelayerTrailerData &data, DataModification modType) { if ((modType == DataModification::eAdded) || (modType == DataModification::eModified)) { VERLEGEDATEN_INTERN daten_intern; convertMinelayerDataToXdrData(data, daten_intern.daten); // old code copied from zssi_wi_Empfaenger.cpp /* INFO_LOG(m_logger) << log_tr("Telegramm 'SONDERSENSORIK_MIVANH_VERLEGEDATEN' empfangen"); if ( checkeTelegrammZeit(telegramm_rt.gps_zeit.gps_zeit) ) { ERROR_LOG(m_logger) << log_tr("Keine plausible gps_zeit !! gps_zeit=%1").arg(telegramm_rt.gps_zeit.gps_zeit); return; } if ( checkeKoordinaten(telegramm_rt.gps_pos)!=0 ) { ERROR_LOG(m_logger) << log_tr("Keine plausible gps_pos !! pos_x=%1 Keine plausible gps_pos !! pos_y=%2").arg(telegramm_rt.gps_pos.utm_ostwert).arg(telegramm_rt.gps_pos.utm_nordwert); return; } */ daten_intern.daten.verlegedaten.ausstossart = ausstossart_et(0); //Diese Null gilt als Unterscheidung zwischen Scorpion und //Minenverlegeangaenger, da der Scorpion nur ausstossart 1..3 hat if (daten_intern.daten.verlegedaten.anzahl_verlegter_minen > 1200) { WARNING_LOG(m_logger) << QStringLiteral("Anzahl_verlegter_minen = %1, wird auf 1200 zurueckgesetzt").arg(daten_intern.daten.verlegedaten.anzahl_verlegter_minen); daten_intern.daten.verlegedaten.anzahl_verlegter_minen = 1200; } VERLEGEDATEN_KEY key_intern; key_intern.fz_id = daten_intern.daten.header.identitaet; key_intern.zeitpunkt.gps_zeit = daten_intern.daten.gps_zeit.gps_zeit; interne_datenbasis_Verlegedaten.eintrag_container( key_intern, daten_intern); INFO_LOG(m_logger) << "Inserted new minelayertrailer data into old interne_datenbasis_Verlegedaten succesfully! Minelayerthrower data:" << data; } } void HandlerMinelayerData::onMinelayerThrowerData(const TrainingAreaBase::MinelayerThrowerData &data, DataModification modType) { if ((modType == DataModification::eAdded) || (modType == DataModification::eModified)) { VERLEGEDATEN_INTERN daten_intern; convertMinelayerDataToXdrData(data, daten_intern.daten); daten_intern.daten.verlegedaten.ausstossart = static_cast(data.throwingType); /* if ( checkeTelegrammZeit(telegramm_rt.gps_zeit.gps_zeit) ) { ERROR_LOG(m_logger) << log_tr("Keine plausible gps_zeit !! gps_zeit=%1").arg(telegramm_rt.gps_zeit.gps_zeit); return; } if ( checkeKoordinaten(telegramm_rt.gps_pos) !=0 ) { ERROR_LOG(m_logger) << log_tr("Keine plausible gps_pos !! pos_x=%1 Keine plausible gps_pos !! pos_y=%2").arg(telegramm_rt.gps_pos.utm_ostwert).arg(telegramm_rt.gps_pos.utm_nordwert); return; } */ if (daten_intern.daten.verlegedaten.anzahl_verlegter_minen > 1200) { WARNING_LOG(m_logger) << QStringLiteral("Anzahl_verlegter_minen = %1, wird auf 1200 zurueckgesetzt").arg(daten_intern.daten.verlegedaten.anzahl_verlegter_minen); daten_intern.daten.verlegedaten.anzahl_verlegter_minen = 1200; } VERLEGEDATEN_KEY key_intern; key_intern.fz_id = daten_intern.daten.header.identitaet; key_intern.zeitpunkt.gps_zeit = daten_intern.daten.gps_zeit.gps_zeit; if (daten_intern.daten.verlegedaten.ausstossart >= 5 && daten_intern.daten.verlegedaten.ausstossart <= 7) { daten_intern.daten.verlegedaten.anzahl_verlegter_minen = 5; m_minefieldInterpreter->ZSSI_WI_modifiziere_Verlegedaten(key_intern, daten_intern); } else { interne_datenbasis_Verlegedaten.eintrag_container( key_intern, daten_intern); } INFO_LOG(m_logger) << "Inserted new minelayerthrower data into old interne_datenbasis_Verlegedaten succesfully! Minelayerthrower data:" << data; } } Core::GeoPosition2D HandlerMinelayerData::geographicFromRelative(const gps_position_rt &position) const { // this function is called after m_baseCoord is set within relativeFromGeographic() // since we do a mgrs->geographic conversion only when a mine area is created const QPointF point(m_baseCoord.geographic(position.utm_ostwert - m_baseCoord.x, position.utm_nordwert - m_baseCoord.y)); Core::GeoPosition2D ret; ret.lon = point.x(); ret.lat = point.y(); return ret; } gps_position_rt HandlerMinelayerData::relativeFromGeographic(double lon, double lat) { const LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(lon, lat, m_baseCoord.zone)); if (m_baseCoord.zone == -1) { const QString mgrs = coord.mgrs(0) + QStringLiteral("00000000000000"); // our mgrs base point (taken from the first coordinate we get from Tetra) m_baseCoord = LtsCoordTrans::UtmCoordinate::fromMgrs(mgrs); } gps_position_rt ret; ret.utm_ostwert = qRound(coord.x); ret.utm_nordwert = qRound(coord.y); return ret; } int HandlerMinelayerData::partyIdFromEquipmentNumber(int eqNumber) const { int partyId = 0; std::function cb = [eqNumber, &partyId](const ParticipantManagement::Participant & participant) -> bool { if (participant.equipmentNumber == eqNumber) { partyId = participant.partyId; return true; } return false; }; m_ppmDtc->participants(cb); return partyId; } // mathmatisch positiv nordbezogen <- mathematisch negativ, ost = 0°, 0,01degree in 1/100° -> Faktor 100 static inline double compassFromMathAngleForSfm(int mathAngle) { double ret = (9000.0 - mathAngle) / 100; while (ret < 0.0) ret += 360.0; while (ret > 360.0) ret -= 360.0; return ret; } void HandlerMinelayerData::onSendMinefield(const wirkfeld_minensperre_rt &minefield, int fzArt) { AreaEffectSimulation::MineArea outData; outData.participantId = minefield.header.identitaet; outData.partyId = partyIdFromEquipmentNumber(minefield.header.identitaet); // Get from PPM; outData.name = QString::fromUtf8(tr_lts("dds", "_%1")).arg(minefield.beschreibung.kennung).toStdString(); outData.effectStart = minefield.beschreibung.wirkbeginn.gps_zeit * 1000LL; // derived from Tetra telegram outData.effectDuration = minefield.beschreibung.wirkdauer * (1000 * 60 * 60); // orig resolution is 1h based outData.density = minefield.beschreibung.verlegedichte / 100.0; // derived from Tetra telegram outData.chargeStruct.chargeTypeId = minefield.beschreibung.minentyp; // is already in TAB converted to chargeTypeId outData.layingProcedureType = static_cast(fzArt); outData.width = minefield.beschreibung.verlegetiefe; outData.isLaidHidden = false; outData.layingProcedureType = AreaEffectSimulation::AesMaLayingProcedureType::LptPioneer; outData.isCenterLine = true; // segments std::vector segVec; segVec.reserve(minefield.beschreibung.segmente.size()); for (const auto &seg : minefield.beschreibung.segmente) { AreaEffectSimulation::MineSegment segment; segment.positionStart = geographicFromRelative(seg.startpunkt); const LtsCoordTrans::UtmCoordinate startPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic({segment.positionStart.lon, segment.positionStart.lat}); QLineF line; line.setP1({startPositionUtm.x, startPositionUtm.y}); line.setAngle(seg.drehwinkel); line.setLength(double(seg.anzahl / outData.density)); LtsCoordTrans::UtmCoordinate endPositionUtm = startPositionUtm; endPositionUtm.x = line.p2().x(); endPositionUtm.y = line.p2().y(); QPointF endPos = endPositionUtm.geographic(); segment.positionEnd = {endPos.x(), endPos.y()}; segVec.emplace_back(segment); } outData.segments = segVec; INFO_LOG(m_logger) << "Sending new minefield from generator to AES: " << outData; // request create mine area from aes m_aesFtc->mineAreaModifyFromCtaDataRequest(outData, this); } void HandlerMinelayerData::onStartMinefieldInterpreter() { INFO_LOG(m_logger) << "Starting minefield interpreter ..."; m_minefieldInterpreter->processData(); } void HandlerMinelayerData::onMineAreaModifyFromCtaDataReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) ERROR_LOG(m_logger) << "Error inserting minefield via AES->FTC"; else INFO_LOG(m_logger) << "Got onMineAreaCreateFromCtaDataReply reply with id " << replyObject.id(); } }