Files
qt5-legatus-legacy/TetraIF/PrtCnv/PrtCnvRadioThread.hpp
2026-08-13 18:33:10 +02:00

584 lines
17 KiB
C++

// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// Implementation of the Class PrtCnvRadioThread
// **************************************************************************
#pragma once
#include "PrtCnvSocketThread.hpp"
#include "PrtCnvBroadcastMgr.hpp"
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
#include <set>
#include <QList>
#include <QMutex>
#include <TrainingAreaBase/training_area_telegrams.h>
#define MAX_IDENTITY 65535
namespace PrtCnv
{
struct BiteError
{
int errorNumber = 0;
int canDeviceNumber = 0;
int subdeviceNumber = 0;
int uniqueId = 0;
};
class PrtCnvCentralThread;
class PrtCnvMember;
class PrtCnvRadioTrafficThread;
class PrtCnvStoredRadioTelegram;
/**
* This class handles the protocol to radio. This includes:
* - handle login and licensing of TNEs
* - send and receive normal telegrams
* - send normal broadcasts and nachforderungen
* - optimize bandwith usage
*
* @author
* @version 1.0
* @created 05-Jan-2006 13:34:41
*/
class PrtCnvRadioThread : public PrtCnv::PrtCnvSocketThread
{
Q_OBJECT
public:
PrtCnvRadioThread(int exerciseId, PrtCnvThreadStarter* a_parent);
/**
* Creates all subcomponents and connects signals to slots
*/
int32_t create(NGL::Settings *settings) override;
/**
* Deallocates subcomponents.
*/
int32_t destroy() override;
/**
* Initializes the variables.
*/
int32_t init() override;
/**
* Starts the thread and connects to TCP-server
*/
int32_t start() override;
/**
* Makes empty the message-queue faster, because the messages will be consumed
* without action.
*/
void prepareCleanUp();
/**
* Immediatelly send the environment telegramm to inform the players
* about the new state
*/
void sendEnvironmentTelegramTimerNow();
void exerciseEquipmentChanged(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data);
protected:
void onCheckMemberForValidLogin(int identity, int issi);
void sendLoginAccept(int identity, int issi, int exerciseId, bool bWithMastering);
bool isIdentityInCurrentExercise(int identity) const;
int exerciseIdForIdentity(int identity) const;
void removeMasteringMember(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram, PrtCnvMember *member,
PrtCnvMember *issiMember,
int masterIdentity,
int masterIssi);
protected:
/**
* Pointer to central-thread
*/
PrtCnvCentralThread *m_CentralThread;
/**
* Pointer to radio traffic counter thread
*/
PrtCnvRadioTrafficThread *m_radioTrafficThread;
public:
Q_SIGNALS:
/**
* Signal to start sending a telegram to central
*/
void checkSendToCentral();
/**
* Signal to start sending a telegram to radio
*/
void checkSendToRadio();
/**
* Signal to indicate thread has finished the cleaning-phase
*/
void cleant();
/**
* Signal to indicate thread has stopped work
*/
void stopped();
/**
* a new equipment exercise mapping was received, check if member (all when identiy = -1)
* is still in this exercise
*/
void checkMemberForValidLogin(int identity, int issi);
// emitted when the tetra connection state changes
void tetraConnectionState(bool connected);
// an effect siumlation was (de)activated
void areaEffectSimulationActivated(int wirkfeldKennung);
void areaEffectSimulationDeactivated(int wirkfeldKennung);
// initialization of the thread is finished
void initDone();
// a player was (un)licensed
void playerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind);
void warehouseMessageFromPtrCnv(const QByteArray &jsonData);
protected:
/**
* Counts the sended telegrams
*/
uint32_t m_SendCounter;
/**
* The ISSI of the protocol-converter
*/
uint32_t m_HostISSI;
/**
* The lowest vaild value for the counter
*/
const uint32_t START_COUNTER;
/**
* One more than the highest vaild value for the counter
*/
const uint32_t END_COUNTER;
/**
* This timer will be used for periodically send the Umgebungsmeldung to TNEs
*/
QTimer *m_EnvironmentTelegramTimer;
/**
* The ISSI used for broadcast-telegrams
*/
uint32_t m_BroadcastISSI;
/**
* The directory and prefix for the login-log-file
*/
QString m_LoginPathWithPrefix;
/**
* Übungskennung (used for login-logfile name)
*/
int m_ExerciseId;
/**
* Bit-map for evaluating whether a playerid is valid
*/
std::set<uint16_t> m_AllowedIdentities;
/**
* true => TPU will be licensed whether selftest and configtest fails or not
*/
bool m_DoLicenseDespiteSelftestOrConfigFailure;
/**
* true => identify of TPU will be checked, whether allowed
*/
bool m_DoCheckIdentity;
PrtCnvBroadcastMgr m_BroadcastManager;
/**
* True => received telegrams will be dumped to common log-file
*/
bool m_DoDumpReceivedTelegrams;
/**
* True => sent telegrams will be dumped to common log-file
*/
bool m_DoDumpSentTelegrams;
/**
* True => radio-telegrams will be sent in SDS-TL-format
*/
bool m_DoUseSDSTL;
/**
* Identities that need an active position response after licensing
*/
std::set<uint16_t> m_DoNeedActPosResp;
/**
* The ISSI used for emergency call-telegrams
*/
uint32_t m_EmergencyCallISSI;
/**
* Sends a telegram to radio. It will be fragmented if needed. It will be checked,
* whether the receiver is logged in, licensed, the content is valid and the
* telegram is not expired and an error-message will be sent to central if needed.
* It will be tested, whether the maximal broadcast-counter is reached and if it
* is, the needed action will be done.
*
* @param a_telegram
* @param a_handle
* @param a_doCheckWhetherExpired
*/
void sendTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_telegram,
PrtCnvStoredRadioTelegram *a_handle,
const bool a_doCheckWhetherExpired = true);
/**
* Sends the register-indication to TETRA
*/
void doRegister();
/**
* Send a register group message to TETRA
*/
void registerGroups();
/**
* Processes the register-response-telegram
*
* @param a_regsitrationStatus
*/
void handleRegisterRsp(const uint8_t a_regsitrationStatus);
public:
/**
* @author alois.wismer
* @version 1.0
* @updated 06-Apr-2010 16:01:59
*/
enum class E_TrafficLoad
{
Unknown = -1,
NormalLoad = 0,
HighLoad,
FullLoad
};
protected:
/**
* Holds the radio-telegram for sending Umgebungsmeldung periodically
*/
N_CoPrtCnv::CoPrtCnvRadioTelegram *m_EnvironmentTelegram;
/**
* load of traffic from Protocolconverter to TETRA
*/
E_TrafficLoad m_SendLoad;
uint32_t m_SendQueueFullLoad;
uint32_t m_SendQueueHighLoad;
uint32_t m_SendTelegramsNormalLoad;
uint32_t m_SendTelegramsHighLoad;
uint32_t m_SendTelegramsFullLoad;
/**
* The number of telegrams sent within the last second
*/
uint32_t m_SentTelegrams;
/**
* The number of bytes sent within last second
*/
uint32_t m_SentBytes;
/**
* how many times tick must be called until 1 second has elapsed
*/
uint32_t m_TickCounter;
/**
* how many times tick was called (used for knowing when 1 second has elapsed,
* which we use for sent-bytes and receive-bytes statistics)
*/
uint32_t m_TicksPerSecond;
/**
* How many values we use for computing average
*/
static const int AVERAGE_COUNT = 10;
/**
* The last few number of bytes sent, used for calculating the average
*/
uint32_t m_SentBytesAverage[AVERAGE_COUNT];
/**
* index for writing into aveage-array
*/
uint8_t m_AverageIndex;
/**
* The number of telegrams sent within the last second
*/
uint32_t m_ReceivedTelegrams;
/**
* The number of bytes sent within last second
*/
uint32_t m_ReceivedBytes;
/**
* The last few number of bytes sent, used for calculating the average
*/
uint32_t m_ReceivedBytesAverage[AVERAGE_COUNT];
/**
* The groups which should be listened to
*/
std::set<uint32_t> m_ListenGroups;
/**
* @brief use scrambling yes/no (Radio/UseScrambling)
*/
bool m_bUseScrambling;
/**
* The logger object for statistics
*/
NGL::INGLLogger &m_loggerStats;
// mapping which equipNos are in which exercise
std::unordered_map<int, std::unordered_set<int>> m_exerciseEquipmentAssignments;
std::unordered_map<int, TrainingAreaBase::TetraIcd::GroupIssiInformation> m_groupIssiInformation;
mutable QMutex m_exerciseEquipmentAssignmentMutex;
private:
/**
* generates an answer to TNE from protocoll-converter for some special radio-
* telegrams (i.e. NachforderungBroadcast, BITE-Meldung)
* returns true when the telegram must be sent to central
*
* @param a_centralTelegram
* @param a_radioTelegram
*/
bool sendAnswer(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram);
/**
* After calling this function, the caller must no longer use a_data, because this
* function 'consumes' a_data and will delete a_data, when no longer needed.
*
* @param a_data A pointer to the telegram-data, including frame-header.
* Control over a_data will be lost (see description of function itself)
*/
void handleReceivedTelegram(const QByteArray &data);
/**
* Processes the data-indication-telegram
*
* @param a_data
* @param bDoDeleteData is set to true when the caller can properly delete the data
*/
void handleDataIndReq(const QByteArray &data, bool bIsMaybeScrambled);
/**
* Processes the login-telegram
*
* @param a_loginTelegram
*/
void handleLoginTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram);
/**
* Processes a fragment of a telegram
*
* @param a_fragmentedTelegram
*/
void handleFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_fragmentedTelegram);
/**
* Sends a telegram "FehlermeldungGefechtsfeld" to central
*
* @param a_identity
* @param a_errorCause
* @param a_telegramId
*/
void sendFehlermeldungGefechtsfeldToCentral(const uint16_t a_identity,
const TrainingAreaBase::TetraIcd::CtaDataError::Reason a_errorCause,
const gef_telegramm_id_et a_telegramId = GEF_BESTAETIGUNG);
/**
* Returns the ISSI of TNE with a_TNE_Id
*
* @param a_TNE_Id
*/
uint32_t getDestinationISSI(const uint16_t a_TNE_Id) const;
/**
* Processes the BITE/BITE extended-telegram
*
* @param a_BITE_CentralTelegram
*/
bool handleBITEEXT_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram);
bool handleBITE_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram,
TrainingAreaBase::TetraIcd::BiteReport::LoginType anmeldeart,
uint32_t ergebnisCAN,
uint32_t ergebnisAusstattung,
uint32_t aktuelleKonfiguration,
uint32_t konfigurationsvergleich,
const QList<PrtCnv::BiteError> &fehlerListe
);
/**
* Sends a login-telegram to radio
*
* @param a_loginTelegramStatus
* @param a_identity
* @param a_ISSI
*/
void sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, const uint32_t a_ISSI);
void sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus,
const uint16_t a_identity, const uint32_t a_ISSI, const TrainingAreaBase::TetraIcd::GroupIssiInformation &group);
/**
* Sends a telegram "LizenzierungTNE" to radio
*
* @param a_identity AusstattungsId
* @param a_issi
* @param a_licensingKind
* @param a_errorCause
*/
void sendLizenzierungTneToRadio(const uint16_t a_identity, const uint32_t a_issi,
const N_CoPrtCnv::E_LicensingKind a_licensingKind,
const N_CoPrtCnv::E_LicensingErrorCode a_errorCause);
/**
* Writes the login of a TNE to the login-logfile
*
* @param a_radioTelegram
* @param a_prosaText
*/
void writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, const QString &a_prosaText);
void writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const QString &a_prosaText);
void writeLoginLog(uint32_t identity, uint32_t issi, const QString &a_prosaText);
/**
* Receives the file with allowed playerId, or the lowest and hightest allowed
* playerIds
*/
void initIdentityArray();
/**
* Reads one line of the playerId-file.
* Aborts when not successful
*
* @param a_idAsText
* @param a_line
* @param a_fileName
*/
uint16_t readIdentity(const QByteArray& a_idAsText, const uint32_t a_line, const QString& a_fileName);
/**
* Checks whether the playerId is allowd.
*
* @param a_identity
*/
bool isIdentityValid(uint16_t a_identity) const;
/**
* Allows this playerId.
*
* @param a_identity
*/
void setIdentityVaild(uint16_t a_identity);
/**
* Fragment a telegram and sends the fragments to radio.
*
* @param a_telegram
*/
void sendFragmentedTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_telegram);
/**
* sends the telegram to radio-socket
* returns the broadcastIndex (0 if it was no broadcast)
*
* @param a_telegram
*/
uint16_t sendToSocket(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_telegram);
/**
* Processes the report-indication-telegram
*
* @param a_data
*/
void handleReportIndReq(const QByteArray &data);
void prepareWareHouseMessage(qint32 equipNr,
bool doLicence,
qint64 ergebnisCAN,
qint64 ergebnisAusstattung,
qint64 aktuelleKonfiguration,
qint64 konfigurationsvergleich,
const QList<PrtCnv::BiteError> &fehlerListe);
protected Q_SLOTS:
/**
* @brief oslot to handle call to sendEnvironmentTelegramTimerNow in correct thread
*/
void onSendEnvironmentTelegramTimerNow();
/**
* see base-class
*/
void timeoutAliveAndConnection() override;
/**
* Processes the periodical stuff, like broadcasts and nachforderungen
*/
void timeoutTick() override;
/**
* Checks whether a normal telegram must be sent and sends it.
*/
void checkSend();
/**
* see base-class
*/
void readyRead() override;
/**
* see base-class
*/
void disconnected() override;
/**
* see base-class
*/
void connected() override;
/**
* Processes the periodical sending of Umgebungsmeldung
*/
void timeoutEnvironmentTelegram();
/**
* Clean the DB.
*/
void doClean();
/**
* Restart work after cleaning Db
*/
void doStart();
/**
* Stops work for cleaning DB
*/
void doStop();
// a broadcastTelegrams request was received from EXCON (e.g. through Wls)
void onBroadcastTelegramsRequestFromCentral(int equipmentNumber, int broadcastIndex, int resetCounter);
private:
/**
* Processes the status-telegram
*
* @param data
*/
void handleStatusIndReq(const QByteArray &data);
/**
* Processes the air-interface-report-telegram
*
* @param a_data
*/
void handleAirInterfaceLoadReq(const QByteArray &data);
/**
* Computes and logs the sent- and receive-statistics
*/
void computeAndLogTrafficStatistics();
/**
* returns true, if at the moment no more telegrams should be sent
*/
bool isSendLimitReached() const;
void sendScrambledContent(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_telegram) const;
bool unscrambleContent(N_CoPrtCnv::CoPrtCnvRadioTelegram &a_telegram) const;
friend class PrtCnvCentralThread;
};
std::ostream &operator<<(std::ostream &os, const PrtCnvRadioThread::E_TrafficLoad tl);
}