summaryrefslogtreecommitdiff
path: root/gr-usrp
diff options
context:
space:
mode:
authorjcorgan2006-08-03 04:51:51 +0000
committerjcorgan2006-08-03 04:51:51 +0000
commit5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch)
treeb71312bf7f1e8d10fef0f3ac6f28784065e73e72 /gr-usrp
downloadgnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.gz
gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.bz2
gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.zip
Houston, we have a trunk.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3122 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gr-usrp')
-rw-r--r--gr-usrp/AUTHORS1
-rw-r--r--gr-usrp/ChangeLog374
-rw-r--r--gr-usrp/Makefile.am25
-rw-r--r--gr-usrp/README_MULTI_USRP.txt251
-rw-r--r--gr-usrp/src/Makefile.am120
-rw-r--r--gr-usrp/src/db_base.py234
-rw-r--r--gr-usrp/src/db_basic.py252
-rw-r--r--gr-usrp/src/db_dbs_rx.py345
-rw-r--r--gr-usrp/src/db_flexrf.py680
-rw-r--r--gr-usrp/src/db_flexrf_mimo.py286
-rw-r--r--gr-usrp/src/db_instantiator.py31
-rw-r--r--gr-usrp/src/db_tv_rx.py198
-rwxr-xr-xgr-usrp/src/flexrf_debug_gui.py176
-rwxr-xr-xgr-usrp/src/qa_usrp.py40
-rw-r--r--gr-usrp/src/run_tests.in47
-rwxr-xr-xgr-usrp/src/tx_debug_gui.py187
-rw-r--r--gr-usrp/src/usrp.py474
-rw-r--r--gr-usrp/src/usrp1.i657
-rw-r--r--gr-usrp/src/usrp1_sink_base.cc359
-rw-r--r--gr-usrp/src/usrp1_sink_base.h359
-rw-r--r--gr-usrp/src/usrp1_sink_c.cc106
-rw-r--r--gr-usrp/src/usrp1_sink_c.h87
-rw-r--r--gr-usrp/src/usrp1_sink_s.cc106
-rw-r--r--gr-usrp/src/usrp1_sink_s.h86
-rw-r--r--gr-usrp/src/usrp1_source_base.cc425
-rw-r--r--gr-usrp/src/usrp1_source_base.h455
-rw-r--r--gr-usrp/src/usrp1_source_c.cc131
-rw-r--r--gr-usrp/src/usrp1_source_c.h93
-rw-r--r--gr-usrp/src/usrp1_source_s.cc131
-rw-r--r--gr-usrp/src/usrp1_source_s.h94
-rw-r--r--gr-usrp/src/usrp_multi.py233
31 files changed, 7043 insertions, 0 deletions
diff --git a/gr-usrp/AUTHORS b/gr-usrp/AUTHORS
new file mode 100644
index 000000000..ee4560a55
--- /dev/null
+++ b/gr-usrp/AUTHORS
@@ -0,0 +1 @@
+Eric Blossom <eb@comsec.com>
diff --git a/gr-usrp/ChangeLog b/gr-usrp/ChangeLog
new file mode 100644
index 000000000..9744d3972
--- /dev/null
+++ b/gr-usrp/ChangeLog
@@ -0,0 +1,374 @@
+2006-06-17 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py, src/usrp1.i, src/usrp1_sink_base.cc, src/usrp1_sink_base.h,
+ src/usrp1_sink_c.cc, src/usrp1_sink_c.h, src/usrp1_sink_s.cc,
+ src/usrp1_sink_s.h, src/usrp1_source_base.cc, src/usrp1_source_base.h,
+ src/usrp1_source_c.cc, src/usrp1_source_c.h, src/usrp1_source_s.cc,
+ src/usrp1_source_s.h: changed constructor args to add
+ fusb_block_size and fusb_nblocks so that the application can
+ adjust the amount of buffering being done. [This was an awful lot
+ of files to have to touch to make this change. There must be an
+ easier way?]
+
+
+2006-05-11 Martin Dudok van Heel <nldudok1 at olifantasia dot com>
+ Added synchronised multi_usrp support.
+ This work was funded by Toby Oliver at Sensus Analytics / Path Intelligence.
+
+ See README_MULTI_USRP.txt and the multi_usrp examples on how to use.
+ In short:
+ Connect the 64MHz clocks between the boards with a short sma coax cable.
+ (See the wiki on how to enable clock-out and clock-in
+ http://comsec.com/wiki?USRPClockingNotes )
+ Connect io15 on the RXA daughterboards of both usrps
+ instantiate multi=usrp_multi.multi_source_align([args])
+ The 4 aligned channels become available as:
+ (multi.get_master_source_c(),1) (multi.get_master_source_c(),2)
+ (multi.get_slave_source(),1) (multi.get_slave_source(),2)
+ call multi.sync() at least once AFTER the flowgraph has started running
+
+ * READMU_MULTI_USRP.txt: new
+ * configure.ac: added missing newline at end of file
+ * src/Makefile.am: added usrp_multi.py
+ * src/usrp1.i: added _write_fpga_reg_masked
+ * src/usrp1_source_base.[cc,h]: added _write_fpga_reg_masked
+ * src/usrp_multi.py: new Instantiate a usrp_multi.multi_source_align to
+ get aligned streams from two usrps.
+
+2006-03-11 Matt Ettus <matt@ettus.com>
+
+ * src/Makefile.am, src/db_flexrf_mimo.py, src/usrp.py: New skeleton
+ file for mimo mode with the flexrf boards
+
+ * src/db_base.py: added standard code to control refclock and
+ adc buffer bypass so all dboards can do it the same way. Taken from
+ db_dbs_rx.py
+
+ * src/db_tv_rx.py: Use standard method for adc buffer bypass
+
+ * src/db_flexrf.py: Use standard method for adc buffer bypass
+
+ * src/db_dbs_rx.py: Use standard methods for adc buffer bypass and
+ refclock control
+
+ * src/db_basic.py: Use standard method for adc buffer bypass,
+ and instantiate a BasicTX when the unknown or missing board is on
+ the TX side
+
+2006-03-10 Eric Blossom <eb@comsec.com>
+
+ * src/db_dbs_rx.py (db_dbs_rx._refclk_freq): replaced 64e6 with
+ call to fpga_master_clock_freq().
+
+2006-02-18 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_{sink,source}_{base,c,s}.{h,cc}, src/usrp1.i,
+ src/usrp.py: added support for specifying the firmware and fpga
+ files that are to be loaded.
+
+2006-02-17 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1.i, src/usrp1_{sink,source}_base.{h,cc}: added serial_number()
+
+2006-01-30 Eric Blossom <eb@comsec.com>
+
+ * src/db_base.py, src/db_flexrf.py: revised to use new auto t/r
+ switching strategy. FR_ATR_CTL no longer exists. We control auto
+ t/r via the FR_ATR_MASK* registers.
+
+2006-01-25 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py (usrp_common): added code to read FPGA capability register.
+ (determine_tx_mux_value): new utility.
+
+2006-01-22 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py (pick_rx_subdevice): added latest d'board revs to list.
+
+2006-01-04 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_{sink,source}_{s,c}.cc: added usrp_bytesex.h include and
+ use usrp_to_host_short or host_to_usrp_short as appropriate to
+ handle usrp to host endianness differences.
+
+ * configure.ac: added AC_C_BIGENDIAN and header check for byteswap.h
+
+2005-12-20 Matt Ettus <matt@ettus.com>
+
+ * src/db_base.py (db_base.spectrum_inverted): Base function
+ defaults to no spectrum inversion, so we can handle daughterboards
+ which have analog spectra which are inverted (currently only tvrx2)
+
+ * src/db_tv_rx.py (db_tv_rx.spectrum_inverted): Report that the
+ tvrx2 has inverted spectrum, the tvrx does not
+
+ * src/usrp.py (tune): Handle daughterboards which have analog
+ spectra which are inverted (currently only tvrx2)
+
+
+2005-12-08 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_s.cc (usrp1_sink_s): call set_output_multiple so
+ we ensure 512 byte writes across USB.
+
+2005-12-07 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py: revised sink_c, sink_s, source_c and source_s to
+ properly fire daughterboard destructors. Without this, we had the
+ nasty habit of leaving the transmitter running if the user didn't
+ explicitly disable it.
+
+2005-12-05 Eric Blossom <eb@comsec.com>
+
+ * src/db_base.py, src/db_flexrf.py: refactored to use new
+ Auto T/R switching.
+
+ * src/db_flexrf.py (flexrf_base.set_freq): Offset the LO by 4 MHz.
+ Helps initial lock-up time with discontinuous transmission.
+
+2005-11-22 Eric Blossom <eb@comsec.com>
+
+ * src/db_base.py, src/db_flexrf.py: renamed set_auto_tx to set_auto_tr.
+
+2005-11-17 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.cc: reduced amount of USB Tx buffering.
+
+2005-11-13 Eric Blossom <eb@comsec.com>
+
+ * src/db_base.py (db_base.set_auto_tx): new stub method.
+
+2005-11-11 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py (pick_rx_subdevice): moved to library.
+
+2005-11-10 Matt Ettus <matt@ettus.com>
+
+ * src/db_flexrf.py (flexrf_base_tx.set_enable): fixed definition.
+
+2005-10-27 Eric Blossom <eb@comsec.com>
+
+ * src/db_base.py, src/db_flexrf.py: new method: set_enable
+
+2005-10-20 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_source_s.{h,cc}, src/usrp1_source_c.{h,cc}: support
+ both 8 and 16-bit samples across the USB.
+ * src/usrp1.i, src/usrp1_source_base.{h,cc}: new methods for
+ setting and getting rx format.
+
+2005-10-11 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py: removed dispatch on usrp revision (no longer
+ support rev0 boards). Constructors now take keyword args, thus
+ all args are optional. This will allow us to get rid of the 64e6's
+ and 128e6's that are scattered throughout the example code.
+ * src/usrp1.i: removed default values from constructors. They are
+ now provided by keyword args in usrp.py
+
+2005-09-29 Eric Blossom <eb@comsec.com>
+
+ * src/db_dbs_rx.py (db_dbs_rx.freq_range): set freq step size to 1M
+
+2005-09-27 Eric Blossom <eb@comsec.com>
+
+ * src/db_base.py (db_base.i_and_q_swapped): new method for
+ Flex 400 Rx and other boards that route I into ADC 1 instead of 0.
+
+ * src/usrp.py (tune): added tune fct. Reworked subdev_spec. No
+ longer accepts (0|1, None). Check for and handle i_and_q_swapped.
+
+2005-09-21 Eric Blossom <eb@comsec.com>
+
+ * src/db_basic.py: new.
+ * src/db_instantiator.py, src/usrp.py: added framework for
+ automatically instantiating daughterboard subclasses.
+
+ * src/usrp1.i, src/usrp1_sink_base.{h,cc},
+ src/usrp1_source_base.{h,cc}: deprecated adc_freq(), dac_freq(),
+ recommend converter_rate().
+
+2005-09-17 Eric Blossom <eb@comsec.com>
+
+ * src/db_dbs_rx.py: renamed from dbs_rx.py
+ * src/db_flexrf.py: renamed from flexrf.py
+ * src/db_tv_rx.py: renamed from tv_rx.py
+ * src/db_base.py: renamed from daughterboard_base.py
+
+2005-08-28 Eric Blossom <eb@comsec.com>
+
+ * src/flexrf.py: added hook to invoke debugging gui.
+ * src/flexrf_debug_gui.py: new debugging tool.
+
+2005-07-19 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_source_base.{h,cc}, src/usrp1.i: new method: set_ddc_phase.
+
+2005-07-02 Eric Blossom <eb@comsec.com>
+
+ * config/gr_no_undefined.m4, config/gr_x86_64.m4: new, x86_64 support.
+ * config/gr_python.m4: backed out search for libpython, making
+ x86_64 work and breaking Cygwin/MinGW.
+ * configure.ac, src/Makefile.am: mods for x86_64, $(NO_UNDEFINED)
+
+2005-06-09 Eric Blossom <eb@comsec.com>
+
+ * src/gen_usrp_dbids.py: new. Generate usrp_dbids.py from
+ usrp_daughterboards.h. This file contains symbolic names for for
+ daughterboard ID's.
+
+2005-05-18 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.{h,cc}, src/usrp1_source_base.{h,cc}: use
+ new start/stop methods.
+
+2005-05-09 Stephane Fillod <f8cfe@free.fr>
+
+ * config/gr_sysv_shm.m4: SysV shared memory not mandatory
+ * config/gr_pwin32.m4, config/gr_python.m4, config/lf_cxx.m4:
+ fixes for Cygwin, MinGW
+
+2005-03-29 Eric Blossom <eb@comsec.com>
+
+ * src/usrp.py: now check for usrp version at open time, not import
+ time.
+
+2005-03-15 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.{h,cc}, src/usrp1_source_base.{h,cc}:
+ read_aux_dac and write_aux_dac now take which_dboard instead of slot.
+
+2005-03-13 Matt Ettus <matt@ettus.com>
+
+ * src/Makefile.am, src/tv_rx.py: first cut at TV RX dboard
+ * src/dbs_rx.py: minor fixes
+
+2005-03-11 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.{h,cc},src/usrp1_source_base.{h,cc}: new
+ methods: set_adc_offset, set_dac_offset, set_adc_buffer_bypass.
+
+2005-02-18 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.cc (_write_oe): fix delegation.
+ * src/usrp1_source_base.cc (_write_oe): fix delegation.
+
+2005-02-16 Eric Blossom <eb@comsec.com>
+
+ * src/dbs_rx.py: new. control DBS_RX daughterboard.
+ * src/usrp1_{sink,source}_base.{h,cc}: add read_i2c and write_i2c.
+
+2005-02-06 Eric Blossom <eb@comsec.com>
+
+ * configure.ac: upped rev to 0.4 for release.
+ * src/Makefile.am: backed out dependency on libpython
+
+2005-01-28 Stephane Fillod <f8cfe@free.fr>
+
+ * src/Makefile.am: fixes for MinGW.
+
+2005-01-12 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.cc,src/usrp1_source_base.cc: changed
+ under/overrun diagnostic indicator to "uU" and "uO" to reduce
+ amount of diagnostic output.
+
+2005-01-10 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1.i,src/usrp1_sink_base.{h,cc},
+ src/usrp1_source_base.{h,cc}: new methods to control all knobs.
+
+2005-01-04 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1.i,src/usrp1_source_base.{h,cc}: new methods for
+ messing with Rx PGA.
+
+2004-11-14 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.cc (work): corrected increment of obi.
+
+2004-10-13 Eric Blossom <eb@comsec.com>
+
+ * configure.ac: upped rev to 0.2cvs
+
+2004-10-11 Eric Blossom <eb@comsec.com>
+
+ * configure.ac: bumped rev to 0.2, make release.
+ * Makefile.am (EXTRA_DIST): added config.h.in
+
+2004-09-30 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_sink_base.{h,cc}, src/usrp1_source_base.{h,cc},
+ src/usrp1.i: new methods for reading and writing aux dac and adc,
+ eeproms, and fpga registers.
+
+2004-09-23 Eric Blossom <eb@comsec.com>
+
+ * config/usrp_fusb_tech.m4, config/bnv_have_qt.m4, config/cppunit.m4,
+ config/gr_check_mc4020.m4, config/gr_check_usrp.m4, config/gr_doxygen.m4,
+ config/gr_gprof.m4, config/gr_scripting.m4, config/gr_set_md_cpu.m4,
+ config/pkg.m4, config/usrp_fusb_tech.m4: added additional quoting
+ to first arg of AC_DEFUN to silence automake warning.
+
+2004-08-19 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_{sink,source}_base.{h,cc}, src/usrp1.i: new method: set_verbose.
+
+2004-08-03 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_source_base.{h,cc}, src/usrp1_sink_base.{h,cc}:
+ extracted base class that handles everything but the packing and
+ unpacking of data into the usrp buffer.
+ * src/usrp1_source_c.{h,cc}, src/usrp1_sink_c.{h,cc}: revised to
+ use new base class.
+ * src/usrp1_source_s.{h,cc}, src/usrp1_sink_s.{h,cc}: new.
+
+
+2004-07-31 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_{sink,source}_c.{h,cc}: new method: set_loopback
+ * src/usrp1.i: new method: set_loopback
+
+2004-07-30 Eric Blossom <eb@comsec.com>
+
+ * src/usrp1_source_c.{h,cc}: renamed from usrp_source_c.{h,cc}
+ * src/usrp1_sink_c.{h,cc}: renamed from usrp_sink_c.{h,cc}
+ * src/usrp1.i: renamed from usrp.i
+ * src/usrp.py: new. Binds proper class depending on hardware found.
+
+
+2004-07-29 Eric Blossom <eb@comsec.com>
+
+ * src/usrp_{sink,source}_c.h: doc fix.
+ * src/usrp0.i: new
+ * src/usrp0_source_c.{h,cc}: new
+ * src/usrp0_sink_c.{h,cc}: new
+
+2004-07-12 Eric Blossom <eb@comsec.com>
+
+ * configure.ac: upped rev to 0.1cvs
+
+2004-07-08 Eric Blossom <eb@comsec.com>
+
+ * src/usrp_source_c.{h,cc}: new.
+
+#
+# Copyright 2004,2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
diff --git a/gr-usrp/Makefile.am b/gr-usrp/Makefile.am
new file mode 100644
index 000000000..e500700cb
--- /dev/null
+++ b/gr-usrp/Makefile.am
@@ -0,0 +1,25 @@
+#
+# Copyright 2004 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+EXTRA_DIST = README_MULTI_USRP.txt
+SUBDIRS = src
diff --git a/gr-usrp/README_MULTI_USRP.txt b/gr-usrp/README_MULTI_USRP.txt
new file mode 100644
index 000000000..4ed7a15b3
--- /dev/null
+++ b/gr-usrp/README_MULTI_USRP.txt
@@ -0,0 +1,251 @@
+Multi usrp
+
+With this code you can connect two or more usrps (with a locked clock) and get synchronised samples.
+You must connect a (flat)cable between a dboard on the master in RXA and a dboard on the slave in RXA.
+You then put one usrp in master mode, put the other in slave mode.
+
+For a quick start using the examples look at gnuradio-examples/python/multi_usrp/README
+
+Use the usrp_multi block which is installed by gr-usrp.
+instantiate in the following way:
+
+ self.multi=usrp_multi.multi_source_align( fg=self, master_serialno=options.master_serialno, decim=options.decim, nchan=options.nchan )
+
+nchan should be 2 or 4.
+
+You determine which is the master by master_serialno (this is a text string a hexadecimal number).
+If you enter a serial number which is not found it will print the serial numbers which are available.
+If you give no serial number (master_serialno=None), the code will pick a Master for you.
+
+You can get a reference to the master and the slave usrp in the following way:
+
+ self.um=self.multi.get_master_usrp()
+ self.us=self.multi.get_slave_usrp()
+
+You only need these references for setting freqs/gains or getting info about daughterboards.
+Don't use the output directly but use the aligned output from multi.get_master_source_c() and multi.get_slave_source_c()
+
+You get references to the aligned output samples in the following way:
+aligned_master_source_c=self.multi.get_master_source_c()
+aligned_slave_source_c=self.multi.get_slave_source_c()
+
+These blocks have multiple outputs.
+output 0 is the sample counter (high bits in I, low bits in Q)
+You normally don't need the samplecounters so you can ignore output 0
+
+output 1 is the first aligend output channel (if you enable 2 or 4 channels)
+output 2 is the second output channel (only if you enable 4 channels)
+
+so the usefull 4 channels are:
+self.aligned_master_chan1=(self.multi.get_master_source_c(),1)
+self.aligned_master_chan2=(self.multi.get_master_source_c(),2)
+self.aligned_slave_chan1=(self.multi.get_slave_source_c(),1)
+self.aligned_slave_chan2=(self.multi.get_slave_source_c(),2)
+
+The two samplecounters are:
+self.aligned_master_samplecounter=(self.multi.get_master_source_c(),0)
+self.aligned_slave_samplecounter=(self.multi.get_slave_source_c(),0)
+
+You can set the gain or tune the frequency for all 4 receive daughetrboards at once:
+ self.multi.set_gain_all_rx(options.gain)
+ result,r1,r2,r3,r4 = self.multi.tune_all_rx(options.freq)
+
+This will only work reliably when you have all the same daughterboards.
+Otherwise set all freqs and gains individually.
+
+You must call self.multi.sync() at least once AFTER the flowgraph has started running.
+(This will synchronise the streams of the two usrps)
+
+This work was funded by Toby Oliver at Sensus Analytics / Path Intelligence.
+Many Thanks for making this possible.
+
+It was written by Martin Dudok van Heel at Olifantasia.
+
+Quick start multi-usrp:
+Unpack, build and install usrp, gnuradio-core and gr-usrp
+Versions need to be more recent then 2.7cvs/svn 11 may 2006
+
+Make sure usrp/fpga/rbf/rev2/multi*.rbf is installed in /usr/local/share/usrp/rev2/
+Make sure usrp/fpga/rbf/rev4/multi*.rbf is installed in /usr/local/share/usrp/rev4/
+(If in doubt, copy manually)
+
+build and install gr-wxgui gr-audio-xxx and so on.
+
+unpack gnuradio-examples.
+
+There is a gnuradio-examples/python/multi_usrp directory which contains examples and a README
+
+
+Put at least a basic RX or dbsrx board in RXA of the master and RXA of the slave board.
+Make sure that the usrps have a serial or unique identifier programmed in their eeprom.
+(All new rev 4.1 boards have this)
+You can do without a serial but then you never know which usrp is the master and which is the slave.
+
+
+CONNECTING THE CABLES
+Now connect the 64MHz clocks between the boards with a short sma coax cable.
+(See the wiki on how to enable clock-out and clock-in
+http://comsec.com/wiki?USRPClockingNotes )
+
+You need one board with a clock out and one board with a clock in.
+
+You can choose any of the two boards as master or slave, this is not dependant on which board has the clock-out or in.
+In my experiments I had fewer problems when the board that has the clock-in will be the master board.
+
+You can use a standard 16-pole flatcable to connect tvrx, basic-rx or dbsrx boards.
+Of this 16pin flatcable only two pins are used (io15 and ground)
+For all new daughterboards which use up a lot of io pins you have to use a cable with fewer connections.
+The savest is using a 2pin headercable connected to io15,gnd (a cable like the ones used to connect frontpanel leds to the mainboard of a PC)
+
+If using basic rx board:
+ Connect a 16-pole flatcable from J25 on basicrx/dbs_rx in rxa of the master usrp to J25 on basicrx/dbsrx in RXA of the slave usrp
+ Don't twist the cable (Make sure the pin1 marker (red line on the flatcable) is on the same side of the connector (at io-8 on the master and at io8 on the slave.))
+ For basic_rx this means the marker should be on the side of the dboard with the sma connectors.
+ For dbs_rx this means the marker should be on the side of the dboard with the two little chips.
+ In other words, don't twist the cable, you will burn your board if you do.
+
+You can also connect a flatcable with multiple connectors from master-J25 to slave1-J25 to slave2-J25 to ...
+You will however have to think of something to create a common 64Mhz clock for more then two usrps.
+
+For all other daughterboards, connect a 2wire cable from masterRXA J25 io15,gnd to slaveRXA J25 io15,gnd
+
+
+So now the hardware is setup, software is setup. Lets do some tests.
+
+Connect power to both usrps.
+unpack the gnuradio_examples somewhere (cvs version later then 11 may 2006)
+go to the gnuradio-examples/python/multi_usrp folder.
+
+Now run
+ ./multi_usrp_oscope.py -x 12345678
+
+It should tell you that usrp 12345678 is not found and tell you which serials are available.
+
+Now run ./multi_usrp_oscope.py -x actualserialnum
+You should now get an oscope with two channels, one is from the master and one is from the slave
+It will which show the I-signal from channel 0 of the master usrp and I-signal from channel 0 of the slave usrp.
+(For testing connect the same signal source to the inputs of both boards)
+The signals should be aligned.
+If you click the sync button, it will resync the master and slave (should never be needed)
+
+Now run
+./multi_usrp_oscope.py --help
+To see all available options.
+
+
+Now you are ready to do phase-locked aligned signal processing.
+
+You can also capture to file with:
+./multi_usrp_rx_cfile.py
+
+run ./multi_usrp_rx_cfile.py --help to see all available options.
+
+
+Here follows a brief of the new blocks and (changes)functionality for multi-usrp.
+You can also look at the generated documentation in
+/usr/local/share/doc/gnuradio-core-X.X
+/usr/local/share/doc/usrp-X.X
+(Make sure to build and install the documentation, go to the doc directory of the sourcetree and issue make doc; make install)
+
+
+gnuradio-examples:
+new/changed files:
+multi_usrp/multi_usrp_oscope.py
+multi_usrp/multi_usrp_rx_cfile.py
+
+
+gnuradio-core:
+gr.align_on_samplenumbers_ss (int nchan,int align_interval)
+
+align several complex short (interleaved short) input channels with corresponding unsigned 32 bit sample_counters (provided as interleaved 16 bit values)
+
+Parameters:
+ nchan number of complex_short input channels (including the 32 bit counting channel)
+ align_interval interval at which the samples are aligned, ignored for now.
+
+Pay attention on how you connect this block It expects a minimum of 2 usrp_source_s with nchan number of channels and as mode usrp_prims.bmFR_MODE_RX_COUNTING_32BIT enabled. This means that the first complex_short channel is an interleaved 32 bit counter. The samples are aligned by dropping samples untill the samplenumbers match.
+
+files:
+gnuradio-core/src/lib/general/gr_align_on_samplenumbers_ss.cc
+gnuradio-core/src/lib/general/gr_align_on_samplenumbers_ss.h
+gnuradio-core/src/lib/general/gr_align_on_samplenumbers_ss.i
+
+
+gr-usrp
+ added _write_fpga_reg_masked
+ added usrp_multi.py
+ new usrp_multi block which can instantiate two linked usrps as master and slave and alignes their output.
+ It has a sync() function which should be called AFTER the flowgraph has started running.
+ bool sync();
+ \brief Call this on a master usrp to sync master and slave by outputing a sync pulse on rx_a_io[15].
+ The 32 bit samplecounter of master and slave will be reset to zero and all phase and buffer related things in the usrps are reset.
+ Call this only after the flowgraph has been started, otherwise there will be no effect since everything is kept in reset state as long as the flowgraph is not running.
+ \returns true if successfull.
+
+files:
+configure.ac
+src/Makefile.am
+src/usrp1.i
+src/usrp1_source_base.cc
+src/usrp1_source_base.h
+src/usrp_multi.py
+
+usrp-0.11cvsmulti:
+usrp:
+ new constant bmFR_MODE_RX_COUNTING_32BIT (could also be added as extra mode like FPGA_MODE_COUNTING_32BIT)
+ Use this for the mode parameter when creating a usrp when you want to use the master/slave setup or if you want to use the 32 bit counter for other things, like testing with gr.check_counting_s(True)
+
+ added register FR_RX_MASTER_SLAVE
+ added bitno and bitmaskes:
+ bmFR_MODE_RX_COUNTING_32BIT
+
+ bitnoFR_RX_SYNC
+ bitnoFR_RX_SYNC_MASTER
+ bitnoFR_RX_SYNC_SLAVE
+
+ bitnoFR_RX_SYNC_INPUT_IOPIN 15
+ bmFR_RX_SYNC_INPUT_IOPIN (1<<bitnoFR_RX_SYNC_INPUT_IOPIN)
+ bitnoFR_RX_SYNC_OUTPUT_IOPIN 15
+ bmFR_RX_SYNC_OUTPUT_IOPIN (1<<bitnoFR_RX_SYNC_OUTPUT_IOPIN)
+
+ added _write_fpga_reg_masked()
+ added new toplevel folder usrp_multi
+ added usrp_multi.v and master_control_multi.v
+ added new MULTI_ON and COUNTER_32BIT_ON defines
+ If these are turned off usrp_multi.v will behave exactly as usrp_std.v
+
+ added setting_reg_masked.v
+ changed reset behaviour of phase_acc.v and rx_buffer.v
+
+ changed generate_regs.py to handle bm and bitno defines
+
+
+files:
+firmware/include/fpga_regs_standard.v
+firmware/include/fpga_regs_common.h
+firmware/include/generate_regs.py
+firmware/include/fpga_regs_standard.h
+host/lib/usrp_basic.h
+host/lib/usrp_basic.cc
+host/lib/usrp_standard.h
+fpga/rbf/Makefile.am
+fpga/toplevel/usrp_std/usrp_std.v
+fpga/toplevel/usrp_multi/usrp_multi.esf
+fpga/toplevel/usrp_multi/usrp_multi.vh
+fpga/toplevel/usrp_multi/usrp_std.vh
+fpga/toplevel/usrp_multi/usrp_multi_config_2rxhb_0tx.vh
+fpga/toplevel/usrp_multi/usrp_multi_config_2rxhb_2tx.vh
+fpga/toplevel/usrp_multi/usrp_multi.v
+fpga/toplevel/usrp_multi/usrp_multi.qpf
+fpga/toplevel/usrp_multi/usrp_multi.psf
+fpga/toplevel/usrp_multi/usrp_multi_config_2rx_0tx.vh
+fpga/toplevel/usrp_multi/usrp_multi.qsf
+fpga/toplevel/usrp_multi/usrp_multi_config_4rx_0tx.vh
+fpga/toplevel/usrp_multi/usrp_multi.csf
+fpga/toplevel/usrp_multi/.cvsignore
+fpga/sdr_lib/rx_buffer.v
+fpga/sdr_lib/master_control_multi.v
+fpga/sdr_lib/phase_acc.v
+fpga/sdr_lib/setting_reg_masked.v
+
+
diff --git a/gr-usrp/src/Makefile.am b/gr-usrp/src/Makefile.am
new file mode 100644
index 000000000..0bcd6c475
--- /dev/null
+++ b/gr-usrp/src/Makefile.am
@@ -0,0 +1,120 @@
+#
+# Copyright 2004,2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+# 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 = \
+ usrp1.i
+
+NON_LOCAL_IFILES = \
+ $(top_srcdir)/gnuradio-core/src/lib/swig/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_instantiator.py \
+ db_tv_rx.py \
+ flexrf_debug_gui.py \
+ tx_debug_gui.py \
+ usrp.py \
+ usrp1.py \
+ usrp_multi.py
+
+
+USRP_INCLUDES = -I$(top_srcdir)/usrp/host/lib -I$(top_srcdir)/usrp/firmware/include
+USRP_LIBS = -L$(top_srcdir)/usrp/host/lib/.libs -lusrp
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS)
+
+SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(STD_DEFINES_AND_INCLUDES) $(USRP_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 = _usrp1.la
+
+
+_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
+
+
+_usrp1_la_LIBADD = \
+ $(PYTHON_LDFLAGS) \
+ $(GNURADIO_CORE_LIBS) \
+ $(USRP_LIBS) \
+ -lstdc++
+
+
+_usrp1_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+
+usrp1.cc usrp1.py: usrp1.i $(NON_LOCAL_IFILES)
+ $(SWIG) $(SWIGPYTHONARGS) -module usrp1 -o usrp1.cc $<
+
+
+noinst_PYTHON = \
+ qa_usrp.py
+
+MOSTLYCLEANFILES = \
+ $(BUILT_SOURCES) *~ *.pyc
+
+
+# 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
+
diff --git a/gr-usrp/src/db_base.py b/gr-usrp/src/db_base.py
new file mode 100644
index 000000000..4f4db38f4
--- /dev/null
+++ b/gr-usrp/src/db_base.py
@@ -0,0 +1,234 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import usrp_prims
+import weakref
+from 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
+
+ FR_TX_A_REFCLK = 40
+ FR_RX_A_REFCLK = 41
+ FR_TX_B_REFCLK = 42
+ FR_RX_B_REFCLK = 43
+
+ 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
+ #
+ # FIXME get these from the fpga_regs_standard.h
+
+ 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)
+
+ # 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 ADC 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
+
diff --git a/gr-usrp/src/db_basic.py b/gr-usrp/src/db_basic.py
new file mode 100644
index 000000000..e9139466e
--- /dev/null
+++ b/gr-usrp/src/db_basic.py
@@ -0,0 +1,252 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import sys
+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
new file mode 100644
index 000000000..24e8d7dbe
--- /dev/null
+++ b/gr-usrp/src/db_dbs_rx.py
@@ -0,0 +1,345 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+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()/150e3)
+ 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<rmin or n<256:
+ r = r * 2
+ continue
+ delta = abs(n*self._refclk_freq()/r - freq)
+ if delta < 75e3:
+ best_r = r
+ best_n = n
+ break
+ if delta < best_delta*0.9:
+ best_r = r
+ best_n = n
+ best_delta = delta
+ r = r * 2
+ self._set_r(int(best_r))
+
+ self._set_n(int(round(best_n)))
+
+ if vcofreq < 2433e6:
+ vco = 0
+ elif vcofreq < 2711e6:
+ vco=1
+ elif vcofreq < 3025e6:
+ vco=2
+ elif vcofreq < 3341e6:
+ vco=3
+ elif vcofreq < 3727e6:
+ vco=4
+ elif vcofreq < 4143e6:
+ vco=5
+ elif vcofreq < 4493e6:
+ vco=6
+ else:
+ vco=7
+
+ self._set_osc(vco)
+
+ # Set CP current
+ adc_val = 0
+ while adc_val == 0 or adc_val == 7:
+ (byte1,byte2) = self._read_status()
+ adc_val = byte1 >> 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_flexrf.py b/gr-usrp/src/db_flexrf.py
new file mode 100644
index 000000000..a00cfe896
--- /dev/null
+++ b/gr-usrp/src/db_flexrf.py
@@ -0,0 +1,680 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import usrp1
+import time,math
+
+import usrp_dbid
+import db_base
+import db_instantiator
+from 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
+ 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 $: 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
+
+# ----------------------------------------------------------------
+
+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.lo_offset = 4e6 # FIXME may want to be a function of d'board
+
+ 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.lo_offset = -4e6 # FIXME may want to be a function of d'board
+
+ 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()
+ 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 + 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.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)
+
+ 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 _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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ self.power_off = ~POWER_UP # 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 = ~POWER_UP
+ 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 = ~POWER_UP
+ 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
new file mode 100644
index 000000000..71c49a8f0
--- /dev/null
+++ b/gr-usrp/src/db_flexrf_mimo.py
@@ -0,0 +1,286 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import usrp1
+import time,math
+
+import usrp_dbid
+import db_base
+import db_instantiator
+from 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_instantiator.py b/gr-usrp/src/db_instantiator.py
new file mode 100644
index 000000000..db10de4a6
--- /dev/null
+++ b/gr-usrp/src/db_instantiator.py
@@ -0,0 +1,31 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+_instantiator_map = {}
+
+def add(dbid, instantiator):
+ _instantiator_map[dbid] = instantiator
+
+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_tv_rx.py b/gr-usrp/src/db_tv_rx.py
new file mode 100644
index 000000000..05504553a
--- /dev/null
+++ b/gr-usrp/src/db_tv_rx.py
@@ -0,0 +1,198 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+__all__ = ['tv_rx']
+
+import math
+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):
+ """
+ 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 = False # FIXME get rid of this
+
+ 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 (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),))
+
+# 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, 20e6),))
+
+# 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, 20e6),))
diff --git a/gr-usrp/src/flexrf_debug_gui.py b/gr-usrp/src/flexrf_debug_gui.py
new file mode 100755
index 000000000..173d48a71
--- /dev/null
+++ b/gr-usrp/src/flexrf_debug_gui.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import sys
+import wx
+from gnuradio.wxgui import form
+
+class flexrf_debug_gui(wx.Frame):
+ def __init__(self, flexrf, title="Flexrf Debug"):
+ wx.Frame.__init__(self, None, -1, title)
+
+ self.flexrf = flexrf
+
+ self.CreateStatusBar (1)
+
+ self.panel = wx.Panel(self, -1)
+ self.vbox = wx.BoxSizer(wx.VERTICAL)
+ self.panel.SetSizer(self.vbox)
+ self.panel.SetAutoLayout(True)
+
+ self._create_form()
+
+ self.vbox.Fit(self.panel)
+
+ self.frame_vbox = wx.BoxSizer(wx.VERTICAL)
+ self.frame_vbox.Add(self.panel, 1, wx.EXPAND)
+ self.SetSizer(self.frame_vbox)
+ self.SetAutoLayout(True)
+ self.frame_vbox.Fit(self)
+
+ def _create_form(self):
+ self._create_set_freq()
+ self._create_write_fpga()
+ self._create_write_all()
+ self._create_write_it()
+ #self._create_set_gain()
+
+ # ----------------------------------------------------------------
+
+ def _create_set_freq(self):
+
+ def _set_freq(kv):
+ return self.flexrf.set_freq(kv['freq'])[0]
+
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.HORIZONTAL)
+ sbs.Add((5,0), 0.1) # stretchy space
+ #sbs.Add(wx.StaticText(self.panel, -1, "set_freq "), 0, 0)
+ #sbs.Add((5,0), 0.1) # stretchy space
+ myform = form.form()
+ myform['freq'] = form.float_field(self.panel, sbs, "Set Frequency")
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(form.button_with_callback(self.panel, "Do It!",
+ self._generic_doit(_set_freq, myform)), 1, wx.EXPAND)
+ sbs.Add((5,0), 0.1) # stretchy space
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+
+ def _create_write_fpga(self):
+
+ def _write_fpga(kv):
+ return self.flexrf._u._write_fpga_reg(kv['regno'], kv['value'])
+
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.HORIZONTAL)
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(wx.StaticText(self.panel, -1, "write_fpga_reg "), 0, 0)
+ sbs.Add((5,0), 0.1) # stretchy space
+ myform = form.form()
+ myform['regno'] = form.int_field(self.panel, sbs, "regno")
+ sbs.Add((5,0), 0.1) # stretchy space
+ myform['value'] = form.int_field(self.panel, sbs, "value")
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(form.button_with_callback(self.panel, "Do It!",
+ self._generic_doit(_write_fpga, myform)), 1, wx.EXPAND)
+ sbs.Add((5,0), 0.1) # stretchy space
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+
+ def _create_write_all(self):
+
+ def _write_all(kv):
+ self.flexrf._write_all(kv['R'], kv['control'], kv['N']) # void
+ return True
+
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.HORIZONTAL)
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(wx.StaticText(self.panel, -1, "write_all "), 0, 0)
+ sbs.Add((5,0), 0.1) # stretchy space
+ myform = form.form()
+ myform['R'] = form.int_field(self.panel, sbs, "R")
+ sbs.Add((5,0), 0.1) # stretchy space
+ myform['control'] = form.int_field(self.panel, sbs, "control")
+ sbs.Add((5,0), 0.1) # stretchy space
+ myform['N'] = form.int_field(self.panel, sbs, "N")
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(form.button_with_callback(self.panel, "Do It!",
+ self._generic_doit(_write_all, myform)), 1, wx.EXPAND)
+ sbs.Add((5,0), 0.1) # stretchy space
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+
+ def _create_write_it(self):
+
+ def _write_it(kv):
+ self.flexrf._write_it(kv['v']) # void
+ return True
+
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.HORIZONTAL)
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(wx.StaticText(self.panel, -1, "write_it "), 0, 0)
+ sbs.Add((5,0), 0.1) # stretchy space
+ myform = form.form()
+ myform['v'] = form.int_field(self.panel, sbs, "24-bit value")
+ sbs.Add((5,0), 0.1) # stretchy space
+ sbs.Add(form.button_with_callback(self.panel, "Do It!",
+ self._generic_doit(_write_it, myform)), 1, wx.EXPAND)
+ sbs.Add((5,0), 0.1) # stretchy space
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+
+ # ----------------------------------------------------------------
+
+ def _set_status_msg(self, msg):
+ self.GetStatusBar().SetStatusText(msg, 0)
+
+ def _generic_doit(self, callback, form):
+
+ def button_callback():
+ errors = form.check_input_for_errors()
+ if errors:
+ self._set_status_msg(errors[0])
+ print '\n'.join(tuple(errors))
+ else:
+ kv = form.get_key_vals()
+ if callback(kv):
+ self._set_status_msg("OK")
+ else:
+ self._set_status_msg("Failed")
+
+ return button_callback
+
+
+
+if False and __name__ == '__main__':
+
+ class demo_app (wx.App):
+ def __init__ (self):
+ wx.App.__init__(self)
+
+ def OnInit (self):
+ frame = flexrf_debug_gui(None, "Debug FlexRF TX")
+ frame.Show(True)
+ self.SetTopWindow (frame)
+ return True
+
+ app = demo_app()
+ app.MainLoop()
+
diff --git a/gr-usrp/src/qa_usrp.py b/gr-usrp/src/qa_usrp.py
new file mode 100755
index 000000000..eb68c6407
--- /dev/null
+++ b/gr-usrp/src/qa_usrp.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import usrp1
+
+class qa_usrp (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.fg = gr.flow_graph ()
+
+ def tearDown (self):
+ self.fg = None
+
+ def test_000_nop (self):
+ """Just see if we can import the module...
+ They may not have a USRP connected, etc. Don't try to run anything"""
+ pass
+
+if __name__ == '__main__':
+ gr_unittest.main ()
diff --git a/gr-usrp/src/run_tests.in b/gr-usrp/src/run_tests.in
new file mode 100644
index 000000000..793cb2491
--- /dev/null
+++ b/gr-usrp/src/run_tests.in
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# All this strange PYTHONPATH manipulation is required to run our
+# tests using our just built shared library and swig-generated python
+# code prior to installation.
+
+# build tree == src tree unless you're doing a VPATH build.
+# If you don't know what a VPATH build is, you're not doing one. Relax...
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Where to look in the build tree for our shared library
+libbld=@abs_top_builddir@/gr-usrp/src
+# Where to look in the src tree for swig generated python code
+libsrc=@abs_top_srcdir@/gr-usrp/src
+# Where to look in the src tree for hand written python code
+py=@abs_top_srcdir@/gr-usrp/src
+
+# Where to look for GNU Radio python modules in current build tree
+# FIXME this is wrong on a distcheck. We really need to ask gnuradio-core
+# where it put its python files.
+grpythonbld=@abs_top_builddir@/gnuradio-core/src/python/:@abs_top_builddir@/gnuradio-core/src/lib/swig/:@abs_top_builddir@/gnuradio-core/src/lib/swig/.libs
+
+PYTHONPATH="$grpythonbld:$libbld:$libbld/.libs:$libsrc:$py:$PYTHONPATH"
+export PYTHONPATH
+
+#
+# This is the simple part...
+# Run everything that matches qa_*.py and return the final result.
+#
+
+ok=yes
+for file in @srcdir@/qa_*.py
+do
+ if ! $file
+ then
+ ok=no
+ fi
+done
+
+if [ $ok = yes ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/gr-usrp/src/tx_debug_gui.py b/gr-usrp/src/tx_debug_gui.py
new file mode 100755
index 000000000..6988f986e
--- /dev/null
+++ b/gr-usrp/src/tx_debug_gui.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import sys
+import wx
+from gnuradio.wxgui import form
+
+class tx_debug_gui(wx.Frame):
+ def __init__(self, tx_subdev, title="Tx Debug"):
+ wx.Frame.__init__(self, None, -1, title)
+
+ self.subdev = tx_subdev
+ self.subdev._u.set_verbose(True)
+
+ self.CreateStatusBar (1)
+
+ self.panel = wx.Panel(self, -1)
+ self.vbox = wx.BoxSizer(wx.VERTICAL)
+ self.panel.SetSizer(self.vbox)
+ self.panel.SetAutoLayout(True)
+
+ self._create_form()
+
+ self.vbox.Fit(self.panel)
+
+ self.frame_vbox = wx.BoxSizer(wx.VERTICAL)
+ self.frame_vbox.Add(self.panel, 1, wx.EXPAND)
+ self.SetSizer(self.frame_vbox)
+ self.SetAutoLayout(True)
+ self.frame_vbox.Fit(self)
+
+ # ----------------------------------------------------------------
+
+ def _write_9862(self, regno, v):
+ return self.subdev._u._write_9862(self.subdev._which, regno, v)
+
+ def _set_dac_offset(self, i_or_q, offset, offset_pin):
+ return self.subdev._u.set_dac_offset(self.subdev._which * 2 + i_or_q, offset, offset_pin)
+
+ def _set_dac_fine_gain(self, i_or_q, gain, coarse):
+ return self._write_9862(14 + i_or_q, (coarse & 0xC0) | (gain & 0x3f))
+
+ def _create_form(self):
+ self._create_dac_offset()
+ self._create_dac_fine_gain()
+ self._create_pga()
+
+ # ----------------------------------------------------------------
+
+ def _create_dac_offset(self):
+
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.VERTICAL)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add(wx.StaticText(self.panel, -1, "DAC Offset"), 5, 0)
+ sbs.Add(hbox, 0, 1)
+
+
+ self._create_dac_offset_helper(sbs, 0)
+ self._create_dac_offset_helper(sbs, 1)
+
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+ def _create_dac_offset_helper(self, vbox, i_or_q):
+
+ def doit(kv):
+ drive_positive = kv['drive_positive']
+ dac_offset = kv['dac_offset']
+ print "drive_positive =", drive_positive
+ print "dac_offset[%d] = %4d" % (i_or_q, dac_offset)
+
+ # FIXME signed magnitude??
+ # dac_offset = signed_mag10(dac_offset)
+ return self._set_dac_offset(i_or_q, dac_offset, int(drive_positive))
+
+ def signed_mag10(x):
+ # not clear from doc if this is really 2's comp or 10-bit signed magnitude
+ # we'll guess it's 10-bit signed mag
+ if x < 0:
+ return (1 << 9) | min(511, max(0, abs(x)))
+ else:
+ return (0 << 9) | min(511, max(0, abs(x)))
+
+ myform = form.form()
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ vbox.Add(hbox, 0, wx.EXPAND)
+ myform['drive_positive'] = form.checkbox_field(parent=self.panel, sizer=hbox,
+ callback=myform.check_input_and_call(doit),
+ weight=0,
+ label="drive +ve")
+ myform['dac_offset'] = form.slider_field(parent=self.panel, sizer=hbox,
+ callback=myform.check_input_and_call(doit),
+ min=-512, max=511, value=0,
+ weight=5)
+
+ # ----------------------------------------------------------------
+
+ def _create_dac_fine_gain(self):
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.VERTICAL)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add(wx.StaticText(self.panel, -1, "DAC Gain"), 5, 0)
+ sbs.Add(hbox, 0, 1)
+
+ self._create_dac_gain_helper(sbs, 0)
+ self._create_dac_gain_helper(sbs, 1)
+
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+ def _create_dac_gain_helper(self, vbox, i_or_q):
+
+ d = { "1/1" : 0xC0,
+ "1/2" : 0x40,
+ "1/11" : 0x00 }
+
+ def doit(kv):
+ dac_gain = kv['dac_gain']
+ coarse_s = kv['coarse']
+ print "dac_gain[%d] = %4d" % (i_or_q, dac_gain)
+ print "coarse = ", coarse_s
+ return self._set_dac_fine_gain(i_or_q, dac_gain, d[coarse_s])
+
+ myform = form.form()
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ vbox.Add(hbox, 0, wx.EXPAND)
+ myform['coarse'] = form.radiobox_field(parent=self.panel, sizer=hbox,
+ callback=myform.check_input_and_call(doit),
+ choices=['1/11', '1/2', '1/1'],
+ weight=1, value='1/1')
+ myform['dac_gain'] = form.slider_field(parent=self.panel, sizer=hbox,
+ callback=myform.check_input_and_call(doit),
+ min=-32, max=31, value=0,
+ weight=4)
+
+
+ # ----------------------------------------------------------------
+
+ def _create_pga(self):
+ sbs = wx.StaticBoxSizer(wx.StaticBox(self.panel), wx.VERTICAL)
+
+ form.quantized_slider_field(parent=self.panel, sizer=sbs, label="PGA",
+ weight=3, range=self.subdev.gain_range(),
+ callback=self.subdev.set_gain)
+
+ self.vbox.Add(sbs, 0, wx.EXPAND)
+
+
+ # ----------------------------------------------------------------
+
+
+ def _set_status_msg(self, msg):
+ self.GetStatusBar().SetStatusText(msg, 0)
+
+
+if False and __name__ == '__main__':
+
+ class demo_app (wx.App):
+ def __init__ (self):
+ wx.App.__init__(self)
+
+ def OnInit (self):
+ frame = tx_debug_gui(None, "Debug TX")
+ frame.Show(True)
+ self.SetTopWindow (frame)
+ return True
+
+ app = demo_app()
+ app.MainLoop()
diff --git a/gr-usrp/src/usrp.py b/gr-usrp/src/usrp.py
new file mode 100644
index 000000000..6e19c1bb3
--- /dev/null
+++ b/gr-usrp/src/usrp.py
@@ -0,0 +1,474 @@
+#
+# Copyright 2004,2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+
+
+import usrp_prims
+import usrp_dbid
+from gnuradio import usrp1 # usrp Rev 1 and later
+from gnuradio import gru
+from usrp_fpga_regs import *
+
+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
+
+
+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:
+ # FIXME 50-50 chance this has the wrong sign...
+ 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,)
+
+ 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 instance derived from db_base
+ """
+ side, subdev = subdev_spec
+ return 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
new file mode 100644
index 000000000..b73abcd76
--- /dev/null
+++ b/gr-usrp/src/usrp1.i
@@ -0,0 +1,657 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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 <stdexcept>
+#include <usrp_standard.h>
+#include <usrp_spi_defs.h>
+%}
+
+%include <usrp_spi_defs.h>
+
+%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_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 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.
+ *
+ * <pre>
+ * The 4 low bits are significant:
+ *
+ * ADC0 = (1 << 0)
+ * ADC1 = (1 << 1)
+ * ADC2 = (1 << 2)
+ * ADC3 = (1 << 3)
+ * </pre>
+ *
+ * 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
new file mode 100644
index 000000000..19e0b23f2
--- /dev/null
+++ b/gr-usrp/src/usrp1_sink_base.cc
@@ -0,0 +1,359 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp1_sink_base.h>
+#include <gr_io_signature.h>
+#include <usrp_standard.h>
+#include <assert.h>
+
+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
new file mode 100644
index 000000000..d5775377b
--- /dev/null
+++ b/gr-usrp/src/usrp1_sink_base.h
@@ -0,0 +1,359 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_USRP1_SINK_BASE_H
+#define INCLUDED_USRP1_SINK_BASE_H
+
+#include <gr_sync_block.h>
+#include <stdexcept>
+
+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_sink_c.cc b/gr-usrp/src/usrp1_sink_c.cc
new file mode 100644
index 000000000..16296cfdf
--- /dev/null
+++ b/gr-usrp/src/usrp1_sink_c.cc
@@ -0,0 +1,106 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp1_sink_c.h>
+#include <gr_io_signature.h>
+#include <usrp_standard.h>
+#include <usrp_bytesex.h>
+
+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)
+{
+ return usrp1_sink_c_sptr (new usrp1_sink_c (which_board,
+ interp_rate,
+ nchan,
+ mux,
+ fusb_block_size,
+ fusb_nblocks,
+ fpga_filename,
+ firmware_filename
+ ));
+}
+
+
+usrp1_sink_c::usrp1_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)
+ : usrp1_sink_base ("usrp1_sink_c",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ which_board, interp_rate, nchan, mux,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename)
+{
+}
+
+usrp1_sink_c::~usrp1_sink_c ()
+{
+ // NOP
+}
+
+/*
+ * Take one complex input stream and format it into interleaved short I & Q
+ * for the usrp.
+ */
+void
+usrp1_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
+ void *usrp_buffer,
+ int usrp_buffer_length,
+ int &bytes_written) // out
+{
+ gr_complex *in = &((gr_complex *) input_items[0])[input_index];
+ short *dst = (short *) usrp_buffer;
+
+ static const int usrp_bytes_per_input_item = 2 * sizeof (short); // I & Q
+
+ int nitems = std::min (input_items_available,
+ usrp_buffer_length / usrp_bytes_per_input_item);
+
+ for (int i = 0; i < nitems; i++){
+ dst[2*i + 0] = host_to_usrp_short((short) real(in[i])); // FIXME saturate?
+ dst[2*i + 1] = host_to_usrp_short((short) imag(in[i])); // FIXME saturate?
+ }
+
+ input_items_consumed = nitems;
+ bytes_written = nitems * usrp_bytes_per_input_item;
+}
+
diff --git a/gr-usrp/src/usrp1_sink_c.h b/gr-usrp/src/usrp1_sink_c.h
new file mode 100644
index 000000000..15d92a9cc
--- /dev/null
+++ b/gr-usrp/src/usrp1_sink_c.h
@@ -0,0 +1,87 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_USRP1_SINK_C_H
+#define INCLUDED_USRP1_SINK_C_H
+
+#include <usrp1_sink_base.h>
+
+class usrp1_sink_c;
+typedef boost::shared_ptr<usrp1_sink_c> usrp1_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);
+
+
+/*!
+ * \brief interface to Universal Software Radio Peripheral Tx path (Rev 1)
+ *
+ * input: gr_complex
+ */
+class usrp1_sink_c : public usrp1_sink_base {
+ private:
+
+ friend 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);
+
+ protected:
+ usrp1_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);
+
+ 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);
+ public:
+ ~usrp1_sink_c ();
+};
+
+#endif /* INCLUDED_USRP1_SINK_C_H */
diff --git a/gr-usrp/src/usrp1_sink_s.cc b/gr-usrp/src/usrp1_sink_s.cc
new file mode 100644
index 000000000..634eb5aea
--- /dev/null
+++ b/gr-usrp/src/usrp1_sink_s.cc
@@ -0,0 +1,106 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp1_sink_s.h>
+#include <gr_io_signature.h>
+#include <usrp_standard.h>
+#include <usrp_bytesex.h>
+
+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)
+{
+ return usrp1_sink_s_sptr (new usrp1_sink_s (which_board,
+ interp_rate,
+ nchan,
+ mux,
+ fusb_block_size,
+ fusb_nblocks,
+ fpga_filename,
+ firmware_filename
+ ));
+}
+
+
+usrp1_sink_s::usrp1_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)
+ : usrp1_sink_base ("usrp1_sink_s",
+ gr_make_io_signature (1, 1, sizeof (short)),
+ which_board, interp_rate, nchan, mux,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename)
+{
+ set_output_multiple (512 / sizeof(short)); // don't change
+}
+
+usrp1_sink_s::~usrp1_sink_s ()
+{
+ // NOP
+}
+
+/*
+ * Take one short input stream and format it into interleaved short I & Q
+ * for the usrp.
+ */
+void
+usrp1_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
+ void *usrp_buffer,
+ int usrp_buffer_length,
+ int &bytes_written) // out
+{
+ short *in = &((short *) input_items[0])[input_index];
+ short *dst = (short *) usrp_buffer;
+
+ static const int usrp_bytes_per_input_item = sizeof (short);
+
+ int nitems = std::min (input_items_available,
+ usrp_buffer_length / usrp_bytes_per_input_item);
+
+ for (int i = 0; i < nitems; i++){ // FIXME unroll
+ dst[i] = host_to_usrp_short(in[i]);
+ }
+
+ input_items_consumed = nitems;
+ bytes_written = nitems * usrp_bytes_per_input_item;
+}
+
diff --git a/gr-usrp/src/usrp1_sink_s.h b/gr-usrp/src/usrp1_sink_s.h
new file mode 100644
index 000000000..a2e086cad
--- /dev/null
+++ b/gr-usrp/src/usrp1_sink_s.h
@@ -0,0 +1,86 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_USRP1_SINK_S_H
+#define INCLUDED_USRP1_SINK_S_H
+
+#include <usrp1_sink_base.h>
+
+class usrp1_sink_s;
+typedef boost::shared_ptr<usrp1_sink_s> usrp1_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);
+
+/*!
+ * \brief interface to Universal Software Radio Peripheral Tx path (Rev 1)
+ *
+ * input: short
+ */
+class usrp1_sink_s : public usrp1_sink_base {
+ private:
+
+ friend 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);
+
+ protected:
+ usrp1_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);
+
+ 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);
+ public:
+ ~usrp1_sink_s ();
+};
+
+#endif /* INCLUDED_USRP1_SINK_S_H */
diff --git a/gr-usrp/src/usrp1_source_base.cc b/gr-usrp/src/usrp1_source_base.cc
new file mode 100644
index 000000000..9f5cb2510
--- /dev/null
+++ b/gr-usrp/src/usrp1_source_base.cc
@@ -0,0 +1,425 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp1_source_base.h>
+#include <gr_io_signature.h>
+#include <usrp_standard.h>
+#include <assert.h>
+
+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/usrp1_source_base.h b/gr-usrp/src/usrp1_source_base.h
new file mode 100644
index 000000000..a04eadf2b
--- /dev/null
+++ b/gr-usrp/src/usrp1_source_base.h
@@ -0,0 +1,455 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_USRP1_SOURCE_BASE_H
+#define INCLUDED_USRP1_SOURCE_BASE_H
+
+#include <gr_sync_block.h>
+#include <stdexcept>
+
+class usrp_standard_rx;
+
+/*!
+ * \brief abstract interface to Universal Software Radio Peripheral Rx path (Rev 1)
+ */
+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;
+
+ ~usrp1_source_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 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);
+
+ void set_verbose (bool verbose);
+
+ /*!
+ * \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);
+
+ /*!
+ * \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;
+
+ // 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
+
+ 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);
+
+ /*!
+ * \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);
+
+ /*!
+ * \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.
+ *
+ * <pre>
+ * The 4 low bits are significant:
+ *
+ * ADC0 = (1 << 0)
+ * ADC1 = (1 << 1)
+ * ADC2 = (1 << 2)
+ * ADC3 = (1 << 3)
+ * </pre>
+ *
+ * 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);
+
+ // ----------------------------------------------------------------
+ // 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 Write FPGA register masked.
+ * \param regno 7-bit register number
+ * \param value 16-bit value
+ * \param mask 16-bit mask
+ * \returns true iff successful
+ */
+ bool _write_fpga_reg_masked (int regno, int value, int mask); //< 7-bit regno, 16-bit value, 16-bit mask
+
+ /*!
+ * \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_SOURCE_BASE_H */
diff --git a/gr-usrp/src/usrp1_source_c.cc b/gr-usrp/src/usrp1_source_c.cc
new file mode 100644
index 000000000..e61437006
--- /dev/null
+++ b/gr-usrp/src/usrp1_source_c.cc
@@ -0,0 +1,131 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp1_source_c.h>
+#include <gr_io_signature.h>
+#include <usrp_standard.h>
+#include <usrp_bytesex.h>
+
+static const int NBASIC_SAMPLES_PER_ITEM = 2; // I & Q
+
+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)
+{
+ return usrp1_source_c_sptr (new usrp1_source_c (which_board,
+ decim_rate,
+ nchan,
+ mux,
+ mode,
+ fusb_block_size,
+ fusb_nblocks,
+ fpga_filename,
+ firmware_filename
+ ));
+}
+
+
+usrp1_source_c::usrp1_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)
+ : usrp1_source_base ("usrp1_source_c",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ which_board, decim_rate, nchan, mux, mode,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename)
+{
+}
+
+usrp1_source_c::~usrp1_source_c ()
+{
+ // NOP
+}
+
+int
+usrp1_source_c::ninput_bytes_reqd_for_noutput_items (int noutput_items)
+{
+ return noutput_items * NBASIC_SAMPLES_PER_ITEM * sizeof_basic_sample();
+}
+
+/*
+ * Convert interleaved 8 or 16-bit I & Q from usrp buffer into a single
+ * complex output stream.
+ */
+void
+usrp1_source_c::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)
+{
+ gr_complex *out = &((gr_complex *) output_items[0])[output_index];
+ unsigned sbs = sizeof_basic_sample();
+ unsigned nusrp_bytes_per_item = NBASIC_SAMPLES_PER_ITEM * sbs;
+
+ int nitems = std::min (output_items_available,
+ (int)(usrp_buffer_length / nusrp_bytes_per_item));
+
+ signed char *s8 = (signed char *) usrp_buffer;
+ short *s16 = (short *) usrp_buffer;
+
+ switch (sbs){
+ case 1:
+ for (int i = 0; i < nitems; i++){
+ out[i] = gr_complex ((float)(s8[2*i+0] << 8), (float)(s8[2*i+1] << 8));
+ }
+ break;
+
+ case 2:
+ for (int i = 0; i < nitems; i++){
+ out[i] = gr_complex ((float) usrp_to_host_short(s16[2*i+0]),
+ (float) usrp_to_host_short(s16[2*i+1]));
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ output_items_produced = nitems;
+ bytes_read = nitems * nusrp_bytes_per_item;
+}
diff --git a/gr-usrp/src/usrp1_source_c.h b/gr-usrp/src/usrp1_source_c.h
new file mode 100644
index 000000000..4b8749356
--- /dev/null
+++ b/gr-usrp/src/usrp1_source_c.h
@@ -0,0 +1,93 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_USRP1_SOURCE_C_H
+#define INCLUDED_USRP1_SOURCE_C_H
+
+#include <usrp1_source_base.h>
+#include <stdexcept>
+
+class usrp_standard_rx;
+
+
+class usrp1_source_c;
+typedef boost::shared_ptr<usrp1_source_c> usrp1_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
+ ) throw (std::runtime_error);
+
+/*!
+ * \brief interface to Universal Software Radio Peripheral Rx path (Rev 1)
+ */
+class usrp1_source_c : public usrp1_source_base {
+ private:
+ friend 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);
+
+ protected:
+ usrp1_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);
+
+ virtual int ninput_bytes_reqd_for_noutput_items (int noutput_items);
+
+ 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);
+
+ public:
+ ~usrp1_source_c ();
+};
+
+#endif /* INCLUDED_USRP1_SOURCE_C_H */
diff --git a/gr-usrp/src/usrp1_source_s.cc b/gr-usrp/src/usrp1_source_s.cc
new file mode 100644
index 000000000..c2c105bc8
--- /dev/null
+++ b/gr-usrp/src/usrp1_source_s.cc
@@ -0,0 +1,131 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp1_source_s.h>
+#include <gr_io_signature.h>
+#include <usrp_standard.h>
+#include <usrp_bytesex.h>
+
+static const int NBASIC_SAMPLES_PER_ITEM = 1;
+
+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)
+{
+ return usrp1_source_s_sptr (new usrp1_source_s (which_board,
+ decim_rate,
+ nchan,
+ mux,
+ mode,
+ fusb_block_size,
+ fusb_nblocks,
+ fpga_filename,
+ firmware_filename
+ ));
+}
+
+
+usrp1_source_s::usrp1_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)
+ : usrp1_source_base ("usrp1_source_s",
+ gr_make_io_signature (1, 1, sizeof (short)),
+ which_board, decim_rate, nchan, mux, mode,
+ fusb_block_size,
+ fusb_nblocks,
+ fpga_filename, firmware_filename)
+{
+}
+
+usrp1_source_s::~usrp1_source_s ()
+{
+ // NOP
+}
+
+int
+usrp1_source_s::ninput_bytes_reqd_for_noutput_items (int noutput_items)
+{
+ return noutput_items * NBASIC_SAMPLES_PER_ITEM * sizeof_basic_sample();
+}
+
+/*
+ * Convert interleaved 8 or 16-bit I & Q from usrp buffer into a single
+ * short output stream.
+ */
+void
+usrp1_source_s::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)
+{
+ short *out = &((short *) output_items[0])[output_index];
+ unsigned sbs = sizeof_basic_sample();
+ unsigned nusrp_bytes_per_item = NBASIC_SAMPLES_PER_ITEM * sbs;
+
+ int nitems = std::min (output_items_available,
+ (int)(usrp_buffer_length / nusrp_bytes_per_item));
+
+ signed char *s8 = (signed char *) usrp_buffer;
+ short *s16 = (short *) usrp_buffer;
+
+ switch(sbs){
+ case 1:
+ for (int i = 0; i < nitems; i++){
+ out[i] = s8[i] << 8;
+ }
+ break;
+
+ case 2:
+ for (int i = 0; i < nitems; i++){
+ out[i] = usrp_to_host_short(s16[i]);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ output_items_produced = nitems;
+ bytes_read = nitems * nusrp_bytes_per_item;
+}
diff --git a/gr-usrp/src/usrp1_source_s.h b/gr-usrp/src/usrp1_source_s.h
new file mode 100644
index 000000000..a3a3e743a
--- /dev/null
+++ b/gr-usrp/src/usrp1_source_s.h
@@ -0,0 +1,94 @@
+/* -*- 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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_USRP1_SOURCE_S_H
+#define INCLUDED_USRP1_SOURCE_S_H
+
+#include <usrp1_source_base.h>
+#include <stdexcept>
+
+class usrp_standard_rx;
+
+
+class usrp1_source_s;
+typedef boost::shared_ptr<usrp1_source_s> usrp1_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);
+
+/*!
+ * \brief interface to Universal Software Radio Peripheral Rx path (Rev 1)
+ *
+ * output: 1 stream of short
+ */
+class usrp1_source_s : public usrp1_source_base {
+ private:
+ friend 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);
+
+ protected:
+ usrp1_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);
+
+ virtual int ninput_bytes_reqd_for_noutput_items (int noutput_items);
+
+ 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);
+ public:
+ ~usrp1_source_s ();
+};
+
+#endif /* INCLUDED_USRP1_SOURCE_S_H */
diff --git a/gr-usrp/src/usrp_multi.py b/gr-usrp/src/usrp_multi.py
new file mode 100644
index 000000000..865e42fa1
--- /dev/null
+++ b/gr-usrp/src/usrp_multi.py
@@ -0,0 +1,233 @@
+#
+# 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 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+from gnuradio import gr, gru
+from gnuradio.gr import hier_block_base
+from gnuradio import usrp
+from gnuradio import usrp1 # usrp Rev 1 and later
+from gnuradio import blks
+import usrp_prims
+import sys
+
+
+class multi_source_align(object):
+ def __init__(self, fg, master_serialno,decim,nchan=2,pga_gain=0.0,cordic_freq=0.0,mux=None,align_interval=-1):
+ """
+ Align multiple sources (usrps) using samplenumbers in the first channel.
+
+ Takes two ore more sources producing interleaved shorts.
+ produces nchan * nsources gr_complex output streams.
+
+ @param nchan: number of interleaved channels in source
+ @param align_interval: number of samples to minimally skip between alignments
+ default = -1 which means align only once per work call.
+ @param master_serial_no: serial number of the source which must be the master.
+
+
+ Exported sub-blocks (attributes):
+ master_source
+ slave_source
+ usrp_master
+ usrp_slave
+ """
+ mode=usrp.FPGA_MODE_NORMAL
+ mode = mode | usrp_prims.bmFR_MODE_RX_COUNTING_32BIT #(1 << 2) #usrp1.FPGA_MODE_COUNTING_32BIT
+ align=gr.align_on_samplenumbers_ss (nchan,align_interval)
+ self.usrp_master = None
+ self.usrp_slave = None
+ # um is master usrp
+ # us is slave usrp
+ if mux is None:
+ mux=self.get_default_mux() #Note that all channels have shifted left because of the added 32 bit counter channel
+
+ u1 = usrp.source_s (1, decim, nchan, gru.hexint(mux), mode,fpga_filename="multi_2rxhb_2tx.rbf" )
+ u0 = usrp.source_s (0, decim, nchan, gru.hexint(mux), mode,fpga_filename="multi_2rxhb_2tx.rbf" )
+ print 'usrp[0] serial',u0.serial_number()
+ print 'usrp[1] serial',u1.serial_number()
+ #default, choose the second found usrp as master (which is usually the usrp which was first plugged in)
+ um_index=1
+ um=u1
+ us_index=0
+ us=u0
+ if (not (master_serialno is None)): #((master_serialno>0) | (master_serialno <-2)):
+ if (u0.serial_number() == master_serialno):
+ um_index=0
+ um=u0
+ us_index=1
+ us=u1
+ elif (u1.serial_number() != master_serialno):
+ errorstring = 'Error. requested master_serialno ' + master_serialno +' not found\n'
+ errorstring = errorstring + 'Available are:\n'
+ errorstring = errorstring + 'usrp[1] serial_no = ' + u1.serial_number() +'\n'
+ errorstring = errorstring + 'usrp[0] serial_no = ' + u0.serial_number() +'\n'
+ print errorstring
+ raise ValueError, errorstring
+ else: #default, just choose the first found usrp as master
+ um_index=0
+ um=u0
+ us_index=1
+ us=u1
+
+ self.usrp_master=um
+ self.usrp_slave=us
+ print 'usrp_master=usrp[%i] serial_no = %s' % (um_index,self.usrp_master.serial_number() ,)
+ print 'usrp_slave=usrp[%i] serial_no = %s' % (us_index,self.usrp_slave.serial_number() ,)
+ self.subdev_mAr = usrp.selected_subdev(self.usrp_master, (0,0))
+ self.subdev_mBr = usrp.selected_subdev(self.usrp_master, (1,0))
+ self.subdev_sAr = usrp.selected_subdev(self.usrp_slave, (0,0))
+ self.subdev_sBr = usrp.selected_subdev(self.usrp_slave, (1,0))
+ #throttle = gr.throttle(gr.sizeof_gr_complex, input_rate)
+ if not (pga_gain is None):
+ um.set_pga (0, pga_gain)
+ um.set_pga (1, pga_gain)
+
+ us.set_pga (0, pga_gain)
+ us.set_pga (1, pga_gain)
+
+ self.input_rate = um.adc_freq () / um.decim_rate ()
+ deintm=gr.deinterleave(gr.sizeof_gr_complex)
+ deints=gr.deinterleave(gr.sizeof_gr_complex)
+ nullsinkm=gr.null_sink(gr.sizeof_gr_complex)
+ nullsinks=gr.null_sink(gr.sizeof_gr_complex)
+
+ tocomplexm=gr.interleaved_short_to_complex()
+ tocomplexs=gr.interleaved_short_to_complex()
+
+ fg.connect(um,(align,0))
+ fg.connect(us,(align,1))
+ fg.connect((align,0),tocomplexm)
+ fg.connect((align,1),tocomplexs)
+ fg.connect(tocomplexm,deintm)
+ fg.connect(tocomplexs,deints)
+ fg.connect((deintm,0),nullsinkm) #The counters are not usefull for the user but must be connected to something
+ fg.connect((deints,0),nullsinks) #The counters are not usefull for the user but must be connected to something
+ if 4==nchan:
+ nullsinkm3=gr.null_sink(gr.sizeof_gr_complex)
+ nullsinks3=gr.null_sink(gr.sizeof_gr_complex)
+ fg.connect((deintm,3), nullsinkm3) #channel 4 is not used but must be connected
+ fg.connect((deints,3), nullsinks3) #channel 4 is not used but must be connected
+
+ self.fg=fg
+ self.master_source=deintm
+ self.slave_source=deints
+
+ if not (cordic_freq is None):
+ um.set_rx_freq (1, cordic_freq)
+ um.set_rx_freq (0, cordic_freq)
+ us.set_rx_freq (1, cordic_freq)
+ us.set_rx_freq (0, cordic_freq)
+
+ self.enable_master_and_slave()
+ # add an idle handler
+ self.unsynced=True
+
+ # wire the block together
+ #hier_block_multi_tail.__init__(self, fg, nchan,deintm,deints)
+
+ def get_default_mux(self):
+ return 0x10321032 # Note that all channels have shifted left because of the added 32 bit counter channel
+
+ def get_master_source_c(self):
+ return self.master_source
+
+ def get_slave_source_c(self):
+ return self.slave_source
+
+ def get_master_usrp(self):
+ return self.usrp_master
+
+ def get_slave_usrp(self):
+ return self.usrp_slave
+
+ def enable_master_and_slave(self):
+ # Warning, allways FIRST enable the slave before you enable the master
+ # This is to be sure you don't have two masters connecting to each other
+ # Otherwise you could ruin your hardware because the two sync outputs would be connected together
+
+ #SLAVE
+ #disable master, enable slave and set sync pulse to zero
+ reg_mask = usrp_prims.bmFR_RX_SYNC_SLAVE | usrp_prims.bmFR_RX_SYNC_MASTER | usrp_prims.bmFR_RX_SYNC
+ self.usrp_slave._u._write_fpga_reg_masked(usrp_prims.FR_RX_MASTER_SLAVE, usrp_prims.bmFR_RX_SYNC_SLAVE,reg_mask)
+ #set SYNC slave iopin on daughterboards RXA as input
+ oe = 0 # set rx_a_io[bitnoFR_RX_SYNC_INPUT_IOPIN] as input
+ oe_mask = usrp_prims.bmFR_RX_SYNC_INPUT_IOPIN
+ self.usrp_slave._u._write_oe(0,oe,oe_mask)
+ #Now it is save to enable the master
+
+ #MASTER
+ #enable master, disable slave and set sync pulse to zero
+ reg_mask = usrp_prims.bmFR_RX_SYNC_SLAVE | usrp_prims.bmFR_RX_SYNC_MASTER | usrp_prims.bmFR_RX_SYNC
+ self.usrp_master._u._write_fpga_reg_masked(usrp_prims.FR_RX_MASTER_SLAVE,usrp_prims.bmFR_RX_SYNC_MASTER,reg_mask)
+ #set SYNC master iopin on daughterboards RXA as output
+ oe = usrp_prims.bmFR_RX_SYNC_OUTPUT_IOPIN # set rx_a_io[bitnoFR_RX_SYNC_OUTPUT_IOPIN] as output
+ oe_mask = usrp_prims.bmFR_RX_SYNC_OUTPUT_IOPIN
+ self.usrp_master._u._write_oe(0,oe,oe_mask)
+
+ def sync_usrps(self, evt):
+ self.sync()
+
+ def sync(self):
+ result=False
+ result = self.usrp_master._u._write_fpga_reg_masked (usrp_prims.FR_RX_MASTER_SLAVE, usrp_prims.bmFR_RX_SYNC, usrp_prims.bmFR_RX_SYNC )
+ #There should be a small delay here, but the time it takes to get the sync to the usrp is long enough
+ #turn sync pulse off
+ result = result & self.usrp_master._u._write_fpga_reg_masked (usrp_prims.FR_RX_MASTER_SLAVE,0 ,usrp_prims.bmFR_RX_SYNC);
+ return result;
+
+ def nullsink_counters(self):
+ nullsinkm=gr.null_sink(gr.sizeof_gr_complex)
+ nullsinks=gr.null_sink(gr.sizeof_gr_complex)
+ self.fg.connect((self.master_source,0),nullsinkm)
+ self.fg.connect((self.slave_source,0),nullsinks)
+
+
+ def print_db_info(self):
+ print "MASTER RX d'board %s" % (self.subdev_mAr.side_and_name(),)
+ print "MASTER RX d'board %s" % (self.subdev_mBr.side_and_name(),)
+ #print "TX d'board %s" % (self.subdev_At.side_and_name(),)
+ #print "TX d'board %s" % (self.subdev_Bt.side_and_name(),)
+ print "SLAVE RX d'board %s" % (self.subdev_sAr.side_and_name(),)
+ print "SLAVE RX d'board %s" % (self.subdev_sBr.side_and_name(),)
+ #print "TX d'board %s" % (self.subdev_At.side_and_name(),)
+ #print "TX d'board %s" % (self.subdev_Bt.side_and_name(),)
+
+ def tune_all_rx(self,target_freq):
+ result = True
+ r1 = usrp.tune(self.usrp_master, 0, self.subdev_mAr, target_freq)
+ if r1 is None:
+ result=False
+ r2 = usrp.tune(self.usrp_master, 1, self.subdev_mBr, target_freq)
+ if r2 is None:
+ result=False
+ r3 = usrp.tune(self.usrp_slave, 0, self.subdev_sAr, target_freq)
+ if r3 is None:
+ result=False
+ r4 = usrp.tune(self.usrp_slave, 1, self.subdev_sBr, target_freq)
+ if r4 is None:
+ result=False
+ return result,r1,r2,r3,r4
+
+ def set_gain_all_rx(self, gain):
+ self.subdev_mAr.set_gain(gain)
+ self.subdev_mBr.set_gain(gain)
+ self.subdev_sAr.set_gain(gain)
+ self.subdev_sBr.set_gain(gain)