560 lines
16 KiB
C++
560 lines
16 KiB
C++
// **************************************************************************
|
|
//
|
|
// (C) Copyright 2009 Swiss SIMTEC AG
|
|
//
|
|
// **************************************************************************
|
|
//
|
|
// $HeadURL$
|
|
// $LastChangedBy$
|
|
// $LastChangedDate$
|
|
// $LastChangedRevision$
|
|
//
|
|
// Implementation of the Class PrtCnvDbThread
|
|
// **************************************************************************
|
|
|
|
#pragma once
|
|
|
|
#include <QtCore/QAtomicInt>
|
|
#include <QtCore/QMutex>
|
|
#include <QtCore/QString>
|
|
#include <QtSql/QSqlDatabase>
|
|
#include "PrtCnvThread.hpp"
|
|
#include "PrtCnvRadioThread.hpp"
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace N_CoPrtCnv
|
|
{
|
|
class CoPrtCnvCentralTelegram;
|
|
class CoPrtCnvRadioTelegram;
|
|
}
|
|
|
|
namespace PrtCnv
|
|
{
|
|
class PrtCnvThreadStarter;
|
|
class PrtCnvStoredCentralTelegram;
|
|
class PrtCnvStoredRadioTelegram;
|
|
class PrtCnvMember;
|
|
/**
|
|
* Handles all data which must be stored permanent:
|
|
* - central-telegrams
|
|
* - radio-telegrams
|
|
* - radio-members (TNE)
|
|
* - reset-counter
|
|
* - states
|
|
*
|
|
* @author wia
|
|
* @version 1.0
|
|
* @created 28-Jul-2009 16:08:53
|
|
*/
|
|
class PrtCnvDbThread : public PrtCnvThread
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
/**
|
|
* Constructor with thread-starter as argument
|
|
*
|
|
* @param a_parent
|
|
*/
|
|
PrtCnvDbThread(const QString &dbDriver,
|
|
const QString &dbHostName,
|
|
const QString &dbDatabaseName,
|
|
const QString &schemaName,
|
|
const QString &dbUserName,
|
|
const QString &dbPassword,
|
|
PrtCnvThreadStarter* a_parent);
|
|
~PrtCnvDbThread();
|
|
|
|
/**
|
|
* starts this thread and its childs
|
|
*/
|
|
int32_t start() override;
|
|
/**
|
|
* stops this thread and its childs
|
|
*/
|
|
int32_t stop() override;
|
|
/**
|
|
* creates this thread and its childs
|
|
*/
|
|
int32_t create(NGL::Settings *settings) override;
|
|
/**
|
|
* initializes this thread and its childs
|
|
*/
|
|
int32_t init() override;
|
|
/**
|
|
* Indicates the Db, which telegrams were successful received by central. This
|
|
* will delete this telegrams from Db.
|
|
*
|
|
* @param a_counter
|
|
*/
|
|
void ackCentralTelegrams(int32_t a_counter);
|
|
|
|
/**
|
|
* returns the next telegram to send to central.
|
|
* returns NULL if no telegram found.
|
|
* ATTENTION: The caller is responsible to deallocate the returned
|
|
* centralTelegram!
|
|
*
|
|
* @param a_handle
|
|
*/
|
|
N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextCentralTelegram(PrtCnvStoredCentralTelegram *& a_handle);
|
|
|
|
/**
|
|
* Marks the central-telegram as to be sent
|
|
*
|
|
* @param a_counter The counter the telegram has while sent
|
|
* @param a_handle The telegram-handle gotten from getNextCentralTelegram()
|
|
*/
|
|
void centralTelegramSent(const int32_t a_counter, PrtCnvStoredCentralTelegram *a_handle);
|
|
|
|
/**
|
|
* Updates the counter for unsuccessful sending the telegram. If a maximal value
|
|
* of this counter is reached, the central-telegram will be deleted.
|
|
* a_handle could be deleted after calling this function!
|
|
* This function could block some milliseconds, because it must wait until all
|
|
* changes are written to DB.
|
|
*
|
|
* @param a_handle The telegram-handle gotten from getNextCentralTelegram()
|
|
*/
|
|
void centralTelegramCouldNotBeSent(PrtCnvStoredCentralTelegram *a_handle);
|
|
|
|
/**
|
|
* Marks the radio-telegram as to be sent
|
|
*
|
|
* @param a_sendCounter
|
|
* @param a_handle
|
|
* @param a_broadcastIndex
|
|
*/
|
|
void radioTelegramSent(const uint32_t a_sendCounter, PrtCnvStoredRadioTelegram *a_handle, const uint32_t a_broadcastIndex);
|
|
|
|
/**
|
|
* returns the next telegram to send to radio, respecting the priority.
|
|
* returns NULL if no radio-telegram found.
|
|
*
|
|
* @param a_handle
|
|
*/
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> getNextRadioTelegram(PrtCnvStoredRadioTelegram *&a_handle);
|
|
|
|
/**
|
|
* returns the next broadcast-telegram from list.
|
|
* Deletes the telegram from this list.
|
|
* returns NULL if list empty.
|
|
*/
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> getNextBroadcastTelegram();
|
|
|
|
/**
|
|
* stores the telegram to be sent to central in working-list and also in Db.
|
|
* Because storing data in XDR_Wrapper_it-format is complicated (has pointer to
|
|
* data), we store them in the radio-telegram-format).
|
|
* Attention: Be aware that centralTelegram and radioTelegram contain the same
|
|
* data.
|
|
* The DbThread takes control over centralTelegram and radioTelegram and deletes
|
|
* them when no longer needed.
|
|
*
|
|
* @param a_centralTelegram
|
|
* @param a_radioTelegram Must be the same telegram like the central-telegram
|
|
* (used for storing the telegram in Db)
|
|
*/
|
|
void storeCentralTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvCentralTelegram> &a_centralTelegram,
|
|
const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram);
|
|
|
|
/**
|
|
* Stores the telegram to be sent to radio in working-list and also in Db.
|
|
* The DbThread takes control over a_telegram and deletes it when no longer needed.
|
|
*
|
|
*
|
|
* @param a_telegram
|
|
* @param a_readCounter
|
|
*/
|
|
void storeRadioTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_telegram, const int32_t a_readCounter);
|
|
|
|
/**
|
|
* This function causes acking a central-telegram, which must not be stored
|
|
* permanent in Db, because it will be handled immediately (i.e.
|
|
* AnforderungStatistikBroadcastNachforderungen).
|
|
*
|
|
* @param a_centralCounter The read-counter of the central-telegram
|
|
*/
|
|
void centralCounterReadyForAck(const int32_t a_centralCounter);
|
|
|
|
/**
|
|
* Adds an sql-command in the sql-command-list. On next iteration of
|
|
* storePermanent() all command in list will be executed.
|
|
*
|
|
* @param a_sqlCommand
|
|
*/
|
|
void addSqlCommand(const QString &sql);
|
|
|
|
|
|
/**
|
|
* erases and initializes the database
|
|
*/
|
|
void cleanAndInit();
|
|
|
|
/**
|
|
* Checks whether central-telegrams have to be resent. If yes, all actions will be
|
|
* done, that getNextCentralTelegram() delivers the telegram(s) to be resent.
|
|
* Returns true if there must telegrams be resent.
|
|
*
|
|
* @param a_lastSendCounter The counter of the telegram we expect a ack-
|
|
* telegram has been received
|
|
*/
|
|
bool resendCentralTelegrams(const int32_t a_lastSendCounter);
|
|
|
|
/**
|
|
* Prepares the telegrams not yet acked from central for reconnection. This will
|
|
* be done by setting the write-counter to 0.
|
|
*/
|
|
void prepareCentralTelegramsForReconnection();
|
|
|
|
/**
|
|
* Blocks until all SQL-commands were written to DB.
|
|
*/
|
|
void waitUntilDbWritten();
|
|
|
|
/**
|
|
* returns NULL if no member found
|
|
*
|
|
* @param a_ISSI
|
|
*/
|
|
PrtCnvMember* getMemberByISSI(const uint32_t a_ISSI) const;
|
|
|
|
/**
|
|
* returns NULL if member not found
|
|
*
|
|
* @param a_id
|
|
*/
|
|
PrtCnvMember* getMemberById(const uint16_t a_id);
|
|
|
|
/**
|
|
* Licenses the member
|
|
*
|
|
* @param a_member
|
|
* @param a_doLicense
|
|
*/
|
|
bool licenseMember(PrtCnvMember *a_member, const bool a_doLicense = true);
|
|
|
|
/**
|
|
* Updates the current exercise for this member
|
|
*/
|
|
void updateExerciseIdForMember(PrtCnvMember *a_member, int newExerciseId);
|
|
|
|
/**
|
|
* adds a member in the 2 maps, sorted by id and ISSI
|
|
* returns the new member
|
|
*
|
|
* @param a_identity
|
|
* @param a_ISSI
|
|
*/
|
|
PrtCnvMember* addMember(const int a_identity, const int a_ISSI);
|
|
|
|
/**
|
|
* removes the member in the 2 maps, sorted by id and ISSI
|
|
*
|
|
* @param a_member
|
|
*/
|
|
void removeMember(PrtCnvMember* a_member);
|
|
|
|
/**
|
|
* Returns the actual reset-counter
|
|
*/
|
|
uint8_t getResetCounter() const;
|
|
|
|
/**
|
|
* Sets the actual reset-counter
|
|
*
|
|
* @param newVal
|
|
*/
|
|
void setResetCounter(uint8_t newVal);
|
|
|
|
/**
|
|
* The actual 'Betriebszustaende Gefechtsfeld' which will be sent to TNEs
|
|
* periodically
|
|
*/
|
|
uint8_t getBattleFieldOperatingState() const;
|
|
|
|
/**
|
|
* Sets or unsets pause, depending on a_doSet.
|
|
* (Bit 0 in UMGEBUNGS_MELDUNG(2))
|
|
* @param a_doSet
|
|
*/
|
|
void setPause(const bool a_doSet = true);
|
|
|
|
/**
|
|
* Set the inhibit time for position telegrams (1 .. 31 Seconds)
|
|
* (Bit 1-5 in UMGEBUNGS_MELDUNG(2))
|
|
* @param a_doSet
|
|
*/
|
|
void setPositionSendTime(unsigned int sendTime);
|
|
|
|
/**
|
|
* Set the current air load to be sent with the Umgebungsmeldung
|
|
* (Bit 6-7 in UMGEBUNGS_MELDUNG(2))
|
|
* @param airLoad The current air-load received from Tetra
|
|
*/
|
|
void setAirLoad(PrtCnvRadioThread::E_TrafficLoad airLoad);
|
|
|
|
/**
|
|
* Returns true if the resetCounter itself is different than the reset-counter of
|
|
* the environment-telegram
|
|
*/
|
|
bool isEnvironmentResetCounterOld() const;
|
|
|
|
/**
|
|
* Returns the actual Umgebungsmeldung
|
|
*/
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> getEnvironmentTelegram();
|
|
|
|
/**
|
|
* Sets the resetcounter of the environment-telegram to the actual reset-counter.
|
|
*/
|
|
void setResetCounterOnEnvironment();
|
|
|
|
/**
|
|
* Increments the counter for nachforderungen of the TNE with id a_identity.
|
|
*
|
|
* @param a_identity The identity of the TNE, which asked for nachforderung
|
|
*/
|
|
void incClaimCount(int a_identity);
|
|
|
|
/**
|
|
* Fills the map with nachforderungsstatistic.
|
|
* Returns the number of elements in map.
|
|
*
|
|
* @param a_statisticMap this map will be filled with pairs of
|
|
* ausstattungsnummer and amount of nachforderungen
|
|
*/
|
|
std::map<int32_t, int32_t> getClaimStatistics() const;
|
|
|
|
/**
|
|
* Sets the actual machine-state permanent, used to proceed cleaning db after a
|
|
* crash.
|
|
*
|
|
* @param a_newMachineState The new machine-state. 0 => working; 1 => cleaning
|
|
* DB
|
|
*/
|
|
void setMachineState(const int a_newMachineState);
|
|
|
|
/**
|
|
* Returns true if protocol-converter was crashed while cleanup DB.
|
|
*/
|
|
bool mustProceedCleanup() const;
|
|
|
|
protected:
|
|
void closeDb();
|
|
|
|
/**
|
|
* List of telegrams to be sent to central
|
|
*/
|
|
std::vector<PrtCnvStoredCentralTelegram*> m_CentralList;
|
|
|
|
/**
|
|
* Synchronizes access to m_BattleFieldOperatingState
|
|
*/
|
|
mutable QMutex m_BattleFieldOpStateMutex;
|
|
|
|
/**
|
|
* Synchronizes access to m_BattleFieldOperatingState
|
|
*/
|
|
mutable QMutex m_MemberListByIdMutex;
|
|
|
|
/**
|
|
* Synchronizes access to m_CentralList
|
|
*/
|
|
mutable QMutex m_CentralListMutex;
|
|
|
|
/**
|
|
* The permanent DB
|
|
*/
|
|
QSqlDatabase m_db;
|
|
|
|
/**
|
|
* The last counter received from central as ack. Used for deleting no longer used
|
|
* central-telegrams and for resending of central-telegrams.
|
|
*/
|
|
QAtomicInt m_CentralAckCounter;
|
|
/**
|
|
* Used for optimizing deletion of no longer needed central-telegrams.
|
|
*/
|
|
unsigned int m_OldCentralAckCounter;
|
|
/**
|
|
* List of telegrams to be sent to radio
|
|
*/
|
|
std::list<PrtCnvStoredRadioTelegram*> m_RadioList;
|
|
/**
|
|
* Synchronizes access to m_RadioList
|
|
*/
|
|
mutable QMutex m_RadioListMutex;
|
|
/**
|
|
* Holds the sql-command, which have to be executed in next physical storing cycle
|
|
*/
|
|
std::vector<QString> m_SqlCommandList;
|
|
/**
|
|
* Synchronizes access to m_SqlCommandList
|
|
*/
|
|
mutable QMutex m_SqlCmdListMutex;
|
|
/**
|
|
* Synchronizes access to m_BroadcastList
|
|
*/
|
|
mutable QMutex m_BroadcastMapMutex;
|
|
/**
|
|
* List of broadcast-telegrams. The broadcast-manager will get them periodically
|
|
* out of this list.
|
|
*/
|
|
std::list<PrtCnvStoredRadioTelegram*> m_BroadcastList;
|
|
/**
|
|
* Used to wait until cleaning is finished and to suppress storing data within
|
|
* database while cleaning
|
|
*/
|
|
bool m_DoClean;
|
|
/**
|
|
* Used for waiting data written to DB
|
|
*/
|
|
bool m_DoWaitUntilSqlWritten;
|
|
/**
|
|
* Holds all logged in members ordered by Id.
|
|
*/
|
|
std::unordered_map<int,PrtCnvMember*> m_MemberListById;
|
|
/**
|
|
* Holds all logged in members ordered by ISSI
|
|
*/
|
|
std::unordered_map<int,PrtCnvMember*> m_MemberListByISSI;
|
|
/**
|
|
* Used to prevent data storing within DB while restoring after crash
|
|
*/
|
|
bool m_DoStorePermanent;
|
|
/**
|
|
* the actual reset-counter
|
|
*/
|
|
uint8_t m_ResetCounter;
|
|
/**
|
|
* The actual 'Betriebszustaende Gefechtsfeld' which will be sent to TNEs
|
|
* periodically
|
|
*/
|
|
uint8_t m_BattleFieldOperatingState;
|
|
/**
|
|
* The actual telegram "Umgebungsmeldung"
|
|
*/
|
|
PrtCnvStoredRadioTelegram* m_EnvironmentTelegram;
|
|
/**
|
|
* True if cleanup has to be proceed after crash.
|
|
*/
|
|
bool m_DoProceedCleanup;
|
|
/**
|
|
* Used to optimize send the signal permanentStored
|
|
*/
|
|
int32_t m_OldCentralCounter;
|
|
/**
|
|
* For ensure that not too much storePermanent-signals will be queued
|
|
*/
|
|
QBasicAtomicInt m_StorePermanentPending;
|
|
|
|
/**
|
|
* nbr of unsuccessful send-attempts, before telegram will be deleted without
|
|
* sending it
|
|
*/
|
|
uint32_t m_NbrOfAttempts;
|
|
|
|
/**
|
|
* creates or restores the permanent database
|
|
*/
|
|
bool createDatabase();
|
|
|
|
/**
|
|
* Sends a signal storePermanent if not already such a signal is pending
|
|
*/
|
|
void sendStorePermanentSignal();
|
|
|
|
/**
|
|
* Helper for storePermanent()
|
|
*/
|
|
void storeCentralTelegrams();
|
|
|
|
/**
|
|
* Helper for storePermanent()
|
|
*/
|
|
int32_t storeRadioTelegrams();
|
|
|
|
/**
|
|
* Helper for storePermanent()
|
|
*/
|
|
void handleSqlCommandList();
|
|
|
|
/**
|
|
* Delete all telegrams with the ids in telegramsToDelete
|
|
* from a given table
|
|
*/
|
|
void deleteTelegramsFromDbById(const QString &table);
|
|
/**
|
|
* Update the write counter for the telegrams in
|
|
* telegramsToUpdateCounter for the given table
|
|
*/
|
|
void updateTelegramsWriteCounter(const QString &table);
|
|
|
|
/**
|
|
* Update the broadcast counter for the telegrams in
|
|
* telegramsToUpdateCounter for the given table
|
|
*/
|
|
void updateTelegramsBroadcast(const QString &table);
|
|
|
|
/**
|
|
* Reinitialize the database
|
|
*/
|
|
void reinitDatabase();
|
|
|
|
QString toCentralTableName() const { return tableName(QStringLiteral("prtcnv_to_central")); }
|
|
QString toRadioTableName() const { return tableName(QStringLiteral("prtcnv_to_radio")); }
|
|
QString memberTableName() const { return tableName(QStringLiteral("prtcnv_member")); }
|
|
QString statusTableName() const { return tableName(QStringLiteral("prtcnv_status")); }
|
|
QString versionTableName() const { return tableName(QStringLiteral("prtcnv_version")); }
|
|
QString tableName(const QString &table) const { return m_dbSchemaName.isEmpty() ? table : m_dbSchemaName + QLatin1Char('.') + table; }
|
|
protected slots:
|
|
/**
|
|
* Stores the radio-telegrams, central-telegrams in Db and executes the sql-
|
|
* command-list.
|
|
*/
|
|
void storePermanent();
|
|
/**
|
|
* cleans up this thread and its childs
|
|
*/
|
|
void clean();
|
|
|
|
public:
|
|
signals:
|
|
/**
|
|
* Signal to call storePermanent()
|
|
*/
|
|
void doStorePermanent();
|
|
/**
|
|
* Signal to inform central-thread about stored telegrams
|
|
*
|
|
* @param a_centralCounter
|
|
*/
|
|
void permanentStored(int32_t a_centralCounter);
|
|
/**
|
|
* a signal to erase the permanent database
|
|
*/
|
|
void doClean();
|
|
|
|
void playerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind);
|
|
|
|
private:
|
|
// local caches to memory (re)allocation all the time
|
|
// note: std::vector.clear() does not release memory and therefore
|
|
// a reallocation in the next turn is not neccessary
|
|
std::vector<int64_t> m_telegramsToDelete;
|
|
std::vector<std::pair<int64_t, int32_t> > m_telegramsToUpdateCounter;
|
|
std::vector<std::pair<int64_t, int32_t> > m_telegramsToUpdateBC;
|
|
std::vector<std::pair<PrtCnvStoredCentralTelegram*, int64_t> > m_telegramsToInsert;
|
|
QString m_dbDriver;
|
|
QString m_dbHostName;
|
|
QString m_dbDatabaseName;
|
|
QString m_dbSchemaName;
|
|
QString m_dbUserName;
|
|
QString m_dbPassword;
|
|
};
|
|
|
|
}
|