Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

@@ -0,0 +1,54 @@
#
# $Id$
# $HeadURL$
# $Author$
#
SET(bsm_SRCS
bsm_api.cpp
bsm_api.h
bsm_socket.cpp
bsm_socket.h
bsm_socket_handler.cpp
bsm_socket_handler.h
bsm_telegrams_alive.h
bsm_telegrams_base.cpp
bsm_telegrams_base.h
bsm_telegrams_bit_timeout_report.cpp
bsm_telegrams_bit_timeout_report.h
bsm_telegrams_bit_timeout_request.h
bsm_telegrams_chopped_signal_flash.cpp
bsm_telegrams_chopped_signal_flash.h
bsm_telegrams_configuration_report.cpp
bsm_telegrams_configuration_report.h
bsm_telegrams_configuration_request.h
bsm_telegrams_configuration_setup.cpp
bsm_telegrams_configuration_setup.h
bsm_telegrams_direct_fire.cpp
bsm_telegrams_direct_fire.h
bsm_telegrams_observer_controller.cpp
bsm_telegrams_observer_controller.h
bsm_telegrams_sw_version_report.cpp
bsm_telegrams_sw_version_report.h
bsm_telegrams_sw_version_request.h
bsm_telegrams_technical_status.cpp
bsm_telegrams_technical_status.h
bsm_telegrams_technical_status_request.h
bsm_types.h
)
NGL_ADD_LIBRARY2(AAR SV BuildingControlBsm SHARED ${bsm_SRCS})
NGL_TARGET_LINK_LIBRARIES(BuildingControlBsm
PRIVATE
NGLLogger
PUBLIC
Qt5::Core
Qt5::Network
BuildingControlCommon
)
NGL_ADD_EXECUTABLE(AAR SV BuildingControlTestBsm bsm_test_main.cpp)
NGL_TARGET_LINK_LIBRARIES(BuildingControlTestBsm
BuildingControlBsm
nglcoreapplication
)
+99
View File
@@ -0,0 +1,99 @@
/**
* @RDE_HEADER@
* Api for BSM access
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-26
*/
#include "bsm_api.h"
#include "bsm_socket_handler.h"
namespace BuildingControlUnit
{
namespace BSM
{
Api::Api(QObject *parent)
: QObject(parent)
, m_socketHandler(new SocketHandler(this))
, m_logger(BuildingControlUnit::getLogger("BSM.Api"))
{
connect(m_socketHandler, &SocketHandler::opticalShot,
this, &Api::opticalShot);
connect(m_socketHandler, &SocketHandler::opticalShotOC,
this, &Api::opticalShotOC);
connect(m_socketHandler, &SocketHandler::bsmStateChanged,
this, &Api::bsmStateChanged);
}
Api::~Api()
{
delete m_socketHandler;
}
bool Api::init(const BuildingBsmConfig &bsmConfig)
{
return m_socketHandler->init(bsmConfig);
}
bool Api::triggerFlashlight(int bsmId, const QString &hostname, int numberOfFlashes, int pauseBetweenFlashesSec)
{
DEBUG_LOG(m_logger) << "triggerFlashlight bsmId=" << bsmId
<< " hostname=" << hostname
<< " numberOfFlashes=" << numberOfFlashes
<< " pauseBetweenFlashesSec=" << pauseBetweenFlashesSec;
return m_socketHandler->triggerFlashlight(bsmId, hostname, numberOfFlashes, pauseBetweenFlashesSec);
}
bool Api::triggerFlashlightPulse(int bsmId, const QString &hostname,
int numberOfFlashes,
int pauseDuration,
int choppedConfiguration,
int flashDuration)
{
DEBUG_LOG(m_logger) << "triggerFlashlightPulse bsmId=" << bsmId
<< " hostname=" << hostname
<< " numberOfFlashes=" << numberOfFlashes
<< " pauseDuration=" << pauseDuration
<< " choppedConfiguration=" << choppedConfiguration
<< " flashDuration=" << flashDuration;
return m_socketHandler->triggerFlashlightPulse(bsmId, hostname, numberOfFlashes, pauseDuration, choppedConfiguration, flashDuration);
}
bool Api::triggerFlashlights( int numberOfFlashes,
int pauseDuration,
int choppedConfiguration,
int flashDuration)
{
DEBUG_LOG(m_logger) << "triggerFlashlights numberOfFlashes=" << numberOfFlashes
<< " pauseDuration=" << pauseDuration
<< " choppedConfiguration" << choppedConfiguration
<< " flashDuration=" << flashDuration;
return m_socketHandler->triggerFlashlights( numberOfFlashes, pauseDuration, choppedConfiguration, flashDuration);
}
QVector<BsmState> Api::bsmStates() const
{
return m_socketHandler->bsmStates();
}
bool Api::getBsmConfiguration(int bsmId)
{
return m_socketHandler->getBsmConfiguration(bsmId);
}
bool Api::getBsmBitTimeout(int bsmId)
{
return m_socketHandler->getBsmBitTimeout(bsmId);
}
bool Api::getBsmTechnicalStatus(int bsmId)
{
return m_socketHandler->getBsmTechnicalStatus(bsmId);
}
} // namespace BSM
} // namespace BuildingControlUnit
+63
View File
@@ -0,0 +1,63 @@
/**
* @RDE_HEADER@
* Api for BSM access
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-26
*/
#pragma once
#include <BSM/buildingcontrolbsm_export.h>
#include <QObject>
#include <logger.h>
#include "bsm_types.h"
namespace BuildingControlUnit
{
namespace BSM
{
class SocketHandler;
class BUILDINGCONTROLBSM_EXPORT Api : public QObject
{
Q_OBJECT
public:
explicit Api(QObject *parent = nullptr);
~Api();
QVector<BsmState> bsmStates() const;
bool init(const BuildingBsmConfig &bsmConfig);
public Q_SLOTS:
bool triggerFlashlight(int bsmId, const QString &hostname = QString(), int numberOfFlashes = 1, int pauseBetweenFlashesSec = 1);
bool triggerFlashlightPulse(int bsmId, const QString &hostname = QString(),
int numberOfFlashes = 1,
int pauseDuration = 1,
int choppedConfiguration = 10,
int flashDuration = 30);
bool triggerFlashlights(int numberOfFlashes,
int pauseDuration,
int choppedConfiguration,
int flashDuration);
bool getBsmConfiguration(int bsmId);
bool getBsmBitTimeout(int bsmId);
bool getBsmTechnicalStatus(int bsmId);
Q_SIGNALS:
void opticalShot(qint64 timeMSec,
int sensorId,
int originatorId,
int ammunitionId,
int deposition1,
int deposition2);
void opticalShotOC(qint64 timeMSec,
int sensorId,
int originatorId,
int ammunitionId,
DamageState damageState);
void bsmStateChanged(const QVector<BsmState> &bsmStates);
private:
SocketHandler *m_socketHandler;
NGL::INGLLogger &m_logger;
};
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,141 @@
/**
* @RDE_HEADER@
* One connection to a bsm
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-18
*/
#include "bsm_socket.h"
#include "bsm_telegrams_configuration_setup.h"
#include <QTimer>
#include <QHostAddress>
static const int s_aliveTimeout = 10; // 10 seconds
namespace BuildingControlUnit
{
namespace BSM
{
Socket::Socket(const Bsm &cfg, QObject *parent)
: QObject(parent)
, m_config(cfg)
, m_tcpSocket(new QTcpSocket(this))
, m_reconnectTimer(nullptr)
, m_aliveTimer(new QTimer(this))
, m_logger(BuildingControlUnit::getLogger("BSM.Socket"))
{
m_aliveTimer->setTimerType(Qt::VeryCoarseTimer);
m_aliveTimer->setSingleShot(true);
m_aliveTimer->setInterval(s_aliveTimeout * 2 * 1000);
connect(m_aliveTimer, &QTimer::timeout, this, &Socket::onAliveTimeout);
connect(m_tcpSocket, &QTcpSocket::connected,
this, &Socket::onConnected);
connect(m_tcpSocket, &QTcpSocket::disconnected,
this, &Socket::onDisconnected);
connect(m_tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),
this, &Socket::onError);
connect(m_tcpSocket, &QTcpSocket::readyRead,
this, &Socket::onReadyRead);
onConnect();
}
bool Socket::isConnected() const
{
return m_tcpSocket && (m_tcpSocket->state() == QAbstractSocket::ConnectedState);
}
bool Socket::sendData(const QByteArray &data)
{
if (!isConnected())
{
WARNING_LOG(m_logger) << "BSM " << m_config.id << ": Trying to send data but not connected!";
return false;
}
DEBUG_LOG(m_logger) << "BSM " << m_config.id << ": sending data: 0x" << data.toHex();
m_tcpSocket->write(data);
m_tcpSocket->flush();
return true;
}
void Socket::setVersionInformation(int verMajor, int verMinor, int verRev, const QString &manufacturer)
{
m_versionInfo = QStringLiteral("%1.%2-%3 (%4)").arg(verMajor).arg(verMinor).arg(verRev).arg(manufacturer);
INFO_LOG(m_logger) << "BSM " << m_config.id
<< ": version = " << m_versionInfo;
}
void Socket::gotAlive()
{
// restart timer
if (m_aliveTimer)
m_aliveTimer->start();
}
void Socket::onConnected()
{
INFO_LOG(m_logger) << "BSM " << m_config.id << " is connected to "
<< m_tcpSocket->peerAddress().toString() << ":" << m_tcpSocket->peerPort();
Telegrams::PanConfigurationSetup tele;
tele.m_aliveMessage = s_aliveTimeout;
sendData(tele.toBytestream());
m_aliveTimer->start();
emit connected(m_config.id);
}
void Socket::onDisconnected()
{
INFO_LOG(m_logger) << "BSM " << m_config.id << " is disconnected";
m_versionInfo.clear();
startReconnectTimer();
emit disconnected(m_config.id);
}
void Socket::onError(QAbstractSocket::SocketError error)
{
DEBUG_LOG(m_logger) << "BSM " << m_config.id
<< " can not connect to " << m_config.hostname << ":" << m_config.port
<< ": " << m_tcpSocket->errorString()
<< " (" << error << ");";
startReconnectTimer();
}
void Socket::onConnect()
{
DEBUG_LOG(m_logger) << "BSM " << m_config.id
<< " trying to connect to " << m_config.hostname << ":" << m_config.port;
m_tcpSocket->connectToHost(m_config.hostname, m_config.port);
}
void Socket::onReadyRead()
{
emit dataAvailable(m_config.id, m_tcpSocket->readAll());
}
void Socket::onAliveTimeout()
{
WARNING_LOG(m_logger) << "BSM " << m_config.id
<< " alive timeout! Reconnecting";
//m_tcpSocket->disconnectFromHost();
}
void Socket::startReconnectTimer()
{
if (!m_reconnectTimer)
{
m_reconnectTimer = new QTimer(this);
m_reconnectTimer->setTimerType(Qt::VeryCoarseTimer);
m_reconnectTimer->setSingleShot(true);
connect(m_reconnectTimer, &QTimer::timeout, this, &Socket::onConnect);
}
m_reconnectTimer->start(2000); // after 2sec
if (m_aliveTimer)
m_aliveTimer->stop();
}
} // namespace BSM
} // namespace BuildingControlUnit
+59
View File
@@ -0,0 +1,59 @@
/**
* @RDE_HEADER@
* One connection to a bsm
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-18
*/
#pragma once
#include <QObject>
#include <QHostAddress>
#include <QTcpSocket>
#include <logger.h>
#include "bsm_types.h"
class QTimer;
namespace BuildingControlUnit
{
namespace BSM
{
class Socket : public QObject
{
Q_OBJECT
public:
explicit Socket(const BuildingControlUnit::Bsm &cfg, QObject *parent = nullptr);
bool isConnected() const;
bool sendData(const QByteArray &data);
const BuildingControlUnit::Bsm &bsmConfig() const { return m_config; }
QString versionInfo() const { return m_versionInfo; }
void setVersionInformation(int verMajor, int verMinor, int verRev, const QString &manufacturer);
void gotAlive();
QHostAddress peerAddress() const { return m_tcpSocket->peerAddress(); }
Q_SIGNALS:
void dataAvailable(int id, const QByteArray &data);
void connected(int id);
void disconnected(int id);
private Q_SLOTS:
void onConnected();
void onDisconnected();
void onError(QAbstractSocket::SocketError error);
void onConnect();
void onReadyRead();
void onAliveTimeout();
private:
void startReconnectTimer();
private:
BuildingControlUnit::Bsm m_config;
QTcpSocket *m_tcpSocket;
QTimer *m_reconnectTimer;
QTimer *m_aliveTimer;
QString m_versionInfo;
NGL::INGLLogger &m_logger;
};
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,469 @@
/**
* @RDE_HEADER@
* Handle incoming/outgoing data from/to all BSMs of one building
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-18
*/
#include "bsm_socket_handler.h"
#include "bsm_telegrams_base.h"
#include "bsm_telegrams_bit_timeout_request.h"
#include "bsm_telegrams_chopped_signal_flash.h"
#include "bsm_telegrams_configuration_request.h"
#include "bsm_telegrams_direct_fire.h"
#include "bsm_telegrams_observer_controller.h"
#include "bsm_telegrams_sw_version_report.h"
#include "bsm_telegrams_sw_version_request.h"
#include "bsm_telegrams_technical_status_request.h"
#include <QDateTime>
#include <QHostInfo>
namespace BuildingControlUnit
{
namespace BSM
{
static const qint64 s_opticalTimeSlot = 100;
SocketHandler::SocketHandler(QObject *parent)
: QObject(parent)
, m_logger(BuildingControlUnit::getLogger("BSM.SocketHandler"))
{
connect(&m_cleanupQueueTimer, &QTimer::timeout,
this, &SocketHandler::onCleanupQueue);
m_cleanupQueueTimer.setSingleShot(false);
m_cleanupQueueTimer.setInterval(10000);
m_cleanupQueueTimer.setTimerType(Qt::VeryCoarseTimer);
m_cleanupQueueTimer.start();
connect(&m_bsmStateTimer, &QTimer::timeout, this, &SocketHandler::onBsmStateTimerTimeOut);
m_bsmStateTimer.setSingleShot(true);
m_bsmStateTimer.setInterval(500);
m_bsmStateTimer.setTimerType(Qt::VeryCoarseTimer);
}
bool SocketHandler::init(const BuildingBsmConfig &bsmConfig)
{
// remove old sockets (should never happen)
qDeleteAll(m_sockets);
m_sockets.clear();
m_socketData.clear();
for (const Bsm &c : bsmConfig.bsmMap)
{
Socket *s = new Socket(c, this);//THIS
connect(s, &Socket::dataAvailable,
this, &SocketHandler::onDataAvailable);
connect(s, &Socket::disconnected,
this, &SocketHandler::onSocketDisconnected);
connect(s, &Socket::connected,
this, &SocketHandler::onSocketConnected);
m_sockets[c.id] = s;
}
return true;
}
bool SocketHandler::triggerFlashlight(int bsmId, const QString &hostname, int numberOfFlashes, int pauseBetweenFlashesSec)
{
Socket *s = hostname.isEmpty() ? getSocketForBsm(bsmId) : getSocketForBsm(hostname);
if (!s)
return false;
DEBUG_LOG(m_logger) << "triggerFlashlight BSM Socket with socketId " << bsmId;
Telegrams::PanChoppedSignalFlashlight flash;
flash.m_noOfFlashes = qBound(0, numberOfFlashes, 255);
flash.m_pauseDuration = qBound(1, pauseBetweenFlashesSec, 10);
flash.m_flashDuration = 1;
return s->sendData(flash.toBytestream());
}
bool SocketHandler::triggerFlashlightPulse(int bsmId, const QString &hostname,
int numberOfFlashes,
int pauseDuration,
int choppedConfiguration,
int flashDuration)
{
Socket *s = hostname.isEmpty() ? getSocketForBsm(bsmId) : getSocketForBsm(hostname);
if (!s)
return false;
DEBUG_LOG(m_logger) << "triggerFlashlightPulse BSM Socket with socketId " << bsmId
<< " hostname=" << hostname
<< " numberOfFlashes=" << numberOfFlashes
<< " pauseDuration=" << pauseDuration
<< " choppedConfiguration=" << choppedConfiguration
<< " flashDuration=" << flashDuration;
Telegrams::PanChoppedSignalFlashlight flash;
flash.m_noOfFlashes = qBound(0, numberOfFlashes, 255);
flash.m_pauseDuration = qBound(1, pauseDuration, 10);
flash.m_choppedFlashConfig = qBound(2, choppedConfiguration, 10);
flash.m_flashDuration = flashDuration;
return s->sendData(flash.toBytestream());
}
bool SocketHandler::triggerFlashlights(int numberOfFlashes,
int pauseDuration,
int choppedConfiguration,
int flashDuration)
{
int cntSocketsActive = 0;
Telegrams::PanChoppedSignalFlashlight flash;
flash.m_noOfFlashes = qBound(0, numberOfFlashes, 255);
flash.m_pauseDuration = qBound(1, pauseDuration, 10);
flash.m_choppedFlashConfig = qBound(2, choppedConfiguration, 10);
flash.m_flashDuration = flashDuration;
const QByteArray data = flash.toBytestream();
for (Socket *s : qAsConst(m_sockets))
{
if (s->isConnected())
{
if (s->sendData(data))
++cntSocketsActive;
}
else
WARNING_LOG(m_logger) << "BSM " << s->bsmConfig().id
<< " is not connected - can not activate flash light";
}
if (cntSocketsActive == 0)
{
WARNING_LOG(m_logger) << "No active bsm - can not trigger flash light for all bsm";
return false;
}
return true;
}
bool SocketHandler::getBsmConfiguration(int bsmId)
{
Socket *s = getSocketForBsm(bsmId);
if (!s)
return false;
Telegrams::PanConfigurationRequest req;
return s->sendData(req.toBytestream());
}
bool SocketHandler::getBsmBitTimeout(int bsmId)
{
Socket *s = getSocketForBsm(bsmId);
if (!s)
return false;
Telegrams::PanBitTimeoutRequest req;
return s->sendData(req.toBytestream());
}
bool SocketHandler::getBsmTechnicalStatus(int bsmId)
{
Socket *s = getSocketForBsm(bsmId);
if (!s)
return false;
Telegrams::PanTechnicalStatusRequest req;
return s->sendData(req.toBytestream());
}
QVector<BsmState> SocketHandler::bsmStates() const
{
QVector<BsmState> ret;
ret.reserve(m_sockets.size());
for (const Socket *s : m_sockets)
{
BsmState bs(s->bsmConfig());
bs.bConnected = s->isConnected();
bs.versionInfo = s->versionInfo();
ret += bs;
}
return ret;
}
void SocketHandler::onBsmStateTimerTimeOut()
{
emit bsmStateChanged(bsmStates());
}
void SocketHandler::onDataAvailable(int id, const QByteArray &data)
{
m_socketData[id] = parseBuffer(id, m_socketData[id] + data);
}
void SocketHandler::onSocketConnected(int id)
{
requestVersion(id); // hopefully 500ms are enough for a version request
DEBUG_LOG(m_logger) << "BSM Socket with id " << id << " connected";
m_bsmStateTimer.start();
}
void SocketHandler::onSocketDisconnected(int id)
{
DEBUG_LOG(m_logger) << "BSM Socket with id " << id << " disconnected";
m_socketData[id].clear();
m_bsmStateTimer.start();
}
void SocketHandler::onCleanupQueue()
{
if (m_lastShots.isEmpty())
return;
QVector<OpticalShot> activeShots;
qint64 tNow = QDateTime::currentMSecsSinceEpoch();
for (const OpticalShot &os : qAsConst(m_lastShots))
{
if (os.timeStampMSec < tNow - s_opticalTimeSlot)
continue;
activeShots += os;
}
m_lastShots = activeShots;
}
Socket *SocketHandler::getSocketForBsm(int bsmId)
{
Socket *s = m_sockets.value(bsmId);
if (!s)
{
WARNING_LOG(m_logger) << "Got invalid bsm id (" << bsmId << ") to trigger flashlight";
return nullptr;
}
if (!s->isConnected())
{
WARNING_LOG(m_logger) << "Bsm with id " << bsmId
<< " is not connected - can not activate flash light";
return nullptr;
}
return s;
}
Socket *SocketHandler::getSocketForBsm(const QString &hostname)
{
const QHostInfo hi = QHostInfo::fromName(hostname);
const auto addresses = hi.addresses();
if (addresses.isEmpty())
return nullptr;
for (const QHostAddress &ha : addresses)
{
if (ha.isLoopback())
continue;
for (Socket *s : qAsConst(m_sockets))
{
if (s->peerAddress() == ha)
return s;
}
}
return nullptr;
}
QByteArray SocketHandler::parseBuffer(int id, const QByteArray &buffer)
{
int iEndPos = 0;
int iCurReadPos = 0;
while (findNextSyncStartByte(buffer, iCurReadPos))
{
const int iStartPos = iCurReadPos;
if (!findNextSyncEndByte(buffer, iCurReadPos))
break;
iEndPos = iCurReadPos;
parseBsmTelegram(id, buffer.mid(iStartPos + 1, iEndPos - iStartPos - 1));
}
return buffer.mid(iEndPos);
}
void SocketHandler::parseBsmTelegram(int id, const QByteArray &baTele)
{
Telegrams::Telegram *tele = Telegrams::Telegram::telegramFromBytestream(baTele);
if (!tele)
return;
if (tele->telId() != Telegrams::PanTelegramId::ALIVE)
DEBUG_LOG(m_logger) << "Got tele from bsm with id " << id << ": " << tele->print();
switch (tele->telId())
{
case Telegrams::PanTelegramId::ALIVE:
{
Socket *s = m_sockets.value(id);
if (s)
s->gotAlive();
break;
}
case Telegrams::PanTelegramId::REQ_BIT_TIMEOUT:
case Telegrams::PanTelegramId::BIT_TIMEOUT_REPORT:
case Telegrams::PanTelegramId::REQ_SW_VERSION:
case Telegrams::PanTelegramId::CONFIGURATION_SETUP:
case Telegrams::PanTelegramId::REQ_CONFIGURATION:
case Telegrams::PanTelegramId::REQ_TECHNICAL_STATUS:
case Telegrams::PanTelegramId::TECHNICAL_STATUS:
case Telegrams::PanTelegramId::SIGNAL_FLASHLIGHT:
case Telegrams::PanTelegramId::CHOPPED_SIGNAL_FLASH:
break;
case Telegrams::PanTelegramId::CONFIGURATION_REPORT:
// request version
//requestVersion(id);
break;
case Telegrams::PanTelegramId::SW_VERSION_REPORT:
{
Telegrams::PanSwVersionReport *rep = static_cast<Telegrams::PanSwVersionReport *>(tele);
Socket *s = m_sockets.value(id);
if (s)
s->setVersionInformation(rep->m_mainVersion,
rep->m_subVersion,
rep->m_revision,
QString::fromLatin1(rep->m_manufacturer));
break;
}
case Telegrams::PanTelegramId::ER_DIRECT_FIRE:
handleDirectFire(id, static_cast<Telegrams::PanDirectFire *>(tele));
break;
case Telegrams::PanTelegramId::ER_OBSERVER_CONTR:
handleObserverController(id, static_cast<Telegrams::PanObserverController *>(tele));
break;
}
delete tele;
}
bool SocketHandler::requestVersion(int id)
{
DEBUG_LOG(m_logger) << "Requesting version for BSM " << id;
Socket *s = m_sockets.value(id);
if (!s || !s->isConnected())
return false;
Telegrams::PanSwVersionRequest tele;
return s->sendData(tele.toBytestream());
}
void SocketHandler::handleDirectFire(int id, const Telegrams::PanDirectFire *tele)
{
if (!tele)
return;
if (tele->m_ammunitionId == 0)
{
WARNING_LOG(m_logger) << "Got direct fire without valid ammunition - ignoring: " << tele->print();
return;
}
OpticalShot osNew;
osNew.id = id;
osNew.ammunitionId = tele->m_ammunitionId;
osNew.originatorId = tele->m_originatorId;
osNew.deposition1 = tele->m_deposition1;
osNew.deposition2 = tele->m_deposition2;
osNew.timeStampMSec = QDateTime::currentMSecsSinceEpoch();
m_lastShots += osNew;
QTimer::singleShot(500, this, &SocketHandler::handleDirectFireSummray);
}
void SocketHandler::handleDirectFireSummray()
{
DEBUG_LOG(m_logger) << "handleDirectFireSummray m_lastShots.size=" << m_lastShots.size();
OpticalShot osNew;
if ( m_lastShots.size() == 0)
return;
int distance = 3000; // Unrealistisch hohe Distanz
DEBUG_LOG(m_logger) << "distance=" << distance;
for (const OpticalShot &os : qAsConst(m_lastShots))
{
int act_distance = os.deposition1 * os.deposition1 + os.deposition2 * os.deposition2;
DEBUG_LOG(m_logger) << "act_distance=" << act_distance << " BSM-ID=" << os.id
<< " ammunitionId=" << os.ammunitionId;
if ( act_distance < distance)
{
distance = act_distance;
DEBUG_LOG(m_logger) << "distance=" << distance << " BSM-ID=" << os.id;
osNew = os;
}
}
emit opticalShot(QDateTime::currentMSecsSinceEpoch(),
osNew.id,
osNew.originatorId,
osNew.ammunitionId,
osNew.deposition1,
osNew.deposition2);
m_lastShots.clear();
}
void SocketHandler::handleObserverController(int id, const Telegrams::PanObserverController *tele)
{
DamageState damageState = DamageState::Unknown;
if (tele->m_codeNo == 2) // Zerstoerung
damageState = DamageState::Destroyed;
else if (tele->m_codeNo == 4 || tele->m_codeNo == 18 || tele->m_codeNo == 28) // Aktivierung, Reaktivierung
damageState = DamageState::NoDamage;
if (damageState == DamageState::Unknown)
return;
if (m_timerOC.isValid())
{
if (m_timerOC.elapsed() < 500) // < 500ms -> ignore event
return;
}
m_timerOC.start();
emit opticalShotOC(QDateTime::currentMSecsSinceEpoch(),
id,
tele->m_originatorId,
tele->m_ammunitionId,
damageState);
}
bool SocketHandler::findNextSyncStartByte(const QByteArray &buffer, int &iCurReadPos)
{
// Suchen nach s_stx
while (iCurReadPos < buffer.size())
{
const char data = buffer.at(iCurReadPos);
if (data == Telegrams::Telegram::s_stx)
return true;
++iCurReadPos;
}
return false;
}
bool SocketHandler::findNextSyncEndByte(const QByteArray &buffer, int &iCurReadPos)
{
// Suchen nach s_endMark
while (iCurReadPos < buffer.size())
{
const char data = buffer.at(iCurReadPos);
if (data == Telegrams::Telegram::s_etx)
return true;
++iCurReadPos;
}
return false;
}
static inline bool isSameAmmuniton(int a1, int a2)
{
if (a1 == a2 - 1)
return true;
if (a1 == a2)
return true;
if (a1 == a2 + 1)
return true;
return false;
}
static inline bool isSameOriginator(int o1, int o2)
{
if (o1 == o2)
return true;
// o1 == 0 || o2 == 0 is filtered out before
if (o1 == 0)
return true;
if (o2 == 0)
return true;
return false;
}
bool SocketHandler::isSameOpticalShot(const OpticalShot &o1, const OpticalShot &o2)
{
// mehr als 100ms auseinander -> nicht der gleiche Treffer
if (o1.timeStampMSec < o2.timeStampMSec - s_opticalTimeSlot)
return false;
return (isSameAmmuniton(o1.ammunitionId, o2.ammunitionId) &&
isSameOriginator(o1.originatorId, o2.originatorId));
}
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,101 @@
/**
* @RDE_HEADER@
* Handle incoming/outgoing data from/to all BSMs of one building
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-18
*/
#pragma once
#include <QObject>
#include <QMap>
#include <QTimer>
#include <QElapsedTimer>
#include <logger.h>
#include "bsm_socket.h"
#include "bsm_telegrams_base.h"
#include "bsm_types.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class PanDirectFire;
class PanObserverController;
}
class SocketHandler : public QObject
{
Q_OBJECT
public:
explicit SocketHandler(QObject *parent = nullptr);
bool init(const BuildingBsmConfig &bsmConfig);
bool triggerFlashlight(int bsmId, const QString &hostname, int numberOfFlashes, int pauseBetweenFlashesSec);
bool triggerFlashlightPulse(int bsmId, const QString &hostname = QString(),
int numberOfFlashes = 1,
int pauseDuration = 1,
int choppedConfiguration = 10,
int flashDuration = 30);
bool triggerFlashlights(int numberOfFlashes,
int pauseDuration,
int choppedConfiguration,
int flashDuration);
bool getBsmConfiguration(int bsmId);
bool getBsmBitTimeout(int bsmId);
bool getBsmTechnicalStatus(int bsmId);
QVector<BsmState> bsmStates() const;
Q_SIGNALS:
void opticalShot(qint64 timeMSec,
int sensorId,
int originatorId,
int ammunitionId,
int deposition1,
int deposition2);
void opticalShotOC(qint64 timeMSec,
int sensorId,
int originatorId,
int ammunitionId,
DamageState damageState);
void bsmStateChanged(const QVector<BsmState> &bsmStates);
private Q_SLOTS:
void onBsmStateTimerTimeOut();
void onDataAvailable(int id, const QByteArray &data);
void onSocketConnected(int id);
void onSocketDisconnected(int id);
void onCleanupQueue();
void handleDirectFireSummray();
private:
Socket *getSocketForBsm(int bsmId);
Socket *getSocketForBsm(const QString &hostname);
QByteArray parseBuffer(int id, const QByteArray &buffer);
void parseBsmTelegram(int id, const QByteArray &baTele);
bool requestVersion(int id);
void handleDirectFire(int id, const Telegrams::PanDirectFire *tele);
void handleObserverController(int id, const Telegrams::PanObserverController *tele);
static bool findNextSyncStartByte(const QByteArray &buffer, int &iCurReadPos);
static bool findNextSyncEndByte(const QByteArray &buffer, int &iCurReadPos);
static QByteArray substituteData(const QByteArray &data);
static QByteArray desubstituteData(const QByteArray &data);
static bool isSameOpticalShot(const OpticalShot &o1, const OpticalShot &o2);
private:
QMap<int, Socket *> m_sockets;
QMap<int, QByteArray> m_socketData;
QVector<OpticalShot> m_lastShots;
QElapsedTimer m_timerOC;
QTimer m_cleanupQueueTimer;
QTimer m_bsmStateTimer;
NGL::INGLLogger &m_logger;
};
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms Alive
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanAlive : public Telegram
{
public:
PanAlive()
: Telegram(PanTelegramId::ALIVE)
{}
static Telegram *fromBytestream(const QByteArray &data)
{
Q_UNUSED(data)
return new PanAlive;
}
protected:
QByteArray payload() const override
{
return QByteArray();
}
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,279 @@
/**
* @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
@@ -0,0 +1,79 @@
/**
* @RDE_HEADER@
* Oberklasser der BSM-Telegramme
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include <QByteArray>
#include "buildingcontrolbsm_export.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
enum class PanTelegramId
{
ALIVE = 0x08,
REQ_BIT_TIMEOUT = 0x09,
BIT_TIMEOUT_REPORT = 0x0a,
REQ_SW_VERSION = 0x0e,
SW_VERSION_REPORT = 0x0f,
CONFIGURATION_SETUP = 0x20,
REQ_CONFIGURATION = 0x21,
CONFIGURATION_REPORT = 0x22,
ER_DIRECT_FIRE = 0x23,
ER_OBSERVER_CONTR = 0x24,
REQ_TECHNICAL_STATUS = 0x27,
TECHNICAL_STATUS = 0x28,
SIGNAL_FLASHLIGHT = 0x30, // not described in icd
CHOPPED_SIGNAL_FLASH = 0x39,
};
QByteArray toString(PanTelegramId teleId);
class BUILDINGCONTROLBSM_EXPORT Telegram
{
protected:
explicit Telegram(PanTelegramId telId)
: m_telId(telId)
{}
public:
virtual ~Telegram() = default;
virtual QByteArray print() const
{
return toString(m_telId);
}
QByteArray toBytestream() const;
PanTelegramId telId() const
{
return m_telId;
}
static Telegram *telegramFromBytestream(const QByteArray &data_);
static const unsigned char s_stx = 0x02;
static const unsigned char s_etx = 0x03;
static const unsigned char s_subMark = 0x80;
static const unsigned char s_subStx = 0x82;
static const unsigned char s_subEtx = 0x83;
static const unsigned char s_subSub = 0x00;
protected:
virtual QByteArray payload() const = 0;
static unsigned short decode_ushort_little(const QByteArray &data, const int start, bool &bOk);
private:
static unsigned char calcChecksum(const QByteArray &data);
static QByteArray substituteData(const QByteArray &data);
static QByteArray desubstituteData(const QByteArray &data);
PanTelegramId m_telId;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms BitTimeoutReport
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_bit_timeout_report.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanBitTimeoutReport::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n BitTimeout = " + QByteArray::number(m_bitTimeout);
return ret;
}
QByteArray PanBitTimeoutReport::payload() const
{
Q_ASSERT(false);
return QByteArray();
}
Telegram *PanBitTimeoutReport::fromBytestream(const QByteArray &data)
{
if (data.length() < 2)
return nullptr;
bool bOk = true;
PanBitTimeoutReport rep;
rep.m_bitTimeout = decode_ushort_little(data, 0, bOk);
return bOk ? new PanBitTimeoutReport(rep) : nullptr;
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms BitTimeoutReport
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanBitTimeoutReport : public Telegram
{
public:
PanBitTimeoutReport()
: Telegram(PanTelegramId::BIT_TIMEOUT_REPORT)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
unsigned short m_bitTimeout = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanSwVersionRequest
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanBitTimeoutRequest : public Telegram
{
public:
PanBitTimeoutRequest()
: Telegram(PanTelegramId::REQ_BIT_TIMEOUT)
{}
static Telegram *fromBytestream(const QByteArray &data)
{
Q_UNUSED(data);
Q_ASSERT(false);
return new PanBitTimeoutRequest;
}
protected:
QByteArray payload() const override
{
return QByteArray();
}
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,53 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanChoppedSignalFlashlight
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_chopped_signal_flash.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanChoppedSignalFlashlight::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n Number of Flashes = " + QByteArray::number(m_noOfFlashes);
ret += "\n Pause duration = " + QByteArray::number(m_pauseDuration);
ret += "\n Choped Flash configuration = " + QByteArray::number(m_choppedFlashConfig);
ret += "\n Number of Flash Pulses = " + QByteArray::number(m_noOfFlashPulses);
ret += "\n Flash duration = " + QByteArray::number(m_flashDuration);
return ret;
}
QByteArray PanChoppedSignalFlashlight::payload() const
{
QByteArray result;
result.resize(5);
result[0] = m_noOfFlashes;
result[1] = m_pauseDuration;
result[2] = m_choppedFlashConfig;
result[3] = m_noOfFlashPulses;
result[4] = m_flashDuration;
return result;
}
Telegram *PanChoppedSignalFlashlight::fromBytestream(const QByteArray &data)
{
Q_UNUSED(data);
Q_ASSERT(false);
return nullptr;
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanChoppedSignalFlashlight
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanChoppedSignalFlashlight : public Telegram
{
public:
PanChoppedSignalFlashlight()
: Telegram(PanTelegramId::CHOPPED_SIGNAL_FLASH)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
char m_noOfFlashes = 0;
char m_pauseDuration = 0;
char m_choppedFlashConfig = 0;
char m_noOfFlashPulses = 0;
char m_flashDuration = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,56 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanConfigurationReport
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_configuration_report.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanConfigurationReport::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n Reserved1 = " + QByteArray::number(m_reserved1);
ret += "\n ModesOfOperations = " + QByteArray::number(m_modesOfOperations);
ret += "\n AlivePresence = " + QByteArray::number(m_aliveMessage);
ret += "\n Reserved2 = " + QByteArray::number(m_reserved2);
ret += "\n Position = " + QByteArray::number(m_position);
return ret;
}
QByteArray PanConfigurationReport::payload() const
{
Q_ASSERT(false);
return QByteArray();
}
Telegram *PanConfigurationReport::fromBytestream(const QByteArray &data)
{
if (data.length() < 5)
return nullptr;
PanConfigurationReport rep;
rep.m_reserved1 = static_cast<unsigned short>(data[0]);
rep.m_modesOfOperations = static_cast<unsigned short>(data[1]);
rep.m_aliveMessage = static_cast<unsigned short>(data[2]);
rep.m_reserved2 = static_cast<unsigned short>(data[3]);
rep.m_position = static_cast<unsigned short>(data[4]);
// the last 2 bytes are rde specific and not decoded here
return new PanConfigurationReport(rep);
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,40 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanConfigurationReport
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanConfigurationReport : public Telegram
{
public:
PanConfigurationReport()
: Telegram(PanTelegramId::CONFIGURATION_REPORT)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
unsigned short m_reserved1 = 0;
unsigned short m_modesOfOperations = 0;
unsigned short m_aliveMessage = 0;
unsigned short m_reserved2 = 0;
unsigned short m_position = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanSwVersionRequest
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanConfigurationRequest : public Telegram
{
public:
PanConfigurationRequest()
: Telegram(PanTelegramId::REQ_CONFIGURATION)
{}
static Telegram *fromBytestream(const QByteArray &data)
{
Q_UNUSED(data);
Q_ASSERT(false);
return new PanConfigurationRequest;
}
protected:
QByteArray payload() const override
{
return QByteArray();
}
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanConfigurationSetup
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_configuration_setup.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanConfigurationSetup::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n Modes of Operations = " + QByteArray::number(m_modesOfOperations);
ret += "\n Alive message [s] = " + QByteArray::number(m_aliveMessage);
ret += "\n IpsInterval [s] = " + QByteArray::number(m_ipsInterval);
ret += "\n reserved = " + QByteArray::number(m_reserved);
return ret;
}
QByteArray PanConfigurationSetup::payload() const
{
QByteArray result;
result.resize(4);
result[0] = m_modesOfOperations;
result[1] = m_ipsInterval;
result[2] = static_cast<unsigned char>(m_aliveMessage / 10); // 10s
result[3] = m_reserved;
return result;
}
Telegram *PanConfigurationSetup::fromBytestream(const QByteArray &data)
{
Q_UNUSED(data);
Q_ASSERT(false);
return nullptr;
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanConfigurationSetup
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanConfigurationSetup : public Telegram
{
public:
PanConfigurationSetup()
: Telegram(PanTelegramId::CONFIGURATION_SETUP)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
int m_aliveMessage = 0; // in seconds
char m_ipsInterval = 0;
// enable OSAG 2.0
char m_modesOfOperations = 0b00000001;
char m_reserved = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,78 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanErDirectFire
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_direct_fire.h"
#include "logger.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanDirectFire::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n TimeofEvent = " + QByteArray::number(m_timeofEvent);
ret += "\n AmmunitionId = " + QByteArray::number(m_ammunitionId);
ret += "\n Deposition1 = " + QByteArray::number(m_deposition1);
ret += "\n Deposition2 = " + QByteArray::number(m_deposition2);
ret += "\n NumberOpticalPulses = " + QByteArray::number(m_numberOpticalPulses);
ret += "\n IDNumberOriginator = " + QByteArray::number(m_originatorId);
ret += "\n DetectorNo = " + QByteArray::number(m_detectorNo);
ret += "\n AmmunitionChildCode = " + QByteArray::number(m_ammunitionChildCode);
return ret;
}
QByteArray PanDirectFire::payload() const
{
Q_ASSERT(false);
return QByteArray();
}
Telegram *PanDirectFire::fromBytestream(const QByteArray &data)
{
NGL::INGLLogger &logger = getLogger("PanDirectFire");
DEBUG_LOG(logger) << "data.length=" << data.length();
if (data.length() < 9)
return nullptr;
bool bOk = true;
PanDirectFire rep;
rep.m_timeofEvent = decode_ushort_little(data, 0, bOk);
rep.m_ammunitionId = decode_ushort_little(data, 2, bOk);
if (data.length() == 9)
{
rep.m_deposition1 = static_cast<short>(data[3]);
rep.m_deposition2 = static_cast<short>(data[4]);
rep.m_numberOpticalPulses = static_cast<unsigned short>(data[5]);
rep.m_originatorId = decode_ushort_little(data, 6, bOk);
rep.m_detectorNo = static_cast<unsigned short>(data[8] & 0xFF);
}
else
{
rep.m_deposition1 = static_cast<short>(data[4]);
rep.m_deposition2 = static_cast<short>(data[5]);
rep.m_numberOpticalPulses = static_cast<unsigned short>(data[6]);
rep.m_originatorId = decode_ushort_little(data, 7, bOk);
rep.m_detectorNo = static_cast<unsigned short>(data[9] & 0xFF);
}
// optional
if (data.length() >= 12)
rep.m_ammunitionChildCode = decode_ushort_little(data, 10, bOk);
return bOk ? new PanDirectFire(rep) : nullptr;
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,44 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanErDirectFire
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
#include <QObject>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanDirectFire : public Telegram
{
public:
PanDirectFire()
: Telegram(PanTelegramId::ER_DIRECT_FIRE)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
short m_timeofEvent = 0;
unsigned short m_ammunitionId = 0;
short m_deposition1 = 0;
short m_deposition2 = 0;
unsigned short m_numberOpticalPulses = 0;
unsigned short m_originatorId = 0;
unsigned short m_detectorNo = 0;
unsigned short m_ammunitionChildCode = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,93 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanObserverController
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_observer_controller.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanObserverController::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n TimeofEvent = " + QByteArray::number(m_timeofEvent);
ret += "\n AmmunitionId = " + QByteArray::number(m_ammunitionId);
switch (m_ammunitionId)
{
case 208:
ret += " (Observer/Controller)";
break;
case 209:
ret += " (Medical Gun)";
break;
case 210:
ret += " (Logistic Gun)";
break;
case 211:
ret += " (Configuration Tool)";
break;
default:
break;
}
ret += "\n Code Number = " + QByteArray::number(m_codeNo);
ret += "\n Detector Number = " + QByteArray::number(m_detectorNo);
switch (m_codeNo)
{
case 1:
ret += " (Test)";
break;
case 2:
ret += " (Zerstoerung, Ausfall)";
break;
case 4:
ret += " (Aktivierung)";
break;
case 18:
ret += " (Reaktivierung)";
break;
default:
break;
}
ret += "\n ID Originator = " + QByteArray::number(m_originatorId);
return ret;
}
QByteArray PanObserverController::payload() const
{
Q_ASSERT(false);
return QByteArray();
}
Telegram *PanObserverController::fromBytestream(const QByteArray &data)
{
if (data.length() < 6)
return nullptr;
bool bOk = true;
PanObserverController rep;
rep.m_timeofEvent = decode_ushort_little(data, 0, bOk);
rep.m_ammunitionId = static_cast<unsigned short>(data[2] & 0xFF);
rep.m_codeNo = static_cast<unsigned short>(data[3] & 0xFF);
rep.m_detectorNo = static_cast<unsigned short>(data[4] & 0xFF);
rep.m_originatorId = decode_ushort_little(data, 5, bOk);
return bOk ? new PanObserverController(rep) : nullptr;
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,40 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanObserverController
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanObserverController : public Telegram
{
public:
PanObserverController()
: Telegram(PanTelegramId::ER_OBSERVER_CONTR)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
unsigned short m_timeofEvent = 0;
unsigned short m_ammunitionId = 0;
unsigned short m_codeNo = 0;
unsigned short m_detectorNo = 0;
unsigned short m_originatorId = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,61 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms SwVersionReport
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_sw_version_report.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanSwVersionReport::print() const
{
QByteArray ret = Telegram::print() ;
ret += "\n mainVersion = " + QByteArray::number(m_mainVersion);
ret += "\n subVersion = " + QByteArray::number(m_subVersion);
ret += "\n revision = " + QByteArray::number(m_revision);
ret += "\n manufacturer = " + m_manufacturer;
return ret;
}
QByteArray PanSwVersionReport::payload() const
{
Q_ASSERT(false);
return QByteArray();
}
Telegram *PanSwVersionReport::fromBytestream(const QByteArray &data)
{
if (data.length() < 4)
return nullptr;
PanSwVersionReport rep;
unsigned short version = (unsigned short)data.at(0);
version <<= 8;
version |= (unsigned short)(data.at(1));
// highest 4 bits
rep.m_mainVersion = (version & 0xF000) >> 12;
// next 7 bits
rep.m_subVersion = (version & 0x0FE0) >> 5;
// last 5 bits
rep.m_revision = (version & 0x001F); // not used as letter
rep.m_manufacturer = data.mid(2, 8);
return new PanSwVersionReport(rep);
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,40 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms SwVersionReport
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanSwVersionReport : public Telegram
{
public:
PanSwVersionReport()
: Telegram(PanTelegramId::SW_VERSION_REPORT)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
QByteArray m_manufacturer;
int m_mainVersion = 0;
int m_subVersion = 0;
int m_revision = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanSwVersionRequest
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanSwVersionRequest : public Telegram
{
public:
PanSwVersionRequest()
: Telegram(PanTelegramId::REQ_SW_VERSION)
{}
static Telegram *fromBytestream(const QByteArray &data)
{
Q_UNUSED(data);
Q_ASSERT(false);
return new PanSwVersionRequest;
}
protected:
QByteArray payload() const override
{
return QByteArray();
}
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,73 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanTechnicalStatus
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include "bsm_telegrams_technical_status.h"
#include <QStringBuilder>
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
QByteArray PanTechnicalStatus::print() const
{
QByteArray ret = Telegram::print() ;
unsigned short first = m_failures;
unsigned short failRFComm = (first & 0x80) >> 7;
unsigned short failRAM = (first & 0x40) >> 6;
unsigned short failFlashRom = (first & 0x20) >> 5;
unsigned short batteryLow = (first & 0x10) >> 4;
unsigned short batteryEol = (first & 0x8) >> 3;
unsigned short optical = (first & 0x4) >> 2;
unsigned short flashlight = (first & 0x2) >> 1;
ret += "\n TimeofEvent = " + QByteArray::number(m_timeofEvent);
ret += "\n Failures = " + QByteArray::number(m_failures);
ret += "\n FailRFComm = " + QByteArray::number(failRFComm);
ret += "\n FailRAM = " + QByteArray::number(failRAM);
ret += "\n FailROM = " + QByteArray::number(failFlashRom);
ret += "\n MCBattery = " + QByteArray::number(batteryLow);
ret += "\n OSBattery = " + QByteArray::number(batteryEol);
ret += "\n Optical = " + QByteArray::number(optical);
ret += "\n Flashlight = " + QByteArray::number(flashlight);
ret += "\n RFCommCRCErrorCount = " + QByteArray::number(m_rfCommCRCErrorCount);
ret += "\n LostBeaconsCount = " + QByteArray::number(m_lostBeaconsCount);
ret += "\n DetectorNo = " + QByteArray::number(m_detectorNo);
return ret;
}
QByteArray PanTechnicalStatus::payload() const
{
Q_ASSERT(false);
return QByteArray();
}
Telegram *PanTechnicalStatus::fromBytestream(const QByteArray &data)
{
if (data.length() < 6)
return nullptr;
bool bOk = true;
PanTechnicalStatus rep;
rep.m_timeofEvent = decode_ushort_little(data, 0, bOk);
rep.m_failures = static_cast<unsigned short>(data[2] & 0xFF);
rep.m_rfCommCRCErrorCount = static_cast<unsigned short>(data[3] & 0xFF);
rep.m_lostBeaconsCount = static_cast<unsigned short>(data[4] & 0xFF);
rep.m_detectorNo = static_cast<unsigned short>(data[5] & 0xFF);
return bOk ? new PanTechnicalStatus(rep) : nullptr;
}
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanTechnicalStatus
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanTechnicalStatus : public Telegram
{
public:
PanTechnicalStatus()
: Telegram(PanTelegramId::TECHNICAL_STATUS)
{}
QByteArray print() const override;
static Telegram *fromBytestream(const QByteArray &data);
unsigned short m_timeofEvent = 0;
unsigned short m_failures = 0;
unsigned short m_rfCommCRCErrorCount = 0;
unsigned short m_lostBeaconsCount = 0;
unsigned short m_detectorNo = 0;
protected:
QByteArray payload() const override;
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Definition des PAN-Telegramms PanSwVersionRequest
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#pragma once
#include "bsm_telegrams_base.h"
namespace BuildingControlUnit
{
namespace BSM
{
namespace Telegrams
{
class BUILDINGCONTROLBSM_EXPORT PanTechnicalStatusRequest : public Telegram
{
public:
PanTechnicalStatusRequest()
: Telegram(PanTelegramId::REQ_TECHNICAL_STATUS)
{}
static Telegram *fromBytestream(const QByteArray &data)
{
Q_UNUSED(data);
Q_ASSERT(false);
return new PanTechnicalStatusRequest;
}
protected:
QByteArray payload() const override
{
return QByteArray();
}
};
} // namespace Telegrams
} // namespace BSM
} // namespace BuildingControlUnit
@@ -0,0 +1,34 @@
/**
* @RDE_HEADER@
* Kleines Testprogramm für BSMs
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
*/
#include <nglapplication/nglcoreapplication.h>
#include <QVector>
#include "bsm_api.h"
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
app.createLogger("BCU", -1);
BuildingControlUnit::BuildingBsmConfig config;
BuildingControlUnit::Bsm c;
c.id = 42;
//c.hostname = QStringLiteral("192.168.133.177");
c.hostname = QStringLiteral("localhost");
c.port = 10001;
config.bsmMap.insert(c.id, c);
BuildingControlUnit::BSM::Api *a = new BuildingControlUnit::BSM::Api;
int ret = -1;
if (a->init(config))
ret = app.exec();
delete a;
return ret;
}
+44
View File
@@ -0,0 +1,44 @@
/**
* @RDE_HEADER@
* Api for BSM access
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-01-26
*/
#pragma once
#include <QString>
#include <bcu_types.h>
namespace BuildingControlUnit
{
namespace BSM
{
enum FlashState
{
Off,
On
};
struct OpticalShot
{
int id = 0;
int ammunitionId = 0;
int originatorId = 0;
int deposition1 = 0;
int deposition2 = 0;
int64_t timeStampMSec = 0;
};
struct BsmState : public BuildingControlUnit::Bsm
{
QString versionInfo;
bool bConnected = false;
explicit BsmState(const BuildingControlUnit::Bsm &c = BuildingControlUnit::Bsm())
: BuildingControlUnit::Bsm(c)
{}
};
} // namespace BSM
} // namespace BuildingControlUnit