commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 10/11: uhd: Added freq hopping example, imp


From: git
Subject: [Commit-gnuradio] [gnuradio] 10/11: uhd: Added freq hopping example, improved tag handling in usrp_sink
Date: Sat, 26 Apr 2014 22:34:12 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch master
in repository gnuradio.

commit 284b75ff1a34e1a02245e4c759c6fa48dc2f4c17
Author: Martin Braun <address@hidden>
Date:   Tue Apr 8 17:22:54 2014 +0200

    uhd: Added freq hopping example, improved tag handling in usrp_sink
---
 gr-uhd/examples/python/freq_hopping.py  | 216 ++++++++++++++++++++++++++++++++
 gr-uhd/grc/gen_uhd_usrp_blocks.py       |   6 +-
 gr-uhd/include/gnuradio/uhd/usrp_sink.h |   8 +-
 gr-uhd/lib/usrp_sink_impl.cc            | 114 ++++++++++-------
 4 files changed, 296 insertions(+), 48 deletions(-)

diff --git a/gr-uhd/examples/python/freq_hopping.py 
b/gr-uhd/examples/python/freq_hopping.py
new file mode 100755
index 0000000..3b4c426
--- /dev/null
+++ b/gr-uhd/examples/python/freq_hopping.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 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 3, 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.
+#
+
+"""
+TXs a waveform (either from a file, or a sinusoid) in a frequency-hopping 
manner.
+"""
+
+import time
+import numpy
+import argparse
+import pmt
+from gnuradio import gr
+from gnuradio import blocks
+from gnuradio import uhd
+
+def setup_parser():
+    """ Setup the parser for the frequency hopper. """
+    parser = argparse.ArgumentParser(
+            description="Transmit a signal in a frequency-hopping manner, 
using tx_freq tags."
+    )
+    parser.add_argument('-i', '--input-file', type=file, default=None,
+            help="File with samples to transmit. If left out, will transmit a 
sinusoid.")
+    parser.add_argument("-a", "--args", default="",
+            help="UHD device address args.")
+    parser.add_argument("--spec", default="",
+            help="UHD subdev spec.")
+    parser.add_argument("--antenna", default="",
+            help="UHD antenna settings.")
+    parser.add_argument("--gain", default=None, type=float,
+            help="USRP gain (defaults to mid-point in dB).")
+    parser.add_argument("-r", "--rate", type=float, default=1e6,
+            help="Sampling rate")
+    parser.add_argument("-N", "--samp-per-burst", type=int, default=10000,
+            help="Samples per burst")
+    parser.add_argument("-t", "--hop-time", type=float, default=1000,
+            help="Time between hops in milliseconds. This must be larger than 
or equal to the burst duration as set by --samp-per-burst")
+    parser.add_argument("-f", "--freq", type=float, default=2.45e9,
+            help="Base frequency. This is the lowest frequency at which the 
USRP will Tx.")
+    parser.add_argument("-d", "--freq-delta", type=float, default=1e6,
+            help="Channel spacing.")
+    parser.add_argument("-c", "--num-channels", type=int, default=5,
+            help="Number of channels.")
+    parser.add_argument("-B", "--num-bursts", type=int, default=30,
+            help="Number of bursts to transmit before terminating.")
+    parser.add_argument("-p", "--post-tuning", action='count',
+            help="Tune after transmitting. Default is to tune immediately 
before transmitting.")
+    parser.add_argument("-v", "--verbose", action='count',
+            help="Print more information.")
+    return parser
+
+
+class FrequencyHopperSrc(gr.hier_block2):
+    """ Provides tags for frequency hopping """
+    def __init__(
+            self,
+            n_bursts, n_channels,
+            freq_delta, base_freq,
+            burst_length, base_time, hop_time,
+            post_tuning=False,
+            tx_gain=0,
+            verbose=False
+        ):
+        gr.hier_block2.__init__(self,
+            "FrequencyHopperSrc",
+            gr.io_signature(1, 1, gr.sizeof_gr_complex),
+            gr.io_signature(1, 1, gr.sizeof_gr_complex),
+        )
+        n_samples_total = n_bursts * burst_length
+        self.hop_sequence = numpy.arange(base_freq, base_freq + n_channels * 
freq_delta, freq_delta)
+        numpy.random.shuffle(self.hop_sequence)
+        self.hop_sequence = [self.hop_sequence[x % n_channels] for x in 
xrange(n_bursts)]
+        if verbose:
+            print "Hop Frequencies  | Hop Pattern" 
+            print "=================|================================"
+            for f in self.hop_sequence:
+                print "{:6.3f} MHz      |  ".format(f/1e6),
+                if n_channels < 50:
+                    print " " * int((f - base_freq) / freq_delta) + "#"
+                else:
+                    print "\n"
+            print "=================|================================"
+        # There's no real point in setting the gain via tag for this 
application,
+        # but this is an example to show you how to do it.
+        gain_tag = gr.tag_t()
+        gain_tag.offset = 0
+        gain_tag.key = pmt.string_to_symbol('tx_command')
+        gain_tag.value = pmt.cons(
+                pmt.intern("gain"),
+                pmt.to_pmt((0, tx_gain))
+        )
+        tag_list = [gain_tag,]
+        for i in xrange(n_bursts):
+            tune_tag = gr.tag_t()
+            tune_tag.offset = i * burst_length
+            if i > 0 and post_tuning:
+                tune_tag.offset -= 1 # Move it to last sample of previous burst
+            tune_tag.key = pmt.string_to_symbol('tx_freq')
+            tune_tag.value = pmt.to_pmt((0, self.hop_sequence[i]))
+            tag_list.append(tune_tag)
+            length_tag = gr.tag_t()
+            length_tag.offset = i * burst_length
+            length_tag.key = pmt.string_to_symbol('packet_len')
+            length_tag.value = pmt.from_long(burst_length)
+            tag_list.append(length_tag)
+            time_tag = gr.tag_t()
+            time_tag.offset = i * burst_length
+            time_tag.key = pmt.string_to_symbol('tx_time')
+            time_tag.value = pmt.make_tuple(
+                    pmt.from_uint64(int(base_time + i * hop_time)),
+                    pmt.from_double((base_time + i * hop_time) % 1),
+            )
+            tag_list.append(time_tag)
+        tag_source = blocks.vector_source_c((1.0,) * n_samples_total, 
repeat=False, tags=tag_list)
+        mult = blocks.multiply_cc()
+        self.connect(self, mult, self)
+        self.connect(tag_source, (mult, 1))
+
+
+class FlowGraph(gr.top_block):
+    """ Flow graph that does the frequency hopping. """
+    def __init__(self, options):
+        gr.top_block.__init__(self)
+
+        if options.input_file is not None:
+            src = blocks.file_source(gr.sizeof_gr_complex, options.filename, 
repeat=True)
+        else:
+            src = blocks.vector_source_c((.5,) * int(1e6) * 2, repeat=True)
+        # Setup USRP
+        self.u = uhd.usrp_sink(options.args, uhd.stream_args('fc32'), 
"packet_len")
+        if(options.spec):
+            self.u.set_subdev_spec(options.spec, 0)
+        if(options.antenna):
+            self.u.set_antenna(options.antenna, 0)
+        self.u.set_samp_rate(options.rate)
+        # Gain is set in the hopper block
+        if options.gain is None:
+            g = self.u.get_gain_range()
+            options.gain = float(g.start()+g.stop())/2.0
+        print "-- Setting gain to {} dB".format(options.gain)
+        r = self.u.set_center_freq(options.freq)
+        if not r:
+            print '[ERROR] Failed to set base frequency.'
+            raise SystemExit, 1
+        hopper_block = FrequencyHopperSrc(
+                options.num_bursts, options.num_channels,
+                options.freq_delta, options.freq,
+                options.samp_per_burst, 1.0, options.hop_time / 1000.,
+                options.post_tuning,
+                options.gain,
+                options.verbose,
+        )
+        self.connect(src, hopper_block, self.u)
+
+def print_hopper_stats(args):
+    """ Nothing to do with Grace Hopper """
+    print """
+Parameter          | Value
+===================+=========================
+Hop Interval       | {hop_time} ms
+Burst duration     | {hop_duration} ms
+Lowest Frequency   | {lowest_freq:6.3f} MHz
+Highest Frequency  | {highest_freq:6.3f} MHz
+Frequency spacing  | {freq_delta:6.4f} MHz
+Number of channels | {num_channels}
+Sampling rate      | {rate} Msps
+Transmit Gain      | {gain} dB
+===================+=========================
+    """.format(
+            hop_time=args.hop_time,
+            hop_duration=1000.0/args.rate*args.samp_per_burst,
+            gain=args.gain,
+            lowest_freq=args.freq/1e6,
+            highest_freq=(args.freq + (args.num_channels-1) * 
args.freq_delta)/1e6,
+            freq_delta=args.freq_delta/1e6,
+            num_channels=args.num_channels,
+            rate=args.rate/1e6,
+        )
+
+def main():
+    """ Go, go, go! """
+    args = setup_parser().parse_args()
+    if (1.0 * args.samp_per_burst / args.rate) > args.hop_time * 1e-3:
+        print "Burst duration must be smaller than hop time."
+        raise SystemExit, 1
+    if args.verbose:
+        print_hopper_stats(args)
+    top_block = FlowGraph(args)
+    print "Starting to hop, skip and jump... press Ctrl+C to exit."
+    top_block.u.set_time_now(uhd.time_spec(0.0))
+    top_block.run()
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+
diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py 
b/gr-uhd/grc/gen_uhd_usrp_blocks.py
index e6e3201..94a1ed8 100644
--- a/gr-uhd/grc/gen_uhd_usrp_blocks.py
+++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py
@@ -27,8 +27,8 @@ MAIN_TMPL = """\
        <import>from gnuradio import uhd</import>
        <import>import time</import>
        <make>uhd.usrp_$(sourk)(
-       device_addr=\$dev_addr,
-       stream_args=uhd.stream_args(
+       \$dev_addr,
+       uhd.stream_args(
                cpu_format="\$type",
                \#if \$otw()
                otw_format=\$otw,
@@ -438,7 +438,7 @@ LENTAG_PARAM = """  <param>
 
 LENTAG_ARG = """
        #if $len_tag_name()
-       length_tag_name=$len_tag_name,
+       $len_tag_name,
        #end if"""
 
 def parse_tmpl(_tmpl, **kwargs):
diff --git a/gr-uhd/include/gnuradio/uhd/usrp_sink.h 
b/gr-uhd/include/gnuradio/uhd/usrp_sink.h
index 273ee4c..46d8351 100644
--- a/gr-uhd/include/gnuradio/uhd/usrp_sink.h
+++ b/gr-uhd/include/gnuradio/uhd/usrp_sink.h
@@ -27,6 +27,7 @@
 #include <gnuradio/sync_block.h>
 #include <uhd/usrp/multi_usrp.hpp>
 
+// TODO In 3.8, UHD 3.4 will be required and we can remove all these ifdefs
 #ifndef INCLUDED_UHD_STREAM_HPP
 namespace uhd {
   struct GR_UHD_API stream_args_t
@@ -61,11 +62,14 @@ namespace gr {
 
       /*!
        * \brief DEPRECATED Make a new USRP sink block using the deprecated 
io_type_t.
+       *
+       * This function will go away in 3.8.
+       *
        * \ingroup uhd_blk
        */
       static sptr make(const ::uhd::device_addr_t &device_addr,
-                       const ::uhd::io_type_t &io_type,
-                       size_t num_channels);
+                      const ::uhd::io_type_t &io_type,
+                      size_t num_channels);
 
       /*!
        * \brief Make a new USRP sink block.
diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc
index 62b5701..02aa1fd 100644
--- a/gr-uhd/lib/usrp_sink_impl.cc
+++ b/gr-uhd/lib/usrp_sink_impl.cc
@@ -20,19 +20,20 @@
  * Boston, MA 02110-1301, USA.
  */
 
+#include <climits>
+#include <stdexcept>
 #include "usrp_sink_impl.h"
 #include "gr_uhd_common.h"
 #include <gnuradio/io_signature.h>
 #include <boost/make_shared.hpp>
-#include <stdexcept>
 
 namespace gr {
   namespace uhd {
 
     usrp_sink::sptr
     usrp_sink::make(const ::uhd::device_addr_t &device_addr,
-                    const ::uhd::io_type_t &io_type,
-                    size_t num_channels)
+                   const ::uhd::io_type_t &io_type,
+                   size_t num_channels)
     {
       //fill in the streamer args
       ::uhd::stream_args_t stream_args;
@@ -44,7 +45,7 @@ namespace gr {
 
       stream_args.otw_format = "sc16"; //only sc16 known to work
       for(size_t chan = 0; chan < num_channels; chan++)
-        stream_args.channels.push_back(chan); //linear mapping
+       stream_args.channels.push_back(chan); //linear mapping
 
       return usrp_sink::make(device_addr, stream_args, "");
     }
@@ -67,7 +68,7 @@ namespace gr {
                       io_signature::make(0, 0, 0)),
         _stream_args(stream_args),
         _nchan(stream_args.channels.size()),
-        _stream_now(_nchan == 1),
+        _stream_now(_nchan == 1 and length_tag_name.empty()),
         _start_time_set(false),
         _length_tag_key(length_tag_name.empty() ? pmt::PMT_NIL : 
pmt::string_to_symbol(length_tag_name)),
         _nitems_to_send(0),
@@ -549,6 +550,10 @@ namespace gr {
         }
       }
 
+      // We send the EOB manually to avoid sending several EOBs in case of 
fragmentation
+      bool eob = _metadata.end_of_burst;
+      _metadata.end_of_burst = false;
+
 #ifdef GR_UHD_USE_STREAM_API
       //send all ninput_items with metadata
       const size_t num_sent = _tx_stream->send
@@ -564,13 +569,29 @@ namespace gr {
         _nitems_to_send -= long(num_sent);
       }
 
-      if (_call_tune) {
-        _set_center_freq_from_internals_allchans();
-       _call_tune = false;
-      }
-
       //increment the timespec by the number of samples sent
       _metadata.time_spec += ::uhd::time_spec_t(0, num_sent, _sample_rate);
+
+      // Some post-processing tasks if we actually transmitted the entire burst
+      if (num_sent == size_t(ninput_items)) {
+        if (_call_tune) {
+          _set_center_freq_from_internals_allchans();
+          _call_tune = false;
+        }
+
+        if (eob) {
+#ifdef GR_UHD_USE_STREAM_API
+          _metadata.end_of_burst = true;
+          _tx_stream->send
+            (gr_vector_const_void_star(_nchan), 0, _metadata, 1.0);
+#else
+          _dev->get_device()->send
+            (gr_vector_const_void_star(_nchan), 0, _metadata,
+             *_type, ::uhd::device::SEND_MODE_ONE_PACKET, 1.0);
+#endif
+        }
+      }
+
       return num_sent;
     }
 
@@ -589,16 +610,21 @@ namespace gr {
 
       // Go through tag list until something indicates the end of a burst.
       bool found_eob = false;
-      bool found_in_burst_cmd_tag = false;
-      uint64_t in_burst_cmd_offset = 0;
+      bool found_freq_tag_in_burst = false;
+      uint64_t freq_cmd_offset = 0;
+      double freq_cmd_freq;
+      int freq_cmd_chan;
       BOOST_FOREACH(const tag_t &my_tag, _tags) {
         const uint64_t my_tag_count = my_tag.offset;
         const pmt::pmt_t &key = my_tag.key;
         const pmt::pmt_t &value = my_tag.value;
 
-        if (my_tag_count > max_count) {
+        if (my_tag_count >= max_count) {
           break;
         }
+       else if (not pmt::is_null(_length_tag_key) and my_tag_count > 
samp0_count + _nitems_to_send) {
+          break;
+       }
 
         /* I. Bursts that can only be on the first sample of burst
          *
@@ -612,7 +638,7 @@ namespace gr {
          * we stop before that tag so they are on the first item the next time 
round.
          */
         else if (pmt::equal(key, COMMAND_KEY)) {
-          if (my_tag.offset != samp0_count) {
+          if (my_tag_count != samp0_count) {
             max_count = my_tag_count;
             break;
           }
@@ -621,7 +647,7 @@ namespace gr {
 
         //set the time specification in the metadata
         else if(pmt::equal(key, TIME_KEY)) {
-          if (my_tag.offset != samp0_count) {
+          if (my_tag_count != samp0_count) {
             max_count = my_tag_count;
             break;
           }
@@ -642,14 +668,14 @@ namespace gr {
 
         //length_tag found; set the start of burst flag in the metadata
         else if(not pmt::is_null(_length_tag_key) and pmt::equal(key, 
_length_tag_key)) {
-          if (my_tag.offset != samp0_count) {
+          if (my_tag_count != samp0_count) {
             max_count = my_tag_count;
-            break;
+           break;
           }
           //If there are still items left to send, the current burst has been 
preempted.
           //Set the items remaining counter to the new burst length. Notify 
the user of
           //the tag preemption.
-          if(_nitems_to_send > 0) {
+         else if(_nitems_to_send > 0) {
               std::cerr << "tP" << std::flush;
           }
           _nitems_to_send = pmt::to_long(value);
@@ -659,23 +685,30 @@ namespace gr {
         /* II. Bursts that can be on the first OR last sample of a burst
          *
          * This includes:
-         * - tx_freq
+         * - tx_freq (tags that don't actually change the frequency are 
ignored)
          *
          * With these tags, we check if they're at the start of a burst, and do
          * the appropriate action. Otherwise, make sure the corresponding 
sample
          * is the last one.
          */
-        else if(pmt::equal(key, FREQ_KEY)) {
-          if (my_tag.offset != samp0_count) {
-            max_count = my_tag_count + 1;
-          }
+       else if (pmt::equal(key, FREQ_KEY) and my_tag_count == samp0_count) {
+          int chan = pmt::to_long(pmt::tuple_ref(value, 0));
+          double new_freq = pmt::to_double(pmt::tuple_ref(value, 1));
+          if (new_freq != _curr_freq[chan]) {
+             _curr_freq[chan] = new_freq;
+             _set_center_freq_from_internals(chan);
+         }
+       }
+
+        else if(pmt::equal(key, FREQ_KEY) and not found_freq_tag_in_burst) {
           int chan = pmt::to_long(pmt::tuple_ref(value, 0));
           double new_freq = pmt::to_double(pmt::tuple_ref(value, 1));
           if (new_freq != _curr_freq[chan]) {
-            found_in_burst_cmd_tag = true;
-            in_burst_cmd_offset = my_tag_count;
-            _chans_to_tune[chan] = true;
-            _curr_freq[chan] = new_freq;
+           freq_cmd_freq = new_freq;
+            freq_cmd_chan = chan;
+           freq_cmd_offset = my_tag_count;
+           max_count = my_tag_count + 1;
+           found_freq_tag_in_burst = true;
           }
         }
 
@@ -697,30 +730,25 @@ namespace gr {
         found_eob = true;
       }
 
-      if (found_in_burst_cmd_tag and in_burst_cmd_offset == samp0_count) {
-        // Currently, this means there's a tx_freq tag in there
-        // If it's at the beginning of the burst, tune immediately
-        for (size_t chan = 0; chan < _nchan; chan++) {
-          if (_chans_to_tune[chan]) {
-            _set_center_freq_from_internals(chan);
-          }
+      if (found_freq_tag_in_burst) {
+        if (not found_eob) {
+          // If it's in the middle of a burst, only send() until before the tag
+          max_count = freq_cmd_offset;
+        } else if (freq_cmd_offset < max_count) {
+          // Otherwise, tune after work()
+         _curr_freq[freq_cmd_chan] = freq_cmd_freq;
+         _chans_to_tune[freq_cmd_chan] = true;
+          _call_tune = true;
         }
-      } else if (not found_eob) {
-        // If it's in the middle of a burst, only send() until before the tag
-        max_count = in_burst_cmd_offset;
-      } else {
-       // Otherwise, tune after work()
-        _call_tune = true;
       }
 
       // Only transmit up to and including end of burst,
       // or everything if no burst boundaries are found.
-      ninput_items = max_count - samp0_count;
+      ninput_items = int(max_count - samp0_count);
 
       // TODO unset has_time_spec for bursty behaviour w/o time!
-
       //time will not be set unless a time tag is found
-      _metadata.has_time_spec = false;
+      //_metadata.has_time_spec = false;
 
     } // end tag_work()
 



reply via email to

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