Changeset - 9f791e07b3c2
[Not reviewed]
default
0 4 0
Hasan Yavuz Ă–ZDERYA - 8 years ago 2017-11-05 03:30:38
hy@ozderya.net
move port error handling to portcontrol
4 files changed with 61 insertions and 63 deletions:
0 comments (0 inline, 0 general)
src/mainwindow.cpp
Show inline comments
 
@@ -134,100 +134,96 @@ MainWindow::MainWindow(QWidget *parent) 
 
    QObject::connect(ui->actionCheckUpdate, &QAction::triggered,
 
              &updateCheckDialog, &QWidget::show);
 

	
 
    QObject::connect(ui->actionReportBug, &QAction::triggered,
 
                     [](){QDesktopServices::openUrl(QUrl(BUG_REPORT_URL));});
 

	
 
    // File menu signals
 
    QObject::connect(ui->actionExportCsv, &QAction::triggered,
 
                     this, &MainWindow::onExportCsv);
 

	
 
    QObject::connect(ui->actionSaveSettings, &QAction::triggered,
 
                     this, &MainWindow::onSaveSettings);
 

	
 
    QObject::connect(ui->actionLoadSettings, &QAction::triggered,
 
                     this, &MainWindow::onLoadSettings);
 

	
 
    ui->actionQuit->setShortcutContext(Qt::ApplicationShortcut);
 

	
 
    QObject::connect(ui->actionQuit, &QAction::triggered,
 
                     this, &MainWindow::close);
 

	
 
    // port control signals
 
    QObject::connect(&portControl, &PortControl::portToggled,
 
                     this, &MainWindow::onPortToggled);
 

	
 
    // plot control signals
 
    connect(&plotControlPanel, &PlotControlPanel::numOfSamplesChanged,
 
            this, &MainWindow::onNumOfSamplesChanged);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::numOfSamplesChanged,
 
            plotMan, &PlotManager::setNumOfSamples);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::yScaleChanged,
 
            plotMan, &PlotManager::setYAxis);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::xScaleChanged,
 
            plotMan, &PlotManager::setXAxis);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::plotWidthChanged,
 
            plotMan, &PlotManager::setPlotWidth);
 

	
 
    // plot toolbar signals
 
    QObject::connect(ui->actionClear, SIGNAL(triggered(bool)),
 
                     this, SLOT(clearPlot()));
 

	
 
    QObject::connect(snapshotMan.takeSnapshotAction(), &QAction::triggered,
 
                     plotMan, &PlotManager::flashSnapshotOverlay);
 

	
 
    // init port signals
 
    QObject::connect(&(this->serialPort), SIGNAL(error(QSerialPort::SerialPortError)),
 
                     this, SLOT(onPortError(QSerialPort::SerialPortError)));
 

	
 
    // init data format and reader
 
    QObject::connect(&channelMan, &ChannelManager::dataAdded,
 
                     plotMan, &PlotManager::replot);
 

	
 
    QObject::connect(ui->actionPause, &QAction::triggered,
 
                     &channelMan, &ChannelManager::pause);
 

	
 
    QObject::connect(&recordPanel, &RecordPanel::recordStarted,
 
                     &dataFormatPanel, &DataFormatPanel::startRecording);
 

	
 
    QObject::connect(&recordPanel, &RecordPanel::recordStopped,
 
                     &dataFormatPanel, &DataFormatPanel::stopRecording);
 

	
 
    QObject::connect(ui->actionPause, &QAction::triggered,
 
                     [this](bool enabled)
 
                     {
 
                         if (enabled && !recordPanel.recordPaused())
 
                         {
 
                             dataFormatPanel.pause(true);
 
                         }
 
                         else
 
                         {
 
                             dataFormatPanel.pause(false);
 
                         }
 
                     });
 

	
 
    QObject::connect(&recordPanel, &RecordPanel::recordPausedChanged,
 
                     [this](bool enabled)
 
                     {
 
                         if (ui->actionPause->isChecked() && enabled)
 
                         {
 
                             dataFormatPanel.pause(false);
 
                         }
 
                     });
 

	
 
    connect(&serialPort, &QIODevice::aboutToClose,
 
            &recordPanel, &RecordPanel::onPortClose);
 

	
 
    // init data arrays and plot
 
    numOfSamples = plotControlPanel.numOfSamples();
 
    unsigned numOfChannels = dataFormatPanel.numOfChannels();
 

	
 
    channelMan.setNumOfSamples(numOfSamples);
 
    channelMan.setNumOfChannels(dataFormatPanel.numOfChannels());
 

	
 
    connect(&dataFormatPanel, &DataFormatPanel::numOfChannelsChanged,
 
            &channelMan, &ChannelManager::setNumOfChannels);
 

	
 
