#include "MainWindow.h" #include "ui_MainWindow.h" #include "rt8016AdcDgr.h" #include #include #include #include #include #include #if defined(__linux__) #include #else #include #endif #include #include #include MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , dateTimeTimer_(new QTimer(this)) , canStatusTimer_(new QTimer(this)) , lastPackageDateTime_(QDateTime::fromMSecsSinceEpoch(0)) { ui->setupUi(this); setupDrivers(); setupTables(); auto& backend = Backend::instance(); connect(backend.getTrace(), &CanTrace::messageEnqueued, this, &MainWindow::handlePackage); dateTimeTimer_->start(1000); connect(dateTimeTimer_, &QTimer::timeout, this, &MainWindow::updateDateTime); canStatusTimer_->start(1000); connect(canStatusTimer_, &QTimer::timeout, this, &MainWindow::updateCanStatus); updateDateTime(); connectCan(); } MainWindow::~MainWindow() { disconnectCan(); delete ui; } void MainWindow::connectCan() { auto& backend = Backend::instance(); backend.clearTrace(); backend.startMeasurement(); QTimer::singleShot(100, this, [this]{ updateCanStatus(); }); // for (const auto interfaceId: backend.getInterfaceList()) // { // log_info(backend.getInterfaceById(interfaceId)->getName()); // } // MeasurementSetup new_setup(&backend); // new_setup.cloneFrom(backend.getSetup()); // auto setupDlg = new SetupDialog(Backend::instance(), 0); // if (setupDlg->showSetupDialog(new_setup)) { // auto& backend = Backend::instance(); // for (const auto interfaceId: backend.getInterfaceList()) // { // log_info(backend.getInterfaceById(interfaceId)->getName()); // } // backend.setSetup(new_setup); // backend.clearTrace(); // backend.startMeasurement(); // } } void MainWindow::disconnectCan() { Backend::instance().stopMeasurement(); } void MainWindow::handlePackage(int index) { log_info("Received message: " + QString::number(index)); lastPackageDateTime_ = QDateTime::currentDateTime(); auto& backend = Backend::instance(); auto message = backend.getTrace()->getMessage(index); if (!message) { return; } if (message->getId() != 0x60) { return; } quint16 frequency = ((message->getByte(1) << 8) + message->getByte(0)) & 0x7FFF; quint8 sign = ((message->getByte(1) & 0x80) >> 7); double frequencyValue = (sign ? -1 : 1) * frequency; frequencyValue /= 128; parameterModel_->setItem(1, 1, new QStandardItem(QString::number(frequencyValue, 'f', 2))); quint16 inputVoltage = (message->getByte(2) << 2) + ((message->getByte(7) & 0x03) >> 0); inputVoltage /= 1.137; parameterModel_->setItem(0, 1, new QStandardItem(QString::number(inputVoltage))); quint16 coolantTemperatureIndex = (message->getByte(4) << 2) + ((message->getByte(7) & 0x30) >> 4); if (coolantTemperatureIndex > 1023) { coolantTemperatureIndex = 0; } coolantTemperatureIndex = coolantTemperatureIndex << 2; qint16 coolantTemperature = adcToTemperature(coolantTemperatureIndex); parameterModel_->setItem(5, 1, new QStandardItem(QString::number(coolantTemperature))); quint16 outputPhaseCurrent = (message->getByte(3) << 2) + ((message->getByte(7) & 0x0C) >> 2); outputPhaseCurrent /= 3.1; quint8 phaseNumber = ((message->getByte(7) & 0xC0) >> 6); switch (phaseNumber) { case 0x00: parameterModel_->setItem(2, 1, new QStandardItem(QString::number(outputPhaseCurrent))); break; case 0x01: parameterModel_->setItem(3, 1, new QStandardItem(QString::number(outputPhaseCurrent))); break; case 0x02: parameterModel_->setItem(4, 1, new QStandardItem(QString::number(outputPhaseCurrent))); break; default: break; } auto status = message->getByte(5); if (status != lastStatus_) { lastStatus_ = status; statusModel_->appendRow({new QStandardItem(message->getDateTime().toString("dd.MM.yyyy hh:mm:ss")), new QStandardItem(statusToString(status)), new QStandardItem(statusToDescription(status))}); } } void MainWindow::updateDateTime() { const auto currentDateTime = QDateTime::currentDateTime(); ui->dateLabel->setText(currentDateTime.toString("dd.MM.yyyy")); ui->timeLabel->setText(currentDateTime.toString("hh:mm:ss")); } void MainWindow::updateCanStatus() { // auto isConnected = false; // auto& backend = Backend::instance(); // for (const auto interfaceId: backend.getInterfaceList()) // { // isConnected |= backend.getInterfaceById(interfaceId)->isOpen(); // } auto isConnected = lastPackageDateTime_.msecsTo(QDateTime::currentDateTime()) < 5000; auto pallette = QPalette(); auto color = QColor(isConnected ? Qt::darkGreen : Qt::darkRed); color.setAlphaF(0.7); pallette.setColor(QPalette::Window, color); ui->titleLabel->setAutoFillBackground(true); ui->titleLabel->setPalette(pallette); } void MainWindow::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 MainWindow::setupTables() { parameterModel_ = new QStandardItemModel(6, 2, this); statusModel_ = new QStandardItemModel(0, 3, this); parameterModel_->setHorizontalHeaderLabels({tr("Parameter"), tr("Value")}); statusModel_->setHorizontalHeaderLabels({tr("Time"), tr("Module status"), tr("Module status description")}); parameterModel_->setItem(0, 0, new QStandardItem(tr("Input voltage, V"))); parameterModel_->setItem(1, 0, new QStandardItem(tr("Input voltage frequency, Hz"))); parameterModel_->setItem(2, 0, new QStandardItem(tr("Phase A input current, A"))); parameterModel_->setItem(3, 0, new QStandardItem(tr("Phase B input current, A"))); parameterModel_->setItem(4, 0, new QStandardItem(tr("Phase C input current, A"))); parameterModel_->setItem(5, 0, new QStandardItem(tr("Coolant temperature, °C"))); ui->parameterTableView->setModel(parameterModel_); ui->statusTableView->setModel(statusModel_); ui->parameterTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->statusTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->parameterTableView->horizontalHeader()->setStretchLastSection(true); ui->statusTableView->horizontalHeader()->setStretchLastSection(true); ui->parameterTableView->verticalHeader()->hide(); ui->parameterTableView->setColumnWidth(0, 280); ui->statusTableView->setColumnWidth(0, 150); } QString MainWindow::statusToString(quint8 status) { return "0x" + QString::number(status, 16).rightJustified(2, '0'); } QString MainWindow::statusToDescription(quint8 status) { QString description; status &= 0x7F; switch (status) { case 0x00: description = tr("Supply voltage 110[V] to the control circuit"); break; case 0x01: description = tr("Pause after blocking"); break; case 0x03: description = tr("Waiting for the required DC link voltage level. 670[V]. Input voltage"); break; case 0x04: description = tr("Waiting for a CAN command to start work"); break; case 0x07: description = tr("Normal operation"); break; case 0x08: description = tr("Normal operation with output current limitation"); break; case 0x10: description = tr("DC link overvoltage. Input voltage"); break; case 0x11: description = tr("Fault half bridge 1"); break; case 0x12: description = tr("Fault half bridge 2"); break; case 0x14: description = tr("Fault half bridge 3"); break; case 0x18: description = tr("Cooler overheating"); break; case 0x21: description = tr("Instantaneous total current fault (270 A)"); break; case 0x22: description = tr("Large total current for 15 seconds (200 A)"); break; case 0x27: description = tr("Instant current fault in one of the phases (396 A)"); break; case 0x25: description = tr("No incoming messages via CAN"); break; default: description = tr("Unknown status"); break; } return description; } qint16 MainWindow::adcToTemperature(quint16 adc) { const double vref = 2.5; // Напряжение опорное const double vin = 5.0; // Входное напряжение const double r = 10; // Сопротивление резистора в КилоОмах (например, 10kΩ) // Преобразуем значение АЦП в выходное напряжение double vout = (adc / 4095.0) * vref; // Проверяем, чтобы Vout не было равно Vin if (vout >= vin) { return -100; // Ошибка: Vout не может быть больше или равно Vin } // Вычисляем сопротивление термистора double r_ntc = r * (vout / (vin - vout)); QList> temp_table = { {-55, 96.3}, {-50, 67.01}, {-45, 47.17}, {-40, 33.65}, {-35, 24.26}, {-30, 17.7}, {-25, 13.04}, {-20, 9.707}, {-15, 7.293}, {-10, 5.533}, {-5, 4.232}, {0, 3.265}, {5, 2.539}, {10, 1.99}, {15, 1.571}, {20, 1.249}, {25, 1.0}, {30, 0.8057}, {35, 0.6531}, {40, 0.5327}, {45, 0.4369}, {50, 0.3603}, {55, 0.2986}, {60, 0.2488}, {65, 0.2083}, {70, 0.1752}, {75, 0.1481}, {80, 0.1258}, {85, 0.1072}, {90, 0.09177}, {95, 0.07885}, {100, 0.068}, {105, 0.05886}, {110, 0.05112}, {115, 0.04454}, {120, 0.03893}, {125, 0.03417}, {130, 0.03009}, {135, 0.02654}, {140, 0.02348}, {145, 0.02083}, {150, 0.01853}, {155, 0.01653}, }; for (qsizetype i = 0; i < temp_table.size() - 1; i++) { if (r_ntc <= temp_table[i].second && r_ntc >= temp_table[i + 1].second) { return temp_table[i].first + (temp_table[i + 1].first - temp_table[i].first) * (r_ntc - temp_table[i].second) / (temp_table[i + 1].second - temp_table[i].second); } } return -101; }