# HG changeset patch # User Hasan Yavuz ÖZDERYA # Date 2015-10-18 05:28:08 # Node ID 3b97826f2f6b9d4ec91db5aae1e1c63c67438f91 # Parent a3aeb9c195e97dd29588948ae40b5b6f9503c3e9 # Parent 41e1dedc32a335312ebe8a7f12c0f9e7db7efb94 Merge with command-panel diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,8 +57,15 @@ qt5_wrap_ui(UI_FILES portcontrol.ui about_dialog.ui snapshotview.ui + commandpanel.ui + commandwidget.ui ) -qt5_add_resources(RES_FILES misc/icons.qrc) + +if (WIN32) + qt5_add_resources(RES_FILES misc/icons.qrc misc/winicons.qrc) +else (WIN32) + qt5_add_resources(RES_FILES misc/icons.qrc) +endif (WIN32) add_executable(${PROGRAM_NAME} WIN32 main.cpp @@ -75,6 +82,9 @@ add_executable(${PROGRAM_NAME} WIN32 snapshotview.cpp snapshotmanager.cpp plotsnapshotoverlay.cpp + commandpanel.cpp + commandwidget.cpp + commandedit.cpp ${UI_FILES} ${RES_FILES} misc/windows_icon.rc diff --git a/commandedit.cpp b/commandedit.cpp new file mode 100644 --- /dev/null +++ b/commandedit.cpp @@ -0,0 +1,142 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + 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 . +*/ + +#include + +#include + +#include "commandedit.h" + +class HexCommandValidator : public QRegExpValidator +{ +public: + explicit HexCommandValidator(QObject* parent = 0); + QValidator::State validate(QString & input, int & pos) const; +}; + +HexCommandValidator::HexCommandValidator(QObject* parent) : + QRegExpValidator(parent) +{ + QRegExp regExp("^(?:(?:[0-9A-F]{2}[ ])+(?:[0-9A-F]{2}))|(?:[0-9A-F]{2})$"); + setRegExp(regExp); +} + +QValidator::State HexCommandValidator::validate(QString & input, int & pos) const +{ + input = input.toUpper(); + + // don't let pos to be altered at this stage + int orgPos = pos; + auto r = QRegExpValidator::validate(input, pos); + pos = orgPos; + + // try fixing up spaces + if (r != QValidator::Acceptable) + { + input = input.replace(" ", ""); + input.replace(QRegExp("([0-9A-F]{2}(?!$))"), "\\1 "); + if (pos == input.size()-1) pos = input.size(); + r = QRegExpValidator::validate(input, pos); + } + + return r; +} + +CommandEdit::CommandEdit(QWidget *parent) : + QLineEdit(parent) +{ + hexValidator = new HexCommandValidator(this); + asciiValidator = new QRegExpValidator(QRegExp("[\\x0000-\\x007F]+")); + ascii_mode = true; + setValidator(asciiValidator); +} + +CommandEdit::~CommandEdit() +{ + delete hexValidator; +} + +QString unEscape(QString str); +QString escape(QString str); + +void CommandEdit::setMode(bool ascii) +{ + ascii_mode = ascii; + if (ascii) + { + setValidator(asciiValidator); + + auto hexText = text().remove(" "); + // try patching HEX string in case of missing nibble so that + // input doesn't turn into gibberish + if (hexText.size() % 2 == 1) + { + hexText.replace(hexText.size()-1, 1, "3F"); // 0x3F = '?' + qWarning() << "Broken byte in hex command is replaced. Check your command!"; + } + + setText(escape(QByteArray::fromHex(hexText.toLatin1()))); + } + else + { + setValidator(hexValidator); + setText(unEscape(text()).toLatin1().toHex()); + } +} + +void CommandEdit::keyPressEvent(QKeyEvent * event) +{ + if (ascii_mode) + { + QLineEdit::keyPressEvent(event); + return; + } + + if (event->key() == Qt::Key_Backspace && !hasSelectedText()) + { + int cursor = cursorPosition(); + if (cursor != 0 && text()[cursor-1] == ' ') + { + setCursorPosition(cursor-1); + } + } + + QLineEdit::keyPressEvent(event); +} + +QString CommandEdit::unEscapedText() +{ + return unEscape(text()); +} + +QString unEscape(QString str) +{ + str.replace("\\n", "\n"); + str.replace("\\r", "\r"); + str.replace("\\t", "\t"); + return str; +} + +QString escape(QString str) +{ + str.replace("\n", "\\n"); + str.replace("\r", "\\r"); + str.replace("\t", "\\t"); + return str; +} diff --git a/commandedit.h b/commandedit.h new file mode 100644 --- /dev/null +++ b/commandedit.h @@ -0,0 +1,46 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + 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 . +*/ + +#ifndef COMMANDEDIT_H +#define COMMANDEDIT_H + +#include +#include +#include + +class CommandEdit : public QLineEdit +{ + Q_OBJECT + +public: + explicit CommandEdit(QWidget *parent = 0); + ~CommandEdit(); + void setMode(bool ascii); // true = ascii, false = hex + QString unEscapedText(); // return unescaped text(), used in ascii_mode only + +private: + bool ascii_mode; + QValidator* hexValidator; + QValidator* asciiValidator; + +protected: + void keyPressEvent(QKeyEvent * event) Q_DECL_OVERRIDE; +}; + +#endif // COMMANDEDIT_H diff --git a/commandpanel.cpp b/commandpanel.cpp new file mode 100644 --- /dev/null +++ b/commandpanel.cpp @@ -0,0 +1,68 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + 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 . +*/ + +#include "commandpanel.h" +#include "ui_commandpanel.h" + +#include +#include + +CommandPanel::CommandPanel(QSerialPort* port, QWidget *parent) : + QWidget(parent), + ui(new Ui::CommandPanel) +{ + serialPort = port; + + ui->setupUi(this); + ui->scrollAreaWidgetContents->setLayout(new QVBoxLayout); + +#ifdef Q_OS_WIN + ui->pbNew->setIcon(QIcon(":/icons/list-add")); +#endif // Q_OS_WIN + + connect(ui->pbNew, &QPushButton::clicked, this, &CommandPanel::newCommand); + + newCommand(); // add an empty slot by default +} + +CommandPanel::~CommandPanel() +{ + delete ui; +} + +void CommandPanel::newCommand() +{ + auto command = new CommandWidget(); + ui->scrollAreaWidgetContents->layout()->addWidget(command); + connect(command, &CommandWidget::sendCommand, this, &CommandPanel::sendCommand); +} + +void CommandPanel::sendCommand(QByteArray command) +{ + if (!serialPort->isOpen()) + { + qCritical() << "Port is not open!"; + return; + } + + if (serialPort->write(command) < 0) + { + qCritical() << "Send command failed!"; + } +} diff --git a/commandpanel.h b/commandpanel.h new file mode 100644 --- /dev/null +++ b/commandpanel.h @@ -0,0 +1,50 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + 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 . +*/ + +#ifndef COMMANDPANEL_H +#define COMMANDPANEL_H + +#include +#include +#include + +#include "commandwidget.h" + +namespace Ui { +class CommandPanel; +} + +class CommandPanel : public QWidget +{ + Q_OBJECT + +public: + explicit CommandPanel(QSerialPort* port, QWidget *parent = 0); + ~CommandPanel(); + +private: + Ui::CommandPanel *ui; + QSerialPort* serialPort; + +private slots: + void newCommand(); + void sendCommand(QByteArray command); +}; + +#endif // COMMANDPANEL_H diff --git a/commandpanel.ui b/commandpanel.ui new file mode 100644 --- /dev/null +++ b/commandpanel.ui @@ -0,0 +1,63 @@ + + + CommandPanel + + + + 0 + 0 + 583 + 109 + + + + Form + + + false + + + + + + QFrame::StyledPanel + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 563 + 16 + + + + + 0 + 0 + + + + + + + + + New Command + + + + + + + + + + + diff --git a/commandwidget.cpp b/commandwidget.cpp new file mode 100644 --- /dev/null +++ b/commandwidget.cpp @@ -0,0 +1,95 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + 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 . +*/ + +#include "commandwidget.h" +#include "ui_commandwidget.h" + +#include +#include +#include +#include + +CommandWidget::CommandWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::CommandWidget) +{ + ui->setupUi(this); + +#ifdef Q_OS_WIN + ui->pbDelete->setIcon(QIcon(":/icons/list-remove")); +#endif // Q_OS_WIN + + connect(ui->pbDelete, &QPushButton::clicked, this, &CommandWidget::onDeleteClicked); + connect(ui->pbSend, &QPushButton::clicked, this, &CommandWidget::onSendClicked); + connect(ui->pbASCII, &QPushButton::toggled, this, &CommandWidget::onASCIIToggled); +} + +CommandWidget::~CommandWidget() +{ + delete ui; +} + +void CommandWidget::onDeleteClicked() +{ + this->deleteLater(); +} + +void CommandWidget::onSendClicked() +{ + auto command = ui->leCommand->text(); + + if (command.isEmpty()) + { + qWarning() << "Enter a command to send!"; + ui->leCommand->setFocus(Qt::OtherFocusReason); + return; + } + + if (isASCIIMode()) + { + qDebug() << "Sending:" << command; + emit sendCommand(ui->leCommand->unEscapedText().toLatin1()); + } + else // hex mode + { + command = command.remove(' '); + // check if nibbles are missing + if (command.size() % 2 == 1) + { + qWarning() << "HEX command is missing a nibble at the end!"; + ui->leCommand->setFocus(Qt::OtherFocusReason); + // highlight the byte that is missing a nibble (last byte obviously) + int textSize = ui->leCommand->text().size(); + ui->leCommand->setSelection(textSize-1, textSize); + return; + } + qDebug() << "Sending HEX:" << command; + emit sendCommand(QByteArray::fromHex(command.toLatin1())); + } +} + +void CommandWidget::onASCIIToggled(bool checked) +{ + ui->leCommand->setMode(checked); +} + +bool CommandWidget::isASCIIMode() +{ + return ui->pbASCII->isChecked(); +} diff --git a/commandwidget.h b/commandwidget.h new file mode 100644 --- /dev/null +++ b/commandwidget.h @@ -0,0 +1,58 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + 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 . +*/ + +#ifndef COMMANDWIDGET_H +#define COMMANDWIDGET_H + +#include +#include + +namespace Ui { +class CommandWidget; +} + +class CommandWidget : public QWidget +{ + Q_OBJECT + +public: + explicit CommandWidget(QWidget *parent = 0); + ~CommandWidget(); + +signals: + void deleteRequested(CommandWidget* thisWidget); // emitted when delete button is clicked + + // emitted when send button is clicked + // + // in case of hex mode, command text should be a hexadecimal + // string containing hexadecimal characters only (not even spaces) + void sendCommand(QByteArray command); + +private: + Ui::CommandWidget *ui; + + bool isASCIIMode(); // true: ascii mode, false hex mode + +private slots: + void onDeleteClicked(); + void onSendClicked(); + void onASCIIToggled(bool checked); +}; + +#endif // COMMANDWIDGET_H diff --git a/commandwidget.ui b/commandwidget.ui new file mode 100644 --- /dev/null +++ b/commandwidget.ui @@ -0,0 +1,173 @@ + + + CommandWidget + + + + 0 + 0 + 433 + 34 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 30 + 0 + + + + + + + + + + + + true + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Enter your command here.</p><p>In ASCII mode you can use backslash '\' to send some special characters. These are:<br/><span style=" font-weight:600;">\n</span> : Line Feed (new line)<br/><span style=" font-weight:600;">\r</span> : Carriage Return<br/><span style=" font-weight:600;">\t</span> : Tab</p><p>Be careful though, you cannot escape the backslash character itself!</p></body></html> + + + true + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 40 + 0 + + + + ASCII + + + true + + + true + + + true + + + + + + + + 0 + 0 + + + + + 40 + 0 + + + + HEX + + + true + + + true + + + + + + + + + + + 0 + 0 + + + + Send + + + + + + + + CommandEdit + QLineEdit +
commandedit.h
+
+
+ + +
diff --git a/mainwindow.cpp b/mainwindow.cpp --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -54,10 +54,12 @@ MainWindow::MainWindow(QWidget *parent) QMainWindow(parent), ui(new Ui::MainWindow), portControl(&serialPort), + commandPanel(&serialPort), snapshotMan(this, &channelBuffers) { ui->setupUi(this); ui->tabWidget->insertTab(0, &portControl, "Port"); + ui->tabWidget->insertTab(3, &commandPanel, "Commands"); ui->tabWidget->setCurrentIndex(0); addToolBar(portControl.toolBar()); diff --git a/mainwindow.h b/mainwindow.h --- a/mainwindow.h +++ b/mainwindow.h @@ -35,6 +35,7 @@ #include #include "portcontrol.h" +#include "commandpanel.h" #include "ui_about_dialog.h" #include "framebuffer.h" #include "snapshotmanager.h" @@ -100,6 +101,8 @@ private: unsigned int sampleCount; QTimer spsTimer; + CommandPanel commandPanel; + SnapshotManager snapshotMan; // demo diff --git a/misc/pseudo_device_2.py b/misc/pseudo_device_2.py new file mode 100755 --- /dev/null +++ b/misc/pseudo_device_2.py @@ -0,0 +1,41 @@ +#!/usr/bin/python3 +# +# Copyright © 2015 Hasan Yavuz Özderya +# +# 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 . +# + +import os, pty, time + +def run(): + # create the pseudo terminal + master, slave = pty.openpty() + + slave_name = os.ttyname(slave) + print("Slave terminal: {}".format(slave_name)) + + masterw = os.fdopen(master, 'w') + masterr = os.fdopen(master, 'r') + + while True: + line = masterr.read(4) + print(">" + line) + if (line.strip() == "data"): + masterw.write("1,1\r\n") + time.sleep(0.01) + +if __name__ == "__main__": + run() diff --git a/misc/tango/license_notice b/misc/tango/license_notice new file mode 100644 --- /dev/null +++ b/misc/tango/license_notice @@ -0,0 +1,3 @@ +Icon files in this directory are taken from Tango project +(http://tango.freedesktop.org/). Please see referenced web page for +more information. \ No newline at end of file diff --git a/misc/tango/list-add.png b/misc/tango/list-add.png new file mode 100644 index 0000000000000000000000000000000000000000..2acdd8f514c199a37b7b14f53081467f88ef7bff GIT binary patch literal 601 zc$@)Q0;c_mP)i&hw@usRe0Hlp%^VXF!>2}-I+fVC+BCh2Xu(H}= zWwkR-i17&Q1@?r1slIQmGmt?bz+``iz=_N4nTEMJnWp6PdlDi4$xDysihSSRJ^#HD zfm0WkcL*Ezw|WjD;wX`Y@`OQ$i> zk~|wHA%P^W-+NY=qm+O%@!?CCIP&DpgbAGaz)s%w=F2r6?z` z-r3~+=g{XtaVheZEby-7%X^w2a;hK35HfD6NN^I8P7V;(0mQ@Z@*Wtm@8FfUzLwkFPvfh|u~3@f)V nN>6CzLo>o}j6Z`3{#X10^GpxssPJ~100000NkvXXu0mjfzW5Zm diff --git a/misc/tango/list-remove.png b/misc/tango/list-remove.png new file mode 100644 index 0000000000000000000000000000000000000000..c5524f7284e4ecb40cbee1e3d3a449bd58a0e4a8 GIT binary patch literal 317 zc$@(}0mA-?P)oXoi$Ept^qyG_6h*pUY)JY1xUgL61ap*$YU>o#o9`0ukRmwYg7fy z#q{lyri8qE6g3Y4Q)K4C3`{ULEziwO932j7CF%n2voBs=XUn#u^MV%pm5i9iZx-vp zUj3U@1pr3JL$sKN`)b!NVJ6&T + + tango/list-add.png + tango/list-remove.png + + diff --git a/serialplot.pro b/serialplot.pro --- a/serialplot.pro +++ b/serialplot.pro @@ -46,7 +46,10 @@ SOURCES += main.cpp\ snapshotview.cpp \ snapshotmanager.cpp \ snapshot.cpp \ - plotsnapshotoverlay.cpp + plotsnapshotoverlay.cpp \ + commandpanel.cpp \ + commandwidget.cpp \ + commandedit.cpp HEADERS += mainwindow.h \ utils.h \ @@ -62,16 +65,24 @@ HEADERS += mainwindow.h \ snapshotview.h \ snapshotmanager.h \ snapshot.h \ - plotsnapshotoverlay.h + plotsnapshotoverlay.h \ + commandpanel.h \ + commandwidget.h \ + commandedit.h FORMS += mainwindow.ui \ about_dialog.ui \ portcontrol.ui \ - snapshotview.ui + snapshotview.ui \ + commandpanel.ui \ + commandwidget.ui INCLUDEPATH += qmake/ CONFIG += c++11 -RESOURCES += \ - misc/icons.qrc +RESOURCES += misc/icons.qrc + +win32 { + RESOURCES += misc/winicons.qrc +}