@@ -327,154 +323,96 @@ void MainWindow::closeEvent(QCloseEvent 
 
        {
 
            QString file = settings.fileName();
 
            errorText = QString("Serialplot cannot save settings due to access error. \
 
This happens if you have run serialplot as root (with sudo for ex.) previously. \
 
Try fixing the permissions of file: %1, or just delete it.").arg(file);
 
        }
 
        else
 
        {
 
            errorText = QString("Serialplot cannot save settings due to unknown error: %1").\
 
                arg(settings.status());
 
        }
 

	
 
        auto button = QMessageBox::critical(
 
            NULL,
 
            "Failed to save settings!", errorText,
 
            QMessageBox::Cancel | QMessageBox::Ok);
 

	
 
        if (button == QMessageBox::Cancel)
 
        {
 
            event->ignore();
 
            return;
 
        }
 
    }
 

	
 
    QMainWindow::closeEvent(event);
 
}
 

	
 
void MainWindow::setupAboutDialog()
 
{
 
    Ui_AboutDialog uiAboutDialog;
 
    uiAboutDialog.setupUi(&aboutDialog);
 

	
 
    QObject::connect(uiAboutDialog.pbAboutQt, &QPushButton::clicked,
 
                     [](){ QApplication::aboutQt();});
 

	
 
    QString aboutText = uiAboutDialog.lbAbout->text();
 
    aboutText.replace("$VERSION_STRING$", VERSION_STRING);
 
    aboutText.replace("$VERSION_REVISION$", VERSION_REVISION);
 
    uiAboutDialog.lbAbout->setText(aboutText);
 
}
 

	
 
void MainWindow::onPortToggled(bool open)
 
{
 
    // make sure demo mode is disabled
 
    if (open && isDemoRunning()) enableDemo(false);
 
    ui->actionDemoMode->setEnabled(!open);
 
}
 

	
 
void MainWindow::onPortError(QSerialPort::SerialPortError error)
 
{
 
    switch(error)
 
    {
 
        case QSerialPort::NoError :
 
            break;
 
        case QSerialPort::ResourceError :
 
            qWarning() << "Port error: resource unavaliable; most likely device removed.";
 
            if (serialPort.isOpen())
 
            {
 
                qWarning() << "Closing port on resource error: " << serialPort.portName();
 
                portControl.togglePort();
 
            }
 
            portControl.loadPortList();
 
            break;
 
        case QSerialPort::DeviceNotFoundError:
 
            qCritical() << "Device doesn't exists: " << serialPort.portName();
 
            break;
 
        case QSerialPort::PermissionError:
 
            qCritical() << "Permission denied. Either you don't have \
 
required privileges or device is already opened by another process.";
 
            break;
 
        case QSerialPort::OpenError:
 
            qWarning() << "Device is already opened!";
 
            break;
 
        case QSerialPort::NotOpenError:
 
            qCritical() << "Device is not open!";
 
            break;
 
        case QSerialPort::ParityError:
 
            qCritical() << "Parity error detected.";
 
            break;
 
        case QSerialPort::FramingError:
 
            qCritical() << "Framing error detected.";
 
            break;
 
        case QSerialPort::BreakConditionError:
 
            qCritical() << "Break condition is detected.";
 
            break;
 
        case QSerialPort::WriteError:
 
            qCritical() << "An error occurred while writing data.";
 
            break;
 
        case QSerialPort::ReadError:
 
            qCritical() << "An error occurred while reading data.";
 
            break;
 
        case QSerialPort::UnsupportedOperationError:
 
            qCritical() << "Operation is not supported.";
 
            break;
 
        case QSerialPort::TimeoutError:
 
            qCritical() << "A timeout error occurred.";
 
            break;
 
        case QSerialPort::UnknownError:
 
            qCritical() << "Unknown error! Error: " << serialPort.errorString();
 
            break;
 
        default:
 
            qCritical() << "Unhandled port error: " << error;
 
            break;
 
    }
 
}
 

	
 
