#include "CanController.h" #include #include #include #include #include #include #include #include #if defined(__linux__) #include #else #include #endif #include #include #include #include #include #include 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 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)); }