From 72c625f7e50b65dc3b642112762e9eb1d633bd42 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Wed, 24 Dec 2008 08:10:48 +0000 Subject: [PATCH] Merged r10071:10164 from features/cppdb-test into trunk. Implements the fully native C++ API for the USRP. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10165 221aa14e-8319-0410-a670-987f0aec2ac5 --- Makefile.common | 3 +- README.building-boost | 2 +- config/grc_gr_usrp.m4 | 2 + configure.ac | 2 +- gnuradio-examples/c++/Makefile.am | 4 +- .../python/apps/hf_explorer/hfx2.py | 4 +- gnuradio-examples/python/dect/usrp_source.py | 4 +- .../python/digital-bert/benchmark_tx.py | 2 +- .../python/digital/transmit_path.py | 2 +- .../python/multi-antenna/multi_fft.py | 10 +- .../python/multi-antenna/multi_file.py | 10 +- .../python/multi-antenna/multi_scope.py | 10 +- .../python/multi_usrp/multi_usrp_oscope.py | 4 +- .../python/ofdm/benchmark_ofdm_tx.py | 2 +- gnuradio-examples/python/ofdm/tunnel.py | 4 +- gnuradio-examples/python/usrp/fm_tx4.py | 14 +- .../python/usrp/fm_tx_2_daughterboards.py | 4 +- .../python/usrp/usrp_nbfm_ptt.py | 2 +- gr-usrp/Makefile.am | 10 +- gr-usrp/apps/Makefile.am | 57 + gr-usrp/apps/usrp_rx_cfile.cc | 245 ++++ gr-usrp/apps/usrp_rx_cfile.h | 62 + gr-usrp/apps/usrp_siggen.cc | 214 +++ gr-usrp/apps/usrp_siggen.h | 52 + gr-usrp/gnuradio-usrp.pc.in | 11 + gr-usrp/src/Makefile.am | 179 +-- .../src/{db_instantiator.py => __init__.py} | 15 +- gr-usrp/src/db_base.py | 264 ---- gr-usrp/src/db_basic.py | 252 ---- gr-usrp/src/db_dbs_rx.py | 345 ----- gr-usrp/src/db_dtt754.py | 229 ---- gr-usrp/src/db_dtt768.py | 203 --- gr-usrp/src/db_flexrf.py | 701 ---------- gr-usrp/src/db_flexrf_mimo.py | 286 ---- gr-usrp/src/db_tv_rx.py | 198 --- gr-usrp/src/db_wbx.py | 622 --------- gr-usrp/src/db_xcvr2450.py | 538 -------- gr-usrp/src/qa_usrp.py | 2 +- gr-usrp/src/usrp.i | 144 +++ gr-usrp/src/usrp.py | 482 ------- gr-usrp/src/usrp1.i | 657 ---------- gr-usrp/src/usrp1_sink_base.cc | 359 ------ gr-usrp/src/usrp1_sink_base.h | 359 ------ gr-usrp/src/usrp1_source_base.cc | 425 ------ gr-usrp/src/usrp_base.cc | 316 +++++ .../src/{usrp1_source_base.h => usrp_base.h} | 456 ++++--- gr-usrp/src/usrp_base.i | 83 ++ gr-usrp/src/usrp_sink_base.cc | 241 ++++ gr-usrp/src/usrp_sink_base.h | 151 +++ gr-usrp/src/usrp_sink_base.i | 54 + .../src/{usrp1_sink_c.cc => usrp_sink_c.cc} | 16 +- gr-usrp/src/{usrp1_sink_c.h => usrp_sink_c.h} | 42 +- gr-usrp/src/usrp_sink_c.i | 47 + .../src/{usrp1_sink_s.cc => usrp_sink_s.cc} | 16 +- gr-usrp/src/{usrp1_sink_s.h => usrp_sink_s.h} | 42 +- gr-usrp/src/usrp_sink_s.i | 47 + gr-usrp/src/usrp_source_base.cc | 295 +++++ gr-usrp/src/usrp_source_base.h | 219 ++++ gr-usrp/src/usrp_source_base.i | 63 + .../{usrp1_source_c.cc => usrp_source_c.cc} | 18 +- .../src/{usrp1_source_c.h => usrp_source_c.h} | 42 +- gr-usrp/src/usrp_source_c.i | 48 + .../{usrp1_source_s.cc => usrp_source_s.cc} | 18 +- .../src/{usrp1_source_s.h => usrp_source_s.h} | 44 +- gr-usrp/src/usrp_source_s.i | 48 + gr-usrp/src/usrp_standard.i | 36 + gr-utils/src/python/usrp_fft.py | 4 +- gr-utils/src/python/usrp_oscope.py | 4 +- gr-utils/src/python/usrp_siggen.py | 3 +- grc/src/grc_gnuradio/usrp/simple_usrp.py | 34 +- usrp/host/apps/test_usrp_standard_rx.cc | 10 +- usrp/host/apps/test_usrp_standard_tx.cc | 12 +- usrp/host/apps/usrp_cal_dc_offset.cc | 10 +- usrp/host/lib/inband/qa_inband_usrp_server.cc | 6 + usrp/host/lib/inband/usrp_usb_interface.cc | 17 +- usrp/host/lib/inband/usrp_usb_interface.h | 6 +- usrp/host/lib/legacy/Makefile.am | 40 +- usrp/host/lib/legacy/db_base.cc | 245 ++++ usrp/host/lib/legacy/db_base.h | 114 ++ usrp/host/lib/legacy/db_base.i | 101 ++ usrp/host/lib/legacy/db_base_impl.h | 33 + usrp/host/lib/legacy/db_basic.cc | 263 ++++ usrp/host/lib/legacy/db_basic.h | 99 ++ usrp/host/lib/legacy/db_boards.cc | 215 +++ usrp/host/lib/legacy/db_boards.h | 33 + usrp/host/lib/legacy/db_dbs_rx.cc | 491 +++++++ usrp/host/lib/legacy/db_dbs_rx.h | 81 ++ usrp/host/lib/legacy/db_dtt754.cc | 321 +++++ usrp/host/lib/legacy/db_dtt754.h | 57 + usrp/host/lib/legacy/db_dtt768.cc | 294 +++++ usrp/host/lib/legacy/db_dtt768.h | 57 + usrp/host/lib/legacy/db_flexrf.cc | 1148 +++++++++++++++++ usrp/host/lib/legacy/db_flexrf.h | 355 +++++ usrp/host/lib/legacy/db_flexrf_mimo.cc | 276 ++++ usrp/host/lib/legacy/db_flexrf_mimo.h | 163 +++ usrp/host/lib/legacy/db_tv_rx.cc | 274 ++++ usrp/host/lib/legacy/db_tv_rx.h | 56 + usrp/host/lib/legacy/db_util.cc | 54 + usrp/host/lib/legacy/db_util.h | 31 + usrp/host/lib/legacy/db_wbx.cc | 953 ++++++++++++++ usrp/host/lib/legacy/db_wbx.h | 221 ++++ usrp/host/lib/legacy/db_xcvr2450.cc | 762 +++++++++++ usrp/host/lib/legacy/db_xcvr2450.h | 221 ++++ usrp/host/lib/legacy/usrp_basic.cc | 694 +++++++--- usrp/host/lib/legacy/usrp_basic.h | 809 +++++++----- usrp/host/lib/legacy/usrp_standard.cc | 370 +++++- usrp/host/lib/legacy/usrp_standard.h | 114 +- usrp/host/lib/legacy/usrp_subdev_spec.h | 50 + usrp/host/lib/legacy/usrp_tune_result.h | 44 + usrp2/host/include/usrp2/tune_result.h | 11 +- 110 files changed, 11465 insertions(+), 7029 deletions(-) create mode 100644 gr-usrp/apps/Makefile.am create mode 100644 gr-usrp/apps/usrp_rx_cfile.cc create mode 100644 gr-usrp/apps/usrp_rx_cfile.h create mode 100644 gr-usrp/apps/usrp_siggen.cc create mode 100644 gr-usrp/apps/usrp_siggen.h create mode 100644 gr-usrp/gnuradio-usrp.pc.in rename gr-usrp/src/{db_instantiator.py => __init__.py} (65%) delete mode 100644 gr-usrp/src/db_base.py delete mode 100644 gr-usrp/src/db_basic.py delete mode 100644 gr-usrp/src/db_dbs_rx.py delete mode 100644 gr-usrp/src/db_dtt754.py delete mode 100644 gr-usrp/src/db_dtt768.py delete mode 100644 gr-usrp/src/db_flexrf.py delete mode 100644 gr-usrp/src/db_flexrf_mimo.py delete mode 100644 gr-usrp/src/db_tv_rx.py delete mode 100644 gr-usrp/src/db_wbx.py delete mode 100644 gr-usrp/src/db_xcvr2450.py create mode 100644 gr-usrp/src/usrp.i delete mode 100644 gr-usrp/src/usrp.py delete mode 100644 gr-usrp/src/usrp1.i delete mode 100644 gr-usrp/src/usrp1_sink_base.cc delete mode 100644 gr-usrp/src/usrp1_sink_base.h delete mode 100644 gr-usrp/src/usrp1_source_base.cc create mode 100644 gr-usrp/src/usrp_base.cc rename gr-usrp/src/{usrp1_source_base.h => usrp_base.h} (54%) create mode 100644 gr-usrp/src/usrp_base.i create mode 100644 gr-usrp/src/usrp_sink_base.cc create mode 100644 gr-usrp/src/usrp_sink_base.h create mode 100644 gr-usrp/src/usrp_sink_base.i rename gr-usrp/src/{usrp1_sink_c.cc => usrp_sink_c.cc} (89%) rename gr-usrp/src/{usrp1_sink_c.h => usrp_sink_c.h} (72%) create mode 100644 gr-usrp/src/usrp_sink_c.i rename gr-usrp/src/{usrp1_sink_s.cc => usrp_sink_s.cc} (88%) rename gr-usrp/src/{usrp1_sink_s.h => usrp_sink_s.h} (72%) create mode 100644 gr-usrp/src/usrp_sink_s.i create mode 100644 gr-usrp/src/usrp_source_base.cc create mode 100644 gr-usrp/src/usrp_source_base.h create mode 100644 gr-usrp/src/usrp_source_base.i rename gr-usrp/src/{usrp1_source_c.cc => usrp_source_c.cc} (88%) rename gr-usrp/src/{usrp1_source_c.h => usrp_source_c.h} (73%) create mode 100644 gr-usrp/src/usrp_source_c.i rename gr-usrp/src/{usrp1_source_s.cc => usrp_source_s.cc} (87%) rename gr-usrp/src/{usrp1_source_s.h => usrp_source_s.h} (72%) create mode 100644 gr-usrp/src/usrp_source_s.i create mode 100644 gr-usrp/src/usrp_standard.i create mode 100644 usrp/host/lib/legacy/db_base.cc create mode 100644 usrp/host/lib/legacy/db_base.h create mode 100644 usrp/host/lib/legacy/db_base.i create mode 100644 usrp/host/lib/legacy/db_base_impl.h create mode 100644 usrp/host/lib/legacy/db_basic.cc create mode 100644 usrp/host/lib/legacy/db_basic.h create mode 100644 usrp/host/lib/legacy/db_boards.cc create mode 100644 usrp/host/lib/legacy/db_boards.h create mode 100644 usrp/host/lib/legacy/db_dbs_rx.cc create mode 100644 usrp/host/lib/legacy/db_dbs_rx.h create mode 100644 usrp/host/lib/legacy/db_dtt754.cc create mode 100644 usrp/host/lib/legacy/db_dtt754.h create mode 100644 usrp/host/lib/legacy/db_dtt768.cc create mode 100644 usrp/host/lib/legacy/db_dtt768.h create mode 100644 usrp/host/lib/legacy/db_flexrf.cc create mode 100644 usrp/host/lib/legacy/db_flexrf.h create mode 100644 usrp/host/lib/legacy/db_flexrf_mimo.cc create mode 100644 usrp/host/lib/legacy/db_flexrf_mimo.h create mode 100644 usrp/host/lib/legacy/db_tv_rx.cc create mode 100644 usrp/host/lib/legacy/db_tv_rx.h create mode 100644 usrp/host/lib/legacy/db_util.cc create mode 100644 usrp/host/lib/legacy/db_util.h create mode 100644 usrp/host/lib/legacy/db_wbx.cc create mode 100644 usrp/host/lib/legacy/db_wbx.h create mode 100644 usrp/host/lib/legacy/db_xcvr2450.cc create mode 100644 usrp/host/lib/legacy/db_xcvr2450.h create mode 100644 usrp/host/lib/legacy/usrp_subdev_spec.h create mode 100644 usrp/host/lib/legacy/usrp_tune_result.h diff --git a/Makefile.common b/Makefile.common index f7c88b0d..35cd1a30 100644 --- a/Makefile.common +++ b/Makefile.common @@ -56,7 +56,8 @@ WITH_INCLUDES = @with_INCLUDES@ WITH_SWIG_INCLUDES = @with_SWIG_INCLUDES@ # swig flags -SWIGPYTHONFLAGS = -fvirtual -python -modern +# -w511 turns off keyword argument warning +SWIGPYTHONFLAGS = -fvirtual -python -modern -keyword -w511 # How to link in the top-level omnithreads library from inside the tree OMNITHREAD_INCLUDES = @omnithread_INCLUDES@ diff --git a/README.building-boost b/README.building-boost index 0e7059de..511adb58 100644 --- a/README.building-boost +++ b/README.building-boost @@ -14,7 +14,7 @@ $ cd boost_1_36_0 $ BOOST_PREFIX=/opt/boost_1_36_0 -$ ./configure --prefix=$BOOST_PREFIX --with-libraries=thread,date_time +$ ./configure --prefix=$BOOST_PREFIX --with-libraries=thread,date_time,program_options $ make $ make install diff --git a/config/grc_gr_usrp.m4 b/config/grc_gr_usrp.m4 index c28d9757..1f2cd1ac 100644 --- a/config/grc_gr_usrp.m4 +++ b/config/grc_gr_usrp.m4 @@ -26,8 +26,10 @@ AC_DEFUN([GRC_GR_USRP],[ AC_CONFIG_FILES([ \ gr-usrp/Makefile \ + gr-usrp/gnuradio-usrp.pc \ gr-usrp/src/Makefile \ gr-usrp/src/run_tests \ + gr-usrp/apps/Makefile \ ]) GRC_BUILD_CONDITIONAL(gr-usrp,[ diff --git a/configure.ac b/configure.ac index cd63f5b1..bb70dd0c 100644 --- a/configure.ac +++ b/configure.ac @@ -230,7 +230,7 @@ dnl AX_BOOST_DATE_TIME dnl AX_BOOST_FILESYSTEM dnl AX_BOOST_IOSTREAMS -dnl AX_BOOST_PROGRAM_OPTIONS +AX_BOOST_PROGRAM_OPTIONS dnl AX_BOOST_REGEX dnl AX_BOOST_SERIALIZATION dnl AX_BOOST_SIGNALS diff --git a/gnuradio-examples/c++/Makefile.am b/gnuradio-examples/c++/Makefile.am index 5ac08607..43c63847 100644 --- a/gnuradio-examples/c++/Makefile.am +++ b/gnuradio-examples/c++/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2006 Free Software Foundation, Inc. +# Copyright 2006,2008 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,4 +20,4 @@ # include $(top_srcdir)/Makefile.common -# SUBDIRS = dial_tone +#SUBDIRS = dial_tone diff --git a/gnuradio-examples/python/apps/hf_explorer/hfx2.py b/gnuradio-examples/python/apps/hf_explorer/hfx2.py index 00b1eddf..00a3b904 100755 --- a/gnuradio-examples/python/apps/hf_explorer/hfx2.py +++ b/gnuradio-examples/python/apps/hf_explorer/hfx2.py @@ -118,9 +118,9 @@ def pick_subdevice(u): If there's a daughterboard on B, select B. Otherwise, select A. """ - if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db[1][0].dbid() >= 0: + if u.db(1, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gnuradio-examples/python/dect/usrp_source.py b/gnuradio-examples/python/dect/usrp_source.py index 6a779840..df19ff27 100644 --- a/gnuradio-examples/python/dect/usrp_source.py +++ b/gnuradio-examples/python/dect/usrp_source.py @@ -64,9 +64,9 @@ class usrp_source_c(gr.hier_block2): If there's a daughterboard on B, select B. Otherwise, select A. """ - if self._u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if self._u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if self._u.db[1][0].dbid() >= 0: + if self._u.db(1, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gnuradio-examples/python/digital-bert/benchmark_tx.py b/gnuradio-examples/python/digital-bert/benchmark_tx.py index 1778a74b..000f4bca 100755 --- a/gnuradio-examples/python/digital-bert/benchmark_tx.py +++ b/gnuradio-examples/python/digital-bert/benchmark_tx.py @@ -60,7 +60,7 @@ class tx_bpsk_block(gr.top_block): subdev_spec = usrp.pick_tx_subdevice(self._usrp) self._usrp.set_mux(usrp.determine_tx_mux_value(self._usrp, subdev_spec)) self._subdev = usrp.selected_subdev(self._usrp, subdev_spec) - tr = usrp.tune(self._usrp, self._subdev._which, self._subdev, freq) + tr = usrp.tune(self._usrp, self._subdev.which(), self._subdev, freq) if not (tr): print "Failed to tune to center frequency!" else: diff --git a/gnuradio-examples/python/digital/transmit_path.py b/gnuradio-examples/python/digital/transmit_path.py index 69989606..250c3f04 100644 --- a/gnuradio-examples/python/digital/transmit_path.py +++ b/gnuradio-examples/python/digital/transmit_path.py @@ -141,7 +141,7 @@ class transmit_path(gr.hier_block2): the result of that operation and our target_frequency to determine the value for the digital up converter. """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) + r = self.u.tune(self.subdev.which(), self.subdev, target_freq) if r: return True diff --git a/gnuradio-examples/python/multi-antenna/multi_fft.py b/gnuradio-examples/python/multi-antenna/multi_fft.py index 0f1dbb10..54d8286d 100755 --- a/gnuradio-examples/python/multi-antenna/multi_fft.py +++ b/gnuradio-examples/python/multi-antenna/multi_fft.py @@ -49,9 +49,9 @@ class my_graph(stdgui2.std_top_block): sw_decim = 1 self.u = usrp.source_c(0, options.decim, fpga_filename="std_4rx_0tx.rbf") - if self.u.nddc() < nchan: + if self.u.nddcs() < nchan: sys.stderr.write('This code requires an FPGA build with %d DDCs. This FPGA has only %d.\n' % ( - nchan, self.u.nddc())) + nchan, self.u.nddcs())) raise SystemExit if not self.u.set_nchannels(nchan): @@ -62,11 +62,11 @@ class my_graph(stdgui2.std_top_block): print "USB data rate = %s" % (eng_notation.num_to_str(input_rate),) print "Scope data rate = %s" % (eng_notation.num_to_str(input_rate/sw_decim),) - self.subdev = self.u.db[0] + self.u.db[1] + self.subdev = self.u.db(0) + self.u.db(1) if (len (self.subdev) != 4 or - self.u.db[0][0].dbid() != usrp_dbid.BASIC_RX or - self.u.db[1][0].dbid() != usrp_dbid.BASIC_RX): + self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX or + self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX): sys.stderr.write('This code requires a Basic Rx board on Sides A & B\n') sys.exit(1) diff --git a/gnuradio-examples/python/multi-antenna/multi_file.py b/gnuradio-examples/python/multi-antenna/multi_file.py index f887b9cf..6f09546e 100755 --- a/gnuradio-examples/python/multi-antenna/multi_file.py +++ b/gnuradio-examples/python/multi-antenna/multi_file.py @@ -54,9 +54,9 @@ class my_graph(gr.top_block): sw_decim = 1 self.u = usrp.source_c(0, options.decim, fpga_filename="std_4rx_0tx.rbf") - if self.u.nddc() < nchan: + if self.u.nddcs() < nchan: sys.stderr.write('This code requires an FPGA build with %d DDCs. This FPGA has only %d.\n' % ( - nchan, self.u.nddc())) + nchan, self.u.nddcs())) raise SystemExit if not self.u.set_nchannels(nchan): @@ -68,11 +68,11 @@ class my_graph(gr.top_block): sink_data_rate = input_rate/sw_decim print "Scope data rate = %s" % (eng_notation.num_to_str(sink_data_rate),) - self.subdev = self.u.db[0] + self.u.db[1] + self.subdev = self.u.db(0) + self.u.db(1) if (len(self.subdev) != 4 or - self.u.db[0][0].dbid() != usrp_dbid.BASIC_RX or - self.u.db[1][0].dbid() != usrp_dbid.BASIC_RX): + self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX or + self.u.db(1, 0).dbid() != usrp_dbid.BASIC_RX): sys.stderr.write('This code requires a Basic Rx board on Sides A & B\n') sys.exit(1) diff --git a/gnuradio-examples/python/multi-antenna/multi_scope.py b/gnuradio-examples/python/multi-antenna/multi_scope.py index 8db183d6..5d6b1e92 100755 --- a/gnuradio-examples/python/multi-antenna/multi_scope.py +++ b/gnuradio-examples/python/multi-antenna/multi_scope.py @@ -49,9 +49,9 @@ class my_top_block(stdgui2.std_top_block): sw_decim = 1 self.u = usrp.source_c(0, options.decim, fpga_filename="std_4rx_0tx.rbf") - if self.u.nddc() < nchan: + if self.u.nddcs() < nchan: sys.stderr.write('This code requires an FPGA build with %d DDCs. This FPGA has only %d.\n' % ( - nchan, self.u.nddc())) + nchan, self.u.nddcs())) raise SystemExit if not self.u.set_nchannels(nchan): @@ -62,11 +62,11 @@ class my_top_block(stdgui2.std_top_block): print "USB data rate = %s" % (eng_notation.num_to_str(input_rate),) print "Scope data rate = %s" % (eng_notation.num_to_str(input_rate/sw_decim),) - self.subdev = self.u.db[0] + self.u.db[1] + self.subdev = self.u.db(0) + self.u.db(1) if (len(self.subdev) != 4 or - self.u.db[0][0].dbid() != usrp_dbid.BASIC_RX or - self.u.db[1][0].dbid() != usrp_dbid.BASIC_RX): + self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX or + self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX): sys.stderr.write('This code requires a Basic Rx board on Sides A & B\n') sys.exit(1) diff --git a/gnuradio-examples/python/multi_usrp/multi_usrp_oscope.py b/gnuradio-examples/python/multi_usrp/multi_usrp_oscope.py index 3d426b45..512b125a 100755 --- a/gnuradio-examples/python/multi_usrp/multi_usrp_oscope.py +++ b/gnuradio-examples/python/multi_usrp/multi_usrp_oscope.py @@ -42,9 +42,9 @@ def pick_subdevice(u): If there's a daughterboard on B, select B. Otherwise, select A. """ - if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db[1][0].dbid() >= 0: + if u.db(0, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py index fb41ab12..918ff084 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py @@ -98,7 +98,7 @@ class my_top_block(gr.top_block): the result of that operation and our target_frequency to determine the value for the digital up converter. """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) + r = self.u.tune(self.subdev.which(), self.subdev, target_freq) if r: return True diff --git a/gnuradio-examples/python/ofdm/tunnel.py b/gnuradio-examples/python/ofdm/tunnel.py index 74f0f04d..7e75c3ee 100755 --- a/gnuradio-examples/python/ofdm/tunnel.py +++ b/gnuradio-examples/python/ofdm/tunnel.py @@ -182,8 +182,8 @@ class usrp_graph(gr.top_block): the result of that operation and our target_frequency to determine the value for the digital up converter. """ - r_snk = self.u_snk.tune(self.subdev._which, self.subdev, target_freq) - r_src = self.u_src.tune(self.subdev._which, self.subdev, target_freq) + r_snk = self.u_snk.tune(self.subdev.which(), self.subdev, target_freq) + r_src = self.u_src.tune(self.subdev.which(), self.subdev, target_freq) if r_snk and r_src: return True diff --git a/gnuradio-examples/python/usrp/fm_tx4.py b/gnuradio-examples/python/usrp/fm_tx4.py index a71eeaa5..a51668dd 100755 --- a/gnuradio-examples/python/usrp/fm_tx4.py +++ b/gnuradio-examples/python/usrp/fm_tx4.py @@ -43,7 +43,7 @@ import math import sys from gnuradio.wxgui import stdgui2, fftsink2 -from gnuradio import tx_debug_gui +#from gnuradio import tx_debug_gui import wx @@ -84,8 +84,8 @@ class fm_tx_block(stdgui2.std_top_block): help="set Tx frequency to FREQ [required]", metavar="FREQ") parser.add_option("-n", "--nchannels", type="int", default=4, help="number of Tx channels [1,4]") - parser.add_option("","--debug", action="store_true", default=False, - help="Launch Tx debugger") + #parser.add_option("","--debug", action="store_true", default=False, + # help="Launch Tx debugger") (options, args) = parser.parse_args () if len(args) != 0: @@ -158,9 +158,9 @@ class fm_tx_block(stdgui2.std_top_block): vbox.Add (post_mod.win, 1, wx.EXPAND) - if options.debug: - self.debugger = tx_debug_gui.tx_debug_gui(self.subdev) - self.debugger.Show(True) + #if options.debug: + # self.debugger = tx_debug_gui.tx_debug_gui(self.subdev) + # self.debugger.Show(True) def set_freq(self, target_freq): @@ -177,7 +177,7 @@ class fm_tx_block(stdgui2.std_top_block): any residual_freq to the s/w freq translater. """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) + r = self.u.tune(self.subdev.which(), self.subdev, target_freq) if r: print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) diff --git a/gnuradio-examples/python/usrp/fm_tx_2_daughterboards.py b/gnuradio-examples/python/usrp/fm_tx_2_daughterboards.py index 499c7230..15fdf283 100755 --- a/gnuradio-examples/python/usrp/fm_tx_2_daughterboards.py +++ b/gnuradio-examples/python/usrp/fm_tx_2_daughterboards.py @@ -112,7 +112,7 @@ class my_top_block(gr.top_block): self.usrp_rate = self.dac_rate / self.usrp_interp # 320 kS/s # we're using both daughterboard slots, thus subdev is a 2-tuple - self.subdev = (self.u.db[0][0], self.u.db[1][0]) + self.subdev = (self.u.db(0, 0), self.u.db(1, 0)) print "Using TX d'board %s" % (self.subdev[0].side_and_name(),) print "Using TX d'board %s" % (self.subdev[1].side_and_name(),) @@ -161,7 +161,7 @@ class my_top_block(gr.top_block): """ print "Tuning side %s to %sHz" % (("A", "B")[side], num_to_str(target_freq)) - r = self.u.tune(self.subdev[side]._which, self.subdev[side], target_freq) + r = self.u.tune(self.subdev[side].which(), self.subdev[side], target_freq) if r: print " r.baseband_freq =", num_to_str(r.baseband_freq) print " r.dxc_freq =", num_to_str(r.dxc_freq) diff --git a/gnuradio-examples/python/usrp/usrp_nbfm_ptt.py b/gnuradio-examples/python/usrp/usrp_nbfm_ptt.py index 35f01521..3ce1e0c4 100755 --- a/gnuradio-examples/python/usrp/usrp_nbfm_ptt.py +++ b/gnuradio-examples/python/usrp/usrp_nbfm_ptt.py @@ -337,7 +337,7 @@ class transmit_path(gr.hier_block2): determine the value for the digital up converter. Finally, we feed any residual_freq to the s/w freq translater. """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) + r = self.u.tune(self.subdev.which(), self.subdev, target_freq) if r: # Use residual_freq in s/w freq translator return True diff --git a/gr-usrp/Makefile.am b/gr-usrp/Makefile.am index 8980c517..136ce157 100644 --- a/gr-usrp/Makefile.am +++ b/gr-usrp/Makefile.am @@ -21,5 +21,11 @@ include $(top_srcdir)/Makefile.common -EXTRA_DIST = README_MULTI_USRP.txt -SUBDIRS = src +EXTRA_DIST = \ + README_MULTI_USRP.txt \ + gnuradio-usrp.pc.in + +SUBDIRS = src apps + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gnuradio-usrp.pc diff --git a/gr-usrp/apps/Makefile.am b/gr-usrp/apps/Makefile.am new file mode 100644 index 00000000..e1ac1b85 --- /dev/null +++ b/gr-usrp/apps/Makefile.am @@ -0,0 +1,57 @@ +# +# Copyright 2008 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. +# + +include $(top_srcdir)/Makefile.common + +# For compiling within the GNU Radio build tree +AM_CPPFLAGS=$(STD_DEFINES_AND_INCLUDES) \ + -I$(top_srcdir)/gr-usrp/src \ + -I$(top_srcdir)/usrp/host/lib/legacy \ + -I$(top_srcdir)/usrp/firmware/include \ + $(WITH_INCLUDES) + +GR_USRP_LA=$(top_builddir)/gr-usrp/src/libgnuradio-usrp.la + +# For compiling outside the tree, these will get fished out by pkgconfig + +noinst_PROGRAMS = \ + usrp_rx_cfile \ + usrp_siggen + +noinst_HEADERS = \ + usrp_rx_cfile.h \ + usrp_siggen.h + +usrp_rx_cfile_SOURCES = \ + usrp_rx_cfile.cc + +usrp_rx_cfile_LDADD = \ + $(BOOST_PROGRAM_OPTIONS_LIB) \ + $(GR_USRP_LA) + +usrp_siggen_SOURCES = \ + usrp_siggen.cc + +usrp_siggen_LDADD = \ + $(BOOST_PROGRAM_OPTIONS_LIB) \ + $(GR_USRP_LA) + +MOSTLYCLEANFILES = *~ diff --git a/gr-usrp/apps/usrp_rx_cfile.cc b/gr-usrp/apps/usrp_rx_cfile.cc new file mode 100644 index 00000000..c41a8deb --- /dev/null +++ b/gr-usrp/apps/usrp_rx_cfile.cc @@ -0,0 +1,245 @@ +/* + * Copyright 2008 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. + */ + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +usrp_subdev_spec +str_to_subdev(std::string spec_str) +{ + usrp_subdev_spec spec; + if(spec_str == "A" || spec_str == "A:0" || spec_str == "0:0") { + spec.side = 0; + spec.subdev = 0; + } + else if(spec_str == "A:1" || spec_str == "0:1") { + spec.side = 0; + spec.subdev = 1; + } + else if(spec_str == "B" || spec_str == "B:0" || spec_str == "1:0") { + spec.side = 1; + spec.subdev = 0; + } + else if(spec_str == "B:1" || spec_str == "1:1") { + spec.side = 1; + spec.subdev = 1; + } + else { + throw std::range_error("Incorrect subdevice specifications.\n"); + } + + return spec; +} + + +// Shared pointer constructor +usrp_rx_cfile_sptr make_usrp_rx_cfile(int which, usrp_subdev_spec spec, + int decim, double freq, float gain, + bool width8, bool nohb, + bool output_shorts, int nsamples, + const std::string &filename) +{ + return gnuradio::get_initial_sptr(new usrp_rx_cfile(which, spec, + decim, freq, gain, + width8, nohb, + output_shorts, + nsamples, + filename)); +} + +// Hierarchical block constructor, with no inputs or outputs +usrp_rx_cfile::usrp_rx_cfile(int which, usrp_subdev_spec spec, + int decim, double freq, float gain, + bool width8, bool nohb, + bool output_shorts, int nsamples, + const std::string &filename) : + gr_top_block("usrp_rx_cfile"), + d_which(which), d_spec(spec), d_decim(decim), d_freq(freq), + d_gain(gain), d_width8(width8), d_nohb(nohb), d_nsamples(nsamples), + d_filename(filename) +{ + usrp_source_c_sptr usrp; + + if(d_nohb || (d_decim<8)) { + // Min decimation of this firmware is 4. + // contains 4 Rx paths without halfbands and 0 tx paths. + std::string fpga_filename="std_4rx_0tx.rbf"; + + // use default values and add fpga_filename + usrp = usrp_make_source_c(d_which, d_decim, + 1, -1, 0, 0, 0, + fpga_filename.c_str()); + } + else { + // standard fpga firmware "std_2rxhb_2tx.rbf" contains + // 2 Rx paths with halfband filters and 2 tx paths + //(the default) min decimation 8 + usrp = usrp_make_source_c(d_which, d_decim); + } + + if(d_width8) { + int sample_width = 8; + int sample_shift = 8; + int format = usrp->make_format(sample_width, sample_shift); + int r = usrp->set_format(format); + printf("width8: format=%d r=%d\n", format, r); + } + + + /* Get subdevice and process it */ + db_base_sptr subdev = usrp->selected_subdev(d_spec); + printf("\nSubdevice name is %s\n", subdev->side_and_name().c_str()); + printf("Subdevice freq range: (%g, %g)\n", + subdev->freq_min(), subdev->freq_max()); + + unsigned int mux = usrp->determine_rx_mux_value(d_spec); + printf("mux: %#08x\n", mux); + usrp->set_mux(mux); + + float gain_min = subdev->gain_min(); + float gain_max = subdev->gain_max(); + if(d_gain == -1) { + d_gain = (gain_min + gain_max)/2.0; + } + printf("gain: %g\n", d_gain); + subdev->set_gain(d_gain); + + + /* Set the USRP/dboard frequency */ + usrp_tune_result r; + bool ok = usrp->tune(subdev->which(), subdev, freq, &r); + + if(!ok) { + throw std::runtime_error("Could not set frequency."); + } + + /* The rest */ + d_dst = gr_make_file_sink(sizeof(gr_complex), d_filename.c_str()); + + if(d_nsamples == -1) { + connect(usrp, 0, d_dst, 0); + } + else { + d_head = gr_make_head(sizeof(gr_complex), d_nsamples*2); + connect(usrp, 0, d_head, 0); + connect(d_head, 0, d_dst, 0); + } +} + + +int main(int argc, char *argv[]) +{ + int which = 0; // specify which USRP board + usrp_subdev_spec spec(0,0); // specify the d'board side + int decim = 16; // set the decimation rate + double freq = 0; // set the frequency + float gain = -1; // set the gain; -1 will set the mid-point gain + int nsamples = -1; // set the number of samples to collect; -1 will continue + bool width8 = false; // use 8-bit samples across USB + bool nohb = false; // don't use halfband filter in USRP + bool output_shorts = false; // use shorts + std::string filename = "received.dat"; + + po::options_description cmdconfig("Program options: usrp_text_rx [options] filename"); + cmdconfig.add_options() + ("help,h", "produce help message") + ("which,W", po::value(&which), "select which USRP board") + ("rx-subdev-spec,R", po::value(), "select USRP Rx side A or B (default=A)") + ("decim,d", po::value(&decim), "set fgpa decimation rate to DECIM") + ("freq,f", po::value(), "set frequency to FREQ") + ("gain,g", po::value(), "set gain in dB (default is midpoint)") + ("width-8,8", "Enable 8-bit samples across USB") + ("no-hb", "don't use halfband filter in usrp") + //("output-shorts,s", "output interleaved shorts in stead of complex floats") + ("nsamples,N", po::value(&nsamples), "number of samples to collect") + ; + + po::options_description fileconfig("Input file options"); + fileconfig.add_options() + ("filename", po::value(), "input file") + ; + + po::positional_options_description inputfile; + inputfile.add("filename", -1); + + po::options_description config; + config.add(cmdconfig).add(fileconfig); + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv). + options(config).positional(inputfile).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << cmdconfig << "\n"; + return 1; + } + + if(vm.count("filename")) { + filename = vm["filename"].as(); + } + + if(vm.count("freq")) { + freq = vm["freq"].as(); + } + else { + fprintf(stderr, "You must specify a frequency.\n"); + return -1; + } + + if(vm.count("rx-subdev-spec")) { + std::string s = vm["rx-subdev-spec"].as(); + spec = str_to_subdev(s); + } + + if(vm.count("width-8")) { + width8 = true; + } + if(vm.count("nohb")) { + nohb = true; + } + if(vm.count("output-shorts")) { + output_shorts = true; + } + + std::cout << "which: " << which << std::endl; + std::cout << "decim: " << decim << std::endl; + std::cout << "freq: " << freq << std::endl; + std::cout << "gain: " << gain << std::endl; + std::cout << "width-8 " << (width8 ? "Yes" : "No") << std::endl; + std::cout << "no-hb " << (nohb ? "Yes" : "no") << std::endl; + std::cout << "shorts: " << (output_shorts ? "Yes" : "No") << std::endl; + std::cout << "samples: " << nsamples << std::endl; + + usrp_rx_cfile_sptr top_block = make_usrp_rx_cfile(which, spec, decim, freq, + gain, width8, nohb, + output_shorts, nsamples, + filename); + top_block->run(); + + return 0; +} diff --git a/gr-usrp/apps/usrp_rx_cfile.h b/gr-usrp/apps/usrp_rx_cfile.h new file mode 100644 index 00000000..3a42972c --- /dev/null +++ b/gr-usrp/apps/usrp_rx_cfile.h @@ -0,0 +1,62 @@ +/* + * Copyright 2008 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. + */ + +#include +#include +#include +#include +#include + +class usrp_rx_cfile; +typedef boost::shared_ptr usrp_rx_cfile_sptr; +usrp_rx_cfile_sptr make_usrp_rx_cfile(int which, usrp_subdev_spec spec, + int decim, double freq, float gain, + bool width8, bool nohb, + bool output_shorts, int nsamples, + const std::string &filename); + +class usrp_rx_cfile : public gr_top_block +{ +private: + usrp_rx_cfile(int which, usrp_subdev_spec spec, + int decim, double freq, float gain, + bool width8, bool nohb, + bool output_shorts, int nsamples, + const std::string &filename); + friend usrp_rx_cfile_sptr make_usrp_rx_cfile(int which, usrp_subdev_spec spec, + int decim, double freq, float gain, + bool width8, bool nohb, + bool output_shorts, int nsamples, + const std::string &filename); + + int d_which; + usrp_subdev_spec d_spec; + int d_decim; + double d_freq; + float d_gain; + bool d_width8, d_nohb; + int d_nsamples; + std::string d_filename; + + public: + gr_block_sptr d_head; + gr_block_sptr d_dst; +}; diff --git a/gr-usrp/apps/usrp_siggen.cc b/gr-usrp/apps/usrp_siggen.cc new file mode 100644 index 00000000..b88e811f --- /dev/null +++ b/gr-usrp/apps/usrp_siggen.cc @@ -0,0 +1,214 @@ +/* + * Copyright 2008 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +usrp_subdev_spec +str_to_subdev(std::string spec_str) +{ + usrp_subdev_spec spec; + if(spec_str == "A" || spec_str == "A:0" || spec_str == "0:0") { + spec.side = 0; + spec.subdev = 0; + } + else if(spec_str == "A:1" || spec_str == "0:1") { + spec.side = 0; + spec.subdev = 1; + } + else if(spec_str == "B" || spec_str == "B:0" || spec_str == "1:0") { + spec.side = 1; + spec.subdev = 0; + } + else if(spec_str == "B:1" || spec_str == "1:1") { + spec.side = 1; + spec.subdev = 1; + } + else { + throw std::range_error("Incorrect subdevice specifications.\n"); + } + + return spec; +} + +// Shared pointer constructor +usrp_siggen_sptr make_usrp_siggen(int which, usrp_subdev_spec spec, + double rf_freq, int interp, double wfreq, + int waveform, float amp, float gain, + float offset) +{ + return gnuradio::get_initial_sptr(new usrp_siggen(which, spec, + rf_freq, interp, wfreq, + waveform, amp, gain, + offset)); +} + +// Hierarchical block constructor, with no inputs or outputs +usrp_siggen::usrp_siggen(int which, usrp_subdev_spec spec, + double rf_freq, int interp, double wfreq, + int waveform, float amp, float gain, + float offset) : + gr_top_block("usrp_siggen") +{ + usrp_sink_c_sptr usrp = usrp_make_sink_c(which, interp); + + db_base_sptr subdev = usrp->selected_subdev(spec); + printf("Subdevice name is %s\n", subdev->name().c_str()); + printf("Subdevice freq range: (%g, %g)\n", + subdev->freq_min(), subdev->freq_max()); + + unsigned int mux = usrp->determine_tx_mux_value(spec); + printf("mux: %#08x\n", mux); + usrp->set_mux(mux); + + if(gain == -1) { + gain = subdev->gain_max(); + } + subdev->set_gain(gain); + + float input_rate = usrp->dac_freq() / usrp->interp_rate(); + printf("baseband rate: %g\n", input_rate); + + usrp_tune_result r; + double target_freq = rf_freq; + bool ok = usrp->tune(subdev->which(), subdev, target_freq, &r); + + if(!ok) { + throw std::runtime_error("Could not set frequency."); + } + + subdev->set_enable(true); + + printf("target_freq: %f\n", target_freq); + printf("ok: %s\n", ok ? "true" : "false"); + printf("r.baseband_freq: %f\n", r.baseband_freq); + printf("r.dxc_freq: %f\n", r.dxc_freq); + printf("r.residual_freq: %f\n", r.residual_freq); + printf("r.inverted: %d\n", r.inverted); + + /* Set up the signal source */ + siggen = gr_make_sig_source_c(input_rate, GR_SIN_WAVE, wfreq, amp); + noisegen = gr_make_noise_source_c (GR_UNIFORM, amp); + if(waveform == GR_SIN_WAVE || waveform == GR_CONST_WAVE) { + source = siggen; + } + else if(waveform == GR_UNIFORM || waveform == GR_GAUSSIAN) { + source = noisegen; + } + else { + throw std::range_error("Unknown waveform type.\n"); + } + + siggen->set_waveform((gr_waveform_t)waveform); + + connect(source, 0, usrp, 0); +} + +int main(int argc, char *argv[]) +{ + int which = 0; // specify which USRP board + usrp_subdev_spec spec(0,0); // specify the d'board side + int interp = 128; // set the interpolation rate + double rf_freq = 0; // set the frequency + double wfreq = 100e3; // set the waveform frequency + float amp = 5; // set the amplitude of the output + float gain = -1; // set the d'board PGA gain + float offset = 0; // set waveform offset + int waveform; + + po::options_description cmdconfig("Program options"); + cmdconfig.add_options() + ("help,h", "produce help message") + ("which,W", po::value(&which), "select which USRP board") + ("tx-subdev-spec,T", po::value(), "select USRP Tx side A or B") + ("rf-freq,f", po::value(), "set RF center frequency to FREQ") + ("interp,i", po::value(&interp), "set fgpa interpolation rate to INTERP") + + ("sine", "generate a complex sinusoid [default]") + ("const", "generate a constant output") + ("gaussian", "generate Gaussian random output") + ("uniform", "generate Uniform random output") + + ("waveform-freq,w", po::value(&wfreq), "set waveform frequency to FREQ") + ("amplitdue,a", po::value(&), "set amplitude") + ("gain,g", po::value(&gain), "set output gain to GAIN") + ("offset,o", po::value(&offset), "set waveform offset to OFFSET") + ; + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv). + options(cmdconfig).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << cmdconfig << "\n"; + return 1; + } + + if(vm.count("rf-freq")) { + rf_freq = vm["rf-freq"].as(); + } + else { + fprintf(stderr, "You must specify a frequency.\n"); + return -1; + } + + if(vm.count("tx-subdev-spec")) { + std::string s = vm["tx-subdev-spec"].as(); + spec = str_to_subdev(s); + } + + if(vm.count("sine")) { + waveform = GR_SIN_WAVE; + } + else if(vm.count("const")) { + waveform = GR_CONST_WAVE; + } + else if(vm.count("gaussian")) { + waveform = GR_GAUSSIAN; + } + else if(vm.count("uniform")) { + waveform = GR_UNIFORM; + } + else { + waveform = GR_SIN_WAVE; + } + + printf("which: %d\n", which); + printf("interp: %d\n", interp); + printf("rf_freq: %g\n", rf_freq); + printf("amp: %f\n", amp); + + usrp_siggen_sptr top_block = make_usrp_siggen(which, spec, rf_freq, + interp, wfreq, waveform, + amp, gain, offset); + + top_block->run(); + + return 0; +} diff --git a/gr-usrp/apps/usrp_siggen.h b/gr-usrp/apps/usrp_siggen.h new file mode 100644 index 00000000..009a2447 --- /dev/null +++ b/gr-usrp/apps/usrp_siggen.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008 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. + */ + +#include +#include +#include +#include + +usrp_subdev_spec str_to_subdev(std::string spec_str); + +class usrp_siggen; +typedef boost::shared_ptr usrp_siggen_sptr; +usrp_siggen_sptr make_usrp_siggen(int which, usrp_subdev_spec spec, + double rf_freq, int interp, double wfreq, + int waveform, float amp, float gain, + float offset); + +class usrp_siggen : public gr_top_block +{ +private: + usrp_siggen(int which, usrp_subdev_spec spec, + double rf_freq, int interp, double wfreq, + int waveform, float amp, float gain, + float offset); + friend usrp_siggen_sptr make_usrp_siggen(int which, usrp_subdev_spec spec, + double rf_freq, int interp, double wfreq, + int waveform, float amp, float gain, + float offset); + + public: + gr_block_sptr source; + gr_sig_source_c_sptr siggen; + gr_noise_source_c_sptr noisegen; +}; diff --git a/gr-usrp/gnuradio-usrp.pc.in b/gr-usrp/gnuradio-usrp.pc.in new file mode 100644 index 00000000..6c1d75d4 --- /dev/null +++ b/gr-usrp/gnuradio-usrp.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gnuradio + +Name: gnuradio-usrp +Description: GNU Software Radio support for Universal Software Radio Peripheral +Requires: gnuradio-core usrp +Version: @VERSION@ +Libs: -L${libdir} -lgnuradio-usrp +Cflags: -I${includedir} diff --git a/gr-usrp/src/Makefile.am b/gr-usrp/src/Makefile.am index 03ca34db..122f977b 100644 --- a/gr-usrp/src/Makefile.am +++ b/gr-usrp/src/Makefile.am @@ -21,107 +21,116 @@ include $(top_srcdir)/Makefile.common +# ---------------------------------------------------------------- +# The straight C++ library + +AM_CPPFLAGS = \ + $(STD_DEFINES_AND_INCLUDES) \ + $(PYTHON_CPPFLAGS) \ + $(USRP_INCLUDES) \ + $(WITH_INCLUDES) + +lib_LTLIBRARIES = \ + libgnuradio-usrp.la + +libgnuradio_usrp_la_SOURCES = \ + usrp_base.cc \ + usrp_sink_base.cc \ + usrp_sink_c.cc \ + usrp_sink_s.cc \ + usrp_source_base.cc \ + usrp_source_c.cc \ + usrp_source_s.cc + +libgnuradio_usrp_la_LIBADD = \ + $(GNURADIO_CORE_LA) \ + $(USRP_LA) + +libgnuradio_usrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 + +grinclude_HEADERS = \ + usrp_base.h \ + usrp_sink_base.h \ + usrp_sink_c.h \ + usrp_sink_s.h \ + usrp_source_base.h \ + usrp_source_c.h \ + usrp_source_s.h + +# ---------------------------------------------------------------- +# The SWIG library and Python modules +# # Install this stuff so that it ends up as the gnuradio.usrp module # This usually ends up at: -# ${prefix}/lib/python${python_version}/site-packages/gnuradio - -ourpythondir = $(grpythondir) -ourlibdir = $(grpyexecdir) - -EXTRA_DIST = run_tests.in -TESTS = run_tests - -LOCAL_IFILES = \ - $(top_srcdir)/gr-usrp/src/usrp1.i - -NON_LOCAL_IFILES = $(GNURADIO_I) - -ALL_IFILES = \ - $(LOCAL_IFILES) \ +# ${prefix}/lib/python${python_version}/site-packages/gnuradio/usrp + +ourpythondir = $(grpythondir)/usrp +ourlibdir = $(grpyexecdir)/usrp + +BUILT_SOURCES = \ + usrp_swig.cc \ + usrp_swig.py + +LOCAL_IFILES = \ + $(srcdir)/usrp.i \ + $(srcdir)/usrp_base.i \ + $(srcdir)/usrp_source_base.i \ + $(srcdir)/usrp_source_c.i \ + $(srcdir)/usrp_source_s.i \ + $(srcdir)/usrp_sink_base.i \ + $(srcdir)/usrp_sink_c.i \ + $(srcdir)/usrp_sink_s.i \ + $(srcdir)/usrp_standard.i + +NON_LOCAL_IFILES = \ + $(GNURADIO_I) + +ALL_IFILES = \ + $(LOCAL_IFILES) \ $(NON_LOCAL_IFILES) -BUILT_SOURCES = \ - usrp1.cc \ - usrp1.py - -ourpython_PYTHON = \ - db_base.py \ - db_basic.py \ - db_dbs_rx.py \ - db_flexrf.py \ - db_flexrf_mimo.py \ - db_wbx.py \ - db_xcvr2450.py \ - db_instantiator.py \ - db_tv_rx.py \ - db_dtt754.py \ - db_dtt768.py \ - flexrf_debug_gui.py \ - tx_debug_gui.py \ - usrp.py \ - usrp1.py \ - usrp_multi.py - - -AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) \ - $(PYTHON_CPPFLAGS) \ - $(USRP_INCLUDES) \ - $(WITH_INCLUDES) - -SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) \ - $(STD_DEFINES_AND_INCLUDES) \ - $(USRP_INCLUDES) \ - $(WITH_INCLUDES) \ - $(WITH_SWIG_INCLUDES) - -grinclude_HEADERS = \ - usrp1_sink_base.h \ - usrp1_sink_c.h \ - usrp1_sink_s.h \ - usrp1_source_base.h \ - usrp1_source_c.h \ - usrp1_source_s.h - -swiginclude_HEADERS = \ - $(LOCAL_IFILES) - +ourlib_LTLIBRARIES = \ + _usrp_swig.la -ourlib_LTLIBRARIES = _usrp1.la +ourlib_PYTHON = \ + __init__.py \ + usrp_swig.py +_usrp_swig_la_SOURCES = \ + usrp_swig.cc -_usrp1_la_SOURCES = \ - usrp1.cc \ - usrp1_sink_base.cc \ - usrp1_sink_c.cc \ - usrp1_sink_s.cc \ - usrp1_source_base.cc \ - usrp1_source_c.cc \ - usrp1_source_s.cc +_usrp_swig_la_LIBADD = \ + $(PYTHON_LDFLAGS) \ + libgnuradio-usrp.la +_usrp_swig_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version -_usrp1_la_LIBADD = \ - $(PYTHON_LDFLAGS) \ - $(GNURADIO_CORE_LA) \ - $(USRP_LA) \ - -lstdc++ +_usrp_swig_la_CXXFLAGS = @swig_CXXFLAGS@ +SWIGPYTHONARGS = \ + $(SWIGPYTHONFLAGS) \ + $(STD_DEFINES_AND_INCLUDES) \ + $(USRP_INCLUDES) \ + $(WITH_INCLUDES) \ + $(WITH_SWIG_INCLUDES) -_usrp1_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version +usrp_swig.cc usrp_swig.py: $(ALL_IFILES) + $(SWIG) $(SWIGPYTHONARGS) -module usrp_swig -o usrp_swig.cc $(srcdir)/usrp.i -_usrp1_la_CXXFLAGS = @swig_CXXFLAGS@ - -usrp1.cc usrp1.py: usrp1.i $(NON_LOCAL_IFILES) $(LOCAL_IFILES) - $(SWIG) $(SWIGPYTHONARGS) -module usrp1 -o usrp1.cc $(LOCAL_IFILES) - - -noinst_PYTHON = \ +noinst_PYTHON = \ qa_usrp.py -MOSTLYCLEANFILES = \ - $(BUILT_SOURCES) *~ *.pyc - +swiginclude_HEADERS = \ + $(LOCAL_IFILES) # Don't distribute output of swig dist-hook: @for file in $(BUILT_SOURCES); do echo $(RM) $(distdir)/$$file; done @for file in $(BUILT_SOURCES); do $(RM) $(distdir)/$$file; done + +# ---------------------------------------------------------------- +# Misc. build/installation activities + +MOSTLYCLEANFILES = $(BUILT_SOURCES) *~ *.pyc +EXTRA_DIST = run_tests.in +TESTS = run_tests diff --git a/gr-usrp/src/db_instantiator.py b/gr-usrp/src/__init__.py similarity index 65% rename from gr-usrp/src/db_instantiator.py rename to gr-usrp/src/__init__.py index b76cdeee..c81b2f2b 100644 --- a/gr-usrp/src/db_instantiator.py +++ b/gr-usrp/src/__init__.py @@ -1,5 +1,5 @@ # -# Copyright 2005 Free Software Foundation, Inc. +# Copyright 2008 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -19,13 +19,10 @@ # Boston, MA 02110-1301, USA. # -_instantiator_map = {} +# The presence of this file turns this directory into a Python package -def add(dbid, instantiator): - _instantiator_map[dbid] = instantiator +# Add SWIG generated code to this namespace +from usrp_swig import * + +# Add other content from pure-Python modules here -def instantiate(usrp, which): - dbid = usrp.daughterboard_id(which) - if _instantiator_map.has_key(dbid): - return _instantiator_map[dbid](usrp, which) - raise ValueError, "No class defined to handle daughterboard (dbid = %d)" % (dbid,) diff --git a/gr-usrp/src/db_base.py b/gr-usrp/src/db_base.py deleted file mode 100644 index 947f8155..00000000 --- a/gr-usrp/src/db_base.py +++ /dev/null @@ -1,264 +0,0 @@ -# -# Copyright 2005,2006,2007 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. -# - -import weakref -from usrpm import usrp_prims -from usrpm.usrp_fpga_regs import * - -class db_base(object): - """ - Abstract base class for all daughterboards. - - This defines the required operations and interfaces for all d'boards. - """ - def __init__(self, usrp, which): - """ - Initialize daughterboard interface. - - @param usrp: instance of usrp - @param which: which daughterboard side: A = 0, B = 1 - @type which: int - """ - - if not (which in (0, 1)): - raise ValueError, "Invalid value of which: %s" % (which,) - - self._u = weakref.proxy(usrp) - - self._which = which - if hasattr(self._u, 'tx_freq'): # is this a tx or rx daughterboard? - self._tx = True - self._slot = which * 2 - else: - self._tx = False - self._slot = which * 2 + 1 - - self._refclk_reg = (FR_TX_A_REFCLK,FR_RX_A_REFCLK,FR_TX_B_REFCLK,FR_RX_B_REFCLK)[self._slot] - - def dbid(self): - return self._u.daughterboard_id(self._which) - - def name(self): - return usrp_prims.usrp_dbid_to_string(self.dbid()) - - def side_and_name(self): - return "AB"[self._which] + ': ' + self.name() - - # Function to bypass ADC buffers. Any board which is DC-coupled should bypass the buffers - def bypass_adc_buffers(self,bypass): - if self._tx: - raise RuntimeError, "TX Board has no adc buffers" - if self._which==0: - self._u.set_adc_buffer_bypass(0, bypass) - self._u.set_adc_buffer_bypass(1, bypass) - else: - self._u.set_adc_buffer_bypass(2, bypass) - self._u.set_adc_buffer_bypass(3, bypass) - - # ------------------------------------------------------------------------ - # Reference Clock section - - # Control whether a reference clock is sent to the daughterboards, - # and what frequency - # - # Bit 7 -- 1 turns on refclk, 0 allows IO use - # Bits 6:0 Divider value - # - - def _refclk_freq(self): - return self._u.fpga_master_clock_freq()/self._refclk_divisor() - - def _enable_refclk(self,enable): - CLOCK_OUT = 1 # Clock is on lowest bit - REFCLK_ENABLE = 0x80 - REFCLK_DIVISOR_MASK = 0x7f - if enable: - self._u._write_oe(self._which, CLOCK_OUT, CLOCK_OUT) # output enable - self._u._write_fpga_reg(self._refclk_reg, - ((self._refclk_divisor() & REFCLK_DIVISOR_MASK) - | REFCLK_ENABLE)) - else: - self._u._write_fpga_reg(self._refclk_reg, 0) - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - raise NotImplementedError - - # ------------------------------------------------------------------------ - # Automatic Transmit/Receive switching - # - # The presence or absence of data in the FPGA transmit fifo - # selects between two sets of values for each of the 4 banks of - # daughterboard i/o pins. - # - # Each daughterboard slot has 3 16-bit registers associated with it: - # FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_* - # - # FR_ATR_MASK_{0,1,2,3}: - # - # These registers determine which of the daugherboard i/o pins are - # affected by ATR switching. If a bit in the mask is set, the - # corresponding i/o bit is controlled by ATR, else it's output - # value comes from the normal i/o pin output register: - # FR_IO_{0,1,2,3}. - # - # FR_ATR_TXVAL_{0,1,2,3}: - # FR_ATR_RXVAL_{0,1,2,3}: - # - # If the Tx fifo contains data, then the bits from TXVAL that are - # selected by MASK are output. Otherwise, the bits from RXVAL that - # are selected by MASK are output. - - def set_atr_mask(self, v): - """ - Set Auto T/R mask. - """ - return self._u._write_fpga_reg(FR_ATR_MASK_0 + 3 * self._slot, v) - - def set_atr_txval(self, v): - """ - Set Auto T/R register value to be used when transmitting. - """ - return self._u._write_fpga_reg(FR_ATR_TXVAL_0 + 3 * self._slot, v) - - def set_atr_rxval(self, v): - """ - Set Auto T/R register value to be used when receiving. - """ - return self._u._write_fpga_reg(FR_ATR_RXVAL_0 + 3 * self._slot, v) - - def set_atr_tx_delay(self, v): - """ - Set Auto T/R delay (in clock ticks) from when Tx fifo gets data to - when T/R switches. - """ - return self._u._write_fpga_reg(FR_ATR_TX_DELAY, v) - - def set_atr_rx_delay(self, v): - """ - Set Auto T/R delay (in clock ticks) from when Tx fifo goes empty to - when T/R switches. - """ - return self._u._write_fpga_reg(FR_ATR_RX_DELAY, v) - - # derived classes should override the following methods - - def freq_range(self): - """ - Return range of frequencies in Hz that can be tuned by this d'board. - - @returns (min_freq, max_freq, step_size) - @rtype tuple - """ - raise NotImplementedError - - def set_freq(self, target_freq): - """ - Set the frequency. - - @param freq: target RF frequency in Hz - @type freq: float - - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - raise NotImplementedError - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - raise NotImplementedError - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - raise NotImplementedError - - def is_quadrature(self): - """ - Return True if this daughterboard does quadrature up or down conversion. - That is, return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - raise NotImplementedError - - def i_and_q_swapped(self): - """ - Return True if this is a quadrature device and (for RX) ADC 0 is Q - or (for TX) DAC 0 is Q - """ - return False - - def spectrum_inverted(self): - """ - Return True if the dboard gives an inverted spectrum - """ - return False - - def set_enable(self, on): - """ - For tx daughterboards, this controls the transmitter enable. - """ - pass - - def set_auto_tr(self,on): - """ - Enable automatic Transmit/Receive switching (ATR). - - Should be overridden in subclasses that care. This will typically - set the atr_mask, txval and rxval. - """ - pass - - def set_lo_offset(self, offset): - """ - Set how much LO is offset from requested frequency - - Should be overriden by daughterboards that care. - """ - pass - - def lo_offset(self, offset): - """ - Get how much LO is offset from requested frequency - - Should be overriden by daughterboards that care. - """ - return 0.0 - - def select_rx_antenna(self, which_antenna): - """ - Specify which antenna port to use for reception. - Should be overriden by daughterboards that care. - """ - pass diff --git a/gr-usrp/src/db_basic.py b/gr-usrp/src/db_basic.py deleted file mode 100644 index c9947aa0..00000000 --- a/gr-usrp/src/db_basic.py +++ /dev/null @@ -1,252 +0,0 @@ -# -# Copyright 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 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. -# - -import sys -from usrpm import usrp_dbid -import db_base -import db_instantiator - -class db_basic_tx(db_base.db_base): - def __init__(self, usrp, which): - """ - Handler for Basic Tx daughterboards. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively - """ - # sets _u and _which - db_base.db_base.__init__(self, usrp, which) - - if 0: # Doing this would give us a different default than the historical values... - g = self.gain_range() # initialize gain - self.set_gain(float(g[0]+g[1]) / 2) - - - def freq_range(self): - """ - Return range of frequencies in Hz that can be tuned by this d'board. - - @returns (min_freq, max_freq, step_size) - @rtype tuple - - We say we can do pretty much anything... - """ - return (-90e9, 90e9, 1e-6) - - def set_freq(self, target_freq): - """ - Set the frequency. - - @param freq: target RF frequency in Hz - @type freq: float - - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - return (True, 0) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max(), self._u.pga_db_per_step()) - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - ok = self._u.set_pga(self._which * 2 + 0, gain) - ok = ok and self._u.set_pga(self._which * 2 + 1, gain) - return ok - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - """ - return True - - -class db_basic_rx(db_base.db_base): - def __init__(self, usrp, which, subdev): - """ - Handler for Basic Rx daughterboards. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - @param subdev: which analog i/o channel: 0 or 1 - @type subdev: int - """ - # sets _u and _which - db_base.db_base.__init__(self, usrp, which) - self._subdev = subdev - - self.bypass_adc_buffers(True) - - if 0: # Doing this would give us a different default than the historical values... - g = self.gain_range() # initialize gain - self.set_gain(float(g[0]+g[1]) / 2) - - - def freq_range(self): - """ - Return range of frequencies in Hz that can be tuned by this d'board. - - @returns (min_freq, max_freq, step_size) - @rtype tuple - - We say we can do pretty much anything... - """ - return (0, 90e9, 1e-6) - - def set_freq(self, target_freq): - """ - Set the frequency. - - @param freq: target RF frequency in Hz - @type freq: float - - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - return (True, 0) - - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max(), self._u.pga_db_per_step()) - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - return self._u.set_pga(self._which * 2 + self._subdev, gain) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return False - -class db_lf_rx(db_basic_rx): - def __init__(self, usrp, which, subdev): - """ - Handler for Low Freq Rx daughterboards. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - @param subdev: which analog i/o channel: 0 or 1 - @type subdev: int - """ - # sets _u and _which - db_basic_rx.__init__(self, usrp, which, subdev) - - def freq_range(self): - """ - Return range of frequencies in Hz that can be tuned by this d'board. - - @returns (min_freq, max_freq, step_size) - @rtype tuple - - We cover the first nyquist zone only - """ - return (0, 32e6, 1e-6) - -class db_lf_tx(db_basic_tx): - def __init__(self, usrp, which): - """ - Handler for Low Freq Tx daughterboards. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - """ - # sets _u and _which - db_basic_tx.__init__(self, usrp, which) - - def freq_range(self): - """ - Return range of frequencies in Hz that can be tuned by this d'board. - - @returns (min_freq, max_freq, step_size) - @rtype tuple - - We cover the first nyquist zone only - """ - return (-32e6, 32e6, 1e-6) - - -# hook these daughterboard classes into the auto-instantiation framework - -def _basic_rx_instantiator(usrp, which): - # two single channel subdevices - return (db_basic_rx(usrp, which, 0), db_basic_rx(usrp, which, 1)) - -def _lf_rx_instantiator(usrp, which): - # two single channel subdevices - return (db_lf_rx(usrp, which, 0), db_lf_rx(usrp, which, 1)) - -def _basic_tx_instantiator(usrp, which): - # one quadrature subdevice - return (db_basic_tx(usrp, which),) - -def _lf_tx_instantiator(usrp, which): - # one quadrature subdevice - return (db_lf_tx(usrp, which),) - -def _no_db_instantiator(usrp, which): - if hasattr(usrp, 'tx_freq'): # is this a tx or rx daughterboard? - return (_basic_tx_instantiator(usrp, which)) - else: - return (_basic_rx_instantiator(usrp, which)) - -def _invalid_instantiator(usrp, which): - if hasattr(usrp, 'tx_freq'): # is this a tx or rx daughterboard? - sys.stderr.write('\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a "Basic Tx."\n') - sys.stderr.write('Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n') - return _basic_tx_instantiator(usrp, which) - else: - sys.stderr.write('\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a "Basic Rx."\n') - sys.stderr.write('Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n') - return _basic_rx_instantiator(usrp, which) - -db_instantiator.add(-1, _no_db_instantiator) # no daughterboard -db_instantiator.add(-2, _invalid_instantiator) # invalid eeprom contents -db_instantiator.add(usrp_dbid.BASIC_TX, _basic_tx_instantiator) -db_instantiator.add(usrp_dbid.BASIC_RX, _basic_rx_instantiator) -db_instantiator.add(usrp_dbid.LF_TX, _lf_tx_instantiator) -db_instantiator.add(usrp_dbid.LF_RX, _lf_rx_instantiator) diff --git a/gr-usrp/src/db_dbs_rx.py b/gr-usrp/src/db_dbs_rx.py deleted file mode 100644 index 699753aa..00000000 --- a/gr-usrp/src/db_dbs_rx.py +++ /dev/null @@ -1,345 +0,0 @@ -# -# Copyright 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 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. -# - -import math -from usrpm import usrp_dbid -import db_base -import db_instantiator - -def int_seq_to_str (seq): - """convert a sequence of integers into a string""" - return ''.join (map (chr, seq)) - -def str_to_int_seq (str): - """convert a string to a list of integers""" - return map (ord, str) - -class db_dbs_rx (db_base.db_base): - def __init__ (self, usrp, which): - """ - Control DBS receiver based USRP daughterboard. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - @type which: int - """ - # sets _u and _which - db_base.db_base.__init__(self, usrp, which) - - self._u._write_oe(self._which,0x0001,0x0001) - self.i2c_addr = (0x67, 0x65)[self._which] - # set basic parameters - # set default values - self.n = 950 - self.div2 = 0 - self.osc = 5 - self.cp = 3 - self.r = 4 - self.r_int = 1 - self.fdac = 127 - self.m = 2 - self.dl = 0 - self.ade = 0 - self.adl = 0 - self.gc2 = 31 - self.diag = 0 - - # FIXME this should be in the core dboard class - self.refclk_divisor = 16 - self._enable_refclk(True) - - g = self.gain_range() - self.set_gain(float(g[0]+g[1]) / 2) - self.bypass_adc_buffers(True) - - def __del__(self): - if self._u: - self._enable_refclk(False) - - def _write_reg (self, regno, v): - """regno is in [0,5], v is value to write to register""" - assert (0 <= regno and regno <= 5) - self._u.write_i2c (self.i2c_addr, int_seq_to_str ((regno, v))) - - def _write_regs (self, starting_regno, vals): - """starting_regno is in [0,5], - vals is a seq of integers to write to consecutive registers""" - self._u.write_i2c (self.i2c_addr, - int_seq_to_str ((starting_regno,) + tuple (vals))) - - def _read_status (self): - """If successful, return list of two ints: [status_info, filter_DAC]""" - s = self._u.read_i2c (self.i2c_addr, 2) - if len (s) != 2: - return None - return str_to_int_seq (s) - - def _send_reg(self,regno): - assert (0 <= regno and regno <= 5) - if regno == 0: - self._write_reg(0,(self.div2<<7) + (self.n>>8)) - if regno == 1: - self._write_reg(1,self.n & 255) - if regno == 2: - self._write_reg(2,self.osc + (self.cp<<3) + (self.r_int<<5)) - if regno == 3: - self._write_reg(3,self.fdac) - if regno == 4: - self._write_reg(4,self.m + (self.dl<<5) + (self.ade<<6) + (self.adl<<7)) - if regno == 5: - self._write_reg(5,self.gc2 + (self.diag<<5)) - - # BW setting - def _set_m(self,m): - assert m>0 and m<32 - self.m = m - self._send_reg(4) - - def _set_fdac(self,fdac): - assert fdac>=0 and fdac<128 - self.fdac = fdac - self._send_reg(3) - - def set_bw (self, bw): - #assert (bw>=4e6 and bw<=33e6) - assert (bw>=1e6 and bw<=33e6) - if bw >= 4e6: - m_max = int(min(31,math.floor(self._refclk_freq()/1e6))) - elif bw >= 2e6: # Outside of Specs! - m_max = int(min(31,math.floor(self._refclk_freq()/.5e6))) - else: # Way outside of Specs! - m_max = int(min(31,math.floor(self._refclk_freq()/.25e6))) - - m_min = int(math.ceil(self._refclk_freq()/2.5e6)) - m_test = m_max - while m_test >= m_min: - fdac_test = int(round(((bw * m_test / self._refclk_freq())-4)/.145)) - if fdac_test>127: - m_test = m_test - 1 - else: - break - if (m_test>=m_min and fdac_test >=0): - self._set_m(m_test) - self._set_fdac(fdac_test) - return (self.m,self.fdac,self._refclk_freq()/self.m*(4+0.145*self.fdac)) - else: - print "Failed to set bw" - - # Gain setting - def _set_dl(self,dl): - assert dl == 0 or dl == 1 - self.dl = dl - self._send_reg(4) - - def _set_gc2(self,gc2): - assert gc2<32 and gc2>=0 - self.gc2 = gc2 - self._send_reg(5) - - def _set_gc1(self,gc1): - assert gc1>=0 and gc1<4096 - self.gc1 = gc1 - self._u.write_aux_dac(self._which,0,int(gc1)) - - def _set_pga(self, pga_gain): - assert pga_gain >=0 and pga_gain <=20 - if(self._which == 0): - self._u.set_pga (0, pga_gain) - self._u.set_pga (1, pga_gain) - else: - self._u.set_pga (2, pga_gain) - self._u.set_pga (3, pga_gain) - - def gain_range(self): - return (0, 104, 1) - - def set_gain(self,gain): - if not (gain>=0 and gain<105): - raise ValueError, "gain out of range" - gc1 = 0 - gc2 = 0 - dl = 0 - pga = 0 - if gain <56: - gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3) - gain = 0 - else: - gc1 = 0 - gain = gain - 56 - if gain < 24: - gc2 = int(round(31.0 * (1-gain/24.0))) - gain = 0 - else: - gc2 = 0 - gain = gain - 24 - if gain >= 4.58: - dl = 1 - gain = gain - 4.58 - pga = gain - self._set_gc1(gc1) - self._set_gc2(gc2) - self._set_dl(dl) - self._set_pga(pga) - - # Frequency setting - def _set_osc(self,osc): - assert osc>=0 and osc<8 - self.osc = osc - self._send_reg(2) - - def _set_cp(self,cp): - assert cp>=0 and cp<4 - self.cp = cp - self._send_reg(2) - - def _set_n(self,n): - assert n>256 and n<32768 - self.n = n - self._send_reg(0) - self._send_reg(1) - - def _set_div2(self,div2): - assert div2 == 0 or div2 == 1 - self.div2 = div2 - self._send_reg(0) - - def _set_r(self,r): - assert r>=0 and r<128 - self.r = r - self.r_int = int(round(math.log10(r)/math.log10(2)) - 1) - self._send_reg(2) - - # FIXME How do we handle ADE and ADL properly? - def _set_ade(self,ade): - assert ade == 0 or ade == 1 - self.ade = ade - self._send_reg(4) - - def freq_range(self): - return (500e6, 2.6e9, 1e6) - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - - def set_freq(self, freq): - """ - Set the frequency. - - @param freq: target frequency in Hz - @type freq: float - - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - if not (freq>=500e6 and freq<=2.6e9): - return (False, 0) - - if(freq<1150e6): - self._set_div2(0) - vcofreq = 4 * freq - else: - self._set_div2(1) - vcofreq = 2 * freq - self._set_ade(1) - rmin=max(2,self._refclk_freq()/2e6) - rmax=min(128,self._refclk_freq()/500e3) - r = 2 - n=0 - best_r = 2 - best_n =0 - best_delta = 10e6 - while r <= rmax: - n = round(freq/(self._refclk_freq()/r)) - if r> 2 - if(adc_val == 0): - if vco <= 0: - return (False, 0) - else: - vco = vco - 1 - elif(adc_val == 7): - if(vco >= 7): - return (False, 0) - else: - vco = vco + 1 - self._set_osc(vco) - if adc_val == 1 or adc_val == 2: - self._set_cp(1) - elif adc_val == 3 or adc_val == 4: - self._set_cp(2) - else: - self._set_cp(3) - - return (True, self.n * self._refclk_freq() / self.r) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return True - -# hook this daughterboard class into the auto-instantiation framework -db_instantiator.add(usrp_dbid.DBS_RX, lambda usrp, which : (db_dbs_rx(usrp, which),)) diff --git a/gr-usrp/src/db_dtt754.py b/gr-usrp/src/db_dtt754.py deleted file mode 100644 index 019eae6a..00000000 --- a/gr-usrp/src/db_dtt754.py +++ /dev/null @@ -1,229 +0,0 @@ -# -# Copyright 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 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. -# - -__all__ = ['tv_rx'] - -import math -from usrpm import usrp_dbid -import db_base -import db_instantiator - -def int_seq_to_str(seq): - """convert a sequence of integers into a string""" - return ''.join (map (chr, seq)) - -def str_to_int_seq(str): - """convert a string to a list of integers""" - return map (ord, str) - -def control_byte_1(): - RS = 0 # 0 = 166.66kHz reference - ATP = 7 # Disable internal AGC - return 0x80 | ATP<<3 | RS - -def control_byte_2(): - STBY = 0 # powered on - XTO = 1 # turn off xtal out, which we don't have - ATC = 0 # not clear exactly, possibly speeds up or slows down AGC, which we are not using - - c = 0xc2 | ATC<<5 | STBY<<4 | XTO - return c - -def bandswitch_byte(freq,bw): - if(bw>7.5e6): - P5 = 1 - else: - P5 = 0 - - if freq < 121e6: - CP = 0 - BS = 1 - elif freq < 141e6: - CP = 1 - BS = 1 - elif freq < 166e6: - CP = 2 - BS = 1 - elif freq < 182e6: - CP = 3 - BS = 1 - elif freq < 286e6: - CP = 0 - BS = 2 - elif freq < 386e6: - CP = 1 - BS = 2 - elif freq < 446e6: - CP = 2 - BS = 2 - elif freq < 466e6: - CP = 3 - BS = 2 - elif freq < 506e6: - CP = 0 - BS = 8 - elif freq < 761e6: - CP = 1 - BS = 8 - elif freq < 846e6: - CP = 2 - BS = 8 - else: # limit is ~905 MHz - CP = 3 - BS = 8 - return CP<<6 | P5 << 4 | BS - -class db_dtt754(db_base.db_base): - def __init__(self, usrp, which): - """ - Control custom DTT75403-based daughterboard. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - @type which: int - """ - # sets _u and _which - db_base.db_base.__init__(self, usrp, which) - - self._i2c_addr = (0x60, 0x62)[which] - self.bw = 7e6 - self._IF = 36e6 - - self.f_ref = 166.6666e3 - self._inverted = False - - g = self.gain_range() # initialize gain - self.set_gain(float(g[0]+g[1]) / 2) - - self.bypass_adc_buffers(False) - - # Gain setting - def _set_rfagc(self,gain): - assert gain <= 60 and gain >= 0 - # FIXME this has a 0.5V step between gain = 60 and gain = 59. - # Why are there two cases instead of a single linear case? - if gain == 60: - voltage = 4 - else: - voltage = gain/60.0 * 2.25 + 1.25 - dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain - - assert dacword>=0 and dacword<4096 - self._u.write_aux_dac(self._which, 1, dacword) - - def _set_ifagc(self,gain): - assert gain <= 35 and gain >= 0 - voltage = gain/35.0 * 2.1 + 1.4 - dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain - - assert dacword>=0 and dacword<4096 - self._u.write_aux_dac(self._which, 0, dacword) - - def _set_pga(self,pga_gain): - assert pga_gain >=0 and pga_gain <=20 - if(self._which == 0): - self._u.set_pga (0, pga_gain) - else: - self._u.set_pga (2, pga_gain) - - def gain_range(self): - return (0, 115, 1) - - def set_gain(self,gain): - assert gain>=0 and gain<=115 - if gain>60: - rfgain = 60 - gain = gain - 60 - else: - rfgain = gain - gain = 0 - if gain > 35: - ifgain = 35 - gain = gain - 35 - else: - ifgain = gain - gain = 0 - pgagain = gain - self._set_rfagc(rfgain) - self._set_ifagc(ifgain) - self._set_pga(pgagain) - - def freq_range(self): - return (44e6, 900e6, 10e3) - - def set_freq(self, target_freq): - """ - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - r = self.freq_range() - if target_freq < r[0] or target_freq > r[1]: - return (False, 0) - - target_lo_freq = target_freq + self._IF; # High side mixing - - divisor = int(0.5+(target_lo_freq / self.f_ref)) - actual_lo_freq = self.f_ref*divisor - - if (divisor & ~0x7fff) != 0: # must be 15-bits or less - return (False, 0) - - # build i2c command string - buf = [0] * 5 - buf[0] = (divisor >> 8) & 0xff # DB1 - buf[1] = divisor & 0xff # DB2 - buf[2] = control_byte_1() - buf[3] = bandswitch_byte(actual_lo_freq,self.bw) - buf[4] = control_byte_2() - - ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf)) - - self.freq = actual_lo_freq - self._IF - - return (ok, actual_lo_freq) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return False - - def spectrum_inverted(self): - """ - The 43.75 MHz version is inverted - """ - return self._inverted - - def set_bw(self,bw): - """ - Choose the SAW filter bandwidth, either 7MHz or 8MHz) - """ - self.bw = bw - self.set_freq(self.freq) - -# hook this daughterboard class into the auto-instantiation framework - -# With DTT75403 -db_instantiator.add(usrp_dbid.DTT754, - lambda usrp, which : (db_dtt754(usrp, which),)) diff --git a/gr-usrp/src/db_dtt768.py b/gr-usrp/src/db_dtt768.py deleted file mode 100644 index dd342bd2..00000000 --- a/gr-usrp/src/db_dtt768.py +++ /dev/null @@ -1,203 +0,0 @@ -# -# Copyright 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 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. -# - -__all__ = ['tv_rx'] - -import math -from usrpm import usrp_dbid -import db_base -import db_instantiator - -def int_seq_to_str(seq): - """convert a sequence of integers into a string""" - return ''.join (map (chr, seq)) - -def str_to_int_seq(str): - """convert a string to a list of integers""" - return map (ord, str) - -def control_byte_4(): - C = 0 # Charge Pump Current, no info on how to choose - R = 4 # 125 kHz fref - - - ATP = 7 # Disable internal AGC - return 0x80 | C<<5 | R - -def control_byte_5(freq,agcmode = 1): - if(agcmode): - if freq < 150e6: - return 0x3B - elif freq < 420e6: - return 0x7E - else: - return 0xB7 - else: - if freq < 150e6: - return 0x39 - elif freq < 420e6: - return 0x7C - else: - return 0xB5 - -def control_byte_6(): - ATC = 0 # AGC time constant = 100ms, 1 = 3S - IFE = 1 # IF AGC amplifier enable - AT = 0 # AGC control, ??? - - return ATC << 5 | IFE << 4 | AT - -def control_byte_7(): - SAS = 1 # SAW Digital mode - AGD = 1 # AGC disable - ADS = 0 # AGC detector into ADC converter - T = 0 # Test mode, undocumented - return SAS << 7 | AGD << 5 | ADS << 4 | T - -class db_dtt768(db_base.db_base): - def __init__(self, usrp, which): - """ - Control custom DTT76803-based daughterboard. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - @type which: int - """ - # sets _u and _which - db_base.db_base.__init__(self, usrp, which) - - self._i2c_addr = (0x60, 0x62)[which] - self._IF = 44e6 - - self.f_ref = 125e3 - self._inverted = False - - g = self.gain_range() # initialize gain - self.set_gain(float(g[0]+g[1]) / 2) - - self.bypass_adc_buffers(False) - - # Gain setting - def _set_rfagc(self,gain): - assert gain <= 60 and gain >= 0 - # FIXME this has a 0.5V step between gain = 60 and gain = 59. - # Why are there two cases instead of a single linear case? - if gain == 60: - voltage = 4 - else: - voltage = gain/60.0 * 2.25 + 1.25 - dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain - - assert dacword>=0 and dacword<4096 - self._u.write_aux_dac(self._which, 1, dacword) - - def _set_ifagc(self,gain): - assert gain <= 35 and gain >= 0 - voltage = gain/35.0 * 2.1 + 1.4 - dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain - - assert dacword>=0 and dacword<4096 - self._u.write_aux_dac(self._which, 0, dacword) - - def _set_pga(self,pga_gain): - assert pga_gain >=0 and pga_gain <=20 - if(self._which == 0): - self._u.set_pga (0, pga_gain) - else: - self._u.set_pga (2, pga_gain) - - def gain_range(self): - return (0, 115, 1) - - def set_gain(self,gain): - assert gain>=0 and gain<=115 - if gain>60: - rfgain = 60 - gain = gain - 60 - else: - rfgain = gain - gain = 0 - if gain > 35: - ifgain = 35 - gain = gain - 35 - else: - ifgain = gain - gain = 0 - pgagain = gain - self._set_rfagc(rfgain) - self._set_ifagc(ifgain) - self._set_pga(pgagain) - - def freq_range(self): - return (44e6, 900e6, 10e3) - - def set_freq(self, target_freq): - """ - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - r = self.freq_range() - if target_freq < r[0] or target_freq > r[1]: - return (False, 0) - - target_lo_freq = target_freq + self._IF; # High side mixing - - divisor = int(0.5+(target_lo_freq / self.f_ref)) - actual_lo_freq = self.f_ref*divisor - - if (divisor & ~0x7fff) != 0: # must be 15-bits or less - return (False, 0) - - # build i2c command string - buf = [0] * 6 - buf[0] = (divisor >> 8) & 0xff # DB1 - buf[1] = divisor & 0xff # DB2 - buf[2] = control_byte_4() - buf[3] = control_byte_5(target_freq) - buf[4] = control_byte_6() - buf[5] = control_byte_7() - - ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf)) - - self.freq = actual_lo_freq - self._IF - - return (ok, actual_lo_freq) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return False - - def spectrum_inverted(self): - """ - The 43.75 MHz version is inverted - """ - return self._inverted - -# hook this daughterboard class into the auto-instantiation framework - -# With DTT76803 -db_instantiator.add(usrp_dbid.DTT768, - lambda usrp, which : (db_dtt768(usrp, which),)) diff --git a/gr-usrp/src/db_flexrf.py b/gr-usrp/src/db_flexrf.py deleted file mode 100644 index b5a0cab1..00000000 --- a/gr-usrp/src/db_flexrf.py +++ /dev/null @@ -1,701 +0,0 @@ -# -# Copyright 2005,2007 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. -# - -from gnuradio import usrp1 -import time,math - -from usrpm import usrp_dbid -import db_base -import db_instantiator -from usrpm.usrp_fpga_regs import * - -#debug_using_gui = True # Must be set to True or False -debug_using_gui = False # Must be set to True or False - -if debug_using_gui: - import flexrf_debug_gui - -# d'board i/o pin defs -# Tx and Rx have shared defs, but different i/o regs -AUX_RXAGC = (1 << 8) -POWER_UP = (1 << 7) # enables power supply -RX_TXN = (1 << 6) # Tx only: T/R antenna switch for TX/RX port -RX2_RX1N = (1 << 6) # Rx only: antenna switch between RX2 and TX/RX port -ENABLE = (1 << 5) # enables mixer -AUX_SEN = (1 << 4) -AUX_SCLK = (1 << 3) -PLL_LOCK_DETECT = (1 << 2) -AUX_SDO = (1 << 1) -CLOCK_OUT = (1 << 0) - -SPI_ENABLE_TX_A = usrp1.SPI_ENABLE_TX_A -SPI_ENABLE_TX_B = usrp1.SPI_ENABLE_TX_B -SPI_ENABLE_RX_A = usrp1.SPI_ENABLE_RX_A -SPI_ENABLE_RX_B = usrp1.SPI_ENABLE_RX_B - -class flexrf_base(db_base.db_base): - """ - Abstract base class for all flexrf boards. - - Derive board specific subclasses from db_flexrf_base_{tx,rx} - """ - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to side A or B respectively - @type which: int - """ - # sets _u _which _tx and _slot - db_base.db_base.__init__(self, usrp, which) - - self.first = True - self.spi_format = usrp1.SPI_FMT_MSB | usrp1.SPI_FMT_HDR_0 - - self._u._write_oe(self._which, 0, 0xffff) # turn off all outputs - self._enable_refclk(False) # disable refclk - - g = self.gain_range() # initialize gain - self.set_gain(float(g[0]+g[1]) / 2) - - self.set_auto_tr(False) - - if debug_using_gui: - title = "FlexRF Debug Rx" - if self._tx: - title = "FlexRF Debug Tx" - self.gui = flexrf_debug_gui.flexrf_debug_gui(self, title) - self.gui.Show(True) - - - def __del__(self): - #print "flexrf_base.__del__" - self._u.write_io(self._which, self.power_off, POWER_UP) # turn off power to board - # Power down VCO/PLL - self.PD = 3 - self._write_control(self._compute_control_reg()) - self._enable_refclk(False) # turn off refclk - self.set_auto_tr(False) - - def _write_all(self, R, control, N): - """ - Write R counter latch, control latch and N counter latch to VCO. - - Adds 10ms delay between writing control and N if this is first call. - This is the required power-up sequence. - - @param R: 24-bit R counter latch - @type R: int - @param control: 24-bit control latch - @type control: int - @param N: 24-bit N counter latch - @type N: int - """ - self._write_R(R) - self._write_control( control) - if self.first: - time.sleep(0.010) - self.first = False - self._write_N(N) - - def _write_control(self, control): - self._write_it((control & ~0x3) | 0) - - def _write_R(self, R): - self._write_it((R & ~0x3) | 1) - - def _write_N(self, N): - self._write_it((N & ~0x3) | 2) - - def _write_it(self, v): - s = ''.join((chr((v >> 16) & 0xff), - chr((v >> 8) & 0xff), - chr(v & 0xff))) - self._u._write_spi(0, self.spi_enable, self.spi_format, s) - - def _lock_detect(self): - """ - @returns: the value of the VCO/PLL lock detect bit. - @rtype: 0 or 1 - """ - if self._u.read_io(self._which) & PLL_LOCK_DETECT: - return True - else: # Give it a second chance - if self._u.read_io(self._which) & PLL_LOCK_DETECT: - return True - else: - return False - - def _compute_regs(self, freq): - """ - Determine values of R, control, and N registers, along with actual freq. - - @param freq: target frequency in Hz - @type freq: float - @returns: (R, control, N, actual_freq) - @rtype: tuple(int, int, int, float) - - Override this in derived classes. - """ - raise NotImplementedError - - def _refclk_freq(self): - # return float(self._u.fpga_master_clock_freq())/self._refclk_divisor() - return 64e6/self._refclk_divisor() - - def set_freq(self, freq): - """ - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - - # Offsetting the LO helps get the Tx carrier leakage out of the way. - # This also ensures that on Rx, we're not getting hosed by the - # FPGA's DC removal loop's time constant. We were seeing a - # problem when running with discontinuous transmission. - # Offsetting the LO made the problem go away. - freq += self._lo_offset - - R, control, N, actual_freq = self._compute_regs(freq) - if R==0: - return(False,0) - self._write_all(R, control, N) - return (self._lock_detect(), actual_freq) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max(), self._u.pga_db_per_step()) - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - return self._set_pga(gain) - - def _set_pga(self, pga_gain): - if(self._which == 0): - self._u.set_pga (0, pga_gain) - self._u.set_pga (1, pga_gain) - else: - self._u.set_pga (2, pga_gain) - self._u.set_pga (3, pga_gain) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return True - - def set_lo_offset(self, offset): - """ - Set amount by which LO is offset from requested tuning frequency. - - @param offset: offset in Hz - """ - self._lo_offset = offset - - def lo_offset(self): - """ - Get amount by which LO is offset from requested tuning frequency. - - @returns Offset in Hz - """ - return self._lo_offset - -# ---------------------------------------------------------------- - -class flexrf_base_tx(flexrf_base): - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.sink_c - @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. - """ - flexrf_base.__init__(self, usrp, which) - self.spi_enable = (SPI_ENABLE_TX_A, SPI_ENABLE_TX_B)[which] - - # power up the transmit side, but don't enable the mixer - self._u._write_oe(self._which,(POWER_UP|RX_TXN|ENABLE), 0xffff) - self._u.write_io(self._which, (self.power_on|RX_TXN), (POWER_UP|RX_TXN|ENABLE)) - self.set_lo_offset(4e6) - - def __del__(self): - #print "flexrf_base_tx.__del__" - # Power down and leave the T/R switch in the R position - self._u.write_io(self._which, (self.power_off|RX_TXN), (POWER_UP|RX_TXN|ENABLE)) - flexrf_base.__del__(self) - - def set_auto_tr(self, on): - if on: - self.set_atr_mask (RX_TXN | ENABLE) - self.set_atr_txval(0 | ENABLE) - self.set_atr_rxval(RX_TXN | 0) - else: - self.set_atr_mask (0) - self.set_atr_txval(0) - self.set_atr_rxval(0) - - def set_enable(self, on): - """ - Enable transmitter if on is True - """ - mask = RX_TXN | ENABLE - if on: - v = ENABLE - else: - v = RX_TXN - self._u.write_io(self._which, v, mask) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - - Flex Tx boards require that the PGA be maxed out to properly bias their circuitry. - """ - g = self._u.pga_max() - return (g, g, 1.0) - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - return self._set_pga(self._u.pga_max()) - -class flexrf_base_rx(flexrf_base): - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.source_c - @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. - """ - flexrf_base.__init__(self, usrp, which) - self.spi_enable = (SPI_ENABLE_RX_A, SPI_ENABLE_RX_B)[which] - - self._u._write_oe(self._which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff) - self._u.write_io(self._which, (self.power_on|RX2_RX1N|ENABLE), (POWER_UP|RX2_RX1N|ENABLE)) - - # set up for RX on TX/RX port - self.select_rx_antenna('TX/RX') - - self.bypass_adc_buffers(True) - self.set_lo_offset(-4e6) - - def __del__(self): - # print "flexrf_base_rx.__del__" - # Power down - self._u.write_io(self._which, self.power_off, (POWER_UP|ENABLE)) - flexrf_base.__del__(self) - - def set_auto_tr(self, on): - if on: - self.set_atr_mask (ENABLE) - self.set_atr_txval( 0) - self.set_atr_rxval(ENABLE) - else: - self.set_atr_mask (0) - self.set_atr_txval(0) - self.set_atr_rxval(0) - - def select_rx_antenna(self, which_antenna): - """ - Specify which antenna port to use for reception. - @param which_antenna: either 'TX/RX' or 'RX2' - """ - if which_antenna in (0, 'TX/RX'): - self._u.write_io(self._which, 0, RX2_RX1N) - elif which_antenna in (1, 'RX2'): - self._u.write_io(self._which, RX2_RX1N, RX2_RX1N) - else: - raise ValueError, "which_antenna must be either 'TX/RX' or 'RX2'" - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - maxgain = self.gain_range()[1] - self._u.pga_max() - mingain = self.gain_range()[0] - if gain > maxgain: - pga_gain = gain-maxgain - assert pga_gain <= self._u.pga_max() - agc_gain = maxgain - else: - pga_gain = 0 - agc_gain = gain - V_maxgain = .2 - V_mingain = 1.2 - V_fullscale = 3.3 - dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale - assert dac_value>=0 and dac_value<4096 - return self._u.write_aux_dac(self._which, 0, int(dac_value)) and \ - self._set_pga(int(pga_gain)) - -# ---------------------------------------------------------------- - -class _AD4360_common(object): - def __init__(self): - # R-Register Common Values - self.R_RSV = 0 # bits 23,22 - self.BSC = 3 # bits 21,20 Div by 8 to be safe - self.TEST = 0 # bit 19 - self.LDP = 1 # bit 18 - self.ABP = 0 # bit 17,16 3ns - - # N-Register Common Values - self.N_RSV = 0 # bit 7 - - # Control Register Common Values - self.PD = 0 # bits 21,20 Normal operation - self.PL = 0 # bits 13,12 11mA - self.MTLD = 1 # bit 11 enabled - self.CPG = 0 # bit 10 CP setting 1 - self.CP3S = 0 # bit 9 Normal - self.PDP = 1 # bit 8 Positive - self.MUXOUT = 1 # bits 7:5 Digital Lock Detect - self.CR = 0 # bit 4 Normal - self.PC = 1 # bits 3,2 Core power 10mA - - def _compute_regs(self, freq): - """ - Determine values of R, control, and N registers, along with actual freq. - - @param freq: target frequency in Hz - @type freq: float - @returns: (R, control, N, actual_freq) - @rtype: tuple(int, int, int, float) - """ - - # Band-specific N-Register Values - phdet_freq = self._refclk_freq()/self.R_DIV - desired_n = round(freq*self.freq_mult/phdet_freq) - actual_freq = desired_n * phdet_freq - B = math.floor(desired_n/self._prescaler()) - A = desired_n - self._prescaler()*B - self.B_DIV = int(B) # bits 20:8 - self.A_DIV = int(A) # bit 6:2 - #assert self.B_DIV >= self.A_DIV - if self.B_DIV < self.A_DIV: - return (0,0,0,0) - R = (self.R_RSV<<22) | (self.BSC<<20) | (self.TEST<<19) | (self.LDP<<18) \ - | (self.ABP<<16) | (self.R_DIV<<2) - - control = self._compute_control_reg() - - N = (self.DIVSEL<<23) | (self.DIV2<<22) | (self.CPGAIN<<21) | (self.B_DIV<<8) | \ - (self.N_RSV<<7) | (self.A_DIV<<2) - - return (R,control,N,actual_freq/self.freq_mult) - - def _compute_control_reg(self): - control = (self.P<<22) | (self.PD<<20) | (self.CP2<<17) | (self.CP1<<14) | (self.PL<<12) \ - | (self.MTLD<<11) | (self.CPG<<10) | (self.CP3S<<9) | (self.PDP<<8) | \ - (self.MUXOUT<<5) | (self.CR<<4) | (self.PC<<2) - return control - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - - def _prescaler(self): - if self.P == 0: - return 8 - elif self.P == 1: - return 16 - else: - return 32 - -#---------------------------------------------------------------------- -class _2400_common(_AD4360_common): - def __init__(self): - _AD4360_common.__init__(self) - - # Band-specific R-Register Values - self.R_DIV = 16 # bits 15:2 - - # Band-specific C-Register values - self.P = 1 # bits 23,22 Div by 16/17 - self.CP2 = 7 # bits 19:17 - self.CP1 = 7 # bits 16:14 - - # Band specifc N-Register Values - self.DIVSEL = 0 # bit 23 - self.DIV2 = 0 # bit 22 - self.CPGAIN = 0 # bit 21 - self.freq_mult = 1 - - def freq_range(self): # FIXME - return (2300e6, 2700e6, 4e6) - -#---------------------------------------------------------------------- -class _1200_common(_AD4360_common): - def __init__(self): - _AD4360_common.__init__(self) - - # Band-specific R-Register Values - self.R_DIV = 16 # bits 15:2 DIV by 16 for a 1 MHz phase detector freq - - # Band-specific C-Register values - self.P = 1 # bits 23,22 Div by 16/17 - self.CP2 = 7 # bits 19:17 1.25 mA - self.CP1 = 7 # bits 16:14 1.25 mA - - # Band specifc N-Register Values - self.DIVSEL = 0 # bit 23 - self.DIV2 = 1 # bit 22 - self.CPGAIN = 0 # bit 21 - self.freq_mult = 2 - - def freq_range(self): # FIXME - return (1150e6, 1350e6, 4e6) - -#------------------------------------------------------------------------- -class _1800_common(_AD4360_common): - def __init__(self): - _AD4360_common.__init__(self) - - # Band-specific R-Register Values - self.R_DIV = 16 # bits 15:2 DIV by 16 for a 1 MHz phase detector freq - - # Band-specific C-Register values - self.P = 1 # bits 23,22 Div by 16/17 - self.CP2 = 7 # bits 19:17 1.25 mA - self.CP1 = 7 # bits 16:14 1.25 mA - - # Band specifc N-Register Values - self.DIVSEL = 0 # bit 23 - self.DIV2 = 0 # bit 22 - self.freq_mult = 1 - self.CPGAIN = 0 # bit 21 - - def freq_range(self): # FIXME - return (1600e6, 2000e6, 4e6) - -#------------------------------------------------------------------------- -class _900_common(_AD4360_common): - def __init__(self): - _AD4360_common.__init__(self) - - # Band-specific R-Register Values - self.R_DIV = 16 # bits 15:2 DIV by 16 for a 1 MHz phase detector freq - - # Band-specific C-Register values - self.P = 1 # bits 23,22 Div by 16/17 - self.CP2 = 7 # bits 19:17 1.25 mA - self.CP1 = 7 # bits 16:14 1.25 mA - - # Band specifc N-Register Values - self.DIVSEL = 0 # bit 23 - self.DIV2 = 1 # bit 22 - self.freq_mult = 2 - self.CPGAIN = 0 # bit 21 - - def freq_range(self): # FIXME - return (800e6, 1000e6, 4e6) - -#------------------------------------------------------------------------- -class _400_common(_AD4360_common): - def __init__(self): - _AD4360_common.__init__(self) - - # Band-specific R-Register Values - self.R_DIV = 16 # bits 15:2 - - # Band-specific C-Register values - self.P = 0 # bits 23,22 Div by 8/9 - self.CP2 = 7 # bits 19:17 1.25 mA - self.CP1 = 7 # bits 16:14 1.25 mA - - # Band specifc N-Register Values These are different for TX/RX - self.DIVSEL = 0 # bit 23 - if self._tx: - self.DIV2 = 1 # bit 22 - else: - self.DIV2 = 0 # bit 22 # RX side has built-in DIV2 in AD8348 - self.freq_mult = 2 - - self.CPGAIN = 0 # bit 21 - - def freq_range(self): - #return (350e6, 465e6, 1e6) # FIXME prototype - return (400e6, 500e6, 1e6) # final version - - -#------------------------------------------------------------ -class db_flexrf_2400_tx(_2400_common, flexrf_base_tx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_tx.__init__(self, usrp, which) - _2400_common.__init__(self) - -class db_flexrf_2400_rx(_2400_common, flexrf_base_rx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # Powering it off kills the serial bus - flexrf_base_rx.__init__(self, usrp, which) - _2400_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max() + 70, 0.05) - - def i_and_q_swapped(self): - return True - -class db_flexrf_1200_tx(_1200_common, flexrf_base_tx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_tx.__init__(self, usrp, which) - _1200_common.__init__(self) - -class db_flexrf_1200_rx(_1200_common, flexrf_base_rx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_rx.__init__(self, usrp, which) - _1200_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max() + 70, 0.05) - - def i_and_q_swapped(self): - return True - -class db_flexrf_1800_tx(_1800_common, flexrf_base_tx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_tx.__init__(self, usrp, which) - _1800_common.__init__(self) - -class db_flexrf_1800_rx(_1800_common, flexrf_base_rx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_rx.__init__(self, usrp, which) - _1800_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max() + 70, 0.05) - - def i_and_q_swapped(self): - return True - -class db_flexrf_900_tx(_900_common, flexrf_base_tx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_tx.__init__(self, usrp, which) - _900_common.__init__(self) - -class db_flexrf_900_rx(_900_common, flexrf_base_rx): - def __init__(self, usrp, which): - self.power_on = 0 - self.power_off = 0 # powering it off kills the serial bus - flexrf_base_rx.__init__(self, usrp, which) - _900_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max() + 70, 0.05) - - def i_and_q_swapped(self): - return True - -class db_flexrf_400_tx(_400_common, flexrf_base_tx): - def __init__(self, usrp, which): - self.power_on = POWER_UP - self.power_off = 0 - flexrf_base_tx.__init__(self, usrp, which) - _400_common.__init__(self) - -class db_flexrf_400_rx(_400_common, flexrf_base_rx): - def __init__(self, usrp, which): - self.power_on = POWER_UP - self.power_off = 0 - flexrf_base_rx.__init__(self, usrp, which) - _400_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max() + 45, 0.035) - - def i_and_q_swapped(self): - return True - -# hook these daughterboard classes into the auto-instantiation framework - -db_instantiator.add(usrp_dbid.FLEX_2400_TX, lambda usrp, which : (db_flexrf_2400_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_2400_RX, lambda usrp, which : (db_flexrf_2400_rx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1200_TX, lambda usrp, which : (db_flexrf_1200_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1200_RX, lambda usrp, which : (db_flexrf_1200_rx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1800_TX, lambda usrp, which : (db_flexrf_1800_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1800_RX, lambda usrp, which : (db_flexrf_1800_rx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_900_TX, lambda usrp, which : (db_flexrf_900_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_900_RX, lambda usrp, which : (db_flexrf_900_rx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_400_TX, lambda usrp, which : (db_flexrf_400_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_400_RX, lambda usrp, which : (db_flexrf_400_rx(usrp, which),)) diff --git a/gr-usrp/src/db_flexrf_mimo.py b/gr-usrp/src/db_flexrf_mimo.py deleted file mode 100644 index 755979bc..00000000 --- a/gr-usrp/src/db_flexrf_mimo.py +++ /dev/null @@ -1,286 +0,0 @@ -# -# Copyright 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 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. -# - -from gnuradio import usrp1 -import time,math - -from usrpm import usrp_dbid -import db_base -import db_instantiator -from usrpm.usrp_fpga_regs import * -from db_flexrf import * - -# self._u.fpga_master_clock_freq() - -# MIMO Classes -class db_flexrf_2400_tx_mimo_a(db_flexrf_2400_tx): - def __init__(self, usrp, which): - db_flexrf_2400_tx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_2400_rx_mimo_a(db_flexrf_2400_rx): - def __init__(self, usrp, which): - db_flexrf_2400_rx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_2400_tx_mimo_b(db_flexrf_2400_tx): - def __init__(self, usrp, which): - db_flexrf_2400_tx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_2400_rx_mimo_b(db_flexrf_2400_rx): - def __init__(self, usrp, which): - db_flexrf_2400_rx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_1800_tx_mimo_a(db_flexrf_1800_tx): - def __init__(self, usrp, which): - db_flexrf_1800_tx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_1800_rx_mimo_a(db_flexrf_1800_rx): - def __init__(self, usrp, which): - db_flexrf_1800_rx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_1800_tx_mimo_b(db_flexrf_1800_tx): - def __init__(self, usrp, which): - db_flexrf_1800_tx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_1800_rx_mimo_b(db_flexrf_1800_rx): - def __init__(self, usrp, which): - db_flexrf_1800_rx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_1200_tx_mimo_a(db_flexrf_1200_tx): - def __init__(self, usrp, which): - db_flexrf_1200_tx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_1200_rx_mimo_a(db_flexrf_1200_rx): - def __init__(self, usrp, which): - db_flexrf_1200_rx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_1200_tx_mimo_b(db_flexrf_1200_tx): - def __init__(self, usrp, which): - db_flexrf_1200_tx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_1200_rx_mimo_b(db_flexrf_1200_rx): - def __init__(self, usrp, which): - db_flexrf_1200_rx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_900_tx_mimo_a(db_flexrf_900_tx): - def __init__(self, usrp, which): - db_flexrf_900_tx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_900_rx_mimo_a(db_flexrf_900_rx): - def __init__(self, usrp, which): - db_flexrf_900_rx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_900_tx_mimo_b(db_flexrf_900_tx): - def __init__(self, usrp, which): - db_flexrf_900_tx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_900_rx_mimo_b(db_flexrf_900_rx): - def __init__(self, usrp, which): - db_flexrf_900_rx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_400_tx_mimo_a(db_flexrf_400_tx): - def __init__(self, usrp, which): - db_flexrf_400_tx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_400_rx_mimo_a(db_flexrf_400_rx): - def __init__(self, usrp, which): - db_flexrf_400_rx.__init__(self, usrp, which) - self._enable_refclk(True) - self.R_DIV = 1 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 16 - -class db_flexrf_400_tx_mimo_b(db_flexrf_400_tx): - def __init__(self, usrp, which): - db_flexrf_400_tx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -class db_flexrf_400_rx_mimo_b(db_flexrf_400_rx): - def __init__(self, usrp, which): - db_flexrf_400_rx.__init__(self, usrp, which) - self.R_DIV = 16 - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - -# hook these daughterboard classes into the auto-instantiation framework -db_instantiator.add(usrp_dbid.FLEX_2400_TX_MIMO_A, lambda usrp, which : (db_flexrf_2400_tx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_2400_RX_MIMO_A, lambda usrp, which : (db_flexrf_2400_rx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1800_TX_MIMO_A, lambda usrp, which : (db_flexrf_1800_tx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1800_RX_MIMO_A, lambda usrp, which : (db_flexrf_1800_rx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1200_TX_MIMO_A, lambda usrp, which : (db_flexrf_1200_tx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1200_RX_MIMO_A, lambda usrp, which : (db_flexrf_1200_rx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_900_TX_MIMO_A, lambda usrp, which : (db_flexrf_900_tx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_900_RX_MIMO_A, lambda usrp, which : (db_flexrf_900_rx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_400_TX_MIMO_A, lambda usrp, which : (db_flexrf_400_tx_mimo_a(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_400_RX_MIMO_A, lambda usrp, which : (db_flexrf_400_rx_mimo_a(usrp, which),)) - -db_instantiator.add(usrp_dbid.FLEX_2400_TX_MIMO_B, lambda usrp, which : (db_flexrf_2400_tx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_2400_RX_MIMO_B, lambda usrp, which : (db_flexrf_2400_rx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1800_TX_MIMO_B, lambda usrp, which : (db_flexrf_1800_tx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1800_RX_MIMO_B, lambda usrp, which : (db_flexrf_1800_rx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1200_TX_MIMO_B, lambda usrp, which : (db_flexrf_1200_tx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_1200_RX_MIMO_B, lambda usrp, which : (db_flexrf_1200_rx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_900_TX_MIMO_B, lambda usrp, which : (db_flexrf_900_tx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_900_RX_MIMO_B, lambda usrp, which : (db_flexrf_900_rx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_400_TX_MIMO_B, lambda usrp, which : (db_flexrf_400_tx_mimo_b(usrp, which),)) -db_instantiator.add(usrp_dbid.FLEX_400_RX_MIMO_B, lambda usrp, which : (db_flexrf_400_rx_mimo_b(usrp, which),)) - diff --git a/gr-usrp/src/db_tv_rx.py b/gr-usrp/src/db_tv_rx.py deleted file mode 100644 index 48fe6ca0..00000000 --- a/gr-usrp/src/db_tv_rx.py +++ /dev/null @@ -1,198 +0,0 @@ -# -# Copyright 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 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. -# - -__all__ = ['tv_rx'] - -import math -from usrpm import usrp_dbid -import db_base -import db_instantiator - -def int_seq_to_str(seq): - """convert a sequence of integers into a string""" - return ''.join (map (chr, seq)) - -def str_to_int_seq(str): - """convert a string to a list of integers""" - return map (ord, str) - -def control_byte_1(fast_tuning_p, reference_divisor): - c = 0x88 - if fast_tuning_p: - c |= 0x40 - if reference_divisor == 512: - c |= 0x3 << 1 - elif reference_divisor == 640: - c |= 0x0 << 1 - elif reference_divisor == 1024: - c |= 0x1 << 1 - else: - assert 0 - return c - -def control_byte_2(target_freq, shutdown_tx_PGA): - if target_freq < 158e6: # VHF low - c = 0xa0 - elif target_freq < 464e6: # VHF high - c = 0x90 - else: # UHF - c = 0x30 - if shutdown_tx_PGA: - c |= 0x08 - return c - -class db_tv_rx(db_base.db_base): - def __init__(self, usrp, which, first_IF, second_IF, inverted): - """ - Control Microtune 4937 based USRP daughterboard. - - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - @type which: int - """ - # sets _u and _which - db_base.db_base.__init__(self, usrp, which) - - self._i2c_addr = (0x60, 0x61)[which] - - self._first_IF = first_IF - self._second_IF = second_IF - self._reference_divisor = 640 - self._fast_tuning = False - self._inverted = inverted - - g = self.gain_range() - self.set_gain(float(g[0]+g[1]) / 2) # default gain is halfscale - - self.bypass_adc_buffers(False) - - # Gain setting - def _set_rfagc(self,gain): - assert gain <= 60 and gain >= 0 - # FIXME this has a 0.5V step between gain = 60 and gain = 59. - # Why are there two cases instead of a single linear case? - if gain == 60: - voltage = 4 - else: - voltage = gain/60.0 * 2.25 + 1.25 - dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain - - assert dacword>=0 and dacword<4096 - self._u.write_aux_dac(self._which, 1, dacword) - - def _set_ifagc(self,gain): - assert gain <= 35 and gain >= 0 - voltage = gain/35.0 * 2.1 + 1.4 - dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain - - assert dacword>=0 and dacword<4096 - self._u.write_aux_dac(self._which, 0, dacword) - - def _set_pga(self,pga_gain): - assert pga_gain >=0 and pga_gain <=20 - if(self._which == 0): - self._u.set_pga (0, pga_gain) - else: - self._u.set_pga (2, pga_gain) - - def gain_range(self): - return (0, 115, 1) - - def set_gain(self,gain): - assert gain>=0 and gain<=115 - if gain>60: - rfgain = 60 - gain = gain - 60 - else: - rfgain = gain - gain = 0 - if gain > 35: - ifgain = 35 - gain = gain - 35 - else: - ifgain = gain - gain = 0 - pgagain = gain - self._set_rfagc(rfgain) - self._set_ifagc(ifgain) - self._set_pga(pgagain) - - def freq_range(self): - return (50e6, 860e6, 10e3) - - def set_freq(self, target_freq): - """ - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - r = self.freq_range() - if target_freq < r[0] or target_freq > r[1]: - return (False, 0) - - target_lo_freq = target_freq + self._first_IF; # High side mixing - f_ref = 4e6 / self._reference_divisor # frequency steps - - divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8)) - actual_lo_freq = (f_ref * 8 * divisor) - actual_freq = actual_lo_freq - self._first_IF; - - if (divisor & ~0x7fff) != 0: # must be 15-bits or less - return (False, 0) - - # build i2c command string - buf = [0] * 4 - buf[0] = (divisor >> 8) & 0xff # DB1 - buf[1] = divisor & 0xff # DB2 - buf[2] = control_byte_1(self._fast_tuning, self._reference_divisor) - buf[3] = control_byte_2(actual_freq, True) - - ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf)) - - return (ok, actual_freq - self._second_IF) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return False - - def spectrum_inverted(self): - """ - The 43.75 MHz version is inverted - """ - return self._inverted - -# hook this daughterboard class into the auto-instantiation framework - -# With MT4937DI5-3x7702 with second downconversion -db_instantiator.add(usrp_dbid.TV_RX, - lambda usrp, which : (db_tv_rx(usrp, which, 43.75e6, 5.75e6, False),)) - -# With MT4937DI5-3x8680, and 3x8769 without second downconversion -db_instantiator.add(usrp_dbid.TV_RX_REV_2, - lambda usrp, which : (db_tv_rx(usrp, which, 44e6, 44e6, True),)) - -# With MT4937DI5-3x7901 without second downconversion, basically the same as tvrx2 -db_instantiator.add(usrp_dbid.TV_RX_REV_3, - lambda usrp, which : (db_tv_rx(usrp, which, 44e6, 44e6, True),)) diff --git a/gr-usrp/src/db_wbx.py b/gr-usrp/src/db_wbx.py deleted file mode 100644 index 72b3e35c..00000000 --- a/gr-usrp/src/db_wbx.py +++ /dev/null @@ -1,622 +0,0 @@ -# -# Copyright 2007 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. -# - -from gnuradio import usrp1 -import time,math - -from usrpm import usrp_dbid -import db_base -import db_instantiator -from usrpm.usrp_fpga_regs import * - -#debug_using_gui = True # Must be set to True or False -debug_using_gui = False # Must be set to True or False - -#if debug_using_gui: -# import flexrf_debug_gui - -# d'board i/o pin defs - -# TX IO Pins -TX_POWER = (1 << 0) # TX Side Power -RX_TXN = (1 << 1) # T/R antenna switch for TX/RX port -TX_ENB_MIX = (1 << 2) # Enable IQ mixer -TX_ENB_VGA = (1 << 3) - -# RX IO Pins -RX2_RX1N = (1 << 0) # antenna switch between RX2 and TX/RX port -RXENABLE = (1 << 1) # enables mixer -PLL_LOCK_DETECT = (1 << 2) # Muxout pin from PLL -- MUST BE INPUT -MReset = (1 << 3) # NB6L239 Master Reset, asserted low -SELA0 = (1 << 4) # NB6L239 SelA0 -SELA1 = (1 << 5) # NB6L239 SelA1 -SELB0 = (1 << 6) # NB6L239 SelB0 -SELB1 = (1 << 7) # NB6L239 SelB1 -PLL_ENABLE = (1 << 8) # CE Pin on PLL -AUX_SCLK = (1 << 9) # ALT SPI SCLK -AUX_SDO = (1 << 10) # ALT SPI SDO -AUX_SEN = (1 << 11) # ALT SPI SEN - -SPI_ENABLE_TX_A = usrp1.SPI_ENABLE_TX_A -SPI_ENABLE_TX_B = usrp1.SPI_ENABLE_TX_B -SPI_ENABLE_RX_A = usrp1.SPI_ENABLE_RX_A -SPI_ENABLE_RX_B = usrp1.SPI_ENABLE_RX_B - - -""" -A few comments about the WBX boards: - They are half-duplex. I.e., transmit and receive are mutually exclusive. - There is a single LO for both the Tx and Rx sides. - The the shared control signals are hung off of the Rx side. - The shared io controls are duplexed onto the Rx side pins. - The wbx_high d'board always needs to be in 'auto_tr_mode' -""" - - -class wbx_base(db_base.db_base): - """ - Abstract base class for all wbx boards. - - Derive board specific subclasses from db_wbx_base_{tx,rx} - """ - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to side A or B respectively - @type which: int - """ - # sets _u _which _tx and _slot - db_base.db_base.__init__(self, usrp, which) - - self.first = True - self.spi_format = usrp1.SPI_FMT_MSB | usrp1.SPI_FMT_HDR_0 - - # FIXME -- the write reg functions don't work with 0xffff for masks - self._rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff) - self._rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE)) - - self._tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff) - self._tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)) # TX off, TR switch set to RX - - self.spi_enable = (SPI_ENABLE_RX_A, SPI_ENABLE_RX_B)[which] - - self.set_auto_tr(False) - - #if debug_using_gui: - # title = "FlexRF Debug Rx" - # if self._tx: - # title = "FlexRF Debug Tx" - # self.gui = flexrf_debug_gui.flexrf_debug_gui(self, title) - # self.gui.Show(True) - - - def __del__(self): - #self._u.write_io(self._which, self.power_off, POWER_UP) # turn off power to board - #self._u._write_oe(self._which, 0, 0xffff) # turn off all outputs - self.set_auto_tr(False) - - def _lock_detect(self): - """ - @returns: the value of the VCO/PLL lock detect bit. - @rtype: 0 or 1 - """ - if self._rx_read_io() & PLL_LOCK_DETECT: - return True - else: # Give it a second chance - if self._rx_read_io() & PLL_LOCK_DETECT: - return True - else: - return False - - # Both sides need access to the Rx pins. - # Write them directly, bypassing the convenience routines. - # (Sort of breaks modularity, but will work...) - - def _tx_write_oe(self, value, mask): - return self._u._write_fpga_reg((FR_OE_0, FR_OE_2)[self._which], - ((mask & 0xffff) << 16) | (value & 0xffff)) - - def _rx_write_oe(self, value, mask): - return self._u._write_fpga_reg((FR_OE_1, FR_OE_3)[self._which], - ((mask & 0xffff) << 16) | (value & 0xffff)) - - def _tx_write_io(self, value, mask): - return self._u._write_fpga_reg((FR_IO_0, FR_IO_2)[self._which], - ((mask & 0xffff) << 16) | (value & 0xffff)) - - def _rx_write_io(self, value, mask): - return self._u._write_fpga_reg((FR_IO_1, FR_IO_3)[self._which], - ((mask & 0xffff) << 16) | (value & 0xffff)) - - def _rx_read_io(self): - t = self._u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self._which]) - return (t >> 16) & 0xffff - - def _tx_read_io(self): - t = self._u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self._which]) - return t & 0xffff - - - def _compute_regs(self, freq): - """ - Determine values of registers, along with actual freq. - - @param freq: target frequency in Hz - @type freq: float - @returns: (R, N, func, init, actual_freq) - @rtype: tuple(int, int, int, int, float) - - Override this in derived classes. - """ - raise NotImplementedError - - def _refclk_freq(self): - return float(self._u.fpga_master_clock_freq())/self._refclk_divisor() - - def _refclk_divisor(self): - """ - Return value to stick in REFCLK_DIVISOR register - """ - return 1 - - # ---------------------------------------------------------------- - - def set_freq(self, freq): - """ - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - raise NotImplementedError - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - raise NotImplementedError - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - raise NotImplementedError - - def _set_pga(self, pga_gain): - if(self._which == 0): - self._u.set_pga (0, pga_gain) - self._u.set_pga (1, pga_gain) - else: - self._u.set_pga (2, pga_gain) - self._u.set_pga (3, pga_gain) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return True - -# ---------------------------------------------------------------- - -class wbx_base_tx(wbx_base): - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.sink_c - @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. - """ - wbx_base.__init__(self, usrp, which) - - # power up the transmit side, NO -- but set antenna to receive - self._u.write_io(self._which, (TX_POWER), (TX_POWER|RX_TXN)) - self._lo_offset = 0e6 - - # Gain is not set by the PGA, but the PGA must be set at max gain in the TX - return self._set_pga(self._u.pga_max()) - - def __del__(self): - # Power down and leave the T/R switch in the R position - self._u.write_io(self._which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)) - wbx_base.__del__(self) - - def set_auto_tr(self, on): - if on: - self.set_atr_mask (RX_TXN) - self.set_atr_txval(0) - self.set_atr_rxval(RX_TXN) - else: - self.set_atr_mask (0) - self.set_atr_txval(0) - self.set_atr_rxval(0) - - def set_enable(self, on): - """ - Enable transmitter if on is True - """ - mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA - print "HERE!!!!" - if on: - self._u.write_io(self._which, TX_ENB_MIX|TX_ENB_VGA, mask) - else: - self._u.write_io(self._which, RX_TXN, mask) - - - def set_lo_offset(self, offset): - """ - Set amount by which LO is offset from requested tuning frequency. - - @param offset: offset in Hz - """ - self._lo_offset = offset - - def lo_offset(self): - """ - Get amount by which LO is offset from requested tuning frequency. - - @returns Offset in Hz - """ - return self._lo_offset - -class wbx_base_rx(wbx_base): - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.source_c - @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. - """ - wbx_base.__init__(self, usrp, which) - - # set up for RX on TX/RX port - self.select_rx_antenna('TX/RX') - - self.bypass_adc_buffers(True) - - self._lo_offset = 0.0 - - def __del__(self): - # Power down - self._u.write_io(self._which, 0, (RXENABLE)) - wbx_base.__del__(self) - - def set_auto_tr(self, on): - if on: - self.set_atr_mask (ENABLE) - self.set_atr_txval( 0) - self.set_atr_rxval(ENABLE) - else: - self.set_atr_mask (0) - self.set_atr_txval(0) - self.set_atr_rxval(0) - - def select_rx_antenna(self, which_antenna): - """ - Specify which antenna port to use for reception. - @param which_antenna: either 'TX/RX' or 'RX2' - """ - if which_antenna in (0, 'TX/RX'): - self._u.write_io(self._which, 0, RX2_RX1N) - elif which_antenna in (1, 'RX2'): - self._u.write_io(self._which, RX2_RX1N, RX2_RX1N) - else: - raise ValueError, "which_antenna must be either 'TX/RX' or 'RX2'" - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - maxgain = self.gain_range()[1] - self._u.pga_max() - mingain = self.gain_range()[0] - if gain > maxgain: - pga_gain = gain-maxgain - assert pga_gain <= self._u.pga_max() - agc_gain = maxgain - else: - pga_gain = 0 - agc_gain = gain - V_maxgain = .2 - V_mingain = 1.2 - V_fullscale = 3.3 - dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale - assert dac_value>=0 and dac_value<4096 - return self._u.write_aux_dac(self._which, 0, int(dac_value)) and \ - self._set_pga(int(pga_gain)) - - def set_lo_offset(self, offset): - """ - Set amount by which LO is offset from requested tuning frequency. - - @param offset: offset in Hz - """ - self._lo_offset = offset - - def lo_offset(self): - """ - Get amount by which LO is offset from requested tuning frequency. - - @returns Offset in Hz - """ - return self._lo_offset - - - def i_and_q_swapped(self): - """ - Return True if this is a quadrature device and ADC 0 is Q. - """ - return False - -# ---------------------------------------------------------------- - -class _ADF410X_common(object): - def __init__(self): - # R-Register Common Values - self.R_RSV = 0 # bits 23,22,21 - self.LDP = 1 # bit 20 Lock detect in 5 cycles - self.TEST = 0 # bit 19,18 Normal - self.ABP = 0 # bit 17,16 2.9ns - - # N-Register Common Values - self.N_RSV = 0 # 23,22 - self.CP_GAIN = 0 # 21 - - # Function Register Common Values - self.P = 0 # bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65 - self.PD2 = 0 # bit 21 Normal operation - self.CP2 = 4 # bits 20,19,18 CP Gain = 5mA - self.CP1 = 4 # bits 17,16,15 CP Gain = 5mA - self.TC = 0 # bits 14-11 PFD Timeout - self.FL = 0 # bit 10,9 Fastlock Disabled - self.CP3S = 0 # bit 8 CP Enabled - self.PDP = 0 # bit 7 Phase detector polarity, Positive=1 - self.MUXOUT = 1 # bits 6:4 Digital Lock Detect - self.PD1 = 0 # bit 3 Normal operation - self.CR = 0 # bit 2 Normal operation - - def _compute_regs(self, freq): - """ - Determine values of R, control, and N registers, along with actual freq. - - @param freq: target frequency in Hz - @type freq: float - @returns: (R, N, control, actual_freq) - @rtype: tuple(int, int, int, float) - """ - - # Band-specific N-Register Values - phdet_freq = self._refclk_freq()/self.R_DIV - print "phdet_freq = %f" % (phdet_freq,) - desired_n = round(freq*self.freq_mult/phdet_freq) - print "desired_n %f" % (desired_n,) - actual_freq = desired_n * phdet_freq - print "actual freq %f" % (actual_freq,) - B = math.floor(desired_n/self._prescaler()) - A = desired_n - self._prescaler()*B - print "A %d B %d" % (A,B) - self.B_DIV = int(B) # bits 20:8 - self.A_DIV = int(A) # bit 6:2 - #assert self.B_DIV >= self.A_DIV - if self.B_DIV < self.A_DIV: - return (0,0,0,0) - R = (self.R_RSV<<21) | (self.LDP<<20) | (self.TEST<<18) | \ - (self.ABP<<16) | (self.R_DIV<<2) - - N = (self.N_RSV<<22) | (self.CP_GAIN<<21) | (self.B_DIV<<8) | (self.A_DIV<<2) - - control = (self.P<<22) | (self.PD2<<21) | (self.CP2<<18) | (self.CP1<<15) | \ - (self.TC<<11) | (self.FL<<9) | (self.CP3S<<8) | (self.PDP<<7) | \ - (self.MUXOUT<<4) | (self.PD1<<3) | (self.CR<<2) - - return (R,N,control,actual_freq/self.freq_mult) - - def _write_all(self, R, N, control): - """ - Write all PLL registers: - R counter latch, - N counter latch, - Function latch, - Initialization latch - - Adds 10ms delay between writing control and N if this is first call. - This is the required power-up sequence. - - @param R: 24-bit R counter latch - @type R: int - @param N: 24-bit N counter latch - @type N: int - @param control: 24-bit control latch - @type control: int - """ - self._write_R(R) - self._write_func(control) - self._write_init(control) - if self.first: - time.sleep(0.010) - self.first = False - self._write_N(N) - - def _write_R(self, R): - self._write_it((R & ~0x3) | 0) - - def _write_N(self, N): - self._write_it((N & ~0x3) | 1) - - def _write_func(self, func): - self._write_it((func & ~0x3) | 2) - - def _write_init(self, init): - self._write_it((init & ~0x3) | 3) - - def _write_it(self, v): - s = ''.join((chr((v >> 16) & 0xff), - chr((v >> 8) & 0xff), - chr(v & 0xff))) - self._u._write_spi(0, self.spi_enable, self.spi_format, s) - - def _prescaler(self): - if self.P == 0: - return 8 - elif self.P == 1: - return 16 - elif self.P == 2: - return 32 - elif self.P == 3: - return 64 - else: - raise ValueError, "Prescaler out of range" - -#---------------------------------------------------------------------- -class _lo_common(_ADF410X_common): - def __init__(self): - _ADF410X_common.__init__(self) - - # Band-specific R-Register Values - self.R_DIV = 4 # bits 15:2 - - # Band-specific C-Register values - self.P = 0 # bits 23,22 0 = Div by 8/9 - self.CP2 = 4 # bits 19:17 - self.CP1 = 4 # bits 16:14 - - # Band specifc N-Register Values - self.DIVSEL = 0 # bit 23 - self.DIV2 = 0 # bit 22 - self.CPGAIN = 0 # bit 21 - self.freq_mult = 1 - - self.div = 1 - self.aux_div = 2 - - def freq_range(self): # FIXME - return (50e6, 1000e6, 16e6) - - def set_divider(self, main_or_aux, divisor): - if main_or_aux not in (0, 'main', 1, 'aux'): - raise ValueError, "main_or_aux must be 'main' or 'aux'" - if main_or_aux in (0, 'main'): - if divisor not in (1,2,4,8): - raise ValueError, "Main Divider Must be 1, 2, 4, or 8" - for (div,val) in ((1,0),(2,1),(4,2),(8,3)): - if(div == divisor): - self.main_div = val - else: - if divisor not in (2,4,8,16): - raise ValueError, "Aux Divider Must be 2, 4, 8 or 16" - for (div,val) in ((2,0),(4,1),(8,2),(16,3)): - if(div == divisor): - self.aux_div = val - - vala = self.main_div*SELA0 - valb = self.aux_div*SELB0 - mask = SELA0|SELA1|SELB0|SELB1 - - self._rx_write_io(((self.main_div*SELA0) | (self.aux_div*SELB0)), - (SELA0|SELA1|SELB0|SELB1)) - - def set_freq(self, freq): - #freq += self._lo_offset - - if(freq < 20e6 or freq > 1200e6): - raise ValueError, "Requested frequency out of range" - div = 1 - lo_freq = freq * 2 - while lo_freq < 1e9 and div < 8: - div = div * 2 - lo_freq = lo_freq * 2 - print "For RF freq of %f, we set DIV=%d and LO Freq=%f" % (freq, div, lo_freq) - self.set_divider('main', div) - self.set_divider('aux', div*2) - - R, N, control, actual_freq = self._compute_regs(lo_freq) - print "R %d N %d control %d actual freq %f" % (R,N,control,actual_freq) - if R==0: - return(False,0) - self._write_all(R, N, control) - return (self._lock_detect(), actual_freq/div/2) - - -#------------------------------------------------------------ -class db_wbx_lo_tx(_lo_common, wbx_base_tx): - def __init__(self, usrp, which): - wbx_base_tx.__init__(self, usrp, which) - _lo_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - - Gain is controlled by a VGA in the output amplifier, not the PGA - """ - return (-56, 0, 0.1) - - def set_gain(self, gain): - """ - Set the gain. - - @param gain: gain in decibels - @returns True/False - """ - maxgain = self.gain_range()[1] - mingain = self.gain_range()[0] - if gain > maxgain: - txvga_gain = maxgain - elif gain < mingain: - txvga_gain = mingain - else: - txvga_gain = gain - - V_maxgain = 1.4 - V_mingain = 0.1 - V_fullscale = 3.3 - dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale - assert dac_value>=0 and dac_value<4096 - print "DAC value %d" % (dac_value,) - return self._u.write_aux_dac(self._which, 1, int(dac_value)) - -class db_wbx_lo_rx(_lo_common, wbx_base_rx): - def __init__(self, usrp, which): - wbx_base_rx.__init__(self, usrp, which) - _lo_common.__init__(self) - - def gain_range(self): - """ - Return range of gain that can be set by this d'board. - - @returns (min_gain, max_gain, step_size) - Where gains are expressed in decibels (your mileage may vary) - """ - return (self._u.pga_min(), self._u.pga_max() + 45, 0.05) - -#------------------------------------------------------------ -# hook these daughterboard classes into the auto-instantiation framework -db_instantiator.add(usrp_dbid.WBX_LO_TX, lambda usrp, which : (db_wbx_lo_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.WBX_LO_RX, lambda usrp, which : (db_wbx_lo_rx(usrp, which),)) - - diff --git a/gr-usrp/src/db_xcvr2450.py b/gr-usrp/src/db_xcvr2450.py deleted file mode 100644 index ec058763..00000000 --- a/gr-usrp/src/db_xcvr2450.py +++ /dev/null @@ -1,538 +0,0 @@ -# -# Copyright 2007 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. -# - -from gnuradio import usrp1, gru, eng_notation -import time, math, weakref - -from usrpm import usrp_dbid -import db_base -import db_instantiator -from usrpm.usrp_fpga_regs import * - -# Convenience function -n2s = eng_notation.num_to_str - -# d'board i/o pin defs - -# TX IO Pins -HB_PA_OFF = (1 << 15) # 5GHz PA, 1 = off, 0 = on -LB_PA_OFF = (1 << 14) # 2.4GHz PA, 1 = off, 0 = on -ANTSEL_TX1_RX2 = (1 << 13) # 1 = Ant 1 to TX, Ant 2 to RX -ANTSEL_TX2_RX1 = (1 << 12) # 1 = Ant 2 to TX, Ant 1 to RX -TX_EN = (1 << 11) # 1 = TX on, 0 = TX off -AD9515DIV = (1 << 4) # 1 = Div by 3, 0 = Div by 2 - -TX_OE_MASK = HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV -TX_SAFE_IO = HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV - -# RX IO Pins -LOCKDET = (1 << 15) # This is an INPUT!!! -EN = (1 << 14) -RX_EN = (1 << 13) # 1 = RX on, 0 = RX off -RX_HP = (1 << 12) -B1 = (1 << 11) -B2 = (1 << 10) -B3 = (1 << 9) -B4 = (1 << 8) -B5 = (1 << 7) -B6 = (1 << 6) -B7 = (1 << 5) -RX_OE_MASK = EN|RX_EN|RX_HP|B1|B2|B3|B4|B5|B6|B7 -RX_SAFE_IO = EN - - -# ------------------------------------------------------------------------ -# A few comments about the XCVR2450: -# -# It is half-duplex. I.e., transmit and receive are mutually exclusive. -# There is a single LO for both the Tx and Rx sides. -# For our purposes the board is always either receiving or transmitting. -# -# Each board is uniquely identified by the *USRP hardware* instance and side -# This dictionary holds a weak reference to existing board controller so it -# can be created or retrieved as needed. - -_xcvr2450_inst = weakref.WeakValueDictionary() -def _get_or_make_xcvr2450(usrp, which): - key = (usrp.serial_number(), which) - if not _xcvr2450_inst.has_key(key): - print "Creating new xcvr2450 instance" - inst = xcvr2450(usrp, which) - _xcvr2450_inst[key] = inst - else: - print "Using existing xcvr2450 instance" - inst = _xcvr2450_inst[key] - return inst - -# ------------------------------------------------------------------------ -# Common, shared object for xcvr2450 board. Transmit and receive classes -# operate on an instance of this; one instance is created per physical -# daughterboard. - -class xcvr2450(object): - def __init__(self, usrp, which): - print "xcvr2450: __init__ with %s: %d" % (usrp.serial_number(), which) - self.u = usrp - self.which = which - - # Use MSB with no header - self.spi_format = usrp1.SPI_FMT_MSB | usrp1.SPI_FMT_HDR_0 - self.spi_enable = (usrp1.SPI_ENABLE_RX_A, usrp1.SPI_ENABLE_RX_B)[which] - - # Sane defaults - self.mimo = 1 # 0 = OFF, 1 = ON - self.int_div = 192 # 128 = min, 255 = max - self.frac_div = 0 # 0 = min, 65535 = max - self.highband = 0 # 0 = freq <= 5.4e9, 1 = freq > 5.4e9 - self.five_gig = 0 # 0 = freq <= 3.e9, 1 = freq > 3e9 - self.cp_current = 0 # 0 = 2mA, 1 = 4mA - self.ref_div = 4 # 1 to 7 - self.rssi_hbw = 0 # 0 = 2 MHz, 1 = 6 MHz - self.txlpf_bw = 1 # 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz - self.rxlpf_bw = 1 # 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz - self.rxlpf_fine = 2 # 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110% - self.rxvga_ser = 1 # 0 = RXVGA controlled by B7:1, 1 = controlled serially - self.rssi_range = 1 # 0 = low range (datasheet typo), 1 = high range (0.5V - 2.0V) - self.rssi_mode = 1 # 0 = enable follows RXHP, 1 = enabled - self.rssi_mux = 0 # 0 = RSSI, 1 = TEMP - self.rx_hp_pin = 0 # 0 = Fc set by rx_hpf, 1 = 600 KHz - self.rx_hpf = 0 # 0 = 100Hz, 1 = 30KHz - self.rx_ant = 0 # 0 = Ant. #1, 1 = Ant. #2 - self.tx_ant = 0 # 0 = Ant. #1, 1 = Ant. #2 - self.txvga_ser = 1 # 0 = TXVGA controlled by B6:1, 1 = controlled serially - self.tx_driver_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin) - self.tx_vga_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin) - self.tx_upconv_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin) - self.tx_bb_gain = 3 # 0 = maxgain-5dB, 1 = max-3dB, 2 = max-1.5dB, 3 = max - self.pabias_delay = 15 # 0 = 0, 15 = 7uS - self.pabias = 0 # 0 = 0 uA, 63 = 315uA - self.rx_rf_gain = 0 # 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB - self.rx_bb_gain = 16 # 0 = min, 31 = max (0 - 62 dB) - - self.txgain = 63 # 0 = min, 63 = max - - # Initialize GPIO and ATR - self.tx_write_io(TX_SAFE_IO, TX_OE_MASK) - self.tx_write_oe(TX_OE_MASK, ~0) - self.tx_set_atr_txval(TX_SAFE_IO) - self.tx_set_atr_rxval(TX_SAFE_IO) - self.tx_set_atr_mask(TX_OE_MASK) - self.rx_write_io(RX_SAFE_IO, RX_OE_MASK) - self.rx_write_oe(RX_OE_MASK, ~0) - self.rx_set_atr_rxval(RX_SAFE_IO) - self.rx_set_atr_txval(RX_SAFE_IO) - self.rx_set_atr_mask(RX_OE_MASK) - - # Initialize chipset - # TODO: perform reset sequence to ensure power up defaults - self.set_reg_standby() - self.set_reg_bandselpll() - self.set_reg_cal() - self.set_reg_lpf() - self.set_reg_rxrssi_ctrl() - self.set_reg_txlin_gain() - self.set_reg_pabias() - self.set_reg_rxgain() - self.set_reg_txgain() - self.set_freq(2.45e9) - - def __del__(self): - print "xcvr2450: __del__" - self.tx_set_atr_txval(TX_SAFE_IO) - self.tx_set_atr_rxval(TX_SAFE_IO) - self.rx_set_atr_rxval(RX_SAFE_IO) - self.rx_set_atr_txval(RX_SAFE_IO) - - - # -------------------------------------------------------------------- - # These methods set the MAX2829 onboard registers over the SPI bus. - # The SPI format is 18 bits, with the four LSBs holding the register no. - # Thus, the shift values used here are the D0-D13 values from the data - # sheet, *plus* four. - - # Standby (2) - def set_reg_standby(self): - self.reg_standby = ( - (self.mimo<<17) | - (1<<16) | - (1<<6) | - (1<<5) | - (1<<4) | 2) - self.send_reg(self.reg_standby) - - # Integer-Divider Ratio (3) - def set_reg_int_divider(self): - self.reg_int_divider = ( - ((self.frac_div & 0x03)<<16) | - (self.int_div<<4) | 3) - self.send_reg(self.reg_int_divider) - - # Fractional-Divider Ratio (4) - def set_reg_frac_divider(self): - self.reg_frac_divider = ((self.frac_div & 0xfffc)<<2) | 4 - self.send_reg(self.reg_frac_divider) - - # Band Select and PLL (5) - def set_reg_bandselpll(self): - self.reg_bandselpll = ( - (self.mimo<<17) | - (1<<16) | - (1<<15) | - (1<<11) | - (self.highband<<10) | - (self.cp_current<<9) | - (self.ref_div<<5) | - (self.five_gig<<4) | 5) - self.send_reg(self.reg_bandselpll) - - - # Calibration (6) - def set_reg_cal(self): - # FIXME do calibration - self.reg_cal = (1<<14)|6 - self.send_reg(self.reg_cal) - - - # Lowpass Filter (7) - def set_reg_lpf(self): - self.reg_lpf = ( - (self.rssi_hbw<<15) | - (self.txlpf_bw<<10) | - (self.rxlpf_bw<<9) | - (self.rxlpf_fine<<4) | 7) - self.send_reg(self.reg_lpf) - - - # Rx Control/RSSI (8) - def set_reg_rxrssi_ctrl(self): - self.reg_rxrssi_ctrl = ( - (self.rxvga_ser<<16) | - (self.rssi_range<<15) | - (self.rssi_mode<<14) | - (self.rssi_mux<<12) | - (1<<9) | - (self.rx_hpf<<6) | - (1<<4) | 8) - self.send_reg(self.reg_rxrssi_ctrl) - - - # Tx Linearity/Baseband Gain (9) - def set_reg_txlin_gain(self): - self.reg_txlin_gain = ( - (self.txvga_ser<<14) | - (self.tx_driver_lin<<12) | - (self.tx_vga_lin<<10) | - (self.tx_upconv_lin<<6) | - (self.tx_bb_gain<<4) | 9) - self.send_reg(self.reg_txlin_gain) - - - # PA Bias DAC (10) - def set_reg_pabias(self): - self.reg_pabias = ( - (self.pabias_delay<<10) | - (self.pabias<<4) | 10) - self.send_reg(self.reg_pabias) - - - # Rx Gain (11) - def set_reg_rxgain(self): - self.reg_rxgain = ( - (self.rx_rf_gain<<9) | - (self.rx_bb_gain<<4) | 11) - self.send_reg(self.reg_rxgain) - - - # Tx Gain (12) - def set_reg_txgain(self): - self.reg_txgain = (self.txgain<<4) | 12 - self.send_reg(self.reg_txgain) - - - # Send register write to SPI - def send_reg(self, v): - # Send 24 bits, it keeps last 18 clocked in - s = ''.join((chr((v >> 16) & 0xff), - chr((v >> 8) & 0xff), - chr(v & 0xff))) - self.u._write_spi(0, self.spi_enable, self.spi_format, s) - #print "xcvr2450: Setting reg %d to %06X" % ((v&15), v) - - # -------------------------------------------------------------------- - # These methods control the GPIO bus. Since the board has to access - # both the io_rx_* and io_tx_* pins, we define our own methods to do so. - # This bypasses any code in db_base. - # - # The board operates in ATR mode, always. Thus, when the board is first - # initialized, it is in receive mode, until bits show up in the TX FIFO. - # - def tx_write_oe(self, value, mask): - return self.u._write_fpga_reg((FR_OE_0, FR_OE_2)[self.which], - gru.hexint((mask << 16) | value)) - - def tx_write_io(self, value, mask): - return self.u._write_fpga_reg((FR_IO_0, FR_IO_2)[self.which], - gru.hexint((mask << 16) | value)) - - def tx_read_io(self): - t = self.u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self.which]) - return t & 0xffff - - - def rx_write_oe(self, value, mask): - return self.u._write_fpga_reg((FR_OE_1, FR_OE_3)[self.which], - gru.hexint((mask << 16) | value)) - - def rx_write_io(self, value, mask): - return self.u._write_fpga_reg((FR_IO_1, FR_IO_3)[self.which], - gru.hexint((mask << 16) | value)) - - def rx_read_io(self): - t = self.u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self.which]) - return (t >> 16) & 0xffff - - def tx_set_atr_mask(self, v): - return self.u._write_fpga_reg((FR_ATR_MASK_0,FR_ATR_MASK_2)[self.which], - gru.hexint(v)) - - def tx_set_atr_txval(self, v): - return self.u._write_fpga_reg((FR_ATR_TXVAL_0,FR_ATR_TXVAL_2)[self.which], - gru.hexint(v)) - - def tx_set_atr_rxval(self, v): - return self.u._write_fpga_reg((FR_ATR_RXVAL_0,FR_ATR_RXVAL_2)[self.which], - gru.hexint(v)) - - def rx_set_atr_mask(self, v): - return self.u._write_fpga_reg((FR_ATR_MASK_1,FR_ATR_MASK_3)[self.which], - gru.hexint(v)) - - def rx_set_atr_txval(self, v): - return self.u._write_fpga_reg((FR_ATR_TXVAL_1,FR_ATR_TXVAL_3)[self.which], - gru.hexint(v)) - - def rx_set_atr_rxval(self, v): - return self.u._write_fpga_reg((FR_ATR_RXVAL_1,FR_ATR_RXVAL_3)[self.which], - gru.hexint(v)) - - def set_gpio(self): - # We calculate four values: - # - # io_rx_while_rx: what to drive onto io_rx_* when receiving - # io_rx_while_tx: what to drive onto io_rx_* when transmitting - # io_tx_while_rx: what to drive onto io_tx_* when receiving - # io_tx_while_tx: what to drive onto io_tx_* when transmitting - # - # B1-B7 is ignored as gain is set serially for now. - - rx_hp = (0, RX_HP)[self.rx_hp_pin] - tx_antsel = (ANTSEL_TX1_RX2, ANTSEL_TX2_RX1)[self.tx_ant] - rx_antsel = (ANTSEL_TX1_RX2, ANTSEL_TX2_RX1)[self.rx_ant] - tx_pa_sel = (HB_PA_OFF, LB_PA_OFF)[self.five_gig] - io_rx_while_rx = EN|rx_hp|RX_EN - io_rx_while_tx = EN|rx_hp - io_tx_while_rx = HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV - io_tx_while_tx = tx_pa_sel|tx_antsel|TX_EN|AD9515DIV - self.rx_set_atr_rxval(io_rx_while_rx) - self.rx_set_atr_txval(io_rx_while_tx) - self.tx_set_atr_rxval(io_tx_while_rx) - self.tx_set_atr_txval(io_tx_while_tx) - - #print "GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X" % ( - #io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx) - - # -------------------------------------------------------------------- - # These methods set control the high-level operating parameters. - - def set_freq(self, target_freq): - if target_freq > 3e9: - self.five_gig = 1 - self.ref_div = 1 - self.ad9515_div = 3 - scaler = 4.0/5.0 - else: - self.five_gig = 0 - self.ref_div = 1 - self.ad9515_div = 3 - scaler = 4.0/3.0; - - if target_freq > 5.275e9: - self.highband = 1 - else: - self.highband = 0 - - vco_freq = target_freq*scaler; - sys_clk = self.u.fpga_master_clock_freq() # Usually 64e6 - ref_clk = sys_clk / self.ad9515_div - - phdet_freq = ref_clk/self.ref_div - div = vco_freq/phdet_freq - self.int_div = int(math.floor(div)) - self.frac_div = int((div-self.int_div)*65536.0) - actual_freq = phdet_freq*(self.int_div+(self.frac_div/65536.0))/scaler - - #print "RF=%s VCO=%s R=%d PHD=%s DIV=%3.5f I=%3d F=%5d ACT=%s" % ( - # n2s(target_freq), n2s(vco_freq), self.ref_div, n2s(phdet_freq), - # div, self.int_div, self.frac_div, n2s(actual_freq)) - - self.set_gpio() - self.set_reg_int_divider() - self.set_reg_frac_divider() - self.set_reg_bandselpll() - - ok = self.lock_detect() - #if(not ok): - # ok = self.lock_detect() - # if ok: - # print "lock detect on 2nd try %f" % (target_freq,) - - if(not ok): - if (target_freq > 5.275e9) and (target_freq <= 5.35e9): - self.highband = 0 - self.set_reg_bandselpll() - ok = self.lock_detect() - print "swap to 0 at %f, ok %d" % (target_freq,ok) - if (target_freq >= 5.25e9) and (target_freq <= 5.275e9): - self.highband = 1 - self.set_reg_bandselpll() - ok = self.lock_detect() - print "swap to 1 at %f, ok %d" % (target_freq,ok) - - if(not ok): - print "Fail %f" % (target_freq,) - return (ok, actual_freq) - - def lock_detect(self): - """ - @returns: the value of the VCO/PLL lock detect bit. - @rtype: 0 or 1 - """ - if self.rx_read_io() & LOCKDET: - return True - else: # Give it a second chance - if self.rx_read_io() & LOCKDET: - return True - else: - return False - - def set_rx_gain(self, gain): - if gain < 0.0: gain = 0.0 - if gain > 92.0: gain = 92.0 - - # Split the gain between RF and baseband - # This is experimental, not prescribed - if gain < 31.0: - self.rx_rf_gain = 0 # 0 dB RF gain - self.rx_bb_gain = int(gain/2.0) - - if gain >= 30.0 and gain < 60.5: - self.rx_rf_gain = 2 # 15 dB RF gain - self.rx_bb_gain = int((gain-15.0)/2.0) - - if gain >= 60.5: - self.rx_rf_gain = 3 # 30.5 dB RF gain - self.rx_bb_gain = int((gain-30.5)/2.0) - - self.set_reg_rxgain() - - def set_tx_gain(self, gain): - if gain < 0.0: gain = 0.0 - if gain > 30.0: gain = 30.0 - self.txgain = int((gain/30.0)*63) - self.set_reg_txgain() - -class db_xcvr2450_base(db_base.db_base): - """ - Abstract base class for all xcvr2450 boards. - - Derive board specific subclasses from db_xcvr2450_base_{tx,rx} - """ - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to side A or B respectively - @type which: int - """ - # sets _u _which _tx and _slot - db_base.db_base.__init__(self, usrp, which) - self.xcvr = _get_or_make_xcvr2450(usrp, which) - - def set_freq(self, target_freq): - """ - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - """ - return self.xcvr.set_freq(target_freq) - - def is_quadrature(self): - """ - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - """ - return True - - def freq_range(self): - return (2.4e9, 6e9, 1e6) - - def set_freq(self, target_freq): - return self.xcvr.set_freq(target_freq) - -# ---------------------------------------------------------------- - -class db_xcvr2450_tx(db_xcvr2450_base): - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.sink_c - @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. - """ - print "db_xcvr2450_tx: __init__" - db_xcvr2450_base.__init__(self, usrp, which) - - def gain_range(self): - return (0, 30, (30.0/63.0)) - - def set_gain(self, gain): - return self.xcvr.set_tx_gain(gain) - - def i_and_q_swapped(self): - return True - -class db_xcvr2450_rx(db_xcvr2450_base): - def __init__(self, usrp, which): - """ - @param usrp: instance of usrp.source_c - @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. - """ - print "db_xcvr2450_rx: __init__" - db_xcvr2450_base.__init__(self, usrp, which) - - def gain_range(self): - return (0.0, 92.0, 1) - - def set_gain(self, gain): - return self.xcvr.set_rx_gain(gain) - -#------------------------------------------------------------ -# hook these daughterboard classes into the auto-instantiation framework -db_instantiator.add(usrp_dbid.XCVR2450_TX, lambda usrp, which : (db_xcvr2450_tx(usrp, which),)) -db_instantiator.add(usrp_dbid.XCVR2450_RX, lambda usrp, which : (db_xcvr2450_rx(usrp, which),)) diff --git a/gr-usrp/src/qa_usrp.py b/gr-usrp/src/qa_usrp.py index 99d1cfa6..db2d3262 100755 --- a/gr-usrp/src/qa_usrp.py +++ b/gr-usrp/src/qa_usrp.py @@ -21,7 +21,7 @@ # from gnuradio import gr, gr_unittest -import usrp1 +import usrp_swig class qa_usrp (gr_unittest.TestCase): diff --git a/gr-usrp/src/usrp.i b/gr-usrp/src/usrp.i new file mode 100644 index 00000000..40fa471b --- /dev/null +++ b/gr-usrp/src/usrp.i @@ -0,0 +1,144 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%feature("autodoc", "1"); // generate python docstrings + +%include "exception.i" +%import "gnuradio.i" // the common stuff + +%{ +#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix +#include +#include +%} + +%include +%include +%include +%include +%include "usrp_standard.i" +%include "usrp_base.i" +%include "usrp_source_base.i" +%include "usrp_source_c.i" +%include "usrp_source_s.i" +%include "usrp_sink_base.i" +%include "usrp_sink_c.i" +%include "usrp_sink_s.i" + +//---Allow a more Pythonic interface +%pythoncode %{ + +# Allow subdev_spec to be tuple +def __selected_subdev(self, subdev_spec): + ss = usrp_subdev_spec(subdev_spec[0], subdev_spec[1]) + return self._real_selected_subdev(ss) + +# Allow subdev_spec to be tuple +def __determine_tx_mux_value(self, subdev_spec): + ss = usrp_subdev_spec(subdev_spec[0], subdev_spec[1]) + return self._real_determine_tx_mux_value(ss) + +# Allow subdev_spec to be tuple +def __determine_rx_mux_value(self, subdev_spec): + ss = usrp_subdev_spec(subdev_spec[0], subdev_spec[1]) + return self._real_determine_rx_mux_value(ss) + +# Allow subdev_spec to be tuple +def __pick_subdev(self, candidates=[]): + ss = self._real_pick_subdev(candidates) + return (ss.side, ss.subdev) + +# Allow subdev_spec to be tuple +def __pick_tx_subdevice(self): + ss = self._real_pick_tx_subdevice() + return (ss.side, ss.subdev) + +# Allow subdev_spec to be tuple +def __pick_rx_subdevice(self): + ss = self._real_pick_rx_subdevice() + return (ss.side, ss.subdev) + +# Make return tune_result or None on failure +def __tune(self, chan, db, target_freq): + tr = usrp_tune_result() + r = self._real_tune(chan, db, target_freq, tr) + if r: + return tr + else: + return None + +# Allow to be called as a free function +def tune(u, chan, subdev, target_freq): + return u.tune(chan, subdev, target_freq) + +# Allow to be called as free function +def determine_tx_mux_value(u, subdev_spec): + return u.determine_tx_mux_value(subdev_spec) + +# Allow to be called as free function +def determine_rx_mux_value(u, subdev_spec): + return u.determine_rx_mux_value(subdev_spec) + +# Allow to be called as free function +def selected_subdev(u, subdev_spec): + return u.selected_subdev(subdev_spec) + +# Allow to be called as free function +def pick_subdev(u, candidates=[]): + return u.pick_subdev(candidates); + +# Allow to be called as free function +def pick_tx_subdevice(u): + return u.pick_tx_subdevice(); + +# Allow to be called as free function +def pick_rx_subdevice(u): + return u.pick_rx_subdevice(); + +# Jam into Python objects +usrp_sink_c_sptr.determine_tx_mux_value = __determine_tx_mux_value +usrp_sink_s_sptr.determine_tx_mux_value = __determine_tx_mux_value + +usrp_source_c_sptr.determine_rx_mux_value = __determine_rx_mux_value +usrp_source_s_sptr.determine_rx_mux_value = __determine_rx_mux_value + +usrp_sink_c_sptr.selected_subdev = __selected_subdev +usrp_sink_s_sptr.selected_subdev = __selected_subdev +usrp_source_c_sptr.selected_subdev = __selected_subdev +usrp_source_s_sptr.selected_subdev = __selected_subdev + +usrp_sink_c_sptr.tune = __tune +usrp_sink_s_sptr.tune = __tune +usrp_source_c_sptr.tune = __tune +usrp_source_s_sptr.tune = __tune + +usrp_sink_c_sptr.pick_subdev = __pick_subdev +usrp_sink_s_sptr.pick_subdev = __pick_subdev +usrp_source_c_sptr.pick_subdev = __pick_subdev +usrp_source_s_sptr.pick_subdev = __pick_subdev + +usrp_sink_c_sptr.pick_tx_subdevice = __pick_tx_subdevice +usrp_sink_s_sptr.pick_tx_subdevice = __pick_tx_subdevice +usrp_source_c_sptr.pick_rx_subdevice = __pick_rx_subdevice +usrp_source_s_sptr.pick_rx_subdevice = __pick_rx_subdevice + +%} diff --git a/gr-usrp/src/usrp.py b/gr-usrp/src/usrp.py deleted file mode 100644 index 0fe6a2c4..00000000 --- a/gr-usrp/src/usrp.py +++ /dev/null @@ -1,482 +0,0 @@ -# -# Copyright 2004,2005,2007 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. -# - - - -from usrpm import usrp_prims -from usrpm import usrp_dbid -from gnuradio import usrp1 # usrp Rev 1 and later -from gnuradio import gru -from usrpm.usrp_fpga_regs import * -import weakref - -FPGA_MODE_NORMAL = usrp1.FPGA_MODE_NORMAL -FPGA_MODE_LOOPBACK = usrp1.FPGA_MODE_LOOPBACK -FPGA_MODE_COUNTING = usrp1.FPGA_MODE_COUNTING - -SPI_FMT_xSB_MASK = usrp1.SPI_FMT_xSB_MASK -SPI_FMT_LSB = usrp1.SPI_FMT_LSB -SPI_FMT_MSB = usrp1.SPI_FMT_MSB -SPI_FMT_HDR_MASK = usrp1.SPI_FMT_HDR_MASK -SPI_FMT_HDR_0 = usrp1.SPI_FMT_HDR_0 -SPI_FMT_HDR_1 = usrp1.SPI_FMT_HDR_1 -SPI_FMT_HDR_2 = usrp1.SPI_FMT_HDR_2 - -SPI_ENABLE_FPGA = usrp1.SPI_ENABLE_FPGA -SPI_ENABLE_CODEC_A = usrp1.SPI_ENABLE_CODEC_A -SPI_ENABLE_CODEC_B = usrp1.SPI_ENABLE_CODEC_B -SPI_ENABLE_reserved = usrp1.SPI_ENABLE_reserved -SPI_ENABLE_TX_A = usrp1.SPI_ENABLE_TX_A -SPI_ENABLE_RX_A = usrp1.SPI_ENABLE_RX_A -SPI_ENABLE_TX_B = usrp1.SPI_ENABLE_TX_B -SPI_ENABLE_RX_B = usrp1.SPI_ENABLE_RX_B - - -# Import all the daughterboard classes we know about. -# This hooks them into the auto-instantiation framework. - -import db_instantiator - -import db_basic -import db_dbs_rx -import db_flexrf -import db_flexrf_mimo -import db_tv_rx -import db_wbx -import db_xcvr2450 -import db_dtt754 -import db_dtt768 - -def _look_for_usrp(which): - """ - Try to open the specified usrp. - - @param which: int >= 0 specifying which USRP to open - @type which: int - - @return: Returns version number, or raises RuntimeError - @rtype: int - """ - d = usrp_prims.usrp_find_device(which) - if not d: - raise RuntimeError, "Unable to find USRP #%d" % (which,) - - return usrp_prims.usrp_hw_rev(d) - - -def _ensure_rev2(which): - v = _look_for_usrp(which) - if not v in (2, 4): - raise RuntimeError, "Sorry, unsupported USRP revision (rev=%d)" % (v,) - - -class tune_result(object): - """ - Container for intermediate tuning information. - """ - def __init__(self, baseband_freq, dxc_freq, residual_freq, inverted): - self.baseband_freq = baseband_freq - self.dxc_freq = dxc_freq - self.residual_freq = residual_freq - self.inverted = inverted - - -def tune(u, chan, subdev, target_freq): - """ - Set the center frequency we're interested in. - - @param u: instance of usrp.source_* or usrp.sink_* - @param chan: DDC/DUC channel - @type chan: int - @param subdev: daughterboard subdevice - @param target_freq: frequency in Hz - @returns False if failure else tune_result - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - - # Does this usrp instance do Tx or Rx? - rx_p = True - try: - u.rx_freq - except AttributeError: - rx_p = False - - ok, baseband_freq = subdev.set_freq(target_freq) - dxc_freq, inverted = calc_dxc_freq(target_freq, baseband_freq, u.converter_rate()) - - # If the spectrum is inverted, and the daughterboard doesn't do - # quadrature downconversion, we can fix the inversion by flipping the - # sign of the dxc_freq... (This only happens using the basic_rx board) - - if subdev.spectrum_inverted(): - inverted = not(inverted) - - if inverted and not(subdev.is_quadrature()): - dxc_freq = -dxc_freq - inverted = not(inverted) - - if rx_p: - ok = ok and u.set_rx_freq(chan, dxc_freq) - else: - dxc_freq = -dxc_freq - ok = ok and u.set_tx_freq(chan, dxc_freq) - - if not(ok): - return False - - # residual_freq is the offset left over because of dxc tuning step size - if rx_p: - residual_freq = dxc_freq - u.rx_freq(chan) - else: - residual_freq = dxc_freq - u.tx_freq(chan) - - return tune_result(baseband_freq, dxc_freq, residual_freq, inverted) - - -# ------------------------------------------------------------------------ -# Build subclasses of raw usrp1.* class that add the db attribute -# by automatically instantiating the appropriate daughterboard classes. -# [Also provides keyword args.] -# ------------------------------------------------------------------------ - -class usrp_common(object): - def __init__(self): - # read capability register - r = self._u._read_fpga_reg(FR_RB_CAPS) - if r < 0: - r += 2**32 - if r == 0xaa55ff77: # value of this reg prior to being defined as cap reg - r = ((2 << bmFR_RB_CAPS_NDUC_SHIFT) - | (2 << bmFR_RB_CAPS_NDDC_SHIFT) - | bmFR_RB_CAPS_RX_HAS_HALFBAND) - self._fpga_caps = r - - if False: - print "FR_RB_CAPS = %#08x" % (self._fpga_caps,) - print "has_rx_halfband =", self.has_rx_halfband() - print "nDDCs =", self.nddc() - print "has_tx_halfband =", self.has_tx_halfband() - print "nDUCs =", self.nduc() - - def __getattr__(self, name): - return getattr(self._u, name) - - def tune(self, chan, subdev, target_freq): - return tune(self, chan, subdev, target_freq) - - def has_rx_halfband(self): - return self._fpga_caps & bmFR_RB_CAPS_RX_HAS_HALFBAND != 0 - - def has_tx_halfband(self): - return self._fpga_caps & bmFR_RB_CAPS_TX_HAS_HALFBAND != 0 - - def nddc(self): - """ - Number of Digital Down Converters implemented in FPGA - """ - return (self._fpga_caps & bmFR_RB_CAPS_NDDC_MASK) >> bmFR_RB_CAPS_NDDC_SHIFT - - def nduc(self): - """ - Number of Digital Up Converters implemented in FPGA - """ - return (self._fpga_caps & bmFR_RB_CAPS_NDUC_MASK) >> bmFR_RB_CAPS_NDUC_SHIFT - - -class sink_c(usrp_common): - def __init__(self, which=0, interp_rate=128, nchan=1, mux=0x98, - fusb_block_size=0, fusb_nblocks=0, - fpga_filename="", firmware_filename=""): - _ensure_rev2(which) - self._u = usrp1.sink_c(which, interp_rate, nchan, mux, - fusb_block_size, fusb_nblocks, - fpga_filename, firmware_filename) - # Add the db attribute, which contains a 2-tuple of tuples of daughterboard classes - self.db = (db_instantiator.instantiate(self._u, 0), - db_instantiator.instantiate(self._u, 1)) - usrp_common.__init__(self) - - def __del__(self): - self.db = None # will fire d'board destructors - self._u = None # will fire usrp1.* destructor - - -class sink_s(usrp_common): - def __init__(self, which=0, interp_rate=128, nchan=1, mux=0x98, - fusb_block_size=0, fusb_nblocks=0, - fpga_filename="", firmware_filename=""): - _ensure_rev2(which) - self._u = usrp1.sink_s(which, interp_rate, nchan, mux, - fusb_block_size, fusb_nblocks, - fpga_filename, firmware_filename) - # Add the db attribute, which contains a 2-tuple of tuples of daughterboard classes - self.db = (db_instantiator.instantiate(self._u, 0), - db_instantiator.instantiate(self._u, 1)) - usrp_common.__init__(self) - - def __del__(self): - self.db = None # will fire d'board destructors - self._u = None # will fire usrp1.* destructor - - -class source_c(usrp_common): - def __init__(self, which=0, decim_rate=64, nchan=1, mux=0x32103210, mode=0, - fusb_block_size=0, fusb_nblocks=0, - fpga_filename="", firmware_filename=""): - _ensure_rev2(which) - self._u = usrp1.source_c(which, decim_rate, nchan, mux, mode, - fusb_block_size, fusb_nblocks, - fpga_filename, firmware_filename) - # Add the db attribute, which contains a 2-tuple of tuples of daughterboard classes - self.db = (db_instantiator.instantiate(self._u, 0), - db_instantiator.instantiate(self._u, 1)) - usrp_common.__init__(self) - - def __del__(self): - self.db = None # will fire d'board destructors - self._u = None # will fire usrp1.* destructor - - -class source_s(usrp_common): - def __init__(self, which=0, decim_rate=64, nchan=1, mux=0x32103210, mode=0, - fusb_block_size=0, fusb_nblocks=0, - fpga_filename="", firmware_filename=""): - _ensure_rev2(which) - self._u = usrp1.source_s(which, decim_rate, nchan, mux, mode, - fusb_block_size, fusb_nblocks, - fpga_filename, firmware_filename) - # Add the db attribute, which contains a 2-tuple of tuples of daughterboard classes - self.db = (db_instantiator.instantiate(self._u, 0), - db_instantiator.instantiate(self._u, 1)) - usrp_common.__init__(self) - - def __del__(self): - self.db = None # will fire d'board destructors - self._u = None # will fire usrp1.* destructor - - -# ------------------------------------------------------------------------ -# utilities -# ------------------------------------------------------------------------ - -def determine_rx_mux_value(u, subdev_spec): - """ - Determine appropriate Rx mux value as a function of the subdevice choosen and the - characteristics of the respective daughterboard. - - @param u: instance of USRP source - @param subdev_spec: return value from subdev option parser. - @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 or 1 - @returns: the Rx mux value - """ - # Figure out which A/D's to connect to the DDC. - # - # Each daughterboard consists of 1 or 2 subdevices. (At this time, - # all but the Basic Rx have a single subdevice. The Basic Rx - # has two independent channels, treated as separate subdevices). - # subdevice 0 of a daughterboard may use 1 or 2 A/D's. We determine this - # by checking the is_quadrature() method. If subdevice 0 uses only a single - # A/D, it's possible that the daughterboard has a second subdevice, subdevice 1, - # and it uses the second A/D. - # - # If the card uses only a single A/D, we wire a zero into the DDC Q input. - # - # (side, 0) says connect only the A/D's used by subdevice 0 to the DDC. - # (side, 1) says connect only the A/D's used by subdevice 1 to the DDC. - # - - side = subdev_spec[0] # side A = 0, side B = 1 - - if not(side in (0, 1)): - raise ValueError, "Invalid subdev_spec: %r:" % (subdev_spec,) - - db = u.db[side] # This is a tuple of length 1 or 2 containing the subdevice - # classes for the selected side. - - # compute bitmasks of used A/D's - - if db[0].is_quadrature(): - subdev0_uses = 0x3 # uses A/D 0 and 1 - else: - subdev0_uses = 0x1 # uses A/D 0 only - - if len(db) > 1: - subdev1_uses = 0x2 # uses A/D 1 only - else: - subdev1_uses = 0x0 # uses no A/D (doesn't exist) - - if subdev_spec[1] == 0: - uses = subdev0_uses - elif subdev_spec[1] == 1: - uses = subdev1_uses - else: - raise ValueError, "Invalid subdev_spec: %r: " % (subdev_spec,) - - if uses == 0: - raise RuntimeError, "Daughterboard doesn't have a subdevice 1: %r: " % (subdev_spec,) - - swap_iq = db[0].i_and_q_swapped() - - truth_table = { - # (side, uses, swap_iq) : mux_val - (0, 0x1, False) : 0xf0f0f0f0, - (0, 0x2, False) : 0xf0f0f0f1, - (0, 0x3, False) : 0x00000010, - (0, 0x3, True) : 0x00000001, - (1, 0x1, False) : 0xf0f0f0f2, - (1, 0x2, False) : 0xf0f0f0f3, - (1, 0x3, False) : 0x00000032, - (1, 0x3, True) : 0x00000023 - } - - return gru.hexint(truth_table[(side, uses, swap_iq)]) - - -def determine_tx_mux_value(u, subdev_spec): - """ - Determine appropriate Tx mux value as a function of the subdevice choosen. - - @param u: instance of USRP source - @param subdev_spec: return value from subdev option parser. - @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 - @returns: the Rx mux value - """ - # This is simpler than the rx case. Either you want to talk - # to side A or side B. If you want to talk to both sides at once, - # determine the value manually. - - side = subdev_spec[0] # side A = 0, side B = 1 - if not(side in (0, 1)): - raise ValueError, "Invalid subdev_spec: %r:" % (subdev_spec,) - - db = u.db[side] - - if(db[0].i_and_q_swapped()): - return gru.hexint([0x0089, 0x8900][side]) - else: - return gru.hexint([0x0098, 0x9800][side]) - - -def selected_subdev(u, subdev_spec): - """ - Return the user specified daughterboard subdevice. - - @param u: an instance of usrp.source_* or usrp.sink_* - @param subdev_spec: return value from subdev option parser. - @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 or 1 - @returns: an weakref to an instance derived from db_base - """ - side, subdev = subdev_spec - # Note: This allows db to go out of scope at the right time - return weakref.proxy(u.db[side][subdev]) - - -def calc_dxc_freq(target_freq, baseband_freq, fs): - """ - Calculate the frequency to use for setting the digital up or down converter. - - @param target_freq: desired RF frequency (Hz) - @type target_freq: number - @param baseband_freq: the RF frequency that corresponds to DC in the IF. - @type baseband_freq: number - @param fs: converter sample rate - @type fs: number - - @returns: 2-tuple (ddc_freq, inverted) where ddc_freq is the value - for the ddc and inverted is True if we're operating in an inverted - Nyquist zone. - """ - - delta = target_freq - baseband_freq - - if delta >= 0: - while delta > fs: - delta -= fs - if delta <= fs/2: - return (-delta, False) # non-inverted region - else: - return (delta - fs, True) # inverted region - else: - while delta < -fs: - delta += fs - if delta >= -fs/2: - return (-delta, False) # non-inverted region - else: - return (delta + fs, True) # inverted region - - -# ------------------------------------------------------------------------ -# Utilities -# ------------------------------------------------------------------------ - -def pick_tx_subdevice(u): - """ - The user didn't specify a tx subdevice on the command line. - Try for one of these, in order: FLEX_400, FLEX_900, FLEX_1200, FLEX_2400, - BASIC_TX, whatever's on side A. - - @return a subdev_spec - """ - return pick_subdev(u, (usrp_dbid.FLEX_400_TX, - usrp_dbid.FLEX_900_TX, - usrp_dbid.FLEX_1200_TX, - usrp_dbid.FLEX_2400_TX, - usrp_dbid.BASIC_TX)) - -def pick_rx_subdevice(u): - """ - The user didn't specify an rx subdevice on the command line. - Try for one of these, in order: FLEX_400, FLEX_900, FLEX_1200, FLEX_2400, - TV_RX, DBS_RX, BASIC_RX, whatever's on side A. - - @return a subdev_spec - """ - return pick_subdev(u, (usrp_dbid.FLEX_400_RX, - usrp_dbid.FLEX_900_RX, - usrp_dbid.FLEX_1200_RX, - usrp_dbid.FLEX_2400_RX, - usrp_dbid.TV_RX, - usrp_dbid.TV_RX_REV_2, - usrp_dbid.DBS_RX, - usrp_dbid.DBS_RX_REV_2_1, - usrp_dbid.BASIC_RX)) - -def pick_subdev(u, candidates): - """ - @param u: usrp instance - @param candidates: list of dbids - @returns: subdev specification - """ - db0 = u.db[0][0].dbid() - db1 = u.db[1][0].dbid() - for c in candidates: - if c == db0: return (0, 0) - if c == db1: return (1, 0) - if db0 >= 0: - return (0, 0) - if db1 >= 0: - return (1, 0) - raise RuntimeError, "No suitable daughterboard found!" - diff --git a/gr-usrp/src/usrp1.i b/gr-usrp/src/usrp1.i deleted file mode 100644 index 24d229f5..00000000 --- a/gr-usrp/src/usrp1.i +++ /dev/null @@ -1,657 +0,0 @@ -/* -*- c++ -*- */ -/* - * 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 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. - */ - -%feature("autodoc", "1"); // generate python docstrings - -%include "exception.i" -%import "gnuradio.i" // the common stuff - -%{ - -#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix -#include "usrp1_sink_c.h" -#include "usrp1_sink_s.h" -#include "usrp1_source_c.h" -#include "usrp1_source_s.h" -#include -#include -#include -%} - -%include - -%constant int FPGA_MODE_NORMAL = usrp_standard_rx::FPGA_MODE_NORMAL; -%constant int FPGA_MODE_LOOPBACK = usrp_standard_rx::FPGA_MODE_LOOPBACK; -%constant int FPGA_MODE_COUNTING = usrp_standard_rx::FPGA_MODE_COUNTING; - -// ================================================================ -// abstract classes -// ================================================================ - -class usrp1_sink_base : public gr_sync_block { -protected: - usrp1_sink_base (const std::string &name, - gr_io_signature_sptr input_signature, - int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - virtual void copy_to_usrp_buffer (gr_vector_const_void_star &input_items, - int input_index, - int input_items_available, - int &input_items_consumed, - void *usrp_buffer, - int usrp_buffer_length, - int &bytes_written) = 0; - public: - ~usrp1_sink_base (); - - /*! - * \brief Set interpolator rate. \p rate must be in [4, 1024] and a multiple of 4. - * - * The final complex sample rate across the USB is - * dac_freq () * nchannels () / interp_rate () - */ - bool set_interp_rate (unsigned int rate); - bool set_nchannels (int nchan); - bool set_mux (int mux); - - /*! - * \brief set the frequency of the digital up converter. - * - * \p channel must be 0 or 1. \p freq is the center frequency in Hz. - * It must be in the range [-44M, 44M]. The frequency specified is - * quantized. Use tx_freq to retrieve the actual value used. - */ - bool set_tx_freq (int channel, double freq); - - void set_verbose (bool verbose); - - // ACCESSORS - - long fpga_master_clock_freq() const; - long converter_rate() const; // D/A sample rate - long dac_rate() const; // alias - long dac_freq () const; // deprecated name. Use converter_rate() or dac_rate(). - - unsigned int interp_rate () const; - double tx_freq (int channel) const; - int nunderruns () const { return d_nunderruns; } - - /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which which D/A [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * Note that DAC 0 and DAC 1 share a gain setting as do DAC 2 and DAC 3. - * Setting DAC 0 affects DAC 1 and vice versa. Same with DAC 2 and DAC 3. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - bool set_pga (int which, double gain_in_db); - - /*! - * \brief Return programmable gain amplifier gain in dB. - * - * \param which which D/A [0,3] - */ - double pga (int which) const; - - /*! - * \brief Return minimum legal PGA gain in dB. - */ - double pga_min () const; - - /*! - * \brief Return maximum legal PGA gain in dB. - */ - double pga_max () const; - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - double pga_db_per_step () const; - - /*! - * \brief Return daughterboard ID for given Tx daughterboard slot [0,1]. - * - * \return daughterboard id >= 0 if successful - * \return -1 if no daugherboard - * \return -2 if invalid EEPROM on daughterboard - */ - int daughterboard_id (int which_dboard) const; - - /*! - * \brief Set ADC offset correction - * \param which which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q... - * \param offset 16-bit value to subtract from raw ADC input. - */ - bool set_adc_offset (int which, int offset); - - /*! - * \brief Set DAC offset correction - * \param which which DAC[0,3]: 0 = TX_A I, 1 = TX_A Q... - * \param offset 10-bit offset value (ambiguous format: See AD9862 datasheet). - * \param offset_pin 1-bit value. If 0 offset applied to -ve differential pin; - * If 1 offset applied to +ve differential pin. - */ - bool set_dac_offset (int which, int offset, int offset_pin); - - /*! - * \brief Control ADC input buffer - * \param which which ADC[0,3] - * \param bypass if non-zero, bypass input buffer and connect input - * directly to switched cap SHA input of RxPGA. - */ - bool set_adc_buffer_bypass (int which, bool bypass); - - /*! - * \brief return the usrp's serial number. - * - * \returns non-zero length string iff successful. - */ - std::string serial_number(); - - /*! - * \brief Write direction register (output enables) for pins that go to daughterboard. - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - bool _write_oe (int which_dboard, int value, int mask); - - /*! - * \brief Write daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - bool write_io (int which_dboard, int value, int mask); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - int read_io (int which_dboard); - - bool write_aux_dac (int which_dboard, int which_dac, int value); - int read_aux_adc (int which_dboard, int which_adc); - bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf); - std::string read_eeprom (int i2c_addr, int eeprom_offset, int len); - bool write_i2c (int i2c_addr, const std::string buf); - std::string read_i2c (int i2c_addr, int len); - - bool _write_fpga_reg (int regno, int value); //< 7-bit regno, 32-bit value - int _read_fpga_reg (int regno); - bool _write_9862 (int which_codec, int regno, unsigned char value); - int _read_9862 (int which_codec, int regno) const; - - /*! - * \brief Write data to SPI bus peripheral. - * - * \param optional_header 0,1 or 2 bytes to write before buf. - * \param enables bitmask of peripherals to write. See usrp_spi_defs.h - * \param format transaction format. See usrp_spi_defs.h SPI_FMT_* - * \param buf the data to write - * \returns true iff successful - * Writes are limited to a maximum of 64 bytes. - * - * If \p format specifies that optional_header bytes are present, they are - * written to the peripheral immediately prior to writing \p buf. - */ - bool _write_spi (int optional_header, int enables, int format, std::string buf); - - /* - * \brief Read data from SPI bus peripheral. - * - * \param optional_header 0,1 or 2 bytes to write before buf. - * \param enables bitmask of peripheral to read. See usrp_spi_defs.h - * \param format transaction format. See usrp_spi_defs.h SPI_FMT_* - * \param len number of bytes to read. Must be in [0,64]. - * \returns the data read if sucessful, else a zero length string. - * - * Reads are limited to a maximum of 64 bytes. - * - * If \p format specifies that optional_header bytes are present, they - * are written to the peripheral first. Then \p len bytes are read from - * the peripheral and returned. - */ - std::string _read_spi (int optional_header, int enables, int format, int len); -}; - -// ---------------------------------------------------------------- - -class usrp1_source_base : public gr_sync_block { - protected: - - usrp1_source_base (const std::string &name, - gr_io_signature_sptr input_signature, - int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - virtual int ninput_bytes_reqd_for_noutput_items (int noutput_items) = 0; - - virtual void copy_from_usrp_buffer (gr_vector_void_star &output_items, - int output_index, - int output_items_available, - int &output_items_produced, - const void *usrp_buffer, - int usrp_buffer_length, - int &bytes_read) = 0; - public: - ~usrp1_source_base (); - - - /*! - * \brief Set decimator rate. \p rate must be EVEN and in [8, 256]. - * - * The final complex sample rate across the USB is - * adc_freq () / decim_rate () - */ - bool set_decim_rate (unsigned int rate); - bool set_nchannels (int nchan); - bool set_mux (int mux); - - /*! - * \brief set the center frequency of the digital down converter. - * - * \p channel must be 0. \p freq is the center frequency in Hz. - * It must be in the range [-FIXME, FIXME]. The frequency specified is - * quantized. Use rx_freq to retrieve the actual value used. - */ - bool set_rx_freq (int channel, double freq); - - /*! - * \brief set fpga special modes - */ - bool set_fpga_mode (int mode); - - /*! - * \brief Set the digital down converter phase register. - * - * \param channel which ddc channel [0, 3] - * \param phase 32-bit integer phase value. - */ - bool set_ddc_phase(int channel, int phase); - - - void set_verbose (bool verbose); - - // ACCESSORS - - long fpga_master_clock_freq() const; - long converter_rate() const; // A/D sample rate - long adc_rate() const; // alias - long adc_freq() const; // Deprecated name. Use converter_rate() or adc_rate(). - - unsigned int decim_rate () const; - double rx_freq (int channel) const; - int noverruns () const { return d_noverruns; } - - - // PGA stuff - /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which which A/D [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - bool set_pga (int which, double gain_in_db); - - /*! - * \brief Return programmable gain amplifier gain setting in dB. - * - * \param which which A/D [0,3] - */ - double pga (int which) const; - - /*! - * \brief Return minimum legal PGA setting in dB. - */ - double pga_min () const; - - /*! - * \brief Return maximum legal PGA setting in dB. - */ - double pga_max () const; - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - double pga_db_per_step () const; - - /*! - * \brief Return daughterboard ID for given Rx daughterboard slot [0,1]. - * - * \return daughterboard id >= 0 if successful - * \return -1 if no daugherboard - * \return -2 if invalid EEPROM on daughterboard - */ - int daughterboard_id (int which_dboard) const; - - /*! - * \brief Set ADC offset correction - * \param which which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q... - * \param offset 16-bit value to subtract from raw ADC input. - */ - bool set_adc_offset (int which, int offset); - - /*! - * \brief Set DAC offset correction - * \param which which DAC[0,3]: 0 = TX_A I, 1 = TX_A Q... - * \param offset 10-bit offset value (ambiguous format: See AD9862 datasheet). - * \param offset_pin 1-bit value. If 0 offset applied to -ve differential pin; - * If 1 offset applied to +ve differential pin. - */ - bool set_dac_offset (int which, int offset, int offset_pin); - - /*! - * \brief Control ADC input buffer - * \param which which ADC[0,3] - * \param bypass if non-zero, bypass input buffer and connect input - * directly to switched cap SHA input of RxPGA. - */ - bool set_adc_buffer_bypass (int which, bool bypass); - - /*! - * \brief return the usrp's serial number. - * - * \returns non-zero length string iff successful. - */ - std::string serial_number(); - - /*! - * \brief Write direction register (output enables) for pins that go to daughterboard. - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - bool _write_oe (int which_dboard, int value, int mask); - - /*! - * \brief Write daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - bool write_io (int which_dboard, int value, int mask); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - int read_io (int which_dboard); - - /*! - * \brief Enable/disable automatic DC offset removal control loop in FPGA - * - * \param bits which control loops to enable - * \param mask which \p bits to pay attention to - * - * If the corresponding bit is set, enable the automatic DC - * offset correction control loop. - * - *
-   * The 4 low bits are significant:
-   *
-   *   ADC0 = (1 << 0)
-   *   ADC1 = (1 << 1)
-   *   ADC2 = (1 << 2)
-   *   ADC3 = (1 << 3)
-   * 
- * - * By default the control loop is enabled on all ADC's. - */ - bool set_dc_offset_cl_enable(int bits, int mask); - - /*! - * \brief Specify Rx data format. - * - * \param format format specifier - * - * Rx data format control register - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------------------------+-+-+---------+-------+ - * | Reserved (Must be zero) |B|Q| WIDTH | SHIFT | - * +-----------------------------------------+-+-+---------+-------+ - * - * SHIFT specifies arithmetic right shift [0, 15] - * WIDTH specifies bit-width of I & Q samples across the USB [1, 16] (not all valid) - * Q if set deliver both I & Q, else just I - * B if set bypass half-band filter. - * - * Right now the acceptable values are: - * - * B Q WIDTH SHIFT - * 0 1 16 0 - * 0 1 8 8 - * - * More valid combos to come. - * - * Default value is 0x00000300 16-bits, 0 shift, deliver both I & Q. - */ - bool set_format(unsigned int format); - - /*! - * \brief return current format - */ - unsigned int format () const; - - static unsigned int make_format(int width=16, int shift=0, - bool want_q=true, bool bypass_halfband=false); - static int format_width(unsigned int format); - static int format_shift(unsigned int format); - static bool format_want_q(unsigned int format); - static bool format_bypass_halfband(unsigned int format); - - - - - bool write_aux_dac (int which_dboard, int which_dac, int value); - int read_aux_adc (int which_dboard, int which_adc); - bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf); - std::string read_eeprom (int i2c_addr, int eeprom_offset, int len); - bool write_i2c (int i2c_addr, const std::string buf); - std::string read_i2c (int i2c_addr, int len); - bool _write_fpga_reg (int regno, int value); //< 7-bit regno, 32-bit value - bool _write_fpga_reg_masked (int regno, int value, int mask); //< 7-bit regno, 16-bit value, 16-bit mask - int _read_fpga_reg (int regno); - bool _write_9862 (int which_codec, int regno, unsigned char value); - int _read_9862 (int which_codec, int regno) const; - - bool _write_spi (int optional_header, int enables, int format, std::string buf); - - /* - * \brief Read data from SPI bus peripheral. - * - * \param optional_header 0,1 or 2 bytes to write before buf. - * \param enables bitmask of peripheral to read. See usrp_spi_defs.h - * \param format transaction format. See usrp_spi_defs.h SPI_FMT_* - * \param len number of bytes to read. Must be in [0,64]. - * \returns the data read if sucessful, else a zero length string. - * - * Reads are limited to a maximum of 64 bytes. - * - * If \p format specifies that optional_header bytes are present, they - * are written to the peripheral first. Then \p len bytes are read from - * the peripheral and returned. - */ - std::string _read_spi (int optional_header, int enables, int format, int len); -}; - - -// ================================================================ -// concrete sinks -// ================================================================ - - -GR_SWIG_BLOCK_MAGIC(usrp1,sink_c) - -usrp1_sink_c_sptr -usrp1_make_sink_c (int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - -class usrp1_sink_c : public usrp1_sink_base { - protected: - usrp1_sink_c (int which_board, unsigned int interp_rate, - int nchan, int mux); - - public: - ~usrp1_sink_c (); -}; - -// ---------------------------------------------------------------- - -GR_SWIG_BLOCK_MAGIC(usrp1,sink_s) - -usrp1_sink_s_sptr -usrp1_make_sink_s (int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - -class usrp1_sink_s : public usrp1_sink_base { - protected: - usrp1_sink_s (int which_board, unsigned int interp_rate, - int nchan, int mux); - - public: - ~usrp1_sink_s (); -}; - -// ================================================================ -// concrete sources -// ================================================================ - -GR_SWIG_BLOCK_MAGIC(usrp1,source_c) - - -usrp1_source_c_sptr -usrp1_make_source_c (int which_board, - unsigned int decim_rate, - int nchan, - int mux, - int mode, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - -class usrp1_source_c : public usrp1_source_base { - protected: - usrp1_source_c (int which_board, unsigned int decim_rate, - int nchan, int mux, int mode); - - public: - ~usrp1_source_c (); -}; - -// ---------------------------------------------------------------- - -GR_SWIG_BLOCK_MAGIC(usrp1,source_s) - -usrp1_source_s_sptr -usrp1_make_source_s (int which_board, - unsigned int decim_rate, - int nchan, - int mux, - int mode, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - -class usrp1_source_s : public usrp1_source_base { - protected: - usrp1_source_s (int which_board, unsigned int decim_rate, - int nchan, int mux, int mode); - - public: - ~usrp1_source_s (); -}; - diff --git a/gr-usrp/src/usrp1_sink_base.cc b/gr-usrp/src/usrp1_sink_base.cc deleted file mode 100644 index 331be5f8..00000000 --- a/gr-usrp/src/usrp1_sink_base.cc +++ /dev/null @@ -1,359 +0,0 @@ -/* -*- c++ -*- */ -/* - * 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 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -static const int OUTPUT_MULTIPLE_SAMPLES = 128; // DON'T CHANGE THIS VALUE! - -usrp1_sink_base::usrp1_sink_base (const std::string &name, - gr_io_signature_sptr input_signature, - int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error) - : gr_sync_block (name, - input_signature, - gr_make_io_signature (0, 0, 0)), - d_nunderruns (0) -{ - d_usrp = usrp_standard_tx::make (which_board, - interp_rate, - nchan, mux, - fusb_block_size, - fusb_nblocks, - fpga_filename, - firmware_filename - ); - if (d_usrp == 0) - throw std::runtime_error ("can't open usrp1"); - - // All calls to d_usrp->write must be multiples of 512 bytes. - - set_output_multiple (OUTPUT_MULTIPLE_SAMPLES); -} - -usrp1_sink_base::~usrp1_sink_base () -{ - delete d_usrp; -} - -bool -usrp1_sink_base::start() -{ - return d_usrp->start(); -} - -bool -usrp1_sink_base::stop() -{ - return d_usrp->stop(); -} - -int -usrp1_sink_base::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - static const int BUFSIZE = 16 * (1L << 10); // 16kB - unsigned char outbuf[BUFSIZE]; - int obi = 0; - int input_index = 0; - int input_items_consumed; - int bytes_written; - bool underrun; - - - while (input_index < noutput_items){ - - copy_to_usrp_buffer (input_items, - input_index, - noutput_items - input_index, // input_items_available - input_items_consumed, // [out] - &outbuf[obi], // [out] usrp_buffer - BUFSIZE - obi, // usrp_buffer_length - bytes_written); // [out] - - assert (input_index + input_items_consumed <= noutput_items); - assert (obi + bytes_written <= BUFSIZE); - - input_index += input_items_consumed; - obi += bytes_written; - - if (obi >= BUFSIZE){ // flush - if (d_usrp->write (outbuf, obi, &underrun) != obi) - return -1; // indicate we're done - - if (underrun){ - d_nunderruns++; - // fprintf (stderr, "usrp1_sink: underrun\n"); - fputs ("uU", stderr); - } - obi = 0; - } - } - - if (obi != 0){ - assert (obi % 512 == 0); - if (d_usrp->write (outbuf, obi, &underrun) != obi) - return -1; // indicate we're done - - if (underrun){ - d_nunderruns++; - // fprintf (stderr, "usrp1_sink: underrun\n"); - fputs ("uU", stderr); - } - } - - return noutput_items; -} - -bool -usrp1_sink_base::set_interp_rate (unsigned int rate) -{ - return d_usrp->set_interp_rate (rate); -} - -bool -usrp1_sink_base::set_nchannels (int nchan) -{ - return d_usrp->set_nchannels (nchan); -} - -bool -usrp1_sink_base::set_mux (int mux) -{ - return d_usrp->set_mux (mux); -} - -bool -usrp1_sink_base::set_tx_freq (int channel, double freq) -{ - return d_usrp->set_tx_freq (channel, freq); -} - -long -usrp1_sink_base::fpga_master_clock_freq() const -{ - return d_usrp->fpga_master_clock_freq(); -} - -long -usrp1_sink_base::converter_rate () const -{ - return d_usrp->converter_rate (); -} - -unsigned int -usrp1_sink_base::interp_rate () const -{ - return d_usrp->interp_rate (); -} - -int -usrp1_sink_base::nchannels () const -{ - return d_usrp->nchannels (); -} - -int -usrp1_sink_base::mux () const -{ - return d_usrp->mux (); -} - - -double -usrp1_sink_base::tx_freq (int channel) const -{ - return d_usrp->tx_freq (channel); -} - -void -usrp1_sink_base::set_verbose (bool verbose) -{ - d_usrp->set_verbose (verbose); -} - -bool -usrp1_sink_base::write_aux_dac (int which_dboard, int which_dac, int value) -{ - return d_usrp->write_aux_dac (which_dboard, which_dac, value); -} - -int -usrp1_sink_base::read_aux_adc (int which_dboard, int which_adc) -{ - return d_usrp->read_aux_adc (which_dboard, which_adc); -} - -bool -usrp1_sink_base::write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf) -{ - return d_usrp->write_eeprom (i2c_addr, eeprom_offset, buf); -} - -std::string -usrp1_sink_base::read_eeprom (int i2c_addr, int eeprom_offset, int len) -{ - return d_usrp->read_eeprom (i2c_addr, eeprom_offset, len); -} - -bool -usrp1_sink_base::write_i2c (int i2c_addr, const std::string buf) -{ - return d_usrp->write_i2c (i2c_addr, buf); -} - -std::string -usrp1_sink_base::read_i2c (int i2c_addr, int len) -{ - return d_usrp->read_i2c (i2c_addr, len); -} - -bool -usrp1_sink_base::set_pga (int which, double gain) -{ - return d_usrp->set_pga (which, gain); -} - -double -usrp1_sink_base::pga (int which) const -{ - return d_usrp->pga (which); -} - -double -usrp1_sink_base::pga_min () const -{ - return d_usrp->pga_min (); -} - -double -usrp1_sink_base::pga_max () const -{ - return d_usrp->pga_max (); -} - -double -usrp1_sink_base::pga_db_per_step () const -{ - return d_usrp->pga_db_per_step (); -} - -int -usrp1_sink_base::daughterboard_id (int which) const -{ - return d_usrp->daughterboard_id (which); -} - -bool -usrp1_sink_base::set_adc_offset (int which, int offset) -{ - return d_usrp->set_adc_offset (which, offset); -} - -bool -usrp1_sink_base::set_dac_offset (int which, int offset, int offset_pin) -{ - return d_usrp->set_dac_offset (which, offset, offset_pin); -} - -bool -usrp1_sink_base::set_adc_buffer_bypass (int which, bool bypass) -{ - return d_usrp->set_adc_buffer_bypass (which, bypass); -} - -std::string -usrp1_sink_base::serial_number() -{ - return d_usrp->serial_number(); -} - -bool -usrp1_sink_base::_write_oe (int which_dboard, int value, int mask) -{ - return d_usrp->_write_oe (which_dboard, value, mask); -} - -bool -usrp1_sink_base::write_io (int which_dboard, int value, int mask) -{ - return d_usrp->write_io (which_dboard, value, mask); -} - -int -usrp1_sink_base::read_io (int which_dboard) -{ - return d_usrp->read_io (which_dboard); -} - -// internal routines... - -bool -usrp1_sink_base::_write_fpga_reg (int regno, int value) -{ - return d_usrp->_write_fpga_reg (regno, value); -} - -int -usrp1_sink_base::_read_fpga_reg (int regno) -{ - return d_usrp->_read_fpga_reg (regno); -} - -bool -usrp1_sink_base::_write_9862 (int which_codec, int regno, unsigned char value) -{ - return d_usrp->_write_9862 (which_codec, regno, value); -} - -int -usrp1_sink_base::_read_9862 (int which_codec, int regno) const -{ - return d_usrp->_read_9862 (which_codec, regno); -} - -bool -usrp1_sink_base::_write_spi (int optional_header, int enables, - int format, std::string buf) -{ - return d_usrp->_write_spi (optional_header, enables, format, buf); -} - -std::string -usrp1_sink_base::_read_spi (int optional_header, int enables, int format, int len) -{ - return d_usrp->_read_spi (optional_header, enables, format, len); -} diff --git a/gr-usrp/src/usrp1_sink_base.h b/gr-usrp/src/usrp1_sink_base.h deleted file mode 100644 index c6284947..00000000 --- a/gr-usrp/src/usrp1_sink_base.h +++ /dev/null @@ -1,359 +0,0 @@ -/* -*- c++ -*- */ -/* - * 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 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. - */ - -#ifndef INCLUDED_USRP1_SINK_BASE_H -#define INCLUDED_USRP1_SINK_BASE_H - -#include -#include - -class usrp_standard_tx; - - -/*! - * \brief abstract interface to Universal Software Radio Peripheral Tx path (Rev 1) - */ -class usrp1_sink_base : public gr_sync_block { - private: - usrp_standard_tx *d_usrp; - int d_nunderruns; - - protected: - usrp1_sink_base (const std::string &name, - gr_io_signature_sptr input_signature, - int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - /*! - * \brief convert between input item format and usrp native format - * - * \param input_items[in] stream(s) of input items - * \param input_index[in] starting index in input_items - * \param input_items_available[in] number of items available starting at item[index] - * \param input_items_consumed[out] number of input items consumed by copy - * \param usrp_buffer[out] destination buffer - * \param usrp_buffer_length[in] \p usrp_buffer length in bytes - * \param bytes_written[out] number of bytes written into \p usrp_buffer - */ - virtual void copy_to_usrp_buffer (gr_vector_const_void_star &input_items, - int input_index, - int input_items_available, - int &input_items_consumed, - void *usrp_buffer, - int usrp_buffer_length, - int &bytes_written) = 0; - - public: - //! magic value used on alternate register read interfaces - static const int READ_FAILED = -99999; - - - ~usrp1_sink_base (); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - bool start(); - bool stop(); - - /*! - * \brief Set interpolator rate. \p rate must be in [4, 1024] and a multiple of 4. - * - * The final complex sample rate across the USB is - * dac_freq () / interp_rate () * nchannels () - */ - bool set_interp_rate (unsigned int rate); - bool set_nchannels (int nchan); - bool set_mux (int mux); - - /*! - * \brief set the frequency of the digital up converter. - * - * \p channel must be 0. \p freq is the center frequency in Hz. - * It must be in the range [-44M, 44M]. The frequency specified is - * quantized. Use tx_freq to retrieve the actual value used. - */ - bool set_tx_freq (int channel, double freq); - - void set_verbose (bool verbose); - - /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which which D/A [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * Note that DAC 0 and DAC 1 share a gain setting as do DAC 2 and DAC 3. - * Setting DAC 0 affects DAC 1 and vice versa. Same with DAC 2 and DAC 3. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - bool set_pga (int which, double gain_in_db); - - /*! - * \brief Return programmable gain amplifier gain in dB. - * - * \param which which D/A [0,3] - */ - double pga (int which) const; - - /*! - * \brief Return minimum legal PGA gain in dB. - */ - double pga_min () const; - - /*! - * \brief Return maximum legal PGA gain in dB. - */ - double pga_max () const; - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - double pga_db_per_step () const; - - - // ACCESSORS - - long fpga_master_clock_freq() const; - long converter_rate() const; - long dac_rate() const { return converter_rate(); } // alias - long dac_freq() const { return converter_rate(); } // deprecated alias - - unsigned int interp_rate () const; - int nchannels () const; - int mux () const; - double tx_freq (int channel) const; - int nunderruns () const { return d_nunderruns; } - - /*! - * \brief Return daughterboard ID for given Rx daughterboard slot [0,1]. - * - * \return daughterboard id >= 0 if successful - * \return -1 if no daugherboard - * \return -2 if invalid EEPROM on daughterboard - */ - int daughterboard_id (int which_dboard) const; - - /*! - * \brief Write auxiliary digital to analog converter. - * - * \param which_dboard [0,1] which d'board - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. - * \param which_dac [2,3] TX slots must use only 2 and 3. - * \param value [0,4095] - * \returns true iff successful - */ - bool write_aux_dac (int which_board, int which_dac, int value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_dboard [0,1] which d'board - * \param which_adc [0,1] - * \returns value in the range [0,4095] if successful, else READ_FAILED. - */ - int read_aux_adc (int which_dboard, int which_adc); - - /*! - * \brief Write EEPROM on motherboard or any daughterboard. - * \param i2c_addr I2C bus address of EEPROM - * \param eeprom_offset byte offset in EEPROM to begin writing - * \param buf the data to write - * \returns true iff sucessful - */ - bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf); - - /*! - * \brief Write EEPROM on motherboard or any daughterboard. - * \param i2c_addr I2C bus address of EEPROM - * \param eeprom_offset byte offset in EEPROM to begin reading - * \param len number of bytes to read - * \returns the data read if successful, else a zero length string. - */ - std::string read_eeprom (int i2c_addr, int eeprom_offset, int len); - - /*! - * \brief Write to I2C peripheral - * \param i2c_addr I2C bus address (7-bits) - * \param buf the data to write - * \returns true iff successful - * Writes are limited to a maximum of of 64 bytes. - */ - bool write_i2c (int i2c_addr, const std::string buf); - - /*! - * \brief Read from I2C peripheral - * \param i2c_addr I2C bus address (7-bits) - * \param len number of bytes to read - * \returns the data read if successful, else a zero length string. - * Reads are limited to a maximum of of 64 bytes. - */ - std::string read_i2c (int i2c_addr, int len); - - /*! - * \brief Set ADC offset correction - * \param which which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q... - * \param offset 16-bit value to subtract from raw ADC input. - */ - bool set_adc_offset (int which, int offset); - - /*! - * \brief Set DAC offset correction - * \param which which DAC[0,3]: 0 = TX_A I, 1 = TX_A Q... - * \param offset 10-bit offset value (ambiguous format: See AD9862 datasheet). - * \param offset_pin 1-bit value. If 0 offset applied to -ve differential pin; - * If 1 offset applied to +ve differential pin. - */ - bool set_dac_offset (int which, int offset, int offset_pin); - - /*! - * \brief Control ADC input buffer - * \param which which ADC[0,3] - * \param bypass if non-zero, bypass input buffer and connect input - * directly to switched cap SHA input of RxPGA. - */ - bool set_adc_buffer_bypass (int which, bool bypass); - - /*! - * \brief return the usrp's serial number. - * - * \returns non-zero length string iff successful. - */ - std::string serial_number(); - - /*! - * \brief Write direction register (output enables) for pins that go to daughterboard. - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - bool _write_oe (int which_dboard, int value, int mask); - - /*! - * \brief Write daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - bool write_io (int which_dboard, int value, int mask); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - int read_io (int which_dboard); - - // - // internal routines... - // You probably shouldn't be using these... - // - /*! - * \brief Write FPGA register. - * \param regno 7-bit register number - * \param value 32-bit value - * \returns true iff successful - */ - bool _write_fpga_reg (int regno, int value); //< 7-bit regno, 32-bit value - - /*! - * \brief Read FPGA register. - * \param regno 7-bit register number - * \returns register value if successful, else READ_FAILED - */ - int _read_fpga_reg (int regno); - - /*! - * \brief Write AD9862 register. - * \param which_codec 0 or 1 - * \param regno 6-bit register number - * \param value 8-bit value - * \returns true iff successful - */ - bool _write_9862 (int which_codec, int regno, unsigned char value); - - /*! - * \brief Read AD9862 register. - * \param which_codec 0 or 1 - * \param regno 6-bit register number - * \returns register value if successful, else READ_FAILED - */ - int _read_9862 (int which_codec, int regno) const; - - /*! - * \brief Write data to SPI bus peripheral. - * - * \param optional_header 0,1 or 2 bytes to write before buf. - * \param enables bitmask of peripherals to write. See usrp_spi_defs.h - * \param format transaction format. See usrp_spi_defs.h SPI_FMT_* - * \param buf the data to write - * \returns true iff successful - * Writes are limited to a maximum of 64 bytes. - * - * If \p format specifies that optional_header bytes are present, they are - * written to the peripheral immediately prior to writing \p buf. - */ - bool _write_spi (int optional_header, int enables, int format, std::string buf); - - /* - * \brief Read data from SPI bus peripheral. - * - * \param optional_header 0,1 or 2 bytes to write before buf. - * \param enables bitmask of peripheral to read. See usrp_spi_defs.h - * \param format transaction format. See usrp_spi_defs.h SPI_FMT_* - * \param len number of bytes to read. Must be in [0,64]. - * \returns the data read if sucessful, else a zero length string. - * - * Reads are limited to a maximum of 64 bytes. - * - * If \p format specifies that optional_header bytes are present, they - * are written to the peripheral first. Then \p len bytes are read from - * the peripheral and returned. - */ - std::string _read_spi (int optional_header, int enables, int format, int len); -}; - -#endif /* INCLUDED_USRP1_SINK_BASE_H */ diff --git a/gr-usrp/src/usrp1_source_base.cc b/gr-usrp/src/usrp1_source_base.cc deleted file mode 100644 index 1aefa8a2..00000000 --- a/gr-usrp/src/usrp1_source_base.cc +++ /dev/null @@ -1,425 +0,0 @@ -/* -*- c++ -*- */ -/* - * 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 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -static const int OUTPUT_MULTIPLE_BYTES = 4 * 1024; - -usrp1_source_base::usrp1_source_base (const std::string &name, - gr_io_signature_sptr output_signature, - int which_board, - unsigned int decim_rate, - int nchan, - int mux, - int mode, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error) - : gr_sync_block (name, - gr_make_io_signature (0, 0, 0), - output_signature), - d_noverruns (0) -{ - d_usrp = usrp_standard_rx::make (which_board, decim_rate, - nchan, mux, mode, - fusb_block_size, - fusb_nblocks, - fpga_filename, - firmware_filename); - if (d_usrp == 0) - throw std::runtime_error ("can't open usrp1"); - - // All calls to d_usrp->read must be multiples of 512 bytes. - // We jack this up to 4k to reduce overhead. - - set_output_multiple (OUTPUT_MULTIPLE_BYTES / output_signature->sizeof_stream_item (0)); -} - -usrp1_source_base::~usrp1_source_base () -{ - delete d_usrp; -} - -unsigned int -usrp1_source_base::sizeof_basic_sample() const -{ - return usrp_standard_rx::format_width(d_usrp->format()) / 8; -} - -bool -usrp1_source_base::start() -{ - return d_usrp->start(); -} - -bool -usrp1_source_base::stop() -{ - return d_usrp->stop(); -} - -int -usrp1_source_base::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - static const int BUFSIZE = 4 * OUTPUT_MULTIPLE_BYTES; - unsigned char buf[BUFSIZE]; - int output_index = 0; - int output_items_produced; - int bytes_read; - bool overrun; - - while (output_index < noutput_items){ - int nbytes = ninput_bytes_reqd_for_noutput_items (noutput_items - output_index); - nbytes = std::min (nbytes, BUFSIZE); - - int result_nbytes = d_usrp->read (buf, nbytes, &overrun); - if (overrun){ - // fprintf (stderr, "usrp1_source: overrun\n"); - fputs ("uO", stderr); - d_noverruns++; - } - - if (result_nbytes < 0) // We've got a problem. Usually board unplugged or powered down. - return -1; // Indicate we're done. - - if (result_nbytes != nbytes){ // not really an error, but unexpected - fprintf (stderr, "usrp1_source: short read. Expected %d, got %d\n", - nbytes, result_nbytes); - } - - copy_from_usrp_buffer (output_items, - output_index, - noutput_items - output_index, // output_items_available - output_items_produced, // [out] - buf, // usrp_buffer - result_nbytes, // usrp_buffer_length - bytes_read); // [out] - - assert (output_index + output_items_produced <= noutput_items); - assert (bytes_read == result_nbytes); - - output_index += output_items_produced; - } - - return noutput_items; -} - - -bool -usrp1_source_base::set_decim_rate (unsigned int rate) -{ - return d_usrp->set_decim_rate (rate); -} - -bool -usrp1_source_base::set_nchannels (int nchan) -{ - return d_usrp->set_nchannels (nchan); -} - -bool -usrp1_source_base::set_mux (int mux) -{ - return d_usrp->set_mux (mux); -} - -bool -usrp1_source_base::set_rx_freq (int channel, double freq) -{ - return d_usrp->set_rx_freq (channel, freq); -} - -long -usrp1_source_base::fpga_master_clock_freq() const -{ - return d_usrp->fpga_master_clock_freq(); -} - -long -usrp1_source_base::converter_rate() const -{ - return d_usrp->converter_rate(); -} - -unsigned int -usrp1_source_base::decim_rate () const -{ - return d_usrp->decim_rate (); -} - -int -usrp1_source_base::nchannels () const -{ - return d_usrp->nchannels (); -} - -int -usrp1_source_base::mux () const -{ - return d_usrp->mux (); -} - -double -usrp1_source_base::rx_freq (int channel) const -{ - return d_usrp->rx_freq (channel); -} - -bool -usrp1_source_base::set_fpga_mode (int mode) -{ - return d_usrp->set_fpga_mode (mode); -} - -bool -usrp1_source_base::set_ddc_phase (int channel, int phase) -{ - return d_usrp->set_ddc_phase(channel, phase); -} - -bool -usrp1_source_base::set_dc_offset_cl_enable(int bits, int mask) -{ - return d_usrp->set_dc_offset_cl_enable(bits, mask); -} - -void -usrp1_source_base::set_verbose (bool verbose) -{ - d_usrp->set_verbose (verbose); -} - -bool -usrp1_source_base::write_aux_dac (int which_dboard, int which_dac, int value) -{ - return d_usrp->write_aux_dac (which_dboard, which_dac, value); -} - -int -usrp1_source_base::read_aux_adc (int which_dboard, int which_adc) -{ - return d_usrp->read_aux_adc (which_dboard, which_adc); -} - -bool -usrp1_source_base::write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf) -{ - return d_usrp->write_eeprom (i2c_addr, eeprom_offset, buf); -} - -std::string -usrp1_source_base::read_eeprom (int i2c_addr, int eeprom_offset, int len) -{ - return d_usrp->read_eeprom (i2c_addr, eeprom_offset, len); -} - -bool -usrp1_source_base::write_i2c (int i2c_addr, const std::string buf) -{ - return d_usrp->write_i2c (i2c_addr, buf); -} - -std::string -usrp1_source_base::read_i2c (int i2c_addr, int len) -{ - return d_usrp->read_i2c (i2c_addr, len); -} - -bool -usrp1_source_base::set_pga (int which, double gain) -{ - return d_usrp->set_pga (which, gain); -} - -double -usrp1_source_base::pga (int which) const -{ - return d_usrp->pga (which); -} - -double -usrp1_source_base::pga_min () const -{ - return d_usrp->pga_min (); -} - -double -usrp1_source_base::pga_max () const -{ - return d_usrp->pga_max (); -} - -double -usrp1_source_base::pga_db_per_step () const -{ - return d_usrp->pga_db_per_step (); -} - -int -usrp1_source_base::daughterboard_id (int which) const -{ - return d_usrp->daughterboard_id (which); -} - - -bool -usrp1_source_base::set_adc_offset (int which, int offset) -{ - return d_usrp->set_adc_offset (which, offset); -} - -bool -usrp1_source_base::set_dac_offset (int which, int offset, int offset_pin) -{ - return d_usrp->set_dac_offset (which, offset, offset_pin); -} - -bool -usrp1_source_base::set_adc_buffer_bypass (int which, bool bypass) -{ - return d_usrp->set_adc_buffer_bypass (which, bypass); -} - -std::string -usrp1_source_base::serial_number() -{ - return d_usrp->serial_number(); -} - -bool -usrp1_source_base::_write_oe (int which_dboard, int value, int mask) -{ - return d_usrp->_write_oe (which_dboard, value, mask); -} - -bool -usrp1_source_base::write_io (int which_dboard, int value, int mask) -{ - return d_usrp->write_io (which_dboard, value, mask); -} - -int -usrp1_source_base::read_io (int which_dboard) -{ - return d_usrp->read_io (which_dboard); -} - - - - -// internal routines... - -bool -usrp1_source_base::_write_fpga_reg (int regno, int value) -{ - return d_usrp->_write_fpga_reg (regno, value); -} - -bool -usrp1_source_base::_write_fpga_reg_masked (int regno, int value, int mask) -{ - return d_usrp->_write_fpga_reg_masked (regno, value, mask); -} - -int -usrp1_source_base::_read_fpga_reg (int regno) -{ - return d_usrp->_read_fpga_reg (regno); -} - -bool -usrp1_source_base::_write_9862 (int which_codec, int regno, unsigned char value) -{ - return d_usrp->_write_9862 (which_codec, regno, value); -} - -int -usrp1_source_base::_read_9862 (int which_codec, int regno) const -{ - return d_usrp->_read_9862 (which_codec, regno); -} - -bool -usrp1_source_base::_write_spi (int optional_header, int enables, - int format, std::string buf) -{ - return d_usrp->_write_spi (optional_header, enables, format, buf); -} - -std::string -usrp1_source_base::_read_spi (int optional_header, int enables, int format, int len) -{ - return d_usrp->_read_spi (optional_header, enables, format, len); -} - -bool -usrp1_source_base::set_format(unsigned int format) -{ - return d_usrp->set_format(format); -} - -unsigned int -usrp1_source_base::format() const -{ - return d_usrp->format(); -} - -unsigned int -usrp1_source_base::make_format(int width, int shift, bool want_q, bool bypass_halfband) -{ - return usrp_standard_rx::make_format(width, shift, want_q, bypass_halfband); -} - -int -usrp1_source_base::format_width(unsigned int format) -{ - return usrp_standard_rx::format_width(format); -} - -int -usrp1_source_base::format_shift(unsigned int format) -{ - return usrp_standard_rx::format_shift(format); -} - -bool -usrp1_source_base::format_want_q(unsigned int format) -{ - return usrp_standard_rx::format_want_q(format); -} - -bool -usrp1_source_base::format_bypass_halfband(unsigned int format) -{ - return usrp_standard_rx::format_bypass_halfband(format); -} diff --git a/gr-usrp/src/usrp_base.cc b/gr-usrp/src/usrp_base.cc new file mode 100644 index 00000000..1709c7a4 --- /dev/null +++ b/gr-usrp/src/usrp_base.cc @@ -0,0 +1,316 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +class truth_table_element_t +{ +public: + truth_table_element_t(int side, unsigned int uses, bool swap_iq, unsigned int mux_val); + bool operator==(const truth_table_element_t &in); + bool operator!=(const truth_table_element_t &in); + + unsigned int mux_val() { return d_mux_val; } + +private: + int d_side; + unsigned int d_uses; + bool d_swap_iq; + unsigned int d_mux_val; +}; + + +usrp_base::~usrp_base() +{ +} + +void +usrp_base::set_usrp_basic(boost::shared_ptr u) +{ + d_usrp_basic = u; +} + +std::vector > +usrp_base::db() +{ + return d_usrp_basic->db(); +} + +std::vector +usrp_base::db(int which_side) +{ + return d_usrp_basic->db(which_side); +} + +db_base_sptr +usrp_base::db(int which_side, int which_dev) +{ + return d_usrp_basic->selected_subdev(usrp_subdev_spec(which_side, which_dev)); +} + +db_base_sptr +usrp_base::selected_subdev(usrp_subdev_spec ss) +{ + return d_usrp_basic->selected_subdev(ss); +} + +long +usrp_base::fpga_master_clock_freq() const +{ + return d_usrp_basic->fpga_master_clock_freq(); +} + +void +usrp_base::set_verbose (bool verbose) +{ + d_usrp_basic->set_verbose (verbose); +} + +bool +usrp_base::write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf) +{ + return d_usrp_basic->write_eeprom (i2c_addr, eeprom_offset, buf); +} + +std::string +usrp_base::read_eeprom (int i2c_addr, int eeprom_offset, int len) +{ + return d_usrp_basic->read_eeprom (i2c_addr, eeprom_offset, len); +} + +bool +usrp_base::write_i2c (int i2c_addr, const std::string buf) +{ + return d_usrp_basic->write_i2c (i2c_addr, buf); +} + +std::string +usrp_base::read_i2c (int i2c_addr, int len) +{ + return d_usrp_basic->read_i2c (i2c_addr, len); +} + +bool +usrp_base::set_adc_offset (int which, int offset) +{ + return d_usrp_basic->set_adc_offset (which, offset); +} + +bool +usrp_base::set_dac_offset (int which, int offset, int offset_pin) +{ + return d_usrp_basic->set_dac_offset (which, offset, offset_pin); +} + +bool +usrp_base::set_adc_buffer_bypass (int which, bool bypass) +{ + return d_usrp_basic->set_adc_buffer_bypass (which, bypass); +} + +bool +usrp_base::set_dc_offset_cl_enable(int bits, int mask) +{ + return d_usrp_basic->set_dc_offset_cl_enable(bits, mask); +} + +std::string +usrp_base::serial_number() +{ + return d_usrp_basic->serial_number(); +} + +int +usrp_base::daughterboard_id (int which) const +{ + return d_usrp_basic->daughterboard_id (which); +} + +bool +usrp_base::write_atr_tx_delay(int value) +{ + return d_usrp_basic->write_atr_tx_delay(value); +} + +bool +usrp_base::write_atr_rx_delay(int value) +{ + return d_usrp_basic->write_atr_rx_delay(value); +} + +bool +usrp_base::set_pga (int which, double gain) +{ + return d_usrp_basic->set_pga (which, gain); +} + +double +usrp_base::pga (int which) const +{ + return d_usrp_basic->pga (which); +} + +double +usrp_base::pga_min () const +{ + return d_usrp_basic->pga_min (); +} + +double +usrp_base::pga_max () const +{ + return d_usrp_basic->pga_max (); +} + +double +usrp_base::pga_db_per_step () const +{ + return d_usrp_basic->pga_db_per_step (); +} + +bool +usrp_base::_write_oe (int which_dboard, int value, int mask) +{ + return d_usrp_basic->_write_oe (which_dboard, value, mask); +} + +bool +usrp_base::write_io (int which_dboard, int value, int mask) +{ + return d_usrp_basic->write_io (which_dboard, value, mask); +} + +int +usrp_base::read_io (int which_dboard) +{ + return d_usrp_basic->read_io (which_dboard); +} + +bool +usrp_base::write_atr_mask(int which_side, int value) +{ + return d_usrp_basic->write_atr_mask(which_side, value); +} + +bool +usrp_base::write_atr_txval(int which_side, int value) +{ + return d_usrp_basic->write_atr_txval(which_side, value); +} + +bool +usrp_base::write_atr_rxval(int which_side, int value) +{ + return d_usrp_basic->write_atr_rxval(which_side, value); +} + +bool +usrp_base::write_aux_dac (int which_dboard, int which_dac, int value) +{ + return d_usrp_basic->write_aux_dac (which_dboard, which_dac, value); +} + +int +usrp_base::read_aux_adc (int which_dboard, int which_adc) +{ + return d_usrp_basic->read_aux_adc (which_dboard, which_adc); +} + +long +usrp_base::converter_rate() const +{ + return d_usrp_basic->converter_rate(); +} + +bool +usrp_base::_set_led(int which_led, bool on) +{ + return d_usrp_basic->_set_led(which_led, on); +} + +bool +usrp_base::_write_fpga_reg (int regno, int value) +{ + return d_usrp_basic->_write_fpga_reg (regno, value); +} + +bool +usrp_base::_write_fpga_reg_masked (int regno, int value, int mask) +{ + return d_usrp_basic->_write_fpga_reg_masked (regno, value, mask); +} + +int +usrp_base::_read_fpga_reg (int regno) +{ + return d_usrp_basic->_read_fpga_reg (regno); +} + +bool +usrp_base::_write_9862 (int which_codec, int regno, unsigned char value) +{ + return d_usrp_basic->_write_9862 (which_codec, regno, value); +} + +int +usrp_base::_read_9862 (int which_codec, int regno) const +{ + return d_usrp_basic->_read_9862 (which_codec, regno); +} + +bool +usrp_base::_write_spi (int optional_header, int enables, + int format, std::string buf) +{ + return d_usrp_basic->_write_spi (optional_header, enables, format, buf); +} + +std::string +usrp_base::_read_spi (int optional_header, int enables, int format, int len) +{ + return d_usrp_basic->_read_spi (optional_header, enables, format, len); +} + +usrp_subdev_spec +usrp_base::pick_subdev(std::vector candidates) +{ + int dbid0 = db(0, 0)->dbid(); + int dbid1 = db(1, 0)->dbid(); + + for (int i = 0; i < candidates.size(); i++) { + int dbid = candidates[i]; + if (dbid0 == dbid) + return usrp_subdev_spec(0, 0); + if (dbid1 == dbid) + return usrp_subdev_spec(1, 0); + } + + if (dbid0 >= 0) + return usrp_subdev_spec(0, 0); + if (dbid1 >= 0) + return usrp_subdev_spec(1, 0); + + throw std::runtime_error("No suitable daughterboard found!"); +} diff --git a/gr-usrp/src/usrp1_source_base.h b/gr-usrp/src/usrp_base.h similarity index 54% rename from gr-usrp/src/usrp1_source_base.h rename to gr-usrp/src/usrp_base.h index 5d29ba60..83aa699a 100644 --- a/gr-usrp/src/usrp1_source_base.h +++ b/gr-usrp/src/usrp_base.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -14,199 +14,96 @@ * 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. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#ifndef INCLUDED_USRP1_SOURCE_BASE_H -#define INCLUDED_USRP1_SOURCE_BASE_H +#ifndef INCLUDED_USRP_BASE_H +#define INCLUDED_USRP_BASE_H #include #include +#include +#include +#include -class usrp_standard_rx; +class usrp_basic; /*! - * \brief abstract interface to Universal Software Radio Peripheral Rx path (Rev 1) + * \brief base class for GNU Radio interface to the USRP */ -class usrp1_source_base : public gr_sync_block { - private: - usrp_standard_rx *d_usrp; - int d_noverruns; - - protected: - usrp1_source_base (const std::string &name, - gr_io_signature_sptr output_signature, - int which_board, - unsigned int decim_rate, - int nchan, - int mux, - int mode, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); - - /*! - * \brief return number of usrp input bytes required to produce noutput items. - */ - virtual int ninput_bytes_reqd_for_noutput_items (int noutput_items) = 0; - - /*! - * \brief number of bytes in a low-level sample - */ - unsigned int sizeof_basic_sample() const; - - /*! - * \brief convert between native usrp format and output item format - * - * \param output_items[out] stream(s) of output items - * \param output_index[in] starting index in output_items - * \param output_items_available[in] number of empty items available at item[index] - * \param output_items_produced[out] number of items produced by copy - * \param usrp_buffer[in] source buffer - * \param usrp_buffer_length[in] number of bytes available in \p usrp_buffer - * \param bytes_read[out] number of bytes read from \p usrp_buffer - * - * The copy must consume all bytes available. That is, \p bytes_read must equal - * \p usrp_buffer_length. - */ - virtual void copy_from_usrp_buffer (gr_vector_void_star &output_items, - int output_index, - int output_items_available, - int &output_items_produced, - const void *usrp_buffer, - int usrp_buffer_length, - int &bytes_read) = 0; - - public: - //! magic value used on alternate register read interfaces - static const int READ_FAILED = -99999; +class usrp_base : public gr_sync_block { +private: + boost::shared_ptr d_usrp_basic; - ~usrp1_source_base (); +protected: + usrp_base(const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) + : gr_sync_block(name, input_signature, output_signature) {} + - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + void set_usrp_basic(boost::shared_ptr u); - bool start(); - bool stop(); +public: + virtual ~usrp_base(); - /*! - * \brief Set decimator rate. \p rate must be EVEN and in [8, 256]. + /* ! + * Return a vector of vectors of daughterboard instances associated with + * the USRP source or sink. The first dimension of the returned vector + * corresponds to the side of the USRP, the second dimension, the subdevice + * on the particular daughterboard. * - * The final complex sample rate across the USB is - * adc_freq () / decim_rate () + * N.B. To ensure proper lifetime management, the caller should + * continue to hold these as weak pointers, not shared pointers. + * As long as the caller does not attempt to directly use the weak + * pointers after this usrp object has been destroyed, everything + * will work out fine. */ - bool set_decim_rate (unsigned int rate); - bool set_nchannels (int nchan); - bool set_mux (int mux); + std::vector > db(); /*! - * \brief set the center frequency of the digital down converter. + * Return a vector of size 1 or 2 that contains shared pointers + * to the daughterboard instance(s) associated with the specified side. * - * \p channel must be 0. \p freq is the center frequency in Hz. - * It must be in the range [-FIXME, FIXME]. The frequency specified is - * quantized. Use rx_freq to retrieve the actual value used. - */ - bool set_rx_freq (int channel, double freq); - - /*! - * \brief set fpga special modes - */ - bool set_fpga_mode (int mode); - - void set_verbose (bool verbose); - - /*! - * \brief Set the digital down converter phase register. + * \param which_side [0,1] which daughterboard * - * \param channel which ddc channel [0, 3] - * \param phase 32-bit integer phase value. + * N.B. To ensure proper lifetime management, the caller should + * continue to hold these as weak pointers, not shared pointers. + * As long as the caller does not attempt to directly use the weak + * pointers after this usrp object has been destroyed, everything + * will work out fine. */ - bool set_ddc_phase(int channel, int phase); + std::vector db(int which_side); /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which which A/D [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() + * Return the daughterboard instance corresponding to the selected + * side of the USRP and selected daughterboard subdevice. + * N.B. To ensure proper lifetime management, the caller should + * continue to hold these as weak pointers, not shared pointers. + * As long as the caller does not attempt to directly use the weak + * pointers after this usrp object has been destroyed, everything + * will work out fine. */ - bool set_pga (int which, double gain_in_db); + db_base_sptr db(int which_side, int which_dev); /*! - * \brief Return programmable gain amplifier gain setting in dB. + * \brief given a usrp_subdev_spec, return the corresponding daughterboard object. + * \throws std::invalid_argument if ss is invalid. * - * \param which which A/D [0,3] + * \param ss specifies the side and subdevice */ - double pga (int which) const; + db_base_sptr selected_subdev(usrp_subdev_spec ss); /*! - * \brief Return minimum legal PGA setting in dB. + * \brief return frequency of master oscillator on USRP */ - double pga_min () const; + long fpga_master_clock_freq() const; - /*! - * \brief Return maximum legal PGA setting in dB. - */ - double pga_max () const; - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - double pga_db_per_step () const; - - // ACCESSORS - - long fpga_master_clock_freq() const; - long converter_rate() const; - long adc_rate() const { return converter_rate(); } // alias - long adc_freq() const { return converter_rate(); } // deprecated alias + void set_verbose (bool on); - unsigned int decim_rate () const; - int nchannels () const; - int mux () const; - double rx_freq (int channel) const; - int noverruns () const { return d_noverruns; } - - /*! - * \brief Return daughterboard ID for given Rx daughterboard slot [0,1]. - * - * \return daughterboard id >= 0 if successful - * \return -1 if no daugherboard - * \return -2 if invalid EEPROM on daughterboard - */ - int daughterboard_id (int which_dboard) const; - - /*! - * \brief Write auxiliary digital to analog converter. - * - * \param which_dboard [0,1] which d'board - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. - * \param which_dac [2,3] TX slots must use only 2 and 3. - * \param value [0,4095] - * \returns true iff successful - */ - bool write_aux_dac (int which_board, int which_dac, int value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_dboard [0,1] which d'board - * \param which_adc [0,1] - * \returns value in the range [0,4095] if successful, else READ_FAILED. - */ - int read_aux_adc (int which_dboard, int which_adc); + //! magic value used on alternate register read interfaces + static const int READ_FAILED = -99999; /*! * \brief Write EEPROM on motherboard or any daughterboard. @@ -218,7 +115,7 @@ class usrp1_source_base : public gr_sync_block { bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf); /*! - * \brief Write EEPROM on motherboard or any daughterboard. + * \brief Read EEPROM on motherboard or any daughterboard. * \param i2c_addr I2C bus address of EEPROM * \param eeprom_offset byte offset in EEPROM to begin reading * \param len number of bytes to read @@ -240,7 +137,7 @@ class usrp1_source_base : public gr_sync_block { * \param i2c_addr I2C bus address (7-bits) * \param len number of bytes to read * \returns the data read if successful, else a zero length string. - * Reads are limited to a maximum of of 64 bytes. + * Reads are limited to a maximum of 64 bytes. */ std::string read_i2c (int i2c_addr, int len); @@ -249,7 +146,7 @@ class usrp1_source_base : public gr_sync_block { * \param which which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q... * \param offset 16-bit value to subtract from raw ADC input. */ - bool set_adc_offset (int which, int offset); + bool set_adc_offset (int which_adc, int offset); /*! * \brief Set DAC offset correction @@ -258,15 +155,37 @@ class usrp1_source_base : public gr_sync_block { * \param offset_pin 1-bit value. If 0 offset applied to -ve differential pin; * If 1 offset applied to +ve differential pin. */ - bool set_dac_offset (int which, int offset, int offset_pin); + bool set_dac_offset (int which_dac, int offset, int offset_pin); /*! * \brief Control ADC input buffer - * \param which which ADC[0,3] + * \param which_adc which ADC[0,3] * \param bypass if non-zero, bypass input buffer and connect input * directly to switched cap SHA input of RxPGA. */ - bool set_adc_buffer_bypass (int which, bool bypass); + bool set_adc_buffer_bypass (int which_adc, bool bypass); + + /*! + * \brief Enable/disable automatic DC offset removal control loop in FPGA + * + * \param bits which control loops to enable + * \param mask which \p bits to pay attention to + * + * If the corresponding bit is set, enable the automatic DC + * offset correction control loop. + * + *
+   * The 4 low bits are significant:
+   *
+   *   ADC0 = (1 << 0)
+   *   ADC1 = (1 << 1)
+   *   ADC2 = (1 << 2)
+   *   ADC3 = (1 << 3)
+   * 
+ * + * By default the control loop is enabled on all ADC's. + */ + bool set_dc_offset_cl_enable(int bits, int mask); /*! * \brief return the usrp's serial number. @@ -275,12 +194,71 @@ class usrp1_source_base : public gr_sync_block { */ std::string serial_number(); + /*! + * \brief Return daughterboard ID for given side [0,1]. + * + * \param which_side [0,1] which daughterboard + * + * \return daughterboard id >= 0 if successful + * \return -1 if no daugherboard + * \return -2 if invalid EEPROM on daughterboard + */ + virtual int daughterboard_id (int which_side) const; + + /*! + * \brief Clock ticks to delay rising of T/R signal + * \sa write_atr_mask, write_atr_txval, write_atr_rxval + */ + bool write_atr_tx_delay(int value); + + /*! + * \brief Clock ticks to delay falling edge of T/R signal + * \sa write_atr_mask, write_atr_txval, write_atr_rxval + */ + bool write_atr_rx_delay(int value); + + /*! + * \brief Set Programmable Gain Amplifier (PGA) + * + * \param which_amp which amp [0,3] + * \param gain_in_db gain value (linear in dB) + * + * gain is rounded to closest setting supported by hardware. + * + * \returns true iff sucessful. + * + * \sa pga_min(), pga_max(), pga_db_per_step() + */ + bool set_pga (int which_amp, double gain_in_db); + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param which_amp which amp [0,3] + */ + double pga (int which_amp) const; + + /*! + * \brief Return minimum legal PGA gain in dB. + */ + double pga_min () const; + + /*! + * \brief Return maximum legal PGA gain in dB. + */ + double pga_max () const; + + /*! + * \brief Return hardware step size of PGA (linear in dB). + */ + double pga_db_per_step () const; + /*! * \brief Write direction register (output enables) for pins that go to daughterboard. * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg + * \param which_side [0,1] which size + * \param value value to write into register + * \param mask which bits of value to write into reg * * Each d'board has 16-bits of general purpose i/o. * Setting the bit makes it an output from the FPGA to the d'board. @@ -290,93 +268,84 @@ class usrp1_source_base : public gr_sync_block { * without a very good reason. Using this method incorrectly will * kill your USRP motherboard and/or daughterboard. */ - bool _write_oe (int which_dboard, int value, int mask); + bool _write_oe (int which_side, int value, int mask); /*! * \brief Write daughterboard i/o pin value * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg + * \param which_side [0,1] which d'board + * \param value value to write into register + * \param mask which bits of value to write into reg */ - bool write_io (int which_dboard, int value, int mask); + bool write_io (int which_side, int value, int mask); /*! * \brief Read daughterboard i/o pin value * - * \param which_dboard [0,1] which d'board + * \param which_side [0,1] which d'board * \returns register value if successful, else READ_FAILED */ - int read_io (int which_dboard); + int read_io (int which_side); /*! - * \brief Enable/disable automatic DC offset removal control loop in FPGA + * \brief Write daughterboard refclk config register * - * \param bits which control loops to enable - * \param mask which \p bits to pay attention to - * - * If the corresponding bit is set, enable the automatic DC - * offset correction control loop. + * \param which_side [0,1] which d'board + * \param value value to write into register, see below * *
-   * The 4 low bits are significant:
-   *
-   *   ADC0 = (1 << 0)
-   *   ADC1 = (1 << 1)
-   *   ADC2 = (1 << 2)
-   *   ADC3 = (1 << 3)
+   * Control whether a reference clock is sent to the daughterboards,
+   * and what frequency.  The refclk is sent on d'board i/o pin 0.
+   * 
+   *     3                   2                   1                       
+   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   *  +-----------------------------------------------+-+------------+
+   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
+   *  +-----------------------------------------------+-+------------+
+   * 
+   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
+   *  Bits 6:0 Divider value
    * 
- * - * By default the control loop is enabled on all ADC's. */ - bool set_dc_offset_cl_enable(int bits, int mask); + bool write_refclk(int which_side, int value); + + bool write_atr_mask(int which_side, int value); + bool write_atr_txval(int which_side, int value); + bool write_atr_rxval(int which_side, int value); /*! - * \brief Specify Rx data format. - * - * \param format format specifier - * - * Rx data format control register - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------------------------+-+-+---------+-------+ - * | Reserved (Must be zero) |B|Q| WIDTH | SHIFT | - * +-----------------------------------------+-+-+---------+-------+ - * - * SHIFT specifies arithmetic right shift [0, 15] - * WIDTH specifies bit-width of I & Q samples across the USB [1, 16] (not all valid) - * Q if set deliver both I & Q, else just I - * B if set bypass half-band filter. - * - * Right now the acceptable values are: - * - * B Q WIDTH SHIFT - * 0 1 16 0 - * 0 1 8 8 + * \brief Write auxiliary digital to analog converter. * - * More valid combos to come. + * \param which_side [0,1] which d'board + * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. + * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. + * \param which_dac [2,3] TX slots must use only 2 and 3. + * \param value [0,4095] + * \returns true iff successful + */ + bool write_aux_dac (int which_side, int which_dac, int value); + + /*! + * \brief Read auxiliary analog to digital converter. * - * Default value is 0x00000300 16-bits, 0 shift, deliver both I & Q. + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. */ - bool set_format(unsigned int format); + int read_aux_adc (int which_side, int which_adc); /*! - * \brief return current format + * \brief returns A/D or D/A converter rate in Hz */ - unsigned int format () const; + long converter_rate() const; - static unsigned int make_format(int width=16, int shift=0, - bool want_q=true, bool bypass_halfband=false); - static int format_width(unsigned int format); - static int format_shift(unsigned int format); - static bool format_want_q(unsigned int format); - static bool format_bypass_halfband(unsigned int format); // ---------------------------------------------------------------- - // internal routines... + // Low level implementation routines. // You probably shouldn't be using these... - // ---------------------------------------------------------------- + // + + bool _set_led (int which_led, bool on); /*! * \brief Write FPGA register. @@ -387,13 +356,12 @@ class usrp1_source_base : public gr_sync_block { bool _write_fpga_reg (int regno, int value); //< 7-bit regno, 32-bit value /*! - * \brief Write FPGA register masked. + * \brief Read FPGA register. * \param regno 7-bit register number - * \param value 16-bit value - * \param mask 16-bit mask + * \param value 32-bit value * \returns true iff successful */ - bool _write_fpga_reg_masked (int regno, int value, int mask); //< 7-bit regno, 16-bit value, 16-bit mask + bool _read_fpga_reg (int regno, int *value); //< 7-bit regno, 32-bit value /*! * \brief Read FPGA register. @@ -402,6 +370,16 @@ class usrp1_source_base : public gr_sync_block { */ int _read_fpga_reg (int regno); + /*! + * \brief Write FPGA register with mask. + * \param regno 7-bit register number + * \param value 16-bit value + * \param mask 16-bit value + * \returns true if successful + * Only use this for registers who actually implement a mask in the verilog firmware, like FR_RX_MASTER_SLAVE + */ + bool _write_fpga_reg_masked (int regno, int value, int mask); + /*! * \brief Write AD9862 register. * \param which_codec 0 or 1 @@ -450,6 +428,16 @@ class usrp1_source_base : public gr_sync_block { * the peripheral and returned. */ std::string _read_spi (int optional_header, int enables, int format, int len); + + /*! + * Return an existing daughterboard from list of candidate dbids, or the first found + * on side A or side B. + * + * \param candidates Vector of candidate dbids + * + * Throws std::runtime_error if not found + */ + usrp_subdev_spec pick_subdev(std::vector candidates=std::vector(0)); }; -#endif /* INCLUDED_USRP1_SOURCE_BASE_H */ +#endif /* INCLUDED_USRP_BASE_H */ diff --git a/gr-usrp/src/usrp_base.i b/gr-usrp/src/usrp_base.i new file mode 100644 index 00000000..8f0c8368 --- /dev/null +++ b/gr-usrp/src/usrp_base.i @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_base.h" +%} + +class usrp_base : public gr_sync_block +{ +protected: + usrp_base(const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) + : gr_sync_block(name, input_signature, output_signature) {} + +public: + std::vector > db(); + std::vector db(int which_side); + db_base_sptr db(int which_side, int which_dev); + %rename (_real_selected_subdev) selected_subdev; + db_base_sptr selected_subdev(usrp_subdev_spec ss); + long fpga_master_clock_freq() const; + void set_verbose (bool on); + static const int READ_FAILED = -99999; + bool write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf); + std::string read_eeprom (int i2c_addr, int eeprom_offset, int len); + bool write_i2c (int i2c_addr, const std::string buf); + std::string read_i2c (int i2c_addr, int len); + bool set_adc_offset (int which_adc, int offset); + bool set_dac_offset (int which_dac, int offset, int offset_pin); + bool set_adc_buffer_bypass (int which_adc, bool bypass); + bool set_dc_offset_cl_enable(int bits, int mask); + std::string serial_number(); + virtual int daughterboard_id (int which_side) const; + bool write_atr_tx_delay(int value); + bool write_atr_rx_delay(int value); + bool set_pga (int which_amp, double gain_in_db); + double pga (int which_amp) const; + double pga_min () const; + double pga_max () const; + double pga_db_per_step () const; + bool _write_oe (int which_side, int value, int mask); + bool write_io (int which_side, int value, int mask); + int read_io (int which_side); + //bool write_refclk(int which_side, int value); + bool write_atr_mask(int which_side, int value); + bool write_atr_txval(int which_side, int value); + bool write_atr_rxval(int which_side, int value); + bool write_aux_dac (int which_side, int which_dac, int value); + int read_aux_adc (int which_side, int which_adc); + long converter_rate() const; + bool _set_led (int which_led, bool on); + bool _write_fpga_reg (int regno, int value); + //bool _read_fpga_reg (int regno, int *value); + int _read_fpga_reg (int regno); + bool _write_fpga_reg_masked (int regno, int value, int mask); + bool _write_9862 (int which_codec, int regno, unsigned char value); + int _read_9862 (int which_codec, int regno) const; + bool _write_spi (int optional_header, int enables, int format, std::string buf); + std::string _read_spi (int optional_header, int enables, int format, int len); + %rename(_real_pick_subdev) pick_subdev; + usrp_subdev_spec pick_subdev(std::vector candidates=std::vector(0)) + throw (std::runtime_error); +}; diff --git a/gr-usrp/src/usrp_sink_base.cc b/gr-usrp/src/usrp_sink_base.cc new file mode 100644 index 00000000..963f4dd6 --- /dev/null +++ b/gr-usrp/src/usrp_sink_base.cc @@ -0,0 +1,241 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +static const int OUTPUT_MULTIPLE_SAMPLES = 128; // DON'T CHANGE THIS VALUE! + +usrp_sink_base::usrp_sink_base (const std::string &name, + gr_io_signature_sptr input_signature, + int which_board, + unsigned int interp_rate, + int nchan, + int mux, + int fusb_block_size, + int fusb_nblocks, + const std::string fpga_filename, + const std::string firmware_filename + ) throw (std::runtime_error) + : usrp_base(name, + input_signature, + gr_make_io_signature (0, 0, 0)), + d_nunderruns (0) +{ + d_usrp = usrp_standard_tx::make (which_board, + interp_rate, + nchan, mux, + fusb_block_size, + fusb_nblocks, + fpga_filename, + firmware_filename + ); + if (d_usrp == 0) + throw std::runtime_error ("can't open usrp"); + + set_usrp_basic(d_usrp); + + // All calls to d_usrp->write must be multiples of 512 bytes. + + set_output_multiple (OUTPUT_MULTIPLE_SAMPLES); +} + +usrp_sink_base::~usrp_sink_base () +{ +} + +int +usrp_sink_base::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + static const int BUFSIZE = 16 * (1L << 10); // 16kB + unsigned char outbuf[BUFSIZE]; + int obi = 0; + int input_index = 0; + int input_items_consumed; + int bytes_written; + bool underrun; + + + while (input_index < noutput_items){ + + copy_to_usrp_buffer (input_items, + input_index, + noutput_items - input_index, // input_items_available + input_items_consumed, // [out] + &outbuf[obi], // [out] usrp_buffer + BUFSIZE - obi, // usrp_buffer_length + bytes_written); // [out] + + assert (input_index + input_items_consumed <= noutput_items); + assert (obi + bytes_written <= BUFSIZE); + + input_index += input_items_consumed; + obi += bytes_written; + + if (obi >= BUFSIZE){ // flush + if (d_usrp->write (outbuf, obi, &underrun) != obi) + return -1; // indicate we're done + + if (underrun){ + d_nunderruns++; + // fprintf (stderr, "usrp_sink: underrun\n"); + fputs ("uU", stderr); + } + obi = 0; + } + } + + if (obi != 0){ + assert (obi % 512 == 0); + if (d_usrp->write (outbuf, obi, &underrun) != obi) + return -1; // indicate we're done + + if (underrun){ + d_nunderruns++; + // fprintf (stderr, "usrp_sink: underrun\n"); + fputs ("uU", stderr); + } + } + + return noutput_items; +} + +bool +usrp_sink_base::set_interp_rate (unsigned int rate) +{ + return d_usrp->set_interp_rate (rate); +} + +bool +usrp_sink_base::set_nchannels (int nchan) +{ + return d_usrp->set_nchannels (nchan); +} + +bool +usrp_sink_base::set_mux (int mux) +{ + return d_usrp->set_mux (mux); +} + +int +usrp_sink_base::determine_tx_mux_value(usrp_subdev_spec ss) +{ + return d_usrp->determine_tx_mux_value(ss); +} + +bool +usrp_sink_base::set_tx_freq (int channel, double freq) +{ + return d_usrp->set_tx_freq (channel, freq); +} + +unsigned int +usrp_sink_base::interp_rate () const +{ + return d_usrp->interp_rate (); +} + +int +usrp_sink_base::nchannels () const +{ + return d_usrp->nchannels (); +} + +int +usrp_sink_base::mux () const +{ + return d_usrp->mux (); +} + + +double +usrp_sink_base::tx_freq (int channel) const +{ + return d_usrp->tx_freq (channel); +} + +bool +usrp_sink_base::has_rx_halfband() +{ + return d_usrp->has_rx_halfband(); +} + +bool +usrp_sink_base::has_tx_halfband() +{ + return d_usrp->has_tx_halfband(); +} + +int +usrp_sink_base::nddcs() +{ + return d_usrp->nddcs(); +} + +int +usrp_sink_base::nducs() +{ + return d_usrp->nducs(); +} + +bool +usrp_sink_base::start() +{ + return d_usrp->start(); +} + +bool +usrp_sink_base::stop() +{ + return d_usrp->stop(); +} + + +bool +usrp_sink_base::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result) +{ + return d_usrp->tune(chan, db, target_freq, result); +} + +usrp_subdev_spec +usrp_sink_base::pick_tx_subdevice() +{ + int dbids[] = { + USRP_DBID_FLEX_400_TX, + USRP_DBID_FLEX_900_TX, + USRP_DBID_FLEX_1200_TX, + USRP_DBID_FLEX_2400_TX, + USRP_DBID_BASIC_TX + }; + + std::vector candidates(dbids, dbids+(sizeof(dbids)/sizeof(int))); + return pick_subdev(candidates); +} diff --git a/gr-usrp/src/usrp_sink_base.h b/gr-usrp/src/usrp_sink_base.h new file mode 100644 index 00000000..12dd51c6 --- /dev/null +++ b/gr-usrp/src/usrp_sink_base.h @@ -0,0 +1,151 @@ + +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2008 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. + */ + +#ifndef INCLUDED_USRP_SINK_BASE_H +#define INCLUDED_USRP_SINK_BASE_H + +#include +#include +#include +#include + +class usrp_standard_tx; + +/*! + * \brief abstract interface to Universal Software Radio Peripheral Tx path (Rev 1) + */ +class usrp_sink_base : public usrp_base { + private: + boost::shared_ptr d_usrp; + int d_nunderruns; + + protected: + usrp_sink_base (const std::string &name, + gr_io_signature_sptr input_signature, + int which_board, + unsigned int interp_rate, + int nchan, + int mux, + int fusb_block_size, + int fusb_nblocks, + const std::string fpga_filename, + const std::string firmware_filename + ) throw (std::runtime_error); + + /*! + * \brief convert between input item format and usrp native format + * + * \param input_items[in] stream(s) of input items + * \param input_index[in] starting index in input_items + * \param input_items_available[in] number of items available starting at item[index] + * \param input_items_consumed[out] number of input items consumed by copy + * \param usrp_buffer[out] destination buffer + * \param usrp_buffer_length[in] \p usrp_buffer length in bytes + * \param bytes_written[out] number of bytes written into \p usrp_buffer + */ + virtual void copy_to_usrp_buffer (gr_vector_const_void_star &input_items, + int input_index, + int input_items_available, + int &input_items_consumed, + void *usrp_buffer, + int usrp_buffer_length, + int &bytes_written) = 0; + + public: + ~usrp_sink_base (); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + /*! + * \brief Set interpolator rate. \p rate must be in [4, 1024] and a multiple of 4. + * + * The final complex sample rate across the USB is + * dac_freq () / interp_rate () * nchannels () + */ + bool set_interp_rate (unsigned int rate); + bool set_nchannels (int nchan); + bool set_mux (int mux); + int determine_tx_mux_value(usrp_subdev_spec ss); + + /*! + * \brief set the frequency of the digital up converter. + * + * \p channel must be 0. \p freq is the center frequency in Hz. + * It must be in the range [-44M, 44M]. The frequency specified is + * quantized. Use tx_freq to retrieve the actual value used. + */ + bool set_tx_freq (int channel, double freq); + + long dac_rate() const { return converter_rate(); } // alias + long dac_freq() const { return converter_rate(); } // deprecated alias + + unsigned int interp_rate () const; + int nchannels () const; + int mux () const; + double tx_freq (int channel) const; + int nunderruns () const { return d_nunderruns; } + + bool has_rx_halfband(); + bool has_tx_halfband(); + int nddcs(); + int nducs(); + + /*! + * \brief Called to enable drivers, etc for i/o devices. + * + * This allows a block to enable an associated driver to begin + * transfering data just before we start to execute the scheduler. + * The end result is that this reduces latency in the pipeline when + * dealing with audio devices, usrps, etc. + */ + bool start(); + + /*! + * \brief Called to disable drivers, etc for i/o devices. + */ + bool stop(); + + /*! + * \brief High-level "tune" method. Works for the single channel case. + * + * This method adjusts both the daughterboard LO and the DUC so that + * DC in the complex baseband samples ends up at RF target_freq. + * + * \param chan which DUC channel we're controlling (usually == which_side). + * \param db the daughterboard we're controlling. + * \param target_freq the RF frequency we want our baseband translated to. + * \param[out] tune_result details how the hardware was configured. + * + * \returns true iff everything was successful. + */ + bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result); + + /*! + * \brief Select suitable Tx daughterboard + */ + usrp_subdev_spec pick_tx_subdevice(); +}; + +#endif /* INCLUDED_USRP_SINK_BASE_H */ diff --git a/gr-usrp/src/usrp_sink_base.i b/gr-usrp/src/usrp_sink_base.i new file mode 100644 index 00000000..ffc70a98 --- /dev/null +++ b/gr-usrp/src/usrp_sink_base.i @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_sink_base.h" +%} + +class usrp_sink_base : public usrp_base +{ +private: + usrp_sink_base() throw (std::runtime_error); + +public: + bool set_interp_rate (unsigned int rate); + bool set_nchannels (int nchan); + bool set_mux (int mux); + %rename(_real_determine_tx_mux_value) determine_tx_mux_value; + int determine_tx_mux_value(usrp_subdev_spec ss); + bool set_tx_freq (int channel, double freq); + long dac_rate() const { return converter_rate(); } + long dac_freq() const { return converter_rate(); } + unsigned int interp_rate () const; + int nchannels () const; + int mux () const; + double tx_freq (int channel) const; + int nunderruns () const { return d_nunderruns; } + bool has_rx_halfband(); + bool has_tx_halfband(); + int nddcs(); + int nducs(); + %rename(_real_tune) tune; + bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result); + %rename(_real_pick_tx_subdevice) pick_tx_subdevice(); + usrp_subdev_spec pick_tx_subdevice(); +}; diff --git a/gr-usrp/src/usrp1_sink_c.cc b/gr-usrp/src/usrp_sink_c.cc similarity index 89% rename from gr-usrp/src/usrp1_sink_c.cc rename to gr-usrp/src/usrp_sink_c.cc index b3830609..363a113f 100644 --- a/gr-usrp/src/usrp1_sink_c.cc +++ b/gr-usrp/src/usrp_sink_c.cc @@ -24,13 +24,13 @@ #include "config.h" #endif -#include +#include #include #include #include -usrp1_sink_c_sptr -usrp1_make_sink_c (int which_board, +usrp_sink_c_sptr +usrp_make_sink_c (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -40,7 +40,7 @@ usrp1_make_sink_c (int which_board, const std::string firmware_filename ) throw (std::runtime_error) { - return usrp1_sink_c_sptr (new usrp1_sink_c (which_board, + return usrp_sink_c_sptr (new usrp_sink_c (which_board, interp_rate, nchan, mux, @@ -52,7 +52,7 @@ usrp1_make_sink_c (int which_board, } -usrp1_sink_c::usrp1_sink_c (int which_board, +usrp_sink_c::usrp_sink_c (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -61,7 +61,7 @@ usrp1_sink_c::usrp1_sink_c (int which_board, const std::string fpga_filename, const std::string firmware_filename ) throw (std::runtime_error) - : usrp1_sink_base ("usrp1_sink_c", + : usrp_sink_base ("usrp_sink_c", gr_make_io_signature (1, 1, sizeof (gr_complex)), which_board, interp_rate, nchan, mux, fusb_block_size, fusb_nblocks, @@ -69,7 +69,7 @@ usrp1_sink_c::usrp1_sink_c (int which_board, { } -usrp1_sink_c::~usrp1_sink_c () +usrp_sink_c::~usrp_sink_c () { // NOP } @@ -79,7 +79,7 @@ usrp1_sink_c::~usrp1_sink_c () * for the usrp. */ void -usrp1_sink_c::copy_to_usrp_buffer (gr_vector_const_void_star &input_items, +usrp_sink_c::copy_to_usrp_buffer (gr_vector_const_void_star &input_items, int input_index, int input_items_available, int &input_items_consumed, // out diff --git a/gr-usrp/src/usrp1_sink_c.h b/gr-usrp/src/usrp_sink_c.h similarity index 72% rename from gr-usrp/src/usrp1_sink_c.h rename to gr-usrp/src/usrp_sink_c.h index 9e1d3f00..32be5e8b 100644 --- a/gr-usrp/src/usrp1_sink_c.h +++ b/gr-usrp/src/usrp_sink_c.h @@ -20,27 +20,27 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_USRP1_SINK_C_H -#define INCLUDED_USRP1_SINK_C_H +#ifndef INCLUDED_USRP_SINK_C_H +#define INCLUDED_USRP_SINK_C_H -#include +#include -class usrp1_sink_c; -typedef boost::shared_ptr usrp1_sink_c_sptr; +class usrp_sink_c; +typedef boost::shared_ptr usrp_sink_c_sptr; // public shared_ptr constructor -usrp1_sink_c_sptr -usrp1_make_sink_c (int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); +usrp_sink_c_sptr +usrp_make_sink_c (int which_board=0, + unsigned int interp_rate=32, + int nchan=1, + int mux=-1, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); /*! @@ -48,11 +48,11 @@ usrp1_make_sink_c (int which_board, * * input: gr_complex */ -class usrp1_sink_c : public usrp1_sink_base { +class usrp_sink_c : public usrp_sink_base { private: - friend usrp1_sink_c_sptr - usrp1_make_sink_c (int which_board, + friend usrp_sink_c_sptr + usrp_make_sink_c (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -63,7 +63,7 @@ class usrp1_sink_c : public usrp1_sink_base { ) throw (std::runtime_error); protected: - usrp1_sink_c (int which_board, + usrp_sink_c (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -81,7 +81,7 @@ class usrp1_sink_c : public usrp1_sink_base { int usrp_buffer_length, int &bytes_written); public: - ~usrp1_sink_c (); + ~usrp_sink_c (); }; -#endif /* INCLUDED_USRP1_SINK_C_H */ +#endif /* INCLUDED_USRP_SINK_C_H */ diff --git a/gr-usrp/src/usrp_sink_c.i b/gr-usrp/src/usrp_sink_c.i new file mode 100644 index 00000000..15480883 --- /dev/null +++ b/gr-usrp/src/usrp_sink_c.i @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_sink_c.h" +%} + +GR_SWIG_BLOCK_MAGIC(usrp,sink_c) + +class usrp_sink_c; +typedef boost::shared_ptr usrp_sink_c_sptr; + +usrp_sink_c_sptr +usrp_make_sink_c(int which=0, + unsigned int interp_rate=32, + int nchan=1, + int mux=-1, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); + +class usrp_sink_c : public usrp_sink_base +{ +private: + usrp_sink_c() throw (std::runtime_error); +}; diff --git a/gr-usrp/src/usrp1_sink_s.cc b/gr-usrp/src/usrp_sink_s.cc similarity index 88% rename from gr-usrp/src/usrp1_sink_s.cc rename to gr-usrp/src/usrp_sink_s.cc index 3ce33632..adbf3acb 100644 --- a/gr-usrp/src/usrp1_sink_s.cc +++ b/gr-usrp/src/usrp_sink_s.cc @@ -24,13 +24,13 @@ #include "config.h" #endif -#include +#include #include #include #include -usrp1_sink_s_sptr -usrp1_make_sink_s (int which_board, +usrp_sink_s_sptr +usrp_make_sink_s (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -40,7 +40,7 @@ usrp1_make_sink_s (int which_board, const std::string firmware_filename ) throw (std::runtime_error) { - return usrp1_sink_s_sptr (new usrp1_sink_s (which_board, + return usrp_sink_s_sptr (new usrp_sink_s (which_board, interp_rate, nchan, mux, @@ -52,7 +52,7 @@ usrp1_make_sink_s (int which_board, } -usrp1_sink_s::usrp1_sink_s (int which_board, +usrp_sink_s::usrp_sink_s (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -61,7 +61,7 @@ usrp1_sink_s::usrp1_sink_s (int which_board, const std::string fpga_filename, const std::string firmware_filename ) throw (std::runtime_error) - : usrp1_sink_base ("usrp1_sink_s", + : usrp_sink_base ("usrp_sink_s", gr_make_io_signature (1, 1, sizeof (short)), which_board, interp_rate, nchan, mux, fusb_block_size, fusb_nblocks, @@ -70,7 +70,7 @@ usrp1_sink_s::usrp1_sink_s (int which_board, set_output_multiple (512 / sizeof(short)); // don't change } -usrp1_sink_s::~usrp1_sink_s () +usrp_sink_s::~usrp_sink_s () { // NOP } @@ -80,7 +80,7 @@ usrp1_sink_s::~usrp1_sink_s () * for the usrp. */ void -usrp1_sink_s::copy_to_usrp_buffer (gr_vector_const_void_star &input_items, +usrp_sink_s::copy_to_usrp_buffer (gr_vector_const_void_star &input_items, int input_index, int input_items_available, int &input_items_consumed, // out diff --git a/gr-usrp/src/usrp1_sink_s.h b/gr-usrp/src/usrp_sink_s.h similarity index 72% rename from gr-usrp/src/usrp1_sink_s.h rename to gr-usrp/src/usrp_sink_s.h index 2420b1e3..17352a5a 100644 --- a/gr-usrp/src/usrp1_sink_s.h +++ b/gr-usrp/src/usrp_sink_s.h @@ -20,38 +20,38 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_USRP1_SINK_S_H -#define INCLUDED_USRP1_SINK_S_H +#ifndef INCLUDED_USRP_SINK_S_H +#define INCLUDED_USRP_SINK_S_H -#include +#include -class usrp1_sink_s; -typedef boost::shared_ptr usrp1_sink_s_sptr; +class usrp_sink_s; +typedef boost::shared_ptr usrp_sink_s_sptr; // public shared_ptr constructor -usrp1_sink_s_sptr -usrp1_make_sink_s (int which_board, - unsigned int interp_rate, - int nchan, - int mux, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); +usrp_sink_s_sptr +usrp_make_sink_s (int which_board=0, + unsigned int interp_rate=32, + int nchan=1, + int mux=-1, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); /*! * \brief interface to Universal Software Radio Peripheral Tx path (Rev 1) * * input: short */ -class usrp1_sink_s : public usrp1_sink_base { +class usrp_sink_s : public usrp_sink_base { private: - friend usrp1_sink_s_sptr - usrp1_make_sink_s (int which_board, + friend usrp_sink_s_sptr + usrp_make_sink_s (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -62,7 +62,7 @@ class usrp1_sink_s : public usrp1_sink_base { ) throw (std::runtime_error); protected: - usrp1_sink_s (int which_board, + usrp_sink_s (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -80,7 +80,7 @@ class usrp1_sink_s : public usrp1_sink_base { int usrp_buffer_length, int &bytes_written); public: - ~usrp1_sink_s (); + ~usrp_sink_s (); }; -#endif /* INCLUDED_USRP1_SINK_S_H */ +#endif /* INCLUDED_USRP_SINK_S_H */ diff --git a/gr-usrp/src/usrp_sink_s.i b/gr-usrp/src/usrp_sink_s.i new file mode 100644 index 00000000..9993d521 --- /dev/null +++ b/gr-usrp/src/usrp_sink_s.i @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_sink_s.h" +%} + +GR_SWIG_BLOCK_MAGIC(usrp,sink_s) + +class usrp_sink_s; +typedef boost::shared_ptr usrp_sink_s_sptr; + +usrp_sink_s_sptr +usrp_make_sink_s(int which=0, + unsigned int interp_rate=32, + int nchan=1, + int mux=-1, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); + +class usrp_sink_s : public usrp_sink_base +{ +private: + usrp_sink_s() throw (std::runtime_error); +}; diff --git a/gr-usrp/src/usrp_source_base.cc b/gr-usrp/src/usrp_source_base.cc new file mode 100644 index 00000000..778fa101 --- /dev/null +++ b/gr-usrp/src/usrp_source_base.cc @@ -0,0 +1,295 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +static const int OUTPUT_MULTIPLE_BYTES = 4 * 1024; + +usrp_source_base::usrp_source_base (const std::string &name, + gr_io_signature_sptr output_signature, + int which_board, + unsigned int decim_rate, + int nchan, + int mux, + int mode, + int fusb_block_size, + int fusb_nblocks, + const std::string fpga_filename, + const std::string firmware_filename + ) throw (std::runtime_error) + : usrp_base(name, + gr_make_io_signature (0, 0, 0), + output_signature), + d_noverruns (0) +{ + d_usrp = usrp_standard_rx::make (which_board, decim_rate, + nchan, mux, mode, + fusb_block_size, + fusb_nblocks, + fpga_filename, + firmware_filename); + if (d_usrp == 0) + throw std::runtime_error ("can't open usrp"); + + set_usrp_basic(d_usrp); + + // All calls to d_usrp->read must be multiples of 512 bytes. + // We jack this up to 4k to reduce overhead. + + set_output_multiple (OUTPUT_MULTIPLE_BYTES / output_signature->sizeof_stream_item (0)); +} + +usrp_source_base::~usrp_source_base () +{ +} + +unsigned int +usrp_source_base::sizeof_basic_sample() const +{ + return usrp_standard_rx::format_width(d_usrp->format()) / 8; +} + +int +usrp_source_base::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + static const int BUFSIZE = 4 * OUTPUT_MULTIPLE_BYTES; + unsigned char buf[BUFSIZE]; + int output_index = 0; + int output_items_produced; + int bytes_read; + bool overrun; + + while (output_index < noutput_items){ + int nbytes = ninput_bytes_reqd_for_noutput_items (noutput_items - output_index); + nbytes = std::min (nbytes, BUFSIZE); + + int result_nbytes = d_usrp->read (buf, nbytes, &overrun); + if (overrun){ + // fprintf (stderr, "usrp_source: overrun\n"); + fputs ("uO", stderr); + d_noverruns++; + } + + if (result_nbytes < 0) // We've got a problem. Usually board unplugged or powered down. + return -1; // Indicate we're done. + + if (result_nbytes != nbytes){ // not really an error, but unexpected + fprintf (stderr, "usrp_source: short read. Expected %d, got %d\n", + nbytes, result_nbytes); + } + + copy_from_usrp_buffer (output_items, + output_index, + noutput_items - output_index, // output_items_available + output_items_produced, // [out] + buf, // usrp_buffer + result_nbytes, // usrp_buffer_length + bytes_read); // [out] + + assert (output_index + output_items_produced <= noutput_items); + assert (bytes_read == result_nbytes); + + output_index += output_items_produced; + } + + return noutput_items; +} + + +bool +usrp_source_base::set_decim_rate (unsigned int rate) +{ + return d_usrp->set_decim_rate (rate); +} + +bool +usrp_source_base::set_nchannels (int nchan) +{ + return d_usrp->set_nchannels (nchan); +} + +bool +usrp_source_base::set_mux (int mux) +{ + return d_usrp->set_mux (mux); +} + +int +usrp_source_base::determine_rx_mux_value(usrp_subdev_spec ss) +{ + return d_usrp->determine_rx_mux_value(ss); +} + +bool +usrp_source_base::set_rx_freq (int channel, double freq) +{ + return d_usrp->set_rx_freq (channel, freq); +} + +unsigned int +usrp_source_base::decim_rate () const +{ + return d_usrp->decim_rate (); +} + +int +usrp_source_base::nchannels () const +{ + return d_usrp->nchannels (); +} + +int +usrp_source_base::mux () const +{ + return d_usrp->mux (); +} + +double +usrp_source_base::rx_freq (int channel) const +{ + return d_usrp->rx_freq (channel); +} + +bool +usrp_source_base::set_fpga_mode (int mode) +{ + return d_usrp->set_fpga_mode (mode); +} + +bool +usrp_source_base::set_ddc_phase (int channel, int phase) +{ + return d_usrp->set_ddc_phase(channel, phase); +} + + +bool +usrp_source_base::set_format(unsigned int format) +{ + return d_usrp->set_format(format); +} + +unsigned int +usrp_source_base::format() const +{ + return d_usrp->format(); +} + +unsigned int +usrp_source_base::make_format(int width, int shift, bool want_q, bool bypass_halfband) +{ + return usrp_standard_rx::make_format(width, shift, want_q, bypass_halfband); +} + +int +usrp_source_base::format_width(unsigned int format) +{ + return usrp_standard_rx::format_width(format); +} + +int +usrp_source_base::format_shift(unsigned int format) +{ + return usrp_standard_rx::format_shift(format); +} + +bool +usrp_source_base::format_want_q(unsigned int format) +{ + return usrp_standard_rx::format_want_q(format); +} + +bool +usrp_source_base::format_bypass_halfband(unsigned int format) +{ + return usrp_standard_rx::format_bypass_halfband(format); +} + +bool +usrp_source_base::has_rx_halfband() +{ + return d_usrp->has_rx_halfband(); +} + +bool +usrp_source_base::has_tx_halfband() +{ + return d_usrp->has_tx_halfband(); +} + +int +usrp_source_base::nddcs() +{ + return d_usrp->nddcs(); +} + +int +usrp_source_base::nducs() +{ + return d_usrp->nducs(); +} + +bool +usrp_source_base::start() +{ + return d_usrp->start(); +} + +bool +usrp_source_base::stop() +{ + return d_usrp->stop(); +} + +bool +usrp_source_base::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result) +{ + return d_usrp->tune(chan, db, target_freq, result); +} + +usrp_subdev_spec +usrp_source_base::pick_rx_subdevice() +{ + int dbids[] = { + USRP_DBID_FLEX_400_RX, + USRP_DBID_FLEX_900_RX, + USRP_DBID_FLEX_1200_RX, + USRP_DBID_FLEX_2400_RX, + USRP_DBID_TV_RX, + USRP_DBID_TV_RX_REV_2, + USRP_DBID_DBS_RX, + USRP_DBID_DBS_RX_REV_2_1, + USRP_DBID_BASIC_RX + }; + + std::vector candidates(dbids, dbids+(sizeof(dbids)/sizeof(int))); + return pick_subdev(candidates); +} diff --git a/gr-usrp/src/usrp_source_base.h b/gr-usrp/src/usrp_source_base.h new file mode 100644 index 00000000..9d8f32ac --- /dev/null +++ b/gr-usrp/src/usrp_source_base.h @@ -0,0 +1,219 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008 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. + */ + +#ifndef INCLUDED_USRP_SOURCE_BASE_H +#define INCLUDED_USRP_SOURCE_BASE_H + +#include +#include +#include +#include + +class usrp_standard_rx; + +/*! + * \brief abstract interface to Universal Software Radio Peripheral Rx path (Rev 1) + */ +class usrp_source_base : public usrp_base { + private: + boost::shared_ptr d_usrp; + int d_noverruns; + + protected: + usrp_source_base (const std::string &name, + gr_io_signature_sptr output_signature, + int which_board, + unsigned int decim_rate, + int nchan, + int mux, + int mode, + int fusb_block_size, + int fusb_nblocks, + const std::string fpga_filename, + const std::string firmware_filename + ) throw (std::runtime_error); + + /*! + * \brief return number of usrp input bytes required to produce noutput items. + */ + virtual int ninput_bytes_reqd_for_noutput_items (int noutput_items) = 0; + + /*! + * \brief number of bytes in a low-level sample + */ + unsigned int sizeof_basic_sample() const; + + /*! + * \brief convert between native usrp format and output item format + * + * \param output_items[out] stream(s) of output items + * \param output_index[in] starting index in output_items + * \param output_items_available[in] number of empty items available at item[index] + * \param output_items_produced[out] number of items produced by copy + * \param usrp_buffer[in] source buffer + * \param usrp_buffer_length[in] number of bytes available in \p usrp_buffer + * \param bytes_read[out] number of bytes read from \p usrp_buffer + * + * The copy must consume all bytes available. That is, \p bytes_read must equal + * \p usrp_buffer_length. + */ + virtual void copy_from_usrp_buffer (gr_vector_void_star &output_items, + int output_index, + int output_items_available, + int &output_items_produced, + const void *usrp_buffer, + int usrp_buffer_length, + int &bytes_read) = 0; + + public: + ~usrp_source_base (); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + /*! + * \brief Set decimator rate. \p rate must be EVEN and in [8, 256]. + * + * The final complex sample rate across the USB is + * adc_freq () / decim_rate () + */ + bool set_decim_rate (unsigned int rate); + bool set_nchannels (int nchan); + bool set_mux (int mux); + int determine_rx_mux_value(usrp_subdev_spec ss); + + /*! + * \brief set the center frequency of the digital down converter. + * + * \p channel must be 0. \p freq is the center frequency in Hz. + * It must be in the range [-FIXME, FIXME]. The frequency specified is + * quantized. Use rx_freq to retrieve the actual value used. + */ + bool set_rx_freq (int channel, double freq); + + /*! + * \brief set fpga special modes + */ + bool set_fpga_mode (int mode); + + /*! + * \brief Set the digital down converter phase register. + * + * \param channel which ddc channel [0, 3] + * \param phase 32-bit integer phase value. + */ + bool set_ddc_phase(int channel, int phase); + + long adc_rate() const { return converter_rate(); } // alias + long adc_freq() const { return converter_rate(); } // deprecated alias + + unsigned int decim_rate () const; + int nchannels () const; + int mux () const; + double rx_freq (int channel) const; + int noverruns () const { return d_noverruns; } + + bool has_rx_halfband(); + bool has_tx_halfband(); + int nddcs(); + int nducs(); + + /*! + * \brief Called to enable drivers, etc for i/o devices. + * + * This allows a block to enable an associated driver to begin + * transfering data just before we start to execute the scheduler. + * The end result is that this reduces latency in the pipeline when + * dealing with audio devices, usrps, etc. + */ + bool start(); + + /*! + * \brief Called to disable drivers, etc for i/o devices. + */ + bool stop(); + + /*! + * \brief Specify Rx data format. + * + * \param format format specifier + * + * Rx data format control register + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------------------------+-+-+---------+-------+ + * | Reserved (Must be zero) |B|Q| WIDTH | SHIFT | + * +-----------------------------------------+-+-+---------+-------+ + * + * SHIFT specifies arithmetic right shift [0, 15] + * WIDTH specifies bit-width of I & Q samples across the USB [1, 16] (not all valid) + * Q if set deliver both I & Q, else just I + * B if set bypass half-band filter. + * + * Right now the acceptable values are: + * + * B Q WIDTH SHIFT + * 0 1 16 0 + * 0 1 8 8 + * + * More valid combos to come. + * + * Default value is 0x00000300 16-bits, 0 shift, deliver both I & Q. + */ + bool set_format(unsigned int format); + + /*! + * \brief return current format + */ + unsigned int format () const; + + static unsigned int make_format(int width=16, int shift=0, + bool want_q=true, bool bypass_halfband=false); + static int format_width(unsigned int format); + static int format_shift(unsigned int format); + static bool format_want_q(unsigned int format); + static bool format_bypass_halfband(unsigned int format); + + /*! + * \brief High-level "tune" method. Works for the single channel case. + * + * This method adjusts both the daughterboard LO and the DDC so that + * target_freq ends up at DC in the complex baseband samples. + * + * \param chan which DDC channel we're controlling (almost always 0). + * \param db the daughterboard we're controlling. + * \param target_freq the RF frequency we want at DC in the complex baseband. + * \param[out] tune_result details how the hardware was configured. + * + * \returns true iff everything was successful. + */ + bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result); + + /*! + * \brief Select suitable Rx daughterboard + */ + usrp_subdev_spec pick_rx_subdevice(); +}; + +#endif /* INCLUDED_USRP_SOURCE_BASE_H */ diff --git a/gr-usrp/src/usrp_source_base.i b/gr-usrp/src/usrp_source_base.i new file mode 100644 index 00000000..6a70c741 --- /dev/null +++ b/gr-usrp/src/usrp_source_base.i @@ -0,0 +1,63 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_source_base.h" +%} + +class usrp_source_base : public usrp_base +{ +private: + usrp_source_base() throw (std::runtime_error); + +public: + bool set_decim_rate (unsigned int rate); + bool set_nchannels (int nchan); + bool set_mux (int mux); + %rename(_real_determine_rx_mux_value) determine_rx_mux_value; + int determine_rx_mux_value(usrp_subdev_spec ss); + bool set_rx_freq (int channel, double freq); + bool set_fpga_mode (int mode); + bool set_ddc_phase(int channel, int phase); + long adc_rate() const { return converter_rate(); } + long adc_freq() const { return converter_rate(); } + unsigned int decim_rate () const; + int nchannels () const; + int mux () const; + double rx_freq (int channel) const; + int noverruns () const { return d_noverruns; } + bool has_rx_halfband(); + bool has_tx_halfband(); + int nddcs(); + int nducs(); + bool set_format(unsigned int format); + static unsigned int make_format(int width=16, int shift=0, + bool want_q=true, bool bypass_halfband=false); + static int format_width(unsigned int format); + static int format_shift(unsigned int format); + static bool format_want_q(unsigned int format); + static bool format_bypass_halfband(unsigned int format); + %rename(_real_tune) tune; + bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result); + %rename(_real_pick_rx_subdevice) pick_rx_subdevice(); + usrp_subdev_spec pick_rx_subdevice(); +}; diff --git a/gr-usrp/src/usrp1_source_c.cc b/gr-usrp/src/usrp_source_c.cc similarity index 88% rename from gr-usrp/src/usrp1_source_c.cc rename to gr-usrp/src/usrp_source_c.cc index a5b82ab7..71ca1e0d 100644 --- a/gr-usrp/src/usrp1_source_c.cc +++ b/gr-usrp/src/usrp_source_c.cc @@ -24,15 +24,15 @@ #include "config.h" #endif -#include +#include #include #include #include static const int NBASIC_SAMPLES_PER_ITEM = 2; // I & Q -usrp1_source_c_sptr -usrp1_make_source_c (int which_board, +usrp_source_c_sptr +usrp_make_source_c (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -43,7 +43,7 @@ usrp1_make_source_c (int which_board, const std::string firmware_filename ) throw (std::runtime_error) { - return usrp1_source_c_sptr (new usrp1_source_c (which_board, + return usrp_source_c_sptr (new usrp_source_c (which_board, decim_rate, nchan, mux, @@ -56,7 +56,7 @@ usrp1_make_source_c (int which_board, } -usrp1_source_c::usrp1_source_c (int which_board, +usrp_source_c::usrp_source_c (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -66,7 +66,7 @@ usrp1_source_c::usrp1_source_c (int which_board, const std::string fpga_filename, const std::string firmware_filename ) throw (std::runtime_error) - : usrp1_source_base ("usrp1_source_c", + : usrp_source_base ("usrp_source_c", gr_make_io_signature (1, 1, sizeof (gr_complex)), which_board, decim_rate, nchan, mux, mode, fusb_block_size, fusb_nblocks, @@ -74,13 +74,13 @@ usrp1_source_c::usrp1_source_c (int which_board, { } -usrp1_source_c::~usrp1_source_c () +usrp_source_c::~usrp_source_c () { // NOP } int -usrp1_source_c::ninput_bytes_reqd_for_noutput_items (int noutput_items) +usrp_source_c::ninput_bytes_reqd_for_noutput_items (int noutput_items) { return noutput_items * NBASIC_SAMPLES_PER_ITEM * sizeof_basic_sample(); } @@ -90,7 +90,7 @@ usrp1_source_c::ninput_bytes_reqd_for_noutput_items (int noutput_items) * complex output stream. */ void -usrp1_source_c::copy_from_usrp_buffer (gr_vector_void_star &output_items, +usrp_source_c::copy_from_usrp_buffer (gr_vector_void_star &output_items, int output_index, int output_items_available, int &output_items_produced, diff --git a/gr-usrp/src/usrp1_source_c.h b/gr-usrp/src/usrp_source_c.h similarity index 73% rename from gr-usrp/src/usrp1_source_c.h rename to gr-usrp/src/usrp_source_c.h index 0d6e50e0..39a282b8 100644 --- a/gr-usrp/src/usrp1_source_c.h +++ b/gr-usrp/src/usrp_source_c.h @@ -20,40 +20,40 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_USRP1_SOURCE_C_H -#define INCLUDED_USRP1_SOURCE_C_H +#ifndef INCLUDED_USRP_SOURCE_C_H +#define INCLUDED_USRP_SOURCE_C_H -#include +#include #include class usrp_standard_rx; -class usrp1_source_c; -typedef boost::shared_ptr usrp1_source_c_sptr; +class usrp_source_c; +typedef boost::shared_ptr usrp_source_c_sptr; // public shared_ptr constructor -usrp1_source_c_sptr -usrp1_make_source_c (int which_board, - unsigned int decim_rate, - int nchan, - int mux, - int mode, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename +usrp_source_c_sptr +usrp_make_source_c (int which_board=0, + unsigned int decim_rate=16, + int nchan = 1, + int mux = -1, + int mode = 0, + int fusb_block_size = 0, + int fusb_nblocks = 0, + const std::string fpga_filename = "", + const std::string firmware_filename = "" ) throw (std::runtime_error); /*! * \brief interface to Universal Software Radio Peripheral Rx path (Rev 1) */ -class usrp1_source_c : public usrp1_source_base { +class usrp_source_c : public usrp_source_base { private: - friend usrp1_source_c_sptr - usrp1_make_source_c (int which_board, + friend usrp_source_c_sptr + usrp_make_source_c (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -65,7 +65,7 @@ class usrp1_source_c : public usrp1_source_base { ) throw (std::runtime_error); protected: - usrp1_source_c (int which_board, + usrp_source_c (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -87,7 +87,7 @@ class usrp1_source_c : public usrp1_source_base { int &bytes_read); public: - ~usrp1_source_c (); + ~usrp_source_c (); }; -#endif /* INCLUDED_USRP1_SOURCE_C_H */ +#endif /* INCLUDED_USRP_SOURCE_C_H */ diff --git a/gr-usrp/src/usrp_source_c.i b/gr-usrp/src/usrp_source_c.i new file mode 100644 index 00000000..499f7f74 --- /dev/null +++ b/gr-usrp/src/usrp_source_c.i @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_source_c.h" +%} + +GR_SWIG_BLOCK_MAGIC(usrp,source_c) + +class usrp_source_c; +typedef boost::shared_ptr usrp_source_c_sptr; + +usrp_source_c_sptr +usrp_make_source_c(int which=0, + unsigned int decim_rate=16, + int nchan=1, + int mux=-1, + int mode=0, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); + +class usrp_source_c : public usrp_source_base +{ +private: + usrp_source_c() throw (std::runtime_error); +}; diff --git a/gr-usrp/src/usrp1_source_s.cc b/gr-usrp/src/usrp_source_s.cc similarity index 87% rename from gr-usrp/src/usrp1_source_s.cc rename to gr-usrp/src/usrp_source_s.cc index 8295d929..f2038459 100644 --- a/gr-usrp/src/usrp1_source_s.cc +++ b/gr-usrp/src/usrp_source_s.cc @@ -24,15 +24,15 @@ #include "config.h" #endif -#include +#include #include #include #include static const int NBASIC_SAMPLES_PER_ITEM = 1; -usrp1_source_s_sptr -usrp1_make_source_s (int which_board, +usrp_source_s_sptr +usrp_make_source_s (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -43,7 +43,7 @@ usrp1_make_source_s (int which_board, const std::string firmware_filename ) throw (std::runtime_error) { - return usrp1_source_s_sptr (new usrp1_source_s (which_board, + return usrp_source_s_sptr (new usrp_source_s (which_board, decim_rate, nchan, mux, @@ -56,7 +56,7 @@ usrp1_make_source_s (int which_board, } -usrp1_source_s::usrp1_source_s (int which_board, +usrp_source_s::usrp_source_s (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -66,7 +66,7 @@ usrp1_source_s::usrp1_source_s (int which_board, const std::string fpga_filename, const std::string firmware_filename ) throw (std::runtime_error) - : usrp1_source_base ("usrp1_source_s", + : usrp_source_base ("usrp_source_s", gr_make_io_signature (1, 1, sizeof (short)), which_board, decim_rate, nchan, mux, mode, fusb_block_size, @@ -75,13 +75,13 @@ usrp1_source_s::usrp1_source_s (int which_board, { } -usrp1_source_s::~usrp1_source_s () +usrp_source_s::~usrp_source_s () { // NOP } int -usrp1_source_s::ninput_bytes_reqd_for_noutput_items (int noutput_items) +usrp_source_s::ninput_bytes_reqd_for_noutput_items (int noutput_items) { return noutput_items * NBASIC_SAMPLES_PER_ITEM * sizeof_basic_sample(); } @@ -91,7 +91,7 @@ usrp1_source_s::ninput_bytes_reqd_for_noutput_items (int noutput_items) * short output stream. */ void -usrp1_source_s::copy_from_usrp_buffer (gr_vector_void_star &output_items, +usrp_source_s::copy_from_usrp_buffer (gr_vector_void_star &output_items, int output_index, int output_items_available, int &output_items_produced, diff --git a/gr-usrp/src/usrp1_source_s.h b/gr-usrp/src/usrp_source_s.h similarity index 72% rename from gr-usrp/src/usrp1_source_s.h rename to gr-usrp/src/usrp_source_s.h index 35beb42a..6f7f98b2 100644 --- a/gr-usrp/src/usrp1_source_s.h +++ b/gr-usrp/src/usrp_source_s.h @@ -20,42 +20,42 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_USRP1_SOURCE_S_H -#define INCLUDED_USRP1_SOURCE_S_H +#ifndef INCLUDED_USRP_SOURCE_S_H +#define INCLUDED_USRP_SOURCE_S_H -#include +#include #include class usrp_standard_rx; -class usrp1_source_s; -typedef boost::shared_ptr usrp1_source_s_sptr; +class usrp_source_s; +typedef boost::shared_ptr usrp_source_s_sptr; // public shared_ptr constructor -usrp1_source_s_sptr -usrp1_make_source_s (int which_board, - unsigned int decim_rate, - int nchan, - int mux, - int mode, - int fusb_block_size, - int fusb_nblocks, - const std::string fpga_filename, - const std::string firmware_filename - ) throw (std::runtime_error); +usrp_source_s_sptr +usrp_make_source_s (int which_board=0, + unsigned int decim_rate=16, + int nchan=1, + int mux=-1, + int mode=0, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); /*! * \brief interface to Universal Software Radio Peripheral Rx path (Rev 1) * * output: 1 stream of short */ -class usrp1_source_s : public usrp1_source_base { +class usrp_source_s : public usrp_source_base { private: - friend usrp1_source_s_sptr - usrp1_make_source_s (int which_board, + friend usrp_source_s_sptr + usrp_make_source_s (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -67,7 +67,7 @@ class usrp1_source_s : public usrp1_source_base { ) throw (std::runtime_error); protected: - usrp1_source_s (int which_board, + usrp_source_s (int which_board, unsigned int decim_rate, int nchan, int mux, @@ -88,7 +88,7 @@ class usrp1_source_s : public usrp1_source_base { int usrp_buffer_length, int &bytes_read); public: - ~usrp1_source_s (); + ~usrp_source_s (); }; -#endif /* INCLUDED_USRP1_SOURCE_S_H */ +#endif /* INCLUDED_USRP_SOURCE_S_H */ diff --git a/gr-usrp/src/usrp_source_s.i b/gr-usrp/src/usrp_source_s.i new file mode 100644 index 00000000..d8b285c9 --- /dev/null +++ b/gr-usrp/src/usrp_source_s.i @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%{ +#include "usrp_source_s.h" +%} + +GR_SWIG_BLOCK_MAGIC(usrp,source_s) + +class usrp_source_s; +typedef boost::shared_ptr usrp_source_s_sptr; + +usrp_source_s_sptr +usrp_make_source_s(int which=0, + unsigned int decim_rate=16, + int nchan=1, + int mux=-1, + int mode=0, + int fusb_block_size=0, + int fusb_nblocks=0, + const std::string fpga_filename="", + const std::string firmware_filename="" + ) throw (std::runtime_error); + +class usrp_source_s : public usrp_source_base +{ +private: + usrp_source_s() throw (std::runtime_error); +}; diff --git a/gr-usrp/src/usrp_standard.i b/gr-usrp/src/usrp_standard.i new file mode 100644 index 00000000..7d32cdf8 --- /dev/null +++ b/gr-usrp/src/usrp_standard.i @@ -0,0 +1,36 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +// FIXME: move to usrp/usrpm component + +%{ +#include +#include +#include +%} + +%include +%include + +%constant int FPGA_MODE_NORMAL = usrp_standard_rx::FPGA_MODE_NORMAL; +%constant int FPGA_MODE_LOOPBACK = usrp_standard_rx::FPGA_MODE_LOOPBACK; +%constant int FPGA_MODE_COUNTING = usrp_standard_rx::FPGA_MODE_COUNTING; diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index fcf4c053..4aa70ada 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -37,9 +37,9 @@ def pick_subdevice(u): If there's a daughterboard on B, select B. Otherwise, select A. """ - if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db[1][0].dbid() >= 0: + if u.db(0, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index d3223cba..f4a539dd 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -40,9 +40,9 @@ def pick_subdevice(u): If there's a daughterboard on B, select B. Otherwise, select A. """ - if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db[1][0].dbid() >= 0: + if u.db(0, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index fe29787f..3e7751c0 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -118,7 +118,7 @@ class my_top_block(gr.top_block): the result of that operation and our target_frequency to determine the value for the digital up converter. """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) + r = self.u.tune(self.subdev.which(), self.subdev, target_freq) if r: #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) @@ -200,5 +200,6 @@ def main (): except KeyboardInterrupt: pass + if __name__ == '__main__': main () diff --git a/grc/src/grc_gnuradio/usrp/simple_usrp.py b/grc/src/grc_gnuradio/usrp/simple_usrp.py index dd33ef12..c1019d33 100644 --- a/grc/src/grc_gnuradio/usrp/simple_usrp.py +++ b/grc/src/grc_gnuradio/usrp/simple_usrp.py @@ -79,7 +79,7 @@ def _setup_tx_subdev(u, subdev_spec, gain, frequency, auto_tr=None, tx_enb=None) """ subdev = usrp.selected_subdev(u, subdev_spec)#get the subdev subdev.set_gain(gain) - _set_frequency(u, subdev._which, subdev, frequency, verbose=True) + _set_frequency(u, subdev.which(), subdev, frequency, verbose=True) if auto_tr is not None: subdev.set_auto_tr(auto_tr) if tx_enb is not None: subdev.set_enable(tx_enb) return subdev @@ -162,10 +162,10 @@ class _simple_source(gr.hier_block2, _simple_usrp): gr.hier_block2.__init__( self, 'usrp_simple_source', gr.io_signature(0, 0, 0), - gr.io_signature(1, 1, constructor_to_size[self.constructor]), + gr.io_signature(1, 1, constructor_to_size[self.constructor[0]]), ) #create usrp object - u = self.constructor(number, nchan=1) + u = self.constructor[0](number, nchan=1) if subdev_spec is None: subdev_spec = usrp.pick_rx_subdevice(u) u.set_decim_rate(decimation) if mux is None: mux = usrp.determine_rx_mux_value(u, subdev_spec) @@ -177,8 +177,8 @@ class _simple_source(gr.hier_block2, _simple_usrp): def set_decim_rate(self, decim): self.get_u().set_decim_rate(int(decim)) -class simple_source_c(_simple_source): constructor = usrp.source_c -class simple_source_s(_simple_source): constructor = usrp.source_s +class simple_source_c(_simple_source): constructor = (usrp.source_c, ) +class simple_source_s(_simple_source): constructor = (usrp.source_s, ) #################################################################### # Simple USRP Sink @@ -201,24 +201,24 @@ class _simple_sink(gr.hier_block2, _simple_usrp): #initialize hier2 block gr.hier_block2.__init__( self, 'usrp_simple_sink', - gr.io_signature(1, 1, constructor_to_size[self.constructor]), + gr.io_signature(1, 1, constructor_to_size[self.constructor[0]]), gr.io_signature(0, 0, 0), ) #create usrp object - u = self.constructor(number, nchan=1) + u = self.constructor[0](number, nchan=1) if subdev_spec is None: subdev_spec = usrp.pick_tx_subdevice(u) u.set_interp_rate(interpolation) if mux is None: mux = usrp.determine_tx_mux_value(u, subdev_spec) u.set_mux(mux) subdev = _setup_tx_subdev(u, subdev_spec, gain, frequency, auto_tr, tx_enb) - _simple_usrp.__init__(self, u, subdev, subdev._which) + _simple_usrp.__init__(self, u, subdev, subdev.which()) #connect self.connect(self, u) def set_interp_rate(self, interp): self.get_u().set_interp_rate(int(interp)) -class simple_sink_c(_simple_sink): constructor = usrp.sink_c -class simple_sink_s(_simple_sink): constructor = usrp.sink_s +class simple_sink_c(_simple_sink): constructor = (usrp.sink_c, ) +class simple_sink_s(_simple_sink): constructor = (usrp.sink_s, ) #################################################################### #################################################################### @@ -317,17 +317,17 @@ class _dual_source(gr.hier_block2, _dual_usrp): gr.hier_block2.__init__( self, 'usrp_dual_source', gr.io_signature(0, 0, 0), - gr.io_signature(2, 2, constructor_to_size[self.constructor]), + gr.io_signature(2, 2, constructor_to_size[self.constructor[0]]), ) #create usrp object - u = self.constructor(number, nchan=2) + u = self.constructor[0](number, nchan=2) u.set_decim_rate(decimation) u.set_mux(mux) subdev_a = _setup_rx_subdev(u, (0, 0), 0, gain_a, frequency_a, auto_tr, rx_ant_a) subdev_b = _setup_rx_subdev(u, (1, 0), 1, gain_b, frequency_b, auto_tr, rx_ant_b) _dual_usrp.__init__(self, u, subdev_a, subdev_b, 0, 1) #connect - deinter = gr.deinterleave(constructor_to_size[self.constructor]) + deinter = gr.deinterleave(constructor_to_size[self.constructor[0]]) self.connect(u, deinter) for i in range(2): self.connect((deinter, i), (self, i)) @@ -357,18 +357,18 @@ class _dual_sink(gr.hier_block2, _dual_usrp): #initialize hier2 block gr.hier_block2.__init__( self, 'usrp_dual_sink', - gr.io_signature(2, 2, constructor_to_size[self.constructor]), + gr.io_signature(2, 2, constructor_to_size[self.constructor[0]]), gr.io_signature(0, 0, 0), ) #create usrp object - u = self.constructor(number, nchan=2) + u = self.constructor[0](number, nchan=2) u.set_interp_rate(interpolation) u.set_mux(mux) subdev_a = _setup_tx_subdev(u, (0, 0), gain_a, frequency_a, auto_tr, tx_enb_a) subdev_b = _setup_tx_subdev(u, (1, 0), gain_b, frequency_b, auto_tr, tx_enb_b) - _dual_usrp.__init__(self, u, subdev_a, subdev_b, subdev_a._which, subdev_b._which) + _dual_usrp.__init__(self, u, subdev_a, subdev_b, subdev_a.which(), subdev_b.which()) #connect - inter = gr.interleave(constructor_to_size[self.constructor]) + inter = gr.interleave(constructor_to_size[self.constructor[0]]) self.connect(inter, u) for i in range(2): self.connect((self, i), (inter, i)) diff --git a/usrp/host/apps/test_usrp_standard_rx.cc b/usrp/host/apps/test_usrp_standard_rx.cc index 49f1f21b..4a47daa9 100644 --- a/usrp/host/apps/test_usrp_standard_rx.cc +++ b/usrp/host/apps/test_usrp_standard_rx.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2006 Free Software Foundation, Inc. + * Copyright 2003,2006,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -44,7 +44,7 @@ char *prog_name; -static bool test_input (usrp_standard_rx *urx, int max_bytes, FILE *fp); +static bool test_input (usrp_standard_rx_sptr urx, int max_bytes, FILE *fp); static void set_progname (char *path) @@ -189,7 +189,7 @@ main (int argc, char **argv) mode |= usrp_standard_rx::FPGA_MODE_COUNTING; - usrp_standard_rx *urx = + usrp_standard_rx_sptr urx = usrp_standard_rx::make (which_board, decim, 1, -1, mode, fusb_block_size, fusb_nblocks); @@ -214,14 +214,12 @@ main (int argc, char **argv) if (fp) fclose (fp); - delete urx; - return 0; } static bool -test_input (usrp_standard_rx *urx, int max_bytes, FILE *fp) +test_input (usrp_standard_rx_sptr urx, int max_bytes, FILE *fp) { int fd = -1; static const int BUFSIZE = urx->block_size(); diff --git a/usrp/host/apps/test_usrp_standard_tx.cc b/usrp/host/apps/test_usrp_standard_tx.cc index 6418c4ab..48899552 100644 --- a/usrp/host/apps/test_usrp_standard_tx.cc +++ b/usrp/host/apps/test_usrp_standard_tx.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2004 Free Software Foundation, Inc. + * Copyright 2003,2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -42,7 +42,7 @@ char *prog_name; -static bool test_output (usrp_standard_tx *utx, int max_bytes, double ampl, +static bool test_output (usrp_standard_tx_sptr utx, int max_bytes, double ampl, bool dc_p, bool counting_p); static void @@ -210,7 +210,7 @@ main (int argc, char **argv) } #endif - usrp_standard_tx *utx; + usrp_standard_tx_sptr utx; utx = usrp_standard_tx::make (which_board, interp, @@ -226,7 +226,7 @@ main (int argc, char **argv) die ("utx->set_tx_freq"); if (dump_regs_p) - do_dump_codec_regs (utx); + do_dump_codec_regs (utx.get()); fflush (stdout); @@ -236,14 +236,12 @@ main (int argc, char **argv) test_output (utx, max_bytes, ampl, dc_p, counting_p); - delete utx; - return 0; } static bool -test_output (usrp_standard_tx *utx, int max_bytes, double ampl, +test_output (usrp_standard_tx_sptr utx, int max_bytes, double ampl, bool dc_p, bool counting_p) { static const int BUFSIZE = utx->block_size(); diff --git a/usrp/host/apps/usrp_cal_dc_offset.cc b/usrp/host/apps/usrp_cal_dc_offset.cc index e836e1aa..5ebac12a 100644 --- a/usrp/host/apps/usrp_cal_dc_offset.cc +++ b/usrp/host/apps/usrp_cal_dc_offset.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -43,7 +43,7 @@ char *prog_name; static void -run_cal(usrp_standard_rx *u, int which_side, int decim, bool verbose_p) +run_cal(usrp_standard_rx_sptr u, int which_side, int decim, bool verbose_p) { static const int BUFSIZE = u->block_size(); static const int N = BUFSIZE/sizeof (short); @@ -213,11 +213,11 @@ main (int argc, char **argv) usrp_local_sighandler sigquit (SIGQUIT, usrp_local_sighandler::throw_signal); #endif - usrp_standard_rx *urx = + usrp_standard_rx_sptr urx = usrp_standard_rx::make(which_board, decim, nchannels, mux, mode, fusb_block_size, fusb_nblocks); - if (urx == 0) + if (!urx) die("usrp_standard_rx::make"); try { @@ -236,7 +236,5 @@ main (int argc, char **argv) catch(...){ fprintf (stderr, "usrp_cal_dc_offset: caught something\n"); } - - delete urx; } diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc index c6641839..6049a8a8 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.cc +++ b/usrp/host/lib/inband/qa_inband_usrp_server.cc @@ -1543,6 +1543,9 @@ qa_inband_usrp_server::test_rx() void qa_inband_usrp_server::test_cs() { + // FIXME This test is disabled because it hangs with the change to use usrp_standard_*_sptr's + return; + mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_T; @@ -1557,6 +1560,9 @@ qa_inband_usrp_server::test_cs() void qa_inband_usrp_server::test_rid() { + // FIXME This test is disabled because it hangs with the change to use usrp_standard_*_sptr's + return; + mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_T; diff --git a/usrp/host/lib/inband/usrp_usb_interface.cc b/usrp/host/lib/inband/usrp_usb_interface.cc index c69eb0b0..d82b589b 100644 --- a/usrp/host/lib/inband/usrp_usb_interface.cc +++ b/usrp/host/lib/inband/usrp_usb_interface.cc @@ -143,13 +143,9 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan connect("self", "rx_cs", "rx", "cs"); connect("self", "tx_cs", "tx", "cs"); - // FIX ME: the code should query the FPGA to retrieve the number of channels and such + // FIXME: the code should query the FPGA to retrieve the number of channels and such d_ntx_chan = 2; d_nrx_chan = 2; - - d_utx = NULL; - d_urx = NULL; - } usrp_usb_interface::~usrp_usb_interface() @@ -394,8 +390,6 @@ usrp_usb_interface::handle_cmd_write(pmt_t data) channel, pkts, tx_handle)); - - return; } /*! @@ -482,14 +476,13 @@ usrp_usb_interface::handle_cmd_close(pmt_t data) if (verbose) std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n"; - delete d_utx; - d_utx = 0; - - delete d_urx; - d_urx = 0; + d_utx.reset(); + d_urx.reset(); d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T)); + // FIXME This seems like a _very_ strange place to be calling shutdown_all. + // That decision should be left to high-level code, not low-level code like this. shutdown_all(PMT_T); } diff --git a/usrp/host/lib/inband/usrp_usb_interface.h b/usrp/host/lib/inband/usrp_usb_interface.h index 5151f155..c1074151 100644 --- a/usrp/host/lib/inband/usrp_usb_interface.h +++ b/usrp/host/lib/inband/usrp_usb_interface.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2007 Free Software Foundation, Inc. + * Copyright 2007,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -32,8 +32,8 @@ class usrp_usb_interface : public mb_mblock { public: - usrp_standard_tx* d_utx; - usrp_standard_rx* d_urx; + usrp_standard_tx_sptr d_utx; + usrp_standard_rx_sptr d_urx; mb_port_sptr d_cs; mb_port_sptr d_rx_cs; diff --git a/usrp/host/lib/legacy/Makefile.am b/usrp/host/lib/legacy/Makefile.am index d913b6bb..7b880924 100644 --- a/usrp/host/lib/legacy/Makefile.am +++ b/usrp/host/lib/legacy/Makefile.am @@ -32,11 +32,11 @@ libusrp_la_common_LIBADD = \ # darwin fusb requires omnithreads if FUSB_TECH_darwin -AM_CPPFLAGS = $(common_INCLUDES) $(OMNITHREAD_INCLUDES) $(WITH_INCLUDES) +AM_CPPFLAGS = $(common_INCLUDES) $(OMNITHREAD_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES) libusrp_la_LIBADD = $(libusrp_la_common_LIBADD) $(OMNITHREAD_LA) libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS) -framework CoreFoundation else -AM_CPPFLAGS = $(common_INCLUDES) $(WITH_INCLUDES) +AM_CPPFLAGS = $(common_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES) libusrp_la_LIBADD = $(libusrp_la_common_LIBADD) libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS) endif @@ -104,7 +104,20 @@ libusrp_la_common_SOURCES = \ usrp_dbid.cc \ usrp_local_sighandler.cc \ usrp_prims.cc \ - usrp_standard.cc + usrp_standard.cc \ + db_boards.cc \ + db_base.cc \ + db_basic.cc \ + db_tv_rx.cc \ + db_flexrf.cc \ + db_flexrf_mimo.cc \ + db_dbs_rx.cc \ + db_xcvr2450.cc \ + db_dtt754.cc \ + db_dtt768.cc \ + db_util.cc + +# db_wbx.cc if FUSB_TECH_generic @@ -128,22 +141,37 @@ libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE) endif include_HEADERS = \ + db_base.h \ usrp_basic.h \ usrp_bytesex.h \ usrp_config.h \ usrp_dbid.h \ usrp_prims.h \ usrp_slots.h \ - usrp_standard.h + usrp_standard.h \ + usrp_subdev_spec.h \ + usrp_tune_result.h noinst_HEADERS = \ ad9862.h \ + db_base_impl.h \ + db_basic.h \ + db_boards.h \ + db_dbs_rx.h \ + db_dtt754.h \ + db_dtt768.h \ + db_flexrf.h \ + db_flexrf_mimo.h \ + db_tv_rx.h \ + db_util.h \ + db_wbx.h \ + db_xcvr2450.h \ fusb.h \ fusb_darwin.h \ - fusb_win32.h \ fusb_generic.h \ fusb_linux.h \ fusb_ra_wb.h \ + fusb_win32.h \ md5.h \ rate_to_regval.h \ usrp_local_sighandler.h @@ -159,5 +187,7 @@ noinst_PYTHON = \ usrp_dbid.py usrp_dbid.h usrp_dbid.cc: gen_usrp_dbid.py usrp_dbid.dat PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat +swiginclude_HEADERS = db_base.i + MOSTLYCLEANFILES = \ $(BUILT_SOURCES) *~ *.pyc diff --git a/usrp/host/lib/legacy/db_base.cc b/usrp/host/lib/legacy/db_base.cc new file mode 100644 index 00000000..9d970435 --- /dev/null +++ b/usrp/host/lib/legacy/db_base.cc @@ -0,0 +1,245 @@ +// +// Copyright 2008 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 asversion 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. +// + +#include +#include + +#if 0 +tune_result::tune_result(double baseband, double dxc, double residual, bool inv) + : ok(false), baseband_freq(baseband), dxc_freq(dxc), + residual_freq(residual), inverted(inv) +{ +} + +tune_result::~tune_result() +{ +} +#endif + + +/*****************************************************************************/ + +db_base::db_base(usrp_basic_sptr usrp, int which) + : d_is_shutdown(false), d_raw_usrp(usrp.get()), d_which(which), d_lo_offset(0.0) +{ +} + +db_base::~db_base() +{ + shutdown(); +} + +void +db_base::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + } +} + +int +db_base::dbid() +{ + return usrp()->daughterboard_id(d_which); +} + +std::string +db_base::name() +{ + return usrp_dbid_to_string(dbid()); +} + +std::string +db_base::side_and_name() +{ + if(d_which == 0) + return "A: " + name(); + else + return "B: " + name(); +} + +// Function to bypass ADC buffers. Any board which is DC-coupled +// should bypass the buffers + +bool +db_base::bypass_adc_buffers(bool bypass) +{ + //if(d_tx) { + // throw std::runtime_error("TX Board has no adc buffers\n"); + //} + + bool ok = true; + if(d_which==0) { + ok &= usrp()->set_adc_buffer_bypass(0, bypass); + ok &= usrp()->set_adc_buffer_bypass(1, bypass); + } + else { + ok &= usrp()->set_adc_buffer_bypass(2, bypass); + ok &= usrp()->set_adc_buffer_bypass(3, bypass); + } + return ok; +} + +bool +db_base::set_atr_mask(int v) +{ + // Set Auto T/R mask. + return usrp()->write_atr_mask(d_which, v); +} + +bool +db_base::set_atr_txval(int v) +{ + // Set Auto T/R register value to be used when transmitting. + return usrp()->write_atr_txval(d_which, v); +} + +bool +db_base::set_atr_rxval(int v) +{ + // Set Auto T/R register value to be used when receiving. + return usrp()->write_atr_rxval(d_which, v); +} + +bool +db_base::set_atr_tx_delay(int v) +{ + // Set Auto T/R delay (in clock ticks) from when Tx fifo gets data to + // when T/R switches. + return usrp()->write_atr_tx_delay(v); +} + +bool +db_base::set_atr_rx_delay(int v) +{ + // Set Auto T/R delay (in clock ticks) from when Tx fifo goes empty to + // when T/R switches. + return usrp()->write_atr_rx_delay(v); +} + +bool +db_base::i_and_q_swapped() +{ + // Return True if this is a quadrature device and (for RX) ADC 0 is Q + // or (for TX) DAC 0 is Q + return false; +} + +bool +db_base::spectrum_inverted() +{ + // Return True if the dboard gives an inverted spectrum + + return false; +} + +bool +db_base::set_enable(bool on) +{ + // For tx daughterboards, this controls the transmitter enable. + + return true; // default is nop +} + +bool +db_base::set_auto_tr(bool on) +{ + // Enable automatic Transmit/Receive switching (ATR). + // + // Should be overridden in subclasses that care. This will typically + // set the atr_mask, txval and rxval. + + return true; +} + +bool +db_base::set_lo_offset(double offset) +{ + // Set how much LO is offset from requested frequency + + d_lo_offset = offset; + return true; +} + +bool +db_base::select_rx_antenna(int which_antenna) +{ + // Specify which antenna port to use for reception. + // Should be overriden by daughterboards that care. + + return which_antenna == 0; +} + +bool +db_base::select_rx_antenna(const std::string &which_antenna) +{ + // Specify which antenna port to use for reception. + // Should be overriden by daughterboards that care. + + return which_antenna == ""; +} + + +// Reference Clock section +// +// Control whether a reference clock is sent to the daughterboards, +// and what frequency +// +// Bit 7 -- 1 turns on refclk, 0 allows IO use +// Bits 6:0 Divider value +// + +double +db_base::_refclk_freq() +{ + return usrp()->fpga_master_clock_freq() / _refclk_divisor(); +} + +void +db_base::_enable_refclk(bool enable) +{ + int CLOCK_OUT = 1; // Clock is on lowest bit + int REFCLK_ENABLE = 0x80; + int REFCLK_DIVISOR_MASK = 0x7f; + + if(enable) { + usrp()->_write_oe(d_which, CLOCK_OUT, CLOCK_OUT); // output enable + usrp()->write_refclk(d_which, (_refclk_divisor() & REFCLK_DIVISOR_MASK) | REFCLK_ENABLE); + } + else { + usrp()->write_refclk(d_which, 0); + } +} + +int +db_base::_refclk_divisor() +{ + // Return value to stick in REFCLK_DIVISOR register + throw std::runtime_error("_reflck_divisor() called from base class\n");; +} + + +std::ostream &operator<<(std::ostream &os, db_base &x) +{ + os << x.side_and_name(); + return os; +} diff --git a/usrp/host/lib/legacy/db_base.h b/usrp/host/lib/legacy/db_base.h new file mode 100644 index 00000000..ff0a412e --- /dev/null +++ b/usrp/host/lib/legacy/db_base.h @@ -0,0 +1,114 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. +// + +#ifndef INCLUDED_DB_BASE_H +#define INCLUDED_DB_BASE_H + +#include +#include +#include +#include + +class db_base; +typedef boost::shared_ptr db_base_sptr; + +class usrp_basic; +typedef boost::shared_ptr usrp_basic_sptr; + +struct freq_result_t +{ + bool ok; + double baseband_freq; +}; + +/******************************************************************************/ + +class db_base +{ + protected: + bool d_is_shutdown; + usrp_basic *d_raw_usrp; + int d_which; + double d_lo_offset; + + void _enable_refclk(bool enable); + virtual double _refclk_freq(); + virtual int _refclk_divisor(); + + usrp_basic *usrp(){ + return d_raw_usrp; + } + + public: + db_base(boost::shared_ptr usrp, int which); + virtual ~db_base(); + + int dbid(); + std::string name(); + std::string side_and_name(); + int which() { return d_which; } + + bool bypass_adc_buffers(bool bypass); + bool set_atr_mask(int v); + bool set_atr_txval(int v); + bool set_atr_rxval(int v); + bool set_atr_tx_delay(int v); + bool set_atr_rx_delay(int v); + bool set_lo_offset(double offset); + double lo_offset() { return d_lo_offset; } + + + //////////////////////////////////////////////////////// + // derived classes should override the following methods + +protected: + friend class usrp_basic; + + /*! + * Called to shutdown daughterboard. Called from dtor and usrp_basic dtor. + * + * N.B., any class that overrides shutdown MUST call shutdown in its destructor. + */ + virtual void shutdown(); + + +public: + virtual float gain_min() = 0; + virtual float gain_max() = 0; + virtual float gain_db_per_step() = 0; + virtual double freq_min() = 0; + virtual double freq_max() = 0; + virtual struct freq_result_t set_freq(double target_freq) = 0; + virtual bool set_gain(float gain) = 0; + virtual bool is_quadrature() = 0; + virtual bool i_and_q_swapped(); + virtual bool spectrum_inverted(); + virtual bool set_enable(bool on); + virtual bool set_auto_tr(bool on); + virtual bool select_rx_antenna(int which_antenna); + virtual bool select_rx_antenna(const std::string &which_antenna); +}; + + +std::ostream & operator<<(std::ostream &os, db_base &x); + +#endif /* INCLUDED_DB_BASE_H */ diff --git a/usrp/host/lib/legacy/db_base.i b/usrp/host/lib/legacy/db_base.i new file mode 100644 index 00000000..36bb59a7 --- /dev/null +++ b/usrp/host/lib/legacy/db_base.i @@ -0,0 +1,101 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. +// + + +%{ +#include "db_base.h" +%} + +%include + +class usrp_tune_result +{ +public: + usrp_tune_result(double baseband=0, double dxc=0, + double residual=0, bool inv=0); + ~usrp_tune_result(); + + double baseband_freq; + double dxc_freq; + double residual_freq; + bool inverted; +}; + +struct freq_result_t +{ + bool ok; + double baseband_freq; +}; + +class db_base +{ + private: + db_base(boost::shared_ptr usrp, int which); + + public: + virtual ~db_base(); + + int dbid(); + std::string name(); + std::string side_and_name(); + int which() { return d_which; } + + bool bypass_adc_buffers(bool bypass); + bool set_atr_mask(int v); + bool set_atr_txval(int v); + bool set_atr_rxval(int v); + bool set_atr_tx_delay(int v); + bool set_atr_rx_delay(int v); + bool set_lo_offset(double offset); + double lo_offset() { return d_lo_offset; } + + virtual float gain_min() = 0; + virtual float gain_max() = 0; + virtual float gain_db_per_step() = 0; + virtual double freq_min() = 0; + virtual double freq_max() = 0; + virtual struct freq_result_t set_freq(double target_freq) = 0; + virtual bool set_gain(float gain) = 0; + virtual bool is_quadrature() = 0; + virtual bool i_and_q_swapped(); + virtual bool spectrum_inverted(); + virtual bool set_enable(bool on); + virtual bool set_auto_tr(bool on); + virtual bool select_rx_antenna(int which_antenna); + virtual bool select_rx_antenna(const std::string &antenna); +}; + +// Create templates for db's, vectors of db's, and vector of vectors of db's +typedef boost::shared_ptr db_base_sptr; +%template(db_base_sptr) boost::shared_ptr; +%template(db_base_sptr_vector) std::vector; +%template(db_base_sptr_vector_vector) std::vector >; + +// Set better class name in Python +// Enable freq_range and gain_range from public methods of class not implemented in C++ +// And create a dummy wrapper for backwards compatability with some of the example code +%pythoncode %{ + db_base_sptr.__repr__ = lambda self: "" % (self.name(),) + db_base_sptr.freq_range = lambda self: (self.freq_min(), self.freq_max(), 1) + db_base_sptr.gain_range = lambda self: (self.gain_min(), self.gain_max(), self.gain_db_per_step()) + +%} diff --git a/usrp/host/lib/legacy/db_base_impl.h b/usrp/host/lib/legacy/db_base_impl.h new file mode 100644 index 00000000..bb4d95d7 --- /dev/null +++ b/usrp/host/lib/legacy/db_base_impl.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_DB_BASE_IMPL_H +#define INCLUDED_DB_BASE_IMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* INCLUDED_DB_BASE_IMPL_H */ diff --git a/usrp/host/lib/legacy/db_basic.cc b/usrp/host/lib/legacy/db_basic.cc new file mode 100644 index 00000000..9c37c438 --- /dev/null +++ b/usrp/host/lib/legacy/db_basic.cc @@ -0,0 +1,263 @@ +// +// Copyright 2008 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 asversion 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. + +#include +#include + + +db_basic_tx::db_basic_tx(boost::shared_ptr usrp, int which) + : db_base(usrp, which) +{ + // Handler for Basic Tx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively + + set_gain((gain_min() + gain_max()) / 2); // initialize gain +} + +db_basic_tx::~db_basic_tx() +{ +} + +double +db_basic_tx::freq_min() +{ + return -90e9; +} + +double +db_basic_tx::freq_max() +{ + return 90e9; +} + +struct freq_result_t +db_basic_tx::set_freq(double target_freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + + struct freq_result_t args = {false, 0}; + args.ok = true; + args.baseband_freq = 0.0; + return args; +} + +float +db_basic_tx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_basic_tx::gain_max() +{ + return usrp()->pga_max(); +} + +float +db_basic_tx::gain_db_per_step() +{ + return usrp()->pga_db_per_step(); +} + +bool +db_basic_tx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + bool ok = usrp()->set_pga(d_which * 2 + 0, gain); + ok = ok && usrp()->set_pga(d_which * 2 + 1, gain); + return ok; +} + +bool +db_basic_tx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + + return true; +} + + +/******************************************************************************/ + + +db_basic_rx::db_basic_rx(usrp_basic_sptr usrp, int which, int subdev) + : db_base(usrp, which) +{ + // Handler for Basic Rx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively + // @param subdev: which analog i/o channel: 0 or 1 + // @type subdev: int + + d_subdev = subdev; + + bypass_adc_buffers(true); + + if(0) { // Doing this would give us a different default than the historical values... + set_gain(float(gain_min() + gain_max()) / 2.0); // initialize gain + } +} + +db_basic_rx::~db_basic_rx() +{ +} + +double +db_basic_rx::freq_min() +{ + return -90e9; +} + +double +db_basic_rx::freq_max() +{ + return 90e9; +} + +struct freq_result_t +db_basic_rx::set_freq(double target_freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + + struct freq_result_t args = {true, 0.0}; + return args; +} + +float +db_basic_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_basic_rx::gain_max() +{ + return usrp()->pga_max(); +} + +float +db_basic_rx::gain_db_per_step() +{ + return usrp()->pga_db_per_step(); +} + +bool +db_basic_rx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + return usrp()->set_pga(d_which * 2 + d_subdev, gain); +} + +bool +db_basic_rx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + + // This bit of info is useful when setting up the USRP Rx mux register. + + return false; +} + + + +/******************************************************************************/ + + +db_lf_tx::db_lf_tx(usrp_basic_sptr usrp, int which) + : db_basic_tx(usrp, which) +{ + // Handler for Low Freq Tx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively +} + +db_lf_tx::~db_lf_tx() +{ +} + +double +db_lf_tx::freq_min() +{ + return -32e6; +} + +double +db_lf_tx::freq_max() +{ + return 32e6; +} + +/******************************************************************************/ + + +db_lf_rx::db_lf_rx(usrp_basic_sptr usrp, int which, int subdev) + : db_basic_rx(usrp, which, subdev) +{ + // Handler for Low Freq Rx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively + // @param subdev: which analog i/o channel: 0 or 1 + // @type subdev: int +} + +db_lf_rx::~db_lf_rx() +{ +} + +double +db_lf_rx::freq_min() +{ + return 0.0; +} + +double +db_lf_rx::freq_max() +{ + return 32e6; +} + + diff --git a/usrp/host/lib/legacy/db_basic.h b/usrp/host/lib/legacy/db_basic.h new file mode 100644 index 00000000..4dd92b99 --- /dev/null +++ b/usrp/host/lib/legacy/db_basic.h @@ -0,0 +1,99 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_BASIC_H +#define DB_BASIC_H + +#include + + +/******************************************************************************/ + + +class db_basic_tx : public db_base +{ +public: + db_basic_tx(usrp_basic_sptr usrp, int which); + ~db_basic_tx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + bool set_gain(float gain); + bool is_quadrature(); +}; + + +/******************************************************************************/ + + +class db_basic_rx : public db_base +{ + public: + db_basic_rx(usrp_basic_sptr usrp, int which, int subdev); + ~db_basic_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + bool set_gain(float gain); + bool is_quadrature(); + +private: + int d_subdev; +}; + + +/******************************************************************************/ + + +class db_lf_rx : public db_basic_rx +{ + public: + db_lf_rx(usrp_basic_sptr usrp, int which, int subdev); + ~db_lf_rx(); + + double freq_min(); + double freq_max(); +}; + + +/******************************************************************************/ + + +class db_lf_tx : public db_basic_tx +{ + public: + db_lf_tx(usrp_basic_sptr usrp, int which); + ~db_lf_tx(); + + double freq_min(); + double freq_max(); +}; + + +#endif diff --git a/usrp/host/lib/legacy/db_boards.cc b/usrp/host/lib/legacy/db_boards.cc new file mode 100644 index 00000000..1ba8b0e7 --- /dev/null +++ b/usrp/host/lib/legacy/db_boards.cc @@ -0,0 +1,215 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::vector +instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) +{ + std::vector db; + + switch(dbid) { + + case(USRP_DBID_BASIC_TX): + db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); + break; + + case(USRP_DBID_BASIC_RX): + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); + break; + + case(USRP_DBID_LF_TX): + db.push_back(db_base_sptr(new db_lf_tx(usrp, which_side))); + break; + + case(USRP_DBID_LF_RX): + db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 1))); + break; + + case(USRP_DBID_DBS_RX): + db.push_back(db_base_sptr(new db_dbs_rx(usrp, which_side))); + break; + + case(USRP_DBID_TV_RX): + db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 43.75e6, 5.75e6))); + break; + case(USRP_DBID_TV_RX_REV_2): + db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 44e6, 20e6))); + break; + case(USRP_DBID_TV_RX_REV_3): + db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 44e6, 20e6))); + break; + + case(USRP_DBID_FLEX_2400_TX): + db.push_back(db_base_sptr(new db_flexrf_2400_tx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_2400_RX): + db.push_back(db_base_sptr(new db_flexrf_2400_rx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1200_TX): + db.push_back(db_base_sptr(new db_flexrf_1200_tx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1200_RX): + db.push_back(db_base_sptr(new db_flexrf_1200_rx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1800_TX): + db.push_back(db_base_sptr(new db_flexrf_1800_tx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1800_RX): + db.push_back(db_base_sptr(new db_flexrf_1800_rx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_900_TX): + db.push_back(db_base_sptr(new db_flexrf_900_tx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_900_RX): + db.push_back(db_base_sptr(new db_flexrf_900_rx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_400_TX): + db.push_back(db_base_sptr(new db_flexrf_400_tx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_400_RX): + db.push_back(db_base_sptr(new db_flexrf_400_rx(usrp, which_side))); + break; + case(USRP_DBID_FLEX_2400_TX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_2400_tx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_2400_RX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_2400_rx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1800_TX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_1800_tx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1800_RX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_1800_rx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1200_TX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_1200_tx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1200_RX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_1200_rx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_900_TX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_900_tx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_900_RX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_900_rx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_400_TX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_400_tx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_400_RX_MIMO_A): + db.push_back(db_base_sptr(new db_flexrf_400_rx_mimo_a(usrp, which_side))); + break; + case(USRP_DBID_FLEX_2400_TX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_2400_tx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_2400_RX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_2400_rx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1800_TX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_1800_tx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1800_RX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_1800_rx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1200_TX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_1200_tx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_1200_RX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_1200_rx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_900_TX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_900_tx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_900_RX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_900_rx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_400_TX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_400_tx_mimo_b(usrp, which_side))); + break; + case(USRP_DBID_FLEX_400_RX_MIMO_B): + db.push_back(db_base_sptr(new db_flexrf_400_rx_mimo_b(usrp, which_side))); + break; + + case(USRP_DBID_XCVR2450_TX): + db.push_back(db_base_sptr(new db_xcvr2450_tx(usrp, which_side))); + break; + case(USRP_DBID_XCVR2450_RX): + db.push_back(db_base_sptr(new db_xcvr2450_rx(usrp, which_side))); + break; + +#if 0 // FIXME wbx doesn't compile + case(USRP_DBID_WBX_LO_TX): + db.push_back(db_base_sptr(new db_wbx_lo_tx(usrp, which_side))); + break; + case(USRP_DBID_WBX_LO_RX): + db.push_back(db_base_sptr(new db_wbx_lo_rx(usrp, which_side))); + break; +#endif + + case(USRP_DBID_DTT754): + db.push_back(db_base_sptr(new db_dtt754(usrp, which_side))); + break; + case(USRP_DBID_DTT768): + db.push_back(db_base_sptr(new db_dtt768(usrp, which_side))); + break; + + case(-1): + if (boost::dynamic_pointer_cast(usrp)){ + db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); + } + else { + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); + } + break; + + case(-2): + default: + if (boost::dynamic_pointer_cast(usrp)){ + fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Tx.\"\n"); + fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n"); + db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); + } + else { + fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Rx.\"\n"); + fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n"); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); + } + break; + } + + return db; +} diff --git a/usrp/host/lib/legacy/db_boards.h b/usrp/host/lib/legacy/db_boards.h new file mode 100644 index 00000000..037c4603 --- /dev/null +++ b/usrp/host/lib/legacy/db_boards.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. +// + +#ifndef DB_BOARDS_H +#define DB_BOARDS_H + +#include +#include + +std::vector instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side); + +#endif + + diff --git a/usrp/host/lib/legacy/db_dbs_rx.cc b/usrp/host/lib/legacy/db_dbs_rx.cc new file mode 100644 index 00000000..5f3b32f9 --- /dev/null +++ b/usrp/host/lib/legacy/db_dbs_rx.cc @@ -0,0 +1,491 @@ +// +// Copyright 2008 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 asversion 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. + +#include +#include +#include + + +/*****************************************************************************/ + + +db_dbs_rx::db_dbs_rx(usrp_basic_sptr _usrp, int which) + : db_base(_usrp, which) +{ + // Control DBS receiver based USRP daughterboard. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively + + usrp()->_write_oe(d_which, 0x0001, 0x0001); + if(which == 0) { + d_i2c_addr = 0x67; + } + else { + d_i2c_addr = 0x65; + } + + d_n = 950; + d_div2 = 0; + d_osc = 5; + d_cp = 3; + d_r = 4; + d_r_int = 1; + d_fdac = 127; + d_m = 2; + d_dl = 0; + d_ade = 0; + d_adl = 0; + d_gc1 = 0; + d_gc2 = 31; + d_diag = 0; + + _enable_refclk(true); + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain + + bypass_adc_buffers(true); +} + +db_dbs_rx::~db_dbs_rx() +{ + shutdown(); +} + +void +db_dbs_rx::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown orderly + _enable_refclk(false); + } +} + +void +db_dbs_rx::_write_reg (int regno, int v) +{ + //regno is in [0,5], v is value to write to register""" + assert (0 <= regno && regno <= 5); + std::vector args(2); + args[0] = regno; + args[1] = v; + usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args)); +} + +void +db_dbs_rx::_write_regs (int starting_regno, const std::vector &vals) +{ + // starting_regno is in [0,5], + // vals is a seq of integers to write to consecutive registers""" + + //FIXME + std::vector args; + args.push_back(starting_regno); + args.insert(args.end(), vals.begin(), vals.end()); + usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args)); +} + +std::vector +db_dbs_rx::_read_status () +{ + //If successful, return list of two ints: [status_info, filter_DAC]""" + std::string s = usrp()->read_i2c (d_i2c_addr, 2); + if(s.size() != 2) { + std::vector ret(0); + return ret; + } + return str_to_int_seq (s); +} + +void +db_dbs_rx::_send_reg(int regno) +{ + assert(0 <= regno && regno <= 5); + if(regno == 0) + _write_reg(0,(d_div2<<7) + (d_n>>8)); + if(regno == 1) + _write_reg(1,d_n & 255); + if(regno == 2) + _write_reg(2,d_osc + (d_cp<<3) + (d_r_int<<5)); + if(regno == 3) + _write_reg(3,d_fdac); + if(regno == 4) + _write_reg(4,d_m + (d_dl<<5) + (d_ade<<6) + (d_adl<<7)); + if(regno == 5) + _write_reg(5,d_gc2 + (d_diag<<5)); +} + +// BW setting +void +db_dbs_rx::_set_m(int m) +{ + assert(m>0 && m<32); + d_m = m; + _send_reg(4); +} + +void +db_dbs_rx::_set_fdac(int fdac) +{ + assert(fdac>=0 && fdac<128); + d_fdac = fdac; + _send_reg(3); +} + +struct bw_t +db_dbs_rx::set_bw (float bw) +{ + assert(bw>=1e6 && bw<=33e6); + + struct bw_t ret = {0, 0, 0}; + int m_max, m_min, m_test, fdac_test; + if(bw >= 4e6) + m_max = int(std::min(31, (int)floor(_refclk_freq()/1e6))); + else if(bw >= 2e6) // Outside of Specs! + m_max = int(std::min(31, (int)floor(_refclk_freq()/.5e6))); + else // Way outside of Specs! + m_max = int(std::min(31, (int)floor(_refclk_freq()/.25e6))); + + m_min = int(ceil(_refclk_freq()/2.5e6)); + m_test = m_max; + while(m_test >= m_min) { + fdac_test = static_cast(round(((bw * m_test / _refclk_freq())-4)/.145)); + if(fdac_test > 127) + m_test = m_test - 1; + else + break; + } + + if(m_test>=m_min && fdac_test>=0) { + _set_m(m_test); + _set_fdac(fdac_test); + + ret.m = d_m; + ret.fdac = d_fdac; + ret.div = _refclk_freq()/d_m*(4+0.145*d_fdac); + } + else { + fprintf(stderr, "Failed to set bw\n"); + } + return ret; +} + +// Gain setting +void +db_dbs_rx::_set_dl(int dl) +{ + assert(dl == 0 || dl == 1); + d_dl = dl; + _send_reg(4); +} + +void +db_dbs_rx::_set_gc2(int gc2) +{ + assert(gc2<32 && gc2>=0); + d_gc2 = gc2; + _send_reg(5); +} + +void +db_dbs_rx::_set_gc1(int gc1) +{ + assert(gc1>=0 && gc1<4096); + d_gc1 = gc1; + usrp()->write_aux_dac(d_which, 0, gc1); +} + +void +db_dbs_rx::_set_pga(int pga_gain) +{ + assert(pga_gain>=0 && pga_gain<=20); + if(d_which == 0) { + usrp()->set_pga (0, pga_gain); + usrp()->set_pga (1, pga_gain); + } + else { + usrp()->set_pga (2, pga_gain); + usrp()->set_pga (3, pga_gain); + } +} + +float +db_dbs_rx::gain_min() +{ + return 0; +} + +float +db_dbs_rx::gain_max() +{ + return 104; +} + +float +db_dbs_rx::gain_db_per_step() +{ + return 1; +} + +bool +db_dbs_rx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + if(!(gain>=0 && gain<105)) { + throw std::runtime_error("gain out of range\n"); + } + + int gc1=0, gc2=0, dl=0, pga=0; + + if(gain < 56) { + gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3); + gain = 0; + } + else { + gc1 = 0; + gain -= 56; + } + + if(gain < 24) { + gc2 = static_cast(round(31.0 * (1-gain/24.0))); + gain = 0; + } + else { + gc2 = 0; + gain -=24; + } + + if(gain >= 4.58) { + dl = 1; + gain -= 4.58; + } + + pga = gain; + _set_gc1(gc1); + _set_gc2(gc2); + _set_dl(dl); + _set_pga(pga); + + return true; +} + +// Frequency setting +void +db_dbs_rx::_set_osc(int osc) +{ + assert(osc>=0 && osc<8); + d_osc = osc; + _send_reg(2); +} + +void +db_dbs_rx::_set_cp(int cp) +{ + assert(cp>=0 && cp<4); + d_cp = cp; + _send_reg(2); +} + +void +db_dbs_rx::_set_n(int n) +{ + assert(n>256 && n<32768); + d_n = n; + _send_reg(0); + _send_reg(1); +} + +void +db_dbs_rx::_set_div2(int div2) +{ + assert(div2 == 0 || div2 == 1); + d_div2 = div2; + _send_reg(0); +} + +void +db_dbs_rx::_set_r(int r) +{ + assert(r>=0 && r<128); + d_r = r; + d_r_int = static_cast(round(log10(r)/log10(2)) - 1); + _send_reg(2); +} + +// FIXME How do we handle ADE and ADL properly? +void +db_dbs_rx::_set_ade(int ade) +{ + assert(ade == 0 || ade == 1); + d_ade = ade; + _send_reg(4); +} + +double +db_dbs_rx::freq_min() +{ + return 500e6; +} + +double +db_dbs_rx::freq_max() +{ + return 2.6e9; +} + +struct freq_result_t +db_dbs_rx::set_freq(double freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is RF frequency that corresponds to DC in the IF. + + freq_result_t args = {false, 0}; + + if(!(freq>=freq_min() && freq<=freq_max())) { + return args; + } + + double vcofreq; + if(freq<1150e6) { + _set_div2(0); + vcofreq = 4 * freq; + } + else { + _set_div2(1); + vcofreq = 2 * freq; + } + + _set_ade(1); + int rmin = std::max(2, (int)(_refclk_freq()/2e6)); + int rmax = std::min(128, (int)(_refclk_freq()/500e3)); + int r = 2; + int n = 0; + int best_r = 2; + int best_n = 0; + int best_delta = 10e6; + int delta; + + while(r <= rmax) { + n = static_cast(round(freq/(_refclk_freq()/r))); + if(r(round(best_n))); + + int vco; + if(vcofreq < 2433e6) + vco = 0; + else if(vcofreq < 2711e6) + vco=1; + else if(vcofreq < 3025e6) + vco=2; + else if(vcofreq < 3341e6) + vco=3; + else if(vcofreq < 3727e6) + vco=4; + else if(vcofreq < 4143e6) + vco=5; + else if(vcofreq < 4493e6) + vco=6; + else + vco=7; + + _set_osc(vco); + + // Set CP current + int adc_val = 0; + std::vector bytes(2); + while(adc_val == 0 || adc_val == 7) { + bytes = _read_status(); + adc_val = bytes[0] >> 2; + if(adc_val == 0) { + if(vco <= 0) { + return args; + } + else { + vco = vco - 1; + } + } + else if(adc_val == 7) { + if(vco >= 7) { + return args; + } + else { + vco = vco + 1; + } + } + _set_osc(vco); + } + + if(adc_val == 1 || adc_val == 2) { + _set_cp(1); + } + else if(adc_val == 3 || adc_val == 4) { + _set_cp(2); + } + else { + _set_cp(3); + } + + args.ok = true; + args.baseband_freq = d_n * _refclk_freq() / d_r; + return args; +} + +int +db_dbs_rx::_refclk_divisor() +{ + //Return value to stick in REFCLK_DIVISOR register + return 16; +} + +bool +db_dbs_rx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + return true; +} diff --git a/usrp/host/lib/legacy/db_dbs_rx.h b/usrp/host/lib/legacy/db_dbs_rx.h new file mode 100644 index 00000000..f3348af8 --- /dev/null +++ b/usrp/host/lib/legacy/db_dbs_rx.h @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_DBS_RX_H +#define DB_DBS_RX_H + +#include +#include + +struct bw_t { + int m; + int fdac; + float div; +}; + +class db_dbs_rx : public db_base +{ +private: + int d_osc, d_cp, d_n, d_div2, d_r, d_r_int; + int d_fdac, d_m, d_dl, d_ade, d_adl, d_gc1, d_gc2, d_diag; + int d_i2c_addr; + + // Internal gain functions + void _write_reg(int regno, int v); + void _write_regs(int starting_regno, const std::vector &vals); + std::vector _read_status(); + void _send_reg(int regno); + void _set_m(int m); + void _set_fdac(int fdac); + bw_t set_bw(float bw); + void _set_dl(int dl); + void _set_gc2(int gc2); + void _set_gc1(int gc1); + void _set_pga(int pga_gain); + + // Internal frequency function + void _set_osc(int osc); + void _set_cp(int cp); + void _set_n(int n); + void _set_div2(int div2); + void _set_r(int r); + void _set_ade(int ade); + + int _refclk_divisor(); + +protected: + void shutdown(); + +public: + db_dbs_rx(usrp_basic_sptr usrp, int which); + ~db_dbs_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double freq); + bool set_gain(float gain); + bool is_quadrature(); +}; + +#endif diff --git a/usrp/host/lib/legacy/db_dtt754.cc b/usrp/host/lib/legacy/db_dtt754.cc new file mode 100644 index 00000000..39f8c3f9 --- /dev/null +++ b/usrp/host/lib/legacy/db_dtt754.cc @@ -0,0 +1,321 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#include +#include + +int +control_byte_1() +{ + int RS = 0; // 0 = 166.66kHz reference + int ATP = 7; // Disable internal AGC + return (0x80 | ATP<<3 | RS); +} + +int +control_byte_2() +{ + int STBY = 0; // powered on + int XTO = 1; // turn off xtal out, which we don't have + int ATC = 0; // not clear exactly, possibly speeds up or slows down AGC, which we are not using + + int c = 0xc2 | ATC<<5 | STBY<<4 | XTO; + return c; +} + +int +bandswitch_byte(float freq, float bw) +{ + int P5, CP, BS; + + if(bw>7.5e6) { + P5 = 1; + } + else { + P5 = 0; + } + + if(freq < 121e6) { + CP = 0; + BS = 1; + } + else if(freq < 141e6) { + CP = 1; + BS = 1; + } + else if(freq < 166e6) { + CP = 2; + BS = 1; + } + else if(freq < 182e6) { + CP = 3; + BS = 1; + } + else if(freq < 286e6) { + CP = 0; + BS = 2; + } + else if(freq < 386e6) { + CP = 1; + BS = 2; + } + else if(freq < 446e6) { + CP = 2; + BS = 2; + } + else if(freq < 466e6) { + CP = 3; + BS = 2; + } + else if(freq < 506e6) { + CP = 0; + BS = 8; + } + else if(freq < 761e6) { + CP = 1; + BS = 8; + } + else if(freq < 846e6) { + CP = 2; + BS = 8; + } + else { // limit is ~905 MHz + CP = 3; + BS = 8; + } + return (CP<<6 | P5 << 4 | BS); +} + +db_dtt754::db_dtt754(usrp_basic_sptr _usrp, int which) + : db_base(_usrp, which) +{ + /* + * Control custom DTT75403-based daughterboard. + * + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively + * @type which: int + */ + + // FIXME: DTT754 and DTT768 can probably inherit from a DTT class + + if(d_which == 0) { + d_i2c_addr = 0x60; + } + else { + d_i2c_addr = 0x62; + } + + d_bw = 7e6; + d_IF = 36e6; + + d_f_ref = 166.6666e3; + d_inverted = false; + + set_gain((gain_min() + gain_max()) / 2.0); + + bypass_adc_buffers(false); +} + +db_dtt754::~db_dtt754() +{ +} + +float +db_dtt754::gain_min() +{ + return 0; +} + +float +db_dtt754::gain_max() +{ + return 115; +} + +float +db_dtt754::gain_db_per_step() +{ + return 1; +} + +bool +db_dtt754::set_gain(float gain) +{ + assert(gain>=0 && gain<=115); + + float rfgain, ifgain, pgagain; + if(gain > 60) { + rfgain = 60; + gain = gain - 60; + } + else { + rfgain = gain; + gain = 0; + } + + if(gain > 35) { + ifgain = 35; + gain = gain - 35; + } + else { + ifgain = gain; + gain = 0; + } + pgagain = gain; + + _set_rfagc(rfgain); + _set_ifagc(ifgain); + _set_pga(pgagain); + + return true; // can't fail with the assert in place +} + +double +db_dtt754::freq_min() +{ + return 44e6; +} + +double +db_dtt754::freq_max() +{ + return 900e6; +} + +struct freq_result_t +db_dtt754::set_freq(double target_freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + freq_result_t ret = {false, 0.0}; + + if(target_freq < freq_min() || target_freq > freq_max()) { + return ret; + } + + double target_lo_freq = target_freq + d_IF; // High side mixing + + int divisor = (int)(0.5+(target_lo_freq / d_f_ref)); + double actual_lo_freq = d_f_ref*divisor; + + if((divisor & ~0x7fff) != 0) { // must be 15-bits or less + return ret; + } + + // build i2c command string + std::vector buf(5); + buf[0] = (divisor >> 8) & 0xff; // DB1 + buf[1] = divisor & 0xff; // DB2 + buf[2] = control_byte_1(); + buf[3] = bandswitch_byte(actual_lo_freq, d_bw); + buf[4] = control_byte_2(); + + bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); + + d_freq = actual_lo_freq - d_IF; + + ret.ok = ok; + ret.baseband_freq = actual_lo_freq; + + return ret; + +} + +bool +db_dtt754::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + + return false; +} + +bool +db_dtt754::spectrum_inverted() +{ + /* + * The 43.75 MHz version is inverted + */ + + return d_inverted; +} + +void +db_dtt754::set_bw(float bw) +{ + /* + * Choose the SAW filter bandwidth, either 7MHz or 8MHz) + */ + + d_bw = bw; + set_freq(d_freq); +} + +void +db_dtt754::_set_rfagc(float gain) +{ + assert(gain <= 60 && gain >= 0); + // FIXME this has a 0.5V step between gain = 60 and gain = 59. + // Why are there two cases instead of a single linear case? + float voltage; + if(gain == 60) { + voltage = 4; + } + else { + voltage = gain/60.0 * 2.25 + 1.25; + } + + int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 1, dacword); +} + +void +db_dtt754::_set_ifagc(float gain) +{ + assert(gain <= 35 && gain >= 0); + float voltage = gain/35.0 * 2.1 + 1.4; + int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 0, dacword); +} + +void +db_dtt754::_set_pga(float pga_gain) +{ + assert(pga_gain >=0 && pga_gain <=20); + if(d_which == 0) { + usrp()->set_pga (0, pga_gain); + } + else { + usrp()->set_pga (2, pga_gain); + } +} diff --git a/usrp/host/lib/legacy/db_dtt754.h b/usrp/host/lib/legacy/db_dtt754.h new file mode 100644 index 00000000..93b9164e --- /dev/null +++ b/usrp/host/lib/legacy/db_dtt754.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_DTT754_H +#define DB_DTT754_H + +#include +#include + +class db_dtt754 : public db_base +{ +public: + db_dtt754(usrp_basic_sptr usrp, int which); + ~db_dtt754(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + + bool is_quadrature(); + bool spectrum_inverted(); + void set_bw(float bw); + +private: + void _set_rfagc(float gain); + void _set_ifagc(float gain); + void _set_pga(float pga_gain); + + int d_i2c_addr; + float d_bw, d_freq, d_IF, d_f_ref; + bool d_inverted; +}; + +#endif diff --git a/usrp/host/lib/legacy/db_dtt768.cc b/usrp/host/lib/legacy/db_dtt768.cc new file mode 100644 index 00000000..c2e9c982 --- /dev/null +++ b/usrp/host/lib/legacy/db_dtt768.cc @@ -0,0 +1,294 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#include +#include + +int +control_byte_4() +{ + int C = 0; // Charge Pump Current, no info on how to choose + int R = 4; // 125 kHz fref + + // int ATP = 7; // Disable internal AGC + return (0x80 | C<<5 | R); +} + +int +control_byte_5(float freq, int agcmode = 1) +{ + if(agcmode) { + if(freq < 150e6) { + return 0x3B; + } + else if(freq < 420e6) { + return 0x7E; + } + else { + return 0xB7; + } + } + else { + if(freq < 150e6) { + return 0x39; + } + else if(freq < 420e6) { + return 0x7C; + } + else { + return 0xB5; + } + } +} + +int +control_byte_6() +{ + int ATC = 0; // AGC time constant = 100ms, 1 = 3S + int IFE = 1; // IF AGC amplifier enable + int AT = 0; // AGC control, ??? + + return (ATC << 5 | IFE << 4 | AT); +} + +int +control_byte_7() +{ + int SAS = 1; // SAW Digital mode + int AGD = 1; // AGC disable + int ADS = 0; // AGC detector into ADC converter + int T = 0; // Test mode, undocumented + return (SAS << 7 | AGD << 5 | ADS << 4 | T); +} + +db_dtt768::db_dtt768(usrp_basic_sptr _usrp, int which) + : db_base(_usrp, which) +{ + /* + * Control custom DTT76803-based daughterboard. + * + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively + * @type which: int + */ + + if(d_which == 0) { + d_i2c_addr = 0x60; + } + else { + d_i2c_addr = 0x62; + } + + d_IF = 44e6; + + d_f_ref = 125e3; + d_inverted = false; + + set_gain((gain_min() + gain_max()) / 2.0); + + bypass_adc_buffers(false); +} + +db_dtt768::~db_dtt768() +{ +} + +float +db_dtt768::gain_min() +{ + return 0; +} + +float +db_dtt768::gain_max() +{ + return 115; +} + +float +db_dtt768::gain_db_per_step() +{ + return 1; +} + +bool +db_dtt768::set_gain(float gain) +{ + assert(gain>=0 && gain<=115); + + float rfgain, ifgain, pgagain; + if(gain > 60) { + rfgain = 60; + gain = gain - 60; + } + else { + rfgain = gain; + gain = 0; + } + + if(gain > 35) { + ifgain = 35; + gain = gain - 35; + } + else { + ifgain = gain; + gain = 0; + } + pgagain = gain; + + _set_rfagc(rfgain); + _set_ifagc(ifgain); + _set_pga(pgagain); + + return true; +} + +double +db_dtt768::freq_min() +{ + return 44e6; +} + +double +db_dtt768::freq_max() +{ + return 900e6; +} + +struct freq_result_t +db_dtt768::set_freq(double target_freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + freq_result_t ret = {false, 0.0}; + + if(target_freq < freq_min() || target_freq > freq_max()) { + return ret; + } + + double target_lo_freq = target_freq + d_IF; // High side mixing + + int divisor = (int)(0.5+(target_lo_freq / d_f_ref)); + double actual_lo_freq = d_f_ref*divisor; + + if((divisor & ~0x7fff) != 0) { // must be 15-bits or less + return ret; + } + + // build i2c command string + std::vector buf(6); + buf[0] = (divisor >> 8) & 0xff; // DB1 + buf[1] = divisor & 0xff; // DB2 + buf[2] = control_byte_4(); + buf[3] = control_byte_5(target_freq); + buf[4] = control_byte_6(); + buf[5] = control_byte_7(); + + bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); + + d_freq = actual_lo_freq - d_IF; + + ret.ok = ok; + ret.baseband_freq = actual_lo_freq; + + return ret; + +} + +bool +db_dtt768::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + + return false; +} + +bool +db_dtt768::spectrum_inverted() +{ + /* + * The 43.75 MHz version is inverted + */ + + return d_inverted; +} + +void +db_dtt768::set_bw(float bw) +{ + /* + * Choose the SAW filter bandwidth, either 7MHz or 8MHz) + */ + + d_bw = bw; + set_freq(d_freq); +} + +void +db_dtt768::_set_rfagc(float gain) +{ + assert(gain <= 60 && gain >= 0); + // FIXME this has a 0.5V step between gain = 60 and gain = 59. + // Why are there two cases instead of a single linear case? + float voltage; + if(gain == 60) { + voltage = 4; + } + else { + voltage = gain/60.0 * 2.25 + 1.25; + } + + int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 1, dacword); +} + +void +db_dtt768::_set_ifagc(float gain) +{ + assert(gain <= 35 && gain >= 0); + float voltage = gain/35.0 * 2.1 + 1.4; + int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 0, dacword); +} + +void +db_dtt768::_set_pga(float pga_gain) +{ + assert(pga_gain >=0 && pga_gain <=20); + if(d_which == 0) { + usrp()->set_pga (0, pga_gain); + } + else { + usrp()->set_pga (2, pga_gain); + } +} diff --git a/usrp/host/lib/legacy/db_dtt768.h b/usrp/host/lib/legacy/db_dtt768.h new file mode 100644 index 00000000..b5560437 --- /dev/null +++ b/usrp/host/lib/legacy/db_dtt768.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_DTT768_H +#define DB_DTT768_H + +#include +#include + +class db_dtt768 : public db_base +{ +public: + db_dtt768(usrp_basic_sptr usrp, int which); + ~db_dtt768(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + + bool is_quadrature(); + bool spectrum_inverted(); + void set_bw(float bw); + +private: + void _set_rfagc(float gain); + void _set_ifagc(float gain); + void _set_pga(float pga_gain); + + int d_i2c_addr; + float d_bw, d_freq, d_IF, d_f_ref; + bool d_inverted; +}; + +#endif diff --git a/usrp/host/lib/legacy/db_flexrf.cc b/usrp/host/lib/legacy/db_flexrf.cc new file mode 100644 index 00000000..662d9095 --- /dev/null +++ b/usrp/host/lib/legacy/db_flexrf.cc @@ -0,0 +1,1148 @@ +// +// Copyright 2008 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 asversion 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. + +#include +#include + +// d'board i/o pin defs +// Tx and Rx have shared defs, but different i/o regs +#define AUX_RXAGC (1 << 8) +#define POWER_UP (1 << 7) // enables power supply +#define RX_TXN (1 << 6) // Tx only: T/R antenna switch for TX/RX port +#define RX2_RX1N (1 << 6) // Rx only: antenna switch between RX2 and TX/RX port +#define ENABLE (1 << 5) // enables mixer +#define AUX_SEN (1 << 4) +#define AUX_SCLK (1 << 3) +#define PLL_LOCK_DETECT (1 << 2) +#define AUX_SDO (1 << 1) +#define CLOCK_OUT (1 << 0) + +flexrf_base::flexrf_base(usrp_basic_sptr _usrp, int which, int _power_on) + : db_base(_usrp, which), d_power_on(_power_on) +{ + /* + @param usrp: instance of usrp.source_c + @param which: which side: 0 or 1 corresponding to side A or B respectively + @type which: int + */ + + d_first = true; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs + _enable_refclk(false); // disable refclk + + set_auto_tr(false); +} + +flexrf_base::~flexrf_base() +{ + delete d_common; +} + +void +flexrf_base::_write_all(int R, int control, int N) +{ + /* + Write R counter latch, control latch and N counter latch to VCO. + + Adds 10ms delay between writing control and N if this is first call. + This is the required power-up sequence. + + @param R: 24-bit R counter latch + @type R: int + @param control: 24-bit control latch + @type control: int + @param N: 24-bit N counter latch + @type N: int + */ + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + + _write_R(R); + _write_control(control); + if(d_first) { + //time.sleep(0.010); + nanosleep(&t, NULL); + d_first = false; + } + _write_N(N); +} + +void +flexrf_base::_write_control(int control) +{ + _write_it((control & ~0x3) | 0); +} + +void +flexrf_base::_write_R(int R) +{ + _write_it((R & ~0x3) | 1); +} + +void +flexrf_base::_write_N(int N) +{ + _write_it((N & ~0x3) | 2); +} + +void +flexrf_base::_write_it(int v) +{ + char s[3]; + s[0] = (char)((v >> 16) & 0xff); + s[1] = (char)((v >> 8) & 0xff); + s[2] = (char)(v & 0xff); + std::string str(s, 3); + usrp()->_write_spi(0, d_spi_enable, d_spi_format, str); +} + +bool +flexrf_base::_lock_detect() +{ + /* + @returns: the value of the VCO/PLL lock detect bit. + @rtype: 0 or 1 + */ + if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { + return true; + } + else { // Give it a second chance + // FIXME: make portable sleep + timespec t; + t.tv_sec = 0; + t.tv_nsec = 100000000; + nanosleep(&t, NULL); + + if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { + return true; + } + else { + return false; + } + } +} + +bool +flexrf_base::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + /* + Determine values of R, control, and N registers, along with actual freq. + + @param freq: target frequency in Hz + @type freq: float + @returns: (R, control, N, actual_freq) + @rtype: tuple(int, int, int, float) + + Override this in derived classes. + */ + + //raise NotImplementedError; + throw std::runtime_error("_compute_regs called from flexrf_base\n"); +} + +int +flexrf_base::_compute_control_reg() +{ + return d_common->_compute_control_reg(); +} + +int +flexrf_base::_refclk_divisor() +{ + return d_common->_refclk_divisor(); +} + +double +flexrf_base::_refclk_freq() +{ + return 64e6/_refclk_divisor(); +} + +struct freq_result_t +flexrf_base::set_freq(double freq) +{ + /* + @returns (ok, actual_baseband_freq) where: + ok is True or False and indicates success or failure, + actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + struct freq_result_t args = {false, 0}; + + // Offsetting the LO helps get the Tx carrier leakage out of the way. + // This also ensures that on Rx, we're not getting hosed by the + // FPGA's DC removal loop's time constant. We were seeing a + // problem when running with discontinuous transmission. + // Offsetting the LO made the problem go away. + freq += d_lo_offset; + + int R, control, N; + double actual_freq; + _compute_regs(freq, R, control, N, actual_freq); + + if(R==0) { + return args; + } + + _write_all(R, control, N); + args.ok = _lock_detect(); + args.baseband_freq = actual_freq; + return args; +} + +bool +flexrf_base::_set_pga(float pga_gain) +{ + if(d_which == 0) { + usrp()->set_pga(0, pga_gain); + usrp()->set_pga(1, pga_gain); + } + else { + usrp()->set_pga(2, pga_gain); + usrp()->set_pga(3, pga_gain); + } + return true; +} + +bool +flexrf_base::is_quadrature() +{ + /* + Return True if this board requires both I & Q analog channels. + + This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + +double +flexrf_base::freq_min() +{ + return d_common->freq_min(); +} + +double +flexrf_base::freq_max() +{ + return d_common->freq_max(); +} + +// ---------------------------------------------------------------- + +flexrf_base_tx::flexrf_base_tx(usrp_basic_sptr _usrp, int which, int _power_on) + : flexrf_base(_usrp, which, _power_on) +{ + /* + @param usrp: instance of usrp.sink_c + @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. + */ + + if(which == 0) { + d_spi_enable = SPI_ENABLE_TX_A; + } + else { + d_spi_enable = SPI_ENABLE_TX_B; + } + + // power up the transmit side, but don't enable the mixer + usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff); + usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); + set_lo_offset(4e6); + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +flexrf_base_tx::~flexrf_base_tx() +{ + shutdown(); +} + + +void +flexrf_base_tx::shutdown() +{ + // fprintf(stderr, "flexrf_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown); + + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + // Power down and leave the T/R switch in the R position + usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); + + // Power down VCO/PLL + d_PD = 3; + + _write_control(_compute_control_reg()); + _enable_refclk(false); // turn off refclk + set_auto_tr(false); + } +} + +bool +flexrf_base_tx::set_auto_tr(bool on) +{ + bool ok = true; + if(on) { + ok &= set_atr_mask (RX_TXN | ENABLE); + ok &= set_atr_txval(0 | ENABLE); + ok &= set_atr_rxval(RX_TXN | 0); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + return ok; +} + +bool +flexrf_base_tx::set_enable(bool on) +{ + /* + Enable transmitter if on is true + */ + + int v; + int mask = RX_TXN | ENABLE; + if(on) { + v = ENABLE; + } + else { + v = RX_TXN; + } + return usrp()->write_io(d_which, v, mask); +} + +float +flexrf_base_tx::gain_min() +{ + return usrp()->pga_max(); +} + +float +flexrf_base_tx::gain_max() +{ + return usrp()->pga_max(); +} + +float +flexrf_base_tx::gain_db_per_step() +{ + return 1; +} + +bool +flexrf_base_tx::set_gain(float gain) +{ + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + return _set_pga(usrp()->pga_max()); +} + + +/**************************************************************************/ + + +flexrf_base_rx::flexrf_base_rx(usrp_basic_sptr _usrp, int which, int _power_on) + : flexrf_base(_usrp, which, _power_on) +{ + /* + @param usrp: instance of usrp.source_c + @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + if(which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff); + usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE), + (POWER_UP|RX2_RX1N|ENABLE)); + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + set_lo_offset(-4e6); +} + +flexrf_base_rx::~flexrf_base_rx() +{ + shutdown(); +} + +void +flexrf_base_rx::shutdown() +{ + // fprintf(stderr, "flexrf_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown); + + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + // Power down + usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE)); + + // Power down VCO/PLL + d_PD = 3; + + + // fprintf(stderr, "flexrf_base_rx::shutdown before _write_control\n"); + _write_control(_compute_control_reg()); + + // fprintf(stderr, "flexrf_base_rx::shutdown before _enable_refclk\n"); + _enable_refclk(false); // turn off refclk + + // fprintf(stderr, "flexrf_base_rx::shutdown before set_auto_tr\n"); + set_auto_tr(false); + + // fprintf(stderr, "flexrf_base_rx::shutdown after set_auto_tr\n"); + } +} + +bool +flexrf_base_rx::set_auto_tr(bool on) +{ + bool ok = true; + if(on) { + ok &= set_atr_mask (ENABLE); + ok &= set_atr_txval( 0); + ok &= set_atr_rxval(ENABLE); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + return true; +} + +bool +flexrf_base_rx::select_rx_antenna(int which_antenna) +{ + /* + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == 0) { + usrp()->write_io(d_which, 0,RX2_RX1N); + } + else if(which_antenna == 1) { + usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + return false; + // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } + return true; +} + +bool +flexrf_base_rx::select_rx_antenna(const std::string &which_antenna) +{ + /* + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == "TX/RX") { + usrp()->write_io(d_which, 0, RX2_RX1N); + } + else if(which_antenna == "RX2") { + usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + return false; + } + return true; +} + +bool +flexrf_base_rx::set_gain(float gain) +{ + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + + // clamp gain + gain = std::max(gain_min(), std::min(gain, gain_max())); + + float pga_gain, agc_gain; + float V_maxgain, V_mingain, V_fullscale, dac_value; + + float maxgain = gain_max() - usrp()->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= usrp()->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + V_maxgain = .2; + V_mingain = 1.2; + V_fullscale = 3.3; + dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + + return (usrp()->write_aux_dac(d_which, 0, int(dac_value)) + && _set_pga(int(pga_gain))); +} + +// ---------------------------------------------------------------- + + +_AD4360_common::_AD4360_common() +{ + // R-Register Common Values + d_R_RSV = 0; // bits 23,22 + d_BSC = 3; // bits 21,20 Div by 8 to be safe + d_TEST = 0; // bit 19 + d_LDP = 1; // bit 18 + d_ABP = 0; // bit 17,16 3ns + + // N-Register Common Values + d_N_RSV = 0; // bit 7 + + // Control Register Common Values + d_PD = 0; // bits 21,20 Normal operation + d_PL = 0; // bits 13,12 11mA + d_MTLD = 1; // bit 11 enabled + d_CPG = 0; // bit 10 CP setting 1 + d_CP3S = 0; // bit 9 Normal + d_PDP = 1; // bit 8 Positive + d_MUXOUT = 1; // bits 7:5 Digital Lock Detect + d_CR = 0; // bit 4 Normal + d_PC = 1; // bits 3,2 Core power 10mA +} + +_AD4360_common::~_AD4360_common() +{ +} + +bool +_AD4360_common::_compute_regs(double refclk_freq, double freq, int &retR, + int &retcontrol, int &retN, double &retfreq) +{ + /* + Determine values of R, control, and N registers, along with actual freq. + + @param freq: target frequency in Hz + @type freq: float + @returns: (R, control, N, actual_freq) + @rtype: tuple(int, int, int, float) + */ + + // Band-specific N-Register Values + //float phdet_freq = _refclk_freq()/d_R_DIV; + double phdet_freq = refclk_freq/d_R_DIV; + double desired_n = round(freq*d_freq_mult/phdet_freq); + double actual_freq = desired_n * phdet_freq; + int B = floor(desired_n/_prescaler()); + int A = desired_n - _prescaler()*B; + d_B_DIV = int(B); // bits 20:8 + d_A_DIV = int(A); // bit 6:2 + + //assert db_B_DIV >= db_A_DIV + if(d_B_DIV < d_A_DIV) { + retR = 0; + retcontrol = 0; + retN = 0; + retfreq = 0; + return false; + } + + int R = (d_R_RSV<<22) | (d_BSC<<20) | (d_TEST<<19) | + (d_LDP<<18) | (d_ABP<<16) | (d_R_DIV<<2); + + int control = _compute_control_reg(); + + int N = (d_DIVSEL<<23) | (d_DIV2<<22) | (d_CPGAIN<<21) | + (d_B_DIV<<8) | (d_N_RSV<<7) | (d_A_DIV<<2); + + retR = R; + retcontrol = control; + retN = N; + retfreq = actual_freq/d_freq_mult; + return true; +} + +int +_AD4360_common::_compute_control_reg() +{ + int control = (d_P<<22) | (d_PD<<20) | (d_CP2<<17) | (d_CP1<<14) + | (d_PL<<12) | (d_MTLD<<11) | (d_CPG<<10) | (d_CP3S<<9) | (d_PDP<<8) + | (d_MUXOUT<<5) | (d_CR<<4) | (d_PC<<2); + + return control; +} + +int +_AD4360_common::_refclk_divisor() +{ + /* + Return value to stick in REFCLK_DIVISOR register + */ + return 1; +} + +int +_AD4360_common::_prescaler() +{ + if(d_P == 0) { + return 8; + } + else if(d_P == 1) { + return 16; + } + else { + return 32; + } +} + +//---------------------------------------------------------------------- + +_2400_common::_2400_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 + d_CP1 = 7; // bits 16:14 + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 1; +} + +double +_2400_common::freq_min() +{ + return 2300e6; +} + +double +_2400_common::freq_max() +{ + return 2700e6; +} + +//---------------------------------------------------------------------- + +_1200_common::_1200_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 1; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 2; +} + +double +_1200_common::freq_min() +{ + return 1150e6; +} + +double +_1200_common::freq_max() +{ + return 1350e6; +} + +//------------------------------------------------------------------------- + +_1800_common::_1800_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_freq_mult = 1; + d_CPGAIN = 0; // bit 21 +} + +double +_1800_common::freq_min() +{ + return 1600e6; +} + +double +_1800_common::freq_max() +{ + return 2000e6; +} + +//------------------------------------------------------------------------- + +_900_common::_900_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 1; // bit 22 + d_freq_mult = 2; + d_CPGAIN = 0; // bit 21 +} + +double +_900_common::freq_min() +{ + return 800e6; +} + +double +_900_common::freq_max() +{ + return 1000e6; +} + +//------------------------------------------------------------------------- + +_400_common::_400_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 + + // Band-specific C-Register values + d_P = 0; // bits 23,22 Div by 8/9 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values These are different for TX/RX + d_DIVSEL = 0; // bit 23 + d_freq_mult = 2; + + d_CPGAIN = 0; // bit 21 +} + +double +_400_common::freq_min() +{ + return 400e6; +} + +double +_400_common::freq_max() +{ + return 500e6; +} + +_400_tx::_400_tx() + : _400_common() +{ + d_DIV2 = 1; // bit 22 +} + +_400_rx::_400_rx() + : _400_common() +{ + d_DIV2 = 0; // bit 22 // RX side has built-in DIV2 in AD8348 +} + +//------------------------------------------------------------ + +db_flexrf_2400_tx::db_flexrf_2400_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _2400_common(); +} + +db_flexrf_2400_tx::~db_flexrf_2400_tx() +{ +} + +bool +db_flexrf_2400_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + +db_flexrf_2400_rx::db_flexrf_2400_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _2400_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_2400_rx::~db_flexrf_2400_rx() +{ +} + +float +db_flexrf_2400_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_2400_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_2400_rx::gain_db_per_step() +{ + return 0.05; +} + + +bool +db_flexrf_2400_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_2400_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + +//------------------------------------------------------------ + + +db_flexrf_1200_tx::db_flexrf_1200_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _1200_common(); +} + +db_flexrf_1200_tx::~db_flexrf_1200_tx() +{ +} + +bool +db_flexrf_1200_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + + +db_flexrf_1200_rx::db_flexrf_1200_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _1200_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_1200_rx::~db_flexrf_1200_rx() +{ +} + +float +db_flexrf_1200_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_1200_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_1200_rx::gain_db_per_step() +{ + return 0.05; +} + +bool +db_flexrf_1200_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_1200_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + +//------------------------------------------------------------ + + +db_flexrf_1800_tx::db_flexrf_1800_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _1800_common(); +} + +db_flexrf_1800_tx::~db_flexrf_1800_tx() +{ +} + +bool +db_flexrf_1800_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + +db_flexrf_1800_rx::db_flexrf_1800_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _1800_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_1800_rx::~db_flexrf_1800_rx() +{ +} + + +float +db_flexrf_1800_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_1800_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_1800_rx::gain_db_per_step() +{ + return 0.05; +} + +bool +db_flexrf_1800_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_1800_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + +//------------------------------------------------------------ + + +db_flexrf_900_tx::db_flexrf_900_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _900_common(); +} + +db_flexrf_900_tx::~db_flexrf_900_tx() +{ +} + +bool +db_flexrf_900_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + +db_flexrf_900_rx::db_flexrf_900_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _900_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_900_rx::~db_flexrf_900_rx() +{ +} + +float +db_flexrf_900_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_900_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_900_rx::gain_db_per_step() +{ + return 0.05; +} + +bool +db_flexrf_900_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_900_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + +//------------------------------------------------------------ + + +db_flexrf_400_tx::db_flexrf_400_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which, POWER_UP) +{ + d_common = new _400_tx(); +} + +db_flexrf_400_tx::~db_flexrf_400_tx() +{ +} + +bool +db_flexrf_400_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + +db_flexrf_400_rx::db_flexrf_400_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which, POWER_UP) +{ + d_common = new _400_rx(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_400_rx::~db_flexrf_400_rx() +{ +} + +float +db_flexrf_400_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_400_rx::gain_max() +{ + return usrp()->pga_max()+45; +} + +float + +db_flexrf_400_rx::gain_db_per_step() +{ + return 0.035; +} + + +bool +db_flexrf_400_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_400_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + diff --git a/usrp/host/lib/legacy/db_flexrf.h b/usrp/host/lib/legacy/db_flexrf.h new file mode 100644 index 00000000..b9ccfc3a --- /dev/null +++ b/usrp/host/lib/legacy/db_flexrf.h @@ -0,0 +1,355 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_FLEXRF_H +#define DB_FLEXRF_H + +#include +#include + +//debug_using_gui = true // Must be set to True or False +#define debug_using_gui false // Must be set to True or False + +class _AD4360_common; + +class flexrf_base : public db_base +{ +public: + flexrf_base(usrp_basic_sptr usrp, int which, int _power_on=0); + ~flexrf_base(); + + struct freq_result_t set_freq(double freq); + + bool is_quadrature(); + double freq_min(); + double freq_max(); + +protected: + void _write_all(int R, int control, int N); + void _write_control(int control); + void _write_R(int R); + void _write_N(int N); + void _write_it(int v); + bool _lock_detect(); + + virtual bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); + int _compute_control_reg(); + int _refclk_divisor(); + double _refclk_freq(); + + bool _set_pga(float pga_gain); + + int power_on() { return d_power_on; } + int power_off() { return 0; } + + bool d_first; + int d_spi_format; + int d_spi_enable; + int d_power_on; + int d_PD; + + _AD4360_common *d_common; +}; + +// ---------------------------------------------------------------- + +class flexrf_base_tx : public flexrf_base +{ +protected: + void shutdown(); + +public: + flexrf_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~flexrf_base_tx(); + + // All RFX tx d'boards have fixed gain + float gain_min(); + float gain_max(); + float gain_db_per_step(); + + bool set_auto_tr(bool on); + bool set_enable(bool on); + bool set_gain(float gain); +}; + +class flexrf_base_rx : public flexrf_base +{ +protected: + void shutdown(); + +public: + flexrf_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~flexrf_base_rx(); + + bool set_auto_tr(bool on); + bool select_rx_antenna(int which_antenna); + bool select_rx_antenna(const std::string &which_antenna); + bool set_gain(float gain); + +}; + +// ---------------------------------------------------------------- + + +class _AD4360_common +{ +public: + _AD4360_common(); + virtual ~_AD4360_common(); + + virtual double freq_min() = 0; + virtual double freq_max() = 0; + + bool _compute_regs(double refclk_freq, double freq, int &retR, + int &retcontrol, int &retN, double &retfreq); + int _compute_control_reg(); + virtual int _refclk_divisor(); + int _prescaler(); + + void R_DIV(int div) { d_R_DIV = div; } + +protected: + int d_R_RSV, d_BSC, d_TEST, d_LDP, d_ABP, d_N_RSV, d_PL, d_MTLD; + int d_CPG, d_CP3S, d_PDP, d_MUXOUT, d_CR, d_PC; + + // FIXME: d_PD might cause conflict from flexrf_base + int d_A_DIV, d_B_DIV, d_R_DIV, d_P, d_PD, d_CP2, d_CP1, d_DIVSEL; + int d_DIV2, d_CPGAIN, d_freq_mult; + +}; + +//---------------------------------------------------------------------- + +class _2400_common : public _AD4360_common +{ + public: + _2400_common(); + ~_2400_common() {} + + double freq_min(); + double freq_max(); +}; + +//---------------------------------------------------------------------- + +class _1200_common : public _AD4360_common +{ +public: + _1200_common(); + ~_1200_common() {} + + double freq_min(); + double freq_max(); +}; + +//------------------------------------------------------------------------- + +class _1800_common : public _AD4360_common +{ + public: + _1800_common(); + ~_1800_common() {} + + double freq_min(); + double freq_max(); +}; + +//------------------------------------------------------------------------- + +class _900_common : public _AD4360_common +{ +public: + _900_common(); + ~_900_common() {} + + double freq_min(); + double freq_max(); +}; + +//------------------------------------------------------------------------- + +class _400_common : public _AD4360_common +{ +public: + _400_common(); + ~_400_common() {} + + double freq_min(); + double freq_max(); +}; + +class _400_tx : public _400_common +{ +public: + _400_tx(); + ~_400_tx() {} +}; + +class _400_rx : public _400_common +{ +public: + _400_rx(); + ~_400_rx() {} +}; + +//------------------------------------------------------------ + +class db_flexrf_2400_tx : public flexrf_base_tx +{ + public: + db_flexrf_2400_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_2400_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_2400_rx : public flexrf_base_rx +{ +public: + db_flexrf_2400_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_2400_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +//------------------------------------------------------------ + +class db_flexrf_1200_tx : public flexrf_base_tx +{ +public: + db_flexrf_1200_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1200_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_1200_rx : public flexrf_base_rx +{ +public: + db_flexrf_1200_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1200_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +//------------------------------------------------------------ + +class db_flexrf_1800_tx : public flexrf_base_tx +{ + public: + db_flexrf_1800_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1800_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_1800_rx : public flexrf_base_rx +{ +public: + db_flexrf_1800_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1800_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +//------------------------------------------------------------ + +class db_flexrf_900_tx : public flexrf_base_tx +{ + public: + db_flexrf_900_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_900_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_900_rx : public flexrf_base_rx +{ +public: + db_flexrf_900_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_900_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + + +//------------------------------------------------------------ + +class db_flexrf_400_tx : public flexrf_base_tx +{ + public: + db_flexrf_400_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_400_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_400_rx : public flexrf_base_rx +{ +public: + db_flexrf_400_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_400_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +#endif diff --git a/usrp/host/lib/legacy/db_flexrf_mimo.cc b/usrp/host/lib/legacy/db_flexrf_mimo.cc new file mode 100644 index 00000000..fd996bfa --- /dev/null +++ b/usrp/host/lib/legacy/db_flexrf_mimo.cc @@ -0,0 +1,276 @@ +/* + * Copyright 2008 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. + */ + +#include +#include +#include +#include +#include + + +db_flexrf_2400_tx_mimo_a::db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_2400_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_2400_rx_mimo_a::db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_2400_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_2400_tx_mimo_b::db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_2400_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_2400_rx_mimo_b::db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_2400_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1800_tx_mimo_a::db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1800_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1800_rx_mimo_a::db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1800_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1800_tx_mimo_b::db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1800_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1800_rx_mimo_b::db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1800_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1200_tx_mimo_a::db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1200_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1200_rx_mimo_a::db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1200_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1200_tx_mimo_b::db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1200_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1200_rx_mimo_b::db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1200_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_900_tx_mimo_a::db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_900_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_900_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_900_rx_mimo_a::db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_900_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_900_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_900_tx_mimo_b::db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_900_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_900_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_900_rx_mimo_b::db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_900_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int db_flexrf_900_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_400_tx_mimo_a::db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_400_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_400_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_400_rx_mimo_a::db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_400_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_400_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_400_tx_mimo_b::db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_400_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_400_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_400_rx_mimo_b::db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_400_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_400_rx_mimo_b::_refclk_divisor() +{ + return 1; +} diff --git a/usrp/host/lib/legacy/db_flexrf_mimo.h b/usrp/host/lib/legacy/db_flexrf_mimo.h new file mode 100644 index 00000000..aeff5325 --- /dev/null +++ b/usrp/host/lib/legacy/db_flexrf_mimo.h @@ -0,0 +1,163 @@ +/* + * Copyright 2008 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. + */ + +#include + +class db_flexrf_2400_tx_mimo_a : public db_flexrf_2400_tx +{ + public: + db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_2400_rx_mimo_a : public db_flexrf_2400_rx +{ + public: + db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_2400_tx_mimo_b : public db_flexrf_2400_tx +{ + public: + db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_2400_rx_mimo_b : public db_flexrf_2400_rx +{ + public: + db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + + +class db_flexrf_1800_tx_mimo_a : public db_flexrf_1800_tx +{ + public: + db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1800_rx_mimo_a : public db_flexrf_1800_rx +{ + public: + db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1800_tx_mimo_b : public db_flexrf_1800_tx +{ + public: + db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1800_rx_mimo_b : public db_flexrf_1800_rx +{ + public: + db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_tx_mimo_a : public db_flexrf_1200_tx +{ + public: + db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_rx_mimo_a : public db_flexrf_1200_rx +{ + public: + db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_tx_mimo_b : public db_flexrf_1200_tx +{ + public: + db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_rx_mimo_b : public db_flexrf_1200_rx +{ + public: + db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_tx_mimo_a : public db_flexrf_900_tx +{ + public: + db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_rx_mimo_a : public db_flexrf_900_rx +{ + public: + db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_tx_mimo_b : public db_flexrf_900_tx +{ + public: + db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_rx_mimo_b : public db_flexrf_900_rx +{ + public: + db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_tx_mimo_a : public db_flexrf_400_tx +{ + public: + db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_rx_mimo_a : public db_flexrf_400_rx +{ + public: + db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_tx_mimo_b : public db_flexrf_400_tx +{ + public: + db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_rx_mimo_b : public db_flexrf_400_rx +{ + public: + db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; diff --git a/usrp/host/lib/legacy/db_tv_rx.cc b/usrp/host/lib/legacy/db_tv_rx.cc new file mode 100644 index 00000000..803ebf86 --- /dev/null +++ b/usrp/host/lib/legacy/db_tv_rx.cc @@ -0,0 +1,274 @@ +// +// Copyright 2008 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 asversion 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. + +#include +#include + +/*****************************************************************************/ + +int +control_byte_1(bool fast_tuning_p, int reference_divisor) +{ + int c = 0x88; + if(fast_tuning_p) { + c |= 0x40; + } + + if(reference_divisor == 512) { + c |= 0x3 << 1; + } + else if(reference_divisor == 640) { + c |= 0x0 << 1; + } + else if(reference_divisor == 1024) { + c |= 0x1 << 1; + } + else { + assert(0); + } + + return c; +} + +int +control_byte_2(double target_freq, bool shutdown_tx_PGA) +{ + int c; + if(target_freq < 158e6) { // VHF low + c = 0xa0; + } + else if(target_freq < 464e6) { // VHF high + c = 0x90; + } + else { // UHF + c = 0x30; + } + + if(shutdown_tx_PGA) { + c |= 0x08; + } + + return c; +} + + +/*****************************************************************************/ + + +db_tv_rx::db_tv_rx(usrp_basic_sptr usrp, int which, + double first_IF, double second_IF) + : db_base(usrp, which) +{ + // Handler for Tv Rx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively + + if(which == 0) { + d_i2c_addr = 0x60; + } + else { + d_i2c_addr = 0x61; + } + + d_first_IF = first_IF; + d_second_IF = second_IF; + d_reference_divisor = 640; + d_fast_tuning = false; + d_inverted = false; // FIXME get rid of this + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain + + bypass_adc_buffers(false); +} + +db_tv_rx::~db_tv_rx() +{ +} + +// Gain setting +void +db_tv_rx::_set_rfagc(float gain) +{ + float voltage; + + assert(gain <= 60 && gain >= 0); + // FIXME this has a 0.5V step between gain = 60 and gain = 59. + // Why are there two cases instead of a single linear case? + if(gain == 60) { + voltage = 4; + } + else { + voltage = gain/60.0 * 2.25 + 1.25; + } + int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 1, dacword); +} + +void +db_tv_rx::_set_ifagc(float gain) +{ + float voltage; + + assert(gain <= 35 && gain >= 0); + voltage = gain/35.0 * 2.1 + 1.4; + int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 0, dacword); +} + +void +db_tv_rx::_set_pga(float pga_gain) +{ + assert(pga_gain >=0 && pga_gain <=20); + if(d_which == 0) { + usrp()->set_pga(0, pga_gain); + } + else { + usrp()->set_pga (2, pga_gain); + } +} + +double +db_tv_rx::freq_min() +{ + return 50e6; +} + +double +db_tv_rx::freq_max() +{ + return 860e6; +} + +struct freq_result_t +db_tv_rx::set_freq(double target_freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is RF frequency that corresponds to DC in the IF. + + freq_result_t args = {false, 0}; + + double fmin = freq_min(); + double fmax = freq_max(); + if((target_freq < fmin) || (target_freq > fmax)) { + return args; + } + + double target_lo_freq = target_freq + d_first_IF; // High side mixing + double f_ref = 4.0e6 / (double)(d_reference_divisor); // frequency steps + + int divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8)); + double actual_lo_freq = (f_ref * 8 * divisor); + double actual_freq = actual_lo_freq - d_first_IF; + + if((divisor & ~0x7fff) != 0) { // must be 15-bits or less + return args; + } + + // build i2c command string + std::vector buf(4); + buf[0] = (divisor >> 8) & 0xff; // DB1 + buf[1] = divisor & 0xff; // DB2 + buf[2] = control_byte_1(d_fast_tuning, d_reference_divisor); + buf[3] = control_byte_2(actual_freq, true); + + args.ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); + args.baseband_freq = actual_freq - d_second_IF; + return args; +} + +float +db_tv_rx::gain_min() +{ + return 0; +} + +float +db_tv_rx::gain_max() +{ + return 115; +} + +float +db_tv_rx::gain_db_per_step() +{ + return 1; +} + +bool +db_tv_rx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + float rfgain, ifgain, pgagain; + + assert(gain>=0 && gain<=115); + if(gain>60) { + rfgain = 60; + gain = gain - 60; + } + else { + rfgain = gain; + gain = 0; + } + + if(gain > 35) { + ifgain = 35; + gain = gain - 35; + } + else { + ifgain = gain; + gain = 0; + } + + pgagain = gain; + _set_rfagc(rfgain); + _set_ifagc(ifgain); + _set_pga(pgagain); + + return true; +} + +bool +db_tv_rx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + return false; +} + +bool +db_tv_rx::spectrum_inverted() +{ + // The 43.75 MHz version is inverted + return d_inverted; +} diff --git a/usrp/host/lib/legacy/db_tv_rx.h b/usrp/host/lib/legacy/db_tv_rx.h new file mode 100644 index 00000000..ed916263 --- /dev/null +++ b/usrp/host/lib/legacy/db_tv_rx.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_TV_RX_H +#define DB_TV_RX_H + +#include + +class db_tv_rx : public db_base +{ +private: + void _set_rfagc(float gain); + void _set_ifagc(float gain); + void _set_pga(float pga_gain); + + int d_i2c_addr; + double d_first_IF, d_second_IF; + int d_reference_divisor; + bool d_fast_tuning; + bool d_inverted; + +public: + db_tv_rx(usrp_basic_sptr usrp, int which, + double first_IF, double second_IF); + ~db_tv_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + bool set_gain(float gain); + bool is_quadrature(); + bool spectrum_inverted(); +}; + +#endif diff --git a/usrp/host/lib/legacy/db_util.cc b/usrp/host/lib/legacy/db_util.cc new file mode 100644 index 00000000..4b46383b --- /dev/null +++ b/usrp/host/lib/legacy/db_util.cc @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +std::string +int_seq_to_str(std::vector &seq) +{ + //convert a sequence of integers into a string + + std::stringstream str; + std::vector::iterator i; + for(i = seq.begin(); i != seq.end(); i++) { + str << char((unsigned int)*i); + } + return str.str(); +} + +std::vector +str_to_int_seq(std::string str) +{ + //convert a string to a list of integers + std::vector seq; + std::vector::iterator sitr; + std::string::iterator i; + for(i=str.begin(); i != str.end(); i++) { + int a = (int)(*i); + seq.push_back(a); + } + return seq; +} + diff --git a/usrp/host/lib/legacy/db_util.h b/usrp/host/lib/legacy/db_util.h new file mode 100644 index 00000000..e07abb60 --- /dev/null +++ b/usrp/host/lib/legacy/db_util.h @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_DB_UTIL_H +#define INCLUDED_DB_UTIL_H + +#include +#include + +std::string int_seq_to_str(std::vector &seq); +std::vector str_to_int_seq(std::string str); + +#endif /* INCLUDED_DB_UTIL_H */ diff --git a/usrp/host/lib/legacy/db_wbx.cc b/usrp/host/lib/legacy/db_wbx.cc new file mode 100644 index 00000000..9f1d7293 --- /dev/null +++ b/usrp/host/lib/legacy/db_wbx.cc @@ -0,0 +1,953 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#include +#include +#include +#include +#include +#include +#include + +// d'board i/o pin defs + +// TX IO Pins +#define TX_POWER (1 << 0) // TX Side Power +#define RX_TXN (1 << 1) // T/R antenna switch for TX/RX port +#define TX_ENB_MIX (1 << 2) // Enable IQ mixer +#define TX_ENB_VGA (1 << 3) + +// RX IO Pins +#define RX2_RX1N (1 << 0) // antenna switch between RX2 and TX/RX port +#define RXENABLE (1 << 1) // enables mixer +#define PLL_LOCK_DETECT (1 << 2) // Muxout pin from PLL -- MUST BE INPUT +#define MReset (1 << 3) // NB6L239 Master Reset, asserted low +#define SELA0 (1 << 4) // NB6L239 SelA0 +#define SELA1 (1 << 5) // NB6L239 SelA1 +#define SELB0 (1 << 6) // NB6L239 SelB0 +#define SELB1 (1 << 7) // NB6L239 SelB1 +#define PLL_ENABLE (1 << 8) // CE Pin on PLL +#define AUX_SCLK (1 << 9) // ALT SPI SCLK +#define AUX_SDO (1 << 10) // ALT SPI SDO +#define AUX_SEN (1 << 11) // ALT SPI SEN + + +wbx_base::wbx_base(usrp_basic_sptr usrp, int which) + : db_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to side A or B respectively + * @type which: int + */ + + d_first = true; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + // FIXME -- the write reg functions don't work with 0xffff for masks + _rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff); + _rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE)); + + _tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff); + _tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); // TX off, TR switch set to RX + + if(d_which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + set_auto_tr(false); + +} + +wbx_base::~wbx_base() +{ + shutdown(); +} + + +void +wbx_base::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + write_io(d_which, d_power_off, POWER_UP); // turn off power to board + _write_oe(d_which, 0, 0xffff); // turn off all outputs + set_auto_tr(false); // disable auto transmit + } +} + +bool +wbx_base::_lock_detect() +{ + /* + * @returns: the value of the VCO/PLL lock detect bit. + * @rtype: 0 or 1 + */ + + if(_rx_read_io() & PLL_LOCK_DETECT) { + return true; + } + else { // Give it a second chance + if(_rx_read_io() & PLL_LOCK_DETECT) { + return true; + } + else { + return false; + } + } +} + +bool +wbx_base::_tx_write_oe(int value, int mask) +{ + int reg = (d_which == 0 ? FR_OE_0 : FR_OE_2); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_write_oe(int value, int mask) +{ + int reg = (d_which == 0 ? FR_OE_1 : FR_OE_3); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_tx_write_io(int value, int mask) +{ + int reg = (d_which == 0 ? FR_IO_0 : FR_IO_2); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_write_io(int value, int mask) +{ + int reg = (d_which == 0 ? FR_IO_1 : FR_IO_3); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_read_io() +{ + int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); + int t = d_usrp->_read_fpga_reg(reg); + return (t >> 16) & 0xffff; +} + +bool +wbx_base::_tx_read_io() +{ + int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); + int t = d_usrp->_read_fpga_reg(reg); + return (t & 0xffff); +} + +bool +wbx_base::_compute_regs(double freq) +{ + /* + * Determine values of registers, along with actual freq. + * + * @param freq: target frequency in Hz + * @type freq: double + * @returns: (R, N, func, init, actual_freq) + * @rtype: tuple(int, int, int, int, double) + * + * Override this in derived classes. + */ + throw std::runtime_error("_compute_regs called from base class\n"); +} + +double +wbx_base::_refclk_freq() +{ + return (double)(d_usrp->fpga_master_clock_freq())/_refclk_divisor(); +} + +int +wbx_base::_refclk_divisor() +{ + /* + * Return value to stick in REFCLK_DIVISOR register + */ + return 1; +} + +struct freq_result_t +wbx_base::set_freq(double freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + throw std::runtime_error("set_freq called from base class\n"); +} + +float +wbx_base::gain_min() +{ + throw std::runtime_error("gain_min called from base class\n"); +} + +float +wbx_base::gain_max() +{ + throw std::runtime_error("gain_max called from base class\n"); +} + +float +wbx_base::gain_db_per_step() +{ + throw std::runtime_error("gain_db_per_step called from base class\n"); +} + +bool +wbx_base::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + throw std::runtime_error("set_gain called from base class\n"); +} + +bool +wbx_base::_set_pga(float pga_gain) +{ + bool ok; + if(d_which == 0) { + ok = d_usrp->set_pga(0, pga_gain); + ok |= d_usrp->set_pga(1, pga_gain); + } + else { + ok = d_usrp->set_pga(2, pga_gain); + ok |= d_usrp->set_pga(3, pga_gain); + } + return ok; +} + +bool +wbx_base::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + + +/****************************************************************************/ + + +wbx_base_tx::wbx_base_tx(usrp_basic_sptr usrp, int which) + : wbx_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.sink_c + * @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. + */ + + // power up the transmit side, NO -- but set antenna to receive + d_usrp->write_io(d_which, (TX_POWER), (TX_POWER|RX_TXN)); + d_lo_offset = 0e6; + + // Gain is not set by the PGA, but the PGA must be set at max gain in the TX + _set_pga(d_usrp->pga_max()); +} + +wbx_base_tx::~wbx_base_tx() +{ + // Power down and leave the T/R switch in the R position + d_usrp->write_io(d_which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); +} + +void +wbx_base_tx::set_auto_tr(bool on) +{ + if(on) { + set_atr_mask (RX_TXN); + set_atr_txval(0); + set_atr_rxval(RX_TXN); + } + else { + set_atr_mask (0); + set_atr_txval(0); + set_atr_rxval(0); + } +} + +void +wbx_base_tx::set_enable(bool on) +{ + /* + * Enable transmitter if on is True + */ + + int mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA; + //printf("HERE!!!!\n"); + if(on) { + d_usrp->write_io(d_which, TX_ENB_MIX|TX_ENB_VGA, mask); + } + else { + d_usrp->write_io(d_which, RX_TXN, mask); + } +} + +void +wbx_base_tx::set_lo_offset(double offset) +{ + /* + * Set amount by which LO is offset from requested tuning frequency. + * + * @param offset: offset in Hz + */ + + d_lo_offset = offset; +} + +double +wbx_base_tx::lo_offset() +{ + /* + * Get amount by which LO is offset from requested tuning frequency. + * + * @returns Offset in Hz + */ + + return d_lo_offset; +} + + +/****************************************************************************/ + + +wbx_base_rx::wbx_base_rx(usrp_basic_sptr usrp, int which) + : wbx_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + d_lo_offset = 0.0; +} + +wbx_base_rx::~wbx_base_rx() +{ + // Power down + d_usrp->write_io(d_which, 0, (RXENABLE)); +} + +void +wbx_base_rx::set_auto_tr(bool on) +{ + if(on) { + // FIXME: where does ENABLE come from? + //set_atr_mask (ENABLE); + set_atr_txval( 0); + //set_atr_rxval(ENABLE); + } + else { + set_atr_mask (0); + set_atr_txval(0); + set_atr_rxval(0); + } +} + +void +wbx_base_rx::select_rx_antenna(int which_antenna) +{ + /* + * Specify which antenna port to use for reception. + * @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == 0) { + d_usrp->write_io(d_which, 0, RX2_RX1N); + } + else if(which_antenna == 1) { + d_usrp->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } +} + +void +wbx_base_rx::select_rx_antenna(const std::string &which_antenna) +{ + if(which_antenna == "TX/RX") { + select_rx_antenna(0); + } + else if(which_antenna == "RX2") { + select_rx_antenna(1); + } + else { + throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } +} + +bool +wbx_base_rx::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + + float pga_gain, agc_gain; + float maxgain = gain_max() - d_usrp->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= d_usrp->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + float V_maxgain = .2; + float V_mingain = 1.2; + float V_fullscale = 3.3; + float dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + + return d_usrp->write_aux_dac(d_which, 0, (int)(dac_value)) && _set_pga((int)(pga_gain)); +} + +void +wbx_base_rx::set_lo_offset(double offset) +{ + /* + * Set amount by which LO is offset from requested tuning frequency. + * + * @param offset: offset in Hz + */ + d_lo_offset = offset; +} + +double +wbx_base_rx::lo_offset() +{ + /* + * Get amount by which LO is offset from requested tuning frequency. + * + * @returns Offset in Hz + */ + return d_lo_offset; +} + +bool +wbx_base_rx::i_and_q_swapped() +{ + /* + * Return True if this is a quadrature device and ADC 0 is Q. + */ + return false; +} + + +/****************************************************************************/ + +_ADF410X_common::_ADF410X_common() +{ + // R-Register Common Values + d_R_RSV = 0; // bits 23,22,21 + d_LDP = 1; // bit 20 Lock detect in 5 cycles + d_TEST = 0; // bit 19,18 Normal + d_ABP = 0; // bit 17,16 2.9ns + + // N-Register Common Values + d_N_RSV = 0; // 23,22 + d_CP_GAIN = 0; // 21 + + // Function Register Common Values + d_P = 0; // bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65 + d_PD2 = 0; // bit 21 Normal operation + d_CP2 = 4; // bits 20,19,18 CP Gain = 5mA + d_CP1 = 4; // bits 17,16,15 CP Gain = 5mA + d_TC = 0; // bits 14-11 PFD Timeout + d_FL = 0; // bit 10,9 Fastlock Disabled + d_CP3S = 0; // bit 8 CP Enabled + d_PDP = 0; // bit 7 Phase detector polarity, Positive=1 + d_MUXOUT = 1; // bits 6:4 Digital Lock Detect + d_PD1 = 0; // bit 3 Normal operation + d_CR = 0; // bit 2 Normal operation +} + +_ADF410X_common::~_ADF410X_common() +{ +} + +bool +_ADF410X_common::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + /* + * Determine values of R, control, and N registers, along with actual freq. + * + * @param freq: target frequency in Hz + * @type freq: double + * @returns: (R, N, control, actual_freq) + * @rtype: tuple(int, int, int, double) + */ + + // Band-specific N-Register Values + double phdet_freq = _refclk_freq()/d_R_DIV; + printf("phdet_freq = %f\n", phdet_freq); + + double desired_n = round(freq*d_freq_mult/phdet_freq); + printf("desired_n %f\n", desired_n); + + double actual_freq = desired_n * phdet_freq; + printf("actual freq %f\n", actual_freq); + + double B = floor(desired_n/_prescaler()); + double A = desired_n - _prescaler()*B; + printf("A %f B %f\n", A, B); + + d_B_DIV = int(B); // bits 20:8; + d_A_DIV = int(A); // bit 6:2; + + if(d_B_DIV < d_A_DIV) { + retR = 0; + retN = 0; + retcontrol = 0; + retfreq = 0; + return false; + } + + retR = (d_R_RSV<<21) | (d_LDP<<20) | (d_TEST<<18) | + (d_ABP<<16) | (d_R_DIV<<2); + + retN = (d_N_RSV<<22) | (d_CP_GAIN<<21) | (d_B_DIV<<8) | (d_A_DIV<<2); + + retcontrol = (d_P<<22) | (d_PD2<<21) | (d_CP2<<18) | (d_CP1<<15) | + (d_TC<<11) | (d_FL<<9) | (d_CP3S<<8) | (d_PDP<<7) | + (d_MUXOUT<<4) | (d_PD1<<3) | (d_CR<<2); + + retfreq = actual_freq/d_freq_mult; + + return true; +} + +void +_ADF410X_common::_write_all(int R, int N, int control) +{ + /* + * Write all PLL registers: + * R counter latch, + * N counter latch, + * Function latch, + * Initialization latch + * + * Adds 10ms delay between writing control and N if this is first call. + * This is the required power-up sequence. + * + * @param R: 24-bit R counter latch + * @type R: int + * @param N: 24-bit N counter latch + * @type N: int + * @param control: 24-bit control latch + * @type control: int + */ + static bool first = true; + + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + + _write_R(R); + _write_func(control); + _write_init(control); + if(first) { + //time.sleep(0.010); + nanosleep(&t, NULL); + first = false; + } + _write_N(N); +} + +void +_ADF410X_common::_write_R(int R) +{ + _write_it((R & ~0x3) | 0); +} + +void +_ADF410X_common::_write_N(int N) +{ + _write_it((N & ~0x3) | 1); +} + +void +_ADF410X_common::_write_func(int func) +{ + _write_it((func & ~0x3) | 2); +} + +void +_ADF410X_common::_write_init(int init) +{ + _write_it((init & ~0x3) | 3); +} + +void +_ADF410X_common::_write_it(int v) +{ + char c[3]; + c[0] = (char)((v >> 16) & 0xff); + c[1] = (char)((v >> 8) & 0xff); + c[2] = (char)((v & 0xff)); + std::string s(c, 3); + //d_usrp->_write_spi(0, d_spi_enable, d_spi_format, s); + usrp()->_write_spi(0, d_spi_enable, d_spi_format, s); +} + +int +_ADF410X_common::_prescaler() +{ + if(d_P == 0) { + return 8; + } + else if(d_P == 1) { + return 16; + } + else if(d_P == 2) { + return 32; + } + else if(d_P == 3) { + return 64; + } + else { + throw std::invalid_argument("Prescaler out of range\n"); + } +} + +double +_ADF410X_common::_refclk_freq() +{ + throw std::runtime_error("_refclk_freq called from base class."); +} + +bool +_ADF410X_common::_rx_write_io(int value, int mask) +{ + throw std::runtime_error("_rx_write_io called from base class."); +} + +bool +_ADF410X_common::_lock_detect() +{ + throw std::runtime_error("_lock_detect called from base class."); +} + +usrp_basic* +_ADF410X_common::usrp() +{ + throw std::runtime_error("usrp() called from base class."); +} + + +/****************************************************************************/ + + +_lo_common::_lo_common() + : _ADF410X_common() +{ + // Band-specific R-Register Values + d_R_DIV = 4; // bits 15:2 + + // Band-specific C-Register values + d_P = 0; // bits 23,22 0 = Div by 8/9 + d_CP2 = 4; // bits 19:17 + d_CP1 = 4; // bits 16:14 + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 1; + + d_div = 1; + d_aux_div = 2; + d_main_div = 0; +} + +_lo_common::~_lo_common() +{ +} + +double +_lo_common::freq_min() +{ + return 50e6; +} + +double +_lo_common::freq_max() +{ + return 1000e6; +} + +void +_lo_common::set_divider(int main_or_aux, int divisor) +{ + if(main_or_aux == 0) { + if((divisor != 1) || (divisor != 2) || (divisor != 4) || (divisor != 8)) { + throw std::invalid_argument("Main Divider Must be 1, 2, 4, or 8\n"); + } + d_main_div = (int)(log10(divisor)/log10(2.0)); + } + else if(main_or_aux == 1) { + if((divisor != 2) || (divisor != 4) || (divisor != 8) || (divisor != 16)) { + throw std::invalid_argument("Aux Divider Must be 2, 4, 8 or 16\n"); + } + d_main_div = (int)(log10(divisor/2.0)/log10(2.0)); + } + else { + throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); + } + + int vala = d_main_div*SELA0; + int valb = d_aux_div*SELB0; + int mask = SELA0|SELA1|SELB0|SELB1; + + _rx_write_io((vala | valb), mask); +} + +void +_lo_common::set_divider(const std::string &main_or_aux, int divisor) +{ + if(main_or_aux == "main") { + set_divider(0, divisor); + } + else if(main_or_aux == "aux") { + set_divider(1, divisor); + } + else { + throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); + } +} + +struct freq_result_t +_lo_common::set_freq(double freq) +{ + struct freq_result_t ret; + + if(freq < 20e6 or freq > 1200e6) { + throw std::invalid_argument("Requested frequency out of range\n"); + } + + int div = 1; + double lo_freq = freq * 2; + while((lo_freq < 1e9) && (div < 8)) { + div = div * 2; + lo_freq = lo_freq * 2; + } + + printf("For RF freq of %f, we set DIV=%d and LO Freq=%f\n", freq, div, lo_freq); + + set_divider("main", div); + set_divider("aux", div*2); + + int R, N, control; + double actual_freq; + _compute_regs(lo_freq, R, N, control, actual_freq); + + printf("R %d N %d control %d actual freq %f\n", R, N, control, actual_freq); + if(R==0) { + ret.ok = false; + ret.baseband_freq = 0.0; + return ret; + } + _write_all(R, N, control); + + ret.ok = _lock_detect(); + ret.baseband_freq = actual_freq/div/2; + return ret; +} + + +/****************************************************************************/ + + +db_wbx_lo_tx::db_wbx_lo_tx(usrp_basic_sptr usrp, int which) + : _lo_common(), + wbx_base_tx(usrp, which) +{ +} + +db_wbx_lo_tx::~db_wbx_lo_tx() +{ +} + +float +db_wbx_lo_tx::gain_min() +{ + return -56.0; +} + +float +db_wbx_lo_tx::gain_max() +{ + return 0.0; +} + +float +db_wbx_lo_tx::gain_db_per_step() +{ + return 0.1; +} + +bool +db_wbx_lo_tx::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + + float txvga_gain; + float maxgain = gain_max(); + float mingain = gain_min(); + if(gain > maxgain) { + txvga_gain = maxgain; + } + else if(gain < mingain) { + txvga_gain = mingain; + } + else { + txvga_gain = gain; + } + + float V_maxgain = 1.4; + float V_mingain = 0.1; + float V_fullscale = 3.3; + float dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/ + (maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + printf("DAC value %f\n", dac_value); + + return d_usrp->write_aux_dac(d_which, 1, (int)(dac_value)); +} + +double +db_wbx_lo_tx::_refclk_freq() +{ + return wbx_base::_refclk_freq(); +} + +bool +db_wbx_lo_tx::_rx_write_io(int value, int mask) +{ + return wbx_base::_rx_write_io(value, mask); +} + +bool +db_wbx_lo_tx::_lock_detect() +{ + return wbx_base::_lock_detect(); +} + +usrp_basic* +db_wbx_lo_tx::usrp() +{ + return d_usrp; +} + + +/****************************************************************************/ + + +db_wbx_lo_rx::db_wbx_lo_rx(usrp_basic_sptr usrp, int which) + : _lo_common(), + wbx_base_rx(usrp, which) +{ +} + +db_wbx_lo_rx::~db_wbx_lo_rx() +{ +} + +float +db_wbx_lo_rx::gain_min() +{ + return d_usrp->pga_min(); +} + +float +db_wbx_lo_rx::gain_max() +{ + return d_usrp->pga_max() + 45; +} + +float +db_wbx_lo_rx::gain_db_per_step() +{ + return 0.05; +} + +double +db_wbx_lo_rx::_refclk_freq() +{ + return wbx_base::_refclk_freq(); +} + +bool +db_wbx_lo_rx::_rx_write_io(int value, int mask) +{ + return wbx_base::_rx_write_io(value, mask); +} + +bool +db_wbx_lo_rx::_lock_detect() +{ + return wbx_base::_lock_detect(); +} + +usrp_basic* +db_wbx_lo_rx::usrp() +{ + return d_usrp; +} diff --git a/usrp/host/lib/legacy/db_wbx.h b/usrp/host/lib/legacy/db_wbx.h new file mode 100644 index 00000000..3202d368 --- /dev/null +++ b/usrp/host/lib/legacy/db_wbx.h @@ -0,0 +1,221 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_WBX_H +#define DB_WBX_H + +#include +#include + + +/* + A few comments about the WBX boards: + They are half-duplex. I.e., transmit and receive are mutually exclusive. + There is a single LO for both the Tx and Rx sides. + The the shared control signals are hung off of the Rx side. + The shared io controls are duplexed onto the Rx side pins. + The wbx_high d'board always needs to be in 'auto_tr_mode' +*/ + + +class wbx_base : public db_base +{ +protected: + void shutdown(); + + /* + * Abstract base class for all wbx boards. + * + * Derive board specific subclasses from db_wbx_base_{tx,rx} + */ + +public: + wbx_base(usrp_basic_sptr usrp, int which); + ~wbx_base(); + + struct freq_result_t set_freq(double freq); + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + bool is_quadrature(); + + +protected: + virtual bool _lock_detect(); + + // FIXME: After testing, replace these with usrp_basic::common_write_io/oe + bool _tx_write_oe(int value, int mask); + bool _rx_write_oe(int value, int mask); + bool _tx_write_io(int value, int mask); + bool _rx_write_io(int value, int mask); + virtual bool _rx_read_io(); + bool _tx_read_io(); + bool _compute_regs(double freq); + virtual double _refclk_freq(); + int _refclk_divisor(); + + bool _set_pga(float pga_gain); + + bool d_first; + int d_spi_format; + int d_spi_enable; + double d_lo_offset; +}; + + +/****************************************************************************/ + + +class wbx_base_tx : public wbx_base +{ +public: + wbx_base_tx(usrp_basic_sptr usrp, int which); + ~wbx_base_tx(); + + bool set_auto_tr(bool on); + bool set_enable(bool on); +}; + + +/****************************************************************************/ + + +class wbx_base_rx : public wbx_base +{ +public: + wbx_base_rx(usrp_basic_sptr usrp, int which); + ~wbx_base_rx(); + + bool set_auto_tr(bool on); + bool select_rx_antenna(int which_antenna); + bool select_rx_antenna(const std::string &which_antenna); + bool set_gain(float gain); + bool i_and_q_swapped(); +}; + + +/****************************************************************************/ + + +class _ADF410X_common +{ +public: + _ADF410X_common(); + virtual ~_ADF410X_common(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); + void _write_all(int R, int N, int control); + void _write_R(int R); + void _write_N(int N); + void _write_func(int func); + void _write_init(int init); + int _prescaler(); + virtual void _write_it(int v); + virtual double _refclk_freq(); + virtual bool _rx_write_io(int value, int mask); + virtual bool _lock_detect(); + +protected: + virtual usrp_basic* usrp(); + + int d_R_RSV, d_LDP, d_TEST, d_ABP; + int d_N_RSV, d_CP_GAIN; + int d_P, d_PD2, d_CP2, d_CP1, d_TC, d_FL; + int d_CP3S, d_PDP, d_MUXOUT, d_PD1, d_CR; + int d_R_DIV, d_A_DIV, d_B_DIV; + int d_freq_mult; + + int d_spi_format; + int d_spi_enable; +}; + + +/****************************************************************************/ + + +class _lo_common : public _ADF410X_common +{ +public: + _lo_common(); + ~_lo_common(); + + double freq_min(); + double freq_max(); + + void set_divider(int main_or_aux, int divisor); + void set_divider(const std::string &main_or_aux, int divisor); + + struct freq_result_t set_freq(double freq); + +protected: + int d_R_DIV, d_P, d_CP2, d_CP1; + int d_DIVSEL, d_DIV2, d_CPGAIN; + int d_div, d_aux_div, d_main_div; +}; + + +/****************************************************************************/ + + +class db_wbx_lo_tx : public _lo_common, public wbx_base_tx +{ +public: + db_wbx_lo_tx(usrp_basic_sptr usrp, int which); + ~db_wbx_lo_tx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + + double _refclk_freq(); + bool _rx_write_io(int value, int mask); + bool _lock_detect(); + +protected: + usrp_basic* usrp(); +}; + + +/****************************************************************************/ + + +class db_wbx_lo_rx : public _lo_common, public wbx_base_rx +{ +public: + db_wbx_lo_rx(usrp_basic_sptr usrp, int which); + ~db_wbx_lo_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + + double _refclk_freq(); + bool _rx_write_io(int value, int mask); + bool _lock_detect(); + +protected: + usrp_basic* usrp(); +}; + +#endif diff --git a/usrp/host/lib/legacy/db_xcvr2450.cc b/usrp/host/lib/legacy/db_xcvr2450.cc new file mode 100644 index 00000000..e0c3f91c --- /dev/null +++ b/usrp/host/lib/legacy/db_xcvr2450.cc @@ -0,0 +1,762 @@ +// +// Copyright 2008 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 asversion 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. + +#include +#include +#include + + +/* ------------------------------------------------------------------------ + * A few comments about the XCVR2450: + * + * It is half-duplex. I.e., transmit and receive are mutually exclusive. + * There is a single LO for both the Tx and Rx sides. + * For our purposes the board is always either receiving or transmitting. + * + * Each board is uniquely identified by the *USRP hardware* instance and side + * This dictionary holds a weak reference to existing board controller so it + * can be created or retrieved as needed. + */ + + +/*****************************************************************************/ + + +xcvr2450::xcvr2450(usrp_basic_sptr _usrp, int which) + : d_weak_usrp(_usrp), d_which(which) +{ + // Handler for Tv Rx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively + + // Use MSB with no header + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + if(which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + // Sane defaults + d_mimo = 1; // 0 = OFF, 1 = ON + d_int_div = 192; // 128 = min, 255 = max + d_frac_div = 0; // 0 = min, 65535 = max + d_highband = 0; // 0 = freq <= 5.4e9, 1 = freq > 5.4e9 + d_five_gig = 0; // 0 = freq <= 3.e9, 1 = freq > 3e9 + d_cp_current = 0; // 0 = 2mA, 1 = 4mA + d_ref_div = 4; // 1 to 7 + d_rssi_hbw = 0; // 0 = 2 MHz, 1 = 6 MHz + d_txlpf_bw = 1; // 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz + d_rxlpf_bw = 1; // 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz + d_rxlpf_fine = 2; // 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110% + d_rxvga_ser = 1; // 0 = RXVGA controlled by B7:1, 1=controlled serially + d_rssi_range = 1; // 0 = low range (datasheet typo), 1=high range (0.5V - 2.0V) + d_rssi_mode = 1; // 0 = enable follows RXHP, 1 = enabled + d_rssi_mux = 0; // 0 = RSSI, 1 = TEMP + d_rx_hp_pin = 0; // 0 = Fc set by rx_hpf, 1 = 600 KHz + d_rx_hpf = 0; // 0 = 100Hz, 1 = 30KHz + d_rx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2 + d_tx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2 + d_txvga_ser = 1; // 0 = TXVGA controlled by B6:1, 1=controlled serially + d_tx_driver_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin) + d_tx_vga_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin) + d_tx_upconv_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin) + d_tx_bb_gain = 3; // 0=maxgain-5dB, 1=max-3dB, 2=max-1.5dB, 3=max + d_pabias_delay = 15; // 0 = 0, 15 = 7uS + d_pabias = 0; // 0 = 0 uA, 63 = 315uA + d_rx_rf_gain = 0; // 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB + d_rx_bb_gain = 16; // 0 = min, 31 = max (0 - 62 dB) + + d_txgain = 63; // 0 = min, 63 = max + + // Initialize GPIO and ATR + tx_write_io(TX_SAFE_IO, TX_OE_MASK); + tx_write_oe(TX_OE_MASK, ~0); + tx_set_atr_txval(TX_SAFE_IO); + tx_set_atr_rxval(TX_SAFE_IO); + tx_set_atr_mask(TX_OE_MASK); + rx_write_io(RX_SAFE_IO, RX_OE_MASK); + rx_write_oe(RX_OE_MASK, ~0); + rx_set_atr_rxval(RX_SAFE_IO); + rx_set_atr_txval(RX_SAFE_IO); + rx_set_atr_mask(RX_OE_MASK); + + // Initialize chipset + // TODO: perform reset sequence to ensure power up defaults + set_reg_standby(); + set_reg_bandselpll(); + set_reg_cal(); + set_reg_lpf(); + set_reg_rxrssi_ctrl(); + set_reg_txlin_gain(); + set_reg_pabias(); + set_reg_rxgain(); + set_reg_txgain(); + //FIXME: set_freq(2.45e9); +} + +xcvr2450::~xcvr2450() +{ + //printf("xcvr2450::destructor\n"); + tx_set_atr_txval(TX_SAFE_IO); + tx_set_atr_rxval(TX_SAFE_IO); + rx_set_atr_rxval(RX_SAFE_IO); + rx_set_atr_txval(RX_SAFE_IO); +} + +bool +xcvr2450::operator==(xcvr2450_key x) +{ + if((x.serial_no == usrp()->serial_number()) && (x.which == d_which)) { + return true; + } + else { + return false; + } +} + +void +xcvr2450::set_reg_standby() +{ + d_reg_standby = ((d_mimo<<17) | + (1<<16) | + (1<<6) | + (1<<5) | + (1<<4) | 2); + send_reg(d_reg_standby); +} + +void +xcvr2450::set_reg_int_divider() +{ + d_reg_int_divider = (((d_frac_div & 0x03)<<16) | + (d_int_div<<4) | 3); + send_reg(d_reg_int_divider); +} + +void +xcvr2450::set_reg_frac_divider() +{ + d_reg_frac_divider = ((d_frac_div & 0xfffc)<<2) | 4; + send_reg(d_reg_frac_divider); +} + +void +xcvr2450::set_reg_bandselpll() +{ + d_reg_bandselpll = ((d_mimo<<17) | + (1<<16) | + (1<<15) | + (1<<11) | + (d_highband<<10) | + (d_cp_current<<9) | + (d_ref_div<<5) | + (d_five_gig<<4) | 5); + send_reg(d_reg_bandselpll); +} + +void +xcvr2450::set_reg_cal() +{ + // FIXME do calibration + d_reg_cal = (1<<14)|6; + send_reg(d_reg_cal); +} + +void +xcvr2450::set_reg_lpf() +{ + d_reg_lpf = ( + (d_rssi_hbw<<15) | + (d_txlpf_bw<<10) | + (d_rxlpf_bw<<9) | + (d_rxlpf_fine<<4) | 7); + send_reg(d_reg_lpf); +} + +void +xcvr2450::set_reg_rxrssi_ctrl() +{ + d_reg_rxrssi_ctrl = ((d_rxvga_ser<<16) | + (d_rssi_range<<15) | + (d_rssi_mode<<14) | + (d_rssi_mux<<12) | + (1<<9) | + (d_rx_hpf<<6) | + (1<<4) | 8); + send_reg(d_reg_rxrssi_ctrl); +} + +void +xcvr2450::set_reg_txlin_gain() +{ + d_reg_txlin_gain = ((d_txvga_ser<<14) | + (d_tx_driver_lin<<12) | + (d_tx_vga_lin<<10) | + (d_tx_upconv_lin<<6) | + (d_tx_bb_gain<<4) | 9); + send_reg(d_reg_txlin_gain); +} + +void +xcvr2450::set_reg_pabias() +{ + d_reg_pabias = ( + (d_pabias_delay<<10) | + (d_pabias<<4) | 10); + send_reg(d_reg_pabias); +} + +void +xcvr2450::set_reg_rxgain() +{ + d_reg_rxgain = ( + (d_rx_rf_gain<<9) | + (d_rx_bb_gain<<4) | 11); + send_reg(d_reg_rxgain); +} + +void +xcvr2450::set_reg_txgain() +{ + d_reg_txgain = (d_txgain<<4) | 12; + send_reg(d_reg_txgain); +} + +void +xcvr2450::send_reg(int v) +{ + // Send 24 bits, it keeps last 18 clocked in + char c[3]; + c[0] = (char)((v >> 16) & 0xff); + c[1] = (char)((v >> 8) & 0xff); + c[2] = (char)((v & 0xff)); + std::string s(c, 3); + + usrp()->_write_spi(0, d_spi_enable, d_spi_format, s); + //printf("xcvr2450: Setting reg %d to %06X\n", (v&15), v); +} + +// -------------------------------------------------------------------- +// These methods control the GPIO bus. Since the board has to access +// both the io_rx_* and io_tx_* pins, we define our own methods to do so. +// This bypasses any code in db_base. +// +// The board operates in ATR mode, always. Thus, when the board is first +// initialized, it is in receive mode, until bits show up in the TX FIFO. +// + +// FIXME these should just call the similarly named common_* method on usrp_basic + +bool +xcvr2450::tx_write_oe(int value, int mask) +{ + int reg; + if(d_which) + reg = FR_OE_0; + else + reg = FR_OE_2; + return usrp()->_write_fpga_reg(reg, (mask << 16) | value); +} + +bool +xcvr2450::tx_write_io(int value, int mask) +{ + int reg; + if(d_which) + reg = FR_IO_0; + else + reg = FR_IO_2; + return usrp()->_write_fpga_reg(reg, (mask << 16) | value); +} + +int +xcvr2450::tx_read_io() +{ + int val; + if(d_which) + val = FR_RB_IO_RX_A_IO_TX_A; + else + val = FR_RB_IO_RX_B_IO_TX_B; + int t = usrp()->_read_fpga_reg(val); + return t & 0xffff; +} + +bool +xcvr2450::rx_write_oe(int value, int mask) +{ + int reg; + if(d_which) + reg = FR_OE_1; + else + reg = FR_OE_3; + return usrp()->_write_fpga_reg(reg, (mask << 16) | value); +} + +bool +xcvr2450::rx_write_io(int value, int mask) +{ + int reg; + if(d_which) + reg = FR_IO_1; + else + reg = FR_IO_3; + return usrp()->_write_fpga_reg(reg, (mask << 16) | value); +} + +int +xcvr2450::rx_read_io() +{ + int val; + if(d_which) + val = FR_RB_IO_RX_A_IO_TX_A; + else + val = FR_RB_IO_RX_B_IO_TX_B; + int t = usrp()->_read_fpga_reg(val); + return (t >> 16) & 0xffff; +} + +bool +xcvr2450::tx_set_atr_mask(int v) +{ + int reg; + if(d_which) + reg = FR_ATR_MASK_0; + else + reg = FR_ATR_MASK_2; + return usrp()->_write_fpga_reg(reg, v); +} + +bool +xcvr2450::tx_set_atr_txval(int v) +{ + int reg; + if(d_which) + reg = FR_ATR_TXVAL_0; + else + reg = FR_ATR_TXVAL_2; + return usrp()->_write_fpga_reg(reg, v); +} + +bool +xcvr2450::tx_set_atr_rxval(int v) +{ + int reg; + if(d_which) + reg = FR_ATR_RXVAL_0; + else + reg = FR_ATR_RXVAL_2; + return usrp()->_write_fpga_reg(reg, v); +} + +bool +xcvr2450::rx_set_atr_mask(int v) +{ + int reg; + if(d_which) + reg = FR_ATR_MASK_1; + else + reg = FR_ATR_MASK_3; + return usrp()->_write_fpga_reg(reg, v); +} + +bool +xcvr2450::rx_set_atr_txval(int v) +{ + int reg; + if(d_which) + reg = FR_ATR_TXVAL_1; + else + reg = FR_ATR_TXVAL_3; + return usrp()->_write_fpga_reg(reg, v); +} + +bool +xcvr2450::rx_set_atr_rxval(int v) +{ + int reg; + if(d_which) + reg = FR_ATR_RXVAL_1; + else + reg = FR_ATR_RXVAL_3; + return usrp()->_write_fpga_reg(reg, v); +} + +// ---------------------------------------------------------------- + +void +xcvr2450::set_gpio() +{ + // We calculate four values: + // + // io_rx_while_rx: what to drive onto io_rx_* when receiving + // io_rx_while_tx: what to drive onto io_rx_* when transmitting + // io_tx_while_rx: what to drive onto io_tx_* when receiving + // io_tx_while_tx: what to drive onto io_tx_* when transmitting + // + // B1-B7 is ignored as gain is set serially for now. + + int rx_hp, tx_antsel, rx_antsel, tx_pa_sel; + if(d_rx_hp_pin) + rx_hp = 0; + else + rx_hp = RX_HP; + + if(d_tx_ant) + tx_antsel = ANTSEL_TX1_RX2; + else + tx_antsel = ANTSEL_TX2_RX1; + + if(d_rx_ant) + rx_antsel = ANTSEL_TX1_RX2; + else + rx_antsel = ANTSEL_TX2_RX1; + + if(d_five_gig) + tx_pa_sel = HB_PA_OFF; + else + tx_pa_sel = LB_PA_OFF; + + int io_rx_while_rx = EN|rx_hp|RX_EN; + int io_rx_while_tx = EN|rx_hp; + int io_tx_while_rx = HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV; + int io_tx_while_tx = tx_pa_sel|tx_antsel|TX_EN|AD9515DIV; + rx_set_atr_rxval(io_rx_while_rx); + rx_set_atr_txval(io_rx_while_tx); + tx_set_atr_rxval(io_tx_while_rx); + tx_set_atr_txval(io_tx_while_tx); + + //printf("GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X", + // io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx); +} + + +struct freq_result_t +xcvr2450::set_freq(double target_freq) +{ + struct freq_result_t args = {false, 0}; + + double scaler; + + if(target_freq > 3e9) { + d_five_gig = 1; + d_ref_div = 1; + d_ad9515_div = 3; + scaler = 4.0/5.0; + } + else { + d_five_gig = 0; + d_ref_div = 1; + d_ad9515_div = 3; + scaler = 4.0/3.0; + } + + if(target_freq > 5.27e9) { + d_highband = 1; + } + else { + d_highband = 0; + } + + double vco_freq = target_freq*scaler; + double sys_clk = usrp()->fpga_master_clock_freq(); // Usually 64e6 + double ref_clk = sys_clk / d_ad9515_div; + + double phdet_freq = ref_clk/d_ref_div; + double div = vco_freq/phdet_freq; + d_int_div = int(floor(div)); + d_frac_div = int((div-d_int_div)*65536.0); + double actual_freq = phdet_freq*(d_int_div+(d_frac_div/65536.0))/scaler; + + //printf("RF=%f VCO=%f R=%d PHD=%f DIV=%3.5f I=%3d F=%5d ACT=%f", + // target_freq, vco_freq, d_ref_div, phdet_freq, + // div, d_int_div, d_frac_div, actual_freq); + + set_gpio(); + set_reg_int_divider(); + set_reg_frac_divider(); + set_reg_bandselpll(); + + args.ok = lock_detect(); + args.baseband_freq = actual_freq; + + if(args.ok) { + if((target_freq > 5.275e9) && (target_freq <= 5.35e9)) { + d_highband = 0; + set_reg_bandselpll(); + args.ok = lock_detect(); + printf("swap to 0 at %f, ok %d\n", target_freq, args.ok); + } + if((target_freq >= 5.25e9) && (target_freq <= 5.275e9)) { + d_highband = 1; + set_reg_bandselpll(); + args.ok = lock_detect(); + printf("swap to 1 at %f, ok %d\n", target_freq, args.ok); + } + if(!args.ok){ + printf("Fail %f\n", target_freq); + } + } + return args; +} + +bool +xcvr2450::lock_detect() +{ + /* + @returns: the value of the VCO/PLL lock detect bit. + @rtype: 0 or 1 + */ + if(rx_read_io() & LOCKDET) { + return true; + } + else { // Give it a second chance + if(rx_read_io() & LOCKDET) + return true; + else + return false; + } +} + +bool +xcvr2450::set_rx_gain(float gain) +{ + if(gain < 0.0) + gain = 0.0; + if(gain > 92.0) + gain = 92.0; + + // Split the gain between RF and baseband + // This is experimental, not prescribed + if(gain < 31.0) { + d_rx_rf_gain = 0; // 0 dB RF gain + rx_bb_gain = int(gain/2.0); + } + + if(gain >= 30.0 and gain < 60.5) { + d_rx_rf_gain = 2; // 15 dB RF gain + d_rx_bb_gain = int((gain-15.0)/2.0); + } + + if(gain >= 60.5) { + d_rx_rf_gain = 3; // 30.5 dB RF gain + d_rx_bb_gain = int((gain-30.5)/2.0); + } + + set_reg_rxgain(); + + return true; +} + +bool +xcvr2450::set_tx_gain(float gain) +{ + if(gain < 0.0) { + gain = 0.0; + } + if(gain > 30.0) { + gain = 30.0; + } + + d_txgain = int((gain/30.0)*63); + set_reg_txgain(); + + return true; +} + + +/*****************************************************************************/ + + +//_xcvr2450_inst = weakref.WeakValueDictionary() +std::vector _xcvr2450_inst; + +xcvr2450_sptr +_get_or_make_xcvr2450(usrp_basic_sptr usrp, int which) +{ + xcvr2450_sptr inst; + xcvr2450_key key = {usrp->serial_number(), which}; + std::vector::iterator itr; // = + //std::find(_xcvr2450_inst.begin(), _xcvr2450_inst.end(), key); + + for(itr = _xcvr2450_inst.begin(); itr != _xcvr2450_inst.end(); itr++) { + if(*(*itr) == key) { + printf("Using existing xcvr2450 instance\n"); + inst = *itr; + break; + } + } + + if(itr != _xcvr2450_inst.end()) { + printf("Creating new xcvr2450 instance\n"); + inst = xcvr2450_sptr(new xcvr2450(usrp, which)); + _xcvr2450_inst.push_back(inst); + } + + return inst; +} + + +/*****************************************************************************/ + + +db_xcvr2450_base::db_xcvr2450_base(usrp_basic_sptr usrp, int which) + : db_base(usrp, which) +{ + /* + * Abstract base class for all xcvr2450 boards. + * + * Derive board specific subclasses from db_xcvr2450_base_{tx,rx} + * + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to side A or B respectively + * @type which: int + */ + + d_xcvr = _get_or_make_xcvr2450(usrp, which); +} + +db_xcvr2450_base::~db_xcvr2450_base() +{ +} + +struct freq_result_t +db_xcvr2450_base::set_freq(double target_freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + return d_xcvr->set_freq(target_freq); +} + +bool +db_xcvr2450_base::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + +double +db_xcvr2450_base::freq_min() +{ + return 2.4e9; +} + +double +db_xcvr2450_base::freq_max() +{ + return 6.0e9; +} + + +/******************************************************************************/ + + +db_xcvr2450_tx::db_xcvr2450_tx(usrp_basic_sptr usrp, int which) + : db_xcvr2450_base(usrp, which) +{ + printf("db_xcvr2450_tx::db_xcvr2450_tx\n"); +} + +db_xcvr2450_tx::~db_xcvr2450_tx() +{ +} + +float +db_xcvr2450_tx::gain_min() +{ + return 0; +} + +float +db_xcvr2450_tx::gain_max() +{ + return 30; +} + +float +db_xcvr2450_tx::gain_db_per_step() +{ + return (30.0/63.0); +} + +bool +db_xcvr2450_tx::set_gain(float gain) +{ + return d_xcvr->set_tx_gain(gain); +} + +bool +db_xcvr2450_tx::i_and_q_swapped() +{ + return true; +} + + +/******************************************************************************/ + + +db_xcvr2450_rx::db_xcvr2450_rx(usrp_basic_sptr usrp, int which) + : db_xcvr2450_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + printf("db_xcvr2450_rx:d_xcvr_2450_rx\n"); +} + +db_xcvr2450_rx::~db_xcvr2450_rx() +{ +} + +float +db_xcvr2450_rx::gain_min() +{ + return 0.0; +} + +float +db_xcvr2450_rx::gain_max() +{ + return 92.0; +} + +float +db_xcvr2450_rx::gain_db_per_step() +{ + return 1; +} + +bool +db_xcvr2450_rx::set_gain(float gain) +{ + return d_xcvr->set_rx_gain(gain); +} diff --git a/usrp/host/lib/legacy/db_xcvr2450.h b/usrp/host/lib/legacy/db_xcvr2450.h new file mode 100644 index 00000000..a67c4302 --- /dev/null +++ b/usrp/host/lib/legacy/db_xcvr2450.h @@ -0,0 +1,221 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 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 asversion 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. + +#ifndef DB_XCVR2450_H +#define DB_XCVR2450_H + +#include +#include + +// TX IO Pins +#define HB_PA_OFF (1 << 15) // 5GHz PA, 1 = off, 0 = on +#define LB_PA_OFF (1 << 14) // 2.4GHz PA, 1 = off, 0 = on +#define ANTSEL_TX1_RX2 (1 << 13) // 1 = Ant 1 to TX, Ant 2 to RX +#define ANTSEL_TX2_RX1 (1 << 12) // 1 = Ant 2 to TX, Ant 1 to RX +#define TX_EN (1 << 11) // 1 = TX on, 0 = TX off +#define AD9515DIV (1 << 4) // 1 = Div by 3, 0 = Div by 2 + +#define TX_OE_MASK HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV +#define TX_SAFE_IO HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV + +// RX IO Pins +#define LOCKDET (1 << 15) // This is an INPUT!!! +#define EN (1 << 14) +#define RX_EN (1 << 13) // 1 = RX on, 0 = RX off +#define RX_HP (1 << 12) +#define B1 (1 << 11) +#define B2 (1 << 10) +#define B3 (1 << 9) +#define B4 (1 << 8) +#define B5 (1 << 7) +#define B6 (1 << 6) +#define B7 (1 << 5) +#define RX_OE_MASK EN|RX_EN|RX_HP|B1|B2|B3|B4|B5|B6|B7 +#define RX_SAFE_IO EN + +struct xcvr2450_key { + std::string serial_no; + int which; +}; + +class xcvr2450; +typedef boost::shared_ptr xcvr2450_sptr; + +class xcvr2450 +{ +private: + boost::weak_ptr d_weak_usrp; + int d_which; + + int d_spi_format, d_spi_enable; + + int d_mimo, d_int_div, d_frac_div, d_highband, d_five_gig; + int d_cp_current, d_ref_div, d_rssi_hbw; + int d_txlpf_bw, d_rxlpf_bw, d_rxlpf_fine, d_rxvga_ser; + int d_rssi_range, d_rssi_mode, d_rssi_mux; + int d_rx_hp_pin, d_rx_hpf, d_rx_ant; + int d_tx_ant, d_txvga_ser, d_tx_driver_lin; + int d_tx_vga_lin, d_tx_upconv_lin, d_tx_bb_gain; + int d_pabias_delay, d_pabias, rx_rf_gain, rx_bb_gain, d_txgain; + int d_rx_rf_gain, d_rx_bb_gain; + + int d_reg_standby, d_reg_int_divider, d_reg_frac_divider, d_reg_bandselpll; + int d_reg_cal, dsend_reg, d_reg_lpf, d_reg_rxrssi_ctrl, d_reg_txlin_gain; + int d_reg_pabias, d_reg_rxgain, d_reg_txgain; + + int d_ad9515_div; + + void _set_rfagc(float gain); + void _set_ifagc(float gain); + void _set_pga(float pga_gain); + + usrp_basic_sptr usrp(){ + return usrp_basic_sptr(d_weak_usrp); // throws bad_weak_ptr if d_usrp.use_count() == 0 + } + +public: + xcvr2450(usrp_basic_sptr usrp, int which); + ~xcvr2450(); + + bool operator==(xcvr2450_key x); + + void set_reg_standby(); + + // Integer-Divider Ratio (3) + void set_reg_int_divider(); + + // Fractional-Divider Ratio (4) + void set_reg_frac_divider(); + + // Band Select and PLL (5) + void set_reg_bandselpll(); + + // Calibration (6) + void set_reg_cal(); + + // Lowpass Filter (7) + void set_reg_lpf(); + + // Rx Control/RSSI (8) + void set_reg_rxrssi_ctrl(); + + // Tx Linearity/Baseband Gain (9) + void set_reg_txlin_gain(); + + // PA Bias DAC (10) + void set_reg_pabias(); + + // Rx Gain (11) + void set_reg_rxgain(); + + // Tx Gain (12) + void set_reg_txgain(); + + // Send register write to SPI + void send_reg(int v); + + // -------------------------------------------------------------------- + // These methods control the GPIO bus. Since the board has to access + // both the io_rx_* and io_tx_* pins, we define our own methods to do so. + // This bypasses any code in db_base. + // + // The board operates in ATR mode, always. Thus, when the board is first + // initialized, it is in receive mode, until bits show up in the TX FIFO. + // + + // FIXME these should just call the similarly named common_* method on usrp_basic + + bool tx_write_oe(int value, int mask); + bool tx_write_io(int value, int mask); + int tx_read_io(); + bool rx_write_oe(int value, int mask); + bool rx_write_io(int value, int mask); + int rx_read_io(); + bool tx_set_atr_mask(int v); + bool tx_set_atr_txval(int v); + bool tx_set_atr_rxval(int v); + bool rx_set_atr_mask(int v); + bool rx_set_atr_txval(int v); + bool rx_set_atr_rxval(int v); + + void set_gpio(); + bool lock_detect(); + bool set_rx_gain(float gain); + bool set_tx_gain(float gain); + + struct freq_result_t set_freq(double target_freq); +}; + + +/******************************************************************************/ + + +class db_xcvr2450_base: public db_base +{ + /* + * Abstract base class for all xcvr2450 boards. + * + * Derive board specific subclasses from db_xcvr2450_base_{tx,rx} + */ +public: + db_xcvr2450_base(usrp_basic_sptr usrp, int which); + ~db_xcvr2450_base(); + struct freq_result_t set_freq(double target_freq); + bool is_quadrature(); + double freq_min(); + double freq_max(); + +protected: + xcvr2450_sptr d_xcvr; +}; + + +/******************************************************************************/ + + +class db_xcvr2450_tx : public db_xcvr2450_base +{ +public: + db_xcvr2450_tx(usrp_basic_sptr usrp, int which); + ~db_xcvr2450_tx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + bool i_and_q_swapped(); +}; + +class db_xcvr2450_rx : public db_xcvr2450_base +{ +public: + db_xcvr2450_rx(usrp_basic_sptr usrp, int which); + ~db_xcvr2450_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); +}; + + + +#endif diff --git a/usrp/host/lib/legacy/usrp_basic.cc b/usrp/host/lib/legacy/usrp_basic.cc index f6730030..e63a097a 100644 --- a/usrp/host/lib/legacy/usrp_basic.cc +++ b/usrp/host/lib/legacy/usrp_basic.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2004 Free Software Foundation, Inc. + * Copyright 2003,2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -28,7 +28,9 @@ #include "usrp_prims.h" #include "usrp_interfaces.h" #include "fpga_regs_common.h" +#include "fpga_regs_standard.h" #include "fusb.h" +#include "db_boards.h" #include #include #include @@ -110,7 +112,7 @@ usrp_basic::usrp_basic (int which_board, : d_udh (0), d_usb_data_rate (16000000), // SWAG, see below d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)), - d_verbose (false) + d_verbose (false), d_db(2) { /* * SWAG: Scientific Wild Ass Guess. @@ -154,12 +156,65 @@ usrp_basic::usrp_basic (int which_board, _write_fpga_reg (FR_DEBUG_EN, 0); // disable debug outputs } +void +usrp_basic::shutdown_daughterboards() +{ + // nuke d'boards before we close down USB in ~usrp_basic + // shutdown() will do any board shutdown while the USRP can still + // be talked to + for(size_t i = 0; i < d_db.size(); i++) + for(size_t j = 0; j < d_db[i].size(); j++) + d_db[i][j]->shutdown(); +} + usrp_basic::~usrp_basic () { + // shutdown_daughterboards(); // call from ~usrp_basic_{tx,rx} + + d_db.resize(0); // forget db shared ptrs + if (d_udh) usb_close (d_udh); } +void +usrp_basic::init_db(usrp_basic_sptr u) +{ + if (u.get() != this) + throw std::invalid_argument("u is not this"); + + d_db[0] = instantiate_dbs(d_dbid[0], u, 0); + d_db[1] = instantiate_dbs(d_dbid[1], u, 1); +} + +std::vector +usrp_basic::db(int which_side) +{ + which_side &= 0x1; // clamp it to avoid any reporting any errors + return d_db[which_side]; +} + +bool +usrp_basic::is_valid(const usrp_subdev_spec &ss) +{ + if (ss.side < 0 || ss.side > 1) + return false; + + if (ss.subdev < 0 || ss.subdev >= d_db[ss.side].size()) + return false; + + return true; +} + +db_base_sptr +usrp_basic::selected_subdev(const usrp_subdev_spec &ss) +{ + if (!is_valid(ss)) + throw std::invalid_argument("invalid subdev_spec"); + + return d_db[ss.side][ss.subdev]; +} + bool usrp_basic::start () { @@ -180,22 +235,22 @@ usrp_basic::set_usb_data_rate (int usb_data_rate) } bool -usrp_basic::write_aux_dac (int slot, int which_dac, int value) +usrp_basic::_write_aux_dac (int slot, int which_dac, int value) { return usrp_write_aux_dac (d_udh, slot, which_dac, value); } bool -usrp_basic::read_aux_adc (int slot, int which_adc, int *value) +usrp_basic::_read_aux_adc (int slot, int which_adc, int *value) { return usrp_read_aux_adc (d_udh, slot, which_adc, value); } int -usrp_basic::read_aux_adc (int slot, int which_adc) +usrp_basic::_read_aux_adc (int slot, int which_adc) { int value; - if (!read_aux_adc (slot, which_adc, &value)) + if (!_read_aux_adc (slot, which_adc, &value)) return READ_FAILED; return value; @@ -250,22 +305,22 @@ usrp_basic::serial_number() // ---------------------------------------------------------------- bool -usrp_basic::set_adc_offset (int which, int offset) +usrp_basic::set_adc_offset (int which_adc, int offset) { - if (which < 0 || which > 3) + if (which_adc < 0 || which_adc > 3) return false; - return _write_fpga_reg (FR_ADC_OFFSET_0 + which, offset); + return _write_fpga_reg (FR_ADC_OFFSET_0 + which_adc, offset); } bool -usrp_basic::set_dac_offset (int which, int offset, int offset_pin) +usrp_basic::set_dac_offset (int which_dac, int offset, int offset_pin) { - if (which < 0 || which > 3) + if (which_dac < 0 || which_dac > 3) return false; - int which_codec = which >> 1; - int tx_a = (which & 0x1) == 0; + int which_codec = which_dac >> 1; + int tx_a = (which_dac & 0x1) == 0; int lo = ((offset & 0x3) << 6) | (offset_pin & 0x1); int hi = (offset >> 2); bool ok; @@ -282,13 +337,13 @@ usrp_basic::set_dac_offset (int which, int offset, int offset_pin) } bool -usrp_basic::set_adc_buffer_bypass (int which, bool bypass) +usrp_basic::set_adc_buffer_bypass (int which_adc, bool bypass) { - if (which < 0 || which > 3) + if (which_adc < 0 || which_adc > 3) return false; - int codec = which >> 1; - int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B; + int codec = which_adc >> 1; + int reg = (which_adc & 1) == 0 ? REG_RX_A : REG_RX_B; unsigned char cur_rx; unsigned char cur_pwr_dn; @@ -302,11 +357,11 @@ usrp_basic::set_adc_buffer_bypass (int which, bool bypass) if (bypass){ cur_rx |= RX_X_BYPASS_INPUT_BUFFER; - cur_pwr_dn |= ((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B; + cur_pwr_dn |= ((which_adc & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B; } else { cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER; - cur_pwr_dn &= ~(((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B); + cur_pwr_dn &= ~(((which_adc & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B); } ok &= _write_9862 (codec, reg, cur_rx); @@ -314,6 +369,13 @@ usrp_basic::set_adc_buffer_bypass (int which, bool bypass) return ok; } +bool +usrp_basic::set_dc_offset_cl_enable(int bits, int mask) +{ + return _write_fpga_reg(FR_DC_OFFSET_CL_EN, + (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & mask)); +} + // ---------------------------------------------------------------- bool @@ -413,11 +475,278 @@ usrp_basic::_read_spi (int optional_header, int enables, int format, int len) bool -usrp_basic::_set_led (int which, bool on) +usrp_basic::_set_led (int which_led, bool on) +{ + return usrp_set_led (d_udh, which_led, on); +} + +bool +usrp_basic::write_atr_tx_delay(int value) +{ + return _write_fpga_reg(FR_ATR_TX_DELAY, value); +} + +bool +usrp_basic::write_atr_rx_delay(int value) +{ + return _write_fpga_reg(FR_ATR_RX_DELAY, value); +} + +/* + * ---------------------------------------------------------------- + * Routines to access and control daughterboard specific i/o + * ---------------------------------------------------------------- + */ +static int +slot_id_to_oe_reg (int slot_id) +{ + static int reg[4] = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_io_reg (int slot_id) +{ + static int reg[4] = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_refclk_reg(int slot_id) +{ + static int reg[4] = { FR_TX_A_REFCLK, FR_RX_A_REFCLK, FR_TX_B_REFCLK, FR_RX_B_REFCLK }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_atr_mask_reg(int slot_id) +{ + static int reg[4] = { FR_ATR_MASK_0, FR_ATR_MASK_1, FR_ATR_MASK_2, FR_ATR_MASK_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_atr_txval_reg(int slot_id) +{ + static int reg[4] = { FR_ATR_TXVAL_0, FR_ATR_TXVAL_1, FR_ATR_TXVAL_2, FR_ATR_TXVAL_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +slot_id_to_atr_rxval_reg(int slot_id) +{ + static int reg[4] = { FR_ATR_RXVAL_0, FR_ATR_RXVAL_1, FR_ATR_RXVAL_2, FR_ATR_RXVAL_3 }; + assert (0 <= slot_id && slot_id < 4); + return reg[slot_id]; +} + +static int +to_slot(txrx_t txrx, int which_side) +{ + // TX_A = 0 + // RX_A = 1 + // TX_B = 2 + // RX_B = 3 + return ((which_side & 0x1) << 1) | ((txrx & 0x1) == C_RX); +} + +bool +usrp_basic::common_set_pga(txrx_t txrx, int which_amp, double gain) +{ + if (which_amp < 0 || which_amp > 3) + return false; + + gain = std::min(common_pga_max(txrx), + std::max(common_pga_min(txrx), gain)); + + int codec = which_amp >> 1; + int int_gain = (int) rint((gain - common_pga_min(txrx)) / common_pga_db_per_step(txrx)); + + if (txrx == C_TX){ // 0 and 1 are same, as are 2 and 3 + return _write_9862(codec, REG_TX_PGA, int_gain); + } + else { + int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B; + + // read current value to get input buffer bypass flag. + unsigned char cur_rx; + if (!_read_9862(codec, reg, &cur_rx)) + return false; + + cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f); + return _write_9862(codec, reg, cur_rx); + } +} + +double +usrp_basic::common_pga(txrx_t txrx, int which_amp) const +{ + if (which_amp < 0 || which_amp > 3) + return READ_FAILED; + + if (txrx == C_TX){ + int codec = which_amp >> 1; + unsigned char v; + bool ok = _read_9862 (codec, REG_TX_PGA, &v); + if (!ok) + return READ_FAILED; + + return (pga_db_per_step() * v) + pga_min(); + } + else { + int codec = which_amp >> 1; + int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B; + unsigned char v; + bool ok = _read_9862 (codec, reg, &v); + if (!ok) + return READ_FAILED; + + return (pga_db_per_step() * (v & 0x1f)) + pga_min(); + } +} + +double +usrp_basic::common_pga_min(txrx_t txrx) const +{ + if (txrx == C_TX) + return -20.0; + else + return 0.0; +} + +double +usrp_basic::common_pga_max(txrx_t txrx) const +{ + if (txrx == C_TX) + return 0.0; + else + return 20.0; +} + +double +usrp_basic::common_pga_db_per_step(txrx_t txrx) const +{ + if (txrx == C_TX) + return 20.0 / 255; + else + return 20.0 / 20; +} + +bool +usrp_basic::_common_write_oe(txrx_t txrx, int which_side, int value, int mask) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_oe_reg(to_slot(txrx, which_side)), + (mask << 16) | (value & 0xffff)); +} + +bool +usrp_basic::common_write_io(txrx_t txrx, int which_side, int value, int mask) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_io_reg(to_slot(txrx, which_side)), + (mask << 16) | (value & 0xffff)); +} + +bool +usrp_basic::common_read_io(txrx_t txrx, int which_side, int *value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + int t; + int reg = which_side + 1; // FIXME, *very* magic number (fix in serial_io.v) + bool ok = _read_fpga_reg(reg, &t); + if (!ok) + return false; + + if (txrx == C_TX){ + *value = t & 0xffff; // FIXME, more magic + return true; + } + else { + *value = (t >> 16) & 0xffff; // FIXME, more magic + return true; + } +} + +int +usrp_basic::common_read_io(txrx_t txrx, int which_side) +{ + int value; + if (!common_read_io(txrx, which_side, &value)) + return READ_FAILED; + return value; +} + +bool +usrp_basic::common_write_refclk(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_refclk_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_atr_mask(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_atr_mask_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_atr_txval(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_atr_txval_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_atr_rxval(txrx_t txrx, int which_side, int value) +{ + if (! (0 <= which_side && which_side <= 1)) + return false; + + return _write_fpga_reg(slot_id_to_atr_rxval_reg(to_slot(txrx, which_side)), + value); +} + +bool +usrp_basic::common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value) { - return usrp_set_led (d_udh, which, on); + return _write_aux_dac(to_slot(txrx, which_side), which_dac, value); } +bool +usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value) +{ + return _read_aux_adc(to_slot(txrx, which_side), which_adc, value); +} + +int +usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc) +{ + return _read_aux_adc(to_slot(txrx, which_side), which_adc); +} + + //////////////////////////////////////////////////////////////// // // usrp_basic_rx @@ -467,6 +796,9 @@ usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int fusb_nbl probe_rx_slots (false); + //d_db[0] = instantiate_dbs(d_dbid[0], this, 0); + //d_db[1] = instantiate_dbs(d_dbid[1], this, 1); + // check fusb buffering parameters if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE) @@ -485,12 +817,12 @@ usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int fusb_nbl d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true, fusb_block_size, fusb_nblocks); - _write_fpga_reg(FR_ATR_MASK_1, 0); // zero Rx side Auto Transmit/Receive regs - _write_fpga_reg(FR_ATR_TXVAL_1, 0); - _write_fpga_reg(FR_ATR_RXVAL_1, 0); - _write_fpga_reg(FR_ATR_MASK_3, 0); - _write_fpga_reg(FR_ATR_TXVAL_3, 0); - _write_fpga_reg(FR_ATR_RXVAL_3, 0); + write_atr_mask(0, 0); // zero Rx A Auto Transmit/Receive regs + write_atr_txval(0, 0); + write_atr_rxval(0, 0); + write_atr_mask(1, 0); // zero Rx B Auto Transmit/Receive regs + write_atr_txval(1, 0); + write_atr_rxval(1, 0); } static unsigned char rx_fini_regs[] = { @@ -511,6 +843,8 @@ usrp_basic_rx::~usrp_basic_rx () if (!usrp_9862_write_many_all (d_udh, rx_fini_regs, sizeof (rx_fini_regs))){ fprintf (stderr, "usrp_basic_rx: failed to fini AD9862 RX regs\n"); } + + shutdown_daughterboards(); } @@ -656,61 +990,6 @@ usrp_basic_rx::restore_rx (bool on) set_rx_enable (on); } -bool -usrp_basic_rx::set_pga (int which, double gain) -{ - if (which < 0 || which > 3) - return false; - - gain = std::max (pga_min (), gain); - gain = std::min (pga_max (), gain); - - int codec = which >> 1; - int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B; - - // read current value to get input buffer bypass flag. - unsigned char cur_rx; - if (!_read_9862 (codec, reg, &cur_rx)) - return false; - - int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step()); - - cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f); - return _write_9862 (codec, reg, cur_rx); -} - -double -usrp_basic_rx::pga (int which) const -{ - if (which < 0 || which > 3) - return READ_FAILED; - - int codec = which >> 1; - int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B; - unsigned char v; - bool ok = _read_9862 (codec, reg, &v); - if (!ok) - return READ_FAILED; - - return (pga_db_per_step() * (v & 0x1f)) + pga_min(); -} - -static int -slot_id_to_oe_reg (int slot_id) -{ - static int reg[4] = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 }; - assert (0 <= slot_id && slot_id < 4); - return reg[slot_id]; -} - -static int -slot_id_to_io_reg (int slot_id) -{ - static int reg[4] = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 }; - assert (0 <= slot_id && slot_id < 4); - return reg[slot_id]; -} - void usrp_basic_rx::probe_rx_slots (bool verbose) { @@ -760,80 +1039,104 @@ usrp_basic_rx::probe_rx_slots (bool verbose) } bool -usrp_basic_rx::_write_oe (int which_dboard, int value, int mask) +usrp_basic_rx::set_pga (int which_amp, double gain) { - if (! (0 <= which_dboard && which_dboard <= 1)) - return false; + return common_set_pga(C_RX, which_amp, gain); +} - return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (which_dboard)), - (mask << 16) | (value & 0xffff)); +double +usrp_basic_rx::pga(int which_amp) const +{ + return common_pga(C_RX, which_amp); } -bool -usrp_basic_rx::write_io (int which_dboard, int value, int mask) +double +usrp_basic_rx::pga_min() const { - if (! (0 <= which_dboard && which_dboard <= 1)) - return false; + return common_pga_min(C_RX); +} - return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (which_dboard)), - (mask << 16) | (value & 0xffff)); +double +usrp_basic_rx::pga_max() const +{ + return common_pga_max(C_RX); +} + +double +usrp_basic_rx::pga_db_per_step() const +{ + return common_pga_db_per_step(C_RX); } bool -usrp_basic_rx::read_io (int which_dboard, int *value) +usrp_basic_rx::_write_oe (int which_side, int value, int mask) { - if (! (0 <= which_dboard && which_dboard <= 1)) - return false; + return _common_write_oe(C_RX, which_side, value, mask); +} - int t; - int reg = which_dboard + 1; // FIXME, *very* magic number (fix in serial_io.v) - bool ok = _read_fpga_reg (reg, &t); - if (!ok) - return false; +bool +usrp_basic_rx::write_io (int which_side, int value, int mask) +{ + return common_write_io(C_RX, which_side, value, mask); +} - *value = (t >> 16) & 0xffff; // FIXME, more magic - return true; +bool +usrp_basic_rx::read_io (int which_side, int *value) +{ + return common_read_io(C_RX, which_side, value); } int -usrp_basic_rx::read_io (int which_dboard) +usrp_basic_rx::read_io (int which_side) { - int value; - if (!read_io (which_dboard, &value)) - return READ_FAILED; - return value; + return common_read_io(C_RX, which_side); } bool -usrp_basic_rx::write_aux_dac (int which_dboard, int which_dac, int value) +usrp_basic_rx::write_refclk(int which_side, int value) { - return usrp_basic::write_aux_dac (dboard_to_slot (which_dboard), - which_dac, value); + return common_write_refclk(C_RX, which_side, value); } bool -usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc, int *value) +usrp_basic_rx::write_atr_mask(int which_side, int value) { - return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), - which_adc, value); + return common_write_atr_mask(C_RX, which_side, value); } -int -usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc) +bool +usrp_basic_rx::write_atr_txval(int which_side, int value) { - return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), which_adc); + return common_write_atr_txval(C_RX, which_side, value); } -int -usrp_basic_rx::block_size () const { return d_ephandle->block_size(); } +bool +usrp_basic_rx::write_atr_rxval(int which_side, int value) +{ + return common_write_atr_rxval(C_RX, which_side, value); +} bool -usrp_basic_rx::set_dc_offset_cl_enable(int bits, int mask) +usrp_basic_rx::write_aux_dac (int which_side, int which_dac, int value) { - return _write_fpga_reg(FR_DC_OFFSET_CL_EN, - (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & mask)); + return common_write_aux_dac(C_RX, which_side, which_dac, value); +} + +bool +usrp_basic_rx::read_aux_adc (int which_side, int which_adc, int *value) +{ + return common_read_aux_adc(C_RX, which_side, which_adc, value); } +int +usrp_basic_rx::read_aux_adc (int which_side, int which_adc) +{ + return common_read_aux_adc(C_RX, which_side, which_adc); +} + +int +usrp_basic_rx::block_size () const { return d_ephandle->block_size(); } + //////////////////////////////////////////////////////////////// // // usrp_basic_tx @@ -902,6 +1205,9 @@ usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nbl probe_tx_slots (false); + //d_db[0] = instantiate_dbs(d_dbid[0], this, 0); + //d_db[1] = instantiate_dbs(d_dbid[1], this, 1); + // check fusb buffering parameters if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE) @@ -920,12 +1226,12 @@ usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nbl d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false, fusb_block_size, fusb_nblocks); - _write_fpga_reg(FR_ATR_MASK_0, 0); // zero Tx side Auto Transmit/Receive regs - _write_fpga_reg(FR_ATR_TXVAL_0, 0); - _write_fpga_reg(FR_ATR_RXVAL_0, 0); - _write_fpga_reg(FR_ATR_MASK_2, 0); - _write_fpga_reg(FR_ATR_TXVAL_2, 0); - _write_fpga_reg(FR_ATR_RXVAL_2, 0); + write_atr_mask(0, 0); // zero Tx A Auto Transmit/Receive regs + write_atr_txval(0, 0); + write_atr_rxval(0, 0); + write_atr_mask(1, 0); // zero Tx B Auto Transmit/Receive regs + write_atr_txval(1, 0); + write_atr_rxval(1, 0); } @@ -945,6 +1251,8 @@ usrp_basic_tx::~usrp_basic_tx () if (!usrp_9862_write_many_all (d_udh, tx_fini_regs, sizeof (tx_fini_regs))){ fprintf (stderr, "usrp_basic_tx: failed to fini AD9862 TX regs\n"); } + + shutdown_daughterboards(); } bool @@ -1094,37 +1402,6 @@ usrp_basic_tx::restore_tx (bool on) set_tx_enable (on); } -bool -usrp_basic_tx::set_pga (int which, double gain) -{ - if (which < 0 || which > 3) - return false; - - gain = std::max (pga_min (), gain); - gain = std::min (pga_max (), gain); - - int codec = which >> 1; // 0 and 1 are same, as are 2 and 3 - - int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step()); - - return _write_9862 (codec, REG_TX_PGA, int_gain); -} - -double -usrp_basic_tx::pga (int which) const -{ - if (which < 0 || which > 3) - return READ_FAILED; - - int codec = which >> 1; - unsigned char v; - bool ok = _read_9862 (codec, REG_TX_PGA, &v); - if (!ok) - return READ_FAILED; - - return (pga_db_per_step() * v) + pga_min(); -} - void usrp_basic_tx::probe_tx_slots (bool verbose) { @@ -1174,68 +1451,99 @@ usrp_basic_tx::probe_tx_slots (bool verbose) } bool -usrp_basic_tx::_write_oe (int which_dboard, int value, int mask) +usrp_basic_tx::set_pga (int which_amp, double gain) { - if (! (0 <= which_dboard && which_dboard <= 1)) - return false; + return common_set_pga(C_TX, which_amp, gain); +} - return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (which_dboard)), - (mask << 16) | (value & 0xffff)); +double +usrp_basic_tx::pga (int which_amp) const +{ + return common_pga(C_TX, which_amp); } -bool -usrp_basic_tx::write_io (int which_dboard, int value, int mask) +double +usrp_basic_tx::pga_min() const { - if (! (0 <= which_dboard && which_dboard <= 1)) - return false; + return common_pga_min(C_TX); +} - return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (which_dboard)), - (mask << 16) | (value & 0xffff)); +double +usrp_basic_tx::pga_max() const +{ + return common_pga_max(C_TX); +} + +double +usrp_basic_tx::pga_db_per_step() const +{ + return common_pga_db_per_step(C_TX); } bool -usrp_basic_tx::read_io (int which_dboard, int *value) +usrp_basic_tx::_write_oe (int which_side, int value, int mask) { - if (! (0 <= which_dboard && which_dboard <= 1)) - return false; + return _common_write_oe(C_TX, which_side, value, mask); +} - int t; - int reg = which_dboard + 1; // FIXME, *very* magic number (fix in serial_io.v) - bool ok = _read_fpga_reg (reg, &t); - if (!ok) - return false; +bool +usrp_basic_tx::write_io (int which_side, int value, int mask) +{ + return common_write_io(C_TX, which_side, value, mask); +} - *value = t & 0xffff; // FIXME, more magic - return true; +bool +usrp_basic_tx::read_io (int which_side, int *value) +{ + return common_read_io(C_TX, which_side, value); } int -usrp_basic_tx::read_io (int which_dboard) +usrp_basic_tx::read_io (int which_side) { - int value; - if (!read_io (which_dboard, &value)) - return READ_FAILED; - return value; + return common_read_io(C_TX, which_side); +} + +bool +usrp_basic_tx::write_refclk(int which_side, int value) +{ + return common_write_refclk(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_atr_mask(int which_side, int value) +{ + return common_write_atr_mask(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_atr_txval(int which_side, int value) +{ + return common_write_atr_txval(C_TX, which_side, value); +} + +bool +usrp_basic_tx::write_atr_rxval(int which_side, int value) +{ + return common_write_atr_rxval(C_TX, which_side, value); } bool -usrp_basic_tx::write_aux_dac (int which_dboard, int which_dac, int value) +usrp_basic_tx::write_aux_dac (int which_side, int which_dac, int value) { - return usrp_basic::write_aux_dac (dboard_to_slot (which_dboard), - which_dac, value); + return common_write_aux_dac(C_TX, which_side, which_dac, value); } bool -usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc, int *value) +usrp_basic_tx::read_aux_adc (int which_side, int which_adc, int *value) { - return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), - which_adc, value); + return common_read_aux_adc(C_TX, which_side, which_adc, value); } int -usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc) +usrp_basic_tx::read_aux_adc (int which_side, int which_adc) { - return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), which_adc); + return common_read_aux_adc(C_TX, which_side, which_adc); } int diff --git a/usrp/host/lib/legacy/usrp_basic.h b/usrp/host/lib/legacy/usrp_basic.h index 395a1dac..c5e3d282 100644 --- a/usrp/host/lib/legacy/usrp_basic.h +++ b/usrp/host/lib/legacy/usrp_basic.h @@ -1,6 +1,7 @@ + /* -*- c++ -*- */ /* - * Copyright 2003,2004 Free Software Foundation, Inc. + * Copyright 2003,2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -39,24 +40,30 @@ #ifndef INCLUDED_USRP_BASIC_H #define INCLUDED_USRP_BASIC_H +#include #include #include +#include +#include +#include struct usb_dev_handle; class fusb_devhandle; class fusb_ephandle; +enum txrx_t { + C_RX = 0, + C_TX = 1 +}; + /*! - * \brief base class for usrp operations + * \brief abstract base class for usrp operations */ -class usrp_basic +class usrp_basic : boost::noncopyable { -private: - // NOT IMPLEMENTED - usrp_basic (const usrp_basic &rhs); // no copy constructor - usrp_basic &operator= (const usrp_basic &rhs); // no assignment operator +protected: + void shutdown_daughterboards(); - protected: struct usb_dev_handle *d_udh; int d_usb_data_rate; // bytes/sec @@ -66,6 +73,22 @@ protected: static const int MAX_REGS = 128; unsigned int d_fpga_shadows[MAX_REGS]; + int d_dbid[2]; // daughterboard ID's (side A, side B) + + /*! + * Shared pointers to subclasses of db_base. + * + * The outer vector is of length 2 (0 = side A, 1 = side B). The + * inner vectors are of length 1, 2 or 3 depending on the number of + * subdevices implemented by the daugherboard. At this time, only + * the Basic Rx and LF Rx implement more than 1 subdevice. + */ + std::vector< std::vector > d_db; + + //! One time call, made only only from usrp_standard_*::make after shared_ptr is created. + void init_db(usrp_basic_sptr u); + + usrp_basic (int which_board, struct usb_dev_handle *open_interface (struct usb_device *dev), const std::string fpga_filename = "", @@ -92,7 +115,7 @@ protected: * \param value [0,4095] * \returns true iff successful */ - bool write_aux_dac (int slot, int which_dac, int value); + bool _write_aux_dac (int slot, int which_dac, int value); /*! * \brief Read auxiliary analog to digital converter. @@ -102,7 +125,7 @@ protected: * \param value return 12-bit value [0,4095] * \returns true iff successful */ - bool read_aux_adc (int slot, int which_adc, int *value); + bool _read_aux_adc (int slot, int which_adc, int *value); /*! * \brief Read auxiliary analog to digital converter. @@ -111,11 +134,46 @@ protected: * \param which_adc [0,1] * \returns value in the range [0,4095] if successful, else READ_FAILED. */ - int read_aux_adc (int slot, int which_adc); + int _read_aux_adc (int slot, int which_adc); + public: virtual ~usrp_basic (); + + /*! + * Return a vector of vectors that contain shared pointers + * to the daughterboard instance(s) associated with the specified side. + * + * It is an error to use the returned objects after the usrp_basic + * object has been destroyed. + */ + std::vector > db() const { return d_db; } + + /*! + * Return a vector of size >= 1 that contains shared pointers + * to the daughterboard instance(s) associated with the specified side. + * + * \param which_side [0,1] which daughterboard + * + * It is an error to use the returned objects after the usrp_basic + * object has been destroyed. + */ + std::vector db(int which_side); + + /*! + * \brief is the subdev_spec valid? + */ + bool is_valid(const usrp_subdev_spec &ss); + + /*! + * \brief given a subdev_spec, return the corresponding daughterboard object. + * \throws std::invalid_ argument if ss is invalid. + * + * \param ss specifies the side and subdevice + */ + db_base_sptr selected_subdev(const usrp_subdev_spec &ss); + /*! * \brief return frequency of master oscillator on USRP */ @@ -172,7 +230,7 @@ public: * \param which which ADC[0,3]: 0 = RX_A I, 1 = RX_A Q... * \param offset 16-bit value to subtract from raw ADC input. */ - bool set_adc_offset (int which, int offset); + bool set_adc_offset (int which_adc, int offset); /*! * \brief Set DAC offset correction @@ -181,16 +239,37 @@ public: * \param offset_pin 1-bit value. If 0 offset applied to -ve differential pin; * If 1 offset applied to +ve differential pin. */ - bool set_dac_offset (int which, int offset, int offset_pin); + bool set_dac_offset (int which_dac, int offset, int offset_pin); /*! * \brief Control ADC input buffer - * \param which which ADC[0,3] + * \param which_adc which ADC[0,3] * \param bypass if non-zero, bypass input buffer and connect input * directly to switched cap SHA input of RxPGA. */ - bool set_adc_buffer_bypass (int which, bool bypass); + bool set_adc_buffer_bypass (int which_adc, bool bypass); + /*! + * \brief Enable/disable automatic DC offset removal control loop in FPGA + * + * \param bits which control loops to enable + * \param mask which \p bits to pay attention to + * + * If the corresponding bit is set, enable the automatic DC + * offset correction control loop. + * + *
+   * The 4 low bits are significant:
+   *
+   *   ADC0 = (1 << 0)
+   *   ADC1 = (1 << 1)
+   *   ADC2 = (1 << 2)
+   *   ADC3 = (1 << 3)
+   * 
+ * + * By default the control loop is enabled on all ADC's. + */ + bool set_dc_offset_cl_enable(int bits, int mask); /*! * \brief return the usrp's serial number. @@ -199,12 +278,376 @@ public: */ std::string serial_number(); + /*! + * \brief Return daughterboard ID for given side [0,1]. + * + * \param which_side [0,1] which daughterboard + * + * \return daughterboard id >= 0 if successful + * \return -1 if no daugherboard + * \return -2 if invalid EEPROM on daughterboard + */ + virtual int daughterboard_id (int which_side) const = 0; + + /*! + * \brief Clock ticks to delay rising of T/R signal + * \sa write_atr_mask, write_atr_txval, write_atr_rxval + */ + bool write_atr_tx_delay(int value); + + /*! + * \brief Clock ticks to delay falling edge of T/R signal + * \sa write_atr_mask, write_atr_txval, write_atr_rxval + */ + bool write_atr_rx_delay(int value); + + + // ================================================================ + // Routines to access and control daughterboard specific i/o + // + // Those with a common_ prefix access either the Tx or Rx side depending + // on the txrx parameter. Those without the common_ prefix are virtual + // and are overriden in usrp_basic_rx and usrp_basic_tx to access the + // the Rx or Tx sides automatically. We provide the common_ versions + // for those daughterboards such as the WBX and XCVR2450 that share + // h/w resources (such as the LO) between the Tx and Rx sides. + + // ---------------------------------------------------------------- + // BEGIN common_ daughterboard control functions + + /*! + * \brief Set Programmable Gain Amplifier(PGA) + * + * \param txrx Tx or Rx? + * \param which_amp which amp [0,3] + * \param gain_in_db gain value(linear in dB) + * + * gain is rounded to closest setting supported by hardware. + * + * \returns true iff sucessful. + * + * \sa pga_min(), pga_max(), pga_db_per_step() + */ + bool common_set_pga(txrx_t txrx, int which_amp, double gain_in_db); + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param txrx Tx or Rx? + * \param which_amp which amp [0,3] + */ + double common_pga(txrx_t txrx, int which_amp) const; + + /*! + * \brief Return minimum legal PGA gain in dB. + * \param txrx Tx or Rx? + */ + double common_pga_min(txrx_t txrx) const; + + /*! + * \brief Return maximum legal PGA gain in dB. + * \param txrx Tx or Rx? + */ + double common_pga_max(txrx_t txrx) const; + + /*! + * \brief Return hardware step size of PGA(linear in dB). + * \param txrx Tx or Rx? + */ + double common_pga_db_per_step(txrx_t txrx) const; + + /*! + * \brief Write direction register(output enables) for pins that go to daughterboard. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which size + * \param value value to write into register + * \param mask which bits of value to write into reg + * + * Each d'board has 16-bits of general purpose i/o. + * Setting the bit makes it an output from the FPGA to the d'board. + * + * This register is initialized based on a value stored in the + * d'board EEPROM. In general, you shouldn't be using this routine + * without a very good reason. Using this method incorrectly will + * kill your USRP motherboard and/or daughterboard. + */ + bool _common_write_oe(txrx_t txrx, int which_side, int value, int mask); + + /*! + * \brief Write daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value value to write into register + * \param mask which bits of value to write into reg + */ + bool common_write_io(txrx_t txrx, int which_side, int value, int mask); + + /*! + * \brief Read daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value output + */ + bool common_read_io(txrx_t txrx, int which_side, int *value); + + /*! + * \brief Read daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \returns register value if successful, else READ_FAILED + */ + int common_read_io(txrx_t txrx, int which_side); + + /*! + * \brief Write daughterboard refclk config register + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value value to write into register, see below + * + *
+   * Control whether a reference clock is sent to the daughterboards,
+   * and what frequency.  The refclk is sent on d'board i/o pin 0.
+   * 
+   *     3                   2                   1                       
+   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   *  +-----------------------------------------------+-+------------+
+   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
+   *  +-----------------------------------------------+-+------------+
+   * 
+   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
+   *  Bits 6:0 Divider value
+   * 
+ */ + bool common_write_refclk(txrx_t txrx, int which_side, int value); + + /*! + * \brief Automatic Transmit/Receive switching + *
+   *
+   * If automatic transmit/receive (ATR) switching is enabled in the
+   * FR_ATR_CTL register, the presence or absence of data in the FPGA
+   * transmit fifo selects between two sets of values for each of the 4
+   * banks of daughterboard i/o pins.
+   *
+   * Each daughterboard slot has 3 16-bit registers associated with it:
+   *   FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_*
+   *
+   * FR_ATR_MASK_{0,1,2,3}: 
+   *
+   *   These registers determine which of the daugherboard i/o pins are
+   *   affected by ATR switching.  If a bit in the mask is set, the
+   *   corresponding i/o bit is controlled by ATR, else it's output
+   *   value comes from the normal i/o pin output register:
+   *   FR_IO_{0,1,2,3}.
+   *
+   * FR_ATR_TXVAL_{0,1,2,3}:
+   * FR_ATR_RXVAL_{0,1,2,3}:
+   *
+   *   If the Tx fifo contains data, then the bits from TXVAL that are
+   *   selected by MASK are output.  Otherwise, the bits from RXVAL that
+   *   are selected by MASK are output.
+   * 
+ */ + bool common_write_atr_mask(txrx_t txrx, int which_side, int value); + bool common_write_atr_txval(txrx_t txrx, int which_side, int value); + bool common_write_atr_rxval(txrx_t txrx, int which_side, int value); + + /*! + * \brief Write auxiliary digital to analog converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. + * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. + * \param which_dac [2,3] TX slots must use only 2 and 3. + * \param value [0,4095] + * \returns true iff successful + */ + bool common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value); + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \param value return 12-bit value [0,4095] + * \returns true iff successful + */ + bool common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value); + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. + */ + int common_read_aux_adc(txrx_t txrx, int which_side, int which_adc); + + // END common_ daughterboard control functions + // ---------------------------------------------------------------- + // BEGIN virtual daughterboard control functions + + /*! + * \brief Set Programmable Gain Amplifier (PGA) + * + * \param which_amp which amp [0,3] + * \param gain_in_db gain value (linear in dB) + * + * gain is rounded to closest setting supported by hardware. + * + * \returns true iff sucessful. + * + * \sa pga_min(), pga_max(), pga_db_per_step() + */ + virtual bool set_pga (int which_amp, double gain_in_db) = 0; + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param which_amp which amp [0,3] + */ + virtual double pga (int which_amp) const = 0; + + /*! + * \brief Return minimum legal PGA gain in dB. + */ + virtual double pga_min () const = 0; + + /*! + * \brief Return maximum legal PGA gain in dB. + */ + virtual double pga_max () const = 0; + + /*! + * \brief Return hardware step size of PGA (linear in dB). + */ + virtual double pga_db_per_step () const = 0; + + /*! + * \brief Write direction register (output enables) for pins that go to daughterboard. + * + * \param which_side [0,1] which size + * \param value value to write into register + * \param mask which bits of value to write into reg + * + * Each d'board has 16-bits of general purpose i/o. + * Setting the bit makes it an output from the FPGA to the d'board. + * + * This register is initialized based on a value stored in the + * d'board EEPROM. In general, you shouldn't be using this routine + * without a very good reason. Using this method incorrectly will + * kill your USRP motherboard and/or daughterboard. + */ + virtual bool _write_oe (int which_side, int value, int mask) = 0; + + /*! + * \brief Write daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \param value value to write into register + * \param mask which bits of value to write into reg + */ + virtual bool write_io (int which_side, int value, int mask) = 0; + + /*! + * \brief Read daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \param value output + */ + virtual bool read_io (int which_side, int *value) = 0; + + /*! + * \brief Read daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \returns register value if successful, else READ_FAILED + */ + virtual int read_io (int which_side) = 0; + + /*! + * \brief Write daughterboard refclk config register + * + * \param which_side [0,1] which d'board + * \param value value to write into register, see below + * + *
+   * Control whether a reference clock is sent to the daughterboards,
+   * and what frequency.  The refclk is sent on d'board i/o pin 0.
+   * 
+   *     3                   2                   1                       
+   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   *  +-----------------------------------------------+-+------------+
+   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
+   *  +-----------------------------------------------+-+------------+
+   * 
+   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
+   *  Bits 6:0 Divider value
+   * 
+ */ + virtual bool write_refclk(int which_side, int value) = 0; + + virtual bool write_atr_mask(int which_side, int value) = 0; + virtual bool write_atr_txval(int which_side, int value) = 0; + virtual bool write_atr_rxval(int which_side, int value) = 0; + + /*! + * \brief Write auxiliary digital to analog converter. + * + * \param which_side [0,1] which d'board + * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. + * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. + * \param which_dac [2,3] TX slots must use only 2 and 3. + * \param value [0,4095] + * \returns true iff successful + */ + virtual bool write_aux_dac (int which_side, int which_dac, int value) = 0; + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \param value return 12-bit value [0,4095] + * \returns true iff successful + */ + virtual bool read_aux_adc (int which_side, int which_adc, int *value) = 0; + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. + */ + virtual int read_aux_adc (int which_side, int which_adc) = 0; + + /*! + * \brief returns current fusb block size + */ + virtual int block_size() const = 0; + + /*! + * \brief returns A/D or D/A converter rate in Hz + */ + virtual long converter_rate() const = 0; + + // END virtual daughterboard control functions + // ---------------------------------------------------------------- // Low level implementation routines. // You probably shouldn't be using these... // - bool _set_led (int which, bool on); + bool _set_led (int which_led, bool on); /*! * \brief Write FPGA register. @@ -229,7 +672,6 @@ public: */ int _read_fpga_reg (int regno); - /*! * \brief Write FPGA register with mask. * \param regno 7-bit register number @@ -324,8 +766,6 @@ private: bool d_rx_enable; protected: - int d_dbid[2]; // Rx daughterboard ID's - /*! * \param which_board Which USRP board on usb (not particularly useful; use 0) * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512. @@ -346,7 +786,6 @@ protected: void restore_rx (bool on); // conditional set void probe_rx_slots (bool verbose); - int dboard_to_slot (int dboard) { return (dboard << 1) | 1; } public: ~usrp_basic_rx (); @@ -358,6 +797,8 @@ public: * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512. * Use zero for a reasonable default. * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default. + * \param fpga_filename name of file that contains image to load into FPGA + * \param firmware_filename name of file that contains image to load into FX2 */ static usrp_basic_rx *make (int which_board, int fusb_block_size=0, @@ -366,8 +807,6 @@ public: const std::string firmware_filename = "" ); - // MANIPULATORS - /*! * \brief tell the fpga the rate rx samples are coming from the A/D's * @@ -389,162 +828,33 @@ public: */ int read (void *buf, int len, bool *overrun); - // ACCESSORS //! sampling rate of A/D converter virtual long converter_rate() const { return fpga_master_clock_freq(); } // 64M long adc_rate() const { return converter_rate(); } - long adc_freq() const { return converter_rate(); } //!< deprecated method name - - /*! - * \brief Return daughterboard ID for given Rx daughterboard slot [0,1]. - * - * \param which_dboard [0,1] which Rx daughterboard - * - * \return daughterboard id >= 0 if successful - * \return -1 if no daugherboard - * \return -2 if invalid EEPROM on daughterboard - */ - int daughterboard_id (int which_dboard) const { return d_dbid[which_dboard & 0x1]; } - - // ---------------------------------------------------------------- - // routines for controlling the Programmable Gain Amplifier - /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which which A/D [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - bool set_pga (int which, double gain_in_db); - - /*! - * \brief Return programmable gain amplifier gain setting in dB. - * - * \param which which A/D [0,3] - */ - double pga (int which) const; - - /*! - * \brief Return minimum legal PGA gain in dB. - */ - double pga_min () const { return 0.0; } - - /*! - * \brief Return maximum legal PGA gain in dB. - */ - double pga_max () const { return 20.0; } - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - double pga_db_per_step () const { return 20.0 / 20; } - - /*! - * \brief Write direction register (output enables) for pins that go to daughterboard. - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - bool _write_oe (int which_dboard, int value, int mask); - - /*! - * \brief Write daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - bool write_io (int which_dboard, int value, int mask); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value output - */ - bool read_io (int which_dboard, int *value); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - int read_io (int which_dboard); - - /*! - * \brief Write auxiliary digital to analog converter. - * - * \param which_dboard [0,1] which d'board - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. - * \param which_dac [2,3] TX slots must use only 2 and 3. - * \param value [0,4095] - * \returns true iff successful - */ - bool write_aux_dac (int which_board, int which_dac, int value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_dboard [0,1] which d'board - * \param which_adc [0,1] - * \param value return 12-bit value [0,4095] - * \returns true iff successful - */ - bool read_aux_adc (int which_dboard, int which_adc, int *value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_dboard [0,1] which d'board - * \param which_adc [0,1] - * \returns value in the range [0,4095] if successful, else READ_FAILED. - */ - int read_aux_adc (int which_dboard, int which_adc); + int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; } + + bool set_pga (int which_amp, double gain_in_db); + double pga (int which_amp) const; + double pga_min () const; + double pga_max () const; + double pga_db_per_step () const; + + bool _write_oe (int which_side, int value, int mask); + bool write_io (int which_side, int value, int mask); + bool read_io (int which_side, int *value); + int read_io (int which_side); + bool write_refclk(int which_side, int value); + bool write_atr_mask(int which_side, int value); + bool write_atr_txval(int which_side, int value); + bool write_atr_rxval(int which_side, int value); + + bool write_aux_dac (int which_side, int which_dac, int value); + bool read_aux_adc (int which_side, int which_adc, int *value); + int read_aux_adc (int which_side, int which_adc); - /*! - * \brief returns current fusb block size - */ int block_size() const; - /*! - * \brief Enable/disable automatic DC offset removal control loop in FPGA - * - * \param bits which control loops to enable - * \param mask which \p bits to pay attention to - * - * If the corresponding bit is set, enable the automatic DC - * offset correction control loop. - * - *
-   * The 4 low bits are significant:
-   *
-   *   ADC0 = (1 << 0)
-   *   ADC1 = (1 << 1)
-   *   ADC2 = (1 << 2)
-   *   ADC3 = (1 << 3)
-   * 
- * - * By default the control loop is enabled on all ADC's. - */ - bool set_dc_offset_cl_enable(int bits, int mask); - // called in base class to derived class order bool start (); bool stop (); @@ -563,13 +873,13 @@ private: bool d_tx_enable; protected: - int d_dbid[2]; // Tx daughterboard ID's - /*! * \param which_board Which USRP board on usb (not particularly useful; use 0) * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512. * Use zero for a reasonable default. * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default. + * \param fpga_filename name of file that contains image to load into FPGA + * \param firmware_filename name of file that contains image to load into FX2 */ usrp_basic_tx (int which_board, int fusb_block_size=0, @@ -585,7 +895,6 @@ private: void restore_tx (bool on); // conditional set void probe_tx_slots (bool verbose); - int dboard_to_slot (int dboard) { return (dboard << 1) | 0; } public: @@ -598,14 +907,14 @@ public: * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512. * Use zero for a reasonable default. * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default. + * \param fpga_filename name of file that contains image to load into FPGA + * \param firmware_filename name of file that contains image to load into FX2 */ static usrp_basic_tx *make (int which_board, int fusb_block_size=0, int fusb_nblocks=0, const std::string fpga_filename = "", const std::string firmware_filename = "" ); - // MANIPULATORS - /*! * \brief tell the fpga the rate tx samples are going to the D/A's * @@ -634,138 +943,30 @@ public: */ void wait_for_completion (); - // ACCESSORS - //! sampling rate of D/A converter virtual long converter_rate() const { return fpga_master_clock_freq () * 2; } // 128M long dac_rate() const { return converter_rate(); } - long dac_freq() const { return converter_rate(); } //!< deprecated method name - - /*! - * \brief Return daughterboard ID for given Tx daughterboard slot [0,1]. - * - * \return daughterboard id >= 0 if successful - * \return -1 if no daugherboard - * \return -2 if invalid EEPROM on daughterboard - */ - int daughterboard_id (int which_dboard) const { return d_dbid[which_dboard & 0x1]; } - - // ---------------------------------------------------------------- - // routines for controlling the Programmable Gain Amplifier - /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which which D/A [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * Note that DAC 0 and DAC 1 share a gain setting as do DAC 2 and DAC 3. - * Setting DAC 0 affects DAC 1 and vice versa. Same with DAC 2 and DAC 3. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - bool set_pga (int which, double gain_in_db); - - /*! - * \brief Return programmable gain amplifier gain in dB. - * - * \param which which D/A [0,3] - */ - double pga (int which) const; - - /*! - * \brief Return minimum legal PGA gain in dB. - */ - double pga_min () const { return -20.0; } + int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; } + + bool set_pga (int which_amp, double gain_in_db); + double pga (int which_amp) const; + double pga_min () const; + double pga_max () const; + double pga_db_per_step () const; + + bool _write_oe (int which_side, int value, int mask); + bool write_io (int which_side, int value, int mask); + bool read_io (int which_side, int *value); + int read_io (int which_side); + bool write_refclk(int which_side, int value); + bool write_atr_mask(int which_side, int value); + bool write_atr_txval(int which_side, int value); + bool write_atr_rxval(int which_side, int value); + + bool write_aux_dac (int which_side, int which_dac, int value); + bool read_aux_adc (int which_side, int which_adc, int *value); + int read_aux_adc (int which_side, int which_adc); - /*! - * \brief Return maximum legal PGA gain in dB. - */ - double pga_max () const { return 0.0; } - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - double pga_db_per_step () const { return 20.0/255; } - - /*! - * \brief Write direction register (output enables) for pins that go to daughterboard. - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - bool _write_oe (int which_dboard, int value, int mask); - - /*! - * \brief Write daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - bool write_io (int which_dboard, int value, int mask); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \param value return value - */ - bool read_io (int which_dboard, int *value); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_dboard [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - int read_io (int which_dboard); - - /*! - * \brief Write auxiliary digital to analog converter. - * - * \param which_dboard [0,1] which d'board - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. - * \param which_dac [2,3] TX slots must use only 2 and 3. - * \param value [0,4095] - * \returns true iff successful - */ - bool write_aux_dac (int which_board, int which_dac, int value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_dboard [0,1] which d'board - * \param which_adc [0,1] - * \param value return 12-bit value [0,4095] - * \returns true iff successful - */ - bool read_aux_adc (int which_dboard, int which_adc, int *value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_dboard [0,1] which d'board - * \param which_adc [0,1] - * \returns value in the range [0,4095] if successful, else READ_FAILED. - */ - int read_aux_adc (int which_dboard, int which_adc); - - /*! - * \brief returns current fusb block size - */ int block_size() const; // called in base class to derived class order diff --git a/usrp/host/lib/legacy/usrp_standard.cc b/usrp/host/lib/legacy/usrp_standard.cc index 768a8f24..d27bbbec 100644 --- a/usrp/host/lib/legacy/usrp_standard.cc +++ b/usrp/host/lib/legacy/usrp_standard.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -44,6 +44,168 @@ using namespace ad9862; #define NELEM(x) (sizeof (x) / sizeof (x[0])) +void +usrp_standard_common::calc_dxc_freq(double target_freq, double baseband_freq, double fs, + double *dxc_freq, bool *inverted) +{ + /* + Calculate the frequency to use for setting the digital up or down converter. + + @param target_freq: desired RF frequency (Hz) + @param baseband_freq: the RF frequency that corresponds to DC in the IF. + @param fs: converter sample rate + + @returns: 2-tuple (ddc_freq, inverted) where ddc_freq is the value + for the ddc and inverted is True if we're operating in an inverted + Nyquist zone. + */ + +#if 0 + printf("calc_dxc_freq:\n"); + printf(" target = %f\n", target_freq); + printf(" baseband = %f\n", baseband_freq); + printf(" fs = %f\n", fs); +#endif + + double delta = target_freq - baseband_freq; + + if(delta >= 0) { + while(delta > fs) { + delta -= fs; + } + if(delta <= fs/2) { // non-inverted region + *dxc_freq = -delta; + *inverted = false; + } + else { // inverted region + *dxc_freq = delta - fs; + *inverted = true; + } + } + else { + while(delta < -fs) { + delta += fs; + } + if(delta >= -fs/2) { + *dxc_freq = -delta; // non-inverted region + *inverted = false; + } + else { // inverted region + *dxc_freq = delta + fs; + *inverted = true; + } + } + +#if 0 + printf(" dxc_freq = %f\n", *dxc_freq); + printf(" inverted = %s\n", *inverted ? "true" : "false"); +#endif +} + + +/* + * Real lambda expressions would be _so_ much easier... + */ +class dxc_control { +public: + virtual bool is_tx() = 0; + virtual bool set_dxc_freq(double dxc_freq) = 0; + virtual double dxc_freq() = 0; +}; + +class ddc_control : public dxc_control { + usrp_standard_rx *d_u; + int d_chan; + +public: + ddc_control(usrp_standard_rx *u, int chan) + : d_u(u), d_chan(chan) {} + + bool is_tx(){ return false; } + bool set_dxc_freq(double dxc_freq){ return d_u->set_rx_freq(d_chan, dxc_freq); } + double dxc_freq(){ return d_u->rx_freq(d_chan); } +}; + +class duc_control : public dxc_control { + usrp_standard_tx *d_u; + int d_chan; + +public: + duc_control(usrp_standard_tx *u, int chan) + : d_u(u), d_chan(chan) {} + + bool is_tx(){ return true; } + bool set_dxc_freq(double dxc_freq){ return d_u->set_tx_freq(d_chan, dxc_freq); } + double dxc_freq() { return d_u->tx_freq(d_chan); } +}; + + +/*! + * \brief Tune such that target_frequency ends up at DC in the complex baseband + * + * \param db the daughterboard to use + * \param target_freq the center frequency we want at baseband (DC) + * \param fs the sample rate + * \param dxc DDC or DUC access and control object + * \param[out] result details of what we did + * + * \returns true iff operation was successful + * + * Tuning is a two step process. First we ask the front-end to + * tune as close to the desired frequency as it can. Then we use + * the result of that operation and our target_frequency to + * determine the value for the digital down converter. + */ +static bool +tune_a_helper(db_base_sptr db, double target_freq, double fs, + dxc_control &dxc, usrp_tune_result *result) +{ + bool inverted = false; + double dxc_freq; + double actual_dxc_freq; + + // Ask the d'board to tune as closely as it can to target_freq +#if 0 + bool ok = db->set_freq(target_freq, &result->baseband_freq); +#else + bool ok; + { + freq_result_t fr = db->set_freq(target_freq); + ok = fr.ok; + result->baseband_freq = fr.baseband_freq; + } +#endif + + // Calculate the DDC setting that will downconvert the baseband from the + // daughterboard to our target frequency. + usrp_standard_common::calc_dxc_freq(target_freq, result->baseband_freq, fs, + &dxc_freq, &inverted); + + // If the spectrum is inverted, and the daughterboard doesn't do + // quadrature downconversion, we can fix the inversion by flipping the + // sign of the dxc_freq... (This only happens using the basic_rx board) + + if(db->spectrum_inverted()) + inverted = !inverted; + + if(inverted && !db->is_quadrature()){ + dxc_freq = -dxc_freq; + inverted = !inverted; + } + + if (dxc.is_tx()) // down conversion versus up conversion + dxc_freq = -dxc_freq; + + ok &= dxc.set_dxc_freq(dxc_freq); + actual_dxc_freq = dxc.dxc_freq(); + + result->dxc_freq = dxc_freq; + result->residual_freq = dxc_freq - actual_dxc_freq; + result->inverted = inverted; + return ok; +} + + static unsigned int compute_freq_control_word_fpga (double master_freq, double target_freq, double *actual_freq, bool verbose) @@ -210,7 +372,7 @@ usrp_standard_rx::stop () return ok; } -usrp_standard_rx * +usrp_standard_rx_sptr usrp_standard_rx::make (int which_board, unsigned int decim_rate, int nchan, int mux, int mode, @@ -219,21 +381,18 @@ usrp_standard_rx::make (int which_board, const std::string firmware_filename ) { - usrp_standard_rx *u = 0; - try { - u = new usrp_standard_rx (which_board, decim_rate, - nchan, mux, mode, - fusb_block_size, fusb_nblocks, - fpga_filename, firmware_filename); + usrp_standard_rx_sptr u = + usrp_standard_rx_sptr(new usrp_standard_rx(which_board, decim_rate, + nchan, mux, mode, + fusb_block_size, fusb_nblocks, + fpga_filename, firmware_filename)); + u->init_db(u); return u; } catch (...){ - delete u; - return 0; + return usrp_standard_rx_sptr(); } - - return u; } bool @@ -371,6 +530,112 @@ usrp_standard_rx::write_hw_mux_reg () return ok; } +int +usrp_standard_rx::determine_rx_mux_value(const usrp_subdev_spec &ss) +{ + /* + Determine appropriate Rx mux value as a function of the subdevice choosen and the + characteristics of the respective daughterboard. + + @param u: instance of USRP source + @param subdev_spec: return value from subdev option parser. + @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 or 1 + @returns: the Rx mux value + + Figure out which A/D's to connect to the DDC. + + Each daughterboard consists of 1 or 2 subdevices. (At this time, + all but the Basic Rx have a single subdevice. The Basic Rx + has two independent channels, treated as separate subdevices). + subdevice 0 of a daughterboard may use 1 or 2 A/D's. We determine this + by checking the is_quadrature() method. If subdevice 0 uses only a single + A/D, it's possible that the daughterboard has a second subdevice, subdevice 1, + and it uses the second A/D. + + If the card uses only a single A/D, we wire a zero into the DDC Q input. + + (side, 0) says connect only the A/D's used by subdevice 0 to the DDC. + (side, 1) says connect only the A/D's used by subdevice 1 to the DDC. + */ + + struct truth_table_element + { + int d_side; + int d_uses; + bool d_swap_iq; + unsigned int d_mux_val; + + truth_table_element(int side, unsigned int uses, bool swap_iq, unsigned int mux_val=0) + : d_side(side), d_uses(uses), d_swap_iq(swap_iq), d_mux_val(mux_val){} + + bool operator==(const truth_table_element &in) + { + return (d_side == in.d_side && d_uses == in.d_uses && d_swap_iq == in.d_swap_iq); + } + + unsigned int mux_val() { return d_mux_val; } + }; + + + if (!is_valid(ss)) + throw std::invalid_argument("subdev_spec"); + + + // This is a tuple of length 1 or 2 containing the subdevice + // classes for the selected side. + std::vector db = this->db(ss.side); + + unsigned int subdev0_uses, subdev1_uses, uses; + + // compute bitmasks of used A/D's + + if(db[0]->is_quadrature()) + subdev0_uses = 0x3; // uses A/D 0 and 1 + else + subdev0_uses = 0x1; // uses A/D 0 only + + if(db.size() > 1) // more than 1 subdevice? + subdev1_uses = 0x2; // uses A/D 1 only + else + subdev1_uses = 0x0; // uses no A/D (doesn't exist) + + if(ss.subdev == 0) + uses = subdev0_uses; + else if(ss.subdev == 1) + uses = subdev1_uses; + else + throw std::invalid_argument("subdev_spec"); + + if(uses == 0){ + throw std::runtime_error("Daughterboard doesn't have a subdevice 1"); + } + + bool swap_iq = db[0]->i_and_q_swapped(); + + truth_table_element truth_table[8] = { + // (side, uses, swap_iq) : mux_val + truth_table_element(0, 0x1, false, 0xf0f0f0f0), + truth_table_element(0, 0x2, false, 0xf0f0f0f1), + truth_table_element(0, 0x3, false, 0x00000010), + truth_table_element(0, 0x3, true, 0x00000001), + truth_table_element(1, 0x1, false, 0xf0f0f0f2), + truth_table_element(1, 0x2, false, 0xf0f0f0f3), + truth_table_element(1, 0x3, false, 0x00000032), + truth_table_element(1, 0x3, true, 0x00000023) + }; + size_t nelements = sizeof(truth_table)/sizeof(truth_table[0]); + + truth_table_element target(ss.side, uses, swap_iq, 0); + + size_t i; + for(i = 0; i < nelements; i++){ + if (truth_table[i] == target) + return truth_table[i].mux_val(); + } + throw std::runtime_error("internal error"); +} + + bool usrp_standard_rx::set_rx_freq (int channel, double freq) @@ -379,7 +644,7 @@ usrp_standard_rx::set_rx_freq (int channel, double freq) return false; unsigned int v = - compute_freq_control_word_fpga (adc_freq(), + compute_freq_control_word_fpga (adc_rate(), freq, &d_rx_freq[channel], d_verbose); @@ -493,6 +758,14 @@ usrp_standard_rx::format_bypass_halfband(unsigned int format) return (format & bmFR_RX_FORMAT_BYPASS_HB) != 0; } +bool +usrp_standard_rx::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result) +{ + ddc_control dxc(this, chan); + return tune_a_helper(db, target_freq, converter_rate(), dxc, result); +} + + ////////////////////////////////////////////////////////////////// @@ -589,7 +862,7 @@ usrp_standard_tx::stop () return ok; } -usrp_standard_tx * +usrp_standard_tx_sptr usrp_standard_tx::make (int which_board, unsigned int interp_rate, int nchan, int mux, @@ -598,20 +871,17 @@ usrp_standard_tx::make (int which_board, const std::string firmware_filename ) { - usrp_standard_tx *u = 0; - try { - u = new usrp_standard_tx (which_board, interp_rate, nchan, mux, - fusb_block_size, fusb_nblocks, - fpga_filename, firmware_filename); + usrp_standard_tx_sptr u = + usrp_standard_tx_sptr(new usrp_standard_tx(which_board, interp_rate, nchan, mux, + fusb_block_size, fusb_nblocks, + fpga_filename, firmware_filename)); + u->init_db(u); return u; } catch (...){ - delete u; - return 0; + return usrp_standard_tx_sptr(); } - - return u; } bool @@ -668,6 +938,39 @@ usrp_standard_tx::write_hw_mux_reg () return ok; } +int +usrp_standard_tx::determine_tx_mux_value(const usrp_subdev_spec &ss) +{ + /* + Determine appropriate Tx mux value as a function of the subdevice choosen. + + @param u: instance of USRP source + @param subdev_spec: return value from subdev option parser. + @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 + @returns: the Rx mux value + + This is simpler than the rx case. Either you want to talk + to side A or side B. If you want to talk to both sides at once, + determine the value manually. + */ + + if (!is_valid(ss)) + throw std::invalid_argument("subdev_spec"); + + std::vector db = this->db(ss.side); + + if(db[0]->i_and_q_swapped()) { + unsigned int mask[2] = {0x0089, 0x8900}; + return mask[ss.side]; + } + else { + unsigned int mask[2] = {0x0098, 0x9800}; + return mask[ss.side]; + } +} + + + #ifdef USE_FPGA_TX_CORDIC bool @@ -679,7 +982,7 @@ usrp_standard_tx::set_tx_freq (int channel, double freq) // This assumes we're running the 4x on-chip interpolator. unsigned int v = - compute_freq_control_word_fpga (dac_freq () / 4, + compute_freq_control_word_fpga (dac_rate () / 4, freq, &d_tx_freq[channel], d_verbose); @@ -700,17 +1003,17 @@ usrp_standard_tx::set_tx_freq (int channel, double freq) coarse_mod_t cm; double coarse; - assert (dac_freq () == 128000000); + assert (dac_rate () == 128000000); if (freq < -44e6) // too low return false; else if (freq < -24e6){ // [-44, -24) cm = CM_NEG_FDAC_OVER_4; - coarse = -dac_freq () / 4; + coarse = -dac_rate () / 4; } else if (freq < -8e6){ // [-24, -8) cm = CM_NEG_FDAC_OVER_8; - coarse = -dac_freq () / 8; + coarse = -dac_rate () / 8; } else if (freq < 8e6){ // [-8, 8) cm = CM_OFF; @@ -718,11 +1021,11 @@ usrp_standard_tx::set_tx_freq (int channel, double freq) } else if (freq < 24e6){ // [8, 24) cm = CM_POS_FDAC_OVER_8; - coarse = dac_freq () / 8; + coarse = dac_rate () / 8; } else if (freq <= 44e6){ // [24, 44] cm = CM_POS_FDAC_OVER_4; - coarse = dac_freq () / 4; + coarse = dac_rate () / 4; } else // too high return false; @@ -738,7 +1041,7 @@ usrp_standard_tx::set_tx_freq (int channel, double freq) // (This is required to use the fine modulator.) unsigned int v = - compute_freq_control_word_9862 (dac_freq () / 4, + compute_freq_control_word_9862 (dac_rate () / 4, fine, &d_tx_freq[channel], d_verbose); d_tx_freq[channel] += coarse; // adjust actual @@ -837,3 +1140,10 @@ usrp_standard_tx::coarse_modulator (int channel) const return d_coarse_mod[channel]; } + +bool +usrp_standard_tx::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result) +{ + duc_control dxc(this, chan); + return tune_a_helper(db, target_freq, converter_rate(), dxc, result); +} diff --git a/usrp/host/lib/legacy/usrp_standard.h b/usrp/host/lib/legacy/usrp_standard.h index 93a8aa56..b7145b84 100644 --- a/usrp/host/lib/legacy/usrp_standard.h +++ b/usrp/host/lib/legacy/usrp_standard.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,10 +24,18 @@ #define INCLUDED_USRP_STANDARD_H #include +#include +#include + +class usrp_standard_tx; +class usrp_standard_rx; + +typedef boost::shared_ptr usrp_standard_tx_sptr; +typedef boost::shared_ptr usrp_standard_rx_sptr; class usrp_standard_common { - int d_fpga_caps; // capability register val + int d_fpga_caps; // capability register val protected: usrp_standard_common(usrp_basic *parent); @@ -56,6 +64,18 @@ public: * This will be 0, 1, or 2. */ int nducs() const; + + /*! + * \brief Calculate the frequency to use for setting the digital up or down converter. + * + * \param target_freq is the desired RF frequency (Hz). + * \param baseband_freq is the RF frequency that corresponds to DC in the IF coming from the d'board. + * \param fs is the sampling frequency. + * \param[out] dxc_freq the frequency to program into the DDC (or DUC). + * \param[out] inverted is true if we're operating in an inverted Nyquist zone. + */ + static void calc_dxc_freq(double target_freq, double baseband_freq, double fs, + double *dxc_freq, bool *inverted); }; /*! @@ -63,7 +83,7 @@ public: * * Assumes digital down converter in FPGA */ -class usrp_standard_rx : public usrp_basic_rx, usrp_standard_common +class usrp_standard_rx : public usrp_basic_rx, public usrp_standard_common { private: static const int MAX_CHAN = 4; @@ -99,23 +119,23 @@ class usrp_standard_rx : public usrp_basic_rx, usrp_standard_common ~usrp_standard_rx (); /*! - * \brief invokes constructor, returns instance or 0 if trouble + * \brief invokes constructor, returns shared_ptr or shared_ptr equivalent of 0 if trouble * * \param which_board Which USRP board on usb (not particularly useful; use 0) * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512. * Use zero for a reasonable default. * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default. */ - static usrp_standard_rx *make (int which_board, - unsigned int decim_rate, - int nchan = 1, - int mux = -1, - int mode = 0, - int fusb_block_size = 0, - int fusb_nblocks = 0, - const std::string fpga_filename = "", - const std::string firmware_filename = "" - ); + static usrp_standard_rx_sptr make(int which_board, + unsigned int decim_rate, + int nchan = 1, + int mux = -1, + int mode = 0, + int fusb_block_size = 0, + int fusb_nblocks = 0, + const std::string fpga_filename = "", + const std::string firmware_filename = "" + ); /*! * \brief Set decimator rate. \p rate MUST BE EVEN and in [8, 256]. * @@ -154,6 +174,12 @@ class usrp_standard_rx : public usrp_basic_rx, usrp_standard_common */ bool set_mux (int mux); + /*! + * Determine the appropriate Rx mux value as a function of the subdevice choosen + * and the characteristics of the respective daughterboard. + */ + int determine_rx_mux_value(const usrp_subdev_spec &ss); + /*! * \brief set the frequency of the digital down converter. * @@ -214,6 +240,22 @@ class usrp_standard_rx : public usrp_basic_rx, usrp_standard_common static bool format_want_q(unsigned int format); static bool format_bypass_halfband(unsigned int format); + /*! + * \brief High-level "tune" method. Works for the single channel case. + * + * This method adjusts both the daughterboard LO and the DDC so that + * target_freq ends up at DC in the complex baseband samples. + * + * \param chan which DDC channel we're controlling (almost always 0). + * \param db the daughterboard we're controlling. + * \param target_freq the RF frequency we want at DC in the complex baseband. + * \param[out] tune_result details how the hardware was configured. + * + * \returns true iff everything was successful. + */ + bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result); + + // ACCESSORS unsigned int decim_rate () const; double rx_freq (int channel) const; @@ -233,7 +275,7 @@ class usrp_standard_rx : public usrp_basic_rx, usrp_standard_common * * Uses digital upconverter (coarse & fine modulators) in AD9862... */ -class usrp_standard_tx : public usrp_basic_tx, usrp_standard_common +class usrp_standard_tx : public usrp_basic_tx, public usrp_standard_common { public: enum coarse_mod_t { @@ -274,22 +316,22 @@ class usrp_standard_tx : public usrp_basic_tx, usrp_standard_common ~usrp_standard_tx (); /*! - * \brief invokes constructor, returns instance or 0 if trouble + * \brief invokes constructor, returns shared_ptr or shared_ptr equivalent of 0 if trouble * * \param which_board Which USRP board on usb (not particularly useful; use 0) * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512. * Use zero for a reasonable default. * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default. */ - static usrp_standard_tx *make (int which_board, - unsigned int interp_rate, - int nchan = 1, - int mux = -1, - int fusb_block_size = 0, - int fusb_nblocks = 0, - const std::string fpga_filename = "", - const std::string firmware_filename = "" - ); + static usrp_standard_tx_sptr make(int which_board, + unsigned int interp_rate, + int nchan = 1, + int mux = -1, + int fusb_block_size = 0, + int fusb_nblocks = 0, + const std::string fpga_filename = "", + const std::string firmware_filename = "" + ); /*! * \brief Set interpolator rate. \p rate must be in [4, 512] and a multiple of 4. @@ -342,6 +384,12 @@ class usrp_standard_tx : public usrp_basic_tx, usrp_standard_common */ bool set_mux (int mux); + /*! + * Determine the appropriate Tx mux value as a function of the subdevice choosen + * and the characteristics of the respective daughterboard. + */ + int determine_tx_mux_value(const usrp_subdev_spec &ss); + /*! * \brief set the frequency of the digital up converter. * @@ -358,6 +406,22 @@ class usrp_standard_tx : public usrp_basic_tx, usrp_standard_common int nchannels () const; int mux () const; + /*! + * \brief High-level "tune" method. Works for the single channel case. + * + * This method adjusts both the daughterboard LO and the DUC so that + * DC in the complex baseband samples ends up at RF target_freq. + * + * \param chan which DUC channel we're controlling (usually == which_side). + * \param db the daughterboard we're controlling. + * \param target_freq the RF frequency we want our baseband translated to. + * \param[out] tune_result details how the hardware was configured. + * + * \returns true iff everything was successful. + */ + bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result); + + // called in base class to derived class order bool start (); bool stop (); diff --git a/usrp/host/lib/legacy/usrp_subdev_spec.h b/usrp/host/lib/legacy/usrp_subdev_spec.h new file mode 100644 index 00000000..e841ff83 --- /dev/null +++ b/usrp/host/lib/legacy/usrp_subdev_spec.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_USRP_SUBDEV_SPEC_H +#define INCLUDED_USRP_SUBDEV_SPEC_H + +/*! + * \brief specify a daughterboard and subdevice on a daughterboard. + * + * In the USRP1, there are two sides, A and B. + * + * A daughterboard generally implements a single subdevice, but may in + * general implement any number of subdevices. At this time, all daughterboards + * with the exception of the Basic Rx and LF Rx implement a single subdevice. + * + * The Basic Rx and LF Rx implement 2 subdevices (soon 3). Subdevice + * 0 routes input RX-A to the DDC I input and routes a constant zero + * to the DDC Q input. Similarly, subdevice 1 routes input RX-B to + * the DDC I input and routes a constant zero to the DDC Q + * input. Subdevice 2 (when implemented) will route RX-A to the DDC I + * input and RX-B to the DDC Q input. + */ + +struct usrp_subdev_spec { + unsigned int side; // 0 -> A; 1 -> B + unsigned int subdev; // which subdevice (usually zero) + + usrp_subdev_spec(unsigned int _side = 0, unsigned int _subdev = 0) + : side(_side), subdev(_subdev) {} +}; + +#endif /* INCLUDED_USRP_SUBDEV_SPEC_H */ diff --git a/usrp/host/lib/legacy/usrp_tune_result.h b/usrp/host/lib/legacy/usrp_tune_result.h new file mode 100644 index 00000000..200541a3 --- /dev/null +++ b/usrp/host/lib/legacy/usrp_tune_result.h @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_USRP_TUNE_RESULT_H +#define INCLUDED_USRP_TUNE_RESULT_H + +class usrp_tune_result +{ +public: + // RF frequency that corresponds to DC in the IF + double baseband_freq; + + // frequency programmed into the DDC/DUC + double dxc_freq; + + // residual frequency (typically < 0.01 Hz) + double residual_freq; + + // is the spectrum inverted? + bool inverted; + + usrp_tune_result(double baseband=0, double dxc=0, double residual=0, bool _inverted=false) + : baseband_freq(baseband), dxc_freq(dxc), + residual_freq(residual), inverted(_inverted) {} +}; + +#endif /* INCLUDED_USRP_TUNE_RESULT_H */ diff --git a/usrp2/host/include/usrp2/tune_result.h b/usrp2/host/include/usrp2/tune_result.h index 6fb2a682..9075596f 100644 --- a/usrp2/host/include/usrp2/tune_result.h +++ b/usrp2/host/include/usrp2/tune_result.h @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#ifndef INCLUDED_TUNE_RESULT_H -#define INCLUDED_TUNE_RESULT_H +#ifndef INCLUDED_USRP2_TUNE_RESULT_H +#define INCLUDED_USRP2_TUNE_RESULT_H namespace usrp2 { @@ -36,10 +36,11 @@ namespace usrp2 { // is the spectrum inverted? bool spectrum_inverted; - tune_result() - : baseband_freq(0), dxc_freq(0), residual_freq(0), spectrum_inverted(false) {} + tune_result(double baseband=0, double dxc=0, double residual=0, bool inverted=false) + : baseband_freq(baseband), dxc_freq(dxc), + residual_freq(residual), spectrum_inverted(inverted) {} }; } // namespace usrp2 -#endif /* INCLUDED_TUNE_RESULT_H */ +#endif /* INCLUDED_USRP2_TUNE_RESULT_H */ -- 2.30.2