306 lines
8.7 KiB
C++
306 lines
8.7 KiB
C++
#include "CanController.h"
|
|
|
|
#include <core/MeasurementSetup.h>
|
|
#include <core/MeasurementNetwork.h>
|
|
#include <core/MeasurementInterface.h>
|
|
#include <core/CanTrace.h>
|
|
#include <core/Log.h>
|
|
|
|
#include <driver/CanInterface.h>
|
|
#include <driver/SLCANDriver/SLCANDriver.h>
|
|
#include <driver/CANBlastDriver/CANBlasterDriver.h>
|
|
|
|
#if defined(__linux__)
|
|
#include <driver/SocketCanDriver/SocketCanDriver.h>
|
|
#else
|
|
#include <driver/CandleApiDriver/CandleApiDriver.h>
|
|
#endif
|
|
|
|
#include <window/SetupDialog/SetupDialog.h>
|
|
|
|
#include <QDateTime>
|
|
#include <QDebug>
|
|
#include <QTimer>
|
|
#include <QSettings>
|
|
#include <QRandomGenerator>
|
|
|
|
CanController::CanController(QObject* parent)
|
|
: QObject{parent}
|
|
, lastPackageDateTime_(QDateTime::fromMSecsSinceEpoch(0))
|
|
, reconnectTimer_(new QTimer(this))
|
|
{
|
|
setupDrivers();
|
|
setupDefaultParameters();
|
|
|
|
auto& backend = Backend::instance();
|
|
connect(backend.getTrace(), &CanTrace::messageEnqueued, this, &CanController::handlePackage);
|
|
|
|
QSettings settings("settings.ini", QSettings::IniFormat);
|
|
|
|
const auto sendParametersTimer = new QTimer(this);
|
|
const auto sendParametersTimeout = settings.value("sendParametersTimeout", 50).toInt();
|
|
sendParametersTimer->start(sendParametersTimeout);
|
|
connect(sendParametersTimer, &QTimer::timeout, this, &CanController::sendParameters);
|
|
|
|
const auto sendVkuClosureTimer = new QTimer(this);
|
|
const auto sendVkuClosureTimeout = settings.value("sendVkuClosureTimeout", 50).toInt();
|
|
sendVkuClosureTimer->start(sendVkuClosureTimeout);
|
|
connect(sendVkuClosureTimer, &QTimer::timeout, this, &CanController::sendVkuClosure);
|
|
|
|
const auto updateCanStatusTimer = new QTimer(this);
|
|
updateCanStatusTimer->start(1000);
|
|
connect(updateCanStatusTimer, &QTimer::timeout, this, &CanController::updateCanStatus);
|
|
|
|
reconnectTimer_->start(5000);
|
|
connect(reconnectTimer_, &QTimer::timeout, this, &CanController::tryConnectCan);
|
|
|
|
// auto statusTimer = new QTimer(this);
|
|
// statusTimer->start(1000);
|
|
// statusTimer->callOnTimeout([this]
|
|
// {
|
|
// showStatus(QRandomGenerator::global()->generate());
|
|
// });
|
|
|
|
QTimer::singleShot(0, this, &CanController::connectCan);
|
|
}
|
|
|
|
CanController::~CanController()
|
|
{
|
|
}
|
|
|
|
QObject* CanController::qmlInstance(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/)
|
|
{
|
|
return new CanController;
|
|
}
|
|
|
|
void CanController::connectCan()
|
|
{
|
|
auto& backend = Backend::instance();
|
|
backend.clearTrace();
|
|
|
|
QSettings settings("settings.ini", QSettings::IniFormat);
|
|
auto bitrate = settings.value("bitrate", 100000).toInt();
|
|
|
|
for (auto* network: backend.getSetup().getNetworks())
|
|
{
|
|
for (auto* mi: network->interfaces())
|
|
{
|
|
mi->setBitrate(bitrate);
|
|
}
|
|
}
|
|
|
|
backend.startMeasurement();
|
|
|
|
QTimer::singleShot(150, this, [this]{ updateCanStatus(); });
|
|
}
|
|
|
|
void CanController::disconnectCan()
|
|
{
|
|
Backend::instance().stopMeasurement();
|
|
}
|
|
|
|
void CanController::tryConnectCan()
|
|
{
|
|
if (!isConnected_)
|
|
{
|
|
connectCan();
|
|
}
|
|
}
|
|
|
|
void CanController::switchVkuClosure()
|
|
{
|
|
setProperty("isVkuClosed", !isVkuClosed_);
|
|
sendVkuClosure();
|
|
}
|
|
|
|
void CanController::emergencyReset()
|
|
{
|
|
CanMessage message(0x201);
|
|
message.setLength(8);
|
|
message.setByte(0, 0x02);
|
|
|
|
auto& backend = Backend::instance();
|
|
for (const auto interfaceId: backend.getInterfaceList())
|
|
{
|
|
auto interface = backend.getInterfaceById(interfaceId);
|
|
if (interface)
|
|
{
|
|
interface->sendMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CanController::sendParameters()
|
|
{
|
|
CanMessage message(0x202);
|
|
message.setLength(8);
|
|
|
|
const auto maximumCurrent = maximumCurrent_.toUInt();
|
|
message.setByte(0, maximumCurrent & 0xFF);
|
|
|
|
const auto breakingDelay = breakingDelay_.toUInt();
|
|
message.setByte(1, (breakingDelay >> 8) & 0xFF);
|
|
message.setByte(2, breakingDelay & 0xFF);
|
|
|
|
const auto breakingCurrent = breakingCurrent_.toUInt();
|
|
message.setByte(3, breakingCurrent & 0xFF);
|
|
|
|
const auto emergencyDelay = qRound(emergencyDelay_.toDouble() * 2.0);
|
|
message.setByte(4, emergencyDelay & 0xFF);
|
|
|
|
const auto retriesAfterEmergencyBreak = retriesAfterEmergencyBreak_.toUInt();
|
|
message.setByte(5, retriesAfterEmergencyBreak & 0xFF);
|
|
|
|
// qDebug() << "Sending parameters: " << maximumCurrent;
|
|
|
|
auto& backend = Backend::instance();
|
|
for (const auto interfaceId: backend.getInterfaceList())
|
|
{
|
|
auto interface = backend.getInterfaceById(interfaceId);
|
|
if (interface)
|
|
{
|
|
interface->sendMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CanController::sendVkuClosure()
|
|
{
|
|
CanMessage message(0x201);
|
|
message.setLength(8);
|
|
message.setByte(0, isVkuClosed_ ? 0x01 : 0x00);
|
|
|
|
auto& backend = Backend::instance();
|
|
for (const auto interfaceId: backend.getInterfaceList())
|
|
{
|
|
auto interface = backend.getInterfaceById(interfaceId);
|
|
if (interface)
|
|
{
|
|
interface->sendMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CanController::handlePackage(int index)
|
|
{
|
|
lastPackageDateTime_ = QDateTime::currentDateTime();
|
|
if (isFirstCheck_)
|
|
{
|
|
updateCanStatus();
|
|
}
|
|
|
|
auto& backend = Backend::instance();
|
|
auto message = backend.getTrace()->getMessage(index);
|
|
if (!message)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (message->getId() == 0x501)
|
|
{
|
|
handleCurrentState(message);
|
|
}
|
|
|
|
if (message->getId() == 0x502)
|
|
{
|
|
handleStatus(message);
|
|
}
|
|
}
|
|
|
|
void CanController::handleCurrentState(const CanMessage* message)
|
|
{
|
|
quint16 inputVoltage = (message->getByte(0) << 8) + message->getByte(1);
|
|
setProperty("inputVoltage", QString::number(inputVoltage));
|
|
|
|
quint16 outputVoltage = (message->getByte(2) << 8) + message->getByte(3);
|
|
setProperty("outputVoltage", QString::number(outputVoltage));
|
|
|
|
quint8 inputCurrent = message->getByte(4);
|
|
setProperty("inputCurrent", QString::number(inputCurrent));
|
|
|
|
qint16 radiatorTemperature = (message->getByte(5) << 8) + message->getByte(6);
|
|
setProperty("radiatorTemperature", QString::number(radiatorTemperature));
|
|
}
|
|
|
|
void CanController::handleStatus(const CanMessage* message)
|
|
{
|
|
quint8 status = message->getByte(0);
|
|
showStatus(status);
|
|
|
|
quint8 emergencyCounter = message->getByte(1);
|
|
setProperty("emergencyCounter", QString::number(emergencyCounter));
|
|
|
|
// bool isVkuClosed = (message->getByte(2) & 0x1) == 1;
|
|
// setProperty("isVkuClosed", isVkuClosed);
|
|
}
|
|
|
|
void CanController::showStatus(quint32 status)
|
|
{
|
|
QMap<quint32, QString> statusDescriptionMap =
|
|
{
|
|
{0x00, tr("Emergency reset")},
|
|
{0x01, tr("No incoming messages via CAN interface")},
|
|
{0x02, tr("Pause after breaking")},
|
|
{0x03, tr("Pause after emergency")},
|
|
{0x04, tr("Waiting for command for closure")},
|
|
{0x05, tr("VKU is closed")},
|
|
{0x18, tr("Exceeding radiator temperature")},
|
|
{0x20, tr("Exceeding input voltage")},
|
|
{0x21, tr("Fault signal")},
|
|
{0x22, tr("Exceeding maximum current")},
|
|
{0x23, tr("Exceeding switching current")},
|
|
{0x25, tr("Voltage 5V is not normal")},
|
|
{0x80, tr("Blocking due to emergency")},
|
|
{0x0100, tr("Can connected")},
|
|
{0x0200, tr("Can disconnected")},
|
|
};
|
|
|
|
auto statusDescription = statusDescriptionMap.value(status, tr("Unknown status"));
|
|
|
|
QVariantMap statusMap;
|
|
statusMap.insert("time", QDateTime::currentDateTime().toString());
|
|
statusMap.insert("status", "0x" + QString::number(status, 16).toUpper().rightJustified(2, '0'));
|
|
statusMap.insert("description", statusDescription);
|
|
|
|
if (statuses_.isEmpty() || statuses_.first().toMap()["status"] != statusMap["status"])
|
|
{
|
|
statuses_.prepend(statusMap);
|
|
emit statusesChanged();
|
|
}
|
|
}
|
|
|
|
void CanController::updateCanStatus()
|
|
{
|
|
auto isConnected = lastPackageDateTime_.msecsTo(QDateTime::currentDateTime()) < 2000;
|
|
if (isConnected_ != isConnected || isFirstCheck_)
|
|
{
|
|
isConnected_ = isConnected;
|
|
isFirstCheck_ = false;
|
|
showStatus(isConnected ? 0x0100 : 0x0200);
|
|
}
|
|
}
|
|
|
|
void CanController::setupDrivers()
|
|
{
|
|
auto& backend = Backend::instance();
|
|
|
|
#if defined(__linux__)
|
|
backend.addCanDriver(*(new SocketCanDriver(backend)));
|
|
#else
|
|
backend.addCanDriver(*(new CandleApiDriver(backend)));
|
|
#endif
|
|
// backend.addCanDriver(*(new SLCANDriver(backend)));
|
|
// backend.addCanDriver(*(new CANBlasterDriver(backend)));
|
|
|
|
backend.setDefaultSetup();
|
|
}
|
|
|
|
void CanController::setupDefaultParameters()
|
|
{
|
|
setProperty("maximumCurrent", QString::number(95));
|
|
setProperty("emergencyDelay", QString::number(2));
|
|
setProperty("breakingDelay", QString::number(0));
|
|
setProperty("retriesAfterEmergencyBreak", QString::number(2));
|
|
setProperty("breakingCurrent", QString::number(100));
|
|
}
|