void MainWindow::clearPlot()
 
{
 
    for (unsigned ci = 0; ci < channelMan.numOfChannels(); ci++)
 
    {
 
        channelMan.channelBuffer(ci)->clear();
 
    }
 
    plotMan->replot();
 
}
 

	
 
void MainWindow::onNumOfSamplesChanged(int value)
 
{
 
    numOfSamples = value;
 
    channelMan.setNumOfSamples(value);
 
    plotMan->replot();
 
}
 

	
 
void MainWindow::onNumOfChannelsChanged(unsigned value)
 
{
 
    unsigned int oldNum = plotMan->numOfCurves();
 
    unsigned numOfChannels = value;
 

	
 
    if (numOfChannels > oldNum)
 
    {
 
        // add new channels
 
        for (unsigned int i = oldNum; i < numOfChannels; i++)
 
        {
 
            plotMan->addCurve(channelMan.channelName(i), channelMan.channelBuffer(i));
 
        }
 
    }
 
    else if(numOfChannels < oldNum)
 
    {
 
        plotMan->removeCurves(oldNum - numOfChannels);
 
    }
 

	
 
    plotMan->replot();
 
}
 

	
 
void MainWindow::onSpsChanged(unsigned sps)
 
{
 
    spsLabel.setText(QString::number(sps) + "sps");
 
}
 

	
 
bool MainWindow::isDemoRunning()
 
{
 
    return ui->actionDemoMode->isChecked();
 
}
 

	
 
void MainWindow::enableDemo(bool enabled)
src/mainwindow.h
Show inline comments
 
@@ -67,64 +67,63 @@ public:
 

	
 
private:
 
    Ui::MainWindow *ui;
 

	
 
    QDialog aboutDialog;
 
    void setupAboutDialog();
 

	
 
    QSerialPort serialPort;
 
    PortControl portControl;
 

	
 
    unsigned int numOfSamples;
 

	
 
    QList<QwtPlotCurve*> curves;
 
    ChannelManager channelMan;
 
    PlotManager* plotMan;
 
    QWidget* secondaryPlot;
 
    SnapshotManager snapshotMan;
 
    DataRecorder recorder;       // operated by `recordPanel`
 

	
 
    QLabel spsLabel;
 
    CommandPanel commandPanel;
 
    DataFormatPanel dataFormatPanel;
 
    RecordPanel recordPanel;
 
    PlotControlPanel plotControlPanel;
 
    PlotMenu plotMenu;
 
    UpdateCheckDialog updateCheckDialog;
 

	
 
    /// Returns true if demo is running
 
    bool isDemoRunning();
 
    /// Display a secondary plot in the splitter, removing and
 
    /// deleting previous one if it exists
 
    void showSecondary(QWidget* wid);
 
    /// Hide secondary plot
 
    void hideSecondary();
 
    /// Stores settings for all modules
 
    void saveAllSettings(QSettings* settings);
 
    /// Load settings for all modules
 
    void loadAllSettings(QSettings* settings);
 
    /// Stores main window settings into a `QSettings`
 
    void saveMWSettings(QSettings* settings);
 
    /// Loads main window settings from a `QSettings`
 
    void loadMWSettings(QSettings* settings);
 

	
 
    /// `QWidget::closeEvent` handler
 
    void closeEvent(QCloseEvent * event);
 

	
 
