diff options
author | n4hy | 2007-02-21 21:24:23 +0000 |
---|---|---|
committer | n4hy | 2007-02-21 21:24:23 +0000 |
commit | d17c86e8c52b6c8ae4ed276ace8727f0c9097bc4 (patch) | |
tree | 0e758746b21cab69b4e5178be9c913736603920e | |
parent | 8097ab89e6e26c08e6ed9bd57502f7fbb1385299 (diff) | |
download | gnuradio-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.m4 | 39 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | gr-qtgui/Changelog | 0 | ||||
-rw-r--r-- | gr-qtgui/Makefile.am | 28 | ||||
-rw-r--r-- | gr-qtgui/README | 31 | ||||
-rw-r--r-- | gr-qtgui/gr-qtgui.conf | 7 | ||||
-rw-r--r-- | gr-qtgui/src/Makefile.am | 24 | ||||
-rw-r--r-- | gr-qtgui/src/lib/Makefile.am | 60 | ||||
-rw-r--r-- | gr-qtgui/src/lib/fftdisplay.cc | 157 | ||||
-rw-r--r-- | gr-qtgui/src/lib/fftdisplay.h | 61 | ||||
-rw-r--r-- | gr-qtgui/src/lib/fftdisplaysink.h | 16 | ||||
-rw-r--r-- | gr-qtgui/src/lib/qt_examples.cc | 122 |
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; +} + |