1794 lines
41 KiB
C++
1794 lines
41 KiB
C++
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "CoPrtCnvRadioTelegram.hpp"
|
|
#include <time.h>
|
|
#include <NGLLogger/NGLLoggerBootstrap.h>
|
|
|
|
using N_CoPrtCnv::CoPrtCnvRadioTelegram;
|
|
|
|
using namespace N_CoPrtCnv;
|
|
|
|
|
|
|
|
constexpr uint8_t CoPrtCnvRadioTelegram::MAGIC_NUMBER;
|
|
constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_WITH_TL_HEADER_LENGTH;
|
|
constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH;
|
|
constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_NO_TL_HEADER_LENGTH;
|
|
constexpr uint16_t CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH;
|
|
constexpr uint16_t CoPrtCnvRadioTelegram::PAYLOAD_STATUS_LENGTH;
|
|
constexpr uint8_t CoPrtCnvRadioTelegram::MAX_NBR_OF_FRAGMENTS;
|
|
|
|
int CoPrtCnvRadioTelegram::s_2ndDelay = 60;
|
|
int CoPrtCnvRadioTelegram::s_3rdDelay = 60;
|
|
int CoPrtCnvRadioTelegram::s_maxBroadcastSendCnt = 0;
|
|
bool CoPrtCnvRadioTelegram::s_etsMode = false;
|
|
|
|
static const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_ProtocolIdentifier
|
|
s_protocolIdentifier = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_TDSMessageWithoutSDS_TL;
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI)
|
|
: m_data(9, Qt::Uninitialized),
|
|
m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
|
|
|
|
setHeader(m_data, e_RegisterInd);
|
|
|
|
setSrcISSI(a_sourceISSI);
|
|
}
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI,
|
|
const std::set<uint32_t> &groups)
|
|
: m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
uint16_t len = groups.size();
|
|
if (len > 5)
|
|
len = 5;
|
|
m_data.resize(12 + len * 4);
|
|
setHeader(m_data, e_GroupMonitorReq);
|
|
|
|
|
|
setSrcISSI(a_sourceISSI);
|
|
|
|
uint8_t mode = 1;
|
|
set1Byte(m_data, 9, mode);
|
|
set2Byte(m_data, 10, len);
|
|
std::set<uint32_t>::iterator it = groups.begin();
|
|
for (uint16_t i = 0; i < len; i++)
|
|
{
|
|
set4Byte(m_data, 12 + i * 4, *it);
|
|
++it;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI,
|
|
const E_DeliveryStatusForTL_Report a_delivery)
|
|
: m_data(17, Qt::Uninitialized),
|
|
m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
|
|
|
|
setHeader(m_data, e_ReportIndReq);
|
|
|
|
setSrcISSI(a_sourceISSI);
|
|
setDestISSI(a_sourceISSI);
|
|
set1Byte(m_data, 13, s_protocolIdentifier);
|
|
set1Byte(m_data, 14, 0);
|
|
set1Byte(m_data, 15, 0);
|
|
set1Byte(m_data, 16, a_delivery);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const QByteArray &a_data)
|
|
: m_data(a_data),
|
|
m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const gef_telegramm_id_et a_telegramId, const uint16_t a_payloadSize, const uint16_t a_identity)
|
|
: m_data(a_payloadSize + DATA_IND_REQ_HEADER_LENGTH, '\0'),
|
|
m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
|
|
|
|
setHeader(m_data, e_DataIndReq);
|
|
fillDataIndReqHeader(m_data);
|
|
|
|
m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH;
|
|
set1Byte(m_data, m_PayloadIndex++, e_NotFragmented);
|
|
|
|
set1Byte(m_data, m_PayloadIndex++, a_telegramId);
|
|
set1Byte(m_data, m_PayloadIndex++, 0);
|
|
set1Byte(m_data, m_PayloadIndex--, 0);
|
|
setIdentity(a_identity);
|
|
m_PayloadIndex += 2;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, uint32_t a_issi)
|
|
: m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
|
|
|
|
const bool withGroupIssis = (a_loginTelegramStatus & e_LoginOtherExercise) == e_LoginOtherExercise;
|
|
m_data.resize(DATA_IND_REQ_HEADER_LENGTH + (withGroupIssis ? 12 : 3));
|
|
setHeader(m_data, e_DataIndReq);
|
|
fillDataIndReqHeader(m_data);
|
|
setDestISSI(a_issi);
|
|
|
|
|
|
uint16_t size = m_data.size();
|
|
set2Byte(m_data, DATA_IND_REQ_WITH_TL_HEADER_LENGTH, 8 * (size - DATA_IND_REQ_HEADER_LENGTH_WITHOUT_PAYLOAD_HEADER));
|
|
|
|
m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH;
|
|
set1Byte(m_data, m_PayloadIndex++, e_NotFragmented + e_LoginTelegram);
|
|
|
|
set1Byte(m_data, m_PayloadIndex++, (a_identity >> 8) & 0x00FF);
|
|
set1Byte(m_data, m_PayloadIndex++, a_identity & 0x00FF);
|
|
set1Byte(m_data, m_PayloadIndex++, a_loginTelegramStatus);
|
|
}
|
|
|
|
void CoPrtCnvRadioTelegram::setLoginIssis(int hostIssi, int groupIssi1, int groupIssi2)
|
|
{
|
|
|
|
|
|
setPayload3Byte(hostIssi);
|
|
|
|
setPayload3Byte(groupIssi1);
|
|
|
|
setPayload3Byte(groupIssi2);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const std::shared_ptr<CoPrtCnvRadioTelegram> &a_bigTelegram,
|
|
const uint8_t a_fragmentIndex,
|
|
bool &a_error)
|
|
: m_data(),
|
|
m_PayloadIndex(0),
|
|
m_BroadcastCounter(0),
|
|
m_NextSendTime(0),
|
|
m_IsBroadcastOnly(false),
|
|
m_BroadcastOnlyTelegram(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"))
|
|
{
|
|
|
|
static const uint16_t MAX_TELEGRAM_SIZE = MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH - PAYLOAD_STATUS_LENGTH;
|
|
|
|
const int payloadSize = a_bigTelegram->getSize() - DATA_IND_REQ_HEADER_LENGTH;
|
|
const uint8_t nbrOfFragmentedTelegrams = uint8_t((payloadSize - 1) / MAX_TELEGRAM_SIZE);
|
|
if (nbrOfFragmentedTelegrams > (MAX_NBR_OF_FRAGMENTS - 1))
|
|
{
|
|
ERROR_LOG(m_logger) << "Radio-telegram is too big (" << nbrOfFragmentedTelegrams + 1
|
|
<< " fragments). There are max " << MAX_NBR_OF_FRAGMENTS
|
|
<< " fragments of size=" << MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH
|
|
<< " (=" << MAX_NBR_OF_FRAGMENTS *MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH
|
|
<< " bytes) possible.";
|
|
a_error = true;
|
|
return;
|
|
}
|
|
if (nbrOfFragmentedTelegrams == 0)
|
|
{
|
|
ERROR_LOG(m_logger) << "Radio-telegram is too small for fragmentation. It must have at least a size of "
|
|
<< (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + 1);
|
|
a_error = true;
|
|
return;
|
|
}
|
|
uint8_t payloadStatus = e_FirstFragment | nbrOfFragmentedTelegrams;
|
|
|
|
|
|
const uint16_t payloadSizeNormal = uint16_t(payloadSize / (nbrOfFragmentedTelegrams + 1));
|
|
const uint16_t payloadSizeLast = uint16_t(payloadSize - (nbrOfFragmentedTelegrams * payloadSizeNormal));
|
|
|
|
uint16_t size = payloadSizeNormal;
|
|
if (0 != a_fragmentIndex)
|
|
{
|
|
if (nbrOfFragmentedTelegrams != a_fragmentIndex)
|
|
{
|
|
|
|
payloadStatus = e_MiddleFragment | (nbrOfFragmentedTelegrams - a_fragmentIndex);
|
|
}
|
|
else
|
|
{
|
|
|
|
payloadStatus = e_LastFragment;
|
|
size = payloadSizeLast;
|
|
}
|
|
}
|
|
size += PAYLOAD_STATUS_LENGTH;
|
|
|
|
|
|
m_data.resize(size + DATA_IND_REQ_WITH_TL_HEADER_LENGTH + sizeof(PrtCnvRadioGwHeader));
|
|
setHeader(m_data, e_DataIndReq);
|
|
fillDataIndReqHeader(m_data);
|
|
m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH;
|
|
set1Byte(m_data, m_PayloadIndex++, payloadStatus);
|
|
|
|
if (size > 1)
|
|
{
|
|
const char *srcData = a_bigTelegram->getData() + DATA_IND_REQ_HEADER_LENGTH + a_fragmentIndex * payloadSizeNormal;
|
|
const uint8_t *ptr = reinterpret_cast<const uint8_t *>(srcData);
|
|
setPayloadData(ptr, size - 1);
|
|
}
|
|
else
|
|
{
|
|
|
|
ERROR_LOG(m_logger) << "Internal error: size must be bigger than 1";
|
|
a_error = true;
|
|
return;
|
|
}
|
|
a_error = false;
|
|
}
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::~CoPrtCnvRadioTelegram()
|
|
{
|
|
if (m_BroadcastOnlyTelegram != nullptr)
|
|
ERROR_LOG(m_logger) << "Internal error: m_BroadcastOnlyTelegram was not nullptr while deletion of radio-telegram";
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setPayload1Byte(const uint8_t a_value)
|
|
{
|
|
set1Byte(m_data, m_PayloadIndex, a_value);
|
|
m_PayloadIndex += 1;
|
|
}
|
|
|
|
void CoPrtCnvRadioTelegram::setPayload2Byte(const uint16_t a_value)
|
|
{
|
|
setPayloadData(a_value, 2);
|
|
}
|
|
|
|
void CoPrtCnvRadioTelegram::setPayload3Byte(const uint32_t a_value)
|
|
{
|
|
setPayloadData(a_value, 3);
|
|
}
|
|
|
|
void CoPrtCnvRadioTelegram::setPayload4Byte(const uint32_t a_value)
|
|
{
|
|
setPayloadData(a_value, 4);
|
|
}
|
|
|
|
void CoPrtCnvRadioTelegram::setPayloadData(uint32_t a_value, const uint8_t a_size)
|
|
{
|
|
for (int i = m_PayloadIndex + a_size - 1; i >= m_PayloadIndex; i--)
|
|
{
|
|
set1Byte(m_data, i, a_value & 0xFF);
|
|
a_value >>= 8;
|
|
}
|
|
m_PayloadIndex += a_size;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setPayloadData(const uint8_t *a_data, const uint16_t a_size)
|
|
{
|
|
uint8_t *ptr = reinterpret_cast<uint8_t *>(m_data.data());
|
|
memcpy(&ptr[m_PayloadIndex], a_data, a_size);
|
|
m_PayloadIndex += a_size;
|
|
}
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::fixupTelegramIdForEts(bool convertToEtsId)
|
|
{
|
|
if (!s_etsMode)
|
|
return;
|
|
char *ptr = &m_data.data()[DATA_IND_REQ_HEADER_LENGTH];
|
|
if (convertToEtsId)
|
|
++(*ptr);
|
|
else
|
|
--(*ptr);
|
|
}
|
|
|
|
void CoPrtCnvRadioTelegram::setEtsMode(bool bIsEtsMode)
|
|
{
|
|
s_etsMode = bIsEtsMode;
|
|
}
|
|
|
|
|
|
|
|
|
|
gef_telegramm_id_et CoPrtCnvRadioTelegram::getTelID() const
|
|
{
|
|
return static_cast<gef_telegramm_id_et>(static_cast<uint8_t>(m_data.at(DATA_IND_REQ_HEADER_LENGTH)));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::zaehler() const
|
|
{
|
|
return static_cast<uint8_t>(m_data.at(1));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setZaehler(const uint8_t a_counter)
|
|
{
|
|
set1Byte(m_data, 1, a_counter);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t CoPrtCnvRadioTelegram::getPayloadDataUInt32(size_t a_offset, uint16_t a_size) const
|
|
{
|
|
uint32_t value = 0;
|
|
const uint8_t *ptr = reinterpret_cast<const uint8_t *>(m_data.data());
|
|
uint8_t *ptrValue = reinterpret_cast<uint8_t *>(&value);
|
|
a_offset += DATA_IND_REQ_HEADER_LENGTH;
|
|
switch (a_size)
|
|
{
|
|
case 4:
|
|
ptrValue[3] = ptr[a_offset++];
|
|
Q_FALLTHROUGH();
|
|
case 3:
|
|
ptrValue[2] = ptr[a_offset++];
|
|
Q_FALLTHROUGH();
|
|
case 2:
|
|
ptrValue[1] = ptr[a_offset++];
|
|
Q_FALLTHROUGH();
|
|
case 1:
|
|
ptrValue[0] = ptr[a_offset++];
|
|
break;
|
|
default:
|
|
Q_ASSERT(false);
|
|
ERROR_LOG(m_logger) << "a_size must be between 1..4";
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::getPayloadDataUInt8(size_t a_offset) const
|
|
{
|
|
return static_cast<uint8_t>(m_data.at(DATA_IND_REQ_HEADER_LENGTH + a_offset));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t CoPrtCnvRadioTelegram::getDestISSI() const
|
|
{
|
|
return getUInt32(9);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getIdentity() const
|
|
{
|
|
return isLoginTelegram() ? getPayloadDataUInt32(0, 2) : getPayloadDataUInt32(1, 2);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setSrcISSI(const uint32_t a_ISSI)
|
|
{
|
|
setSrcISSI_Internal(m_data, a_ISSI);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::mustBroadcastBeSet() const
|
|
{
|
|
|
|
|
|
if (isNormalTelegram())
|
|
return getIdentity() == 0 && getBroadcastIndex() == 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setBroadcastIndex(const uint16_t a_broadcastIndex)
|
|
{
|
|
set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + 3, (a_broadcastIndex >> 8) & 0xFF);
|
|
set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + 4, a_broadcastIndex & 0xFF);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setDestISSI(const uint32_t a_ISSI)
|
|
{
|
|
setDestISSI_Internal(m_data, a_ISSI);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::E_PDU_Type CoPrtCnvRadioTelegram::getPDU_Type() const
|
|
{
|
|
return static_cast<E_PDU_Type>(m_data.at(4));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::E_FragmentStatus CoPrtCnvRadioTelegram::getFragmentStatus() const
|
|
{
|
|
return static_cast<E_FragmentStatus>(m_data.at(26) & e_FragmentStatusMask);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::getFragmentCounter() const
|
|
{
|
|
return static_cast<uint8_t>(m_data.at(26) & e_CounterMask);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isCrcOk() const
|
|
{
|
|
if ((m_data.at(26) & e_Checksum) == e_Checksum)
|
|
{
|
|
|
|
uint32_t sum = getProtocolIdentifier();
|
|
for (int i = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; i < m_data.size() - 2; i++)
|
|
sum += static_cast<uint8_t>(m_data.at(i));
|
|
|
|
uint16_t checksum = getUInt8(m_data.size() - 2) * 256 + getUInt8(m_data.size() - 1);
|
|
checksum = ~checksum;
|
|
checksum++;
|
|
|
|
auto that = const_cast<CoPrtCnvRadioTelegram*>(this);
|
|
that->m_data.resize(m_data.size() - 2);
|
|
that->m_data[26] = (m_data.at(26) & ~e_Checksum);
|
|
|
|
if (sum != checksum)
|
|
{
|
|
ERROR_LOG(m_logger) << "Checksum of telegram is wrong: " << QString::number(checksum, 16)
|
|
<< " (expected: " << QString::number(sum, 16) << "), issi: " << getUInt32(5);
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t CoPrtCnvRadioTelegram::getSrcISSI() const
|
|
{
|
|
return getUInt32(5);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isLoginTelegram() const
|
|
{
|
|
if (e_DataIndReq == getPDU_Type())
|
|
return (e_LoginTelegram == ((e_FragmentStatusMask | e_CounterMask) & m_data.at(26)));
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::mustBeFragmented() const
|
|
{
|
|
if (e_DataIndReq == getPDU_Type())
|
|
return size_t(getSize()) > (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + DATA_IND_REQ_WITH_TL_HEADER_LENGTH + sizeof(PrtCnvRadioGwHeader));
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uint8_t *CoPrtCnvRadioTelegram::getPayloadDataPtr(uint16_t a_offset) const
|
|
{
|
|
return reinterpret_cast<const uint8_t *>(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH + a_offset]);
|
|
}
|
|
|
|
uint8_t *CoPrtCnvRadioTelegram::getPayloadDataPtr(uint16_t a_offset)
|
|
{
|
|
return reinterpret_cast<uint8_t *>(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH + a_offset]);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getPayloadSize() const
|
|
{
|
|
return static_cast<uint16_t>((getPDU_Type() == e_DataIndReq) ? m_data.size() - DATA_IND_REQ_HEADER_LENGTH : 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QByteArray CoPrtCnvRadioTelegram::getUnfragmentedData(const std::multimap<uint16_t, CoPrtCnvRadioTelegram *> &a_fragTelegramList)
|
|
{
|
|
NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram");
|
|
|
|
uint16_t totalSize = 0;
|
|
bool first = true;
|
|
uint8_t expectedNextFragment = 0;
|
|
CoPrtCnvRadioTelegram *firstFragment = nullptr;
|
|
std::multimap<uint16_t, CoPrtCnvRadioTelegram *>::const_reverse_iterator rit;
|
|
for (rit = a_fragTelegramList.rbegin(); rit != a_fragTelegramList.rend(); ++rit)
|
|
{
|
|
CoPrtCnvRadioTelegram *fragRadioTelegram = rit->second;
|
|
if (first)
|
|
{
|
|
if (e_FirstFragment == fragRadioTelegram->getFragmentStatus())
|
|
{
|
|
totalSize += fragRadioTelegram->getSize();
|
|
expectedNextFragment = fragRadioTelegram->getFragmentCounter() - 1;
|
|
firstFragment = fragRadioTelegram;
|
|
first = false;
|
|
}
|
|
else
|
|
{
|
|
ERROR_LOG(l) << "The fragment with the highest counter is not marked as first fragment";
|
|
return nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (e_MiddleFragment == fragRadioTelegram->getFragmentStatus() || e_LastFragment == fragRadioTelegram->getFragmentStatus())
|
|
{
|
|
if (expectedNextFragment-- == fragRadioTelegram->getFragmentCounter())
|
|
{
|
|
if (e_LastFragment == fragRadioTelegram->getFragmentStatus() && 0 != fragRadioTelegram->getFragmentCounter())
|
|
{
|
|
ERROR_LOG(l) << "The last fragment must have a counter of 0, but the counter is " << (int)fragRadioTelegram->getFragmentCounter();
|
|
return nullptr;
|
|
}
|
|
totalSize += fragRadioTelegram->getPayloadSize();
|
|
}
|
|
else
|
|
{
|
|
ERROR_LOG(l) << "The fragmented Radio-Telegram from TNE with id=" << fragRadioTelegram->getIdentity() << " with fragment-counter=" << (expectedNextFragment + 1) << " was lost";
|
|
return nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_LOG(l) << "A fragment which is not the first one, is not marked as middle or last fragment";
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (firstFragment
|
|
&& totalSize <= (DATA_IND_REQ_HEADER_LENGTH + MAX_NBR_OF_FRAGMENTS * (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH - PAYLOAD_STATUS_LENGTH))
|
|
&& totalSize > DATA_IND_REQ_HEADER_LENGTH)
|
|
{
|
|
QByteArray data(totalSize, Qt::Uninitialized);
|
|
|
|
setHeader(data, e_DataIndReq);
|
|
fillDataIndReqHeader(data);
|
|
setSrcISSI_Internal(data, firstFragment->getSrcISSI());
|
|
setDestISSI_Internal(data, firstFragment->getDestISSI());
|
|
uint16_t index = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH;
|
|
set1Byte(data, index++, e_NotFragmented);
|
|
|
|
|
|
for (rit = a_fragTelegramList.rbegin(); rit != a_fragTelegramList.rend(); ++rit)
|
|
{
|
|
CoPrtCnvRadioTelegram *fragRadioTelegram = rit->second;
|
|
uint16_t fragSize = fragRadioTelegram->getPayloadSize();
|
|
if (index + fragSize <= totalSize)
|
|
{
|
|
memcpy(&data.data()[index], fragRadioTelegram->getPayloadDataPtr(0), fragSize);
|
|
index += fragSize;
|
|
}
|
|
else
|
|
{
|
|
|
|
ERROR_LOG(l) << "Internal error: size of allocated datablock is too small";
|
|
return QByteArray();
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
ERROR_LOG(l) << "Internal error while building unfragmented radio-telegram: fragTelegram=" << firstFragment << " totalSize=" << totalSize;
|
|
return QByteArray();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isTelegramLengthOk(const uint16_t a_lengthWithoutFrame)
|
|
{
|
|
return (a_lengthWithoutFrame <= (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + DATA_IND_REQ_HEADER_LENGTH - sizeof(PrtCnvRadioGwHeader) - PAYLOAD_STATUS_LENGTH));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isNormalTelegram() const
|
|
{
|
|
return (e_DataIndReq == getPDU_Type() && (e_NormalTelegram == ((e_FragmentStatusMask | e_CounterMask) & m_data.at(26))));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::getPriority() const
|
|
{
|
|
if (isNormalTelegram())
|
|
{
|
|
switch (getTelID())
|
|
{
|
|
case GEF_INIT:
|
|
case GEF_DEAKTIVIERUNG_EINZELMINE:
|
|
case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG:
|
|
case GEF_SANITAETSDIENST_INSTANDSETZUNG:
|
|
case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN:
|
|
return 2;
|
|
case GEF_WIRKFELD_EINZELGESCHOSS:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
|
|
case GEF_WIRKFELD_MINENSPERRE:
|
|
case GEF_WIRKFELD_STATUS_MINENSPERRE:
|
|
case GEF_WIRKFELD_A_KAMPFMITTEL:
|
|
case GEF_WIRKFELD_C_KAMPFMITTEL:
|
|
case GEF_DEAKTIVIERUNG_WIRKFELD:
|
|
case GEF_REAKTIVIERUNG_DUS_MINE:
|
|
case GEF_TECHNIK_FUNKTIONSRAUM:
|
|
case GEF_FUNKTIONSRAUM:
|
|
case GEF_DEAKTIVIEREN_FUNKTIONSRAUM:
|
|
case GEF_DATENVERKEHR_TDS_GEOP:
|
|
case GEF_WIRKFELD_EINZELMINENSIMULATOR:
|
|
case GEF_POSITIONS_MELDUNG:
|
|
return 3;
|
|
case GEF_UMGEBUNGS_MELDUNG2:
|
|
case GEF_AUFFORDERUNG_BITE_MELDUNG:
|
|
case GEF_LIZENSIERUNG_TNE:
|
|
case GEF_TREFFER_AUSLOESUNG:
|
|
case GEF_SPRACHAUSWAHL:
|
|
case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL:
|
|
case GEF_SELEKTIVE_AUFMUNITIONIERUNG:
|
|
case GEF_SCHIEDSRICHTERKOMMANDO:
|
|
return 4;
|
|
case GEF_KONFIGURATION_WIRKMODELL:
|
|
case GEF_ANFORDERUNG_KONFIGURATIONSDATEN:
|
|
case GEF_WIRKFELD_AENDERUNG_BEZEICHNER:
|
|
case GEF_DATENVERKEHR_TDS_SRT:
|
|
case GEF_DATENVERKEHR_TDS_DMF:
|
|
case GEF_DATENVERKEHR_TDS_TGTC:
|
|
case GEF_TEILNEHMERMODE_SETZEN:
|
|
case GEF_TEILNEHMER_KONFIG_ANFORDERN:
|
|
case GEF_TEILNEHMER_KONFIG_SETZEN:
|
|
return 5;
|
|
case GEF_ALLGEMEINE_NACHRICHT:
|
|
return 6;
|
|
case GEF_SW_VERSIONSMELDUNG:
|
|
return 7;
|
|
|
|
case GEF_NOP:
|
|
case GEF_WF_SAMMELDEAKTIVIERUNG:
|
|
case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN:
|
|
case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM:
|
|
return 99;
|
|
default:
|
|
ERROR_LOG(m_logger) << "Priority of telegram with telId=" << getTelID() << " not defined.";
|
|
|
|
#ifdef DEBUG
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
else if (isLoginTelegram())
|
|
return 4;
|
|
return 10;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getBroadcastIndex() const
|
|
{
|
|
if (isNormalTelegram() && m_data.size() > (DATA_IND_REQ_HEADER_LENGTH + 4))
|
|
return getPayloadDataUInt32(3, 2);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setPayloadDataWithIndex(const uint16_t a_index, const uint32_t a_value, const uint16_t a_size)
|
|
{
|
|
|
|
|
|
if (1 == a_size)
|
|
set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + a_index, a_value);
|
|
else
|
|
{
|
|
uint16_t savedPayloadIndex = m_PayloadIndex;
|
|
m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH + a_index;
|
|
setPayloadData(a_value, a_size);
|
|
m_PayloadIndex = savedPayloadIndex;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setPayloadDataComplete(const QByteArray &payload)
|
|
{
|
|
m_data.resize(payload.size() + DATA_IND_REQ_HEADER_LENGTH);
|
|
setHeader(m_data, getPDU_Type());
|
|
memcpy(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH], payload.data(), payload.size());
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::resetPayloadSize(const uint16_t a_newPayloadSize)
|
|
{
|
|
m_data.resize(a_newPayloadSize + DATA_IND_REQ_HEADER_LENGTH);
|
|
setHeader(m_data, getPDU_Type());
|
|
|
|
uint16_t size = m_data.size();
|
|
set2Byte(m_data, 22, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH) * 8);
|
|
set2Byte(m_data, 24, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setIdentity(const uint16_t a_identity)
|
|
{
|
|
setPayloadDataWithIndex(isLoginTelegram() ? 0 : 1, a_identity, 2);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setProtocolIdentifier(const E_ProtocolIdentifier a_ProtocolIdentifier)
|
|
{
|
|
if (e_DataIndReq == getPDU_Type())
|
|
set1Byte(m_data, 13, a_ProtocolIdentifier);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setMessageReference(const uint8_t a_MessageReference)
|
|
{
|
|
if (isSDSTL())
|
|
set1Byte(m_data, 14, a_MessageReference);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isSDSTL() const
|
|
{
|
|
return (e_DataIndReq == getPDU_Type() && (e_UsingSDS_TL == (e_UsingSDS_TL & getProtocolIdentifier())));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::E_RegistrationStatus CoPrtCnvRadioTelegram::getRegistrationStatus() const
|
|
{
|
|
return static_cast<E_RegistrationStatus>(m_data.at(5));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string CoPrtCnvRadioTelegram::getRegistrationStatusAsText() const
|
|
{
|
|
switch (getRegistrationStatus())
|
|
{
|
|
case e_IssiSuccessfulRegistered:
|
|
return "IssiSuccessfulRegistered";
|
|
case e_DuplicateISSI:
|
|
return "DuplicateISSI";
|
|
case e_InvalidISSI:
|
|
return "InvalidISSI";
|
|
case e_InvalidIpAddress:
|
|
return "InvalidIpAddress";
|
|
}
|
|
return std::to_string(getRegistrationStatus());
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::E_ProtocolIdentifier CoPrtCnvRadioTelegram::getProtocolIdentifier() const
|
|
{
|
|
return static_cast<E_ProtocolIdentifier>(m_data.at(13));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string CoPrtCnvRadioTelegram::getProtocolIdentifierAsText() const
|
|
{
|
|
switch (getProtocolIdentifier())
|
|
{
|
|
case e_SimpleTextMessagingWithoutSDS_TL:
|
|
return "Simple Text Messaging w/o SDS/TL";
|
|
case e_SimpleGPS_WithoutSDS_TL:
|
|
return "Simple GPS w/o SDS/TL";
|
|
case e_TDSMessageWithoutSDS_TL:
|
|
return "TDS Message w/o SDS/TL";
|
|
case e_UsingSDS_TL:
|
|
return "SDS/TL";
|
|
case e_SimpleTextMessagingUsingSDS_TL:
|
|
return "Simple Text Messaging with SDS/TL";
|
|
case e_SimpleGPS_UsingSDS_TL:
|
|
return "Simple GPS with SDS/TL";
|
|
case e_LoginTest:
|
|
return "Login-Test / Hohenfels";
|
|
}
|
|
return std::to_string(getProtocolIdentifier());
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::getMessageReference() const
|
|
{
|
|
return static_cast<uint8_t>(m_data.at(14));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::getAreaSelection() const
|
|
{
|
|
return static_cast<uint8_t>(m_data.at(15));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t CoPrtCnvRadioTelegram::getValidityPeriod() const
|
|
{
|
|
return static_cast<uint8_t>(m_data.at(16));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t CoPrtCnvRadioTelegram::getForwardAddress() const
|
|
{
|
|
return getUInt32(17);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::E_Flags CoPrtCnvRadioTelegram::getFlags() const
|
|
{
|
|
return static_cast<E_Flags>(m_data.at(21));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string CoPrtCnvRadioTelegram::getFlagsAsText() const
|
|
{
|
|
switch (getFlags())
|
|
{
|
|
case e_FlagsNone:
|
|
return "No Flags";
|
|
|
|
case e_StorageAllowed:
|
|
return "Storage Allowed";
|
|
|
|
case e_GroupServiceOrOnlyStandardReportAllowed:
|
|
return "Group Service or only Standard Report Allowed";
|
|
|
|
case e_ReceivedConfirmationRequested:
|
|
return "Received Confirmation Requested";
|
|
|
|
case e_ConsumedConfirmationRequested:
|
|
return "Consumed Confirmation Requested";
|
|
|
|
}
|
|
std::ostringstream str;
|
|
str << getFlags();
|
|
return str.str();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getLengthInBits() const
|
|
{
|
|
return getUInt16(22);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getLengthInBytes() const
|
|
{
|
|
return getUInt16(24);
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::getWithCrc() const
|
|
{
|
|
if (getSize() > 26)
|
|
return ((m_data.at(26) & e_Checksum) == e_Checksum);
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report CoPrtCnvRadioTelegram::getDelivery() const
|
|
{
|
|
return static_cast<E_DeliveryStatusForTL_Report>(m_data.at(16));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string CoPrtCnvRadioTelegram::getDeliveryAsText() const
|
|
{
|
|
switch (getDelivery())
|
|
{
|
|
case e_SDS_ReceiptAcknowledgedByDestination:
|
|
return "SDS receipt acknowledged by destination";
|
|
|
|
case e_SDS_ConsumedByDestination:
|
|
return "SDS consumed by destination";
|
|
|
|
case e_SourceIsNotAuthorizedForSDS:
|
|
return "Source is not authorized for SDS";
|
|
|
|
case e_DestinationIsNotAuthorizedForSDS:
|
|
return "Destination is not authorized for SDS";
|
|
|
|
case e_UnknownDestinationAddress:
|
|
return "Unknown destination address";
|
|
|
|
case e_DeliveryFailed:
|
|
return "Delivery failed";
|
|
|
|
case e_DestinationNotRegisteredOnSystem:
|
|
return "Destination not registered on system";
|
|
|
|
case e_DestinationQueueFull:
|
|
return "Destination queue full";
|
|
|
|
case e_MessageTooLong:
|
|
return "Message too long";
|
|
|
|
case e_DestinationHostPC_NotConnected:
|
|
return "Destination host PC not connected";
|
|
|
|
case e_ProtocolNotSupported:
|
|
return "Protocol not supported";
|
|
|
|
case e_DataCodingSchemeNotSupported:
|
|
return "Datat coding scheme not supported";
|
|
|
|
case e_DestinationNotReachable:
|
|
return "Destination not reachable";
|
|
|
|
}
|
|
std::ostringstream str;
|
|
str << getDelivery();
|
|
return str.str();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int32_t CoPrtCnvRadioTelegram::getPayloadDataSInt24(uint16_t a_offset) const
|
|
{
|
|
uint32_t value = getPayloadDataUInt32(a_offset, 3);
|
|
|
|
if (value & 0x800000)
|
|
value |= 0xFF800000;
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::needsLicensing() const
|
|
{
|
|
if (isNormalTelegram())
|
|
{
|
|
switch (getTelID())
|
|
{
|
|
|
|
case GEF_UMGEBUNGS_MELDUNG2:
|
|
case GEF_LIZENSIERUNG_TNE:
|
|
case GEF_AUFFORDERUNG_BITE_MELDUNG:
|
|
case GEF_ALLGEMEINE_NACHRICHT:
|
|
return false;
|
|
default:
|
|
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::hasExpired() const
|
|
{
|
|
uint32_t expireTime = getExpireTime();
|
|
if (expireTime > 0)
|
|
{
|
|
uint32_t now = time(nullptr);
|
|
return (now >= expireTime);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t CoPrtCnvRadioTelegram::getExpireTime() const
|
|
{
|
|
if (isNormalTelegram())
|
|
{
|
|
uint32_t wirkBegin = 0;
|
|
uint32_t wirkDauer = 0;
|
|
switch (getTelID())
|
|
{
|
|
case GEF_WIRKFELD_EINZELGESCHOSS:
|
|
wirkBegin = getPayloadDataUInt32(11 + 5, 4);
|
|
wirkDauer = 5;
|
|
break;
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER:
|
|
wirkBegin = getPayloadDataUInt32(11 + 5, 4);
|
|
wirkDauer = getPayloadDataUInt32(15 + 5, 2);
|
|
break;
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
|
|
wirkBegin = getPayloadDataUInt32(11, 4);
|
|
wirkDauer = getPayloadDataUInt32(15, 2);
|
|
break;
|
|
case GEF_WIRKFELD_A_KAMPFMITTEL:
|
|
wirkBegin = getPayloadDataUInt32(11 + 5, 4);
|
|
wirkDauer = getPayloadDataUInt32(15 + 5, 2) * 60 * 10;
|
|
break;
|
|
case GEF_WIRKFELD_C_KAMPFMITTEL:
|
|
wirkBegin = getPayloadDataUInt32(11 + 5, 4);
|
|
wirkDauer = getPayloadDataUInt32(15 + 5, 1) * 60;
|
|
break;
|
|
case GEF_WIRKFELD_MINENSPERRE:
|
|
wirkBegin = getPayloadDataUInt32(11 + 5, 4);
|
|
wirkDauer = getPayloadDataUInt32(15 + 5, 1) * 60 * 60;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
if (0 == wirkDauer)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (wirkBegin > 0)
|
|
return (wirkBegin + wirkDauer);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isContentValid()
|
|
{
|
|
if (isNormalTelegram())
|
|
{
|
|
uint16_t wirkfeldkennung = 0;
|
|
uint8_t wirkfeldtyp = 0;
|
|
switch (getTelID())
|
|
{
|
|
case GEF_WIRKFELD_EINZELGESCHOSS:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP:
|
|
case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN:
|
|
case GEF_WIRKFELD_MINENSPERRE:
|
|
case GEF_WIRKFELD_STATUS_MINENSPERRE:
|
|
case GEF_WIRKFELD_A_KAMPFMITTEL:
|
|
case GEF_WIRKFELD_C_KAMPFMITTEL:
|
|
case GEF_WIRKFELD_EINZELMINENSIMULATOR:
|
|
wirkfeldkennung = getPayloadDataUInt32(5, 2);
|
|
wirkfeldtyp = 3;
|
|
Q_FALLTHROUGH();
|
|
case GEF_DEAKTIVIERUNG_WIRKFELD:
|
|
case GEF_WIRKFELD_AENDERUNG_BEZEICHNER:
|
|
if (GEF_DEAKTIVIERUNG_WIRKFELD == getTelID() || GEF_WIRKFELD_AENDERUNG_BEZEICHNER == getTelID())
|
|
{
|
|
wirkfeldtyp = getPayloadDataUInt8(5);
|
|
wirkfeldkennung = getPayloadDataUInt32(6, 2);
|
|
}
|
|
|
|
if ((wirkfeldtyp >= 1 && wirkfeldtyp <= 5) || (wirkfeldtyp == 8))
|
|
{
|
|
if (wirkfeldkennung > 0 && wirkfeldkennung <= 32767)
|
|
return true;
|
|
ERROR_LOG(m_logger) << "Wirkfeldkennung (" << wirkfeldkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..32768.";
|
|
return false;
|
|
}
|
|
if (GEF_WIRKFELD_AENDERUNG_BEZEICHNER == getTelID() && wirkfeldkennung > 0)
|
|
return true;
|
|
|
|
|
|
|
|
ERROR_LOG(m_logger) << "Wirkfeldtyp (" << wirkfeldtyp << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..5 or 8.";
|
|
return false;
|
|
|
|
case GEF_DEAKTIVIERUNG_EINZELMINE:
|
|
if (isPayloadLengthOk(13))
|
|
{
|
|
wirkfeldkennung = getPayloadDataUInt32(9, 2);
|
|
{
|
|
if (wirkfeldkennung > 32767)
|
|
{
|
|
ERROR_LOG(m_logger) << "DeaktivierungEinzelmine: wirkfeldkennung=" << wirkfeldkennung << " too big. Must be 1..32767";
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case GEF_TECHNIK_FUNKTIONSRAUM:
|
|
case GEF_FUNKTIONSRAUM:
|
|
case GEF_DEAKTIVIEREN_FUNKTIONSRAUM:
|
|
{
|
|
uint32_t funktionsraumkennung = getPayloadDataUInt32(5, 2);
|
|
if (funktionsraumkennung > 0)
|
|
return true;
|
|
|
|
ERROR_LOG(m_logger) << "Funktionsraumkennung (" << funktionsraumkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..65535.";
|
|
return false;
|
|
}
|
|
case GEF_EINTRETEN_FUNKTIONSRAUM:
|
|
if (isPayloadLengthOk(15))
|
|
{
|
|
uint32_t funktionsraumkennung = getPayloadDataUInt32(13, 2);
|
|
if (funktionsraumkennung > 0)
|
|
return true;
|
|
|
|
ERROR_LOG(m_logger) << "Funktionsraumkennung (" << funktionsraumkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..65535.";
|
|
return false;
|
|
}
|
|
return false;
|
|
|
|
case GEF_SPRACHAUSWAHL:
|
|
{
|
|
uint8_t sprache = getPayloadDataUInt8(5);
|
|
if (sprache <= 3)
|
|
return true;
|
|
|
|
ERROR_LOG(m_logger) << "Sprache (" << sprache << ") of telegram with telId=" << getTelID() << " is invalid. Must be 0..3.";
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
case GEF_MANIPULATIONSMELDUNG:
|
|
return isPayloadLengthOk(12);
|
|
|
|
case GEF_BITE_MELDUNG2:
|
|
return isPayloadLengthOk(27, 19, 7);
|
|
|
|
case GEF_BETRIEBSZUSTAND_AUSSTATTUNG:
|
|
return isPayloadLengthOk(9);
|
|
|
|
case GEF_FEHLERMELDUNG_GFD:
|
|
return isPayloadLengthOk(9);
|
|
|
|
case GEF_POSITIONS_MELDUNG:
|
|
return isPayloadLengthOk(14);
|
|
|
|
case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER:
|
|
return isPayloadLengthOk(15, 14, 2);
|
|
|
|
case GEF_POSITIONS_MELDUNG_LFZ:
|
|
return isPayloadLengthOk(15);
|
|
|
|
case GEF_TREFFER_EREIGNIS_DUS:
|
|
return isPayloadLengthOk(23);
|
|
|
|
case GEF_TREFFER_EREIGNIS_WIRKSIMULATION:
|
|
return isPayloadLengthOk(22);
|
|
|
|
case GEF_SCHIEDSRICHTEREINGRIFF:
|
|
return isPayloadLengthOk(16);
|
|
|
|
case GEF_SELEKTIVE_AUFMUNITIONIERUNG:
|
|
return isPayloadLengthOk(8,7,8);
|
|
|
|
case GEF_TAKTISCHER_STATUS:
|
|
return isPayloadLengthOk(16);
|
|
|
|
case GEF_DATENVERKEHR_SRT_TDS:
|
|
case GEF_DATENVERKEHR_DMF_TDS:
|
|
{
|
|
uint16_t length = m_data.size() - DATA_IND_REQ_HEADER_LENGTH;
|
|
|
|
const uint16_t MIN_LENGTH = 7;
|
|
if (length >= MIN_LENGTH)
|
|
return true;
|
|
|
|
ERROR_LOG(m_logger) << "The payload-length of telegram with telId=" << getTelID() << " must be at least " << MIN_LENGTH << ", but it is only " << length;
|
|
return false;
|
|
}
|
|
|
|
case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME:
|
|
return isPayloadLengthOk(10);
|
|
|
|
case GEF_SONDERSENSORIK_BETRIEBSZUSTAND:
|
|
return isPayloadLengthOk(9);
|
|
|
|
case GEF_SONDERSENSORIK_FAHRSPUR:
|
|
return isPayloadLengthOk(15);
|
|
|
|
case GEF_SONDERSENSORIK_DATEN:
|
|
return isPayloadLengthOk(17);
|
|
|
|
case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN:
|
|
return isPayloadLengthOk(24);
|
|
|
|
case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN:
|
|
return isPayloadLengthOk(25);
|
|
|
|
case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION:
|
|
return isPayloadLengthOk(16);
|
|
|
|
case GEF_DATENVERKEHR_GEOP_TDS:
|
|
|
|
return isPayloadLengthOk(15, 14, 1);
|
|
|
|
case GEF_DATENVERKEHR_TGTC_TDS:
|
|
|
|
return isPayloadLengthOk(8, 7, 1);
|
|
|
|
case GEF_GERAETEEREIGNIS:
|
|
|
|
return isPayloadLengthOk(25, 24, 1);
|
|
|
|
case GEF_WAFFENZUORDNUNG:
|
|
|
|
return isPayloadLengthOk(8, 7, 6);
|
|
|
|
case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE:
|
|
|
|
return isPayloadLengthOk(13, 12, 5);
|
|
|
|
case GEF_IPS_POSITIONSDATEN:
|
|
|
|
return isPayloadLengthOk(8, 7, 2);
|
|
|
|
case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG:
|
|
return isPayloadLengthOk({13, 17});
|
|
|
|
case GEF_TEILNEHMERMODE_MELDUNG:
|
|
return isPayloadLengthOk(15);
|
|
|
|
case GEF_TEILNEHMER_KONFIG_ANTWORT:
|
|
return isPayloadLengthOk(27);
|
|
|
|
case GEF_DEFINITION_IED:
|
|
return isPayloadLengthOk(24);
|
|
|
|
case GEF_ZUSTAND_IED:
|
|
return isPayloadLengthOk(16);
|
|
|
|
case GEF_STATUS_EINZELMINENSIMULATOR:
|
|
return isPayloadLengthOk(17);
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_minLength,
|
|
const uint16_t a_dataAmountOffset,
|
|
const uint8_t a_variableDataElementSize) const
|
|
{
|
|
if (0 == a_variableDataElementSize)
|
|
return isPayloadLengthOk(a_minLength);
|
|
|
|
const uint16_t length = getPayloadSize();
|
|
if (length >= a_minLength)
|
|
{
|
|
uint8_t dataAmount = getPayloadDataUInt8(a_dataAmountOffset);
|
|
uint16_t dataSize = a_variableDataElementSize * dataAmount;
|
|
uint16_t expectedLength = dataSize + a_minLength;
|
|
if (expectedLength != length)
|
|
{
|
|
WARNING_LOG(m_logger) << "The payload-length of telegram with telId: "
|
|
<< getTelID() << " must be " << expectedLength
|
|
<< ", but it is " << length << " (the amount of variable data in telegram was "
|
|
<< dataAmount << " => " << dataSize << " bytes)";
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " << getTelID()
|
|
<< " must be at least " << a_minLength << ", but it is only " << length;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_minLength,
|
|
uint16_t a_maxLength) const
|
|
{
|
|
if (a_maxLength == 0)
|
|
return isPayloadLengthOk(a_minLength);
|
|
|
|
const uint16_t length = getPayloadSize();
|
|
if (length < a_minLength)
|
|
{
|
|
WARNING_LOG(m_logger) << "The payload-length of telegram with telId: "
|
|
<< getTelID() << " must be greater or equal to "
|
|
<< a_minLength << ", but it is " << length;
|
|
return false;
|
|
}
|
|
|
|
if (length > a_maxLength)
|
|
{
|
|
WARNING_LOG(m_logger) << "The payload-length of telegram with telId: "
|
|
<< getTelID() << " must be fewer than "
|
|
<< a_minLength << ", but it is " << length;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_length) const
|
|
{
|
|
const uint16_t length = getPayloadSize();
|
|
if (length == a_length)
|
|
return true;
|
|
|
|
WARNING_LOG(m_logger) << "The payload-length of telegram with telId: "
|
|
<< getTelID() << " must be "
|
|
<< a_length << ", but it is " << length;
|
|
return false;
|
|
}
|
|
|
|
bool CoPrtCnvRadioTelegram::isPayloadLengthOk(const std::vector<uint16_t> &a_lengths) const
|
|
{
|
|
const uint16_t length = getPayloadSize();
|
|
if (std::any_of(a_lengths.begin(), a_lengths.end(), [length](int len) { return len == length;}))
|
|
return true;
|
|
|
|
WARNING_LOG(m_logger) << "The payload-length of telegram with telId: "
|
|
<< getTelID() << ", is: " << length;
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::mustBeSentAsBroadcast(time_t a_currentTime, bool &a_wasLastBroadcast, const bool a_updateBroadcastCounter)
|
|
{
|
|
a_wasLastBroadcast = false;
|
|
|
|
if (m_BroadcastCounter < s_maxBroadcastSendCnt && m_NextSendTime <= a_currentTime)
|
|
{
|
|
if (a_updateBroadcastCounter)
|
|
{
|
|
|
|
switch (m_BroadcastCounter)
|
|
{
|
|
case 0:
|
|
if (s_2ndDelay >= 0)
|
|
{
|
|
m_NextSendTime = time(nullptr) + s_2ndDelay;
|
|
INFO_LOG(m_logger) << "1st Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex();
|
|
break;
|
|
}
|
|
++m_BroadcastCounter;
|
|
Q_FALLTHROUGH();
|
|
case 1:
|
|
if (s_3rdDelay >= 0)
|
|
{
|
|
m_NextSendTime = time(nullptr) + s_3rdDelay;
|
|
INFO_LOG(m_logger) << "2nd Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex();
|
|
break;
|
|
}
|
|
++m_BroadcastCounter;
|
|
Q_FALLTHROUGH();
|
|
default:
|
|
INFO_LOG(m_logger) << "3rd Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex();
|
|
m_NextSendTime = 0;
|
|
a_wasLastBroadcast = true;
|
|
}
|
|
++m_BroadcastCounter;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setBroadcastDelayTimes(int a_2ndDelay, int a_3rdDelay)
|
|
{
|
|
s_2ndDelay = a_2ndDelay;
|
|
s_3rdDelay = a_3rdDelay;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setMaxBroadcastSendCnt(int a_maxSendCnt)
|
|
{
|
|
s_maxBroadcastSendCnt = a_maxSendCnt;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isMovedToBroadcastList() const
|
|
{
|
|
return (m_BroadcastCounter >= 1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setBroadcastOnly(const bool a_doSet)
|
|
{
|
|
m_IsBroadcastOnly = a_doSet;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CoPrtCnvRadioTelegram::isBroadcastOnly() const
|
|
{
|
|
return m_IsBroadcastOnly;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setBroadcastonlyTelegram(const std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> &a_radioTelegram)
|
|
{
|
|
if (a_radioTelegram != nullptr && m_BroadcastOnlyTelegram != nullptr)
|
|
ERROR_LOG(m_logger) << "Internal error: m_BroadcastOnlyTelegram was not nullptr";
|
|
if (a_radioTelegram != nullptr)
|
|
{
|
|
INFO_LOG(m_logger) << "Set braodcastonly-telegram: telId=" << a_radioTelegram->getTelID()
|
|
<< " BC=" << a_radioTelegram->getBroadcastIndex();
|
|
}
|
|
m_BroadcastOnlyTelegram = a_radioTelegram;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<N_CoPrtCnv::CoPrtCnvRadioTelegram> CoPrtCnvRadioTelegram::getBroadcastonlyTelegram() const
|
|
{
|
|
return m_BroadcastOnlyTelegram;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::set1Byte(QByteArray &a_data, uint16_t a_offset, uint8_t a_value)
|
|
{
|
|
Q_ASSERT(a_offset < a_data.size());
|
|
uint8_t *ptr = reinterpret_cast<uint8_t *>(&a_data.data()[a_offset]);
|
|
*ptr = a_value;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::set2Byte(QByteArray &a_data, uint16_t a_offset, uint16_t a_value)
|
|
{
|
|
Q_ASSERT(a_offset < a_data.size());
|
|
uint16_t *ptr = reinterpret_cast<uint16_t *>(&a_data.data()[a_offset]);
|
|
*ptr = a_value;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::set4Byte(QByteArray &a_data, uint16_t a_offset, uint32_t a_value)
|
|
{
|
|
Q_ASSERT(a_offset < a_data.size());
|
|
uint32_t *ptr = reinterpret_cast<uint32_t *>(&a_data.data()[a_offset]);
|
|
*ptr = a_value;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getUInt16(const uint16_t a_offset) const
|
|
{
|
|
const uint16_t *ptr = reinterpret_cast<const uint16_t *>(&m_data.data()[a_offset]);
|
|
return *ptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t CoPrtCnvRadioTelegram::getUInt32(const uint16_t a_offset) const
|
|
{
|
|
const uint32_t *ptr = reinterpret_cast<const uint32_t *>(&m_data.data()[a_offset]);
|
|
return *ptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setHeader(QByteArray &data, E_PDU_Type pduType)
|
|
{
|
|
|
|
set1Byte(data, 0, MAGIC_NUMBER);
|
|
set1Byte(data, 1, 0);
|
|
set2Byte(data, 2, data.size() - sizeof(PrtCnvRadioGwHeader));
|
|
set1Byte(data, 4, pduType);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::fillDataIndReqHeader(QByteArray &a_data)
|
|
{
|
|
set1Byte(a_data, 4, e_DataIndReq);
|
|
setSrcISSI_Internal(a_data, 0);
|
|
setDestISSI_Internal(a_data, 0);
|
|
|
|
set1Byte(a_data, 13, s_protocolIdentifier);
|
|
set1Byte(a_data, 14, 0);
|
|
set1Byte(a_data, 15, 0);
|
|
set1Byte(a_data, 16, 0);
|
|
set1Byte(a_data, 17, 0);
|
|
set1Byte(a_data, 18, 0);
|
|
set1Byte(a_data, 19, 0);
|
|
set1Byte(a_data, 20, 0);
|
|
set1Byte(a_data, 21, e_FlagsNone);
|
|
|
|
uint16_t size = a_data.size();
|
|
set2Byte(a_data, 22, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH) * 8);
|
|
set2Byte(a_data, 24, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setSrcISSI_Internal(QByteArray &data, const uint32_t issi)
|
|
{
|
|
set4Byte(data, 5, issi);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t CoPrtCnvRadioTelegram::getBroadcastCounter() const
|
|
{
|
|
return m_BroadcastCounter;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CoPrtCnvRadioTelegram::setDestISSI_Internal(QByteArray &data, const uint32_t issi)
|
|
{
|
|
set4Byte(data, 9, issi);
|
|
}
|