1710 lines
69 KiB
C++
1710 lines
69 KiB
C++
// **************************************************************************
|
|
//
|
|
// (C) Copyright 2009 Swiss SIMTEC AG
|
|
//
|
|
// **************************************************************************
|
|
//
|
|
// $HeadURL$
|
|
// $LastChangedBy$
|
|
// $LastChangedDate$
|
|
// $LastChangedRevision$
|
|
//
|
|
// **************************************************************************
|
|
|
|
#include "PrtCnvBroadcastMgr.hpp"
|
|
#include "PrtCnvDbThread.hpp"
|
|
#include <CoPrtCnv/CoPrtCnvRadioTelegram.hpp>
|
|
#include <CoPrtCnv/CoPrtCnvHexDumpHelper.hpp>
|
|
#include <time.h>
|
|
#include <TrainingAreaBase/training_area_telegrams.h>
|
|
|
|
namespace PrtCnv
|
|
{
|
|
|
|
PrtCnvBroadcastMgr::PrtCnvBroadcastMgr()
|
|
: m_ClaimWindow(0)
|
|
, m_HighLoadFactor(0)
|
|
, m_BroadcastLimit(0)
|
|
, m_Config(nullptr)
|
|
, m_ActClaimWindow(0)
|
|
, m_State(e_ST_UNDEFINED)
|
|
, m_TickCounter(0)
|
|
, m_DbThread(nullptr)
|
|
, m_BroadcastIndex(0)
|
|
, m_IsFullLoad(false)
|
|
, m_FinishedBroadcastIndex(0)
|
|
, m_FirstBroadcastIndexOfBc1(0)
|
|
, m_logger(getLogger("PrtCnvBroadcastMgr"))
|
|
, m_loggerBcRequest(getLogger("PrtCnvBroadcastMgr.BcRequest"))
|
|
{
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Creates all subcomponents
|
|
// ---------------------------------------------------------------
|
|
int32_t PrtCnvBroadcastMgr::create(NGL::Settings *settings)
|
|
{
|
|
m_Config = settings;
|
|
return 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Initializes the variables.
|
|
// ---------------------------------------------------------------
|
|
int32_t PrtCnvBroadcastMgr::init()
|
|
{
|
|
const QString broadcastGroup(QStringLiteral("Broadcast"));
|
|
N_CoPrtCnv::CoPrtCnvRadioTelegram::setBroadcastDelayTimes(
|
|
m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastDelay2"), 60),
|
|
m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastDelay3"), 60));
|
|
N_CoPrtCnv::CoPrtCnvRadioTelegram::setMaxBroadcastSendCnt(m_Config->getInteger(broadcastGroup, QStringLiteral("MaxBroadcastSendCount"), 1));
|
|
// the time [ms] to wait between sending broadcasts
|
|
const int sendGap = m_Config->getInteger(broadcastGroup, QStringLiteral("SendGap"), 500);
|
|
m_ClaimWindow = (m_Config->getInteger(broadcastGroup, QStringLiteral("ClaimWindow"), 30) * 1000) / sendGap;
|
|
m_HighLoadFactor = m_Config->getInteger(broadcastGroup, QStringLiteral("HighLoadFactor"), 3); // fixme: in spec steht 90sec normal und 3min für high
|
|
m_BroadcastLimit = m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastLimit"), 10);
|
|
|
|
cleanAndInit(true);
|
|
|
|
INFO_LOG(m_loggerBcRequest) << "m_ActClaimWindow=" << m_ActClaimWindow << " m_State=" << m_State;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// sets the DbThread used for get the stored broadcast-
|
|
// telegrams
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::setDbThread(PrtCnvDbThread *a_dbThread)
|
|
{
|
|
m_DbThread = a_dbThread;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Initializes the broadcast-manager. If a_deleteTelegrams is
|
|
// true, all stored telegrams and maps will be deleted.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::cleanAndInit(const bool a_deleteTelegrams)
|
|
{
|
|
if (a_deleteTelegrams)
|
|
{
|
|
m_deactivatedAesArea2bcIndex.clear();
|
|
m_deactivatedBcIndex2AesArea.clear();
|
|
|
|
m_deactivatedDusMine2bcIndex.clear();
|
|
m_deactivatedBcIndex2DusMine.clear();
|
|
|
|
m_deactivatedFuncArea2bcIndex.clear();
|
|
m_deactivatedBcIndex2FuncArea.clear();
|
|
|
|
m_BroadcastMap.clear();
|
|
|
|
m_LastTelegramMap.clear(); // the telegrams itself were already deleted while looping through broadcastmap
|
|
m_FunktionsraumTelegramMap.clear(); // the telegrams itself were already deleted while looping through broadcastmap
|
|
m_WirkfeldTelegramMapByKennung.clear(); // the telegrams itself were already deleted while looping through broadcastmap
|
|
m_WirkfeldTelegramMapByTime.clear(); // the telegrams itself were already deleted while looping through broadcastmap
|
|
|
|
m_BroadcastIndex = 0;
|
|
}
|
|
|
|
m_claimerArray.clear();
|
|
|
|
m_ActClaimWindow = m_ClaimWindow;
|
|
m_IsFullLoad = false;
|
|
m_TickCounter = 0;
|
|
m_State = e_ST_COLLECT;
|
|
|
|
m_FinishedBroadcastIndex = 0;
|
|
m_FirstBroadcastIndexOfBc1 = 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// returns true when the telegram should be sent to central
|
|
// ---------------------------------------------------------------
|
|
bool PrtCnvBroadcastMgr::handleRadioTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram)
|
|
{
|
|
switch (a_radioTelegram.getTelID())
|
|
{
|
|
case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME:
|
|
handleNachforderungBroadcastTelegram(a_radioTelegram.getIdentity(),
|
|
a_radioTelegram.getPayloadDataUInt32(8, 2) + 1,
|
|
a_radioTelegram.getPayloadDataUInt8(7));
|
|
return false;
|
|
default:
|
|
// nothing
|
|
break;
|
|
}
|
|
return true; // => send the telegram to central
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Adds the TNE to the nachforderungs-list
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::handleNachforderungBroadcastTelegram(int identity, int broadcastIndex, int resetCounter)
|
|
{
|
|
INFO_LOG(m_loggerBcRequest) << "Got NachforderungBroadcast from TNE with id=" << identity
|
|
<< " resetCounter=" << resetCounter
|
|
<< " broadcastIndex=" << broadcastIndex - 1
|
|
<< " m_TickCounter=" << m_TickCounter << " m_State=" << m_State;
|
|
if (resetCounter == m_DbThread->getResetCounter())
|
|
{
|
|
m_DbThread->incClaimCount(identity);
|
|
// already in there?
|
|
for (auto &ebi : m_claimerArray)
|
|
{
|
|
if (ebi.equipNo == identity)
|
|
{
|
|
ebi.bcIndex = broadcastIndex;
|
|
return;
|
|
}
|
|
}
|
|
m_claimerArray.emplace_back(identity, broadcastIndex);
|
|
return;
|
|
}
|
|
WARNING_LOG(m_logger) << "NachforderungBroadcast from TNE with id=" << identity
|
|
<< ": resetCounter different we have: " << int(m_DbThread->getResetCounter())
|
|
<< "; TNE has: " << resetCounter << " => discarded";
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// returns the next normal broadcast to send.
|
|
// Use the same a_currentTime in one tick-loop.
|
|
// ---------------------------------------------------------------
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::getNextBroadcastTelegramToSend(const uint16_t a_beginSearchWithBroadcastIndex,
|
|
const time_t a_currentTime)
|
|
{
|
|
|
|
// iterate the braodcast-list and get the next broadcast to send
|
|
// but check whether it is not a sammeltelegram or has an attached
|
|
// broadcast-only-telegram
|
|
DEBUG_LOG(m_logger) << "getNextBroadcastTelegramToSend, startIdx: " << a_beginSearchWithBroadcastIndex;
|
|
auto iter = m_BroadcastMap.upper_bound(0 == a_beginSearchWithBroadcastIndex ? m_FinishedBroadcastIndex : a_beginSearchWithBroadcastIndex);
|
|
while (iter != m_BroadcastMap.end())
|
|
{
|
|
auto broadcastTelegram = iter->second;
|
|
gef_telegramm_id_et telId = broadcastTelegram->getTelID();
|
|
// the following telegrams will never be sent as normal broadcast
|
|
if (GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM == telId
|
|
|| GEF_WF_SAMMELDEAKTIVIERUNG == telId
|
|
|| GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN == telId)
|
|
{
|
|
// respect an attached broadcast-only-telegram, otherwise step to next telegram
|
|
if (!broadcastTelegram->getBroadcastonlyTelegram())
|
|
{
|
|
++iter;
|
|
continue;
|
|
}
|
|
}
|
|
// use the attached broadcast-only-telegram if there is one
|
|
bool isBcOnly = false;
|
|
if (broadcastTelegram->getBroadcastonlyTelegram())
|
|
{
|
|
broadcastTelegram = broadcastTelegram->getBroadcastonlyTelegram();
|
|
isBcOnly = true;
|
|
}
|
|
// check whether it is time to send this broadcast-telegram the 2nd or 3rd time
|
|
bool wasLast = false;
|
|
if (broadcastTelegram->mustBeSentAsBroadcast(a_currentTime, wasLast))
|
|
{
|
|
// remove a 3rd-time-sent broadcast-only from all maps
|
|
if (wasLast)
|
|
{
|
|
if (isBcOnly || broadcastTelegram->isBroadcastOnly())
|
|
{
|
|
removeFromAllMaps(broadcastTelegram); // this will destroy our iterator, but we don't need it anymore...
|
|
}
|
|
else
|
|
{
|
|
// time-optimizing: 3rd-time sent broadcast-telegrams must no longer be examined
|
|
m_FinishedBroadcastIndex = broadcastTelegram->getBroadcastIndex();
|
|
}
|
|
}
|
|
// the identity could be dirty, because it could be sent as directed nachforderung in past
|
|
broadcastTelegram->setIdentity(0);
|
|
return broadcastTelegram;
|
|
}
|
|
else
|
|
{
|
|
// this broadcast-telegram must not yet be sent
|
|
// ------------------------------------------------------------------------------------
|
|
// optimize by time:
|
|
// Beside the fact that the m_BroadcastMap is ordered by BC-index there is also another
|
|
// implicit order: first come all 3rd time sent telegramms, then all 2nd time sent
|
|
// telegrams and finally all 1st time sent telegrams. Furthermore, the 3rd time sent
|
|
// telegrams are ordered ascending by nextsendtime. The same order exists also for 2nd
|
|
// and 1st time sent telegrams. This allows us some optimizings.
|
|
// Example:
|
|
// BC-index broadcast-counter next-send-time
|
|
// 1 3 0
|
|
// 2 3 0
|
|
// 3 2 1000
|
|
// 4 2 1000
|
|
// 5 2 1001
|
|
// 6 2 1005
|
|
// 7 1 1000
|
|
// 8 1 1001
|
|
// 9 1 1001
|
|
// -------------------------------------------------------------------------------------
|
|
uint16_t bcCounter = broadcastTelegram->getBroadcastCounter();
|
|
if (2 == bcCounter)
|
|
{
|
|
// step to first telegram with bc-counter == 1, because all other telegrams will have same
|
|
// or higher nextsendtime
|
|
if (m_FirstBroadcastIndexOfBc1 > iter->first)
|
|
{
|
|
iter = m_BroadcastMap.lower_bound(m_FirstBroadcastIndexOfBc1);
|
|
continue;
|
|
}
|
|
}
|
|
else if (1 == bcCounter)
|
|
{
|
|
m_FirstBroadcastIndexOfBc1 = broadcastTelegram->getBroadcastIndex();
|
|
return nullptr; // break, because all further telegrams will have same or higher nextsendtime
|
|
}
|
|
}
|
|
++iter;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// returns the next broadcast to send for nachforderungen
|
|
// ---------------------------------------------------------------
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::getNextNachforderungTelegramToSend()
|
|
{
|
|
removeExpiredTelegrams();
|
|
switch (m_State)
|
|
{
|
|
case e_ST_COLLECT:
|
|
// is the claim-window elapsed (usually 30 sec)?
|
|
if (m_TickCounter >= m_ActClaimWindow && !m_IsFullLoad)
|
|
{
|
|
// yes, the window has elapsed
|
|
prepareForSendNachforderungen();
|
|
}
|
|
else
|
|
{
|
|
// the claim-window has not elapsed
|
|
getAllFinishedBroadcastsFromDb();
|
|
}
|
|
break;
|
|
|
|
|
|
case e_ST_SEND_NACHFORDERUNG:
|
|
return evaluateNextNachforderungToSend();
|
|
default:
|
|
break;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Takes expired wirkfeld-telegrams out of maps.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeExpiredTelegrams()
|
|
{
|
|
const time_t now = time(nullptr);
|
|
auto iter = m_WirkfeldTelegramMapByTime.begin();
|
|
while (iter != m_WirkfeldTelegramMapByTime.end())
|
|
{
|
|
// 5 Sekunden warten wir noch da sonst ggf. Wirkfelder mit Wirkzeiten < 5 Sekunden
|
|
// schon rausfallen bevor sie ins Gefechtsfeld gesendet wurden.
|
|
if (iter->first + 5 > now)
|
|
return;
|
|
|
|
auto radioTelegram = iter->second;
|
|
INFO_LOG(m_logger) << "Remove expired telegram with telId=" << radioTelegram->getTelID()
|
|
<< " and BC=" << radioTelegram->getBroadcastIndex() << " from BC-list";
|
|
uint16_t wirkfeldKennung = radioTelegram->getPayloadDataUInt32(5, 2);
|
|
removeWirkfeldTelegrams(wirkfeldKennung);
|
|
iter = m_WirkfeldTelegramMapByTime.begin();
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Prepares values for start sending nachforderungen
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::prepareForSendNachforderungen()
|
|
{
|
|
// are there any broadcast nachforderungen?
|
|
m_TickCounter = 0;
|
|
if (!m_claimerArray.empty())
|
|
{
|
|
dump();
|
|
|
|
// yes, there are any nachforderungen
|
|
// do we have to send them directed or broadcasted?
|
|
m_State = e_ST_SEND_NACHFORDERUNG;
|
|
|
|
// fill the receiver-map
|
|
std::swap(m_claimerArray, m_claimerArray);
|
|
std::sort(m_claimerArray.begin(), m_claimerArray.end(),
|
|
[] (const EquipNoBcIndex &a, const EquipNoBcIndex &b)
|
|
{
|
|
if (a.bcIndex != b.bcIndex)
|
|
return a.bcIndex < b.bcIndex;
|
|
return a.equipNo < b.equipNo;
|
|
});
|
|
|
|
// evaluate if we begin with sending directed or broadcasted
|
|
INFO_LOG(m_loggerBcRequest) << "BroadcastLimit: " << m_BroadcastLimit;
|
|
if (m_claimerArray.size() > m_BroadcastLimit)
|
|
{
|
|
m_claimerArray.clear();
|
|
m_claimerArray.emplace_back(0, m_claimerArray.begin()->bcIndex);
|
|
}
|
|
|
|
// now build up the telegrams
|
|
for (const EquipNoBcIndex &enbi : m_claimerArray)
|
|
{
|
|
int curBcIndex = enbi.bcIndex;
|
|
int nextBcIndex = -1;
|
|
|
|
while (true)
|
|
{
|
|
auto tel = getNachforderungsTelegram(curBcIndex, enbi.bcIndex, nextBcIndex);
|
|
curBcIndex = nextBcIndex;
|
|
if (tel)
|
|
{
|
|
auto copy(std::make_shared<N_CoPrtCnv::CoPrtCnvRadioTelegram>(*tel));
|
|
copy->setIdentity(enbi.equipNo); // issi is set during sending
|
|
m_broadcastTelegamsToSend.push_back(copy);
|
|
}
|
|
else
|
|
break;
|
|
};
|
|
|
|
std::sort(m_broadcastTelegamsToSend.begin(), m_broadcastTelegamsToSend.end(),
|
|
[] (const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a, const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &b)
|
|
{
|
|
const int bcIndexA = a->getTelID() == GEF_NOP ? a->getPayloadDataUInt32(3, 2) : a->getBroadcastIndex();
|
|
const int bcIndexB = b->getTelID() == GEF_NOP ? b->getPayloadDataUInt32(3, 2) : b->getBroadcastIndex();
|
|
if (bcIndexA != bcIndexB)
|
|
return bcIndexA > bcIndexB; // reverse, we use back()/pop_back()
|
|
return a->getIdentity() < b->getIdentity();
|
|
});
|
|
|
|
if (m_loggerBcRequest.isDebugEnabled())
|
|
{
|
|
DEBUG_LOG(m_loggerBcRequest) << "Created broadcast list:";
|
|
for (const auto &tele : m_broadcastTelegamsToSend)
|
|
DEBUG_LOG(m_loggerBcRequest) << "Identity: " << tele->getIdentity()
|
|
<< ", bc: " << tele->getBroadcastIndex()
|
|
<< ", type: " << tele->getTelID();
|
|
}
|
|
}
|
|
m_claimerArray.clear();
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// returns the next nachforderung to send
|
|
// ---------------------------------------------------------------
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::evaluateNextNachforderungToSend()
|
|
{
|
|
if (m_broadcastTelegamsToSend.empty())
|
|
{
|
|
m_State = e_ST_COLLECT;
|
|
return nullptr;
|
|
}
|
|
auto tel = m_broadcastTelegamsToSend.back();
|
|
m_broadcastTelegamsToSend.pop_back();
|
|
return tel;
|
|
}
|
|
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::createAccumulationTelegram(int curBcIndex,
|
|
int startBcIndex,
|
|
gef_telegramm_id_et telId,
|
|
const QMap<int, int> &bcIndex2Type,
|
|
int maxIdsPerTelegram,
|
|
int sizeOfSumField) const
|
|
{
|
|
if (bcIndex2Type.isEmpty())
|
|
return nullptr;
|
|
|
|
auto itLastBcTele = m_BroadcastMap.end();
|
|
--itLastBcTele;
|
|
const int endBcIndex = itLastBcTele->second->getBroadcastIndex();
|
|
|
|
DEBUG_LOG(m_loggerBcRequest) << "createAccumulationTelegram for telId " << telId
|
|
<< ", begin: " << startBcIndex
|
|
<< ", cur: " << curBcIndex << ", end: " << endBcIndex
|
|
<< ", #elements in container: " << bcIndex2Type.size();
|
|
DEBUG_LOG(m_loggerBcRequest) << "Given broadcast list for " << telegramId2String(telId);
|
|
for (auto it = bcIndex2Type.begin(); it != bcIndex2Type.end(); ++it)
|
|
DEBUG_LOG(m_loggerBcRequest) << " bcIndex: " << it.key()
|
|
<< ", id: " << it.value();
|
|
|
|
// the asserts are only sanity checks - should never happen
|
|
auto itStart = bcIndex2Type.lowerBound(startBcIndex);
|
|
if (itStart == bcIndex2Type.end())
|
|
{
|
|
Q_ASSERT(false);
|
|
return nullptr;
|
|
}
|
|
auto itEnd = bcIndex2Type.lowerBound(endBcIndex);
|
|
if (itEnd == bcIndex2Type.end())
|
|
--itEnd;
|
|
|
|
const int completeTelegrams = std::distance(itStart, itEnd) + 1;
|
|
if (completeTelegrams <= 0)
|
|
{
|
|
Q_ASSERT(false);
|
|
return nullptr;
|
|
}
|
|
const auto itCur = bcIndex2Type.find(curBcIndex);
|
|
if (itCur == bcIndex2Type.end())
|
|
{
|
|
Q_ASSERT(false);
|
|
return nullptr;
|
|
}
|
|
const int telegramsStillSendable = std::distance(itCur, itEnd) + 1;
|
|
if (telegramsStillSendable <= 0)
|
|
{
|
|
Q_ASSERT(false);
|
|
return nullptr;
|
|
}
|
|
|
|
const int telegramsToSend = (completeTelegrams / maxIdsPerTelegram) + 1;
|
|
if (telegramsStillSendable > telegramsToSend)
|
|
{
|
|
INFO_LOG(m_loggerBcRequest) << telId << ": sending nop since accuTelegram is sent later (" << telegramsStillSendable
|
|
<< ", need only " << telegramsToSend << ")";
|
|
return nullptr;
|
|
}
|
|
|
|
const int curIdStart = (telegramsToSend - telegramsStillSendable) * maxIdsPerTelegram;
|
|
const int idsToSendNow = (curIdStart + maxIdsPerTelegram <= completeTelegrams ? maxIdsPerTelegram : completeTelegrams % maxIdsPerTelegram);
|
|
INFO_LOG(m_loggerBcRequest) << telId << ": creating accuTelegram from index " << curIdStart << ", count: " << idsToSendNow;
|
|
|
|
itStart += curIdStart;
|
|
|
|
// hdr (3 bytes) + bc idx + sum field
|
|
auto tele(std::make_shared<N_CoPrtCnv::CoPrtCnvRadioTelegram>(telId, 3 + 2 + sizeOfSumField + sizeof(uint16_t) * idsToSendNow, 0));
|
|
tele->setPayload2Byte(curBcIndex);
|
|
if (sizeOfSumField == 1)
|
|
tele->setPayload1Byte(idsToSendNow); // #Ids
|
|
else if (sizeOfSumField == 2)
|
|
tele->setPayload2Byte(idsToSendNow); // #Ids
|
|
else
|
|
{
|
|
Q_ASSERT(false);
|
|
return nullptr;
|
|
}
|
|
for (int i = 0; i < idsToSendNow; ++i)
|
|
{
|
|
tele->setPayload2Byte(itStart.value());
|
|
++itStart;
|
|
}
|
|
return tele;
|
|
}
|
|
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::createAccuTeleDeactivatedAesAreas(int curBcIndex,
|
|
int startBcIndex) const
|
|
{
|
|
return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG,
|
|
m_deactivatedBcIndex2AesArea, 100, 1);
|
|
}
|
|
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::createAccuTeleDeactivatedFuncAreas(int curBcIndex,
|
|
int startBcIndex) const
|
|
{
|
|
return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM,
|
|
m_deactivatedBcIndex2FuncArea, 100, 1);
|
|
}
|
|
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::createAccuTeleDeactivatedDusMines(int curBcIndex,
|
|
int startBcIndex) const
|
|
{
|
|
return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN,
|
|
m_deactivatedBcIndex2DusMine, 500, 2);
|
|
}
|
|
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::createAccuTeleActivatedDusMines(int curBcIndex)
|
|
{
|
|
if (m_activatedDusMines.isEmpty())
|
|
return {};
|
|
// we currently only can have exactly *one* telegram of this type (with max. 500 entries)
|
|
const int idsToSendNow = m_activatedDusMines.size();
|
|
if (idsToSendNow > 500)
|
|
{
|
|
WARNING_LOG(m_logger) << "More than 500 activated DUS mines in system - this is not allowed!";
|
|
Q_ASSERT(false);
|
|
return {};
|
|
}
|
|
auto tele(std::make_shared<N_CoPrtCnv::CoPrtCnvRadioTelegram>(GEF_REAKTIVIERUNG_DUS_MINE, 5 + 2 + sizeof(uint16_t) * idsToSendNow, 0));
|
|
tele->setPayload2Byte(curBcIndex);
|
|
tele->setPayload2Byte(idsToSendNow);
|
|
for (int dusMineId : qAsConst(m_activatedDusMines))
|
|
tele->setPayload2Byte(dusMineId);
|
|
|
|
return tele;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// returns the Nachforderungs-telegram with this broadcast-
|
|
// index from the broadcast-map with sammeltelegrams. If the
|
|
// telegram with a_broadcastIndex does not exist, a NOP-
|
|
// telegram will be returned, which must be consumed
|
|
// immediately and must never be deleted.
|
|
// The parameter a_broadcastIndex will be updated to the value
|
|
// of found telegram.
|
|
// ATTENTION: the returned a_broadcastIndex could be different
|
|
// from the value returned by getBroadcastIndex(), for example
|
|
// in NOP-telegrams getBroadcastIndex() returns the Anfang,
|
|
// but a_broadcastIndex will be the Ende.
|
|
// ---------------------------------------------------------------
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram>PrtCnvBroadcastMgr::getNachforderungsTelegram(int curBcIndex,
|
|
int startBcIndex,
|
|
int &nextBcIndex)
|
|
{
|
|
DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - curBcIndex: " << curBcIndex
|
|
<< ", startBcIndex: " << startBcIndex;
|
|
if (curBcIndex == 0) curBcIndex++;
|
|
DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - curBcIndex after Ssnity: " << curBcIndex
|
|
<< ", startBcIndex: " << startBcIndex;
|
|
|
|
nextBcIndex = curBcIndex;
|
|
bool doSendNop = false;
|
|
|
|
while (true)
|
|
{
|
|
auto iter = m_BroadcastMap.lower_bound(nextBcIndex);
|
|
if (iter == m_BroadcastMap.end())
|
|
break;
|
|
|
|
auto radioTelegram = iter->second;
|
|
DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - cur tel id is " << radioTelegram->getTelID()
|
|
<< ", bcIndex: " << radioTelegram->getBroadcastIndex()
|
|
<< ", send nop: " << doSendNop;
|
|
|
|
if (nextBcIndex < iter->first)
|
|
{
|
|
// do we have gaps or is it a broadcast-only telegram => send NOP-telegram
|
|
// but iterate for summarize all broadcast-only and gaps
|
|
doSendNop = true;
|
|
nextBcIndex = iter->first;
|
|
}
|
|
else if (radioTelegram->isBroadcastOnly())
|
|
{
|
|
doSendNop = true;
|
|
nextBcIndex = iter->first + 1;
|
|
}
|
|
else
|
|
{
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> retTele;
|
|
switch (radioTelegram->getTelID())
|
|
{
|
|
case GEF_DEAKTIVIERUNG_WIRKFELD:
|
|
retTele = createAccuTeleDeactivatedAesAreas(radioTelegram->getBroadcastIndex(), startBcIndex);
|
|
break;
|
|
case GEF_DEAKTIVIEREN_FUNKTIONSRAUM:
|
|
retTele = createAccuTeleDeactivatedFuncAreas(radioTelegram->getBroadcastIndex(), startBcIndex);
|
|
break;
|
|
case GEF_DEAKTIVIERUNG_EINZELMINE:
|
|
retTele = createAccuTeleDeactivatedDusMines(radioTelegram->getBroadcastIndex(), startBcIndex);
|
|
break;
|
|
case GEF_REAKTIVIERUNG_DUS_MINE:
|
|
retTele = createAccuTeleActivatedDusMines(radioTelegram->getBroadcastIndex());
|
|
break;
|
|
default:
|
|
retTele = radioTelegram;
|
|
break;
|
|
}
|
|
|
|
// when we got a tele but have to send a nop first, wait for the next iteration and return nop now
|
|
if (retTele && doSendNop)
|
|
break;
|
|
++nextBcIndex;
|
|
if (retTele)
|
|
return retTele;
|
|
doSendNop = true;
|
|
}
|
|
}
|
|
|
|
// due to some asyncs during startup it *may* happen that the last entry(ies) of
|
|
// the broadcast map are empty - make sure that we send a nop for them
|
|
if (!doSendNop && nextBcIndex <= m_BroadcastIndex)
|
|
{
|
|
nextBcIndex = m_BroadcastIndex + 1;
|
|
doSendNop = true;
|
|
}
|
|
|
|
if (doSendNop)
|
|
{
|
|
// return a NOP-telegram since next tele is a 'normal' telegram to send
|
|
INFO_LOG(m_loggerBcRequest) << "Returning NOP: " << curBcIndex << " to " << nextBcIndex - 1;
|
|
return getNopTelegram(curBcIndex, nextBcIndex - 1);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Gets the braodcast-telegrams from Db, which were sent 1st
|
|
// time and adds them to the maps. Expired telegrams will be
|
|
// removed.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::getAllFinishedBroadcastsFromDb(const bool a_doRestore)
|
|
{
|
|
// => get all broadcasts which are sent first time; replace some telegrams with
|
|
// sammeltelegrams or NOP-telegrams
|
|
|
|
// Attention: this must only be done, when we are not sending broadcast-nachforderungen,
|
|
// because otherwise we could change sammeltelegrams which are already sent.
|
|
|
|
uint16_t broadcastIndex = 0;
|
|
while (true)
|
|
{
|
|
auto radioTelegram = m_DbThread->getNextBroadcastTelegram();
|
|
if (!radioTelegram)
|
|
break;
|
|
broadcastIndex = radioTelegram->getBroadcastIndex();
|
|
INFO_LOG(m_logger) << "Move Broadcast-telegram from DbThread>BroadcastMgr with telId="
|
|
<< radioTelegram->getTelID() << " BC=" << broadcastIndex;
|
|
dumpTelegram(m_logger, broadcastIndex, radioTelegram.get());
|
|
// abgelaufene Telegramme hier *nicht* loeschen da sonst z.B. WF_FL_FEUER_STOP/FORTSETZEN
|
|
// spaeter nicht beachtet werden und WF_FL_FEUER nicht aus der Broadcastliste
|
|
// entfernt wird. außerdem hätten wir so eine andere Ausgangsbasis als wenn der PrtCnv
|
|
// nicht neu gestartet wurde was u.U. auch woanders noch zu Problemen führt.
|
|
//if (radioTelegram->hasExpired())
|
|
//{
|
|
// INFO_LOG(m_logger) << "Telegram with BC " << broadcastIndex
|
|
// << " is expired - throwing away";
|
|
// delete radioTelegram;
|
|
//}
|
|
//else
|
|
{
|
|
addToBroadcastMap(radioTelegram);
|
|
}
|
|
// remake overrun when restoring
|
|
if (a_doRestore && MAX_BROADCAST_INDEX == broadcastIndex)
|
|
handleOverrunOfBroadcastCounter(a_doRestore);
|
|
}
|
|
|
|
if (m_logger.isDebugEnabled())
|
|
{
|
|
static int iBroadcastDumpCounter = 0;
|
|
if ((iBroadcastDumpCounter++ % 30) == 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Dumping broadcast map:";
|
|
for (const auto &it : m_BroadcastMap)
|
|
dumpTelegram(m_logger, it.first, it.second.get());
|
|
}
|
|
}
|
|
|
|
// set the actual BC-index
|
|
if (a_doRestore)
|
|
{
|
|
m_BroadcastIndex = broadcastIndex;
|
|
m_FinishedBroadcastIndex = m_BroadcastIndex;
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// adds the radio-telegram to the broadcast-map, or generates
|
|
// the sammeltelegramme
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::addToBroadcastMap(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
INFO_LOG(m_logger) << "Move from radioList to bcList: BC=" << a_radioTelegram->getBroadcastIndex()
|
|
<< " telID=" << a_radioTelegram->getTelID();
|
|
switch (a_radioTelegram->getTelID())
|
|
{
|
|
// following telegrams should never be broadcasts
|
|
case GEF_INIT:
|
|
case GEF_UMGEBUNGS_MELDUNG2:
|
|
ERROR_LOG(m_logger) << "Internal error: telegram with telId=" << a_radioTelegram->getTelID() << " should never be a normal broadcast";
|
|
break;
|
|
// the following telegrams should only be sent as normal broadcast (not as Nachforderung)
|
|
case GEF_DATENVERKEHR_TDS_SRT:
|
|
case GEF_DATENVERKEHR_TDS_DMF:
|
|
case GEF_TREFFER_AUSLOESUNG:
|
|
case GEF_ALLGEMEINE_NACHRICHT:
|
|
addBroadcastOnlyTelegramToMap(a_radioTelegram);
|
|
break;
|
|
|
|
// the following telegrams must exist only once in BC-list
|
|
case GEF_SPRACHAUSWAHL:
|
|
case GEF_KONFIGURATION_WIRKMODELL:
|
|
case GEF_TEILNEHMERMODE_SETZEN:
|
|
case GEF_TEILNEHMER_KONFIG_SETZEN:
|
|
replaceLastTelegramAndAddAtEnd(a_radioTelegram);
|
|
break;
|
|
|
|
case GEF_WIRKFELD_EINZELGESCHOSS:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER:
|
|
case GEF_WIRKFELD_MINENSPERRE:
|
|
case GEF_WIRKFELD_A_KAMPFMITTEL:
|
|
case GEF_WIRKFELD_C_KAMPFMITTEL:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
|
|
case GEF_WIRKFELD_STATUS_MINENSPERRE:
|
|
case GEF_WIRKFELD_EINZELMINENSIMULATOR:
|
|
{
|
|
// take wirkfeld to be (re)activated out of sammeltelegram of deactivated wirkfelder
|
|
const uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(5, 2);
|
|
INFO_LOG(m_logger) << "Adding to braodcast map, Telegram Id: " << a_radioTelegram->getTelID()
|
|
<< ", kennung: " << wirkfeldKennung;
|
|
if (isEffectSimulationIdDeactivated(wirkfeldKennung))
|
|
{
|
|
INFO_LOG(m_logger) << "Got tele with tel id " << telegramId2String(a_radioTelegram->getTelID())
|
|
<< ", wirkfeldkennung: " << wirkfeldKennung << ", bcIndex: " << a_radioTelegram->getBroadcastIndex()
|
|
<< " but this effect simulation is already deactivated... ignoring";
|
|
dumpTelegram(m_logger, a_radioTelegram->getBroadcastIndex(), a_radioTelegram.get());
|
|
emit areaEffectSimulationActivated(wirkfeldKennung);
|
|
}
|
|
else if (0 != wirkfeldKennung && wirkfeldKennung <= std::numeric_limits<int16_t>::max())
|
|
{
|
|
switch (a_radioTelegram->getTelID())
|
|
{
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP:
|
|
// remove the corresponding FeuerFortsetzen telegram
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN);
|
|
break;
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
|
|
// remove the corresponding FeuerStop telegram
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP);
|
|
break;
|
|
case GEF_WIRKFELD_AENDERUNG_BEZEICHNER:
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung);
|
|
break;
|
|
case GEF_WIRKFELD_STATUS_MINENSPERRE:
|
|
// remove the corresponding deactivierung_einzelmine telegrams
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_DEAKTIVIERUNG_EINZELMINE);
|
|
break;
|
|
default:
|
|
removeWirkfeldTelegrams(wirkfeldKennung);
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung);
|
|
removeFromDeactivatedAesArea(wirkfeldKennung);
|
|
emit areaEffectSimulationActivated(wirkfeldKennung);
|
|
break;
|
|
}
|
|
// the original telegram will be added to broadcast-list
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
}
|
|
else
|
|
{
|
|
// this should never happen, because CoPrtCnvRadioTelegram::isContentValid() filters this out
|
|
ERROR_LOG(m_logger) << "Internal error: Got invalid kennung: " << wirkfeldKennung;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case GEF_WIRKFELD_AENDERUNG_BEZEICHNER:
|
|
{
|
|
auto wirkfeldTyp = static_cast<TrainingAreaBase::TetraIcd::AreaEffectSimulationType>(a_radioTelegram->getPayloadDataUInt32(5, 1));
|
|
uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2);
|
|
INFO_LOG(m_logger) << "addToBroadcastMap - Wirkfeld Aenderung Bezeichner for type "
|
|
<< wirkfeldTyp2Str(wirkfeldTyp) << " - kennung: "
|
|
<< wirkfeldKennung;
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung);
|
|
break;
|
|
}
|
|
case GEF_DEAKTIVIERUNG_WIRKFELD:
|
|
{
|
|
auto wirkfeldTyp = static_cast<TrainingAreaBase::TetraIcd::AreaEffectSimulationType>(a_radioTelegram->getPayloadDataUInt32(5, 1));
|
|
uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2);
|
|
INFO_LOG(m_logger) << "Deaktivierung Wirkfeld for type "
|
|
<< wirkfeldTyp2Str(wirkfeldTyp) << " - kennung: "
|
|
<< wirkfeldKennung << ", bc: " << a_radioTelegram->getBroadcastIndex();
|
|
switch (wirkfeldTyp)
|
|
{
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::MineArea: // Minensperre
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionArea: // Steilfeuer Fläche
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionSingle: // Steilfeuer Einzel
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::NContamination: // A-Waffe
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::CContamination: // C-Waffe
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DusSingleMineSimulator: // DUS-Einzelminensimulator
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DangerZoneExplosion:
|
|
if (0 != wirkfeldKennung && wirkfeldKennung <= 32767)
|
|
{
|
|
emit areaEffectSimulationDeactivated(wirkfeldKennung);
|
|
|
|
removeWirkfeldTelegrams(wirkfeldKennung);
|
|
if (addToDeactivatedAesArea(wirkfeldKennung, a_radioTelegram->getBroadcastIndex()))
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung);
|
|
}
|
|
else
|
|
{
|
|
// this should never happen, because CoPrtCnvRadioTelegram::isContentValid() filters this out
|
|
ERROR_LOG(m_logger) << "Internal error: Got invalid kennung: " << wirkfeldKennung;
|
|
}
|
|
break;
|
|
case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::FunctionalArea: // Telegram DeaktivierenFunktionsraum should be used, instead DeaktivierungWirkfeld with wirkfeldTyp 6
|
|
default:
|
|
// this should never happen, because CoPrtCnvRadioTelegram::isContentValid() filters this out
|
|
ERROR_LOG(m_logger) << "Internal error: WirkfeldTyp " << wirkfeldTyp2Str(wirkfeldTyp) << " in GEF_DEAKTIVIERUNG_WIRKFELD not implemented";
|
|
}
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
break;
|
|
}
|
|
|
|
case GEF_DEAKTIVIERUNG_EINZELMINE:
|
|
{
|
|
deactivateSingleMine(a_radioTelegram);
|
|
break;
|
|
}
|
|
|
|
case GEF_REAKTIVIERUNG_DUS_MINE:
|
|
{
|
|
reactivateDusMine(a_radioTelegram);
|
|
break;
|
|
}
|
|
|
|
case GEF_TECHNIK_FUNKTIONSRAUM:
|
|
{
|
|
// take funktionsraum to be (re)activated out of sammeltelegram of deactivated funktionsräume
|
|
uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2);
|
|
// remove an old already existing funktionsraum-telegram with this kennung
|
|
removeFromTechnikFunktionsAndBroadcastMaps(funktionsraumkennung);
|
|
|
|
// insert the funktionsraum-telegram
|
|
m_TechnikFunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram));
|
|
|
|
// the original telegram will be added to broadcast-list
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
break;
|
|
}
|
|
|
|
case GEF_FUNKTIONSRAUM:
|
|
{
|
|
// take funktionsraum to be (re)activated out of sammeltelegram of deactivated funktionsräume
|
|
uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2);
|
|
// remove an old already existing funktionsraum-telegram with this kennung
|
|
removeFromFunktionsAndBroadcastMaps(funktionsraumkennung);
|
|
removeFromDeactivatedFuncArea(funktionsraumkennung);
|
|
|
|
// insert the funktionsraum-telegram
|
|
m_FunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram));
|
|
|
|
// the original telegram will be added to broadcast-list
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
break;
|
|
}
|
|
|
|
case GEF_DEAKTIVIEREN_FUNKTIONSRAUM:
|
|
{
|
|
uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2);
|
|
emit areaEffectSimulationDeactivated(funktionsraumkennung);
|
|
|
|
removeFromFunktionsAndBroadcastMaps(funktionsraumkennung);
|
|
if (addToDeactivatedFuncArea(funktionsraumkennung, a_radioTelegram->getBroadcastIndex()))
|
|
m_FunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram));
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
}
|
|
// dump();
|
|
}
|
|
|
|
|
|
template <typename T, typename S>
|
|
bool removeFromContainers(T &id2bcIndex, S &BcIndex2id, int aesAreaId)
|
|
{
|
|
auto it = id2bcIndex.find(aesAreaId);
|
|
if (it == id2bcIndex.end())
|
|
return false;
|
|
BcIndex2id.remove(it.value());
|
|
id2bcIndex.erase(it);
|
|
return true;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
bool addToContainers(T &id2bcIndex, S &BcIndex2id, int aesAreaId, int bcIndex)
|
|
{
|
|
auto it = id2bcIndex.find(aesAreaId);
|
|
if (it != id2bcIndex.end())
|
|
{
|
|
if (it.value() == bcIndex)
|
|
return false;
|
|
BcIndex2id.remove(it.value());
|
|
}
|
|
id2bcIndex[aesAreaId] = bcIndex;
|
|
BcIndex2id[bcIndex] = aesAreaId;
|
|
return true;
|
|
}
|
|
|
|
bool PrtCnvBroadcastMgr::removeFromDeactivatedAesArea(int aesAreaId)
|
|
{
|
|
return removeFromContainers(m_deactivatedAesArea2bcIndex, m_deactivatedBcIndex2AesArea, aesAreaId);
|
|
}
|
|
|
|
// returns true when added
|
|
bool PrtCnvBroadcastMgr::addToDeactivatedAesArea(int aesAreaId, int bcIndex)
|
|
{
|
|
return addToContainers(m_deactivatedAesArea2bcIndex, m_deactivatedBcIndex2AesArea, aesAreaId, bcIndex);
|
|
}
|
|
|
|
bool PrtCnvBroadcastMgr::removeFromDeactivatedFuncArea(int aesAreaId)
|
|
{
|
|
return removeFromContainers(m_deactivatedFuncArea2bcIndex, m_deactivatedBcIndex2FuncArea, aesAreaId);
|
|
}
|
|
|
|
bool PrtCnvBroadcastMgr::addToDeactivatedFuncArea(int aesAreaId, int bcIndex)
|
|
{
|
|
return addToContainers(m_deactivatedFuncArea2bcIndex, m_deactivatedBcIndex2FuncArea, aesAreaId, bcIndex);
|
|
}
|
|
|
|
bool PrtCnvBroadcastMgr::removeFromDeactivatedDusMine(int dusMineId)
|
|
{
|
|
return removeFromContainers(m_deactivatedDusMine2bcIndex, m_deactivatedBcIndex2DusMine, dusMineId);
|
|
}
|
|
|
|
bool PrtCnvBroadcastMgr::addToDeactivatedDusMine(int dusMineId, int bcIndex)
|
|
{
|
|
return addToContainers(m_deactivatedDusMine2bcIndex, m_deactivatedBcIndex2DusMine, dusMineId, bcIndex);
|
|
}
|
|
|
|
bool PrtCnvBroadcastMgr::removeFromActivatedDusMine(int dusMineId)
|
|
{
|
|
return (m_activatedDusMines.remove(dusMineId));
|
|
}
|
|
|
|
void PrtCnvBroadcastMgr::addToActivatedDusMine(int dusMineId)
|
|
{
|
|
m_activatedDusMines.insert(dusMineId);
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// searches the kennung within sammeltelegram.
|
|
// returns -1 when kennung not found
|
|
// ---------------------------------------------------------------
|
|
int PrtCnvBroadcastMgr::getSammeltelegramIndex(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_sammelTelegram,
|
|
const uint16_t a_kennung) const
|
|
{
|
|
// decide the length of anzahl
|
|
uint16_t nbrLength = 0;
|
|
switch (a_sammelTelegram->getTelID())
|
|
{
|
|
case GEF_WF_SAMMELDEAKTIVIERUNG:
|
|
case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM:
|
|
nbrLength = 1;
|
|
break;
|
|
case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN:
|
|
case GEF_REAKTIVIERUNG_DUS_MINE:
|
|
nbrLength = 2;
|
|
break;
|
|
default:
|
|
ERROR_LOG(m_logger) << "Unknown Sammeltelegram with telId=" << a_sammelTelegram->getTelID();
|
|
return -1;
|
|
}
|
|
// search the kennung in sammeltelegram
|
|
const int cntAesIds = a_sammelTelegram->getPayloadDataUInt32(5, nbrLength);
|
|
for (int i = 0; i < cntAesIds; i++)
|
|
{
|
|
if (a_kennung == a_sammelTelegram->getPayloadDataUInt32(5 + nbrLength + i * 2, 2))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Handles the DEAKTIVIERUNG_EINZELMINE-telegram for normal-
|
|
// broadcasts and nachforderungen. This includes deactivation
|
|
// of mines from minen-sperre and DUS-mines.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::deactivateSingleMine(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
uint32_t wirkfeldkennung = a_radioTelegram->getPayloadDataUInt32(9, 2);
|
|
uint32_t minenkennung = a_radioTelegram->getPayloadDataUInt32(11, 2);
|
|
// DUS or normal mine?
|
|
if (0 == wirkfeldkennung)
|
|
{
|
|
removeFromActivatedDusMine(minenkennung);
|
|
addToDeactivatedDusMine(minenkennung, a_radioTelegram->getBroadcastIndex());
|
|
DEBUG_LOG(m_logger) << "Deactivating DUS-Mine: " << minenkennung << ", #deactivated mines: " << m_deactivatedBcIndex2DusMine.size();
|
|
removeDusMineDeactivationFromBroadcastMap(minenkennung); // remove old if there is already a telegram
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
}
|
|
else
|
|
{
|
|
// normal mine => change mine in "wirkfeldStatusMinensperre"
|
|
bool sentAsNormalBroadcastFinished = deactivateEinzelmineFromMinensperre(wirkfeldkennung, minenkennung, a_radioTelegram->getBroadcastIndex());
|
|
if (sentAsNormalBroadcastFinished)
|
|
{
|
|
// add the deactivierungEinzelmine-telegram as broadcast-only-telegram
|
|
addWirkfeldTelegram(a_radioTelegram, wirkfeldkennung, GEF_BESTAETIGUNG, minenkennung);
|
|
addBroadcastOnlyTelegramToMap(a_radioTelegram);
|
|
}
|
|
else
|
|
{
|
|
// the wirkfeldstatusMinensperre-telegram has changed while sending it as normal broadcast is not yet
|
|
// finished => we not add the deactiveEinzelmine-telegram as broadcast-only, so the updated wirkfeld-
|
|
// statusMinensperre-telegram will be sent as normal broadcast-telegram. The deactivateEinzelmine-
|
|
// telegram must be deleted
|
|
// delete a_radioTelegram; // no longer needed, shared_ptr
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Deactivates the mine in the corresponding
|
|
// "WirkfeldstatusMinensperre"-telegram and moves the
|
|
// "WirkfeldstatusMinensperre"-telegram to the position of
|
|
// "DeactiviereEinzelmine"-telegram.
|
|
// Returns true if the "WirkfeldstatusMinensperre"-telegram
|
|
// was already sent 3 times as normal broadcast.
|
|
// ---------------------------------------------------------------
|
|
bool PrtCnvBroadcastMgr::deactivateEinzelmineFromMinensperre(const uint16_t a_wirkfeldKennung,
|
|
const uint16_t a_minenKennung,
|
|
const uint16_t a_broadcastIndex)
|
|
{
|
|
// search the corresponding "WirkfeldstatusMinensperre"-telegram in the broadcast-map
|
|
auto iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung);
|
|
while (iter != m_WirkfeldTelegramMapByKennung.end())
|
|
{
|
|
if (iter->first != a_wirkfeldKennung) break;
|
|
|
|
auto radioTelegram = iter->second;
|
|
if (radioTelegram->getTelID() == GEF_WIRKFELD_STATUS_MINENSPERRE && a_wirkfeldKennung == radioTelegram->getPayloadDataUInt32(5, 2))
|
|
{
|
|
// check whether the minekennung is valid
|
|
uint16_t nbrOfMines = radioTelegram->getPayloadDataUInt32(7, 2);
|
|
if (nbrOfMines >= a_minenKennung && a_minenKennung != 0)
|
|
{
|
|
// calc the position of mine
|
|
// definition: The first mine is mine 1; MSB is bit 0 => mine 1 is bit 7; mine 2 is bit 6; ... mine 8 is bit 0; Mine 9 is bit 7 (of next byte)...
|
|
uint16_t bytePos = 9 + (a_minenKennung - 1) / 8;
|
|
if (bytePos < radioTelegram->getPayloadSize())
|
|
{
|
|
uint8_t mask = 0x80 >> ((a_minenKennung - 1) % 8);
|
|
// INFO_LOG(m_logger) << "pos=" << (pos-9) << " mask=" << (int)mask;
|
|
// clear the bit for the mine
|
|
radioTelegram->setPayloadDataWithIndex(bytePos, (uint8_t)(radioTelegram->getPayloadDataUInt8(bytePos) & (~mask)), 1);
|
|
moveTelegramInBroadcastMap(radioTelegram, a_broadcastIndex);
|
|
|
|
// if we have a corresponding wirkstatus-minensperre which was not sent 3 times as normal broadcast,
|
|
// we have to take it out and to send the new wirkfeldstatus-minensperre-telegram instead. Also all
|
|
// the deactivate einzelmine-telegrams must not be stored within the broadcast-list as broadcast-only
|
|
// telegram, therefore we return false
|
|
bool dummy;
|
|
if (radioTelegram->mustBeSentAsBroadcast(std::numeric_limits<time_t>::max(), dummy, false))
|
|
{
|
|
INFO_LOG(m_logger) << "A normal broadcast-telegram WirkfeldStatusMinensperre still exists";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
ERROR_LOG(m_logger) << "Got corrupt telegram WirkfeldstatusMinensperre with nbrOfMines=" << nbrOfMines << " and payloadSize=" << radioTelegram->getPayloadSize();
|
|
}
|
|
else
|
|
{
|
|
// minenkennung is too big to fit into statusMinensperre => Errormessage, do not update in status, but send as normal broadcast
|
|
ERROR_LOG(m_logger) << "Mine with kennung=" << a_minenKennung << " does not fit into status (nbrOfMines=" << nbrOfMines << ")";
|
|
}
|
|
return true;
|
|
}
|
|
++iter;
|
|
}
|
|
ERROR_LOG(m_logger) << "Did not find the WirkfeldStatusMinensperre with kennung=" << a_wirkfeldKennung
|
|
<< ", therefore deactivated mine with kennung=" << a_minenKennung << " could not be updated.";
|
|
return true;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Handles the REAKTIVIERUNG_DUS_MINE-telegram for normal-
|
|
// broadcasts and nachforderungen.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::reactivateDusMine(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
// take all DUS-mines to be reactivated out of sammeltelegram of deactivated DUS-mines
|
|
const uint32_t nbrOfMines = a_radioTelegram->getPayloadDataUInt32(5, 2); // #mines is 2 bytes
|
|
|
|
DEBUG_LOG(m_logger) << "Reactivating DUS-Mines, #mines: " << nbrOfMines;
|
|
if (0 == nbrOfMines)
|
|
{
|
|
// move all mines from sammeltelegram deactivation to activation
|
|
for (int dusMineId : qAsConst(m_deactivatedBcIndex2DusMine))
|
|
{
|
|
removeDusMineDeactivationFromBroadcastMap(dusMineId);
|
|
addToActivatedDusMine(dusMineId);
|
|
}
|
|
m_deactivatedDusMine2bcIndex.clear();
|
|
m_deactivatedBcIndex2DusMine.clear();
|
|
}
|
|
else
|
|
{
|
|
// normal-case: reactivate some DUS-mines
|
|
for (uint32_t i = 0; i < nbrOfMines; i++)
|
|
{
|
|
const int dusMineId = a_radioTelegram->getPayloadDataUInt32(7 + 2 * i, 2);
|
|
DEBUG_LOG(m_logger) << "Reactivating DUS-Mines, mindId: " << dusMineId;
|
|
removeDusMineDeactivationFromBroadcastMap(dusMineId);
|
|
removeFromDeactivatedDusMine(dusMineId);
|
|
addToActivatedDusMine(dusMineId);
|
|
}
|
|
}
|
|
|
|
auto pred = [](const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &tele) -> bool
|
|
{
|
|
return (tele->getTelID() == GEF_REAKTIVIERUNG_DUS_MINE);
|
|
};
|
|
removeFromBroadcastMapFunc(pred);
|
|
m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram));
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// adds the wirkfeld-telegram to the by time and by kennung
|
|
// maps
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::addWirkfeldTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram,
|
|
const uint16_t a_wirkfeldKennung,
|
|
const gef_telegramm_id_et a_telId,
|
|
const uint16_t a_minenKennung)
|
|
{
|
|
// remove an old already existing wirkfeld-telegram with this kennung
|
|
auto iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung);
|
|
while (iter != m_WirkfeldTelegramMapByKennung.end())
|
|
{
|
|
if (iter->first != a_wirkfeldKennung)
|
|
break;
|
|
auto radioTelegram = iter->second;
|
|
// same mineindex (only for "Deaktivierung_Einzelmine")?
|
|
bool isSameMine = true;
|
|
if (0 != a_minenKennung)
|
|
{
|
|
if (GEF_DEAKTIVIERUNG_EINZELMINE == a_radioTelegram->getTelID())
|
|
{
|
|
if (GEF_DEAKTIVIERUNG_EINZELMINE == radioTelegram->getTelID())
|
|
{
|
|
uint16_t mineIndex = radioTelegram->getPayloadDataUInt32(11, 2);
|
|
isSameMine = mineIndex == a_minenKennung;
|
|
INFO_LOG(m_logger) << "Mine with kennung=" << a_minenKennung << " found: " << isSameMine;
|
|
}
|
|
}
|
|
else
|
|
ERROR_LOG(m_logger) << "Internal error: Only telegrams 'Deaktivierung_Einzelmine' must be called with a_mineKennung. I proceed without respecting mine-kennung...";
|
|
}
|
|
// same telegram-id, or opposite telegram (used for stop- and fortsetzen dauerfeuer and deaktivierung einzelmine)?
|
|
if ((radioTelegram->getTelID() == a_radioTelegram->getTelID() || radioTelegram->getTelID() == a_telId) && isSameMine)
|
|
{
|
|
// remove the old telegram from wirkfeld- and broadcast-map
|
|
removeFromWirkfeldAndBroadcastMaps(iter); // iterator is corrupt after calling this function ...
|
|
iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung);
|
|
}
|
|
else
|
|
++iter;
|
|
}
|
|
|
|
// now add the new wirkfeld-telegram
|
|
INFO_LOG(m_logger) << "Add kennung: " << a_wirkfeldKennung
|
|
<< " telId=" << a_radioTelegram->getTelID()
|
|
<< " BC=" << a_radioTelegram->getBroadcastIndex();
|
|
m_WirkfeldTelegramMapByKennung.insert(std::make_pair(a_wirkfeldKennung, a_radioTelegram));
|
|
time_t expireTime = a_radioTelegram->getExpireTime();
|
|
if (expireTime > 0)
|
|
m_WirkfeldTelegramMapByTime.insert(std::make_pair(expireTime, a_radioTelegram));
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes the wirkfeld-telegrams with this kennung from the
|
|
// by time and by kennung maps.
|
|
// Replace this telegrams with Nop in BC-list.
|
|
// Finally the telegram will be deleted.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeWirkfeldTelegrams(const uint16_t a_kennung)
|
|
{
|
|
INFO_LOG(m_logger) << "Removing all Wirkfeld-Telegrams with kennung=" << a_kennung;
|
|
// search all wirkfeld-telegrams with this kennung
|
|
auto iter = m_WirkfeldTelegramMapByKennung.find(a_kennung);
|
|
while (iter != m_WirkfeldTelegramMapByKennung.end())
|
|
{
|
|
if (iter->first != a_kennung)
|
|
break;
|
|
|
|
removeFromWirkfeldAndBroadcastMaps(iter);
|
|
|
|
iter = m_WirkfeldTelegramMapByKennung.find(a_kennung);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes the telegram with a_funktionsraumKennung from
|
|
// funktionsraum-map and from the broadcast-map.
|
|
// If the telegram is a attached BC-only-telegram, it will be
|
|
// detached.
|
|
// The telegram itself will be deleted.
|
|
// ATTENTION: iterators to m_FunktionsraumTelegramMap could be
|
|
// invalid after calling this function
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeFromFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung)
|
|
{
|
|
auto iter = m_FunktionsraumTelegramMap.find(a_funktionsraumKennung);
|
|
if (iter != m_FunktionsraumTelegramMap.end())
|
|
{
|
|
auto radioTelegram = iter->second;
|
|
// get the BC-Index for removing of broadcast-map
|
|
// remove the telegram from funktionsraum-map
|
|
INFO_LOG(m_logger) << "Removing Funktionsraum-telegram with kennung=" << a_funktionsraumKennung
|
|
<< " and BC=" << radioTelegram->getBroadcastIndex();
|
|
m_FunktionsraumTelegramMap.erase(iter);
|
|
|
|
removeFromBroadcastMap(radioTelegram);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes the telegram with a_funktionsraumKennung from
|
|
// funktionsraum-map and from the broadcast-map.
|
|
// If the telegram is a attached BC-only-telegram, it will be
|
|
// detached.
|
|
// The telegram itself will be deleted.
|
|
// ATTENTION: iterators to m_FunktionsraumTelegramMap could be
|
|
// invalid after calling this function
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeFromTechnikFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung)
|
|
{
|
|
auto iter = m_TechnikFunktionsraumTelegramMap.find(a_funktionsraumKennung);
|
|
if (iter != m_TechnikFunktionsraumTelegramMap.end())
|
|
{
|
|
auto radioTelegram = iter->second;
|
|
// get the BC-Index for removing of broadcast-map
|
|
// remove the telegram from funktionsraum-map
|
|
INFO_LOG(m_logger) << "Removing Funktionsraum-telegram with kennung=" << a_funktionsraumKennung
|
|
<< " and BC=" << radioTelegram->getBroadcastIndex();
|
|
m_TechnikFunktionsraumTelegramMap.erase(iter);
|
|
|
|
removeFromBroadcastMap(radioTelegram);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes the telegram where
|
|
// wirkfeldTelegramMapByKennungIterator points to from
|
|
// wirkfeld-maps and from the broadcast-map.
|
|
// If the telegram is a attached BC-only-telegram, it will be
|
|
// detached.
|
|
// The telegram itself will be deleted.
|
|
// ATTENTION: iterators to m_WirkfeldTelegramMapByKennung and
|
|
// m_WirkfeldTelegramMapByTime could be invalid after calling
|
|
// this function
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeFromWirkfeldAndBroadcastMaps(const std::multimap<uint16_t, std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram>>::iterator &a_wirkfeldTelegramMapByKennungIterator)
|
|
{
|
|
auto radioTelegram = a_wirkfeldTelegramMapByKennungIterator->second;
|
|
|
|
INFO_LOG(m_logger) << "Removing wirkfeld-telegram with telId=" << radioTelegram->getTelID()
|
|
<< ", kennung=" << a_wirkfeldTelegramMapByKennungIterator->first
|
|
<< " and BC=" << radioTelegram->getBroadcastIndex()
|
|
<< " from byWirkfeldKennung-map";
|
|
|
|
// remove the telegram from by kennung map
|
|
m_WirkfeldTelegramMapByKennung.erase(a_wirkfeldTelegramMapByKennungIterator);
|
|
|
|
// remove the telegram from by time map
|
|
time_t expireTime = radioTelegram->getExpireTime();
|
|
if (0 != expireTime)
|
|
{
|
|
auto iter = m_WirkfeldTelegramMapByTime.find(expireTime);
|
|
while (iter != m_WirkfeldTelegramMapByTime.end())
|
|
{
|
|
if (iter->second == radioTelegram)
|
|
{
|
|
INFO_LOG(m_logger) << "Removing wirkfeld-telegram with telId=" << radioTelegram->getTelID()
|
|
<< " also from byTime-map";
|
|
m_WirkfeldTelegramMapByTime.erase(iter);
|
|
break;
|
|
}
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
removeFromBroadcastMap(radioTelegram);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes the telegram a_radioTelegram from the broadcast-map.
|
|
// If the a_radioTelegram has an attached telegram, the
|
|
// attached telegram will be detached and added to broadcast-
|
|
// map as broadcast-only telegram.
|
|
// If the telegram is an attached BC-only-telegram, it will be
|
|
// detached.
|
|
// ATTENTION: iterators to m_BroadcastMap could be invalid
|
|
// after calling this function
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeFromBroadcastMap(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
// remove from broadcast-map
|
|
if (!a_radioTelegram)
|
|
return;
|
|
|
|
auto iter = m_BroadcastMap.find(a_radioTelegram->getBroadcastIndex());
|
|
if (iter != m_BroadcastMap.end())
|
|
{
|
|
if (iter->second == a_radioTelegram)
|
|
{
|
|
m_BroadcastMap.erase(iter);
|
|
detachTelegram(a_radioTelegram);
|
|
}
|
|
else if (iter->second->getBroadcastonlyTelegram() == a_radioTelegram)
|
|
iter->second->setBroadcastonlyTelegram(nullptr);
|
|
}
|
|
}
|
|
|
|
void PrtCnvBroadcastMgr::removeFromBroadcastMapFunc(const std::function<bool(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &)> &pred)
|
|
{
|
|
auto it = m_BroadcastMap.begin();
|
|
while (it != m_BroadcastMap.end())
|
|
{
|
|
const auto &p = *it;
|
|
if (pred(p.second))
|
|
it = m_BroadcastMap.erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void PrtCnvBroadcastMgr::removeDusMineDeactivationFromBroadcastMap(int dusMineId)
|
|
{
|
|
auto pred = [dusMineId](const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &tele) -> bool
|
|
{
|
|
return (tele->getTelID() == GEF_DEAKTIVIERUNG_EINZELMINE &&
|
|
0 == tele->getPayloadDataUInt32(9, 2) &&
|
|
uint32_t(dusMineId) == tele->getPayloadDataUInt32(11, 2));
|
|
};
|
|
removeFromBroadcastMapFunc(pred);
|
|
}
|
|
|
|
template <typename T>
|
|
void removeFromMap(T &cont, const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
auto iter = cont.begin();
|
|
while (iter != cont.end())
|
|
{
|
|
if (iter->second == a_radioTelegram)
|
|
iter = cont.erase(iter);
|
|
else
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes the telegram a_radioTelegram from all maps
|
|
// (broadcast-, wirkfeld-, funktionsraum- and lastTelegram-
|
|
// map).
|
|
// If the telegram is a attached BC-only-telegram, it will be
|
|
// detached.
|
|
// ATTENTION: iterators to all maps could be invalid after
|
|
// calling this function
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::removeFromAllMaps(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
INFO_LOG(m_logger) << "Remove telegram with telId=" << a_radioTelegram->getTelID() << " BC=" << a_radioTelegram->getBroadcastIndex();
|
|
|
|
removeFromBroadcastMap(a_radioTelegram);
|
|
|
|
// remove from byWirkfeldKennung-map
|
|
removeFromMap(m_WirkfeldTelegramMapByKennung, a_radioTelegram);
|
|
|
|
// remove from byWirkfeldTime-map
|
|
removeFromMap(m_WirkfeldTelegramMapByTime, a_radioTelegram);
|
|
|
|
// remove from funktionsraum-map
|
|
removeFromMap(m_FunktionsraumTelegramMap, a_radioTelegram);
|
|
|
|
// remove from last-telegram-map
|
|
removeFromMap(m_LastTelegramMap, a_radioTelegram);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// used for telegrams that must only exists once in BC-list
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::replaceLastTelegramAndAddAtEnd(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_newRadioTelegram)
|
|
{
|
|
// do we have a last telegram?
|
|
auto iter = m_LastTelegramMap.find(a_newRadioTelegram->getTelID());
|
|
if (iter != m_LastTelegramMap.end())
|
|
{
|
|
auto lastRadioTelegram = iter->second;
|
|
// yes => replace the last telegram with NOP
|
|
INFO_LOG(m_logger) << "remove last telegram with telId=" << lastRadioTelegram->getTelID()
|
|
<< " and BC=" << lastRadioTelegram->getBroadcastIndex();
|
|
removeFromBroadcastMap(lastRadioTelegram);
|
|
m_LastTelegramMap.erase(iter);
|
|
}
|
|
// insert the new telegram into BC-list
|
|
m_BroadcastMap.insert(std::make_pair(a_newRadioTelegram->getBroadcastIndex(), a_newRadioTelegram));
|
|
// and insert into last-telegram-list
|
|
m_LastTelegramMap.insert(std::make_pair(a_newRadioTelegram->getTelID(), a_newRadioTelegram));
|
|
INFO_LOG(m_logger) << "New last telegram with with telId=" << a_newRadioTelegram->getTelID()
|
|
<< " and BC=" << a_newRadioTelegram->getBroadcastIndex();
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Moves a_radioTelegram to a_newBroadcastIndex in broadcast-
|
|
// map.
|
|
// If a_radioTelegram has an attached broadcast-only-telegram,
|
|
// the broadcastOnly-telegram will be detached and kept on the
|
|
// old broadcast-index position.
|
|
// If a_attachTelegram in not NULL, this telegram will be
|
|
// attached to a_radioTelegram.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::moveTelegramInBroadcastMap(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram,
|
|
const uint16_t a_newBroadcastIndex,
|
|
const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_attachTelegram)
|
|
{
|
|
// remove the old telegram from map (and detach)
|
|
INFO_LOG(m_logger) << "Move telId=" << a_radioTelegram->getTelID()
|
|
<< " from BC=" << a_radioTelegram->getBroadcastIndex()
|
|
<< " to BC=" << a_newBroadcastIndex;
|
|
removeFromBroadcastMap(a_radioTelegram);
|
|
// insert telegram a end
|
|
a_radioTelegram->setBroadcastIndex(a_newBroadcastIndex);
|
|
m_BroadcastMap.insert(std::make_pair(a_newBroadcastIndex, a_radioTelegram));
|
|
// attach a_attachTelegram
|
|
if (a_attachTelegram && (a_attachTelegram->getTelID() != GEF_REAKTIVIERUNG_DUS_MINE))
|
|
{
|
|
INFO_LOG(m_logger) << "Attach telID=" << a_attachTelegram->getTelID()
|
|
<< " to telID=" << a_radioTelegram->getTelID()
|
|
<< " BC=" << a_newBroadcastIndex;
|
|
a_radioTelegram->setBroadcastonlyTelegram(a_attachTelegram);
|
|
a_attachTelegram->setBroadcastIndex(a_newBroadcastIndex);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Returns the actual broadcast-index for normal broadcasts.
|
|
// ---------------------------------------------------------------
|
|
uint16_t PrtCnvBroadcastMgr::getBroadcastIndex() const
|
|
{
|
|
return m_BroadcastIndex;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Returns the broadcastindex for the next broadcast
|
|
// ---------------------------------------------------------------
|
|
uint16_t PrtCnvBroadcastMgr::getNextBroadcastIndex()
|
|
{
|
|
return ++m_BroadcastIndex;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Returns a NOP-telegramm filled with the desired values.
|
|
// ---------------------------------------------------------------
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> PrtCnvBroadcastMgr::getNopTelegram(const uint16_t a_from, const uint16_t a_to)
|
|
{
|
|
auto nopTelegram(std::make_shared<N_CoPrtCnv::CoPrtCnvRadioTelegram>(GEF_NOP, 7, 0));
|
|
nopTelegram->setPayloadDataWithIndex(3, a_from, 2); // Feld Anfang
|
|
nopTelegram->setPayloadDataWithIndex(5, a_to, 2); // Feld Ende
|
|
return nopTelegram;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Adds the telegram a_broadcastOnlyTelegram (which must have
|
|
// set already the broadcast-index) to the broadcast-map. The
|
|
// telegram will be attached to an already existing broadcast-
|
|
// telegram with same broadcast-index in the map, otherwise it
|
|
// will be marked as broadcast-only.
|
|
// If the there is already an broadcast-only-telegram attached,
|
|
// nothing will be done.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::addBroadcastOnlyTelegramToMap(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_broadcastOnlyTelegram)
|
|
{
|
|
uint16_t broadcastIndex = a_broadcastOnlyTelegram->getBroadcastIndex();
|
|
auto iter = m_BroadcastMap.find(broadcastIndex);
|
|
if (m_BroadcastMap.end() == iter)
|
|
{
|
|
// insert as braodcast-only marked telegram
|
|
INFO_LOG(m_logger) << "Insert telId=" << a_broadcastOnlyTelegram->getTelID()
|
|
<< " as broadcastonly telegram with BC=" << broadcastIndex;
|
|
a_broadcastOnlyTelegram->setBroadcastOnly();
|
|
m_BroadcastMap.insert(std::make_pair(broadcastIndex, a_broadcastOnlyTelegram));
|
|
}
|
|
else
|
|
{
|
|
// attach to an already existing broadcast-telegram
|
|
INFO_LOG(m_logger) << "Add telId=" << a_broadcastOnlyTelegram->getTelID()
|
|
<< " as broadcastonly telegram to telegramm with BC=" << iter->second->getBroadcastIndex();
|
|
iter->second->setBroadcastonlyTelegram(a_broadcastOnlyTelegram);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Detaches an existing radio-telegram and adds it to the
|
|
// broadcast-map
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::detachTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
auto broadcastOnlyTelegram = a_radioTelegram->getBroadcastonlyTelegram();
|
|
if (broadcastOnlyTelegram)
|
|
{
|
|
uint16_t broadcastIndex = a_radioTelegram->getBroadcastIndex();
|
|
// do some checks
|
|
INFO_LOG(m_logger) << "detach bconly-telegram : telId=" << a_radioTelegram->getTelID() << " BC=" << broadcastIndex;
|
|
if (broadcastOnlyTelegram->getBroadcastIndex() != broadcastIndex)
|
|
ERROR_LOG(m_logger) << "Internal error: BC=" << broadcastOnlyTelegram->getBroadcastIndex() << " of attached telegram is not equal BC=" << broadcastIndex;
|
|
auto iter = m_BroadcastMap.find(broadcastIndex);
|
|
if (iter != m_BroadcastMap.end())
|
|
ERROR_LOG(m_logger) << "Internal error: m_BroadcastMap-entry with BC=" << broadcastIndex << " must not exists";
|
|
else
|
|
{
|
|
INFO_LOG(m_logger) << "Insert broadcast-only BC=" << broadcastOnlyTelegram->getBroadcastIndex();
|
|
broadcastOnlyTelegram->setBroadcastOnly();
|
|
m_BroadcastMap.insert(std::make_pair(broadcastIndex, broadcastOnlyTelegram));
|
|
}
|
|
a_radioTelegram->setBroadcastonlyTelegram(nullptr);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Removes all Nop out of broadcast-list and numerates the
|
|
// broadcast-index of kept broadcast-telegrams new.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::handleOverrunOfBroadcastCounter(const bool a_doRestore)
|
|
{
|
|
WARNING_LOG(m_logger) << "Broadcast-counter reaches maximum => reduce broadcast-list and increment reset-counter";
|
|
|
|
// first we must wait until all data are stored in DB, otherwise we will loose
|
|
// the broadcast-telegrams, which were sent the 1st time, but not yet stored permanent
|
|
if (!a_doRestore)
|
|
{
|
|
m_DbThread->waitUntilDbWritten();
|
|
getAllFinishedBroadcastsFromDb();
|
|
}
|
|
|
|
// reduce the broadcast-list
|
|
uint16_t newBroadcastCounter = 0;
|
|
std::map<uint16_t, std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram>> newBroadcastMap;
|
|
auto iter = m_BroadcastMap.begin();
|
|
while (iter != m_BroadcastMap.end())
|
|
{
|
|
auto radioTelegram = iter->second;
|
|
if (radioTelegram->isBroadcastOnly())
|
|
{
|
|
// delete all broadcast-only telegrams
|
|
++iter; // removeFromAllMaps() will destroy the iterator => we increment it before removing
|
|
removeFromAllMaps(radioTelegram);
|
|
}
|
|
else
|
|
{
|
|
radioTelegram->setBroadcastIndex(++newBroadcastCounter);
|
|
auto broadcastOnlyTelegram = radioTelegram->getBroadcastonlyTelegram();
|
|
if (broadcastOnlyTelegram)
|
|
{
|
|
radioTelegram->setBroadcastonlyTelegram(nullptr);
|
|
++iter; // removeFromAllMaps() will destroy the iterator => we increment it before removing
|
|
removeFromAllMaps(broadcastOnlyTelegram);
|
|
}
|
|
else
|
|
{
|
|
// all pending normal broadcast should no longer be sent as normal broadcasts, because all TNEs
|
|
// will anyway ask for nachforderung
|
|
bool wasLast;
|
|
if (radioTelegram->mustBeSentAsBroadcast(std::numeric_limits<time_t>::max(), wasLast, false))
|
|
{
|
|
do
|
|
{
|
|
radioTelegram->mustBeSentAsBroadcast(std::numeric_limits<time_t>::max(), wasLast, true);
|
|
}
|
|
while (!wasLast);
|
|
}
|
|
++iter;
|
|
}
|
|
INFO_LOG(m_logger) << "New BC-index for broadcast-telegram with telId=" << radioTelegram->getTelID() << " BC=" << newBroadcastCounter;
|
|
newBroadcastMap.insert(std::make_pair(newBroadcastCounter, radioTelegram));
|
|
}
|
|
}
|
|
m_BroadcastMap.clear();
|
|
m_BroadcastMap = newBroadcastMap;
|
|
|
|
// stop actual nachforderungen and increment reset-counter
|
|
cleanAndInit(false);
|
|
if (!a_doRestore) m_DbThread->setResetCounter(m_DbThread->getResetCounter() + 1);
|
|
|
|
WARNING_LOG(m_logger) << "New broadcast-counter=" << newBroadcastCounter << " new reset-counter=" << (int)m_DbThread->getResetCounter();
|
|
m_BroadcastIndex = newBroadcastCounter;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Restores data after crash for seamless proceeding of work.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::restoreAfterCrash()
|
|
{
|
|
getAllFinishedBroadcastsFromDb(true);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// dumps important values, only for debugging
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::dump()
|
|
{
|
|
// dump the broadcast-list
|
|
for (const auto &it : m_BroadcastMap)
|
|
dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_BroadcastMap, ");
|
|
|
|
for (const auto &it : m_WirkfeldTelegramMapByKennung)
|
|
dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_WirkfeldTelegramMapByKennung, ");
|
|
|
|
for (const auto &it : m_WirkfeldTelegramMapByTime)
|
|
dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_WirkfeldTelegramMapByTime, ");
|
|
|
|
for (const auto &it : m_FunktionsraumTelegramMap)
|
|
dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_FunktionsraumTelegramMap, ");
|
|
|
|
for (const auto &it : m_TechnikFunktionsraumTelegramMap)
|
|
dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_TechnikFunktionsraumTelegramMap, ");
|
|
|
|
for (const auto &it : m_LastTelegramMap)
|
|
dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_LastTelegramMap, ");
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Increments the tick-counter of broadcast-manager and
|
|
// informs the broadcast-manager about the traffic-load.
|
|
// ---------------------------------------------------------------
|
|
void PrtCnvBroadcastMgr::incTickAndSetTrafficLoad(const bool a_isHighLoad, const bool a_isFullLoad)
|
|
{
|
|
if (e_ST_COLLECT == m_State)
|
|
++m_TickCounter;
|
|
m_IsFullLoad = a_isFullLoad;
|
|
if (a_isHighLoad)
|
|
m_ActClaimWindow = m_HighLoadFactor * m_ClaimWindow;
|
|
else
|
|
m_ActClaimWindow = m_ClaimWindow;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Checks if the given id is in m_deactivatedAesArea2bcIndex
|
|
// ---------------------------------------------------------------
|
|
bool PrtCnvBroadcastMgr::isEffectSimulationIdDeactivated(const uint16_t effectsimulationId) const
|
|
{
|
|
INFO_LOG(m_logger) << "Checking deactivation for Id " << effectsimulationId;
|
|
return m_deactivatedAesArea2bcIndex.contains(effectsimulationId);
|
|
}
|
|
|
|
} // namespace PrtCnv
|