commit-gnuradio
[Top][All Lists]
Advanced

[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;
+}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]