private slots:
 
    void onPortToggled(bool open);
 
    void onPortError(QSerialPort::SerialPortError error);
 

	
 
    void onNumOfSamplesChanged(int value);
 
    void onNumOfChannelsChanged(unsigned value);
 

	
 
    void clearPlot();
 
    void onSpsChanged(unsigned sps);
 
    void enableDemo(bool enabled);
 
    void showBarPlot(bool show);
 

	
 
    void onExportCsv();
 
    void onSaveSettings();
 
    void onLoadSettings();
 
};
 

	
 
#endif // MAINWINDOW_H
src/portcontrol.cpp
Show inline comments
 
@@ -3,96 +3,98 @@
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "portcontrol.h"
 
#include "ui_portcontrol.h"
 

	
 
#include <QSerialPortInfo>
 
#include <QKeySequence>
 
#include <QLabel>
 
#include <QMap>
 
#include <QtDebug>
 

	
 
#include "setting_defines.h"
 
#include "utils.h"
 

	
 
#define TBPORTLIST_MINWIDTH (200)
 

	
 
// setting mappings
 
const QMap<QSerialPort::Parity, QString> paritySettingMap({
 
        {QSerialPort::NoParity, "none"},
 
        {QSerialPort::OddParity, "odd"},
 
        {QSerialPort::EvenParity, "even"},
 
    });
 

	
 
PortControl::PortControl(QSerialPort* port, QWidget* parent) :
 
    QWidget(parent),
 
    ui(new Ui::PortControl),
 
    portToolBar("Port Toolbar"),
 
    openAction("Open", this),
 
    loadPortListAction("↺", this)
 
