// ************************************************************************** // // (C) Copyright 2009 Swiss SIMTEC AG // // ************************************************************************** // // $HeadURL$ // $LastChangedBy$ // $LastChangedDate$ // $LastChangedRevision$ // // Implementation of the Class PrtCnvRadioThread // ************************************************************************** #pragma once #include "PrtCnvSocketThread.hpp" #include "PrtCnvBroadcastMgr.hpp" #include #include #include #include #include #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 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 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 &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 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> m_exerciseEquipmentAssignments; std::unordered_map 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 &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 &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 &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 &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 &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); }