Files
qt5-legatus-legacy/Lts/Proxies/Buildings/BuildingControlUnit/BSM/bsm_telegrams_base.cpp
T
2026-08-13 18:33:10 +02:00

280 lines
7.2 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Oberklasser der BSM-Telegramme
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_base.h"
#include "bsm_telegrams_alive.h"
#include "bsm_telegrams_bit_timeout_report.h"
#include "bsm_telegrams_direct_fire.h"
#include "bsm_telegrams_sw_version_report.h"
#include "bsm_telegrams_sw_version_request.h"
#include "bsm_telegrams_configuration_report.h"
#include "bsm_telegrams_observer_controller.h"
#include "bsm_telegrams_technical_status.h"
#include <logger.h>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
static inline QByteArray escapeData(const QByteArray &bufferData)
{
QByteArray ret;
ret.reserve(bufferData.size() * 1.2);
for (const unsigned char c : bufferData)
{
if (c >= 0x20 && c < 0x7f)
ret += c;
else
ret += "\\x" + QByteArray::number(static_cast<unsigned char>(c), 16);
}
return ret;
}
QByteArray toString(PanTelegramId teleId)
{
switch (teleId)
{
case PanTelegramId::ALIVE:
return "ALIVE";
case PanTelegramId::REQ_BIT_TIMEOUT:
return "REQ_BIT_TIMEOUT";
case PanTelegramId::BIT_TIMEOUT_REPORT:
return "BIT_TIMEOUT_REPORT";
case PanTelegramId::REQ_SW_VERSION:
return "REQ_SW_VERSION";
case PanTelegramId::SW_VERSION_REPORT:
return "SW_VERSION_REPORT";
case PanTelegramId::CONFIGURATION_SETUP:
return "CONFIGURATION_SETUP";
case PanTelegramId::REQ_CONFIGURATION:
return "REQ_CONFIGURATION";
case PanTelegramId::CONFIGURATION_REPORT:
return "CONFIGURATION_REPORT";
case PanTelegramId::ER_DIRECT_FIRE:
return "ER_DIRECT_FIRE";
case PanTelegramId::ER_OBSERVER_CONTR:
return "ER_OBSERVER_CONTR";
case PanTelegramId::REQ_TECHNICAL_STATUS:
return "REQ_TECHNICAL_STATUS";
case PanTelegramId::TECHNICAL_STATUS:
return "TECHNICAL_STATUS";
case PanTelegramId::SIGNAL_FLASHLIGHT:
return "SIGNAL_FLASHLIGHT";
case PanTelegramId::CHOPPED_SIGNAL_FLASH:
return "CHOPPED_SIGNAL_FLASH";
}
return QByteArray("Unknown: ") + QByteArray::number(static_cast<int>(teleId));
}
QByteArray Telegram::toBytestream() const
{
const int teleId = static_cast<int>(telId());
const int payloadLen = payload().size();
QByteArray ret;
ret.reserve(5 + payloadLen);
// N. Thoden, 02.11.2021
// without resize following message appears:
// "Using QByteRef with an index pointing outside the valid range of a QByteArray. The corresponding behavior is deprecated, and will be changed in a future version of Qt."
// Qt doc at operator[]: "If an assignment is made beyond the end of the byte array, the array is extended with resize() before the assignment takes place."
// so resize explicit:
ret.resize(2);
ret[0] = teleId & 0xFF; //Message.ID (LSB)
ret[1] = ((teleId & 0x100) >> 1) | (((payloadLen + 3) & 0x1F) << 2); //Bit 1 MsgID-MSB; Bit 2-6 Length (Payload == Datafields+Checksum)
// END
ret += payload();
ret += calcChecksum(ret);
ret = substituteData(ret);
ret.prepend(s_stx);
ret.append(s_etx);
return ret;
}
Telegram *Telegram::telegramFromBytestream(const QByteArray &data_)
{
NGL::INGLLogger &logger = BuildingControlUnit::getLogger("BSM.Telegrams");
QByteArray data = desubstituteData(data_);
if (data.size() < 2)
return nullptr;
TRACE_LOG(logger) << "Incoming data: 0x" << data.toHex();
const unsigned char cs = data.at(data.size() - 1);
// jetzt checksum wegnehmen
data.chop(1);
// und checksumme über Rest berechnen
const unsigned char csCalc = calcChecksum(data);
if (cs != csCalc)
{
WARNING_LOG(logger) << "Checksum does not match. Is: 0x" << QByteArray::number(cs, 16)
<< ", should be: 0x" << QByteArray::number(csCalc, 16);
}
int msg_id; // die ersten 9 Bits
int msg_id_lsb = static_cast<int>(data.at(0)) & 0xFF;
int msg_id_msb = static_cast<int>(data.at(1)) & 0x80;
msg_id_msb <<= 1;
msg_id = msg_id_lsb + msg_id_msb;
const PanTelegramId teleId = static_cast<PanTelegramId>(msg_id);
const QByteArray payload = data.mid(2);
TRACE_LOG(logger) << "incoming data: " << data.toHex() << ", - payload: " << payload.toHex();
Telegram *tele = nullptr;
switch (teleId)
{
case PanTelegramId::ALIVE:
tele = PanAlive::fromBytestream(payload);
break;
case PanTelegramId::REQ_BIT_TIMEOUT:
break;
case PanTelegramId::BIT_TIMEOUT_REPORT:
tele = PanBitTimeoutReport::fromBytestream(payload);
break;
case PanTelegramId::SW_VERSION_REPORT:
tele = PanSwVersionReport::fromBytestream(payload);
break;
case PanTelegramId::REQ_SW_VERSION:
break;
case PanTelegramId::CONFIGURATION_SETUP:
break;
case PanTelegramId::REQ_CONFIGURATION:
break;
case PanTelegramId::CONFIGURATION_REPORT:
tele = PanConfigurationReport::fromBytestream(payload);
break;
case PanTelegramId::ER_DIRECT_FIRE:
tele = PanDirectFire::fromBytestream(payload);
break;
case PanTelegramId::ER_OBSERVER_CONTR:
tele = PanObserverController::fromBytestream(payload);
break;
case PanTelegramId::REQ_TECHNICAL_STATUS:
break;
case PanTelegramId::TECHNICAL_STATUS:
tele = PanTechnicalStatus::fromBytestream(payload);
break;
case PanTelegramId::SIGNAL_FLASHLIGHT:
break;
case PanTelegramId::CHOPPED_SIGNAL_FLASH:
break;
}
if (!tele)
{
WARNING_LOG(logger) << "Error parsing bsm tele with id " << toString(teleId)
<< ", data: " << escapeData(data);
}
// else
// {
// if (tele->telId() != PanTelegramId::ALIVE)
// DEBUG_LOG(logger) << "tele: " << tele->print();
// }
return tele;
}
unsigned short Telegram::decode_ushort_little(const QByteArray &data, const int start, bool &bOk)
{
bOk = false;
// Always 2 Bytes
unsigned short byte1 = 0;
unsigned short byte2 = 0;
if (start + 2 <= data.size())
{
byte1 = ((data[start + 1]) & 0xFF) << 8;
byte2 = (data[start]) & 0xFF;
bOk = true;
}
return (byte1 + byte2);
}
unsigned char Telegram::calcChecksum(const QByteArray &data)
{
unsigned char cs = 0;
for (const unsigned char c : data)
cs += c;
return cs ^ 0xff;
}
QByteArray Telegram::substituteData(const QByteArray &data)
{
QByteArray ret;
ret.reserve(data.size());
for (const unsigned char c : data)
{
switch (c)
{
case s_stx:
ret += s_subMark;
ret += s_subStx;
break;
case s_etx:
ret += s_subMark;
ret += s_subEtx;
break;
case s_subMark:
ret += s_subMark;
ret += static_cast<char>(s_subSub);
break;
default:
ret += c;
break;
}
}
return ret;
}
QByteArray Telegram::desubstituteData(const QByteArray &data)
{
QByteArray ret;
ret.reserve(data.size());
for (int i = 0; i < data.size(); ++i)
{
const unsigned char c = data.at(i);
if (c == s_subMark)
{
++i;
if (i < data.size())
{
const unsigned char s = data.at(i);
switch (s)
{
case s_subStx:
ret += s_stx;
break;
case s_subEtx:
ret += s_etx;
break;
case s_subSub:
ret += s_subMark;
break;
default:
ret += s;
break;
}
}
}
else
ret += c;
}
return ret;
}
} // namespace Telegrams
} // namespace BSM
} //namespace BuildingControlUnit