/** * $Id$ * $HeadURL$ * $Author$ */ #include "tetra_if.h" #include "dgps_config.h" #include #include #include #include #include #include #include #include namespace DifferentialGPS { void TetraIF::startThreadInternal(int threadIndex) { const DgpsConfig::TetraConfig_t &cfg = DgpsConfig::instance().getTetraConfig(); m_srcIssi = cfg.issi[threadIndex]; m_broadcastIssi = cfg.broadcastIssi[threadIndex]; m_feedbackTimeout_ms = cfg.feedbackTimeout_ms; TcpSocket::startThreadInternal(cfg.ip[threadIndex], cfg.port[threadIndex]); } void TetraIF::run() { m_feedbackTimeout = new QTimer(this); m_feedbackTimeout->setSingleShot(true); connect(m_feedbackTimeout, &QTimer::timeout, this, &TetraIF::onFeedbackTimeout); TcpSocket::run(); m_feedbackTimeout->disconnect(this); delete m_feedbackTimeout; m_feedbackTimeout = nullptr; } void TetraIF::onNewDataAvailable() { if (m_socket->state() != QAbstractSocket::ConnectedState) { DEBUG_LOG(m_logger) << "Can not send new data to Tetra - not yet connected (" << m_socket->state() << ")"; return; } if (!m_bTetraOk) { DEBUG_LOG(m_logger) << "Can not send new data to Tetra - not yet logged in"; return; } if (onNewDataAvailableInternal()) { // feedback expected; start feedback timeout timer m_feedbackTimeout->start(m_feedbackTimeout_ms); } } void TetraIF::onFeedbackTimeout() { ERROR_LOG(m_logger) << "Tetra feedback timeout" << m_socket->peerAddress().toString() << ":" << m_socket->peerPort(); m_socket->disconnectFromHost(); if (m_socket->state() != QAbstractSocket::UnconnectedState) m_socket->waitForDisconnected(); exit(3); } bool TetraIF::checkTetraConnecting() { return m_bTetraOk; } void TetraIF::doInitialLogin() { N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_srcIssi); m_socket->write(tele.data()); m_socket->flush(); } void TetraIF::onConnected() { TcpSocket::onConnected(); m_counter = 1; doInitialLogin(); } void TetraIF::onDisconnected() { INFO_LOG(m_logger) << "Disconnected from " << m_socket->peerAddress().toString() << ":" << m_socket->peerPort(); exit(3); // stop the thread } void TetraIF::onReadyRead() { do { DEBUG_LOG(m_logger) << "Reading " << m_socket->bytesAvailable() << " from " << m_socket->peerAddress().toString() << ":" << m_socket->peerPort(); // read the 4-byte frame-header for find out the length of whole telegram N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; if (m_socket->bytesAvailable() < (int)sizeof(header)) return; m_socket->peek((char *)&header, sizeof(header)); if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) { ERROR_LOG(m_logger) << "Incorrect magic number (0x" << (int)header.m_MagicNumber << " - aborting"; exit(2); } if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) { ERROR_LOG(m_logger) << "Radio-Telegram length to big: " << header.m_Length << ", but I proceed with this telegram."; } quint16 dataSize = header.m_Length + sizeof(header); if (m_socket->bytesAvailable() < dataSize) { INFO_LOG(m_logger) << "not enough bytes available"; return; } uint8_t *data = new uint8_t[dataSize]; m_socket->read((char *)data, dataSize); handleReceivedTelegram(data, dataSize); } while (m_socket->bytesAvailable()); } void TetraIF::onError(QAbstractSocket::SocketError err) { ERROR_LOG(m_logger) << "Socket error: " << err << " " << m_socket->errorString() << ":" << m_socket->peerPort(); m_socket->disconnectFromHost(); if (m_socket->state() != QAbstractSocket::UnconnectedState) m_socket->waitForDisconnected(); exit(3); } void TetraIF::handleReceivedTelegram(uint8_t *a_data, quint16 a_dataSize) { if (a_dataSize < 4) { ERROR_LOG(m_logger) << "To few bytes for handle receieved telegramm (" << a_dataSize << ")"; return; } switch (a_data[4]) { // response to register indication case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: INFO_LOG(m_logger) << "Got data from Tetra ..."; if (m_feedbackTimeout->isActive()) m_feedbackTimeout->stop(); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: if (a_dataSize < 5) { ERROR_LOG(m_logger) << "To few bytes for handle register response telegramm (" << a_dataSize << ")"; return; } handleRegisterRsp(a_data[5]); // registration status break; default: INFO_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << (int)a_data[4] << " ignored"; break; } } void TetraIF::handleRegisterRsp(const uint8_t a_registrationStatus) { std::stringstream logText; switch (a_registrationStatus) { case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered: INFO_LOG(m_logger) << "Valid register response from Tetra"; m_bTetraOk = true; onAddGroupMonitoring(); onNewDataAvailable(); return; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI: logText << "TETRA: Register-Response: Status=Duplicate ISSI"; break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI: logText << "TETRA: Register-Response: Status=Invalid ISSI"; break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress: logText << "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address ("; { const QList ipList = QNetworkInterface::allAddresses(); QList::const_iterator iter = ipList.begin(); while (iter != ipList.end()) { logText << (*iter).toString().toStdString() << ", "; ++iter; } logText << ")..."; } break; default: logText << "Unknown registration status: " << (int)a_registrationStatus; break; } ERROR_LOG(m_logger) << logText.str(); exit(2); } void TetraIF::onAddGroupMonitoring() { std::set groupsToMonitor; groupsToMonitor.insert(m_broadcastIssi); N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_srcIssi, groupsToMonitor); tele.setZaehler(m_counter++); m_socket->write(tele.data()); m_socket->flush(); NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Debug, tele.data()); } } // namespace DifferentialGPS