From f891bee44c78a09ed1c112fc8eb44e9e53874f2c Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 20 Feb 2014 23:56:30 +0000 Subject: [PATCH 01/35] Fixed a segmentation fault. Added a dummy thread which can be used for asynchronous acquisition. --- QwtExample.pro | 6 +++-- window.cpp | 61 +++++++++++++++++++++++++++++++++----------------- window.h | 19 ++++++++++------ 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/QwtExample.pro b/QwtExample.pro index 8302b83..a9212e5 100644 --- a/QwtExample.pro +++ b/QwtExample.pro @@ -2,12 +2,14 @@ QT += core gui +CONFIG += qt warn_on debug + greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = QwtExample LIBS += -lqwt -lm -HEADERS += window.h +HEADERS += window.h adcreader.h -SOURCES += main.cpp window.cpp +SOURCES += main.cpp window.cpp adcreader.cpp diff --git a/window.cpp b/window.cpp index 2cfdad7..f1daee8 100644 --- a/window.cpp +++ b/window.cpp @@ -1,21 +1,24 @@ #include "window.h" +#include "adcreader.h" #include // for sine stuff -Window::Window() : plot( QString("Example Plot") ), gain(5), count(0) // <-- 'c++ initialisation list' - google it! +Window::Window() : gain(5), count(0) { + knob = new QwtKnob; // set up the gain knob - knob.setValue(gain); + knob->setValue(gain); // use the Qt signals/slots framework to update the gain - // every time the knob is moved, the setGain function will be called - connect( &knob, SIGNAL(valueChanged(double)), SLOT(setGain(double)) ); + connect( knob, SIGNAL(valueChanged(double)), SLOT(setGain(double)) ); // set up the thermometer - thermo.setFillBrush( QBrush(Qt::red) ); - thermo.setRange(0, 20); - thermo.show(); + thermo = new QwtThermo; + thermo->setFillBrush( QBrush(Qt::red) ); + thermo->setRange(0, 20); + thermo->show(); // set up the initial plot data @@ -25,40 +28,58 @@ Window::Window() : plot( QString("Example Plot") ), gain(5), count(0) // <-- 'c+ yData[index] = gain * sin( M_PI * index/50 ); } + curve = new QwtPlotCurve; + plot = new QwtPlot; // make a plot curve from the data and attach it to the plot - curve.setSamples(xData, yData, plotDataSize); - curve.attach(&plot); + curve->setSamples(xData, yData, plotDataSize); + curve->attach(plot); - plot.replot(); - plot.show(); + plot->replot(); + plot->show(); // set up the layout - knob above thermometer - vLayout.addWidget(&knob); - vLayout.addWidget(&thermo); + vLayout = new QVBoxLayout; + vLayout->addWidget(knob); + vLayout->addWidget(thermo); // plot to the left of knob and thermometer - hLayout.addLayout(&vLayout); - hLayout.addWidget(&plot); - - setLayout(&hLayout); + hLayout = new QHBoxLayout; + hLayout->addLayout(vLayout); + hLayout->addWidget(plot); + + setLayout(hLayout); + + // This is a demo for a thread which can be + // used to read from the ADC asynchronously. + // At the moment it doesn't do anything else than + // running in an endless loop and which prints out "tick" + // every second. + adcreader = new ADCreader(); + adcreader->start(); } +Window::~Window() { + // tells the thread to no longer run its endless loop + adcreader->quit(); + // wait until the run method has terminated + adcreader->wait(); + delete adcreader; +} void Window::timerEvent( QTimerEvent * ) { - // generate an sine wave input for example purposes - you must get yours from the A/D! double inVal = gain * sin( M_PI * count/50.0 ); ++count; // add the new input to the plot memmove( yData, yData+1, (plotDataSize-1) * sizeof(double) ); yData[plotDataSize-1] = inVal; - curve.setSamples(xData, yData, plotDataSize); - plot.replot(); + curve->setSamples(xData, yData, plotDataSize); + plot->replot(); // set the thermometer value - thermo.setValue( inVal + 10 ); + thermo->setValue( inVal + 10 ); } diff --git a/window.h b/window.h index e511d40..c9bd185 100644 --- a/window.h +++ b/window.h @@ -8,6 +8,8 @@ #include +#include "adcreader.h" + // class definition 'Window' class Window : public QWidget { @@ -17,6 +19,8 @@ class Window : public QWidget public: Window(); // default constructor - called when a Window is declared without arguments + ~Window(); + void timerEvent( QTimerEvent * ); public slots: @@ -24,15 +28,14 @@ public slots: // internal variables for the window class private: - // graphical elements from the Qwt library - http://qwt.sourceforge.net/annotated.html - QwtKnob knob; - QwtThermo thermo; - QwtPlot plot; - QwtPlotCurve curve; + QwtKnob *knob; + QwtThermo *thermo; + QwtPlot *plot; + QwtPlotCurve *curve; // layout elements from Qt itself http://qt-project.org/doc/qt-4.8/classes.html - QVBoxLayout vLayout; // vertical layout - QHBoxLayout hLayout; // horizontal layout + QVBoxLayout *vLayout; // vertical layout + QHBoxLayout *hLayout; // horizontal layout static const int plotDataSize = 100; @@ -42,6 +45,8 @@ public slots: double gain; int count; + + ADCreader *adcreader; }; #endif // WINDOW_H From 9d5571edffc6db8d74279473ba47b9bb454b7659 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Fri, 21 Feb 2014 11:17:27 +0000 Subject: [PATCH 02/35] Forgotten to add the files! --- adcreader.cpp | 17 +++++++++++++++++ adcreader.h | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 adcreader.cpp create mode 100644 adcreader.h diff --git a/adcreader.cpp b/adcreader.cpp new file mode 100644 index 0000000..b978cf2 --- /dev/null +++ b/adcreader.cpp @@ -0,0 +1,17 @@ +#include "adcreader.h" +#include + +void ADCreader::run() +{ + running = true; + while (running) { + qDebug() << "Tick"; + sleep(1); + } +} + +void ADCreader::quit() +{ + running = false; + exit(0); +} diff --git a/adcreader.h b/adcreader.h new file mode 100644 index 0000000..91c9c6b --- /dev/null +++ b/adcreader.h @@ -0,0 +1,17 @@ +#ifndef ADCREADER +#define ADCREADER + +#include + +class ADCreader : public QThread +{ +public: + ADCreader() {running = 0;}; + void quit(); + void run(); +private: + bool running; + +}; + +#endif From 5329a02b30d9c9bfb7d3481fdae3f1eb86b44806 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Sat, 22 Feb 2014 18:12:04 +0000 Subject: [PATCH 03/35] Deactivated the adcreader. --- window.cpp | 12 ++++++------ window.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/window.cpp b/window.cpp index f1daee8..f8104e2 100644 --- a/window.cpp +++ b/window.cpp @@ -1,5 +1,5 @@ #include "window.h" -#include "adcreader.h" +// #include "adcreader.h" #include // for sine stuff @@ -55,16 +55,16 @@ Window::Window() : gain(5), count(0) // At the moment it doesn't do anything else than // running in an endless loop and which prints out "tick" // every second. - adcreader = new ADCreader(); - adcreader->start(); +// adcreader = new ADCreader(); +// adcreader->start(); } Window::~Window() { // tells the thread to no longer run its endless loop - adcreader->quit(); +// adcreader->quit(); // wait until the run method has terminated - adcreader->wait(); - delete adcreader; +// adcreader->wait(); +// delete adcreader; } void Window::timerEvent( QTimerEvent * ) diff --git a/window.h b/window.h index c9bd185..2b182f2 100644 --- a/window.h +++ b/window.h @@ -8,7 +8,7 @@ #include -#include "adcreader.h" +// #include "adcreader.h" // class definition 'Window' class Window : public QWidget @@ -46,7 +46,7 @@ public slots: double gain; int count; - ADCreader *adcreader; +// ADCreader *adcreader; }; #endif // WINDOW_H From 8ad887051b53ab22ec48645abb8ecd055d999d14 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 15 Feb 2017 12:20:47 +0000 Subject: [PATCH 04/35] SetRange no longer exists. --- window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window.cpp b/window.cpp index f8104e2..e1e0598 100644 --- a/window.cpp +++ b/window.cpp @@ -17,7 +17,7 @@ Window::Window() : gain(5), count(0) // set up the thermometer thermo = new QwtThermo; thermo->setFillBrush( QBrush(Qt::red) ); - thermo->setRange(0, 20); + //thermo->setRange(0, 20); thermo->show(); From d7eccb532bde281e23e3656c8f8119393fc63688 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Fri, 24 Feb 2017 11:51:17 +0000 Subject: [PATCH 05/35] Crashed under QT5 because it loaded the QT4 QWT library. --- QwtExample.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/QwtExample.pro b/QwtExample.pro index a9212e5..3a563e6 100644 --- a/QwtExample.pro +++ b/QwtExample.pro @@ -8,7 +8,8 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = QwtExample -LIBS += -lqwt -lm +greaterThan(QT_MAJOR_VERSION, 4): LIBS += -lqwt-qt5 -lm +lessThan(QT_MAJOR_VERSION, 5): LIBS += -lqwt -lm HEADERS += window.h adcreader.h From e8dd1e386fcb48dce256ba36500a343bde150613 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 1 Feb 2018 22:24:14 +0000 Subject: [PATCH 06/35] Updated links --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8d67282..50b4e32 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,8 @@ QwtExample A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. Qt is a cross platform framework for developing graphical applications, for more information please visit the links below: -* [Qt Homepage](http://qt-project.org/) -* [Qt 4.8 Class List](http://qt-project.org/doc/qt-4.8/classes.html) +* [Qt5 Homepage](https://www.qt.io/) * [Wikpedia](http://en.wikipedia.org/wiki/Qt_%28framework%29) -* [Signals and Slots](http://qt-project.org/doc/qt-4.8/signalsandslots.html) Qwt is a technical widget library based on Qt, please see: * [Qwt Hompage](http://qwt.sourceforge.net/) @@ -29,3 +27,8 @@ To build: To run (assuming you are logged into the RPi over ssh and no X-server is running): startx ./QwtExample + +or with X running + + ./QwtExample + From d25effd9188e5f0e75f473c780cdc899441fa29d Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 28 Feb 2018 19:26:11 +0000 Subject: [PATCH 07/35] Added reference to qwt --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 50b4e32..6678af6 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,15 @@ QwtExample =========== -A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. +A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. It also creates a Thread which could be used to aquire the data with the help of poll/select. -Qt is a cross platform framework for developing graphical applications, for more information please visit the links below: -* [Qt5 Homepage](https://www.qt.io/) -* [Wikpedia](http://en.wikipedia.org/wiki/Qt_%28framework%29) +Making it work +-------------- -Qwt is a technical widget library based on Qt, please see: -* [Qwt Hompage](http://qwt.sourceforge.net/) +Install QT5 development files and the Qwt development libraries: + apt-get install libqwt-qt5-dev -Making it work --------------- To clone the git repository: From ede255053dc3bf302f58bd950c5e9e99c3f8028a Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 28 Feb 2018 19:29:20 +0000 Subject: [PATCH 08/35] Added package reference to QT5 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6678af6..d82fd1b 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,10 @@ A simple example program using Qt/Qwt widgets to be used as a base for students Making it work -------------- -Install QT5 development files and the Qwt development libraries: +Install the QT5 and Qwt development packages: - apt-get install libqwt-qt5-dev + apt-get install qtdeclarative5-dev-tools + apt-get install libqwt-qt5-dev To clone the git repository: From 192a7d10be14bc002b64ae430420de50364f43c3 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 28 Feb 2018 19:33:41 +0000 Subject: [PATCH 09/35] Added screenshot --- README.md | 2 ++ screenshot.png | Bin 0 -> 15386 bytes 2 files changed, 2 insertions(+) create mode 100644 screenshot.png diff --git a/README.md b/README.md index d82fd1b..0b8a35b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ QwtExample A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. It also creates a Thread which could be used to aquire the data with the help of poll/select. +![alt tag](screenshot.png) + Making it work -------------- diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b0d794fae09805837fdee67bcbb39ae996f014 GIT binary patch literal 15386 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 literal 0 HcmV?d00001 From ddda7e4b2ea8523b919f131d07badcddc04519ce Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 28 Feb 2018 19:35:31 +0000 Subject: [PATCH 10/35] Fixed formatting --- README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0b8a35b..af9793c 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,40 @@ -QwtExample -=========== +# QwtExample A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. It also creates a Thread which could be used to aquire the data with the help of poll/select. ![alt tag](screenshot.png) -Making it work --------------- +# Making it work Install the QT5 and Qwt development packages: - apt-get install qtdeclarative5-dev-tools - apt-get install libqwt-qt5-dev - +``` + apt-get install qtdeclarative5-dev-tools + apt-get install libqwt-qt5-dev +``` To clone the git repository: +``` git clone https://github.com/glasgow-bio/qwt-example +``` To build: +``` cd qwt-example qmake make +``` To run (assuming you are logged into the RPi over ssh and no X-server is running): +``` startx ./QwtExample +``` or with X running +``` ./QwtExample - +``` From ef4da6791b51dd40cc6df33ca920388414308921 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 28 Feb 2018 19:37:01 +0000 Subject: [PATCH 11/35] Fixed spelling mishtake! --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index af9793c..45e50a9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # QwtExample -A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. It also creates a Thread which could be used to aquire the data with the help of poll/select. +A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. It also creates a Thread which could be used to acquire ADC data with the help of poll/select and storing it in a ringbuffer. ![alt tag](screenshot.png) -# Making it work +## Making it work Install the QT5 and Qwt development packages: From 97e960d85575ed88702aefdeb62bf67f74d30c91 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 12 Feb 2020 15:58:38 +0000 Subject: [PATCH 12/35] Fixed old link. --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 45e50a9..23c6275 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,7 @@ Install the QT5 and Qwt development packages: apt-get install libqwt-qt5-dev ``` -To clone the git repository: - -``` - git clone https://github.com/glasgow-bio/qwt-example -``` +To clone this git repository. To build: From 71ee77f8f7cce6cc088187068d0eb301ae44ab1c Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 20 Jan 2021 13:02:33 +0000 Subject: [PATCH 13/35] Removed the ref to startx --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index 23c6275..f5e169c 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,7 @@ To build: make ``` -To run (assuming you are logged into the RPi over ssh and no X-server is running): - -``` - startx ./QwtExample -``` - -or with X running +To run: ``` ./QwtExample From c36ddc85bf71b0ff80376a2ff09b6be270a5642a Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 20 Jan 2021 14:34:09 +0000 Subject: [PATCH 14/35] Added nice comment --- main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/main.cpp b/main.cpp index cd0103a..7a6891c 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,7 @@ #include +// Main program int main(int argc, char *argv[]) { QApplication app(argc, argv); From 26004b889b4d71d5206c4dabcea650d17090a372 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 28 Jan 2021 09:14:56 +0000 Subject: [PATCH 15/35] Changed to CMake --- CMakeLists.txt | 26 ++++++++++++++++++++++++++ QwtExample.pro | 16 ---------------- README.md | 6 +++--- adcreader.cpp | 17 ----------------- adcreader.h | 17 ----------------- main.cpp | 2 +- 6 files changed, 30 insertions(+), 54 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 QwtExample.pro delete mode 100644 adcreader.cpp delete mode 100644 adcreader.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..513060b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.1.0) + +project(analogclock VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(CMAKE_VERSION VERSION_LESS "3.7.0") + set(CMAKE_INCLUDE_CURRENT_DIR ON) +endif() + +find_package(Qt5 COMPONENTS Widgets REQUIRED) + +add_executable(qwt-example + window.cpp + main.cpp +) + +target_link_libraries(qwt-example Qt5::Widgets) +target_link_libraries(qwt-example qwt-qt5) + +install(TARGETS qwt-example) diff --git a/QwtExample.pro b/QwtExample.pro deleted file mode 100644 index 3a563e6..0000000 --- a/QwtExample.pro +++ /dev/null @@ -1,16 +0,0 @@ -# Qt project file - qmake uses his to generate a Makefile - -QT += core gui - -CONFIG += qt warn_on debug - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = QwtExample - -greaterThan(QT_MAJOR_VERSION, 4): LIBS += -lqwt-qt5 -lm -lessThan(QT_MAJOR_VERSION, 5): LIBS += -lqwt -lm - -HEADERS += window.h adcreader.h - -SOURCES += main.cpp window.cpp adcreader.cpp diff --git a/README.md b/README.md index f5e169c..9c99c70 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # QwtExample -A simple example program using Qt/Qwt widgets to be used as a base for students doing Raspberry Pi data acquisition. It also creates a Thread which could be used to acquire ADC data with the help of poll/select and storing it in a ringbuffer. +A simple example program using Qt/Qwt widgets. ![alt tag](screenshot.png) @@ -19,12 +19,12 @@ To build: ``` cd qwt-example - qmake + cmake . make ``` To run: ``` - ./QwtExample + ./qwt-example ``` diff --git a/adcreader.cpp b/adcreader.cpp deleted file mode 100644 index b978cf2..0000000 --- a/adcreader.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "adcreader.h" -#include - -void ADCreader::run() -{ - running = true; - while (running) { - qDebug() << "Tick"; - sleep(1); - } -} - -void ADCreader::quit() -{ - running = false; - exit(0); -} diff --git a/adcreader.h b/adcreader.h deleted file mode 100644 index 91c9c6b..0000000 --- a/adcreader.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ADCREADER -#define ADCREADER - -#include - -class ADCreader : public QThread -{ -public: - ADCreader() {running = 0;}; - void quit(); - void run(); -private: - bool running; - -}; - -#endif diff --git a/main.cpp b/main.cpp index 7a6891c..3e339d1 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,4 @@ -#include +#include "window.h" #include From 793dc265090c473b15060fa791065443b45d9beb Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 2 Feb 2021 01:20:02 +0000 Subject: [PATCH 16/35] Min cmake vers is now 3.7.0 --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 513060b..839b9e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1.0) +cmake_minimum_required(VERSION 3.7.0) project(analogclock VERSION 1.0.0 LANGUAGES CXX) @@ -9,10 +9,6 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) -if(CMAKE_VERSION VERSION_LESS "3.7.0") - set(CMAKE_INCLUDE_CURRENT_DIR ON) -endif() - find_package(Qt5 COMPONENTS Widgets REQUIRED) add_executable(qwt-example From e163b44495f663276736381750627d1c89746ecf Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Sat, 20 Feb 2021 12:30:09 +0000 Subject: [PATCH 17/35] Fixed some leftovers in the readme --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9c99c70..cd43ad2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A simple example program using Qt/Qwt widgets. ![alt tag](screenshot.png) -## Making it work +## Required packages Install the QT5 and Qwt development packages: @@ -13,9 +13,7 @@ Install the QT5 and Qwt development packages: apt-get install libqwt-qt5-dev ``` -To clone this git repository. - -To build: +## Build it ``` cd qwt-example @@ -23,7 +21,7 @@ To build: make ``` -To run: +## Run it ``` ./qwt-example From b4ca288bf22a97cdd5aadbb6127f4214e46ceea1 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Sat, 20 Feb 2021 13:21:46 +0000 Subject: [PATCH 18/35] Showing it in the size as needed! --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 3e339d1..0af68d0 100644 --- a/main.cpp +++ b/main.cpp @@ -9,7 +9,7 @@ int main(int argc, char *argv[]) // create the window Window window; - window.showMaximized(); + window.show(); // call the window.timerEvent function every 40 ms window.startTimer(40); From b8c20e5e3372907e81c3fd88fa6636d4a894b866 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Sat, 20 Feb 2021 13:27:54 +0000 Subject: [PATCH 19/35] Got rid of a few leftovers --- window.cpp | 17 ----------------- window.h | 6 ------ 2 files changed, 23 deletions(-) diff --git a/window.cpp b/window.cpp index e1e0598..948bebb 100644 --- a/window.cpp +++ b/window.cpp @@ -1,5 +1,4 @@ #include "window.h" -// #include "adcreader.h" #include // for sine stuff @@ -49,22 +48,6 @@ Window::Window() : gain(5), count(0) hLayout->addWidget(plot); setLayout(hLayout); - - // This is a demo for a thread which can be - // used to read from the ADC asynchronously. - // At the moment it doesn't do anything else than - // running in an endless loop and which prints out "tick" - // every second. -// adcreader = new ADCreader(); -// adcreader->start(); -} - -Window::~Window() { - // tells the thread to no longer run its endless loop -// adcreader->quit(); - // wait until the run method has terminated -// adcreader->wait(); -// delete adcreader; } void Window::timerEvent( QTimerEvent * ) diff --git a/window.h b/window.h index 2b182f2..3ef8b60 100644 --- a/window.h +++ b/window.h @@ -8,8 +8,6 @@ #include -// #include "adcreader.h" - // class definition 'Window' class Window : public QWidget { @@ -19,8 +17,6 @@ class Window : public QWidget public: Window(); // default constructor - called when a Window is declared without arguments - ~Window(); - void timerEvent( QTimerEvent * ); public slots: @@ -45,8 +41,6 @@ public slots: double gain; int count; - -// ADCreader *adcreader; }; #endif // WINDOW_H From 33c12fda2ea31ff3b4b0c8b6315d62ba1a26d3c4 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 8 Mar 2022 21:33:53 +0000 Subject: [PATCH 20/35] got rid of signal & slot --- window.cpp | 34 +++++++++++++++------------------- window.h | 8 ++++---- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/window.cpp b/window.cpp index 948bebb..52e90ce 100644 --- a/window.cpp +++ b/window.cpp @@ -5,14 +5,6 @@ Window::Window() : gain(5), count(0) { - knob = new QwtKnob; - // set up the gain knob - knob->setValue(gain); - - // use the Qt signals/slots framework to update the gain - - // every time the knob is moved, the setGain function will be called - connect( knob, SIGNAL(valueChanged(double)), SLOT(setGain(double)) ); - // set up the thermometer thermo = new QwtThermo; thermo->setFillBrush( QBrush(Qt::red) ); @@ -36,20 +28,32 @@ Window::Window() : gain(5), count(0) plot->replot(); plot->show(); + button = new QPushButton("Reset"); + connect(button,&QPushButton::clicked,this,[this](){reset();}); // set up the layout - knob above thermometer - vLayout = new QVBoxLayout; - vLayout->addWidget(knob); + vLayout = new QVBoxLayout(); + vLayout->addWidget(button); vLayout->addWidget(thermo); // plot to the left of knob and thermometer - hLayout = new QHBoxLayout; + hLayout = new QHBoxLayout(); hLayout->addLayout(vLayout); hLayout->addWidget(plot); setLayout(hLayout); } +void Window::reset() { + // set up the initial plot data + for( int index=0; indexsetValue( inVal + 10 ); } - - -// this function can be used to change the gain of the A/D internal amplifier -void Window::setGain(double gain) -{ - // for example purposes just change the amplitude of the generated input - this->gain = gain; -} diff --git a/window.h b/window.h index 3ef8b60..5cbffc3 100644 --- a/window.h +++ b/window.h @@ -7,6 +7,7 @@ #include #include +#include // class definition 'Window' class Window : public QWidget @@ -19,12 +20,9 @@ class Window : public QWidget void timerEvent( QTimerEvent * ); -public slots: - void setGain(double gain); - // internal variables for the window class private: - QwtKnob *knob; + QPushButton *button; QwtThermo *thermo; QwtPlot *plot; QwtPlotCurve *curve; @@ -41,6 +39,8 @@ public slots: double gain; int count; + + void reset(); }; #endif // WINDOW_H From 4cdc14517298f8f16bb9854f739c368488a318c9 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 8 Mar 2022 21:36:54 +0000 Subject: [PATCH 21/35] New screenshot --- screenshot.png | Bin 15386 -> 22044 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/screenshot.png b/screenshot.png index f3b0d794fae09805837fdee67bcbb39ae996f014..e2f7b5537e0597cf96c81a11a354763b6d61f007 100644 GIT binary patch literal 22044 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 X4HTBAx`%m#_kOS5Uq8jJ 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 From fcc1c8eca1c1f2c922dcf5bc65e05d80d5df13ad Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 8 Mar 2022 21:57:40 +0000 Subject: [PATCH 22/35] Fixed range --- window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/window.cpp b/window.cpp index 52e90ce..c747a42 100644 --- a/window.cpp +++ b/window.cpp @@ -3,12 +3,12 @@ #include // for sine stuff -Window::Window() : gain(5), count(0) +Window::Window() : gain(7.5), count(0) { // set up the thermometer thermo = new QwtThermo; thermo->setFillBrush( QBrush(Qt::red) ); - //thermo->setRange(0, 20); + thermo->setScale(0, 10); thermo->show(); @@ -66,5 +66,5 @@ void Window::timerEvent( QTimerEvent * ) plot->replot(); // set the thermometer value - thermo->setValue( inVal + 10 ); + thermo->setValue( fabs(inVal) ); } From 0416023f1a58337d095f204994f9458063ed92db Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 8 Mar 2022 22:02:34 +0000 Subject: [PATCH 23/35] Moved var init into the class --- window.cpp | 6 +++--- window.h | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/window.cpp b/window.cpp index c747a42..f2f6ceb 100644 --- a/window.cpp +++ b/window.cpp @@ -3,7 +3,7 @@ #include // for sine stuff -Window::Window() : gain(7.5), count(0) +Window::Window() { // set up the thermometer thermo = new QwtThermo; @@ -31,12 +31,12 @@ Window::Window() : gain(7.5), count(0) button = new QPushButton("Reset"); connect(button,&QPushButton::clicked,this,[this](){reset();}); - // set up the layout - knob above thermometer + // set up the layout - button above thermometer vLayout = new QVBoxLayout(); vLayout->addWidget(button); vLayout->addWidget(thermo); - // plot to the left of knob and thermometer + // plot to the left of button and thermometer hLayout = new QHBoxLayout(); hLayout->addLayout(vLayout); hLayout->addWidget(plot); diff --git a/window.h b/window.h index 5cbffc3..aa05b0d 100644 --- a/window.h +++ b/window.h @@ -2,7 +2,6 @@ #define WINDOW_H #include -#include #include #include @@ -22,6 +21,9 @@ class Window : public QWidget // internal variables for the window class private: + static constexpr int plotDataSize = 100; + static constexpr double gain = 7.5; + QPushButton *button; QwtThermo *thermo; QwtPlot *plot; @@ -31,14 +33,11 @@ class Window : public QWidget QVBoxLayout *vLayout; // vertical layout QHBoxLayout *hLayout; // horizontal layout - static const int plotDataSize = 100; - // data arrays for the plot double xData[plotDataSize]; double yData[plotDataSize]; - double gain; - int count; + long count = 0; void reset(); }; From 2e4be21bc1d6b4e368bf673a417cffa097fc9ed9 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 8 Mar 2022 23:05:44 +0000 Subject: [PATCH 24/35] No need of a lambda function. --- window.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/window.cpp b/window.cpp index f2f6ceb..4ecabac 100644 --- a/window.cpp +++ b/window.cpp @@ -29,7 +29,8 @@ Window::Window() plot->show(); button = new QPushButton("Reset"); - connect(button,&QPushButton::clicked,this,[this](){reset();}); + // see https://doc.qt.io/qt-5/signalsandslots-syntaxes.html + connect(button,&QPushButton::clicked,this,&Window::reset); // set up the layout - button above thermometer vLayout = new QVBoxLayout(); From d7d6e6ae2201152afc82de8b02bede3bc436712e Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 9 Mar 2022 07:45:10 +0000 Subject: [PATCH 25/35] Fixed a few spelling issues. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index cd43ad2..b17e616 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # QwtExample -A simple example program using Qt/Qwt widgets. +A simple example program using QT and Qwt widgets. ![alt tag](screenshot.png) @@ -16,7 +16,6 @@ Install the QT5 and Qwt development packages: ## Build it ``` - cd qwt-example cmake . make ``` From 324884f899ec8d3b0b24c1fabf5cffc5f4fad7ba Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 10 Mar 2022 10:12:09 +0000 Subject: [PATCH 26/35] Old project name fixed. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 839b9e1..6e42899 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.7.0) -project(analogclock VERSION 1.0.0 LANGUAGES CXX) +project(qwt-example-app VERSION 1.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) From fe35fae75d94b0fea34544fd93ab42b1a718622e Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 21 Apr 2022 14:41:10 +0100 Subject: [PATCH 27/35] Removed the old memmove command --- window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/window.cpp b/window.cpp index 4ecabac..d4728bb 100644 --- a/window.cpp +++ b/window.cpp @@ -16,7 +16,7 @@ Window::Window() for( int index=0; indexsetSamples(xData, yData, plotDataSize); plot->replot(); From 8ddd5448535dbd880a3176bca640f5bf585c2e64 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 8 Feb 2024 11:43:26 +0000 Subject: [PATCH 28/35] Now with cpp timer --- CppTimer.h | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++ window.cpp | 114 +++++++++++++++++++------------------ window.h | 56 ++++++++++++------ 3 files changed, 259 insertions(+), 73 deletions(-) create mode 100644 CppTimer.h diff --git a/CppTimer.h b/CppTimer.h new file mode 100644 index 0000000..deaa6bf --- /dev/null +++ b/CppTimer.h @@ -0,0 +1,162 @@ +#ifndef __CPP_TIMER_H_ +#define __CPP_TIMER_H_ + +/** + * GNU GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * (C) 2020-2024, Bernd Porr + * + * This is inspired by the timer_create man page. + **/ + +#include +#include +#include +#include +#include +#include + +/** + * Enumeration of CppTimer types + **/ +enum cppTimerType_t +{ + PERIODIC, + ONESHOT +}; + +/** + * Timer class which repeatedly fires. It's wrapper around the + * POSIX per-process timer. + **/ +class CppTimer +{ + +public: + /** + * Starts the timer. The timer fires first after + * the specified time in nanoseconds and then at + * that interval in PERIODIC mode. In ONESHOT mode + * the timer fires once after the specified time in + * nanoseconds. + * @param nanosecs Time in nanoseconds + * @param type Either PERIODIC or ONESHOT + **/ + virtual void startns(long nanosecs, cppTimerType_t type = PERIODIC) { + if (running) return; + fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd < 0) + throw("Could not start timer"); + switch (type) + { + case (PERIODIC): + //starts after specified period of nanoseconds + its.it_value.tv_sec = nanosecs / 1000000000; + its.it_value.tv_nsec = nanosecs % 1000000000; + its.it_interval.tv_sec = nanosecs / 1000000000; + its.it_interval.tv_nsec = nanosecs % 1000000000; + break; + case (ONESHOT): + //fires once after specified period of nanoseconds + its.it_value.tv_sec = nanosecs / 1000000000; + its.it_value.tv_nsec = nanosecs % 1000000000; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + break; + } + if (timerfd_settime(fd, 0, &its, NULL) == -1) + throw("Could not start timer"); + uthread = std::thread(&CppTimer::worker,this); + } + + /** + * Starts the timer. The timer fires first after + * the specified time in milliseconds and then at + * that interval in PERIODIC mode. In ONESHOT mode + * the timer fires once after the specified time in + * milliseconds. + * @param millisecs Time in milliseconds + * @param type Either PERIODIC or ONESHOT + **/ + virtual void startms(long millisecs, cppTimerType_t type = PERIODIC) { + if (running) return; + fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd < 0) + throw("Could not start timer"); + switch (type) + { + case (PERIODIC): + //starts after specified period of milliseconds + its.it_value.tv_sec = millisecs / 1000; + its.it_value.tv_nsec = (millisecs % 1000) * 1000000; + its.it_interval.tv_sec = millisecs / 1000; + its.it_interval.tv_nsec = (millisecs % 1000) * 1000000; + break; + case (ONESHOT): + //fires once after specified period of milliseconds + its.it_value.tv_sec = millisecs / 1000; + its.it_value.tv_nsec = (millisecs % 1000) * 1000000; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + break; + } + if (timerfd_settime(fd, 0, &its, NULL) == -1) + throw("Could not start timer"); + uthread = std::thread(&CppTimer::worker,this); + } + + /** + * Stops the timer by disarming it. It can be re-started + * with start(). + **/ + virtual void stop() { + if (!running) return; + running = false; + uthread.join(); + } + + /** + * Destructor disarms the timer, deletes it and + * disconnect the signal handler. + **/ + virtual ~CppTimer() { + stop(); + } + +protected: + /** + * Abstract function which needs to be implemented by the children. + * This is called every time the timer fires. + **/ + virtual void timerEvent() = 0; + +private: + int fd = 0; + struct itimerspec its; + bool running = false; + std::thread uthread; + void worker() { + running = true; + while (running) { + uint64_t exp; + const long int s = read(fd, &exp, sizeof(uint64_t)); + if (s != sizeof(uint64_t) ) { + running = false; + return; + } + timerEvent(); + } + // disarm + struct itimerspec itsnew; + itsnew.it_value.tv_sec = 0; + itsnew.it_value.tv_nsec = 0; + itsnew.it_interval.tv_sec = 0; + itsnew.it_interval.tv_nsec = 0; + timerfd_settime(fd, 0, &itsnew, &its); + close(fd); + fd = -1; + } +}; + +#endif diff --git a/window.cpp b/window.cpp index d4728bb..270a9d2 100644 --- a/window.cpp +++ b/window.cpp @@ -5,67 +5,71 @@ Window::Window() { - // set up the thermometer - thermo = new QwtThermo; - thermo->setFillBrush( QBrush(Qt::red) ); - thermo->setScale(0, 10); - thermo->show(); - - - // set up the initial plot data - for( int index=0; indexsetSamples(xData, yData, plotDataSize); - curve->attach(plot); - - plot->replot(); - plot->show(); - - button = new QPushButton("Reset"); - // see https://doc.qt.io/qt-5/signalsandslots-syntaxes.html - connect(button,&QPushButton::clicked,this,&Window::reset); - - // set up the layout - button above thermometer - vLayout = new QVBoxLayout(); - vLayout->addWidget(button); - vLayout->addWidget(thermo); - - // plot to the left of button and thermometer - hLayout = new QHBoxLayout(); - hLayout->addLayout(vLayout); - hLayout->addWidget(plot); - - setLayout(hLayout); + fakeSensor.window = this; + + // set up the thermometer + thermo = new QwtThermo; + thermo->setFillBrush( QBrush(Qt::red) ); + thermo->setScale(0, 10); + thermo->show(); + + + // set up the initial plot data + for( int index=0; indexsetSamples(xData, yData, plotDataSize); + curve->attach(plot); + + plot->setAxisScale(QwtPlot::yLeft,-10,10); + plot->replot(); + plot->show(); + + button = new QPushButton("Reset"); + // see https://doc.qt.io/qt-5/signalsandslots-syntaxes.html + connect(button,&QPushButton::clicked,this,&Window::reset); + + // set up the layout - button above thermometer + vLayout = new QVBoxLayout(); + vLayout->addWidget(button); + vLayout->addWidget(thermo); + + // plot to the left of button and thermometer + hLayout = new QHBoxLayout(); + hLayout->addLayout(vLayout); + hLayout->addWidget(plot); + + setLayout(hLayout); + + fakeSensor.startms(5); } void Window::reset() { - // set up the initial plot data - for( int index=0; indexsetSamples(xData, yData, plotDataSize); + thermo->setValue( fabs(inVal) ); +} + void Window::timerEvent( QTimerEvent * ) { - double inVal = gain * sin( M_PI * count/50.0 ); - ++count; - - // add the new input to the plot - std::move( yData, yData + plotDataSize - 1, yData+1 ); - yData[0] = inVal; - curve->setSamples(xData, yData, plotDataSize); - plot->replot(); - - // set the thermometer value - thermo->setValue( fabs(inVal) ); + plot->replot(); + update(); } diff --git a/window.h b/window.h index aa05b0d..bade6fa 100644 --- a/window.h +++ b/window.h @@ -8,38 +8,58 @@ #include #include +#include "CppTimer.h" + // class definition 'Window' class Window : public QWidget { - // must include the Q_OBJECT macro for for the Qt signals/slots framework to work with this class - Q_OBJECT + // must include the Q_OBJECT macro for for the Qt signals/slots framework to work with this class + Q_OBJECT + + + class FakeSensor : public CppTimer { + static constexpr double gain = 7.5; + public: + Window* window = nullptr; + int count = 0; + void timerEvent() { + double inVal = gain * sin( M_PI * count / 50.0 ); + window->hasData(inVal); + ++count; + } + }; + public: - Window(); // default constructor - called when a Window is declared without arguments + Window(); // default constructor - called when a Window is declared without arguments - void timerEvent( QTimerEvent * ); + void timerEvent( QTimerEvent * ); // internal variables for the window class private: - static constexpr int plotDataSize = 100; - static constexpr double gain = 7.5; + static constexpr int plotDataSize = 100; + + QPushButton *button; + QwtThermo *thermo; + QwtPlot *plot; + QwtPlotCurve *curve; + + - QPushButton *button; - QwtThermo *thermo; - QwtPlot *plot; - QwtPlotCurve *curve; + // layout elements from Qt itself http://qt-project.org/doc/qt-4.8/classes.html + QVBoxLayout *vLayout; // vertical layout + QHBoxLayout *hLayout; // horizontal layout - // layout elements from Qt itself http://qt-project.org/doc/qt-4.8/classes.html - QVBoxLayout *vLayout; // vertical layout - QHBoxLayout *hLayout; // horizontal layout + FakeSensor fakeSensor; - // data arrays for the plot - double xData[plotDataSize]; - double yData[plotDataSize]; + // data arrays for the plot + double xData[plotDataSize]; + double yData[plotDataSize]; - long count = 0; + long count = 0; - void reset(); + void reset(); + void hasData(double v); }; #endif // WINDOW_H From a9c438c87e68fa7756190a3b6ef4c1ba52910e35 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 8 Feb 2024 12:05:02 +0000 Subject: [PATCH 29/35] Stopping sensor on exit. --- window.cpp | 4 ++++ window.h | 1 + 2 files changed, 5 insertions(+) diff --git a/window.cpp b/window.cpp index 270a9d2..3a21e82 100644 --- a/window.cpp +++ b/window.cpp @@ -50,6 +50,10 @@ Window::Window() fakeSensor.startms(5); } +Window::~Window() { + fakeSensor.stop(); +} + void Window::reset() { // set up the initial plot data for( int index=0; index Date: Thu, 8 Feb 2024 15:17:09 +0000 Subject: [PATCH 30/35] Added mutex --- window.cpp | 8 ++++++-- window.h | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/window.cpp b/window.cpp index 3a21e82..5fdc971 100644 --- a/window.cpp +++ b/window.cpp @@ -65,15 +65,19 @@ void Window::reset() { void Window::hasData(double inVal) { + mtx.lock(); // add the new input to the plot std::move( yData, yData + plotDataSize - 1, yData+1 ); yData[0] = inVal; - curve->setSamples(xData, yData, plotDataSize); - thermo->setValue( fabs(inVal) ); + mtx.unlock(); } void Window::timerEvent( QTimerEvent * ) { + mtx.lock(); + curve->setSamples(xData, yData, plotDataSize); + thermo->setValue( fabs(yData[0]) ); plot->replot(); update(); + mtx.unlock(); } diff --git a/window.h b/window.h index ce387a8..e5b23aa 100644 --- a/window.h +++ b/window.h @@ -8,6 +8,8 @@ #include #include +#include + #include "CppTimer.h" // class definition 'Window' @@ -61,6 +63,8 @@ class Window : public QWidget void reset(); void hasData(double v); + + std::mutex mtx; }; #endif // WINDOW_H From 6b01141c2bf4ab51ae218ab4bda3da8989470fa5 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Sun, 11 Feb 2024 23:39:05 +0000 Subject: [PATCH 31/35] Moved both timing measures into window.cpp --- main.cpp | 3 --- window.cpp | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main.cpp b/main.cpp index 0af68d0..21fa4e9 100644 --- a/main.cpp +++ b/main.cpp @@ -11,9 +11,6 @@ int main(int argc, char *argv[]) Window window; window.show(); - // call the window.timerEvent function every 40 ms - window.startTimer(40); - // execute the application return app.exec(); } diff --git a/window.cpp b/window.cpp index 5fdc971..86e52db 100644 --- a/window.cpp +++ b/window.cpp @@ -47,7 +47,10 @@ Window::Window() setLayout(hLayout); - fakeSensor.startms(5); + // a fake data sample every 10ms + fakeSensor.startms(10); + // Screen refresh every 40ms + startTimer(40); } Window::~Window() { From 15a3cf7504c923b2e964827144fd46970b89533f Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Sun, 11 Feb 2024 23:42:01 +0000 Subject: [PATCH 32/35] Moved the mutex closer to the action! --- window.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/window.cpp b/window.cpp index 86e52db..2cb6891 100644 --- a/window.cpp +++ b/window.cpp @@ -67,20 +67,21 @@ void Window::reset() { } +// add the new input to the plot void Window::hasData(double inVal) { mtx.lock(); - // add the new input to the plot std::move( yData, yData + plotDataSize - 1, yData+1 ); yData[0] = inVal; mtx.unlock(); } +// screen refresh void Window::timerEvent( QTimerEvent * ) { mtx.lock(); curve->setSamples(xData, yData, plotDataSize); thermo->setValue( fabs(yData[0]) ); + mtx.unlock(); plot->replot(); update(); - mtx.unlock(); } From 6d08e757c493c0df724744af019507bee9b63384 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Fri, 31 Jan 2025 17:07:41 +0000 Subject: [PATCH 33/35] Added a separate class for the fake sensor --- fakesensor.h | 20 ++++++++++++++++++++ window.cpp | 8 +++----- window.h | 22 +++------------------- 3 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 fakesensor.h diff --git a/fakesensor.h b/fakesensor.h new file mode 100644 index 0000000..db06419 --- /dev/null +++ b/fakesensor.h @@ -0,0 +1,20 @@ +#ifndef __FAKESENSOR_H +#define __FAKESENSOR_H + +#include "CppTimer.h" +#include + +class FakeSensor : public CppTimer { + public: + virtual void fakeSensorHasData(double inVal) = 0; + void timerEvent() { + const double inVal = gain * sin( M_PI * (float)(count++) / 50.0 ); + fakeSensorHasData(inVal); + } + private: + int count = 0; + static constexpr double gain = 7.5; +}; + + +#endif diff --git a/window.cpp b/window.cpp index 2cb6891..b6f94bc 100644 --- a/window.cpp +++ b/window.cpp @@ -4,9 +4,7 @@ Window::Window() -{ - fakeSensor.window = this; - +{ // set up the thermometer thermo = new QwtThermo; thermo->setFillBrush( QBrush(Qt::red) ); @@ -48,13 +46,13 @@ Window::Window() setLayout(hLayout); // a fake data sample every 10ms - fakeSensor.startms(10); + FakeSensor::startms(10); // Screen refresh every 40ms startTimer(40); } Window::~Window() { - fakeSensor.stop(); + FakeSensor::stop(); } void Window::reset() { diff --git a/window.h b/window.h index e5b23aa..bfb98c0 100644 --- a/window.h +++ b/window.h @@ -10,27 +10,13 @@ #include -#include "CppTimer.h" +#include "fakesensor.h" // class definition 'Window' -class Window : public QWidget +class Window : public QWidget, FakeSensor { // must include the Q_OBJECT macro for for the Qt signals/slots framework to work with this class Q_OBJECT - - - class FakeSensor : public CppTimer { - static constexpr double gain = 7.5; - public: - Window* window = nullptr; - int count = 0; - void timerEvent() { - double inVal = gain * sin( M_PI * count / 50.0 ); - window->hasData(inVal); - ++count; - } - }; - public: Window(); // default constructor - called when a Window is declared without arguments @@ -53,8 +39,6 @@ class Window : public QWidget QVBoxLayout *vLayout; // vertical layout QHBoxLayout *hLayout; // horizontal layout - FakeSensor fakeSensor; - // data arrays for the plot double xData[plotDataSize]; double yData[plotDataSize]; @@ -62,7 +46,7 @@ class Window : public QWidget long count = 0; void reset(); - void hasData(double v); + virtual void hasData(double v); std::mutex mtx; }; From 045e0aa8c62ea8743c7acb12a1eb24ee543bc01c Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 6 Feb 2025 11:48:26 +0000 Subject: [PATCH 34/35] Fixed bug where the function wasn't overridden. --- window.cpp | 2 +- window.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/window.cpp b/window.cpp index b6f94bc..9386e15 100644 --- a/window.cpp +++ b/window.cpp @@ -66,7 +66,7 @@ void Window::reset() { // add the new input to the plot -void Window::hasData(double inVal) { +void Window::fakeSensorHasData(double inVal) { mtx.lock(); std::move( yData, yData + plotDataSize - 1, yData+1 ); yData[0] = inVal; diff --git a/window.h b/window.h index bfb98c0..6a46018 100644 --- a/window.h +++ b/window.h @@ -46,7 +46,7 @@ class Window : public QWidget, FakeSensor long count = 0; void reset(); - virtual void hasData(double v); + virtual void fakeSensorHasData(double v); std::mutex mtx; }; From 6314b22978f0ce2fd804b4e77f9bac2c5c1a1b39 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 25 Mar 2025 19:01:39 +0000 Subject: [PATCH 35/35] Added missing libraries --- README.md | 2 +- window.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b17e616..9df6036 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A simple example program using QT and Qwt widgets. Install the QT5 and Qwt development packages: ``` - apt-get install qtdeclarative5-dev-tools + apt-get install qtdeclarative5-dev-tools qt5-qmake qt5-qmake-bin qtbase5-dev qtbase5-dev-tools apt-get install libqwt-qt5-dev ``` diff --git a/window.cpp b/window.cpp index 9386e15..e8d857d 100644 --- a/window.cpp +++ b/window.cpp @@ -31,7 +31,7 @@ Window::Window() button = new QPushButton("Reset"); // see https://doc.qt.io/qt-5/signalsandslots-syntaxes.html - connect(button,&QPushButton::clicked,this,&Window::reset); + connect(button,&QPushButton::clicked,[this](){reset();}); // set up the layout - button above thermometer vLayout = new QVBoxLayout();