mainwindow.cpp Example File | Qt Serial Bus 5.6

Qt Documentation (Technology Preview) | Qt Serial Bus | CAN Bus example | mainwindow.cpp Example File

Qt 5.6.2 Reference Documentation

# mainwindow.cpp Example File

can/mainwindow.cpp

      /****************************************************************************
      **
      ** Copyright (C) 2015 The Qt Company Ltd.
      ** Contact: http://www.qt.io/licensing/
      **
      ** This file is part of the examples of the QtSerialBus module.
      **
      ** $QT_BEGIN_LICENSE:BSD$
      ** You may use this file under the terms of the BSD license as follows:
      **
      ** "Redistribution and use in source and binary forms, with or without
      ** modification, are permitted provided that the following conditions are
      ** met:
      **   * Redistributions of source code must retain the above copyright
      **     notice, this list of conditions and the following disclaimer.
      **   * Redistributions in binary form must reproduce the above copyright
      **     notice, this list of conditions and the following disclaimer in
      **     the documentation and/or other materials provided with the
      **     distribution.
      **   * Neither the name of The Qt Company Ltd nor the names of its
      **     contributors may be used to endorse or promote products derived
      **     from this software without specific prior written permission.
      **
      **
      ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
      **
      ** $QT_END_LICENSE$
      **
      ****************************************************************************/

      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      #include "connectdialog.h"

      #include <QCanBusFrame>
      #include <QCanBus>
      #include <QCloseEvent>
      #include <QTimer>

      #include <QtCore/qbytearray.h>
      #include <QtCore/qvariant.h>
      #include <QtCore/qdebug.h>

      MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          m_ui(new Ui::MainWindow),
          m_canDevice(nullptr)
      {
          m_ui->setupUi(this);

          m_connectDialog = new ConnectDialog;

          m_status = new QLabel;
          m_ui->statusBar->addWidget(m_status);

          m_ui->sendMessagesBox->setEnabled(false);

          initActionsConnections();
          QTimer::singleShot(50, m_connectDialog, &ConnectDialog::show);

          connect(m_ui->sendButton, &QPushButton::clicked, this, &MainWindow::sendMessage);
      }

      MainWindow::~MainWindow()
      {
          delete m_canDevice;

          delete m_connectDialog;
          delete m_ui;
      }

      void MainWindow::showStatusMessage(const QString &message)
      {
          m_status->setText(message);
      }

      void MainWindow::initActionsConnections()
      {
          m_ui->actionConnect->setEnabled(true);
          m_ui->actionDisconnect->setEnabled(false);
          m_ui->actionQuit->setEnabled(true);

          connect(m_ui->actionConnect, &QAction::triggered, m_connectDialog, &ConnectDialog::show);
          connect(m_connectDialog, &QDialog::accepted, this, &MainWindow::connectDevice);
          connect(m_ui->actionDisconnect, &QAction::triggered, this, &MainWindow::disconnectDevice);
          connect(m_ui->actionQuit, &QAction::triggered, this, &QWidget::close);
          connect(m_ui->actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
      }

      void MainWindow::receiveError(QCanBusDevice::CanBusError error) const
      {
          switch (error) {
          case QCanBusDevice::ReadError:
          case QCanBusDevice::WriteError:
          case QCanBusDevice::ConnectionError:
          case QCanBusDevice::ConfigurationError:
          case QCanBusDevice::UnknownError:
              qWarning() << m_canDevice->errorString();
          default:
              break;
          }
      }

      void MainWindow::connectDevice()
      {
          const ConnectDialog::Settings p = m_connectDialog->settings();

          m_canDevice = QCanBus::instance()->createDevice(p.backendName.toLocal8Bit(), p.deviceInterfaceName);
          if (!m_canDevice) {
              showStatusMessage(tr("Error creating device: %1").arg(p.backendName));
              return;
          }

          connect(m_canDevice, &QCanBusDevice::errorOccurred,
                  this, &MainWindow::receiveError);
          connect(m_canDevice, &QCanBusDevice::framesReceived,
                  this, &MainWindow::checkMessages);
          connect(m_canDevice, &QCanBusDevice::framesWritten,
                  this, &MainWindow::framesWritten);

          if (p.useConfigurationEnabled) {
              foreach (const ConnectDialog::ConfigurationItem &item, p.configurations)
                  m_canDevice->setConfigurationParameter(item.first, item.second);
          }

          if (!m_canDevice->connectDevice()) {
              showStatusMessage(tr("Connection error: %1").arg(m_canDevice->errorString()));

              delete m_canDevice;
              m_canDevice = nullptr;
          } else {
              m_ui->actionConnect->setEnabled(false);
              m_ui->actionDisconnect->setEnabled(true);

              m_ui->sendMessagesBox->setEnabled(true);

              QVariant bitRate = m_canDevice->configurationParameter(QCanBusDevice::BitRateKey);
              if (bitRate.isValid()) {
                  showStatusMessage(tr("Backend: %1, connected to %2 at %3 kBit/s")
                          .arg(p.backendName).arg(p.deviceInterfaceName)
                          .arg(bitRate.toInt() / 1000));
              } else {
                  showStatusMessage(tr("Backend: %1, connected to %2")
                          .arg(p.backendName).arg(p.deviceInterfaceName));
              }
          }
      }

      void MainWindow::disconnectDevice()
      {
          if (!m_canDevice)
              return;

          m_canDevice->disconnectDevice();
          delete m_canDevice;
          m_canDevice = nullptr;

          m_ui->actionConnect->setEnabled(true);
          m_ui->actionDisconnect->setEnabled(false);

          m_ui->sendMessagesBox->setEnabled(false);

          showStatusMessage(tr("Disconnected"));
      }

      void MainWindow::framesWritten(qint64 count)
      {
          qDebug() << "Number of frames written:" << count;
      }

      void MainWindow::closeEvent(QCloseEvent *event)
      {
          m_connectDialog->close();
          event->accept();
      }

      static QByteArray dataToHex(const QByteArray &data)
      {
          QByteArray result = data.toHex().toUpper();

          for (int i = 0; i < result.size(); i += 3)
              result.insert(i, ' ');

          return result;
      }

      void MainWindow::checkMessages()
      {
          if (!m_canDevice)
              return;

          const QCanBusFrame frame = m_canDevice->readFrame();

          const qint8 dataLength = frame.payload().size();

          const qint32 id = frame.frameId();

          QString view;
          if (frame.frameType() == QCanBusFrame::ErrorFrame) {
              interpretError(view, frame);
          } else {
              const char *format =
                      frame.hasExtendedFrameFormat() ? "Id: %08X" : "Id:      %03X";
              view += QString::asprintf(format, static_cast<uint>(id));
              view += QLatin1String(" bytes: ");
              view += QString::number(dataLength, 10);
              if (frame.frameType() != QCanBusFrame::RemoteRequestFrame) {
                  view += QLatin1String(" data: ");
                  view += dataToHex(frame.payload());
              }
          }

          if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) {
              m_ui->requestList->addItem(view);
              m_ui->requestList->scrollToBottom();
          } else if (frame.frameType() == QCanBusFrame::ErrorFrame) {
              m_ui->errorList->addItem(view);
              m_ui->errorList->scrollToBottom();
          } else {
              m_ui->receiveList->addItem(view);
              m_ui->receiveList->scrollToBottom();
          }
      }

      static QByteArray dataFromHex(const QString &hex)
      {
          QByteArray line = hex.toLatin1();
          line.replace(' ', QByteArray());
          return QByteArray::fromHex(line);
      }

      void MainWindow::sendMessage() const
      {
          if (!m_canDevice)
              return;

          QByteArray writings = dataFromHex(m_ui->lineEdit->displayText());

          QCanBusFrame frame;
          const int maxPayload = m_ui->fdBox->checkState() ? 64 : 8;
          int size = writings.size();
          if (size > maxPayload)
              size = maxPayload;
          writings = writings.left(size);
          frame.setPayload(writings);

          qint32 id = m_ui->idEdit->displayText().toInt(nullptr, 16);
          if (!m_ui->effBox->checkState() && id > 2047) //11 bits
              id = 2047;

          frame.setFrameId(id);
          frame.setExtendedFrameFormat(m_ui->effBox->checkState());

          if (m_ui->remoteFrame->isChecked())
              frame.setFrameType(QCanBusFrame::RemoteRequestFrame);
          else if (m_ui->errorFrame->isChecked())
              frame.setFrameType(QCanBusFrame::ErrorFrame);
          else
              frame.setFrameType(QCanBusFrame::DataFrame);

          m_canDevice->writeFrame(frame);
      }

      void MainWindow::interpretError(QString &view, const QCanBusFrame &frame)
      {
          if (!m_canDevice)
              return;

          view = m_canDevice->interpretErrorFrame(frame);
      }