/** * Read XDR telegrams from a directory and convert it to EtsTetraIcd structures * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2016-04-14 */ #include "tetra_handler_rx.h" #include #include #include #include namespace WlsTetra { TetraHandlerRx::TetraHandlerRx(const std::shared_ptr &rxHandler) : m_rxHandler(rxHandler) , m_ackTimer(new QTimer(this)) , m_receiveCounter(0) , m_bWarnedOnce(false) , m_bWaitForInitialAck(true) , m_logger(getLogger("TetraHandlerRx")) { m_ackTimer->setInterval(1000); m_ackTimer->setSingleShot(false); connect(m_ackTimer, &QTimer::timeout, this, &TetraHandlerRx::onAckTimeout); } bool TetraHandlerRx::handleTelegram(const QByteArray &baJson) { using namespace TrainingAreaBase::TetraIcd; if (baJson.isEmpty()) return false; const QJsonObject obj = QJsonDocument::fromJson(baJson).object(); const QJsonValue sendCounter = obj.value(QStringLiteral("counter")); if (!sendCounter.isUndefined()) { if (!sendCounter.isDouble()) return false; m_receiveCounter = sendCounter.toInt(-1); DEBUG_LOG(m_logger) << "Incoming telegram with Id " << obj.value(QStringLiteral("type")).toString(); if (m_receiveCounter < 0) return false; } const QJsonValue typeId = obj.value(QStringLiteral("typeId")); if (!typeId.isDouble()) { ERROR_LOG(m_logger) << "Can not read type id: " << baJson; return false; } const QJsonObject data = obj.value(QStringLiteral("data")).toObject(); try { switch (typeId.toInt()) { case Constraints::id(): // 0 { auto ack = TrainingAreaBase::TetraIcd::Acknowledge::fromJson(data); handleAcknowledge(ack.timeStamp, ack.ackCounter); break; } case Constraints::id(): // 2 rxData(ManipulationReport::fromJson(data)); break; case Constraints::id(): // 7 rxData(EquipmentOperationalState::fromJson(data)); break; case Constraints::id(): // 11 rxData(EquipmentConfigurationReport::fromJson(data)); break; case Constraints::id(): // 12 rxData(CtaDataError::fromJson(data)); break; case Constraints::id(): // 21 rxData(PositionReport::fromJson(data)); break; case Constraints::id(): // 22 rxData(PositionReportWithMountedEquipments::fromJson(data)); break; case Constraints::id(): // 40 rxData(MineTriggered::fromJson(data)); break; case Constraints::id(): // 43 rxData(DefinitionIed::fromJson(data)); break; case Constraints::id(): // 44 rxData(StateIed::fromJson(data)); break; case Constraints::id(): // 45 rxData(DusSingleMineState::fromJson(data)); break; case Constraints::id(): // 52 rxData(StateChangeDirect::fromJson(data)); break; case Constraints::id(): // 53 rxData(StateChangeIndirect::fromJson(data)); break; case Constraints::id(): // 55 rxData(OperatorAction::fromJson(data)); break; case Constraints::id(): // 56 rxData(SelectiveReammunition::fromJson(data)); break; case Constraints::id(): // 61 rxData(StateChange::fromJson(data)); break; case Constraints::id(): // 63 rxData(FunctionalAreaEntry::fromJson(data)); break; case Constraints::id(): // 71 rxData(OpaquePayloadDataIn::fromJson(data)); break; case Constraints::id(): // 92 rxData(SpecialSensorData::fromJson(data)); break; case Constraints::id(): // 95 rxData(MinelayerTrailerData::fromJson(data)); break; case Constraints::id(): // 96 rxData(MinelayerThrowerData::fromJson(data)); break; case Constraints::id(): // 97 rxData(MinelayerTrailerPosition::fromJson(data)); break; case Constraints::id(): // 185 rxData(EquipmentEvent::fromJson(data)); break; case Constraints::id(): // 200 rxData(EquipmentGearAssignment::fromJson(data)); break; case Constraints::id(): // 202 rxData(EquipmentGearChargeState::fromJson(data)); break; case Constraints::id(): // 205 rxData(BiteReport::fromJson(data)); break; case Constraints::id(): // 210 rxData(EquipmentGearEvent::fromJson(data)); break; case Constraints::id(): // 213 rxData(ParticipantSwVersions::fromJson(data)); break; case Constraints::id(): // 231 rxData(ParticipantModeReport::fromJson(data)); break; case Constraints::id(): // 233 rxData(ParticipantConfigurationReport::fromJson(data)); break; case Constraints::id(): // 1120 rxData(EmergencyCall::fromJson(data)); break; case Constraints::id(): // 240 rxData(SanitationRepair::fromJson(data)); break; case Constraints::id(): // 241 rxData(SanitaryMaterialStockReport::fromJson(data)); break; case Constraints::id(): // 242 rxData(Sanitation::fromJson(data)); break; case Constraints::id(): rxData(ApacheLaserDesignation::fromJson(data)); break; case Constraints::id(): // 2013 emit tetraConnectionChanged(ProxyConnectionState::fromJson(data).connectedToSystem); break; case Constraints::id(): // 2014 emit participantLicenseChange(ParticipantLicenseChange::fromJson(data)); break; default: WARNING_LOG(m_logger) << "Handler for telegram Id " << typeId.toInt() << " not yet implemented (" << baJson << ")"; return false; } } catch (const std::exception &e) { WARNING_LOG(m_logger) << "Could not parse json: " << e.what() << " (" << baJson << ")"; return false; } return true; } void TetraHandlerRx::handleAcknowledge(qint64 timeStamp, int counter) { TRACE_LOG(m_logger) << "Ack from Socket for time " << timeStamp << " with counter " << counter << ", initial: " << m_bWaitForInitialAck; if (m_bWaitForInitialAck) { m_bWaitForInitialAck = false; emit initialAckReceived(); m_ackTimer->start(); } } void TetraHandlerRx::onAckTimeout() { TrainingAreaBase::TetraIcd::Acknowledge ack; ack.timeStamp = time(nullptr) * 1000; ack.ackCounter = m_receiveCounter; emit txData(ack); } template void TetraHandlerRx::rxData(const T &data) { if (!m_rxHandler) { if (!m_bWarnedOnce) { ERROR_LOG(m_logger) << "No RecvFromTab available"; m_bWarnedOnce = true; } return; } return m_rxHandler->rxData(data); } } // namespace WlsTetra