summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorn4hy2007-02-21 21:24:23 +0000
committern4hy2007-02-21 21:24:23 +0000
commitd17c86e8c52b6c8ae4ed276ace8727f0c9097bc4 (patch)
tree0e758746b21cab69b4e5178be9c913736603920e
parent8097ab89e6e26c08e6ed9bd57502f7fbb1385299 (diff)
downloadgnuradio-d17c86e8c52b6c8ae4ed276ace8727f0c9097bc4.tar.gz
gnuradio-d17c86e8c52b6c8ae4ed276ace8727f0c9097bc4.tar.bz2
gnuradio-d17c86e8c52b6c8ae4ed276ace8727f0c9097bc4.zip
Beginnings of a qt based gui system added under gr-qtgui
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4564 221aa14e-8319-0410-a670-987f0aec2ac5
-rw-r--r--config/grc_gr_qtgui.m439
-rw-r--r--configure.ac1
-rw-r--r--gr-qtgui/Changelog0
-rw-r--r--gr-qtgui/Makefile.am28
-rw-r--r--gr-qtgui/README31
-rw-r--r--gr-qtgui/gr-qtgui.conf7
-rw-r--r--gr-qtgui/src/Makefile.am24
-rw-r--r--gr-qtgui/src/lib/Makefile.am60
-rw-r--r--gr-qtgui/src/lib/fftdisplay.cc157
-rw-r--r--gr-qtgui/src/lib/fftdisplay.h61
-rw-r--r--gr-qtgui/src/lib/fftdisplaysink.h16
-rw-r--r--gr-qtgui/src/lib/qt_examples.cc122
12 files changed, 546 insertions, 0 deletions
diff --git a/config/grc_gr_qtgui.m4 b/config/grc_gr_qtgui.m4
new file mode 100644
index 000000000..42174a08a
--- /dev/null
+++ b/config/grc_gr_qtgui.m4
@@ -0,0 +1,39 @@
+dnl Copyright 2001,2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+dnl
+dnl This file is part of GNU Radio
+dnl
+dnl GNU Radio is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2, or (at your option)
+dnl any later version.
+dnl
+dnl GNU Radio is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU Radio; see the file COPYING. If not, write to
+dnl the Free Software Foundation, Inc., 51 Franklin Street,
+dnl Boston, MA 02110-1301, USA.
+
+AC_DEFUN([GRC_GR_QTGUI],[
+ GRC_ENABLE([gr-qtgui])
+
+ AC_CONFIG_FILES([ \
+ gr-qtgui/Makefile \
+ gr-qtgui/src/Makefile \
+ gr-qtgui/src/lib/Makefile \
+ ])
+
+ passed=yes
+ PKG_CHECK_MODULES(QT, qt >= 3.3,[],
+ [passed=no;AC_MSG_RESULT([gr-qtgui requires qt, not found. Check for symlink between qt-mt.pc and qt.pc])])
+
+ PKG_CHECK_MODULES(QWT, qwt >= 5.0.0, [],
+ [passed=no;AC_MSG_RESULT([gr-qtgui requires qwt, not found.])])
+
+ GRC_BUILD_CONDITIONAL([gr-qtgui], [
+ AC_SUBST(QT_LIBS)
+ AC_SUBST(QWT_LIBS)])
+])
diff --git a/configure.ac b/configure.ac
index d934c5c35..d7130c166 100644
--- a/configure.ac
+++ b/configure.ac
@@ -201,6 +201,7 @@ GRC_GR_PAGER
GRC_GR_RADIO_ASTRONOMY
GRC_GR_TRELLIS
GRC_GR_VIDEO_SDL
+GRC_GR_QTGUI
GRC_GR_WXGUI
GRC_PMT
GRC_MBLOCK dnl this must come after GRC_PMT
diff --git a/gr-qtgui/Changelog b/gr-qtgui/Changelog
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/gr-qtgui/Changelog
diff --git a/gr-qtgui/Makefile.am b/gr-qtgui/Makefile.am
new file mode 100644
index 000000000..11238a40f
--- /dev/null
+++ b/gr-qtgui/Makefile.am
@@ -0,0 +1,28 @@
+#
+# Copyright 2004,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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 2, or (at your option)
+# any later version.
+#
+# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+EXTRA_DIST = gr-qtgui.conf
+SUBDIRS = src
+
+etcdir = $(sysconfdir)/gnuradio/conf.d
+etc_DATA = gr-qtgui.conf
diff --git a/gr-qtgui/README b/gr-qtgui/README
new file mode 100644
index 000000000..c8ac73525
--- /dev/null
+++ b/gr-qtgui/README
@@ -0,0 +1,31 @@
+This requires qt 3 or later. See http://www.trolltech.com
+
+To support the widgets needed for this code you need Qwt:
+
+http://n4hy.org/Qwt/qwt.spec
+http://n4hy.org/Qwt/qwt.pc
+http://n4hy.org/Qwt/qwt-5.0.0.tar.bz2
+http://n4hy.org/Qwt/qwt-5.0.0-1.src.rpm
+
+QTDIR is an environment variable that must be set for
+gr-qtgui to make.
+
+On Ubuntu with a standard apt-get or synaptic install,
+this is done by:
+
+export QTDIR=/usr/share/qt3
+
+on Fedora Core 6 for example it is automatically set to
+
+/usr/lib/qt-3.3
+
+by Qt install
+
+Qwt probably needs to be built and installed for now using
+
+rpmbuild --rebuild qwt-5.0.0-1.src.rpm
+
+which must be run as root (as in sudo) so that files are
+installed in the proper place for the gnuradio build
+(such as qwt.pc).
+
diff --git a/gr-qtgui/gr-qtgui.conf b/gr-qtgui/gr-qtgui.conf
new file mode 100644
index 000000000..523ff20ad
--- /dev/null
+++ b/gr-qtgui/gr-qtgui.conf
@@ -0,0 +1,7 @@
+# This file contains system wide configuration data for GNU Radio.
+# You may override any setting on a per-user basis by editing
+# ~/.gnuradio/config.conf
+
+[qtgui]
+fft_rate = 15 # fftsink and waterfallsink
+frame_decim = 1 # scopesink
diff --git a/gr-qtgui/src/Makefile.am b/gr-qtgui/src/Makefile.am
new file mode 100644
index 000000000..6e5c054bc
--- /dev/null
+++ b/gr-qtgui/src/Makefile.am
@@ -0,0 +1,24 @@
+#
+# Copyright 2004 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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 2, or (at your option)
+# any later version.
+#
+# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+SUBDIRS = lib
diff --git a/gr-qtgui/src/lib/Makefile.am b/gr-qtgui/src/lib/Makefile.am
new file mode 100644
index 000000000..2f98dd5d0
--- /dev/null
+++ b/gr-qtgui/src/lib/Makefile.am
@@ -0,0 +1,60 @@
+#
+# Copyright 2004,2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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 2, or (at your option)
+# any later version.
+#
+# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) \
+ $(QT_CFLAGS) \
+ $(QWT_CFLAGS)
+
+# This rule lets GNU create any moc_*.cc files from the equivalent *.h
+moc_%.cc: %.h
+ moc $< -o $@
+
+# Generate the .h and .cc files from the .ui file
+%.h: %.ui
+ uic $< -o $@
+
+%.cc: %.ui
+ uic -impl $*.h $< -o $@
+
+include_HEADERS =
+ fftdisplay.h \
+ fftdisplaysink.h
+
+noinst_PROGRAMS = \
+ qt_examples
+
+qt_examples_MOC = \
+ moc_fftdisplay.cc
+
+qt_examples_SOURCES = \
+ fftdisplay.cc \
+ qt_examples.cc \
+ $(qt_examples_MOC)
+
+qt_examples_LDADD = $(QWT_LIBS) $(QT_LIBS)
+qt_examples_LDFLAGS = $(QT_CFLAGS) $(QWT_CFLAGS) $(GNURADIO_CORE_LIBS)
+
+MOSTLYCLEANFILES = \
+ *~
+
+CLEANFILES = $(filter moc_%.cc, $(qt_examples_SOURCES))
diff --git a/gr-qtgui/src/lib/fftdisplay.cc b/gr-qtgui/src/lib/fftdisplay.cc
new file mode 100644
index 000000000..d70164280
--- /dev/null
+++ b/gr-qtgui/src/lib/fftdisplay.cc
@@ -0,0 +1,157 @@
+#ifndef FFT_DISPLAY_CC
+#define FFT_DISPLAY_CC
+
+#include <qwt_painter.h>
+#include <qwt_plot_canvas.h>
+#include <qwt_plot_curve.h>
+#include <qwt_scale_engine.h>
+#include <qapplication.h>
+#include <fftdisplay.h>
+
+const int fft_display_event::EVENT_TYPE_ID = QEvent::User+100;
+
+fft_display_event::fft_display_event( std::vector<gr_complex>* fft_data, const float start_frequency, const float stop_frequency):QCustomEvent(fft_display_event::EVENT_TYPE_ID){
+ d_fft_data.resize(fft_data->size());
+ for(unsigned int i = 0; i < fft_data->size(); i++){
+ d_fft_data[i] = fft_data->operator[](i);
+ }
+ d_start_frequency = start_frequency;
+ d_stop_frequency = stop_frequency;
+}
+
+fft_display_event::~fft_display_event(){
+
+}
+
+const std::vector<gr_complex>& fft_display_event::get_fft_data() const{
+ return d_fft_data;
+}
+
+float fft_display_event::get_start_frequency()const{
+ return d_start_frequency;
+}
+
+float fft_display_event::get_stop_frequency()const{
+ return d_stop_frequency;
+}
+
+fft_display::fft_display(const unsigned int fft_size, QWidget* parent):
+ QwtPlot(parent)
+{
+ // Disable polygon clipping
+ QwtPainter::setDeviceClipping(false);
+
+ // We don't need the cache here
+ canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
+ canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
+
+ canvas()->setPaletteBackgroundColor(QColor("white"));
+
+ d_fft_bin_size = fft_size;
+ if(d_fft_bin_size < 1){
+ d_fft_bin_size = 1;
+ }
+
+ d_start_frequency = 0.0;
+ d_stop_frequency = 4000.0;
+
+ d_fft_data = new std::vector<gr_complex>(d_fft_bin_size);
+ d_plot_data = new double[d_fft_bin_size];
+ d_x_data = new double[d_fft_bin_size];
+ for( unsigned int i = 0; i < d_fft_bin_size; i++){
+ d_fft_data->operator[](i) = gr_complex(static_cast<float>(i), 0.0);
+ d_x_data[i] = d_start_frequency + ((d_stop_frequency-d_start_frequency) / static_cast<float>(d_fft_bin_size)*static_cast<float>(i));
+ d_plot_data[i] = 1.0;
+ }
+
+ // Set the Appropriate Axis Scale Engine
+#warning Pass the axis info as necessary...
+ if(true){
+ setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
+ }
+ else{
+ setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine);
+ }
+
+ QwtPlotCurve* fft_plot_curve = new QwtPlotCurve("FFT Spectrum");
+ fft_plot_curve->attach(this);
+ fft_plot_curve->setPen(QPen(Qt::blue));
+ fft_plot_curve->setRawData(d_x_data, d_plot_data, d_fft_bin_size);
+
+ setTitle("Spectral Display");
+}
+
+fft_display::~fft_display(){
+ /* The Qwt objects are destroyed by Qt when their parent is destroyed */
+
+ delete[] d_plot_data;
+ delete[] d_x_data;
+ delete d_fft_data;
+}
+
+
+void fft_display::set_data(const std::vector<gr_complex>& input_data){
+ unsigned int min_points = d_fft_data->size();
+ if(min_points < input_data.size()){
+ min_points = input_data.size();
+ }
+ if(min_points > d_fft_bin_size){
+ min_points = d_fft_bin_size;
+ }
+ for(unsigned int point = 0; point < min_points; point++){
+ d_fft_data->operator[](point) = input_data[point];
+ }
+}
+
+void fft_display::update_display(){
+
+ // Tell the event loop to display the new data - the event loop handles deleting this object
+ qApp->postEvent(this, new fft_display_event(d_fft_data, d_start_frequency, d_stop_frequency));
+
+}
+
+void fft_display::customEvent(QCustomEvent* e){
+ if(e->type() == fft_display_event::EVENT_TYPE_ID){
+ fft_display_event* fft_display_event_ptr = (fft_display_event*)e;
+ // Write out the FFT data to the display here
+
+ gr_complex data_value;
+ for(unsigned int number = 0; number < fft_display_event_ptr->get_fft_data().size(); number++){
+ data_value = fft_display_event_ptr->get_fft_data()[number];
+ d_plot_data[number] = abs(data_value);
+#warning Add code here for handling magnitude, scaling, etc...
+
+ d_x_data[number] = d_start_frequency + ((d_stop_frequency-d_start_frequency) / static_cast<float>(d_fft_bin_size)*static_cast<float>(number));
+ }
+
+ // Axis
+ setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)");
+ setAxisScale(QwtPlot::xBottom, fft_display_event_ptr->get_start_frequency(), fft_display_event_ptr->get_stop_frequency());
+
+ setAxisTitle(QwtPlot::yLeft, "Values");
+ replot();
+ }
+}
+
+void fft_display::set_start_frequency(const float new_freq){
+ d_start_frequency = new_freq;
+}
+
+float fft_display::get_start_frequency()const{
+ return d_start_frequency;
+}
+
+void fft_display::set_stop_frequency(const float new_freq){
+ d_stop_frequency = new_freq;
+}
+
+float fft_display::get_stop_frequency()const{
+ return d_stop_frequency;
+}
+
+unsigned int fft_display::get_fft_bin_size()const{
+ return d_fft_bin_size;
+}
+
+
+#endif /* FFT_DISPLAY_CC */
diff --git a/gr-qtgui/src/lib/fftdisplay.h b/gr-qtgui/src/lib/fftdisplay.h
new file mode 100644
index 000000000..c567e88f5
--- /dev/null
+++ b/gr-qtgui/src/lib/fftdisplay.h
@@ -0,0 +1,61 @@
+#ifndef FFT_DISPLAY_H
+#define FFT_DISPLAY_H
+
+#include <gr_complex.h>
+
+#include <vector>
+
+#include <qwidget.h>
+#include <qwt_plot.h>
+#include <qevent.h>
+
+class fft_display_event:public QCustomEvent{
+public:
+ fft_display_event(std::vector<gr_complex>*, const float, const float);
+ ~fft_display_event();
+
+ const std::vector<gr_complex>& get_fft_data()const;
+ float get_start_frequency()const;
+ float get_stop_frequency()const;
+
+ static const int EVENT_TYPE_ID;
+protected:
+
+private:
+ std::vector<gr_complex> d_fft_data;
+ float d_start_frequency;
+ float d_stop_frequency;
+};
+
+class fft_display:public QwtPlot{
+ Q_OBJECT
+public:
+ fft_display(const unsigned int, QWidget* = ((QWidget*)0));
+ virtual ~fft_display();
+
+ virtual void customEvent(QCustomEvent*);
+
+ void set_start_frequency(const float);
+ float get_start_frequency()const;
+
+ void set_stop_frequency(const float);
+ float get_stop_frequency()const;
+
+ unsigned int get_fft_bin_size()const;
+
+public slots:
+ virtual void set_data( const std::vector<gr_complex>& );
+ virtual void update_display();
+
+protected:
+
+private:
+ std::vector<gr_complex>* d_fft_data;
+ double* d_plot_data;
+ double* d_x_data;
+ unsigned int d_fft_bin_size;
+ float d_start_frequency;
+ float d_stop_frequency;
+};
+
+#endif /* FFT_DISPLAY_H */
diff --git a/gr-qtgui/src/lib/fftdisplaysink.h b/gr-qtgui/src/lib/fftdisplaysink.h
new file mode 100644
index 000000000..f6583f91d
--- /dev/null
+++ b/gr-qtgui/src/lib/fftdisplaysink.h
@@ -0,0 +1,16 @@
+#ifndef FFT_DISPLAY_SINK_H
+#define FFT_DISPLAY_SINK_H
+
+
+class FFTDisplaySink{
+
+public:
+ FFTDisplaySink();
+ ~FFTDisplaySink();
+protected:
+
+private:
+
+};
+
+#endif /* FFT_DISPLAY_SINK_H */
diff --git a/gr-qtgui/src/lib/qt_examples.cc b/gr-qtgui/src/lib/qt_examples.cc
new file mode 100644
index 000000000..d79a3ad6c
--- /dev/null
+++ b/gr-qtgui/src/lib/qt_examples.cc
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <fstream>
+
+#include <qapplication.h>
+#include <omnithread.h>
+#include <vector>
+
+#include <fftdisplay.h>
+
+#warning Must make this threadsafe
+static bool g_exit_flag = false;
+
+void read_function(void* ptr){
+
+ fft_display* fftDisplay = (fft_display*)ptr;
+
+ std::vector<gr_complex> fftData(fftDisplay->get_fft_bin_size());
+ for(unsigned int number = 0; number < fftData.size(); number++){
+ fftData[number] = gr_complex(static_cast<float>(number), static_cast<float>(number));
+ }
+
+ float* readBuffer = new float[fftDisplay->get_fft_bin_size()*2];
+ int amntRead = 0;
+
+ fftDisplay->set_data(fftData);
+
+ while(!g_exit_flag){
+ // Read in the data here
+ sched_yield();
+ std::cin.read((char*)readBuffer, fftDisplay->get_fft_bin_size()*sizeof(gr_complex));
+ amntRead = std::cin.gcount();
+
+ if(amntRead != static_cast<int>(fftDisplay->get_fft_bin_size()*sizeof(gr_complex))){
+ fprintf(stderr, "Invalid Read Amount from stdin - closing program\n");
+ qApp->quit();
+ g_exit_flag = true;
+ }
+ else{
+ for(unsigned int number = 0; number < fftData.size(); number++){
+ fftData[number] = gr_complex(readBuffer[2*number], readBuffer[(2*number)+1]);
+ }
+
+ fftDisplay->set_data(fftData);
+
+ fftDisplay->update_display();
+
+ qApp->wakeUpGuiThread();
+ }
+ }
+
+ delete[] readBuffer;
+}
+
+int main (int argc, char* argv[]){
+ extern char* optarg;
+ extern int optind, optopt;
+ float start_frequency = 0.0;
+ float stop_frequency = 4000.0;
+ int c;
+ unsigned int fft_bin_size = 1024;
+
+ while ((c = getopt(argc, argv, "s:p:b:")) != -1){
+ switch(c){
+ case 's': start_frequency = strtod(optarg, NULL); break;
+ case 'p': stop_frequency = strtod(optarg, NULL); break;
+ case 'b': fft_bin_size = (unsigned int)(atoi(optarg)); break;
+ case ':': /* -s or -p w/o operand */
+ fprintf(stderr, "Option -%c requires an arguement\n", optopt); break;
+ case '?': fprintf(stderr, "Unrecognized option: -%c\n", optopt);
+ fprintf(stderr, "Valid Arguements\n -s <start frequency>\n -p <stop frequency> -b <fft_bin_size> - number of fft samples per display\n");
+ exit(-1); break;
+ }
+ }
+
+ // Verify the stop frequency is greater than the stop frequency
+ if(stop_frequency < start_frequency){
+ fprintf(stderr, "Stop Frequency (%0.0f Hz) was less than the Start Frequency (%0.0f Hz)\n", stop_frequency, start_frequency);
+ exit(-1);
+ }
+
+ // Create the QApplication - this MUST be done before ANY QObjects are created
+ QApplication* qApp = new QApplication(argc, argv);
+
+ fft_display* fftDisplay = new fft_display(fft_bin_size); // No Parent Specified
+
+ // Resize the Display
+ fftDisplay->resize(640,240);
+
+ // Set the start and stop frequency
+ fftDisplay->set_start_frequency(start_frequency);
+ fftDisplay->set_stop_frequency(stop_frequency);
+
+ g_exit_flag = false;
+ omni_thread* thread_ptr = new omni_thread(&read_function, (void*)fftDisplay);
+
+ // Set up the thread to read the data from stdin
+ thread_ptr->start();
+ sched_yield();
+
+ // Make the closing of the last window call the quit()
+ QObject::connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()));
+
+ // finally, refresh the plot
+ fftDisplay->update_display();
+ fftDisplay->show();
+
+ // Start the Event Thread
+ qApp->exec();
+
+ // No QObjects should be deleted once the event thread exits...
+ g_exit_flag = true;
+
+ delete fftDisplay;
+
+ // Destroy the Event Thread
+ delete qApp;
+ return 0;
+}
+