[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] [gnuradio] 05/08: qtgui: added triggering to freq sink
From: |
git |
Subject: |
[Commit-gnuradio] [gnuradio] 05/08: qtgui: added triggering to freq sinks. |
Date: |
Thu, 23 Oct 2014 22:03:16 +0000 (UTC) |
This is an automated email from the git hooks/post-receive script.
trondeau pushed a commit to branch master
in repository gnuradio.
commit 3151fe43ff62156bfa91db1f1b7df7fbb3a08fd6
Author: Tom Rondeau <address@hidden>
Date: Thu Oct 23 15:35:44 2014 -0400
qtgui: added triggering to freq sinks.
- Trigger off power (norm/auto): if any power bin in the FFT is greater
than the level, output.
- Trigger off tag: if the given tag is found, take FFT from that triggered
sample.
- Simplifies work funciton by relying on set_output_multiple so we always
work off a multiple of FFT-length slices.
---
gr-qtgui/grc/qtgui_freq_sink_x.xml | 59 +++++++
gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h | 28 +++
gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h | 28 +++
gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h | 27 +++
gr-qtgui/lib/freq_sink_c_impl.cc | 203 ++++++++++++++++------
gr-qtgui/lib/freq_sink_c_impl.h | 22 ++-
gr-qtgui/lib/freq_sink_f_impl.cc | 192 +++++++++++++++-----
gr-qtgui/lib/freq_sink_f_impl.h | 24 ++-
gr-qtgui/lib/freqdisplayform.cc | 112 ++++++++++++
9 files changed, 593 insertions(+), 102 deletions(-)
diff --git a/gr-qtgui/grc/qtgui_freq_sink_x.xml
b/gr-qtgui/grc/qtgui_freq_sink_x.xml
index bf9303f..aea46ab 100644
--- a/gr-qtgui/grc/qtgui_freq_sink_x.xml
+++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml
@@ -22,6 +22,7 @@ qtgui.$(type.fcn)(
)
self.$(id).set_update_time($update_time)
self.$(id).set_y_axis($ymin, $ymax)
+self.$(id).set_trigger_mode($tr_mode, $tr_level, $tr_chan, $tr_tag)
self.$(id).enable_autoscale($autoscale)
self.$(id).enable_grid($grid)
self.$(id).set_fft_average($average)
@@ -56,6 +57,7 @@ $(gui_hint()($win))</make>
<param_tab_order>
<tab>General</tab>
+ <tab>Trigger</tab>
<tab>Config</tab>
</param_tab_order>
@@ -259,6 +261,63 @@ $(gui_hint()($win))</make>
</option>
</param>
+
+ <!-- Begin Trigger Tab items -->
+ <param>
+ <name>Trigger Mode</name>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_FREE</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Free</name>
+ <key>qtgui.TRIG_MODE_FREE</key>
+ </option>
+ <option>
+ <name>Auto</name>
+ <key>qtgui.TRIG_MODE_AUTO</key>
+ </option>
+ <option>
+ <name>Normal</name>
+ <key>qtgui.TRIG_MODE_NORM</key>
+ </option>
+ <option>
+ <name>Tag</name>
+ <key>qtgui.TRIG_MODE_TAG</key>
+ </option>
+ <tab>Trigger</tab>
+ </param>
+
+ <param>
+ <name>Trigger Level</name>
+ <key>tr_level</key>
+ <value>0.0</value>
+ <type>float</type>
+ <hide>part</hide>
+ <tab>Trigger</tab>
+ </param>
+
+ <param>
+ <name>Trigger Channel</name>
+ <key>tr_chan</key>
+ <value>0</value>
+ <type>int</type>
+ <hide>part</hide>
+ <tab>Trigger</tab>
+ </param>
+
+ <param>
+ <name>Trigger Tag Key</name>
+ <key>tr_tag</key>
+ <value>""</value>
+ <type>string</type>
+ <hide>part</hide>
+ <tab>Trigger</tab>
+ </param>
+
+
+
+ <!-- Begin Config Tab items -->
<param>
<name>Line 1 Label</name>
<key>label1</key>
diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
index d02505c..f49e7b0 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
@@ -28,6 +28,7 @@
#endif
#include <gnuradio/qtgui/api.h>
+#include <gnuradio/qtgui/trigger_mode.h>
#include <gnuradio/sync_block.h>
#include <qapplication.h>
#include <gnuradio/filter/firdes.h>
@@ -118,6 +119,33 @@ namespace gr {
virtual void set_line_marker(int which, int marker) = 0;
virtual void set_line_alpha(int which, double alpha) = 0;
+ /*!
+ * Set up a trigger for the sink to know when to start
+ * plotting. Useful to isolate events and avoid noise.
+ *
+ * The trigger modes are Free, Auto, Normal, and Tag (see
+ * gr::qtgui::trigger_mode). The first three are like a normal
+ * trigger function. Free means free running with no trigger,
+ * auto will trigger if the trigger event is seen, but will
+ * still plot otherwise, and normal will hold until the trigger
+ * event is observed. The Tag trigger mode allows us to trigger
+ * off a specific stream tag. The tag trigger is based only on
+ * the name of the tag, so when a tag of the given name is seen,
+ * the trigger is activated.
+ *
+ * In auto and normal mode, we look to see if the magnitude of
+ * the any FFT point is over the set level.
+ *
+ * \param mode The trigger_mode: free, auto, normal, or tag.
+ * \param level The magnitude of the trigger even for auto or normal
modes.
+ * \param channel Which input channel to use for the trigger events.
+ * \param tag_key The name (as a string) of the tag to trigger off
+ * of if using the tag mode.
+ */
+ virtual void set_trigger_mode(trigger_mode mode,
+ float level, int channel,
+ const std::string &tag_key="") = 0;
+
virtual std::string title() = 0;
virtual std::string line_label(int which) = 0;
virtual std::string line_color(int which) = 0;
diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
index f0ebe8d..ed65d31 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
@@ -28,6 +28,7 @@
#endif
#include <gnuradio/qtgui/api.h>
+#include <gnuradio/qtgui/trigger_mode.h>
#include <gnuradio/sync_block.h>
#include <qapplication.h>
#include <gnuradio/filter/firdes.h>
@@ -124,6 +125,33 @@ namespace gr {
*/
virtual void set_plot_pos_half(bool half) = 0;
+ /*!
+ * Set up a trigger for the sink to know when to start
+ * plotting. Useful to isolate events and avoid noise.
+ *
+ * The trigger modes are Free, Auto, Normal, and Tag (see
+ * gr::qtgui::trigger_mode). The first three are like a normal
+ * trigger function. Free means free running with no trigger,
+ * auto will trigger if the trigger event is seen, but will
+ * still plot otherwise, and normal will hold until the trigger
+ * event is observed. The Tag trigger mode allows us to trigger
+ * off a specific stream tag. The tag trigger is based only on
+ * the name of the tag, so when a tag of the given name is seen,
+ * the trigger is activated.
+ *
+ * In auto and normal mode, we look to see if the magnitude of
+ * the any FFT point is over the set level.
+ *
+ * \param mode The trigger_mode: free, auto, normal, or tag.
+ * \param level The magnitude of the trigger even for auto or normal
modes.
+ * \param channel Which input channel to use for the trigger events.
+ * \param tag_key The name (as a string) of the tag to trigger off
+ * of if using the tag mode.
+ */
+ virtual void set_trigger_mode(trigger_mode mode,
+ float level, int channel,
+ const std::string &tag_key="") = 0;
+
virtual std::string title() = 0;
virtual std::string line_label(int which) = 0;
virtual std::string line_color(int which) = 0;
diff --git a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
index 2fea33d..744ac3e 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
@@ -49,6 +49,13 @@ class FreqDisplayForm : public DisplayForm
float getFFTAverage() const;
gr::filter::firdes::win_type getFFTWindowType() const;
+ // Trigger methods
+ gr::qtgui::trigger_mode getTriggerMode() const;
+ float getTriggerLevel() const;
+ int getTriggerChannel() const;
+ std::string getTriggerTagKey() const;
+
+
// returns the frequency that was last double-clicked on by the user
float getClickedFreq() const;
@@ -73,6 +80,15 @@ public slots:
void clearMaxHold();
void clearMinHold();
+ // Trigger slots
+ void updateTrigger(gr::qtgui::trigger_mode mode);
+ void setTriggerMode(gr::qtgui::trigger_mode mode);
+ void setTriggerLevel(QString s);
+ void setTriggerLevel(float level);
+ void setTriggerChannel(int chan);
+ void setTriggerTagKey(QString s);
+ void setTriggerTagKey(const std::string &s);
+
private slots:
void newData(const QEvent *updateEvent);
void onPlotPointSelected(const QPointF p);
@@ -94,6 +110,17 @@ private:
FFTAverageMenu *d_avgmenu;
FFTWindowMenu *d_winmenu;
QAction *d_clearmin_act, *d_clearmax_act;
+
+ QMenu *d_triggermenu;
+ TriggerModeMenu *d_tr_mode_menu;
+ PopupMenu *d_tr_level_act;
+ TriggerChannelMenu *d_tr_channel_menu;
+ PopupMenu *d_tr_tag_key_act;
+
+ gr::qtgui::trigger_mode d_trig_mode;
+ float d_trig_level;
+ int d_trig_channel;
+ std::string d_trig_tag_key;
};
#endif /* FREQ_DISPLAY_FORM_H */
diff --git a/gr-qtgui/lib/freq_sink_c_impl.cc b/gr-qtgui/lib/freq_sink_c_impl.cc
index 72648e3..9cb2aa3 100644
--- a/gr-qtgui/lib/freq_sink_c_impl.cc
+++ b/gr-qtgui/lib/freq_sink_c_impl.cc
@@ -54,7 +54,7 @@ namespace gr {
int nconnections,
QWidget *parent)
: sync_block("freq_sink_c",
- io_signature::make(1, -1, sizeof(gr_complex)),
+ io_signature::make(nconnections, nconnections,
sizeof(gr_complex)),
io_signature::make(0, 0, 0)),
d_fftsize(fftsize), d_fftavg(1.0),
d_wintype((filter::firdes::win_type)(wintype)),
@@ -103,6 +103,8 @@ namespace gr {
buildwindow();
initialize();
+
+ set_trigger_mode(TRIG_MODE_FREE, 0, 0);
}
freq_sink_c_impl::~freq_sink_c_impl()
@@ -127,15 +129,6 @@ namespace gr {
}
void
- freq_sink_c_impl::forecast(int noutput_items, gr_vector_int
&ninput_items_required)
- {
- unsigned int ninputs = ninput_items_required.size();
- for (unsigned int i = 0; i < ninputs; i++) {
- ninput_items_required[i] = std::min(d_fftsize, 8191);
- }
- }
-
- void
freq_sink_c_impl::initialize()
{
if(qApp != NULL) {
@@ -164,6 +157,8 @@ namespace gr {
if(d_name.size() > 0)
set_title(d_name);
+ set_output_multiple(d_fftsize);
+
// initialize update time to 10 times a second
set_update_time(0.1);
}
@@ -305,6 +300,29 @@ namespace gr {
d_main_gui->resize(QSize(width, height));
}
+ void
+ freq_sink_c_impl::set_trigger_mode(trigger_mode mode,
+ float level,
+ int channel,
+ const std::string &tag_key)
+ {
+ gr::thread::scoped_lock lock(d_setlock);
+
+ d_trigger_mode = mode;
+ d_trigger_level = level;
+ d_trigger_channel = channel;
+ d_trigger_tag_key = pmt::intern(tag_key);
+ d_triggered = false;
+ d_trigger_count = 0;
+
+ d_main_gui->setTriggerMode(d_trigger_mode);
+ d_main_gui->setTriggerLevel(d_trigger_level);
+ d_main_gui->setTriggerChannel(d_trigger_channel);
+ d_main_gui->setTriggerTagKey(tag_key);
+
+ _reset();
+ }
+
std::string
freq_sink_c_impl::title()
{
@@ -380,9 +398,25 @@ namespace gr {
void
freq_sink_c_impl::reset()
{
- d_index = 0;
+ gr::thread::scoped_lock lock(d_setlock);
+ _reset();
+ }
+
+ void
+ freq_sink_c_impl::_reset()
+ {
+ d_trigger_count = 0;
+
+ // Reset the trigger.
+ if(d_trigger_mode == TRIG_MODE_FREE) {
+ d_triggered = true;
+ }
+ else {
+ d_triggered = false;
+ }
}
+
void
freq_sink_c_impl::fft(float *data_out, const gr_complex *data_in, int size)
{
@@ -408,7 +442,7 @@ namespace gr {
free(tmp);
}
- void
+ bool
freq_sink_c_impl::windowreset()
{
gr::thread::scoped_lock lock(d_setlock);
@@ -418,7 +452,9 @@ namespace gr {
if(d_wintype != newwintype) {
d_wintype = newwintype;
buildwindow();
+ return true;
}
+ return false;
}
void
@@ -430,7 +466,7 @@ namespace gr {
}
}
- void
+ bool
freq_sink_c_impl::fftresize()
{
gr::thread::scoped_lock lock(d_setlock);
@@ -471,7 +507,14 @@ namespace gr {
d_fbuf = (float*)volk_malloc(d_outputsize*sizeof(float),
volk_get_alignment());
memset(d_fbuf, 0, d_outputsize*sizeof(float));
+
+ d_last_time = 0;
+
+ set_output_multiple(d_fftsize);
+
+ return true;
}
+ return false;
}
void
@@ -498,59 +541,121 @@ namespace gr {
}
}
+ void
+ freq_sink_c_impl::_gui_update_trigger()
+ {
+ trigger_mode new_trigger_mode = d_main_gui->getTriggerMode();
+ d_trigger_level = d_main_gui->getTriggerLevel();
+ d_trigger_channel = d_main_gui->getTriggerChannel();
+
+ std::string tagkey = d_main_gui->getTriggerTagKey();
+ d_trigger_tag_key = pmt::intern(tagkey);
+
+ if(new_trigger_mode != d_trigger_mode) {
+ d_trigger_mode = new_trigger_mode;
+ _reset();
+ }
+ }
+
+ void
+ freq_sink_c_impl::_test_trigger_tags(int start, int nitems)
+ {
+ uint64_t nr = nitems_read(d_trigger_channel);
+ std::vector<gr::tag_t> tags;
+ get_tags_in_range(tags, d_trigger_channel,
+ nr+start, nr+start+nitems,
+ d_trigger_tag_key);
+ if(tags.size() > 0) {
+ d_triggered = true;
+ d_index = tags[0].offset - nr;
+ d_trigger_count = 0;
+ }
+ }
+
+ void
+ freq_sink_c_impl::_test_trigger_norm(int nitems, std::vector<double*>
inputs)
+ {
+ const double *in = (const double*)inputs[d_trigger_channel];
+ for(int i = 0; i < nitems; i++) {
+ d_trigger_count++;
+
+ // Test if trigger has occurred based on the FFT magnitude and
+ // channel number. Test if any value is > the level (in dBx).
+ if(in[i] > d_trigger_level) {
+ d_triggered = true;
+ d_trigger_count = 0;
+ break;
+ }
+ }
+
+ // If using auto trigger mode, trigger periodically even
+ // without a trigger event.
+ if((d_trigger_mode == TRIG_MODE_AUTO) && (d_trigger_count >
d_outputsize)) {
+ d_triggered = true;
+ d_trigger_count = 0;
+ }
+ }
+
int
freq_sink_c_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
- int j=0;
const gr_complex *in = (const gr_complex*)input_items[0];
// Update the FFT size from the application
- fftresize();
- windowreset();
- check_clicked();
+ bool updated = false;
+ updated |= fftresize();
+ updated |= windowreset();
+ if(updated)
+ return 0;
- for(int i=0; i < noutput_items; i+=d_fftsize) {
- unsigned int datasize = noutput_items - i;
- unsigned int resid = d_fftsize-d_index;
+ check_clicked();
+ _gui_update_trigger();
- // If we have enough input for one full FFT, do it
- if(datasize >= resid) {
+ gr::thread::scoped_lock lock(d_setlock);
+ for(d_index = 0; d_index < noutput_items; d_index+=d_outputsize) {
- if(gr::high_res_timer_now() - d_last_time > d_update_time) {
- for(int n = 0; n < d_nconnections; n++) {
- // Fill up residbuf with d_fftsize number of items
- in = (const gr_complex*)input_items[n];
- memcpy(d_residbufs[n]+d_index, &in[j], sizeof(gr_complex)*resid);
+ if((gr::high_res_timer_now() - d_last_time) > d_update_time) {
- fft(d_fbuf, d_residbufs[n], d_fftsize);
- for(int x = 0; x < d_outputsize; x++) {
- d_magbufs[n][x] = (double)((1.0-d_fftavg)*d_magbufs[n][x] +
(d_fftavg)*d_fbuf[x]);
- }
- //volk_32f_convert_64f_a(d_magbufs[n], d_fbuf, d_fftsize);
+ // Trigger off tag, if active
+ if((d_trigger_mode == TRIG_MODE_TAG) && !d_triggered) {
+ _test_trigger_tags(d_index, d_outputsize);
+ if(d_triggered) {
+ // If not enough from tag position, early exit
+ if((d_index + d_outputsize) >= noutput_items)
+ return d_index;
}
+ }
- d_last_time = gr::high_res_timer_now();
- d_qApplication->postEvent(d_main_gui,
- new FreqUpdateEvent(d_magbufs,
d_outputsize));
- }
+ // Perform FFT and shift operations into d_magbufs
+ for(int n = 0; n < d_nconnections; n++) {
+ in = (const gr_complex*)input_items[n];
+ memcpy(d_residbufs[n], &in[d_index], sizeof(gr_complex)*d_fftsize);
- d_index = 0;
- j += resid;
- }
- // Otherwise, copy what we received into the residbuf for next time
- else {
- for(int n = 0; n < d_nconnections; n++) {
- in = (const gr_complex*)input_items[n];
- memcpy(d_residbufs[n]+d_index, &in[j], sizeof(gr_complex)*datasize);
- }
- d_index += datasize;
- j += datasize;
- }
+ fft(d_fbuf, d_residbufs[n], d_fftsize);
+ for(int x = 0; x < d_outputsize; x++) {
+ d_magbufs[n][x] = (double)((1.0-d_fftavg)*d_magbufs[n][x] +
(d_fftavg)*d_fbuf[x]);
+ }
+ //volk_32f_convert_64f_a(d_magbufs[n], d_fbuf, d_fftsize);
+ }
+
+ // Test trigger off signal power in d_magbufs
+ if((d_trigger_mode == TRIG_MODE_NORM) || (d_trigger_mode ==
TRIG_MODE_AUTO)) {
+ _test_trigger_norm(d_outputsize, d_magbufs);
+ }
+
+ // If a trigger (FREE always triggers), plot and reset state
+ if(d_triggered) {
+ d_last_time = gr::high_res_timer_now();
+ d_qApplication->postEvent(d_main_gui,
+ new FreqUpdateEvent(d_magbufs,
d_outputsize));
+ _reset();
+ }
+ }
}
- return j;
+ return noutput_items;
}
} /* namespace qtgui */
diff --git a/gr-qtgui/lib/freq_sink_c_impl.h b/gr-qtgui/lib/freq_sink_c_impl.h
index 0e8f2ce..dc83f96 100644
--- a/gr-qtgui/lib/freq_sink_c_impl.h
+++ b/gr-qtgui/lib/freq_sink_c_impl.h
@@ -35,8 +35,6 @@ namespace gr {
class QTGUI_API freq_sink_c_impl : public freq_sink_c
{
private:
- void forecast(int noutput_items, gr_vector_int &ninput_items_required);
-
void initialize();
int d_fftsize;
@@ -65,9 +63,9 @@ namespace gr {
gr::high_res_timer_type d_update_time;
gr::high_res_timer_type d_last_time;
- void windowreset();
+ bool windowreset();
void buildwindow();
- void fftresize();
+ bool fftresize();
void check_clicked();
void fft(float *data_out, const gr_complex *data_in, int size);
@@ -75,6 +73,19 @@ namespace gr {
// The message is a PMT pair (intern('freq'), double(frequency)).
void handle_set_freq(pmt::pmt_t msg);
+ // Members used for triggering scope
+ trigger_mode d_trigger_mode;
+ float d_trigger_level;
+ int d_trigger_channel;
+ pmt::pmt_t d_trigger_tag_key;
+ bool d_triggered;
+ int d_trigger_count;
+
+ void _reset();
+ void _gui_update_trigger();
+ void _test_trigger_tags(int start, int nitems);
+ void _test_trigger_norm(int nitems, std::vector<double*> inputs);
+
public:
freq_sink_c_impl(int size, int wintype,
double fc, double bw,
@@ -113,6 +124,9 @@ namespace gr {
void set_line_style(int which, int style);
void set_line_marker(int which, int marker);
void set_line_alpha(int which, double alpha);
+ void set_trigger_mode(trigger_mode mode,
+ float level, int channel,
+ const std::string &tag_key="");
std::string title();
std::string line_label(int which);
diff --git a/gr-qtgui/lib/freq_sink_f_impl.cc b/gr-qtgui/lib/freq_sink_f_impl.cc
index d01c535..c50280e 100644
--- a/gr-qtgui/lib/freq_sink_f_impl.cc
+++ b/gr-qtgui/lib/freq_sink_f_impl.cc
@@ -54,7 +54,7 @@ namespace gr {
int nconnections,
QWidget *parent)
: sync_block("freq_sink_f",
- io_signature::make(1, -1, sizeof(float)),
+ io_signature::make(nconnections, nconnections,
sizeof(float)),
io_signature::make(0, 0, 0)),
d_fftsize(fftsize), d_fftavg(1.0),
d_wintype((filter::firdes::win_type)(wintype)),
@@ -103,6 +103,8 @@ namespace gr {
buildwindow();
initialize();
+
+ set_trigger_mode(TRIG_MODE_FREE, 0, 0);
}
freq_sink_f_impl::~freq_sink_f_impl()
@@ -127,15 +129,6 @@ namespace gr {
}
void
- freq_sink_f_impl::forecast(int noutput_items, gr_vector_int
&ninput_items_required)
- {
- unsigned int ninputs = ninput_items_required.size();
- for (unsigned int i = 0; i < ninputs; i++) {
- ninput_items_required[i] = std::min(d_fftsize, 8191);
- }
- }
-
- void
freq_sink_f_impl::initialize()
{
if(qApp != NULL) {
@@ -164,6 +157,8 @@ namespace gr {
if(d_name.size() > 0)
set_title(d_name);
+ set_output_multiple(d_fftsize);
+
// initialize update time to 10 times a second
set_update_time(0.1);
}
@@ -311,6 +306,29 @@ namespace gr {
d_main_gui->setPlotPosHalf(half);
}
+ void
+ freq_sink_f_impl::set_trigger_mode(trigger_mode mode,
+ float level,
+ int channel,
+ const std::string &tag_key)
+ {
+ gr::thread::scoped_lock lock(d_setlock);
+
+ d_trigger_mode = mode;
+ d_trigger_level = level;
+ d_trigger_channel = channel;
+ d_trigger_tag_key = pmt::intern(tag_key);
+ d_triggered = false;
+ d_trigger_count = 0;
+
+ d_main_gui->setTriggerMode(d_trigger_mode);
+ d_main_gui->setTriggerLevel(d_trigger_level);
+ d_main_gui->setTriggerChannel(d_trigger_channel);
+ d_main_gui->setTriggerTagKey(tag_key);
+
+ _reset();
+ }
+
std::string
freq_sink_f_impl::title()
{
@@ -386,10 +404,25 @@ namespace gr {
void
freq_sink_f_impl::reset()
{
- d_index = 0;
+ gr::thread::scoped_lock lock(d_setlock);
+ _reset();
}
void
+ freq_sink_f_impl::_reset()
+ {
+ d_trigger_count = 0;
+
+ // Reset the trigger.
+ if(d_trigger_mode == TRIG_MODE_FREE) {
+ d_triggered = true;
+ }
+ else {
+ d_triggered = false;
+ }
+ }
+
+ void
freq_sink_f_impl::fft(float *data_out, const float *data_in, int size)
{
// float to complex conversion
@@ -415,7 +448,7 @@ namespace gr {
free(tmp);
}
- void
+ bool
freq_sink_f_impl::windowreset()
{
gr::thread::scoped_lock lock(d_setlock);
@@ -425,7 +458,9 @@ namespace gr {
if(d_wintype != newwintype) {
d_wintype = newwintype;
buildwindow();
+ return true;
}
+ return false;
}
void
@@ -437,7 +472,7 @@ namespace gr {
}
}
- void
+ bool
freq_sink_f_impl::fftresize()
{
gr::thread::scoped_lock lock(d_setlock);
@@ -478,7 +513,14 @@ namespace gr {
d_fbuf = (float*)volk_malloc(d_outputsize*sizeof(float),
volk_get_alignment());
memset(d_fbuf, 0, d_outputsize*sizeof(float));
+
+ d_last_time = 0;
+
+ set_output_multiple(d_fftsize);
+
+ return true;
}
+ return false;
}
void
@@ -505,59 +547,121 @@ namespace gr {
}
}
+ void
+ freq_sink_f_impl::_gui_update_trigger()
+ {
+ trigger_mode new_trigger_mode = d_main_gui->getTriggerMode();
+ d_trigger_level = d_main_gui->getTriggerLevel();
+ d_trigger_channel = d_main_gui->getTriggerChannel();
+
+ std::string tagkey = d_main_gui->getTriggerTagKey();
+ d_trigger_tag_key = pmt::intern(tagkey);
+
+ if(new_trigger_mode != d_trigger_mode) {
+ d_trigger_mode = new_trigger_mode;
+ _reset();
+ }
+ }
+
+ void
+ freq_sink_f_impl::_test_trigger_tags(int start, int nitems)
+ {
+ uint64_t nr = nitems_read(d_trigger_channel);
+ std::vector<gr::tag_t> tags;
+ get_tags_in_range(tags, d_trigger_channel,
+ nr+start, nr+start+nitems,
+ d_trigger_tag_key);
+ if(tags.size() > 0) {
+ d_triggered = true;
+ d_index = tags[0].offset - nr;
+ d_trigger_count = 0;
+ }
+ }
+
+ void
+ freq_sink_f_impl::_test_trigger_norm(int nitems, std::vector<double*>
inputs)
+ {
+ const double *in = (const double*)inputs[d_trigger_channel];
+ for(int i = 0; i < nitems; i++) {
+ d_trigger_count++;
+
+ // Test if trigger has occurred based on the FFT magnitude and
+ // channel number. Test if any value is > the level (in dBx).
+ if(in[i] > d_trigger_level) {
+ d_triggered = true;
+ d_trigger_count = 0;
+ break;
+ }
+ }
+
+ // If using auto trigger mode, trigger periodically even
+ // without a trigger event.
+ if((d_trigger_mode == TRIG_MODE_AUTO) && (d_trigger_count >
d_outputsize)) {
+ d_triggered = true;
+ d_trigger_count = 0;
+ }
+ }
+
int
freq_sink_f_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
- int j=0;
const float *in = (const float*)input_items[0];
// Update the FFT size from the application
- fftresize();
- windowreset();
+ bool updated = false;
+ updated |= fftresize();
+ updated |= windowreset();
+ if(updated)
+ return 0;
+
check_clicked();
+ _gui_update_trigger();
- for(int i=0; i < noutput_items; i+=d_fftsize) {
- unsigned int datasize = noutput_items - i;
- unsigned int resid = d_fftsize-d_index;
+ gr::thread::scoped_lock lock(d_setlock);
+ for(d_index = 0; d_index < noutput_items; d_index+=d_outputsize) {
+
+ if((gr::high_res_timer_now() - d_last_time) > d_update_time) {
- // If we have enough input for one full FFT, do it
- if(datasize >= resid) {
+ // Trigger off tag, if active
+ if((d_trigger_mode == TRIG_MODE_TAG) && !d_triggered) {
+ _test_trigger_tags(d_index, d_outputsize);
+ if(d_triggered) {
+ // If not enough from tag position, early exit
+ if((d_index + d_outputsize) >= noutput_items)
+ return d_index;
+ }
+ }
- if(gr::high_res_timer_now() - d_last_time > d_update_time) {
- for(int n = 0; n < d_nconnections; n++) {
- // Fill up residbuf with d_fftsize number of items
- in = (const float*)input_items[n];
- memcpy(d_residbufs[n]+d_index, &in[j], sizeof(float)*resid);
+ for(int n = 0; n < d_nconnections; n++) {
+ // Fill up residbuf with d_fftsize number of items
+ in = (const float*)input_items[n];
+ memcpy(d_residbufs[n], &in[d_index], sizeof(float)*d_fftsize);
- fft(d_fbuf, d_residbufs[n], d_fftsize);
- for(int x = 0; x < d_outputsize; x++) {
- d_magbufs[n][x] = (double)((1.0-d_fftavg)*d_magbufs[n][x] +
(d_fftavg)*d_fbuf[x]);
- }
- //volk_32f_convert_64f_a(d_magbufs[n], d_fbuf, d_fftsize);
+ fft(d_fbuf, d_residbufs[n], d_fftsize);
+ for(int x = 0; x < d_outputsize; x++) {
+ d_magbufs[n][x] = (double)((1.0-d_fftavg)*d_magbufs[n][x] +
(d_fftavg)*d_fbuf[x]);
}
+ //volk_32f_convert_64f_a(d_magbufs[n], d_fbuf, d_fftsize);
+ }
+
+ // Test trigger off signal power in d_magbufs
+ if((d_trigger_mode == TRIG_MODE_NORM) || (d_trigger_mode ==
TRIG_MODE_AUTO)) {
+ _test_trigger_norm(d_outputsize, d_magbufs);
+ }
+ // If a trigger (FREE always triggers), plot and reset state
+ if(d_triggered) {
d_last_time = gr::high_res_timer_now();
d_qApplication->postEvent(d_main_gui,
new FreqUpdateEvent(d_magbufs,
d_outputsize));
+ _reset();
}
-
- d_index = 0;
- j += resid;
- }
- // Otherwise, copy what we received into the residbuf for next time
- else {
- for(int n = 0; n < d_nconnections; n++) {
- in = (const float*)input_items[n];
- memcpy(d_residbufs[n]+d_index, &in[j], sizeof(float)*datasize);
- }
- d_index += datasize;
- j += datasize;
}
}
- return j;
+ return noutput_items;
}
} /* namespace qtgui */
diff --git a/gr-qtgui/lib/freq_sink_f_impl.h b/gr-qtgui/lib/freq_sink_f_impl.h
index d03acba..2794942 100644
--- a/gr-qtgui/lib/freq_sink_f_impl.h
+++ b/gr-qtgui/lib/freq_sink_f_impl.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2012 Free Software Foundation, Inc.
+ * Copyright 2012,2014 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -35,8 +35,6 @@ namespace gr {
class QTGUI_API freq_sink_f_impl : public freq_sink_f
{
private:
- void forecast(int noutput_items, gr_vector_int &ninput_items_required);
-
void initialize();
int d_fftsize;
@@ -65,9 +63,9 @@ namespace gr {
gr::high_res_timer_type d_update_time;
gr::high_res_timer_type d_last_time;
- void windowreset();
+ bool windowreset();
void buildwindow();
- void fftresize();
+ bool fftresize();
void check_clicked();
void fft(float *data_out, const float *data_in, int size);
@@ -75,6 +73,19 @@ namespace gr {
// The message is a PMT pair (intern('freq'), double(frequency)).
void handle_set_freq(pmt::pmt_t msg);
+ // Members used for triggering scope
+ trigger_mode d_trigger_mode;
+ float d_trigger_level;
+ int d_trigger_channel;
+ pmt::pmt_t d_trigger_tag_key;
+ bool d_triggered;
+ int d_trigger_count;
+
+ void _reset();
+ void _gui_update_trigger();
+ void _test_trigger_tags(int start, int nitems);
+ void _test_trigger_norm(int nitems, std::vector<double*> inputs);
+
public:
freq_sink_f_impl(int size, int wintype,
double fc, double bw,
@@ -113,6 +124,9 @@ namespace gr {
void set_line_marker(int which, int marker);
void set_line_alpha(int which, double alpha);
void set_plot_pos_half(bool half);
+ void set_trigger_mode(trigger_mode mode,
+ float level, int channel,
+ const std::string &tag_key="");
std::string title();
std::string line_label(int which);
diff --git a/gr-qtgui/lib/freqdisplayform.cc b/gr-qtgui/lib/freqdisplayform.cc
index 8004c99..d7fa156 100644
--- a/gr-qtgui/lib/freqdisplayform.cc
+++ b/gr-qtgui/lib/freqdisplayform.cc
@@ -74,6 +74,37 @@ FreqDisplayForm::FreqDisplayForm(int nplots, QWidget* parent)
connect(d_clearmin_act, SIGNAL(triggered()),
this, SLOT(clearMinHold()));
+ // Set up the trigger menu
+ d_triggermenu = new QMenu("Trigger", this);
+ d_tr_mode_menu = new TriggerModeMenu(this);
+ d_tr_level_act = new PopupMenu("Level", this);
+ d_tr_channel_menu = new TriggerChannelMenu(nplots, this);
+ d_tr_tag_key_act = new PopupMenu("Tag Key", this);
+ d_triggermenu->addMenu(d_tr_mode_menu);
+ d_triggermenu->addAction(d_tr_level_act);
+ d_triggermenu->addMenu(d_tr_channel_menu);
+ d_triggermenu->addAction(d_tr_tag_key_act);
+ d_menu->addMenu(d_triggermenu);
+
+ setTriggerMode(gr::qtgui::TRIG_MODE_FREE);
+ connect(d_tr_mode_menu, SIGNAL(whichTrigger(gr::qtgui::trigger_mode)),
+ this, SLOT(setTriggerMode(gr::qtgui::trigger_mode)));
+ // updates trigger state by calling set level or set tag key.
+ connect(d_tr_mode_menu, SIGNAL(whichTrigger(gr::qtgui::trigger_mode)),
+ this, SLOT(updateTrigger(gr::qtgui::trigger_mode)));
+
+ setTriggerLevel(0);
+ connect(d_tr_level_act, SIGNAL(whichTrigger(QString)),
+ this, SLOT(setTriggerLevel(QString)));
+
+ setTriggerChannel(0);
+ connect(d_tr_channel_menu, SIGNAL(whichTrigger(int)),
+ this, SLOT(setTriggerChannel(int)));
+
+ setTriggerTagKey(std::string(""));
+ connect(d_tr_tag_key_act, SIGNAL(whichTrigger(QString)),
+ this, SLOT(setTriggerTagKey(QString)));
+
Reset();
connect(d_display_plot, SIGNAL(plotPointSelected(const QPointF)),
@@ -264,3 +295,84 @@ FreqDisplayForm::getClickedFreq() const
{
return d_clicked_freq;
}
+
+
+/********************************************************************
+ * TRIGGER METHODS
+ *******************************************************************/
+
+void
+FreqDisplayForm::setTriggerMode(gr::qtgui::trigger_mode mode)
+{
+ d_trig_mode = mode;
+ d_tr_mode_menu->getAction(mode)->setChecked(true);
+}
+
+void
+FreqDisplayForm::updateTrigger(gr::qtgui::trigger_mode mode)
+{
+ // If auto or normal mode, popup trigger level box to set
+ if((d_trig_mode == gr::qtgui::TRIG_MODE_AUTO) || (d_trig_mode ==
gr::qtgui::TRIG_MODE_NORM))
+ d_tr_level_act->activate(QAction::Trigger);
+
+ // if tag mode, popup tag key box to set
+ if(d_trig_mode == gr::qtgui::TRIG_MODE_TAG)
+ d_tr_tag_key_act->activate(QAction::Trigger);
+}
+
+gr::qtgui::trigger_mode
+FreqDisplayForm::getTriggerMode() const
+{
+ return d_trig_mode;
+}
+
+void
+FreqDisplayForm::setTriggerLevel(QString s)
+{
+ d_trig_level = s.toFloat();
+}
+
+void
+FreqDisplayForm::setTriggerLevel(float level)
+{
+ d_trig_level = level;
+ d_tr_level_act->setText(QString().setNum(d_trig_level));
+}
+
+float
+FreqDisplayForm::getTriggerLevel() const
+{
+ return d_trig_level;
+}
+
+void
+FreqDisplayForm::setTriggerChannel(int channel)
+{
+ d_trig_channel = channel;
+ d_tr_channel_menu->getAction(d_trig_channel)->setChecked(true);
+}
+
+int
+FreqDisplayForm::getTriggerChannel() const
+{
+ return d_trig_channel;
+}
+
+void
+FreqDisplayForm::setTriggerTagKey(QString s)
+{
+ d_trig_tag_key = s.toStdString();
+}
+
+void
+FreqDisplayForm::setTriggerTagKey(const std::string &key)
+{
+ d_trig_tag_key = key;
+ d_tr_tag_key_act->setText(QString().fromStdString(d_trig_tag_key));
+}
+
+std::string
+FreqDisplayForm::getTriggerTagKey() const
+{
+ return d_trig_tag_key;
+}
- [Commit-gnuradio] [gnuradio] branch master updated (d814381 -> 82779dc), git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 04/08: qtgui: fixed comment., git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 05/08: qtgui: added triggering to freq sinks.,
git <=
- [Commit-gnuradio] [gnuradio] 07/08: qtgui: removing malloc/free in fft function; doing once in ctor and when fftsize changes, instead., git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 06/08: qtgui: removes use of outputsize in freq sinks., git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 03/08: qtgui: allow toggle to only show positive half of waterfall spectrum., git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 02/08: qtgui: fixed problem with setting fft size and averaging of the float waterfall at runtime., git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 01/08: qtgui: allow float freq plot to only plot positive half of spectrum., git, 2014/10/23
- [Commit-gnuradio] [gnuradio] 08/08: Merge branch 'maint', git, 2014/10/23