{
 
    ui->setupUi(this);
 

	
 
    serialPort = port;
 
    connect(serialPort, SIGNAL(error(QSerialPort::SerialPortError)),
 
            this, SLOT(onPortError(QSerialPort::SerialPortError)));
 

	
 
    // setup actions
 
    openAction.setCheckable(true);
 
    openAction.setShortcut(QKeySequence("F12"));
 
    openAction.setToolTip("Open Port");
 
    QObject::connect(&openAction, &QAction::triggered,
 
                     this, &PortControl::openActionTriggered);
 

	
 
    loadPortListAction.setToolTip("Reload port list");
 
    QObject::connect(&loadPortListAction, &QAction::triggered,
 
                     [this](bool checked){loadPortList();});
 

	
 
    // setup toolbar
 
    portToolBar.addWidget(&tbPortList);
 
    portToolBar.addAction(&loadPortListAction);
 
    portToolBar.addAction(&openAction);
 

	
 
    // setup port selection widgets
 
    tbPortList.setMinimumWidth(TBPORTLIST_MINWIDTH);
 
    tbPortList.setModel(&portList);
 
    ui->cbPortList->setModel(&portList);
 
    QObject::connect(ui->cbPortList,
 
                     SELECT<int>::OVERLOAD_OF(&QComboBox::activated),
 
                     this, &PortControl::onCbPortListActivated);
 
    QObject::connect(&tbPortList,
 
                     SELECT<int>::OVERLOAD_OF(&QComboBox::activated),
 
                     this, &PortControl::onTbPortListActivated);
 
    QObject::connect(ui->cbPortList,
 
                     SELECT<const QString&>::OVERLOAD_OF(&QComboBox::activated),
 
                     this, &PortControl::selectPort);
 
    QObject::connect(&tbPortList,
 
                     SELECT<const QString&>::OVERLOAD_OF(&QComboBox::activated),
 
                     this, &PortControl::selectPort);
 

	
 
    // setup buttons
 
    ui->pbOpenPort->setDefaultAction(&openAction);
 
    ui->pbReloadPorts->setDefaultAction(&loadPortListAction);
 

	
 
    // setup baud rate selection widget
 
    QObject::connect(ui->cbBaudRate,
 
                     SELECT<const QString&>::OVERLOAD_OF(&QComboBox::activated),
 
                     this, &PortControl::selectBaudRate);
 

	
 
    // setup parity selection buttons
 
    parityButtons.addButton(ui->rbNoParity, (int) QSerialPort::NoParity);
 
    parityButtons.addButton(ui->rbEvenParity, (int) QSerialPort::EvenParity);
 
    parityButtons.addButton(ui->rbOddParity, (int) QSerialPort::OddParity);
 

	
 
@@ -317,96 +319,154 @@ void PortControl::selectPort(QString por
 
    {
 
        // if another port is already open, close it by toggling
 
        if (serialPort->isOpen())
 
        {
 
            togglePort();
 

	
 
            // open new selection by toggling
 
            togglePort();
 
        }
 
    }
 
}
 

	
 
QString PortControl::selectedPortName()
 
{
 
    QString portText = ui->cbPortList->currentText();
 
    int portIndex = portList.indexOf(portText);
 
    if (portIndex < 0) // not in the list yet
 
    {
 
        // return the displayed name as port name
 
        return portText;
 
    }
 
    else
 
    {
 
        // get the port name from the 'port list'
 
        return static_cast<PortListItem*>(portList.item(portIndex))->portName();
 
    }
 
}
 

	
 
QToolBar* PortControl::toolBar()
 
{
 
    return &portToolBar;
 
}
 

	
 
void PortControl::openActionTriggered(bool checked)
 
{
 
    togglePort();
 
}
 

	
 
void PortControl::onCbPortListActivated(int index)
 
{
 
    tbPortList.setCurrentIndex(index);
 
}
 

	
 
void PortControl::onTbPortListActivated(int index)
 
{
 
    ui->cbPortList->setCurrentIndex(index);
 
}
 

	
 
void PortControl::onPortError(QSerialPort::SerialPortError error)
 
{
 
    switch(error)
 
    {
 
        case QSerialPort::NoError :
 
            break;
 
        case QSerialPort::ResourceError :
 
            qWarning() << "Port error: resource unavaliable; most likely device removed.";
 
            if (serialPort->isOpen())
 
            {
 
                qWarning() << "Closing port on resource error: " << serialPort->portName();
 
                togglePort();
 
            }
 
            loadPortList();
 
            break;
 
        case QSerialPort::DeviceNotFoundError:
 
            qCritical() << "Device doesn't exists: " << serialPort->portName();
 
            break;
 
        case QSerialPort::PermissionError:
 
            qCritical() << "Permission denied. Either you don't have \
 
required privileges or device is already opened by another process.";
 
            break;
 
        case QSerialPort::OpenError:
 
            qWarning() << "Device is already opened!";
 
            break;
 
        case QSerialPort::NotOpenError:
 
            qCritical() << "Device is not open!";
 
            break;
 
        case QSerialPort::ParityError:
 
            qCritical() << "Parity error detected.";
 
            break;
 
        case QSerialPort::FramingError:
 
            qCritical() << "Framing error detected.";
 
            break;
 
        case QSerialPort::BreakConditionError:
 
            qCritical() << "Break condition is detected.";
 
            break;
 
        case QSerialPort::WriteError:
 
            qCritical() << "An error occurred while writing data.";
 
            break;
 
        case QSerialPort::ReadError:
 
            qCritical() << "An error occurred while reading data.";
 
            break;
 
        case QSerialPort::UnsupportedOperationError:
 
            qCritical() << "Operation is not supported.";
 
            break;
 
        case QSerialPort::TimeoutError:
 
            qCritical() << "A timeout error occurred.";
 
            break;
 
        case QSerialPort::UnknownError:
 
            qCritical() << "Unknown error! Error: " << serialPort->errorString();
 
            break;
 
        default:
 
            qCritical() << "Unhandled port error: " << error;
 
            break;
 
    }
 
}
 

	
 
void PortControl::updatePinLeds(void)
 
{
 
    auto pins = serialPort->pinoutSignals();
 
    ui->ledDCD->setOn(pins & QSerialPort::DataCarrierDetectSignal);
 
    ui->ledDSR->setOn(pins & QSerialPort::DataSetReadySignal);
 
    ui->ledRI->setOn(pins & QSerialPort::RingIndicatorSignal);
 
    ui->ledCTS->setOn(pins & QSerialPort::ClearToSendSignal);
 
}
 

	
 
QString PortControl::currentParityText()
 
{
 
    return paritySettingMap.value(
 
        (QSerialPort::Parity) parityButtons.checkedId());
 
}
 

	
 
QString PortControl::currentFlowControlText()
 
{
 
    if (flowControlButtons.checkedId() == QSerialPort::HardwareControl)
 
    {
 
        return "hardware";
 
    }
 
    else if (flowControlButtons.checkedId() == QSerialPort::SoftwareControl)
 
    {
 
        return "software";
 
    }
 
    else // no parity
 
    {
 
        return "none";
 
    }
 
}
 

	
 
void PortControl::saveSettings(QSettings* settings)
 
{
 
    settings->beginGroup(SettingGroup_Port);
 
    settings->setValue(SG_Port_SelectedPort, selectedPortName());
 
    settings->setValue(SG_Port_BaudRate, ui->cbBaudRate->currentText());
 
    settings->setValue(SG_Port_Parity, currentParityText());
 
    settings->setValue(SG_Port_DataBits, dataBitsButtons.checkedId());
 
    settings->setValue(SG_Port_StopBits, stopBitsButtons.checkedId());
 
    settings->setValue(SG_Port_FlowControl, currentFlowControlText());
 
    settings->endGroup();
 
}
 

	
 
void PortControl::loadSettings(QSettings* settings)
 
{
 
    // make sure the port is closed
 
    if (serialPort->isOpen()) togglePort();
 

	
src/portcontrol.h
Show inline comments
 
@@ -47,55 +47,56 @@ public:
 
    QSerialPort* serialPort;
 
    QToolBar* toolBar();
 

	
 
    /// Stores port settings into a `QSettings`
 
    void saveSettings(QSettings* settings);
 
    /// Loads port settings from a `QSettings`. If open serial port is closed.
 
    void loadSettings(QSettings* settings);
 

	
 
private:
 
    Ui::PortControl *ui;
 

	
 
    QButtonGroup parityButtons;
 
    QButtonGroup dataBitsButtons;
 
    QButtonGroup stopBitsButtons;
 
    QButtonGroup flowControlButtons;
 

	
 
    QToolBar portToolBar;
 
    QAction openAction;
 
    QAction loadPortListAction;
 
    QComboBox tbPortList;
 
    PortList portList;
 

	
 
    /// Used to refresh pinout signal leds periodically
 
    QTimer pinUpdateTimer;
 

	
 
    /// Returns the currently selected (entered) "portName" in the UI
 
    QString selectedPortName();
 
    /// Returns currently selected parity as text to be saved in settings
 
    QString currentParityText();
 
    /// Returns currently selected flow control as text to be saved in settings
 
    QString currentFlowControlText();
 

	
 
public slots:
 
    void loadPortList();
 
    void loadBaudRateList();
 
    void togglePort();
 
    void selectPort(QString portName);
 

	
 
    void selectBaudRate(QString baudRate);
 
    void selectParity(int parity); // parity must be one of QSerialPort::Parity
 
    void selectDataBits(int dataBits); // bits must be one of QSerialPort::DataBits
 
    void selectStopBits(int stopBits); // stopBits must be one of QSerialPort::StopBits
 
    void selectFlowControl(int flowControl); // flowControl must be one of QSerialPort::FlowControl
 

	
 
private slots:
 
    void openActionTriggered(bool checked);
 
    void onCbPortListActivated(int index);
 
    void onTbPortListActivated(int index);
 
    void onPortError(QSerialPort::SerialPortError error);
 
    void updatePinLeds(void);
 

	
 
signals:
 
    void portToggled(bool open);
 
};
 

	
 
#endif // PORTCONTROL_H
0 comments (0 inline, 0 general)