summaryrefslogtreecommitdiff
path: root/usrp/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usrp/host/lib')
-rw-r--r--usrp/host/lib/Makefile.am137
-rw-r--r--usrp/host/lib/README_OSX63
-rw-r--r--usrp/host/lib/ad9862.h221
-rwxr-xr-xusrp/host/lib/check_data.py50
-rw-r--r--usrp/host/lib/circular_buffer.h325
-rw-r--r--usrp/host/lib/circular_linked_list.h267
-rw-r--r--usrp/host/lib/darwin_libusb.h190
-rwxr-xr-xusrp/host/lib/dump_data.py40
-rw-r--r--usrp/host/lib/dxc-io-assignments.gnumericbin0 -> 3251 bytes
-rw-r--r--usrp/host/lib/fusb.cc60
-rw-r--r--usrp/host/lib/fusb.h128
-rw-r--r--usrp/host/lib/fusb_darwin.cc499
-rw-r--r--usrp/host/lib/fusb_darwin.h215
-rw-r--r--usrp/host/lib/fusb_generic.cc108
-rw-r--r--usrp/host/lib/fusb_generic.h83
-rw-r--r--usrp/host/lib/fusb_linux.cc684
-rw-r--r--usrp/host/lib/fusb_linux.h116
-rw-r--r--usrp/host/lib/fusb_sysconfig_darwin.cc37
-rw-r--r--usrp/host/lib/fusb_sysconfig_generic.cc37
-rw-r--r--usrp/host/lib/fusb_sysconfig_linux.cc37
-rw-r--r--usrp/host/lib/fusb_sysconfig_win32.cc37
-rw-r--r--usrp/host/lib/fusb_win32.cc265
-rw-r--r--usrp/host/lib/fusb_win32.h90
-rwxr-xr-xusrp/host/lib/gen-ratios48
-rwxr-xr-xusrp/host/lib/gen_usrp_dbid.py137
-rw-r--r--usrp/host/lib/md5.c452
-rw-r--r--usrp/host/lib/md5.h129
-rw-r--r--usrp/host/lib/mld_threads.h257
-rw-r--r--usrp/host/lib/rate_to_regval.h97
-rw-r--r--usrp/host/lib/std_paths.h.in27
-rw-r--r--usrp/host/lib/usrp_basic.cc1239
-rw-r--r--usrp/host/lib/usrp_basic.h776
-rw-r--r--usrp/host/lib/usrp_bytesex.h74
-rw-r--r--usrp/host/lib/usrp_config.cc35
-rw-r--r--usrp/host/lib/usrp_config.h67
-rw-r--r--usrp/host/lib/usrp_dbid.dat75
-rw-r--r--usrp/host/lib/usrp_local_sighandler.cc190
-rw-r--r--usrp/host/lib/usrp_local_sighandler.h61
-rw-r--r--usrp/host/lib/usrp_prims.cc1355
-rw-r--r--usrp/host/lib/usrp_prims.h294
-rw-r--r--usrp/host/lib/usrp_slots.h33
-rw-r--r--usrp/host/lib/usrp_standard.cc831
-rw-r--r--usrp/host/lib/usrp_standard.h366
43 files changed, 10232 insertions, 0 deletions
diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am
new file mode 100644
index 000000000..e2086bc2c
--- /dev/null
+++ b/usrp/host/lib/Makefile.am
@@ -0,0 +1,137 @@
+#
+# USRP - Universal Software Radio Peripheral
+#
+# Copyright (C) 2003,2004,2006 Free Software Foundation, Inc.
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+INCLUDES = -I$(top_srcdir)/usrp/firmware/include
+
+lib_LTLIBRARIES = libusrp.la
+
+
+EXTRA_DIST = \
+ std_paths.h.in \
+ usrp_dbid.dat
+
+
+BUILT_SOURCES = \
+ usrp_dbid.h \
+ usrp_dbid.cc \
+ usrp_dbid.py
+
+
+# ----------------------------------------------------------------
+# FUSB_TECH is set at configure time by way of
+# usrp/config/usrp_fusb_tech.m4.
+# It indicates which fast usb strategy we should be building.
+# We currently implement "generic", "darwin", "win32" and "linux"
+
+
+generic_CODE = \
+ fusb_generic.cc \
+ fusb_sysconfig_generic.cc
+
+darwin_CODE = \
+ fusb_darwin.cc \
+ fusb_sysconfig_darwin.cc \
+ README_OSX \
+ circular_buffer.h \
+ circular_linked_list.h \
+ darwin_libusb.h \
+ mld_threads.h
+
+win32_CODE = \
+ fusb_win32.cc \
+ fusb_sysconfig_win32.cc
+
+linux_CODE = \
+ fusb_linux.cc \
+ fusb_sysconfig_linux.cc
+
+
+#
+# include each <foo>_CODE entry here...
+#
+EXTRA_libusrp_la_SOURCES = \
+ $(generic_CODE) \
+ $(darwin_CODE) \
+ $(win32_CODE) \
+ $(linux_CODE)
+
+
+# work around automake deficiency
+libusrp_la_common_SOURCES = \
+ fusb.cc \
+ md5.c \
+ usrp_basic.cc \
+ usrp_config.cc \
+ usrp_dbid.cc \
+ usrp_local_sighandler.cc \
+ usrp_prims.cc \
+ usrp_standard.cc
+
+
+if FUSB_TECH_generic
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(generic_CODE)
+endif
+
+if FUSB_TECH_darwin
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(darwin_CODE)
+endif
+
+if FUSB_TECH_win32
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(win32_CODE)
+endif
+
+if FUSB_TECH_linux
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(linux_CODE)
+endif
+
+
+libusrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
+libusrp_la_LIBADD = $(USB_LIBS) ../misc/libmisc.la
+
+include_HEADERS = \
+ usrp_basic.h \
+ usrp_bytesex.h \
+ usrp_config.h \
+ usrp_dbid.h \
+ usrp_prims.h \
+ usrp_slots.h \
+ usrp_standard.h
+
+noinst_HEADERS = \
+ ad9862.h \
+ fusb.h \
+ fusb_darwin.h \
+ fusb_win32.h \
+ fusb_generic.h \
+ fusb_linux.h \
+ md5.h \
+ rate_to_regval.h \
+ usrp_local_sighandler.h
+
+python_PYTHON = \
+ usrp_dbid.py
+
+noinst_PYTHON = \
+ gen_usrp_dbid.py
+
+usrp_dbid.py usrp_dbid.h usrp_dbid.cc: gen_usrp_dbid.py usrp_dbid.dat
+ PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat
+
+MOSTLYCLEANFILES = \
+ $(BUILT_SOURCES) *~ *.pyc
diff --git a/usrp/host/lib/README_OSX b/usrp/host/lib/README_OSX
new file mode 100644
index 000000000..20230f121
--- /dev/null
+++ b/usrp/host/lib/README_OSX
@@ -0,0 +1,63 @@
+USRP Darwin Fast USB Changes
+Version 0.2 of 2006-04-27
+Michael Dickens <mdickens @at@ nd .dot. edu>
+
+The files included in this archive are:
+
+circular_buffer.h
+circular_linked_list.h
+darwin_libusb.h
+fusb_darwin.cc
+fusb_darwin.h
+mld_threads.h
+
+These files allow GNURadio code for Darwin / MaxOS X to talk to the
+USRP via USB 2.0 at rates up to around 30 Mega-Bytes/sec (MBps), up
+from 4-8 MBps without the changes.
+
+I implemented the buffering myself; there are probably GR buffers
+available which would do the work but as this is "beta" software it's
+a good place to start. Speed improvements are made by porting
+LIBUSB's non-true async bulk read and write functions into USRP's
+"fusb", and upgrading them to handle -true- async transfers.
+Unfortunately, the easiest way to do this is to spawn a thread or 2 to
+handle the "async" part of the transfers. This implementation uses
+Darwin's pthreads to do the work for mutexes, conditions, and threads.
+Previous implementations (0.1 and before) used "omni_threads" as
+provided by gnuradio-core, which caused issues with compiling and
+execution ... I'm glad that this is no longer the case.
+
+As far as I have tested, there is no way to improve the throughput to
+32+ MBps without moving into Darwin's "port"s ... a kernel-level data
+transport method with a user/application layer for USB-specific
+functions. Unfortunately, Apple's documentation for these "port"s is
+minimal; I have learned more from reading the Darwin source code
+< http://darwinsource.opendarwin.org/ > than by reading Apple's
+documents! This would also require -not- using LIBUSB, of which the
+removal from the rest of the USRP code would be potentially tedious.
+
+If you run into issues either compiling or testing the USRP on
+OSX, please send me a note.
+
+(1) Go through the bootstrap, configure, compile, and install as
+usual (e.g. see < http://www.nd.edu/~mdickens/GNURadio/ > for my
+usual).
+
+(2) from .../usrp/host/apps : run the scripts
+++++++++++++++++
+./test_usrp_standard_tx
+./test_usrp_standard_rx
+++++++++++++++++
+
+For -all- systems I've tested on thus far, both of these return
+exactly 41 overruns / underruns, and -most- systems start out with a
+stalled pipe. This stall comes in a usb_control funciton call to
+LIBUSB; one would have to change the LIBUSB code to handle this issue.
+
+(3) from gr-build/gnuradio-examples/python/usrp :
+++++++++++++++++
+./benchmark_usb.py
+++++++++++++++++
+
+(4) If you get to here, the try doing the FM receiver (gui or not).
+If that sounds correct, then the USB is working. Yay! \ No newline at end of file
diff --git a/usrp/host/lib/ad9862.h b/usrp/host/lib/ad9862.h
new file mode 100644
index 000000000..70cb20289
--- /dev/null
+++ b/usrp/host/lib/ad9862.h
@@ -0,0 +1,221 @@
+/* -*- 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_AD9862_H
+#define INCLUDED_AD9862_H
+
+/*
+ * Analog Devices AD9862 registers and some fields
+ */
+
+#define BEGIN_AD9862 namespace ad9862 {
+#define END_AD962 }
+#define DEF static const int
+
+BEGIN_AD9862;
+
+DEF REG_GENERAL = 0;
+DEF REG_RX_PWR_DN = 1;
+DEF RX_PWR_DN_VREF_DIFF = (1 << 7);
+DEF RX_PWR_DN_VREF = (1 << 6);
+DEF RX_PWR_DN_RX_DIGIGAL = (1 << 5);
+DEF RX_PWR_DN_RX_B = (1 << 4);
+DEF RX_PWR_DN_RX_A = (1 << 3);
+DEF RX_PWR_DN_BUF_B = (1 << 2);
+DEF RX_PWR_DN_BUF_A = (1 << 1);
+DEF RX_PWR_DN_ALL = (1 << 0);
+
+DEF REG_RX_A = 2; // bypass input buffer / RxPGA
+DEF REG_RX_B = 3; // pypass input buffer / RxPGA
+DEF RX_X_BYPASS_INPUT_BUFFER = (1 << 7);
+
+DEF REG_RX_MISC = 4;
+DEF RX_MISC_HS_DUTY_CYCLE = (1 << 2);
+DEF RX_MISC_SHARED_REF = (1 << 1);
+DEF RX_MISC_CLK_DUTY = (1 << 0);
+
+DEF REG_RX_IF = 5;
+DEF RX_IF_THREE_STATE = (1 << 4);
+DEF RX_IF_USE_CLKOUT1 = (0 << 3);
+DEF RX_IF_USE_CLKOUT2 = (1 << 3); // aka Rx Retime
+DEF RX_IF_2S_COMP = (1 << 2);
+DEF RX_IF_INV_RX_SYNC = (1 << 1);
+DEF RX_IF_MUX_OUT = (1 << 0);
+
+DEF REG_RX_DIGITAL = 6;
+DEF RX_DIGITAL_2_CHAN = (1 << 3);
+DEF RX_DIGITAL_KEEP_MINUS_VE = (1 << 2);
+DEF RX_DIGITAL_HILBERT = (1 << 1);
+DEF RX_DIGITAL_DECIMATE = (1 << 0);
+
+DEF REG_RESERVED_7 = 7;
+
+DEF REG_TX_PWR_DN = 8;
+DEF TX_PWR_DN_ALT_TIMING_MODE = (1 << 5);
+DEF TX_PWR_DN_TX_OFF_ENABLE = (1 << 4);
+DEF TX_PWR_DN_TX_DIGITAL = (1 << 3);
+DEF TX_PWR_DN_TX_ANALOG_B = 0x4;
+DEF TX_PWR_DN_TX_ANALOG_A = 0x2;
+DEF TX_PWR_DN_TX_ANALOG_BOTH = 0x7;
+
+DEF REG_RESERVED_9 = 9;
+
+DEF REG_TX_A_OFFSET_LO = 10;
+DEF REG_TX_A_OFFSET_HI = 11;
+DEF REG_TX_B_OFFSET_LO = 12;
+DEF REG_TX_B_OFFSET_HI = 13;
+
+DEF REG_TX_A_GAIN = 14; // fine trim for matching
+DEF REG_TX_B_GAIN = 15; // fine trim for matching
+DEF TX_X_GAIN_COARSE_FULL = (3 << 6);
+DEF TX_X_GAIN_COARSE_1_HALF = (1 << 6);
+DEF TX_X_GAIN_COARSE_1_ELEVENTH = (0 << 6);
+
+DEF REG_TX_PGA = 16; // 20 dB continuous gain in 0.1 dB steps
+ // 0x00 = min gain (-20 dB)
+ // 0xff = max gain ( 0 dB)
+
+DEF REG_TX_MISC = 17;
+DEF TX_MISC_SLAVE_ENABLE = (1 << 1);
+DEF TX_MISC_TX_PGA_FAST = (1 << 0);
+
+DEF REG_TX_IF = 18;
+DEF TX_IF_USE_CLKOUT2 = (0 << 6);
+DEF TX_IF_USE_CLKOUT1 = (1 << 6); // aka Tx Retime
+DEF TX_IF_I_FIRST = (0 << 5);
+DEF TX_IF_Q_FIRST = (1 << 5);
+DEF TX_IF_INV_TX_SYNC = (1 << 4);
+DEF TX_IF_2S_COMP = (1 << 3);
+DEF TX_IF_INVERSE_SAMPLE = (1 << 2);
+DEF TX_IF_TWO_EDGES = (1 << 1);
+DEF TX_IF_INTERLEAVED = (1 << 0);
+
+DEF REG_TX_DIGITAL = 19;
+DEF TX_DIGITAL_2_DATA_PATHS = (1 << 4);
+DEF TX_DIGITAL_KEEP_NEGATIVE = (1 << 3);
+DEF TX_DIGITAL_HILBERT = (1 << 2);
+DEF TX_DIGITAL_INTERPOLATE_NONE = 0x0;
+DEF TX_DIGITAL_INTERPOLATE_2X = 0x1;
+DEF TX_DIGITAL_INTERPOLATE_4X = 0x2;
+
+DEF REG_TX_MODULATOR = 20;
+DEF TX_MODULATOR_NEG_FINE_TUNE = (1 << 5);
+DEF TX_MODULATOR_DISABLE_NCO = (0 << 4);
+DEF TX_MODULATOR_ENABLE_NCO = (1 << 4); // aka Fine Mode
+DEF TX_MODULATOR_REAL_MIX_MODE = (1 << 3);
+DEF TX_MODULATOR_NEG_COARSE_TUNE = (1 << 2);
+DEF TX_MODULATOR_COARSE_MODULATION_NONE = 0x0;
+DEF TX_MODULATOR_COARSE_MODULATION_F_OVER_4 = 0x1;
+DEF TX_MODULATOR_COARSE_MODULATION_F_OVER_8 = 0x2;
+DEF TX_MODULATOR_CM_MASK = 0x7;
+
+
+DEF REG_TX_NCO_FTW_7_0 = 21;
+DEF REG_TX_NCO_FTW_15_8 = 22;
+DEF REG_TX_NCO_FTW_23_16= 23;
+
+DEF REG_DLL = 24;
+DEF DLL_DISABLE_INTERNAL_XTAL_OSC = (1 << 6); // aka Input Clock Ctrl
+DEF DLL_ADC_DIV2 = (1 << 5);
+DEF DLL_MULT_1X = (0 << 3);
+DEF DLL_MULT_2X = (1 << 3);
+DEF DLL_MULT_4X = (2 << 3);
+DEF DLL_PWR_DN = (1 << 2);
+// undefined bit = (1 << 1);
+DEF DLL_FAST = (1 << 0);
+
+DEF REG_CLKOUT = 25;
+DEF CLKOUT2_EQ_DLL = (0 << 6);
+DEF CLKOUT2_EQ_DLL_OVER_2 = (1 << 6);
+DEF CLKOUT2_EQ_DLL_OVER_4 = (2 << 6);
+DEF CLKOUT2_EQ_DLL_OVER_8 = (3 << 6);
+DEF CLKOUT_INVERT_CLKOUT2 = (1 << 5);
+DEF CLKOUT_DISABLE_CLKOUT2 = (1 << 4);
+// undefined bit = (1 << 3);
+// undefined bit = (1 << 2);
+DEF CLKOUT_INVERT_CLKOUT1 = (1 << 1);
+DEF CLKOUT_DISABLE_CLKOUT1 = (1 << 0);
+
+DEF REG_AUX_ADC_A2_LO = 26;
+DEF REG_AUX_ADC_A2_HI = 27;
+DEF REG_AUX_ADC_A1_LO = 28;
+DEF REG_AUX_ADC_A1_HI = 29;
+DEF REG_AUX_ADC_B2_LO = 30;
+DEF REG_AUX_ADC_B2_HI = 31;
+DEF REG_AUX_ADC_B1_LO = 32;
+DEF REG_AUX_ADC_B1_HI = 33;
+
+DEF REG_AUX_ADC_CTRL = 34;
+DEF AUX_ADC_CTRL_AUX_SPI = (1 << 7);
+DEF AUX_ADC_CTRL_SELBNOTA = (1 << 6);
+DEF AUX_ADC_CTRL_REFSEL_B = (1 << 5);
+DEF AUX_ADC_CTRL_SELECT_B2 = (0 << 4);
+DEF AUX_ADC_CTRL_SELECT_B1 = (1 << 4);
+DEF AUX_ADC_CTRL_START_B = (1 << 3);
+DEF AUX_ADC_CTRL_REFSEL_A = (1 << 2);
+DEF AUX_ADC_CTRL_SELECT_A2 = (0 << 1);
+DEF AUX_ADC_CTRL_SELECT_A1 = (1 << 1);
+DEF AUX_ADC_CTRL_START_A = (1 << 0);
+
+DEF REG_AUX_ADC_CLK = 35;
+DEF AUX_ADC_CLK_CLK_OVER_4 = (1 << 0);
+
+DEF REG_AUX_DAC_A = 36;
+DEF REG_AUX_DAC_B = 37;
+DEF REG_AUX_DAC_C = 38;
+
+DEF REG_AUX_DAC_UPDATE = 39;
+DEF AUX_DAC_UPDATE_SLAVE_ENABLE = (1 << 7);
+DEF AUX_DAC_UPDATE_C = (1 << 2);
+DEF AUX_DAC_UPDATE_B = (1 << 1);
+DEF AUX_DAC_UPDATE_A = (1 << 0);
+
+DEF REG_AUX_DAC_PWR_DN = 40;
+DEF AUX_DAC_PWR_DN_C = (1 << 2);
+DEF AUX_DAC_PWR_DN_B = (1 << 1);
+DEF AUX_DAC_PWR_DN_A = (1 << 0);
+
+DEF REG_AUX_DAC_CTRL = 41;
+DEF AUX_DAC_CTRL_INV_C = (1 << 4);
+DEF AUX_DAC_CTRL_INV_B = (1 << 2);
+DEF AUX_DAC_CTRL_INV_A = (1 << 0);
+
+DEF REG_SIGDELT_LO = 42;
+DEF REG_SIGDELT_HI = 43;
+
+// 44 to 48 reserved
+
+DEF REG_ADC_LOW_PWR_LO = 49;
+DEF REG_ADC_LOW_PWR_HI = 50;
+
+// 51 to 62 reserved
+
+DEF REG_CHIP_ID = 63;
+
+
+END_AD962;
+
+#undef DEF
+#undef BEGIN_AD9862
+#undef END_AD962
+
+#endif /* INCLUDED_AD9862_H */
diff --git a/usrp/host/lib/check_data.py b/usrp/host/lib/check_data.py
new file mode 100755
index 000000000..0f8ea2ef5
--- /dev/null
+++ b/usrp/host/lib/check_data.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+#
+# Copyright 2003 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 struct
+
+fin = sys.stdin
+
+count = 0
+expected = 0
+last_correction = 0
+
+while 1:
+ s = fin.read(2)
+ if not s or len(s) != 2:
+ break
+
+ v, = struct.unpack ('H', s)
+ iv = int(v) & 0xffff
+ # print "%8d %6d 0x%04x" % (count, iv, iv)
+ if count & 0x1: # only counting on the Q channel
+ if (expected & 0xffff) != iv:
+ print "%8d (%6d) %6d 0x%04x" % (count, count - last_correction, iv, iv)
+ expected = iv # reset expected sequence
+ last_correction = count
+ expected = (expected + 1) & 0xffff
+
+ count += 1
+
+
+
+
diff --git a/usrp/host/lib/circular_buffer.h b/usrp/host/lib/circular_buffer.h
new file mode 100644
index 000000000..4d507c2e5
--- /dev/null
+++ b/usrp/host/lib/circular_buffer.h
@@ -0,0 +1,325 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 _CIRCULAR_BUFFER_H_
+#define _CIRCULAR_BUFFER_H_
+
+#include "mld_threads.h"
+#include <stdexcept>
+
+#define DO_DEBUG 0
+
+template <class T> class circular_buffer
+{
+private:
+// the buffer to use
+ T* d_buffer;
+
+// the following are in Items (type T)
+ UInt32 d_bufLen_I, d_readNdx_I, d_writeNdx_I;
+ UInt32 d_n_avail_write_I, d_n_avail_read_I;
+
+// stuff to control access to class internals
+ mld_mutex_ptr d_internal;
+ mld_condition_ptr d_readBlock, d_writeBlock;
+
+// booleans to decide how to control reading, writing, and aborting
+ bool d_doWriteBlock, d_doFullRead, d_doAbort;
+
+ void delete_mutex_cond () {
+ if (d_internal) {
+ delete d_internal;
+ d_internal = NULL;
+ }
+ if (d_readBlock) {
+ delete d_readBlock;
+ d_readBlock = NULL;
+ }
+ if (d_writeBlock) {
+ delete d_writeBlock;
+ d_writeBlock = NULL;
+ }
+ };
+
+public:
+ circular_buffer (UInt32 bufLen_I,
+ bool doWriteBlock = true, bool doFullRead = false) {
+ if (bufLen_I == 0)
+ throw std::runtime_error ("circular_buffer(): "
+ "Number of items to buffer must be > 0.\n");
+ d_bufLen_I = bufLen_I;
+ d_buffer = (T*) new T[d_bufLen_I];
+ d_doWriteBlock = doWriteBlock;
+ d_doFullRead = doFullRead;
+ d_internal = NULL;
+ d_readBlock = d_writeBlock = NULL;
+ reset ();
+#if DO_DEBUG
+ fprintf (stderr, "c_b(): buf len (items) = %ld, "
+ "doWriteBlock = %s, doFullRead = %s\n", d_bufLen_I,
+ (d_doWriteBlock ? "true" : "false"),
+ (d_doFullRead ? "true" : "false"));
+#endif
+ };
+
+ ~circular_buffer () {
+ delete_mutex_cond ();
+ delete [] d_buffer;
+ };
+
+ inline UInt32 n_avail_write_items () {
+ d_internal->lock ();
+ UInt32 retVal = d_n_avail_write_I;
+ d_internal->unlock ();
+ return (retVal);
+ };
+
+ inline UInt32 n_avail_read_items () {
+ d_internal->lock ();
+ UInt32 retVal = d_n_avail_read_I;
+ d_internal->unlock ();
+ return (retVal);
+ };
+
+ inline UInt32 buffer_length_items () {return (d_bufLen_I);};
+ inline bool do_write_block () {return (d_doWriteBlock);};
+ inline bool do_full_read () {return (d_doFullRead);};
+
+ void reset () {
+ d_doAbort = false;
+ bzero (d_buffer, d_bufLen_I * sizeof (T));
+ d_readNdx_I = d_writeNdx_I = d_n_avail_read_I = 0;
+ d_n_avail_write_I = d_bufLen_I;
+ delete_mutex_cond ();
+ d_internal = new mld_mutex ();
+ d_readBlock = new mld_condition ();
+ d_writeBlock = new mld_condition ();
+ };
+
+/*
+ * enqueue: add the given buffer of item-length to the queue,
+ * first-in-first-out (FIFO).
+ *
+ * inputs:
+ * buf: a pointer to the buffer holding the data
+ *
+ * bufLen_I: the buffer length in items (of the instantiated type)
+ *
+ * returns:
+ * -1: on overflow (write is not blocking, and data is being
+ * written faster than it is being read)
+ * 0: if nothing to do (0 length buffer)
+ * 1: if success
+ * 2: in the process of aborting, do doing nothing
+ *
+ * will throw runtime errors if inputs are improper:
+ * buffer pointer is NULL
+ * buffer length is larger than the instantiated buffer length
+ */
+
+ int enqueue (T* buf, UInt32 bufLen_I) {
+#if DO_DEBUG
+ fprintf (stderr, "enqueue: buf = %X, bufLen = %ld.\n",
+ (unsigned int)buf, bufLen_I);
+#endif
+ if (bufLen_I > d_bufLen_I) {
+ fprintf (stderr, "cannot add buffer longer (%ld"
+ ") than instantiated length (%ld"
+ ").\n", bufLen_I, d_bufLen_I);
+ throw std::runtime_error ("circular_buffer::enqueue()");
+ }
+
+ if (bufLen_I == 0)
+ return (0);
+ if (!buf)
+ throw std::runtime_error ("circular_buffer::enqueue(): "
+ "input buffer is NULL.\n");
+ d_internal->lock ();
+ if (d_doAbort) {
+ d_internal->unlock ();
+ return (2);
+ }
+ if (bufLen_I > d_n_avail_write_I) {
+ if (d_doWriteBlock) {
+ while (bufLen_I > d_n_avail_write_I) {
+#if DO_DEBUG
+ fprintf (stderr, "enqueue: #len > #a, waiting.\n");
+#endif
+ d_internal->unlock ();
+ d_writeBlock->wait ();
+ d_internal->lock ();
+ if (d_doAbort) {
+ d_internal->unlock ();
+#if DO_DEBUG
+ fprintf (stderr, "enqueue: #len > #a, aborting.\n");
+#endif
+ return (2);
+ }
+#if DO_DEBUG
+ fprintf (stderr, "enqueue: #len > #a, done waiting.\n");
+#endif
+ }
+ } else {
+ d_n_avail_read_I = d_bufLen_I - bufLen_I;
+ d_n_avail_write_I = bufLen_I;
+#if DO_DEBUG
+ fprintf (stderr, "circular_buffer::enqueue: overflow\n");
+#endif
+ return (-1);
+ }
+ }
+ UInt32 n_now_I = d_bufLen_I - d_writeNdx_I, n_start_I = 0;
+ if (n_now_I > bufLen_I)
+ n_now_I = bufLen_I;
+ else if (n_now_I < bufLen_I)
+ n_start_I = bufLen_I - n_now_I;
+ bcopy (buf, &(d_buffer[d_writeNdx_I]), n_now_I * sizeof (T));
+ if (n_start_I) {
+ bcopy (&(buf[n_now_I]), d_buffer, n_start_I * sizeof (T));
+ d_writeNdx_I = n_start_I;
+ } else
+ d_writeNdx_I += n_now_I;
+ d_n_avail_read_I += bufLen_I;
+ d_n_avail_write_I -= bufLen_I;
+ d_readBlock->signal ();
+ d_internal->unlock ();
+ return (1);
+ };
+
+/*
+ * dequeue: removes from the queue the number of items requested, or
+ * available, into the given buffer on a FIFO basis.
+ *
+ * inputs:
+ * buf: a pointer to the buffer into which to copy the data
+ *
+ * bufLen_I: pointer to the number of items to remove in items
+ * (of the instantiated type)
+ *
+ * returns:
+ * 0: if nothing to do (0 length buffer)
+ * 1: if success
+ * 2: in the process of aborting, do doing nothing
+ *
+ * will throw runtime errors if inputs are improper:
+ * buffer pointer is NULL
+ * buffer length pointer is NULL
+ * buffer length is larger than the instantiated buffer length
+ */
+
+
+ int dequeue (T* buf, UInt32* bufLen_I) {
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: buf = %X, *bufLen = %ld.\n",
+ (unsigned int)buf, *bufLen_I);
+#endif
+ if (!bufLen_I)
+ throw std::runtime_error ("circular_buffer::dequeue(): "
+ "input bufLen pointer is NULL.\n");
+ if (!buf)
+ throw std::runtime_error ("circular_buffer::dequeue(): "
+ "input buffer pointer is NULL.\n");
+ UInt32 l_bufLen_I = *bufLen_I;
+ if (l_bufLen_I == 0)
+ return (0);
+ if (l_bufLen_I > d_bufLen_I) {
+ fprintf (stderr, "cannot remove buffer longer (%ld"
+ ") than instantiated length (%ld"
+ ").\n", l_bufLen_I, d_bufLen_I);
+ throw std::runtime_error ("circular_buffer::dequeue()");
+ }
+
+ d_internal->lock ();
+ if (d_doAbort) {
+ d_internal->unlock ();
+ return (2);
+ }
+ if (d_doFullRead) {
+ while (d_n_avail_read_I < l_bufLen_I) {
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: #a < #len, waiting.\n");
+#endif
+ d_internal->unlock ();
+ d_readBlock->wait ();
+ d_internal->lock ();
+ if (d_doAbort) {
+ d_internal->unlock ();
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: #a < #len, aborting.\n");
+#endif
+ return (2);
+ }
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: #a < #len, done waiting.\n");
+#endif
+ }
+ } else {
+ while (d_n_avail_read_I == 0) {
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: #a == 0, waiting.\n");
+#endif
+ d_internal->unlock ();
+ d_readBlock->wait ();
+ d_internal->lock ();
+ if (d_doAbort) {
+ d_internal->unlock ();
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: #a == 0, aborting.\n");
+#endif
+ return (2);
+ }
+#if DO_DEBUG
+ fprintf (stderr, "dequeue: #a == 0, done waiting.\n");
+#endif
+ }
+ }
+ if (l_bufLen_I > d_n_avail_read_I)
+ l_bufLen_I = d_n_avail_read_I;
+ UInt32 n_now_I = d_bufLen_I - d_readNdx_I, n_start_I = 0;
+ if (n_now_I > l_bufLen_I)
+ n_now_I = l_bufLen_I;
+ else if (n_now_I < l_bufLen_I)
+ n_start_I = l_bufLen_I - n_now_I;
+ bcopy (&(d_buffer[d_readNdx_I]), buf, n_now_I * sizeof (T));
+ if (n_start_I) {
+ bcopy (d_buffer, &(buf[n_now_I]), n_start_I * sizeof (T));
+ d_readNdx_I = n_start_I;
+ } else
+ d_readNdx_I += n_now_I;
+ *bufLen_I = l_bufLen_I;
+ d_n_avail_read_I -= l_bufLen_I;
+ d_n_avail_write_I += l_bufLen_I;
+ d_writeBlock->signal ();
+ d_internal->unlock ();
+ return (1);
+ };
+
+ void abort () {
+ d_internal->lock ();
+ d_doAbort = true;
+ d_writeBlock->signal ();
+ d_readBlock->signal ();
+ d_internal->unlock ();
+ };
+};
+
+#endif /* _CIRCULAR_BUFFER_H_ */
diff --git a/usrp/host/lib/circular_linked_list.h b/usrp/host/lib/circular_linked_list.h
new file mode 100644
index 000000000..bdfcb0847
--- /dev/null
+++ b/usrp/host/lib/circular_linked_list.h
@@ -0,0 +1,267 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 _CIRCULAR_LINKED_LIST_H_
+#define _CIRCULAR_LINKED_LIST_H_
+
+#include <mld_threads.h>
+#include <stdexcept>
+
+#define __INLINE__ inline
+
+template <class T> class s_both;
+
+template <class T> class s_node
+{
+ typedef s_node<T>* s_node_ptr;
+
+private:
+ T d_object;
+ bool d_available;
+ s_node_ptr d_prev, d_next;
+ s_both<T>* d_both;
+
+public:
+ s_node (T l_object,
+ s_node_ptr l_prev = NULL,
+ s_node_ptr l_next = NULL)
+ : d_object (l_object), d_available (TRUE), d_prev (l_prev),
+ d_next (l_next), d_both (0) {};
+
+ __INLINE__ s_node (s_node_ptr l_prev, s_node_ptr l_next = NULL) {
+ s_node ((T) NULL, l_prev, l_next); };
+ __INLINE__ s_node () { s_node (NULL, NULL, NULL); };
+ __INLINE__ ~s_node () {};
+
+ void remove () {
+ d_prev->next (d_next);
+ d_next->prev (d_prev);
+ d_prev = d_next = this;
+ };
+
+ void insert_before (s_node_ptr l_next) {
+ if (l_next) {
+ s_node_ptr l_prev = l_next->prev ();
+ d_next = l_next;
+ d_prev = l_prev;
+ l_prev->next (this);
+ l_next->prev (this);
+ } else
+ d_next = d_prev = this;
+ };
+
+ void insert_after (s_node_ptr l_prev) {
+ if (l_prev) {
+ s_node_ptr l_next = l_prev->next ();
+ d_prev = l_prev;
+ d_next = l_next;
+ l_next->prev (this);
+ l_prev->next (this);
+ } else
+ d_prev = d_next = this;
+ };
+
+ __INLINE__ T object () { return (d_object); };
+ __INLINE__ void object (T l_object) { d_object = l_object; };
+ __INLINE__ bool available () { return (d_available); };
+ __INLINE__ void set_available () { d_available = TRUE; };
+ __INLINE__ void set_available (bool l_avail) { d_available = l_avail; };
+ __INLINE__ void set_not_available () { d_available = FALSE; };
+ __INLINE__ s_node_ptr next () { return (d_next); };
+ __INLINE__ s_node_ptr prev () { return (d_prev); };
+ __INLINE__ s_both<T>* both () { return (d_both); };
+ __INLINE__ void next (s_node_ptr l_next) { d_next = l_next; };
+ __INLINE__ void prev (s_node_ptr l_prev) { d_prev = l_prev; };
+ __INLINE__ void both (s_both<T>* l_both) { d_both = l_both; };
+};
+
+template <class T> class circular_linked_list {
+ typedef s_node<T>* s_node_ptr;
+
+private:
+ s_node_ptr d_current, d_iterate, d_available, d_inUse;
+ UInt32 d_n_nodes, d_n_used;
+ mld_mutex_ptr d_internal;
+ mld_condition_ptr d_ioBlock;
+
+public:
+ circular_linked_list (UInt32 n_nodes) {
+ if (n_nodes == 0)
+ throw std::runtime_error ("circular_linked_list(): n_nodes == 0");
+
+ d_iterate = NULL;
+ d_n_nodes = n_nodes;
+ d_n_used = 0;
+ s_node_ptr l_prev, l_next;
+ d_inUse = d_current = l_next = l_prev = NULL;
+
+ l_prev = new s_node<T> ();
+ l_prev->set_available ();
+ l_prev->next (l_prev);
+ l_prev->prev (l_prev);
+ if (n_nodes > 1) {
+ l_next = new s_node<T> (l_prev, l_prev);
+ l_next->set_available ();
+ l_next->next (l_prev);
+ l_next->prev (l_prev);
+ l_prev->next (l_next);
+ l_prev->prev (l_next);
+ if (n_nodes > 2) {
+ UInt32 n = n_nodes - 2;
+ while (n-- > 0) {
+ d_current = new s_node<T> (l_prev, l_next);
+ d_current->set_available ();
+ d_current->prev (l_prev);
+ d_current->next (l_next);
+ l_prev->next (d_current);
+ l_next->prev (d_current);
+ l_next = d_current;
+ d_current = NULL;
+ }
+ }
+ }
+ d_available = d_current = l_prev;
+ d_internal = new mld_mutex ();
+ d_ioBlock = new mld_condition ();
+ };
+
+ ~circular_linked_list () {
+ iterate_start ();
+ s_node_ptr l_node = iterate_next ();
+ while (l_node) {
+ delete l_node;
+ l_node = iterate_next ();
+ }
+ delete d_internal;
+ d_internal = NULL;
+ delete d_ioBlock;
+ d_ioBlock = NULL;
+ d_available = d_inUse = d_iterate = d_current = NULL;
+ d_n_used = d_n_nodes = 0;
+ };
+
+ s_node_ptr find_next_available_node () {
+ d_internal->lock ();
+// find an available node
+ s_node_ptr l_node = d_available;
+ while (! l_node) {
+ d_internal->unlock ();
+ d_ioBlock->wait ();
+ d_internal->lock ();
+ l_node = d_available;
+ }
+// fprintf (stderr, "::f_n_a_n: #u = %ld, node = %p\n", num_used(), l_node);
+// remove this one from the current available list
+ if (num_available () == 1) {
+// last one, just set available to NULL
+ d_available = NULL;
+ } else
+ d_available = l_node->next ();
+ l_node->remove ();
+// add is to the inUse list
+ if (! d_inUse)
+ d_inUse = l_node;
+ else
+ l_node->insert_before (d_inUse);
+ d_n_used++;
+ l_node->set_not_available ();
+ d_internal->unlock ();
+ return (l_node);
+ };
+
+ void make_node_available (s_node_ptr l_node) {
+ if (!l_node) return;
+ d_internal->lock ();
+// fprintf (stderr, "::m_n_a: #u = %ld, node = %p\n", num_used(), l_node);
+// remove this node from the inUse list
+ if (num_used () == 1) {
+// last one, just set inUse to NULL
+ d_inUse = NULL;
+ } else
+ d_inUse = l_node->next ();
+ l_node->remove ();
+// add this node to the available list
+ if (! d_available)
+ d_available = l_node;
+ else
+ l_node->insert_before (d_available);
+ d_n_used--;
+// signal the condition when new data arrives
+ d_ioBlock->signal ();
+// unlock the mutex for thread safety
+ d_internal->unlock ();
+ };
+
+ __INLINE__ void iterate_start () { d_iterate = d_current; };
+
+ s_node_ptr iterate_next () {
+#if 0
+// lock the mutex for thread safety
+ d_internal->lock ();
+#endif
+ s_node_ptr l_this = NULL;
+ if (d_iterate) {
+ l_this = d_iterate;
+ d_iterate = d_iterate->next ();
+ if (d_iterate == d_current)
+ d_iterate = NULL;
+ }
+#if 0
+// unlock the mutex for thread safety
+ d_internal->unlock ();
+#endif
+ return (l_this);
+ };
+
+ __INLINE__ T object () { return (d_current->d_object); };
+ __INLINE__ void object (T l_object) { d_current->d_object = l_object; };
+ __INLINE__ UInt32 num_nodes () { return (d_n_nodes); };
+ __INLINE__ UInt32 num_used () { return (d_n_used); };
+ __INLINE__ void num_used (UInt32 l_n_used) { d_n_used = l_n_used; };
+ __INLINE__ UInt32 num_available () { return (d_n_nodes - d_n_used); };
+ __INLINE__ void num_used_inc (void) {
+ if (d_n_used < d_n_nodes) ++d_n_used;
+ };
+ __INLINE__ void num_used_dec (void) {
+ if (d_n_used != 0) --d_n_used;
+// signal the condition that new data has arrived
+ d_ioBlock->signal ();
+ };
+ __INLINE__ bool in_use () { return (d_n_used != 0); };
+};
+
+template <class T> class s_both
+{
+private:
+ s_node<T>* d_node;
+ void* d_this;
+public:
+ __INLINE__ s_both (s_node<T>* l_node, void* l_this)
+ : d_node (l_node), d_this (l_this) {};
+ __INLINE__ ~s_both () {};
+ __INLINE__ s_node<T>* node () { return (d_node); };
+ __INLINE__ void* This () { return (d_this); };
+ __INLINE__ void set (s_node<T>* l_node, void* l_this) {
+ d_node = l_node; d_this = l_this;};
+};
+
+#endif /* _CIRCULAR_LINKED_LIST_H_ */
diff --git a/usrp/host/lib/darwin_libusb.h b/usrp/host/lib/darwin_libusb.h
new file mode 100644
index 000000000..164ab9c71
--- /dev/null
+++ b/usrp/host/lib/darwin_libusb.h
@@ -0,0 +1,190 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+/*
+ * The following code was taken from LIBUSB verion 0.1.10a,
+ * and makes the fusb_darwin codes do-able in the current GR
+ * programming framework. Parts and pieces were taken from
+ * usbi.h, darwin.c, and error.h .
+ *
+ * LIBUSB version 0.1.10a is covered by the LGPL, version 2;
+ * These codes are used with permission from:
+ * (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ * (c) 2002-2005 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ * All rights reserved.
+ */
+
+#ifndef __DARWIN_LIBUSB_H__
+#define __DARWIN_LIBUSB_H__
+
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOKitLib.h>
+
+extern "C" {
+static char *
+darwin_error_str (int result)
+{
+ switch (result) {
+ case kIOReturnSuccess:
+ return "no error";
+ case kIOReturnNotOpen:
+ return "device not opened for exclusive access";
+ case kIOReturnNoDevice:
+ return "no connection to an IOService";
+ case kIOUSBNoAsyncPortErr:
+ return "no asyc port has been opened for interface";
+ case kIOReturnExclusiveAccess:
+ return "another process has device opened for exclusive access";
+ case kIOUSBPipeStalled:
+ return "pipe is stalled";
+ case kIOReturnError:
+ return "could not establish a connection to Darin kernel";
+ case kIOReturnBadArgument:
+ return "invalid argument";
+ default:
+ return "unknown error";
+ }
+}
+
+/* not a valid errorno outside darwin.c */
+#define LUSBDARWINSTALL (ELAST+1)
+
+static int
+darwin_to_errno (int result)
+{
+ switch (result) {
+ case kIOReturnSuccess:
+ return 0;
+ case kIOReturnNotOpen:
+ return EBADF;
+ case kIOReturnNoDevice:
+ case kIOUSBNoAsyncPortErr:
+ return ENXIO;
+ case kIOReturnExclusiveAccess:
+ return EBUSY;
+ case kIOUSBPipeStalled:
+ return LUSBDARWINSTALL;
+ case kIOReturnBadArgument:
+ return EINVAL;
+ case kIOReturnError:
+ default:
+ return 1;
+ }
+}
+
+typedef enum {
+ USB_ERROR_TYPE_NONE = 0,
+ USB_ERROR_TYPE_STRING,
+ USB_ERROR_TYPE_ERRNO,
+} usb_error_type_t;
+
+extern char usb_error_str[1024];
+extern int usb_error_errno;
+extern usb_error_type_t usb_error_type;
+
+#define USB_ERROR(r, x) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_ERRNO; \
+ usb_error_errno = x; \
+ return r; \
+ } while (0)
+
+#define USB_ERROR_STR(r, x, format, args...) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_STRING; \
+ snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+ if (usb_debug) \
+ fprintf(stderr, "USB error: %s\n", usb_error_str); \
+ return r; \
+ } while (0)
+
+#define USB_ERROR_STR_ORIG(x, format, args...) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_STRING; \
+ snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+ if (usb_debug) \
+ fprintf(stderr, "USB error: %s\n", usb_error_str); \
+ return x; \
+ } while (0)
+
+#define USB_ERROR_STR_NO_RET(x, format, args...) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_STRING; \
+ snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+ if (usb_debug) \
+ fprintf(stderr, "USB error: %s\n", usb_error_str); \
+ } while (0)
+
+/* simple function that figures out what pipeRef is associated with an endpoint */
+static int ep_to_pipeRef (darwin_dev_handle *device, int ep)
+{
+ io_return_t ret;
+ UInt8 numep, direction, number;
+ UInt8 dont_care1, dont_care3;
+ UInt16 dont_care2;
+ int i;
+
+ if (usb_debug > 3)
+ fprintf(stderr, "Converting ep address to pipeRef.\n");
+
+ /* retrieve the total number of endpoints on this interface */
+ ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep);
+ if ( ret ) {
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "ep_to_pipeRef: interface is %p\n", device->interface );
+ USB_ERROR_STR_ORIG ( -ret, "ep_to_pipeRef: can't get number of endpoints for interface" );
+ }
+
+ /* iterate through the pipeRefs until we find the correct one */
+ for (i = 1 ; i <= numep ; i++) {
+ ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number,
+ &dont_care1, &dont_care2, &dont_care3);
+
+ if (ret != kIOReturnSuccess) {
+ fprintf (stderr, "ep_to_pipeRef: an error occurred getting pipe information on pipe %d\n",
+ i );
+ USB_ERROR_STR_ORIG (-darwin_to_errno(ret), "ep_to_pipeRef(GetPipeProperties): %s", darwin_error_str(ret));
+ }
+
+ if (usb_debug > 3)
+ fprintf (stderr, "ep_to_pipeRef: Pipe %i: DIR: %i number: %i\n", i, direction, number);
+
+ /* calculate the endpoint of the pipe and check it versus the requested endpoint */
+ if ( ((direction << 7 & USB_ENDPOINT_DIR_MASK) | (number & USB_ENDPOINT_ADDRESS_MASK)) == ep ) {
+ if (usb_debug > 3)
+ fprintf(stderr, "ep_to_pipeRef: pipeRef for ep address 0x%02x found: 0x%02x\n", ep, i);
+
+ return i;
+ }
+ }
+
+ if (usb_debug > 3)
+ fprintf(stderr, "ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep);
+
+ /* none of the found pipes match the requested endpoint */
+ return -1;
+}
+
+}
+#endif /* __DARWIN_LIBUSB_H__ */
diff --git a/usrp/host/lib/dump_data.py b/usrp/host/lib/dump_data.py
new file mode 100755
index 000000000..fea0b9de6
--- /dev/null
+++ b/usrp/host/lib/dump_data.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# Copyright 2003 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 struct
+
+fin = sys.stdin
+
+count = 0
+
+while 1:
+ s = fin.read(2)
+ if not s or len(s) != 2:
+ break
+
+ v, = struct.unpack ('H', s)
+ iv = int(v) & 0xffff
+ print "%8d %6d 0x%04x" % (count, iv, iv)
+ count += 1
+
+
+
diff --git a/usrp/host/lib/dxc-io-assignments.gnumeric b/usrp/host/lib/dxc-io-assignments.gnumeric
new file mode 100644
index 000000000..85e1a8817
--- /dev/null
+++ b/usrp/host/lib/dxc-io-assignments.gnumeric
Binary files differ
diff --git a/usrp/host/lib/fusb.cc b/usrp/host/lib/fusb.cc
new file mode 100644
index 000000000..ef32cd8d3
--- /dev/null
+++ b/usrp/host/lib/fusb.cc
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 <fusb.h>
+
+
+// ------------------------------------------------------------------------
+// device handle
+// ------------------------------------------------------------------------
+
+fusb_devhandle::fusb_devhandle (usb_dev_handle *udh)
+ : d_udh (udh)
+{
+ // that's it
+};
+
+fusb_devhandle::~fusb_devhandle ()
+{
+ // nop
+}
+
+// ------------------------------------------------------------------------
+// end point handle
+// ------------------------------------------------------------------------
+
+fusb_ephandle::fusb_ephandle (int endpoint, bool input_p,
+ int block_size, int nblocks)
+ : d_endpoint (endpoint), d_input_p (input_p),
+ d_block_size (block_size), d_nblocks (nblocks), d_started (false)
+{
+ // that't it
+}
+
+fusb_ephandle::~fusb_ephandle ()
+{
+ // nop
+}
diff --git a/usrp/host/lib/fusb.h b/usrp/host/lib/fusb.h
new file mode 100644
index 000000000..5a902278a
--- /dev/null
+++ b/usrp/host/lib/fusb.h
@@ -0,0 +1,128 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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.
+ */
+
+// Fast USB interface
+
+#ifndef _FUSB_H_
+#define _FUSB_H_
+
+
+struct usb_dev_handle;
+class fusb_ephandle;
+
+/*!
+ * \brief abstract usb device handle
+ */
+class fusb_devhandle {
+private:
+ // NOT IMPLEMENTED
+ fusb_devhandle (const fusb_devhandle &rhs); // no copy constructor
+ fusb_devhandle &operator= (const fusb_devhandle &rhs); // no assignment operator
+
+protected:
+ usb_dev_handle *d_udh;
+
+public:
+ // CREATORS
+ fusb_devhandle (usb_dev_handle *udh);
+ virtual ~fusb_devhandle ();
+
+ // MANIPULATORS
+
+ /*!
+ * \brief return an ephandle of the correct subtype
+ */
+ virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0) = 0;
+
+ // ACCESSORS
+ usb_dev_handle *get_usb_dev_handle () const { return d_udh; }
+};
+
+
+/*!
+ * \brief abstract usb end point handle
+ */
+class fusb_ephandle {
+private:
+ // NOT IMPLEMENTED
+ fusb_ephandle (const fusb_ephandle &rhs); // no copy constructor
+ fusb_ephandle &operator= (const fusb_ephandle &rhs); // no assignment operator
+
+protected:
+ int d_endpoint;
+ bool d_input_p;
+ int d_block_size;
+ int d_nblocks;
+ bool d_started;
+
+public:
+ fusb_ephandle (int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+ virtual ~fusb_ephandle ();
+
+ virtual bool start () = 0; //!< begin streaming i/o
+ virtual bool stop () = 0; //!< stop streaming i/o
+
+ /*!
+ * \returns \p nbytes if write was successfully enqueued, else -1.
+ * Will block if no free buffers available.
+ */
+ virtual int write (const void *buffer, int nbytes) = 0;
+
+ /*!
+ * \returns number of bytes read or -1 if error.
+ * number of bytes read will be <= nbytes.
+ * Will block if no input available.
+ */
+ virtual int read (void *buffer, int nbytes) = 0;
+
+ /*
+ * block until all outstanding writes have completed
+ */
+ virtual void wait_for_completion () = 0;
+
+ /*!
+ * \brief returns current block size.
+ */
+ int block_size () { return d_block_size; };
+};
+
+
+/*!
+ * \brief factory for creating concrete instances of the appropriate subtype.
+ */
+class fusb_sysconfig {
+public:
+ /*!
+ * \brief returns fusb_devhandle or throws if trouble
+ */
+ static fusb_devhandle *make_devhandle (usb_dev_handle *udh);
+
+ /*!
+ * \brief returns max block size hard limit
+ */
+ static int max_block_size ();
+
+};
+
+#endif /* _FUSB_H_ */
diff --git a/usrp/host/lib/fusb_darwin.cc b/usrp/host/lib/fusb_darwin.cc
new file mode 100644
index 000000000..081e98111
--- /dev/null
+++ b/usrp/host/lib/fusb_darwin.cc
@@ -0,0 +1,499 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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
+
+// tell mld_threads to NOT use omni_threads,
+// but rather Darwin's pthreads
+#undef _USE_OMNI_THREADS_
+
+#include <usb.h>
+#include "fusb.h"
+#include "fusb_darwin.h"
+#include "darwin_libusb.h"
+
+static const int USB_TIMEOUT = 100; // in milliseconds
+static const UInt8 NUM_QUEUE_ITEMS = 20;
+
+fusb_devhandle_darwin::fusb_devhandle_darwin (usb_dev_handle* udh)
+ : fusb_devhandle (udh)
+{
+ // that's it
+}
+
+fusb_devhandle_darwin::~fusb_devhandle_darwin ()
+{
+ // nop
+}
+
+fusb_ephandle*
+fusb_devhandle_darwin::make_ephandle (int endpoint, bool input_p,
+ int block_size, int nblocks)
+{
+ return new fusb_ephandle_darwin (this, endpoint, input_p,
+ block_size, nblocks);
+}
+
+// ----------------------------------------------------------------
+
+fusb_ephandle_darwin::fusb_ephandle_darwin (fusb_devhandle_darwin* dh,
+ int endpoint, bool input_p,
+ int block_size, int nblocks)
+ : fusb_ephandle (endpoint, input_p, block_size, nblocks),
+ d_devhandle (dh), d_pipeRef (0), d_transferType (0),
+ d_interfaceRef (0), d_interface (0), d_queue (0),
+ d_buffer (0), d_bufLenBytes (0)
+{
+ d_bufLenBytes = fusb_sysconfig::max_block_size();
+
+// create circular buffer
+ d_buffer = new circular_buffer<char> (NUM_QUEUE_ITEMS * d_bufLenBytes,
+ !d_input_p, d_input_p);
+
+// create the queue
+ d_queue = new circular_linked_list <s_buffer_ptr> (NUM_QUEUE_ITEMS);
+ d_queue->iterate_start ();
+ s_node_ptr l_node = d_queue->iterate_next ();
+ while (l_node) {
+ l_node->both (new s_both<s_buffer_ptr> (l_node, this));
+ s_buffer_ptr l_buf = new s_buffer (d_bufLenBytes);
+ l_node->object (l_buf);
+ l_node = d_queue->iterate_next ();
+ l_buf = NULL;
+ }
+
+ d_readRunning = new mld_mutex ();
+ d_runThreadRunning = new mld_mutex ();
+ d_runBlock = new mld_condition ();
+ d_readBlock = new mld_condition ();
+}
+
+fusb_ephandle_darwin::~fusb_ephandle_darwin ()
+{
+ stop ();
+
+ d_queue->iterate_start ();
+ s_node_ptr l_node = d_queue->iterate_next ();
+ while (l_node) {
+ s_both_ptr l_both = l_node->both ();
+ delete l_both;
+ l_both = NULL;
+ l_node->both (NULL);
+ s_buffer_ptr l_buf = l_node->object ();
+ delete l_buf;
+ l_buf = NULL;
+ l_node->object (NULL);
+ l_node = d_queue->iterate_next ();
+ }
+ delete d_queue;
+ d_queue = NULL;
+ delete d_buffer;
+ d_buffer = NULL;
+ delete d_readRunning;
+ d_readRunning = NULL;
+ delete d_runThreadRunning;
+ d_runThreadRunning = NULL;
+ delete d_runBlock;
+ d_runBlock = NULL;
+ delete d_readBlock;
+ d_readBlock = NULL;
+}
+
+bool
+fusb_ephandle_darwin::start ()
+{
+ UInt8 direction, number, interval;
+ UInt16 maxPacketSize;
+
+// reset circular buffer
+ d_buffer->reset ();
+
+// reset the queue
+ d_queue->num_used (0);
+ d_queue->iterate_start ();
+ s_node_ptr l_node = d_queue->iterate_next ();
+ while (l_node) {
+ l_node->both()->set (l_node, this);
+ l_node->object()->reset ();
+ l_node->set_available ();
+ l_node = d_queue->iterate_next ();
+ }
+
+ d_pipeRef = d_transferType = 0;
+
+ usb_dev_handle* dev = d_devhandle->get_usb_dev_handle ();
+ if (! dev)
+ USB_ERROR_STR (false, -ENXIO, "fusb_ephandle_darwin::start: "
+ "null device");
+
+ darwin_dev_handle* device = (darwin_dev_handle*) dev->impl_info;
+ if (! device)
+ USB_ERROR_STR (false, -ENOENT, "fusb_ephandle_darwin::start: "
+ "device not initialized");
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::start: "
+ "dev = %p, device = %p\n", dev, device);
+
+ d_interfaceRef = device->interface;
+ if (! d_interfaceRef)
+ USB_ERROR_STR (false, -EACCES, "fusb_ephandle_darwin::start: "
+ "interface used without being claimed");
+ d_interface = *d_interfaceRef;
+
+// get read or write pipe info (depends on "d_input_p")
+
+ if (usb_debug > 3)
+ fprintf (stderr, "fusb_ephandle_darwin::start "
+ "d_endpoint = %d, d_input_p = %s\n",
+ d_endpoint, d_input_p ? "TRUE" : "FALSE");
+
+ int l_endpoint = (d_input_p ? USB_ENDPOINT_IN : USB_ENDPOINT_OUT);
+ int pipeRef = ep_to_pipeRef (device, d_endpoint | l_endpoint);
+ if (pipeRef < 0)
+ USB_ERROR_STR (false, -EINVAL, "fusb_ephandle_darwin::start "
+ " invalid pipeRef.\n");
+
+ d_pipeRef = pipeRef;
+ d_interface->GetPipeProperties (d_interfaceRef,
+ d_pipeRef,
+ &direction,
+ &number,
+ &d_transferType,
+ &maxPacketSize,
+ &interval);
+ if (usb_debug == 3)
+ fprintf (stderr, "fusb_ephandle_darwin::start: %s: ep = 0x%02x, "
+ "pipeRef = %d, d_i = %p, d_iR = %p, if_dir = %d, if_# = %d, "
+ "if_int = %d, if_maxPS = %d\n", d_input_p ? "read" : "write",
+ d_endpoint, d_pipeRef, d_interface, d_interfaceRef, direction,
+ number, interval, maxPacketSize);
+
+// set global start boolean
+ d_started = true;
+
+// create the run thread, which allows OSX to process I/O separately
+ d_runThread = new mld_thread (run_thread, this);
+
+// wait until the threads are -really- going
+ d_runBlock->wait ();
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::start: %s started.\n",
+ d_input_p ? "read" : "write");
+
+ return (true);
+}
+
+void
+fusb_ephandle_darwin::run_thread (void* arg)
+{
+ fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
+ mld_mutex_ptr l_runThreadRunning = This->d_runThreadRunning;
+ l_runThreadRunning->lock ();
+
+ mld_mutex_ptr l_readRunning = This->d_readRunning;
+ mld_condition_ptr l_readBlock = This->d_readBlock;
+
+ bool l_input_p = This->d_input_p;
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::run_thread: "
+ "starting for %s.\n",
+ l_input_p ? "read" : "write");
+
+ usb_interface_t** l_interfaceRef = This->d_interfaceRef;
+ usb_interface_t* l_interface = This->d_interface;
+ CFRunLoopSourceRef l_cfSource;
+
+// create async run loop
+ l_interface->CreateInterfaceAsyncEventSource (l_interfaceRef, &l_cfSource);
+ CFRunLoopAddSource (CFRunLoopGetCurrent (), l_cfSource,
+ kCFRunLoopDefaultMode);
+// get run loop reference, to allow other threads to stop
+ This->d_CFRunLoopRef = CFRunLoopGetCurrent ();
+
+ mld_thread_ptr l_rwThread = NULL;
+
+ if (l_input_p) {
+ l_rwThread = new mld_thread (read_thread, arg);
+// wait until the the rwThread is -really- going
+ l_readBlock->wait ();
+ }
+
+// now signal the run condition to release and finish ::start()
+ This->d_runBlock->signal ();
+
+// run the loop
+ CFRunLoopRun ();
+
+ if (l_input_p) {
+// wait for read_thread () to finish
+ l_readRunning->lock ();
+ l_readRunning->unlock ();
+ }
+
+// remove run loop stuff
+ CFRunLoopRemoveSource (CFRunLoopGetCurrent (),
+ l_cfSource, kCFRunLoopDefaultMode);
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::run_thread: finished for %s.\n",
+ l_input_p ? "read" : "write");
+
+ l_runThreadRunning->unlock ();
+}
+
+void
+fusb_ephandle_darwin::read_thread (void* arg)
+{
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::read_thread: starting.\n");
+
+ fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(arg);
+
+ mld_mutex_ptr l_readRunning = This->d_readRunning;
+ l_readRunning->lock ();
+
+// signal the read condition from run_thread() to continue
+ mld_condition_ptr l_readBlock = This->d_readBlock;
+ l_readBlock->signal ();
+
+ s_queue_ptr l_queue = This->d_queue;
+ l_queue->iterate_start ();
+ s_node_ptr l_node = l_queue->iterate_next ();
+ while (l_node) {
+ This->read_issue (l_node->both ());
+ l_node = l_queue->iterate_next ();
+ }
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::read_thread: finished.\n");
+
+ l_readRunning->unlock ();
+}
+
+void
+fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
+{
+ if ((! l_both) || (! d_started))
+ return;
+
+// set the node and buffer from the input "both"
+ s_node_ptr l_node = l_both->node ();
+ s_buffer_ptr l_buf = l_node->object ();
+ void* v_buffer = (void*) l_buf->buffer ();
+
+// read up to d_bufLenBytes
+ UInt32 bufLen = d_bufLenBytes;
+ l_buf->n_used (bufLen);
+
+// setup system call result
+ io_return_t result = kIOReturnSuccess;
+
+ if (d_transferType == kUSBInterrupt)
+/* This is an interrupt pipe. We can't specify a timeout. */
+ result = d_interface->ReadPipeAsync
+ (d_interfaceRef, d_pipeRef, v_buffer, bufLen,
+ (IOAsyncCallback1) read_completed, (void*) l_both);
+ else
+ result = d_interface->ReadPipeAsyncTO
+ (d_interfaceRef, d_pipeRef, v_buffer, bufLen, 0, USB_TIMEOUT,
+ (IOAsyncCallback1) read_completed, (void*) l_both);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
+ "fusb_ephandle_darwin::read_issue "
+ "(ReadPipeAsync%s): %s",
+ d_transferType == kUSBInterrupt ? "" : "TO",
+ darwin_error_str (result));
+}
+
+void
+fusb_ephandle_darwin::read_completed (void* refCon,
+ io_return_t result,
+ void* io_size)
+{
+ UInt32 l_size = (UInt32) io_size;
+ s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
+ fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
+ s_node_ptr l_node = l_both->node ();
+ circular_buffer<char>* l_buffer = This->d_buffer;
+ s_buffer_ptr l_buf = l_node->object ();
+ UInt32 l_i_size = l_buf->n_used ();
+
+ if (This->d_started && (l_i_size != l_size))
+ fprintf (stderr, "fusb_ephandle_darwin::read_completed: "
+ "Expected %ld bytes; read %ld.\n",
+ l_i_size, l_size);
+
+// add this read to the transfer buffer
+ if (l_buffer->enqueue (l_buf->buffer (), l_size) == -1) {
+ fputs ("iU", stderr);
+ fflush (stderr);
+ }
+
+// set buffer's # data to 0
+ l_buf->n_used (0);
+
+// issue another read for this "both"
+ This->read_issue (l_both);
+}
+
+int
+fusb_ephandle_darwin::read (void* buffer, int nbytes)
+{
+ UInt32 l_nbytes = (UInt32) nbytes;
+ d_buffer->dequeue ((char*) buffer, &l_nbytes);
+ return ((int) l_nbytes);
+}
+
+int
+fusb_ephandle_darwin::write (const void* buffer, int nbytes)
+{
+ UInt32 l_nbytes = (UInt32) nbytes;
+
+ if (! d_started) return (0);
+
+ while (l_nbytes != 0) {
+// find out how much data to copy; limited to "d_bufLenBytes" per node
+ UInt32 t_nbytes = (l_nbytes > d_bufLenBytes) ? d_bufLenBytes : l_nbytes;
+
+// get next available node to write into;
+// blocks internally if none available
+ s_node_ptr l_node = d_queue->find_next_available_node ();
+
+// copy the input into the node's buffer
+ s_buffer_ptr l_buf = l_node->object ();
+ l_buf->buffer ((char*) buffer, t_nbytes);
+ void* v_buffer = (void*) l_buf->buffer ();
+
+// setup callback parameter & system call return
+ s_both_ptr l_both = l_node->both ();
+ io_return_t result = kIOReturnSuccess;
+
+ if (d_transferType == kUSBInterrupt)
+/* This is an interrupt pipe ... can't specify a timeout. */
+ result = d_interface->WritePipeAsync
+ (d_interfaceRef, d_pipeRef, v_buffer, l_nbytes,
+ (IOAsyncCallback1) write_completed, (void*) l_both);
+ else
+ result = d_interface->WritePipeAsyncTO
+ (d_interfaceRef, d_pipeRef, v_buffer, l_nbytes, 0, USB_TIMEOUT,
+ (IOAsyncCallback1) write_completed, (void*) l_both);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-1, - darwin_to_errno (result),
+ "fusb_ephandle_darwin::write_thread "
+ "(WritePipeAsync%s): %s",
+ d_transferType == kUSBInterrupt ? "" : "TO",
+ darwin_error_str (result));
+ l_nbytes -= t_nbytes;
+ }
+
+ return (nbytes);
+}
+
+void
+fusb_ephandle_darwin::write_completed (void* refCon,
+ io_return_t result,
+ void* io_size)
+{
+ s_both_ptr l_both = static_cast<s_both_ptr>(refCon);
+ fusb_ephandle_darwin* This = static_cast<fusb_ephandle_darwin*>(l_both->This ());
+ UInt32 l_size = (UInt32) io_size;
+ s_node_ptr l_node = l_both->node ();
+ s_queue_ptr l_queue = This->d_queue;
+ s_buffer_ptr l_buf = l_node->object ();
+ UInt32 l_i_size = l_buf->n_used ();
+
+ if (This->d_started && (l_i_size != l_size))
+ fprintf (stderr, "fusb_ephandle_darwin::write_completed: "
+ "Expected %ld bytes written; wrote %ld.\n",
+ l_i_size, l_size);
+
+// set buffer's # data to 0
+ l_buf->n_used (0);
+// make the node available for reuse
+ l_queue->make_node_available (l_node);
+}
+
+void
+fusb_ephandle_darwin::abort ()
+{
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::abort: starting.\n");
+
+ io_return_t result = d_interface->AbortPipe (d_interfaceRef, d_pipeRef);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR_NO_RET (- darwin_to_errno (result),
+ "fusb_ephandle_darwin::abort "
+ "(AbortPipe): %s", darwin_error_str (result));
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::abort: finished.\n");
+}
+
+bool
+fusb_ephandle_darwin::stop ()
+{
+ if (! d_started)
+ return (true);
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::stop: stopping %s.\n",
+ d_input_p ? "read" : "write");
+
+ d_started = false;
+
+// abort any pending IO transfers
+ abort ();
+
+// wait for write transfer to finish
+ wait_for_completion ();
+
+// tell IO buffer to abort any waiting conditions
+ d_buffer->abort ();
+
+// stop the run loop
+ CFRunLoopStop (d_CFRunLoopRef);
+
+// wait for the runThread to stop
+ d_runThreadRunning->lock ();
+ d_runThreadRunning->unlock ();
+
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::stop: %s stopped.\n",
+ d_input_p ? "read" : "write");
+
+ return (true);
+}
+
+void
+fusb_ephandle_darwin::wait_for_completion ()
+{
+ if (d_queue)
+ while (d_queue->in_use ())
+ usleep (1000);
+}
diff --git a/usrp/host/lib/fusb_darwin.h b/usrp/host/lib/fusb_darwin.h
new file mode 100644
index 000000000..601f39abb
--- /dev/null
+++ b/usrp/host/lib/fusb_darwin.h
@@ -0,0 +1,215 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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 _FUSB_DARWIN_H_
+#define _FUSB_DARWIN_H_
+
+#include <usb.h>
+#include "fusb.h"
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOKitLib.h>
+#include "circular_linked_list.h"
+#include "circular_buffer.h"
+
+// for MacOS X 10.4.[0-3]
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+// for MacOS X 10.3.[0-9] and 10.4.[0-3]
+#define usb_device_t IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+extern "C" {
+typedef struct usb_dev_handle {
+ int fd;
+
+ struct usb_bus *bus;
+ struct usb_device *device;
+
+ int config;
+ int interface;
+ int altsetting;
+
+ /* Added by RMT so implementations can store other per-open-device data */
+ void *impl_info;
+} usb_dev_handle;
+
+/* Darwin/OS X impl does not use fd field, instead it uses this */
+typedef struct darwin_dev_handle {
+ usb_device_t** device;
+ usb_interface_t** interface;
+ int open;
+} darwin_dev_handle;
+
+typedef IOReturn io_return_t;
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+
+static int ep_to_pipeRef (darwin_dev_handle* device, int ep);
+extern int usb_debug;
+}
+
+class s_buffer
+{
+private:
+ char* d_buffer;
+ UInt32 d_n_used, d_n_alloc;
+
+public:
+ inline s_buffer (UInt32 n_alloc = 0) {
+ d_n_used = 0;
+ d_n_alloc = n_alloc;
+ if (n_alloc) {
+ d_buffer = (char*) new char [n_alloc];
+ } else {
+ d_buffer = 0;
+ }
+ };
+ inline ~s_buffer () {
+ if (d_n_alloc) {
+ delete [] d_buffer;
+ }
+ };
+ inline UInt32 n_used () { return (d_n_used); };
+ inline void n_used (UInt32 bufLen) {
+ d_n_used = (bufLen > d_n_alloc) ? d_n_alloc : bufLen; };
+ inline UInt32 n_alloc () { return (d_n_alloc); };
+ void buffer (char* l_buffer, UInt32 bufLen) {
+ if (bufLen > d_n_alloc) {
+ fprintf (stderr, "s_buffer::set: Copying only allocated bytes.\n");
+ bufLen = d_n_alloc;
+ }
+ if (!l_buffer) {
+ fprintf (stderr, "s_buffer::set: NULL buffer.\n");
+ return;
+ }
+ bcopy (l_buffer, d_buffer, bufLen);
+ d_n_used = bufLen;
+ };
+ inline char* buffer () { return (d_buffer); };
+ inline void reset () {
+ bzero (d_buffer, d_n_alloc);
+ d_n_used = 0;
+ };
+};
+
+typedef s_buffer* s_buffer_ptr;
+typedef s_node<s_buffer_ptr>* s_node_ptr;
+typedef circular_linked_list<s_buffer_ptr>* s_queue_ptr;
+typedef s_both<s_buffer_ptr>* s_both_ptr;
+
+/*!
+ * \brief darwin implementation of fusb_devhandle
+ *
+ * This is currently identical to the generic implementation
+ * and is intended as a starting point for whatever magic is
+ * required to make usb fly.
+ */
+class fusb_devhandle_darwin : public fusb_devhandle
+{
+public:
+ // CREATORS
+ fusb_devhandle_darwin (usb_dev_handle* udh);
+ virtual ~fusb_devhandle_darwin ();
+
+ // MANIPULATORS
+ virtual fusb_ephandle* make_ephandle (int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+};
+
+/*!
+ * \brief darwin implementation of fusb_ephandle
+ *
+ * This is currently identical to the generic implementation
+ * and is intended as a starting point for whatever magic is
+ * required to make usb fly.
+ */
+class fusb_ephandle_darwin : public fusb_ephandle
+{
+private:
+ fusb_devhandle_darwin* d_devhandle;
+ mld_thread_ptr d_runThread;
+ mld_mutex_ptr d_runThreadRunning;
+
+ CFRunLoopRef d_CFRunLoopRef;
+
+ static void write_completed (void* ret_io_size,
+ io_return_t result,
+ void* io_size);
+ static void read_completed (void* ret_io_size,
+ io_return_t result,
+ void* io_size);
+ static void run_thread (void* arg);
+ static void read_thread (void* arg);
+
+ void read_issue (s_both_ptr l_both);
+
+public:
+ // variables, for now
+ UInt8 d_pipeRef, d_transferType;
+ usb_interface_t** d_interfaceRef;
+ usb_interface_t* d_interface;
+ s_queue_ptr d_queue;
+ circular_buffer<char>* d_buffer;
+ UInt32 d_bufLenBytes;
+ mld_mutex_ptr d_readRunning;
+ mld_condition_ptr d_runBlock, d_readBlock;
+
+// CREATORS
+
+ fusb_ephandle_darwin (fusb_devhandle_darwin *dh, int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+ virtual ~fusb_ephandle_darwin ();
+
+// MANIPULATORS
+
+ virtual bool start (); //!< begin streaming i/o
+ virtual bool stop (); //!< stop streaming i/o
+
+ /*!
+ * \returns \p nbytes if write was successfully enqueued, else -1.
+ * Will block if no free buffers available.
+ */
+ virtual int write (const void* buffer, int nbytes);
+
+ /*!
+ * \returns number of bytes read or -1 if error.
+ * number of bytes read will be <= nbytes.
+ * Will block if no input available.
+ */
+ virtual int read (void* buffer, int nbytes);
+
+ /*
+ * abort any pending IO transfers
+ */
+ void abort ();
+
+ /*
+ * block until all outstanding writes have completed
+ */
+ virtual void wait_for_completion ();
+};
+
+#endif /* _FUSB_DARWIN_H_ */
diff --git a/usrp/host/lib/fusb_generic.cc b/usrp/host/lib/fusb_generic.cc
new file mode 100644
index 000000000..001363222
--- /dev/null
+++ b/usrp/host/lib/fusb_generic.cc
@@ -0,0 +1,108 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 <fusb_generic.h>
+#include <usb.h>
+
+
+static const int USB_TIMEOUT = 1000; // in milliseconds
+
+
+fusb_devhandle_generic::fusb_devhandle_generic (usb_dev_handle *udh)
+ : fusb_devhandle (udh)
+{
+ // that's it
+}
+
+fusb_devhandle_generic::~fusb_devhandle_generic ()
+{
+ // nop
+}
+
+fusb_ephandle *
+fusb_devhandle_generic::make_ephandle (int endpoint, bool input_p,
+ int block_size, int nblocks)
+{
+ return new fusb_ephandle_generic (this, endpoint, input_p,
+ block_size, nblocks);
+}
+
+// ----------------------------------------------------------------
+
+fusb_ephandle_generic::fusb_ephandle_generic (fusb_devhandle_generic *dh,
+ int endpoint, bool input_p,
+ int block_size, int nblocks)
+ : fusb_ephandle (endpoint, input_p, block_size, nblocks),
+ d_devhandle (dh)
+{
+ // that's it
+}
+
+fusb_ephandle_generic::~fusb_ephandle_generic ()
+{
+ // nop
+}
+
+bool
+fusb_ephandle_generic::start ()
+{
+ d_started = true;
+ return true;
+}
+
+bool
+fusb_ephandle_generic::stop ()
+{
+ d_started = false;
+ return true;
+}
+
+int
+fusb_ephandle_generic::write (const void *buffer, int nbytes)
+{
+ if (!d_started) // doesn't matter here, but keeps semantics constant
+ return -1;
+
+ if (d_input_p)
+ return -1;
+
+ return usb_bulk_write (d_devhandle->get_usb_dev_handle (),
+ d_endpoint, (char *) buffer, nbytes, USB_TIMEOUT);
+}
+
+int
+fusb_ephandle_generic::read (void *buffer, int nbytes)
+{
+ if (!d_started) // doesn't matter here, but keeps semantics constant
+ return -1;
+
+ if (!d_input_p)
+ return -1;
+
+ return usb_bulk_read (d_devhandle->get_usb_dev_handle (),
+ d_endpoint|USB_ENDPOINT_IN, (char *) buffer, nbytes,
+ USB_TIMEOUT);
+}
diff --git a/usrp/host/lib/fusb_generic.h b/usrp/host/lib/fusb_generic.h
new file mode 100644
index 000000000..93ae77fdf
--- /dev/null
+++ b/usrp/host/lib/fusb_generic.h
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 _FUSB_GENERIC_H_
+#define _FUSB_GENERIC_H_
+
+#include <fusb.h>
+
+/*!
+ * \brief generic implementation of fusb_devhandle using only libusb
+ */
+class fusb_devhandle_generic : public fusb_devhandle
+{
+public:
+ // CREATORS
+ fusb_devhandle_generic (usb_dev_handle *udh);
+ virtual ~fusb_devhandle_generic ();
+
+ // MANIPULATORS
+ virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+};
+
+
+/*!
+ * \brief generic implementation of fusb_ephandle using only libusb
+ */
+class fusb_ephandle_generic : public fusb_ephandle
+{
+private:
+ fusb_devhandle_generic *d_devhandle;
+
+public:
+ // CREATORS
+ fusb_ephandle_generic (fusb_devhandle_generic *dh, int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+ virtual ~fusb_ephandle_generic ();
+
+ // MANIPULATORS
+
+ virtual bool start (); //!< begin streaming i/o
+ virtual bool stop (); //!< stop streaming i/o
+
+ /*!
+ * \returns \p nbytes if write was successfully enqueued, else -1.
+ * Will block if no free buffers available.
+ */
+ virtual int write (const void *buffer, int nbytes);
+
+ /*!
+ * \returns number of bytes read or -1 if error.
+ * number of bytes read will be <= nbytes.
+ * Will block if no input available.
+ */
+ virtual int read (void *buffer, int nbytes);
+
+ /*
+ * block until all outstanding writes have completed
+ */
+ virtual void wait_for_completion () { };
+};
+
+#endif /* _FUSB_GENERIC_H_ */
+
diff --git a/usrp/host/lib/fusb_linux.cc b/usrp/host/lib/fusb_linux.cc
new file mode 100644
index 000000000..2fe244f1a
--- /dev/null
+++ b/usrp/host/lib/fusb_linux.cc
@@ -0,0 +1,684 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 <fusb_linux.h>
+#include <usb.h> // libusb header
+#include <stdexcept>
+#include <linux/compiler.h>
+#include <linux/usbdevice_fs.h> // interface to kernel portion of user mode usb driver
+#include <sys/ioctl.h>
+#include <assert.h>
+#include <string.h>
+#include <algorithm>
+#include <errno.h>
+#include <string.h>
+
+#define MINIMIZE_TX_BUFFERING 1 // must be defined to 0 or 1
+
+
+static const int MAX_BLOCK_SIZE = fusb_sysconfig::max_block_size(); // hard limit
+static const int DEFAULT_BLOCK_SIZE = MAX_BLOCK_SIZE;
+static const int DEFAULT_BUFFER_SIZE = 4 * (1L << 20); // 4 MB / endpoint
+
+
+// Totally evil and fragile extraction of file descriptor from
+// guts of libusb. They don't install usbi.h, which is what we'd need
+// to do this nicely.
+//
+// FIXME if everything breaks someday in the future, look here...
+
+static int
+fd_from_usb_dev_handle (usb_dev_handle *udh)
+{
+ return *((int *) udh);
+}
+
+inline static void
+urb_set_ephandle (usbdevfs_urb *urb, fusb_ephandle_linux *handle)
+{
+ urb->usercontext = handle;
+}
+
+inline static fusb_ephandle_linux *
+urb_get_ephandle (usbdevfs_urb *urb)
+{
+ return (fusb_ephandle_linux *) urb->usercontext;
+}
+
+// ------------------------------------------------------------------------
+// USB request block (urb) allocation
+// ------------------------------------------------------------------------
+
+static usbdevfs_urb *
+alloc_urb (fusb_ephandle_linux *self, int buffer_length, int endpoint,
+ bool input_p, unsigned char *write_buffer)
+{
+ usbdevfs_urb *urb = new usbdevfs_urb;
+ memset (urb, 0, sizeof (*urb));
+
+ urb->buffer_length = buffer_length;
+
+ // We allocate dedicated memory only for input buffers.
+ // For output buffers we reuse the same buffer (the kernel
+ // copies the data at submital time)
+
+ if (input_p)
+ urb->buffer = new unsigned char [buffer_length];
+ else
+ urb->buffer = write_buffer;
+
+ // init common values
+
+ urb->type = USBDEVFS_URB_TYPE_BULK;
+ urb->endpoint = (endpoint & 0x7f) | (input_p ? 0x80 : 0);
+
+ // USBDEVFS_URB_QUEUE_BULK goes away in linux 2.5, but is needed if
+ // we are using a 2.4 usb-uhci host controller driver. This is
+ // unlikely since we're almost always going to be plugged into a
+ // high speed host controller (ehci)
+#if 0 && defined (USBDEVFS_URB_QUEUE_BULK)
+ urb->flags = USBDEVFS_URB_QUEUE_BULK;
+#endif
+
+ urb->signr = 0;
+ urb_set_ephandle (urb, self);
+
+ return urb;
+}
+
+static void
+free_urb (usbdevfs_urb *urb)
+{
+ // if this was an input urb, free the buffer
+ if (urb->endpoint & 0x80)
+ delete [] ((unsigned char *) urb->buffer);
+
+ delete urb;
+}
+
+// ------------------------------------------------------------------------
+// device handle
+// ------------------------------------------------------------------------
+
+fusb_devhandle_linux::fusb_devhandle_linux (usb_dev_handle *udh)
+ : fusb_devhandle (udh)
+{
+ // that's all
+}
+
+fusb_devhandle_linux::~fusb_devhandle_linux ()
+{
+ // if there are any pending requests, cancel them and free the urbs.
+
+ std::list<usbdevfs_urb*>::reverse_iterator it;
+
+ for (it = d_pending_rqsts.rbegin (); it != d_pending_rqsts.rend (); it++){
+ _cancel_urb (*it);
+ free_urb (*it);
+ }
+}
+
+fusb_ephandle *
+fusb_devhandle_linux::make_ephandle (int endpoint, bool input_p,
+ int block_size, int nblocks)
+{
+ return new fusb_ephandle_linux (this, endpoint, input_p,
+ block_size, nblocks);
+}
+
+
+// Attempt to cancel all transactions associated with eph.
+
+void
+fusb_devhandle_linux::_cancel_pending_rqsts (fusb_ephandle_linux *eph)
+{
+ std::list<usbdevfs_urb*>::reverse_iterator it;
+
+ for (it = d_pending_rqsts.rbegin (); it != d_pending_rqsts.rend (); it++){
+ if (urb_get_ephandle (*it) == eph)
+ _cancel_urb (*it);
+ }
+}
+
+void
+fusb_devhandle_linux::pending_add (usbdevfs_urb *urb)
+{
+ d_pending_rqsts.push_back (urb);
+}
+
+usbdevfs_urb *
+fusb_devhandle_linux::pending_get ()
+{
+ if (d_pending_rqsts.empty ())
+ return 0;
+
+ usbdevfs_urb *urb = d_pending_rqsts.front ();
+ d_pending_rqsts.pop_front ();
+ return urb;
+}
+
+bool
+fusb_devhandle_linux::pending_remove (usbdevfs_urb *urb)
+{
+ std::list<usbdevfs_urb*>::iterator result = find (d_pending_rqsts.begin (),
+ d_pending_rqsts.end (),
+ urb);
+ if (result == d_pending_rqsts.end ()){
+ fprintf (stderr, "fusb::pending_remove: failed to find urb in pending_rqsts: %p\n", urb);
+ return false;
+ }
+ d_pending_rqsts.erase (result);
+ return true;
+}
+
+/*
+ * Submit the urb to the kernel.
+ * iff successful, the urb will be placed on the devhandle's pending list.
+ */
+bool
+fusb_devhandle_linux::_submit_urb (usbdevfs_urb *urb)
+{
+ int ret;
+
+ ret = ioctl (fd_from_usb_dev_handle (d_udh), USBDEVFS_SUBMITURB, urb);
+ if (ret < 0){
+ perror ("fusb::_submit_urb");
+ return false;
+ }
+
+ pending_add (urb);
+ return true;
+}
+
+/*
+ * Attempt to cancel the in pending or in-progress urb transaction.
+ * Return true iff transaction was sucessfully cancelled.
+ *
+ * Failure to cancel should not be considered a problem. This frequently
+ * occurs if the transaction has already completed in the kernel but hasn't
+ * yet been reaped by the user mode code.
+ *
+ * urbs which were cancelled have their status field set to -ENOENT when
+ * they are reaped.
+ */
+bool
+fusb_devhandle_linux::_cancel_urb (usbdevfs_urb *urb)
+{
+ int ret = ioctl (fd_from_usb_dev_handle (d_udh), USBDEVFS_DISCARDURB, urb);
+ if (ret < 0){
+ // perror ("fusb::_cancel_urb");
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Check with the kernel and see if any of our outstanding requests
+ * have completed. For each completed transaction, remove it from the
+ * devhandle's pending list and append it to the completed list for
+ * the corresponding endpoint.
+ *
+ * If any transactions are reaped return true.
+ *
+ * If ok_to_block_p is true, then this will block until at least one
+ * transaction completes.
+ */
+bool
+fusb_devhandle_linux::_reap (bool ok_to_block_p)
+{
+ int ret;
+ int nreaped = 0;
+ usbdevfs_urb *urb = 0;
+
+ int fd = fd_from_usb_dev_handle (d_udh);
+
+ // try to reap as many as possible without blocking...
+
+ while ((ret = ioctl (fd, USBDEVFS_REAPURBNDELAY, &urb)) == 0){
+ if (urb->status != 0 && urb->status != -ENOENT){
+ fprintf (stderr, "_reap: usb->status = %d, actual_length = %5d\n",
+ urb->status, urb->actual_length);
+ }
+ pending_remove (urb);
+ urb_get_ephandle (urb)->completed_list_add (urb);
+ nreaped++;
+ }
+
+ if (nreaped > 0) // if we got any, return w/o blocking
+ return true;
+
+ if (!ok_to_block_p)
+ return false;
+
+ ret = ioctl (fd, USBDEVFS_REAPURB, &urb);
+ if (ret < 0){
+ perror ("fusb::_reap");
+ return false;
+ }
+
+ pending_remove (urb);
+ urb_get_ephandle (urb)->completed_list_add (urb);
+ return true;
+}
+
+void
+fusb_devhandle_linux::_wait_for_completion ()
+{
+ while (!d_pending_rqsts.empty ())
+ _reap (true);
+}
+ // ------------------------------------------------------------------------
+// end point handle
+// ------------------------------------------------------------------------
+
+fusb_ephandle_linux::fusb_ephandle_linux (fusb_devhandle_linux *devhandle,
+ int endpoint,
+ bool input_p,
+ int block_size, int nblocks)
+ : fusb_ephandle (endpoint, input_p, block_size, nblocks),
+ d_devhandle (devhandle),
+ d_write_work_in_progress (0), d_write_buffer (0),
+ d_read_work_in_progress (0), d_read_buffer (0), d_read_buffer_end (0)
+{
+
+ if (d_block_size < 0 || d_block_size > MAX_BLOCK_SIZE)
+ throw std::out_of_range ("fusb_ephandle_linux: block_size");
+
+ if (d_nblocks < 0)
+ throw std::out_of_range ("fusb_ephandle_linux: nblocks");
+
+ if (d_block_size == 0)
+ d_block_size = DEFAULT_BLOCK_SIZE;
+
+ if (d_nblocks == 0)
+ d_nblocks = std::max (1, DEFAULT_BUFFER_SIZE / d_block_size);
+
+ if (!d_input_p)
+ if (!MINIMIZE_TX_BUFFERING)
+ d_write_buffer = new unsigned char [d_block_size];
+
+ if (0)
+ fprintf(stderr, "fusb_ephandle_linux::ctor: d_block_size = %d d_nblocks = %d\n",
+ d_block_size, d_nblocks);
+
+ // allocate urbs
+
+ for (int i = 0; i < d_nblocks; i++)
+ d_free_list.push_back (alloc_urb (this, d_block_size, d_endpoint,
+ d_input_p, d_write_buffer));
+}
+
+fusb_ephandle_linux::~fusb_ephandle_linux ()
+{
+ stop ();
+
+ usbdevfs_urb *urb;
+
+ while ((urb = free_list_get ()) != 0)
+ free_urb (urb);
+
+ while ((urb = completed_list_get ()) != 0)
+ free_urb (urb);
+
+ if (d_write_work_in_progress)
+ free_urb (d_write_work_in_progress);
+
+ delete [] d_write_buffer;
+
+ if (d_read_work_in_progress)
+ free_urb (d_read_work_in_progress);
+}
+
+// ----------------------------------------------------------------
+
+bool
+fusb_ephandle_linux::start ()
+{
+ if (d_started)
+ return true; // already running
+
+ d_started = true;
+
+ if (d_input_p){ // fire off all the reads
+ usbdevfs_urb *urb;
+
+ int nerrors = 0;
+ while ((urb = free_list_get ()) != 0 && nerrors < d_nblocks){
+ if (!submit_urb (urb))
+ nerrors++;
+ }
+ }
+
+ return true;
+}
+
+//
+// kill all i/o in progress.
+// kill any completed but unprocessed transactions.
+//
+bool
+fusb_ephandle_linux::stop ()
+{
+ if (!d_started)
+ return true;
+
+ d_devhandle->_cancel_pending_rqsts (this);
+ d_devhandle->_reap (false);
+
+
+ usbdevfs_urb *urb;
+ while ((urb = completed_list_get ()) != 0)
+ free_list_add (urb);
+
+ if (d_write_work_in_progress){
+ free_list_add (d_write_work_in_progress);
+ d_write_work_in_progress = 0;
+ }
+
+ if (d_read_work_in_progress){
+ free_list_add (d_read_work_in_progress);
+ d_read_work_in_progress = 0;
+ d_read_buffer = 0;
+ d_read_buffer_end = 0;
+ }
+
+ if (d_free_list.size () != (unsigned) d_nblocks)
+ fprintf (stderr, "d_free_list.size () = %d, d_nblocks = %d\n",
+ d_free_list.size (), d_nblocks);
+
+ assert (d_free_list.size () == (unsigned) d_nblocks);
+
+ d_started = false;
+ return true;
+}
+
+// ----------------------------------------------------------------
+// routines for writing
+// ----------------------------------------------------------------
+
+#if (MINIMIZE_TX_BUFFERING)
+
+int
+fusb_ephandle_linux::write(const void *buffer, int nbytes)
+{
+ if (!d_started)
+ return -1;
+
+ if (d_input_p)
+ return -1;
+
+ assert(nbytes % 512 == 0);
+
+ unsigned char *src = (unsigned char *) buffer;
+
+ int n = 0;
+ while (n < nbytes){
+
+ usbdevfs_urb *urb = get_write_work_in_progress();
+ assert(urb->actual_length == 0);
+ int m = std::min(nbytes - n, MAX_BLOCK_SIZE);
+ urb->buffer = src;
+ urb->buffer_length = m;
+
+ n += m;
+ src += m;
+
+ if (!submit_urb(urb))
+ return -1;
+
+ d_write_work_in_progress = 0;
+ }
+
+ return n;
+}
+
+#else
+
+int
+fusb_ephandle_linux::write (const void *buffer, int nbytes)
+{
+ if (!d_started)
+ return -1;
+
+ if (d_input_p)
+ return -1;
+
+ unsigned char *src = (unsigned char *) buffer;
+
+ int n = 0;
+ while (n < nbytes){
+
+ usbdevfs_urb *urb = get_write_work_in_progress ();
+ unsigned char *dst = (unsigned char *) urb->buffer;
+ int m = std::min (nbytes - n, urb->buffer_length - urb->actual_length);
+
+ memcpy (&dst[urb->actual_length], &src[n], m);
+ urb->actual_length += m;
+ n += m;
+
+ if (urb->actual_length == urb->buffer_length){
+ if (!submit_urb (urb))
+ return -1;
+ d_write_work_in_progress = 0;
+ }
+ }
+
+ return n;
+}
+
+#endif
+
+usbdevfs_urb *
+fusb_ephandle_linux::get_write_work_in_progress ()
+{
+ // if we've already got some work in progress, return it
+
+ if (d_write_work_in_progress)
+ return d_write_work_in_progress;
+
+ while (1){
+
+ reap_complete_writes ();
+
+ usbdevfs_urb *urb = free_list_get ();
+
+ if (urb != 0){
+ assert (urb->actual_length == 0);
+ d_write_work_in_progress = urb;
+ return urb;
+ }
+
+ // The free list is empty. Tell the device handle to reap.
+ // Anything it reaps for us will end up on our completed list.
+
+ d_devhandle->_reap (true);
+ }
+}
+
+void
+fusb_ephandle_linux::reap_complete_writes ()
+{
+ // take a look at the completed_list and xfer to free list after
+ // checking for errors.
+
+ usbdevfs_urb *urb;
+
+ while ((urb = completed_list_get ()) != 0){
+
+ // Check for any errors or short writes that were reported in the urb.
+ // The kernel sets status, actual_length and error_count.
+ // error_count is only used for ISO xfers.
+ // status is 0 if successful, else is an errno kind of thing
+
+ if (urb->status != 0){
+ fprintf (stderr, "fusb: (status %d) %s\n", urb->status, strerror (-urb->status));
+ }
+ else if (urb->actual_length != urb->buffer_length){
+ fprintf (stderr, "fusb: short write xfer: %d != %d\n",
+ urb->actual_length, urb->buffer_length);
+ }
+
+ free_list_add (urb);
+ }
+}
+
+void
+fusb_ephandle_linux::wait_for_completion ()
+{
+ d_devhandle->_wait_for_completion ();
+}
+
+// ----------------------------------------------------------------
+// routines for reading
+// ----------------------------------------------------------------
+
+int
+fusb_ephandle_linux::read (void *buffer, int nbytes)
+{
+ if (!d_started)
+ return -1;
+
+ if (!d_input_p)
+ return -1;
+
+ unsigned char *dst = (unsigned char *) buffer;
+
+ int n = 0;
+ while (n < nbytes){
+
+ if (d_read_buffer >= d_read_buffer_end)
+ if (!reload_read_buffer ())
+ return -1;
+
+ int m = std::min (nbytes - n, (int) (d_read_buffer_end - d_read_buffer));
+
+ memcpy (&dst[n], d_read_buffer, m);
+ d_read_buffer += m;
+ n += m;
+ }
+
+ return n;
+}
+
+bool
+fusb_ephandle_linux::reload_read_buffer ()
+{
+ assert (d_read_buffer >= d_read_buffer_end);
+
+ usbdevfs_urb *urb;
+
+ if (d_read_work_in_progress){
+ // We're done with this urb. Fire off a read to refill it.
+ urb = d_read_work_in_progress;
+ d_read_work_in_progress = 0;
+ d_read_buffer = 0;
+ d_read_buffer_end = 0;
+ urb->actual_length = 0;
+ if (!submit_urb (urb))
+ return false;
+ }
+
+ while (1){
+
+ while ((urb = completed_list_get ()) == 0)
+ d_devhandle->_reap (true);
+
+ // check result of completed read
+
+ if (urb->status != 0){
+ // We've got a problem.
+ // Report the problem and resubmit.
+ fprintf (stderr, "fusb: (rd status %d) %s\n", urb->status, strerror (-urb->status));
+ urb->actual_length = 0;
+ if (!submit_urb (urb))
+ return false;
+
+ continue;
+ }
+
+ // we've got a happy urb, full of data...
+
+ d_read_work_in_progress = urb;
+ d_read_buffer = (unsigned char *) urb->buffer;
+ d_read_buffer_end = d_read_buffer + urb->actual_length;
+
+ return true;
+ }
+}
+
+// ----------------------------------------------------------------
+
+void
+fusb_ephandle_linux::free_list_add (usbdevfs_urb *urb)
+{
+ assert (urb_get_ephandle (urb) == this);
+ urb->actual_length = 0;
+ d_free_list.push_back (urb);
+}
+
+usbdevfs_urb *
+fusb_ephandle_linux::free_list_get ()
+{
+ if (d_free_list.empty ())
+ return 0;
+
+ usbdevfs_urb *urb = d_free_list.front ();
+ d_free_list.pop_front ();
+ return urb;
+}
+
+void
+fusb_ephandle_linux::completed_list_add (usbdevfs_urb *urb)
+{
+ assert (urb_get_ephandle (urb) == this);
+ d_completed_list.push_back (urb);
+}
+
+usbdevfs_urb *
+fusb_ephandle_linux::completed_list_get ()
+{
+ if (d_completed_list.empty ())
+ return 0;
+
+ usbdevfs_urb *urb = d_completed_list.front ();
+ d_completed_list.pop_front ();
+ return urb;
+}
+
+/*
+ * Submit the urb. If successful the urb ends up on the devhandle's
+ * pending list, otherwise, it's back on our free list.
+ */
+bool
+fusb_ephandle_linux::submit_urb (usbdevfs_urb *urb)
+{
+ if (!d_devhandle->_submit_urb (urb)){ // FIXME record the problem somewhere
+ fprintf (stderr, "_submit_urb failed\n");
+ free_list_add (urb);
+ return false;
+ }
+ return true;
+}
diff --git a/usrp/host/lib/fusb_linux.h b/usrp/host/lib/fusb_linux.h
new file mode 100644
index 000000000..9b7091807
--- /dev/null
+++ b/usrp/host/lib/fusb_linux.h
@@ -0,0 +1,116 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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.
+ */
+
+// Fast USB interface
+
+#ifndef _FUSB_LINUX_H_
+#define _FUSB_LINUX_H_
+
+#include <fusb.h>
+#include <list>
+
+struct usbdevfs_urb;
+class fusb_ephandle_linux;
+
+/*!
+ * \brief linux specific implementation of fusb_devhandle using usbdevice_fs
+ */
+class fusb_devhandle_linux : public fusb_devhandle {
+private:
+ std::list<usbdevfs_urb*> d_pending_rqsts;
+
+ void pending_add (usbdevfs_urb *urb);
+ bool pending_remove (usbdevfs_urb *urb);
+ usbdevfs_urb * pending_get ();
+
+
+public:
+ // CREATORS
+ fusb_devhandle_linux (usb_dev_handle *udh);
+ virtual ~fusb_devhandle_linux ();
+
+ // MANIPULATORS
+ virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+
+ // internal use only
+ bool _submit_urb (usbdevfs_urb *urb);
+ bool _cancel_urb (usbdevfs_urb *urb);
+ void _cancel_pending_rqsts (fusb_ephandle_linux *eph);
+ bool _reap (bool ok_to_block_p);
+ void _wait_for_completion ();
+};
+
+ /*!
+ * \brief linux specific implementation of fusb_ephandle using usbdevice_fs
+ */
+
+class fusb_ephandle_linux : public fusb_ephandle {
+private:
+ fusb_devhandle_linux *d_devhandle;
+ std::list<usbdevfs_urb*> d_free_list;
+ std::list<usbdevfs_urb*> d_completed_list;
+ usbdevfs_urb *d_write_work_in_progress;
+ unsigned char *d_write_buffer;
+ usbdevfs_urb *d_read_work_in_progress;
+ unsigned char *d_read_buffer;
+ unsigned char *d_read_buffer_end;
+
+ usbdevfs_urb *get_write_work_in_progress ();
+ void reap_complete_writes ();
+ bool reload_read_buffer ();
+ bool submit_urb (usbdevfs_urb *urb);
+
+public:
+ fusb_ephandle_linux (fusb_devhandle_linux *dh, int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+ virtual ~fusb_ephandle_linux ();
+
+ virtual bool start (); //!< begin streaming i/o
+ virtual bool stop (); //!< stop streaming i/o
+
+ /*!
+ * \returns \p nbytes if write was successfully enqueued, else -1.
+ * Will block if no free buffers available.
+ */
+ virtual int write (const void *buffer, int nbytes);
+
+ /*!
+ * \returns number of bytes read or -1 if error.
+ * number of bytes read will be <= nbytes.
+ * Will block if no input available.
+ */
+ virtual int read (void *buffer, int nbytes);
+
+ /*
+ * block until all outstanding writes have completed
+ */
+ virtual void wait_for_completion ();
+
+ // internal use only
+ void free_list_add (usbdevfs_urb *urb);
+ void completed_list_add (usbdevfs_urb *urb);
+ usbdevfs_urb *free_list_get (); // pop and return head of list or 0
+ usbdevfs_urb *completed_list_get (); // pop and return head of list or 0
+};
+
+#endif /* _FUSB_LINUX_H_ */
diff --git a/usrp/host/lib/fusb_sysconfig_darwin.cc b/usrp/host/lib/fusb_sysconfig_darwin.cc
new file mode 100644
index 000000000..3a4fcf98d
--- /dev/null
+++ b/usrp/host/lib/fusb_sysconfig_darwin.cc
@@ -0,0 +1,37 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 <fusb.h>
+#include <fusb_darwin.h>
+
+static const int MAX_BLOCK_SIZE = 32 * 1024; // hard limit
+
+fusb_devhandle *
+fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
+{
+ return new fusb_devhandle_darwin (udh);
+}
+
+int fusb_sysconfig::max_block_size ()
+{
+ return MAX_BLOCK_SIZE;
+}
diff --git a/usrp/host/lib/fusb_sysconfig_generic.cc b/usrp/host/lib/fusb_sysconfig_generic.cc
new file mode 100644
index 000000000..6fa2e48b2
--- /dev/null
+++ b/usrp/host/lib/fusb_sysconfig_generic.cc
@@ -0,0 +1,37 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 <fusb.h>
+#include <fusb_generic.h>
+
+static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
+
+fusb_devhandle *
+fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
+{
+ return new fusb_devhandle_generic (udh);
+}
+
+int fusb_sysconfig::max_block_size ()
+{
+ return MAX_BLOCK_SIZE;
+}
diff --git a/usrp/host/lib/fusb_sysconfig_linux.cc b/usrp/host/lib/fusb_sysconfig_linux.cc
new file mode 100644
index 000000000..f7fc5d631
--- /dev/null
+++ b/usrp/host/lib/fusb_sysconfig_linux.cc
@@ -0,0 +1,37 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 <fusb.h>
+#include <fusb_linux.h>
+
+static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
+
+fusb_devhandle *
+fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
+{
+ return new fusb_devhandle_linux (udh);
+}
+
+int fusb_sysconfig::max_block_size ()
+{
+ return MAX_BLOCK_SIZE;
+}
diff --git a/usrp/host/lib/fusb_sysconfig_win32.cc b/usrp/host/lib/fusb_sysconfig_win32.cc
new file mode 100644
index 000000000..b2b6cb14a
--- /dev/null
+++ b/usrp/host/lib/fusb_sysconfig_win32.cc
@@ -0,0 +1,37 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,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.
+ */
+
+#include <fusb.h>
+#include <fusb_win32.h>
+
+static const int MAX_BLOCK_SIZE = 64 * 1024; // Windows kernel hard limit
+
+fusb_devhandle *
+fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
+{
+ return new fusb_devhandle_win32 (udh);
+}
+
+int fusb_sysconfig::max_block_size ()
+{
+ return MAX_BLOCK_SIZE;
+}
diff --git a/usrp/host/lib/fusb_win32.cc b/usrp/host/lib/fusb_win32.cc
new file mode 100644
index 000000000..494a6bebe
--- /dev/null
+++ b/usrp/host/lib/fusb_win32.cc
@@ -0,0 +1,265 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fusb_win32.h>
+#include <usb.h>
+#include <assert.h>
+#include <stdexcept>
+
+static const int MAX_BLOCK_SIZE = fusb_sysconfig::max_block_size();
+static const int DEFAULT_BLOCK_SIZE = MAX_BLOCK_SIZE;
+static const int DEFAULT_BUFFER_SIZE = 16 * (1L << 20); // 16 MB / endpoint
+
+
+static const int USB_TIMEOUT = 1000; // in milliseconds
+
+
+fusb_devhandle_win32::fusb_devhandle_win32 (usb_dev_handle *udh)
+ : fusb_devhandle (udh)
+{
+ // that's it
+}
+
+fusb_devhandle_win32::~fusb_devhandle_win32 ()
+{
+ // nop
+}
+
+fusb_ephandle *
+fusb_devhandle_win32::make_ephandle (int endpoint, bool input_p,
+ int block_size, int nblocks)
+{
+ return new fusb_ephandle_win32 (this, endpoint, input_p,
+ block_size, nblocks);
+}
+
+// ----------------------------------------------------------------
+
+fusb_ephandle_win32::fusb_ephandle_win32 (fusb_devhandle_win32 *dh,
+ int endpoint, bool input_p,
+ int block_size, int nblocks)
+ : fusb_ephandle (endpoint, input_p, block_size, nblocks),
+ d_devhandle (dh), d_input_leftover(0),d_output_short(0)
+{
+ if (d_block_size < 0 || d_block_size > MAX_BLOCK_SIZE)
+ throw std::out_of_range ("fusb_ephandle_win32: block_size");
+
+ if (d_nblocks < 0)
+ throw std::out_of_range ("fusb_ephandle_win32: nblocks");
+
+ if (d_block_size == 0)
+ d_block_size = DEFAULT_BLOCK_SIZE;
+
+ if (d_nblocks == 0)
+ d_nblocks = std::max (1, DEFAULT_BUFFER_SIZE / d_block_size);
+
+ d_buffer = new char [d_block_size*d_nblocks];
+ d_context = new void * [d_nblocks];
+
+ // allocate contexts
+
+ usb_dev_handle *dev = dh->get_usb_dev_handle ();
+ int i;
+
+ if (d_input_p)
+ endpoint |= USB_ENDPOINT_IN;
+
+ for (i=0; i<d_nblocks; i++)
+ usb_bulk_setup_async(dev, &d_context[i], endpoint);
+}
+
+fusb_ephandle_win32::~fusb_ephandle_win32 ()
+{
+ int i;
+
+ stop ();
+
+ for (i=0; i<d_nblocks; i++)
+ usb_free_async(&d_context[i]);
+
+ delete [] d_buffer;
+ delete [] d_context;
+}
+
+bool
+fusb_ephandle_win32::start ()
+{
+ if (d_started)
+ return true; // already running
+
+ d_started = true;
+
+ d_curr = d_nblocks-1;
+ d_outstanding_write = 0;
+ d_input_leftover =0;
+ d_output_short = 0;
+
+ if (d_input_p){ // fire off all the reads
+ int i;
+
+ for (i=0; i<d_nblocks; i++) {
+ usb_submit_async(d_context[i], (char * ) d_buffer+i*d_block_size,
+ d_block_size);
+ }
+ }
+
+ return true;
+}
+
+bool
+fusb_ephandle_win32::stop ()
+{
+ if (!d_started)
+ return true;
+
+ if (!d_input_p)
+ wait_for_completion ();
+
+ d_started = false;
+ return true;
+}
+
+int
+fusb_ephandle_win32::write (const void *buffer, int nbytes)
+{
+ int retval=0;
+ char *buf;
+
+ if (!d_started) // doesn't matter here, but keeps semantics constant
+ return -1;
+
+ if (d_input_p)
+ return -1;
+
+ int bytes_to_write = nbytes;
+ int a=0;
+
+ if (d_output_short != 0) {
+
+ buf = &d_buffer[d_curr*d_block_size + d_block_size - d_output_short];
+ a = std::min(nbytes, d_output_short);
+ memcpy(buf, buffer, a);
+ bytes_to_write -= a;
+ d_output_short -= a;
+
+ if (d_output_short == 0)
+ usb_submit_async(d_context[d_curr],
+ &d_buffer[d_curr*d_block_size], d_block_size);
+
+ if (bytes_to_write == 0)
+ return nbytes;
+
+ assert(d_output_short == 0);
+ }
+
+ d_curr = (d_curr+1)%d_nblocks;
+ buf = &d_buffer[d_curr*d_block_size];
+
+ if (d_outstanding_write != d_nblocks) {
+ d_outstanding_write++;
+ } else {
+ retval = usb_reap_async(d_context[d_curr], USB_TIMEOUT);
+ if (retval < 0) {
+ fprintf(stderr, "%s: usb_reap_async: %s\n",
+ __FUNCTION__, usb_strerror());
+ return retval;
+ }
+ }
+
+ memcpy(buf, (void *) &(((char*)buffer)[a]), bytes_to_write);
+
+ d_output_short = d_block_size - bytes_to_write;
+ if (d_output_short == 0)
+ usb_submit_async(d_context[d_curr], buf, d_block_size);
+
+ return retval < 0 ? retval : nbytes;
+}
+
+int
+fusb_ephandle_win32::read (void *buffer, int nbytes)
+{
+ int retval=0;
+ char *buf;
+
+ if (!d_started) // doesn't matter here, but keeps semantics constant
+ return -1;
+
+ if (!d_input_p)
+ return -1;
+
+ int bytes_to_read = nbytes;
+
+ int a=0;
+ if (d_input_leftover != 0) {
+
+ buf = &d_buffer[d_curr*d_block_size + d_block_size - d_input_leftover];
+ a = std::min(nbytes, d_input_leftover);
+ memcpy(buffer, buf, a);
+ bytes_to_read -= a;
+ d_input_leftover -= a;
+
+ if (d_input_leftover == 0)
+ usb_submit_async(d_context[d_curr],
+ &d_buffer[d_curr*d_block_size], d_block_size);
+
+ if (bytes_to_read == 0)
+ return nbytes;
+
+ assert(d_input_leftover == 0);
+ }
+
+
+ d_curr = (d_curr+1)%d_nblocks;
+ buf = &d_buffer[d_curr*d_block_size];
+
+ retval = usb_reap_async(d_context[d_curr], USB_TIMEOUT);
+ if (retval < 0)
+ fprintf(stderr, "%s: usb_reap_async: %s\n",
+ __FUNCTION__, usb_strerror());
+
+ memcpy((void *) &(((char*)buffer)[a]), buf, bytes_to_read);
+
+ d_input_leftover = d_block_size - bytes_to_read;
+ if (d_input_leftover == 0)
+ usb_submit_async(d_context[d_curr], buf, d_block_size);
+
+ return retval < 0 ? retval : nbytes;
+}
+
+void
+fusb_ephandle_win32::wait_for_completion ()
+{
+ int i;
+
+ for (i=0; i<d_outstanding_write; i++) {
+ int context_num;
+
+ context_num = (d_curr+d_outstanding_write+i+1)%d_nblocks;
+ usb_reap_async(d_context[context_num], USB_TIMEOUT);
+ }
+
+ d_outstanding_write = 0;
+}
diff --git a/usrp/host/lib/fusb_win32.h b/usrp/host/lib/fusb_win32.h
new file mode 100644
index 000000000..77435d040
--- /dev/null
+++ b/usrp/host/lib/fusb_win32.h
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 _FUSB_WIN32_H_
+#define _FUSB_WIN32_H_
+
+#include <fusb.h>
+
+/*!
+ * \brief win32 implementation of fusb_devhandle using libusb-win32
+ */
+class fusb_devhandle_win32 : public fusb_devhandle
+{
+public:
+ // CREATORS
+ fusb_devhandle_win32 (usb_dev_handle *udh);
+ virtual ~fusb_devhandle_win32 ();
+
+ // MANIPULATORS
+ virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+};
+
+
+/*!
+ * \brief win32 implementation of fusb_ephandle using libusb-win32
+ */
+class fusb_ephandle_win32 : public fusb_ephandle
+{
+private:
+ fusb_devhandle_win32 *d_devhandle;
+
+ unsigned d_curr;
+ unsigned d_outstanding_write;
+ int d_output_short;
+ int d_input_leftover;
+ void ** d_context;
+ char * d_buffer;
+
+public:
+ // CREATORS
+ fusb_ephandle_win32 (fusb_devhandle_win32 *dh, int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+ virtual ~fusb_ephandle_win32 ();
+
+ // MANIPULATORS
+
+ virtual bool start (); //!< begin streaming i/o
+ virtual bool stop (); //!< stop streaming i/o
+
+ /*!
+ * \returns \p nbytes if write was successfully enqueued, else -1.
+ * Will block if no free buffers available.
+ */
+ virtual int write (const void *buffer, int nbytes);
+
+ /*!
+ * \returns number of bytes read or -1 if error.
+ * number of bytes read will be <= nbytes.
+ * Will block if no input available.
+ */
+ virtual int read (void *buffer, int nbytes);
+
+ /*
+ * block until all outstanding writes have completed
+ */
+ virtual void wait_for_completion ();
+};
+
+#endif /* _FUSB_WIN32_H_ */
+
diff --git a/usrp/host/lib/gen-ratios b/usrp/host/lib/gen-ratios
new file mode 100755
index 000000000..2250090d7
--- /dev/null
+++ b/usrp/host/lib/gen-ratios
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- python -*-
+
+def how_good (x):
+ pof2 = [1,2,4,8,16]
+ if x in pof2:
+ return 0
+ if x in map (lambda x: x+1, pof2):
+ return -10
+ if x in map (lambda x: x-1, pof2):
+ return -5
+ return -2
+
+
+def better (v1, v2):
+ return abs ((v1 & 0xf) - ((v1 >> 4) & 0xf)) < abs ((v2 & 0xf) - ((v2 >> 4) & 0xf))
+
+
+def foo ():
+ result = {}
+ for i in range (1,17):
+ for j in range (1,17):
+ i_goodness = how_good (i)
+ j_goodness = how_good (j)
+ goodness = i_goodness + j_goodness
+ v = ((i - 1) << 4) | (j - 1)
+
+ key = i * j
+ prev = result.get (key, None)
+ # print "i=%3d j=%3d key=%3d good=%3d v=0x%02x prev=%s" % (i, j, key, goodness, v, prev)
+
+ if not prev:
+ result[key] = (goodness, v)
+ elif goodness > prev[0]:
+ result[key] = (goodness, v)
+ elif goodness == prev[0] and better(v, prev[1]):
+ result[key] = (goodness, v)
+
+ r = result.items ()
+ r.sort ()
+ for k, d in r:
+ print "(%3d, 0x%02x)" % (k, d[1])
+
+
+
+foo ()
+
+
diff --git a/usrp/host/lib/gen_usrp_dbid.py b/usrp/host/lib/gen_usrp_dbid.py
new file mode 100755
index 000000000..34a994f9b
--- /dev/null
+++ b/usrp/host/lib/gen_usrp_dbid.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+
+import sys
+import os
+import os.path
+import re
+from optparse import OptionParser
+
+def write_header(f, comment_char):
+ f.write(comment_char); f.write('\n')
+ f.write(comment_char); f.write(' Machine generated by gen_usrp_dbid.py from usrp_dbid.dat\n')
+ f.write(comment_char); f.write(' Do not edit by hand. All edits will be overwritten.\n')
+ f.write(comment_char); f.write('\n')
+ f.write('\n')
+
+def gen_dbid_py(r):
+ f = open('usrp_dbid.py', 'w')
+ comment_char = '#'
+ write_header(f, comment_char)
+ f.write(comment_char); f.write('\n')
+ f.write(comment_char); f.write(" USRP Daughterboard ID's\n")
+ f.write(comment_char); f.write('\n')
+ f.write('\n')
+ for x in r:
+ f.write('%-16s = %s\n' % (x[1], x[2]))
+
+def gen_dbid_h(r):
+ f = open('usrp_dbid.h', 'w')
+ comment_char = '//'
+ write_header(f, comment_char)
+ f.write(comment_char); f.write('\n')
+ f.write(comment_char); f.write(" USRP Daughterboard ID's\n")
+ f.write(comment_char); f.write('\n')
+ f.write('\n')
+ f.write('#ifndef INCLUDED_USRP_DBID_H\n')
+ f.write('#define INCLUDED_USRP_DBID_H\n')
+ f.write('\n')
+ for x in r:
+ f.write('#define %-25s %s\n' % ('USRP_DBID_' + x[1], x[2]))
+ f.write('\n')
+ f.write('#endif /* INCLUDED_USRP_DBID_H */\n')
+
+def gen_dbid_cc(r):
+ f = open('usrp_dbid.cc', 'w')
+ write_header(f, '//')
+ head = '''/*
+ * 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.
+ */
+
+#include <usrp_prims.h>
+#include <usrp_dbid.h>
+#include <stdio.h>
+
+#define NELEM(x) sizeof(x)/sizeof(x[0])
+
+static struct {
+ unsigned short dbid;
+ const char *name;
+} dbid_map[] = {
+'''
+
+ tail = '''};
+
+const std::string
+usrp_dbid_to_string (int dbid)
+{
+ if (dbid == -1)
+ return "<none>";
+
+ if (dbid == -2)
+ return "<invalid EEPROM contents>";
+
+ for (unsigned i = 0; i < NELEM (dbid_map); i++)
+ if (dbid == dbid_map[i].dbid)
+ return dbid_map[i].name;
+
+ char tmp[64];
+ snprintf (tmp, sizeof (tmp), "Unknown (0x%04x)", dbid);
+ return tmp;
+}
+'''
+ f.write(head)
+ for x in r:
+ f.write(' { %-27s "%s" },\n' % (
+ 'USRP_DBID_' + x[1] + ',', x[0]))
+ f.write(tail)
+
+def gen_all(src_filename):
+ src_file = open(src_filename, 'r')
+ r = []
+ for line in src_file:
+ line = line.strip()
+ line = re.sub(r'\s*#.*$','', line)
+ if len(line) == 0:
+ continue
+ mo = re.match('"([^"]+)"\s*(0x[0-9a-fA-F]+)', line)
+ if mo:
+ str_name = mo.group(1)
+ id_name = str_name.upper().replace(' ', '_')
+ id_val = mo.group(2)
+ r.append((str_name, id_name, id_val))
+ #sys.stdout.write('%-16s\t%-16s\t%s\n' % ('"'+str_name+'"', id_name, id_val))
+
+ gen_dbid_h(r)
+ gen_dbid_py(r)
+ gen_dbid_cc(r)
+
+
+def main():
+ usage = "usage: %prog [options] usrp_dbid.dat"
+ parser = OptionParser(usage=usage)
+ (options, args) = parser.parse_args()
+ if len(args) != 1:
+ parser.print_help()
+ sys.exit(1)
+
+ gen_all(args[0])
+
+if __name__ == '__main__':
+ main()
diff --git a/usrp/host/lib/md5.c b/usrp/host/lib/md5.c
new file mode 100644
index 000000000..9fbed5b37
--- /dev/null
+++ b/usrp/host/lib/md5.c
@@ -0,0 +1,452 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ according to the definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "md5.h"
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+// #include "unlocked-io.h"
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+ protected using leading __ . */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_read_ctx __md5_read_ctx
+# define md5_stream __md5_stream
+# define md5_buffer __md5_buffer
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+#define BLOCKSIZE 4096
+/* Ensure that BLOCKSIZE is a multiple of 64. */
+#if BLOCKSIZE % 64 != 0
+/* FIXME-someday (soon?): use #error instead of this kludge. */
+"invalid BLOCKSIZE"
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (struct md5_ctx *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+md5_stream (FILE *stream, void *resblock)
+{
+ struct md5_ctx ctx;
+ char buffer[BLOCKSIZE + 72];
+ size_t sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ while (1)
+ {
+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+
+ if (sum == BLOCKSIZE)
+ break;
+
+ if (n == 0)
+ {
+ /* Check for the error flag IFF N == 0, so that we don't
+ exit the loop after a partial read due to e.g., EAGAIN
+ or EWOULDBLOCK. */
+ if (ferror (stream))
+ return 1;
+ goto process_partial_block;
+ }
+
+ /* We've read at least one byte, so ignore errors. But always
+ check for EOF, since feof may be true even though N > 0.
+ Otherwise, we could end up calling fread after EOF. */
+ if (feof (stream))
+ goto process_partial_block;
+ }
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ process_partial_block:;
+
+ /* Process any remaining bytes. */
+ if (sum > 0)
+ md5_process_bytes (buffer, sum, &ctx);
+
+ /* Construct result in desired memory. */
+ md5_finish_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (const char *buffer, size_t len, void *resblock)
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64)
+ {
+ md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ ctx->buflen);
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 64)
+ {
+#if !_STRING_ARCH_unaligned
+/* To check alignment gcc has an appropriate operator. Other
+ compilers don't. */
+# if __GNUC__ >= 2
+# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
+# else
+# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0)
+# endif
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+#endif
+ {
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ size_t left_over = ctx->buflen;
+
+ memcpy (&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64)
+ {
+ md5_process_block (ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ a = rol (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or
+ perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ a = rol (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
diff --git a/usrp/host/lib/md5.h b/usrp/host/lib/md5.h
new file mode 100644
index 000000000..2b336073d
--- /dev/null
+++ b/usrp/host/lib/md5.h
@@ -0,0 +1,129 @@
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright (C) 1995, 1996, 1999, 2000, 2003 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+#include <limits.h>
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#ifdef _LIBC
+# include <stdint.h>
+typedef uint32_t md5_uint32;
+typedef uintptr_t md5_uintptr;
+#else
+# define UINT_MAX_32_BITS 4294967295U
+
+# if UINT_MAX == UINT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+# else
+# if USHRT_MAX == UINT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if ULONG_MAX == UINT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+# endif
+/* We have to make a guess about the integer type equivalent in size
+ to pointers which should always be correct. */
+typedef unsigned long int md5_uintptr;
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void md5_init_ctx (struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void md5_process_bytes (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF be correctly
+ aligned for a 32 bits value. */
+extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf);
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int md5_stream (FILE *stream, void *resblock);
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *md5_buffer (const char *buffer, size_t len, void *resblock);
+
+#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+
+#endif
diff --git a/usrp/host/lib/mld_threads.h b/usrp/host/lib/mld_threads.h
new file mode 100644
index 000000000..ae6253e6e
--- /dev/null
+++ b/usrp/host/lib/mld_threads.h
@@ -0,0 +1,257 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * Primary Author: Michael Dickens, NCIP Lab, University of Notre Dame
+ *
+ * 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_MLD_THREADS_H_
+#define _INCLUDED_MLD_THREADS_H_
+
+/* classes which allow for either pthreads or omni_threads */
+
+#ifdef _USE_OMNI_THREADS_
+#include <gnuradio/omnithread.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <stdexcept>
+
+#define __INLINE__ inline
+
+class mld_condition_t;
+
+class mld_mutex_t {
+#ifdef _USE_OMNI_THREADS_
+ typedef omni_mutex l_mutex, *l_mutex_ptr;
+#else
+ typedef pthread_mutex_t l_mutex, *l_mutex_ptr;
+#endif
+
+ friend class mld_condition_t;
+
+private:
+ l_mutex_ptr d_mutex;
+
+protected:
+ inline l_mutex_ptr mutex () { return (d_mutex); };
+
+public:
+ __INLINE__ mld_mutex_t () {
+#ifdef _USE_OMNI_THREADS_
+ d_mutex = new omni_mutex ();
+#else
+ d_mutex = (l_mutex_ptr) new l_mutex;
+ int l_ret = pthread_mutex_init (d_mutex, NULL);
+ if (l_ret != 0) {
+ fprintf (stderr, "Error %d creating mutex.\n", l_ret);
+ throw std::runtime_error ("mld_mutex_t::mld_mutex_t()\n");
+ }
+#endif
+ };
+
+ __INLINE__ ~mld_mutex_t () {
+ unlock ();
+#ifndef _USE_OMNI_THREADS_
+ int l_ret = pthread_mutex_destroy (d_mutex);
+ if (l_ret != 0) {
+ fprintf (stderr, "mld_mutex_t::~mld_mutex_t(): "
+ "Error %d destroying mutex.\n", l_ret);
+ }
+#endif
+ delete d_mutex;
+ d_mutex = NULL;
+ };
+
+ __INLINE__ void lock () {
+#ifdef _USE_OMNI_THREADS_
+ d_mutex->lock ();
+#else
+ int l_ret = pthread_mutex_lock (d_mutex);
+ if (l_ret != 0) {
+ fprintf (stderr, "mld_mutex_t::lock(): "
+ "Error %d locking mutex.\n", l_ret);
+ }
+#endif
+ };
+
+ __INLINE__ void unlock () {
+#ifdef _USE_OMNI_THREADS_
+ d_mutex->unlock ();
+#else
+ int l_ret = pthread_mutex_unlock (d_mutex);
+ if (l_ret != 0) {
+ fprintf (stderr, "mld_mutex_t::unlock(): "
+ "Error %d locking mutex.\n", l_ret);
+ }
+#endif
+ };
+
+ __INLINE__ bool trylock () {
+#ifdef _USE_OMNI_THREADS_
+ int l_ret = d_mutex->trylock ();
+#else
+ int l_ret = pthread_mutex_unlock (d_mutex);
+#endif
+ return (l_ret == 0 ? true : false);
+ };
+
+ inline void acquire () { lock(); };
+ inline void release () { unlock(); };
+ inline void wait () { lock(); };
+ inline void post () { unlock(); };
+};
+
+typedef mld_mutex_t mld_mutex, *mld_mutex_ptr;
+
+class mld_condition_t {
+#ifdef _USE_OMNI_THREADS_
+ typedef omni_condition l_condition, *l_condition_ptr;
+#else
+ typedef pthread_cond_t l_condition, *l_condition_ptr;
+#endif
+
+private:
+ l_condition_ptr d_condition;
+ mld_mutex_ptr d_mutex;
+ bool d_waiting;
+
+public:
+ __INLINE__ mld_condition_t () {
+ d_waiting = false;
+ d_mutex = new mld_mutex ();
+#ifdef _USE_OMNI_THREADS_
+ d_condition = new omni_condition (d_mutex->mutex ());
+#else
+ d_condition = (l_condition_ptr) new l_condition;
+ int l_ret = pthread_cond_init (d_condition, NULL);
+ if (l_ret != 0) {
+ fprintf (stderr, "Error %d creating condition.\n", l_ret);
+ throw std::runtime_error ("mld_condition_t::mld_condition_t()\n");
+ }
+#endif
+ };
+
+ __INLINE__ ~mld_condition_t () {
+ signal ();
+#ifndef _USE_OMNI_THREADS_
+ int l_ret = pthread_cond_destroy (d_condition);
+ if (l_ret != 0) {
+ fprintf (stderr, "mld_condition_t::mld_condition_t(): "
+ "Error %d destroying condition.\n", l_ret);
+ }
+#endif
+ delete d_condition;
+ d_condition = NULL;
+ delete d_mutex;
+ d_mutex = NULL;
+ };
+
+ __INLINE__ void signal () {
+ if (d_waiting == true) {
+#ifdef _USE_OMNI_THREADS_
+ d_condition->signal ();
+#else
+ int l_ret = pthread_cond_signal (d_condition);
+ if (l_ret != 0) {
+ fprintf (stderr, "mld_condition_t::signal(): "
+ "Error %d.\n", l_ret);
+ }
+#endif
+ d_waiting = false;
+ }
+ };
+
+ __INLINE__ void wait () {
+ if (d_waiting == false) {
+ d_waiting = true;
+#ifdef _USE_OMNI_THREADS_
+ d_condition->wait ();
+#else
+ int l_ret = pthread_cond_wait (d_condition, d_mutex->mutex ());
+ if (l_ret != 0) {
+ fprintf (stderr, "mld_condition_t::wait(): "
+ "Error %d.\n", l_ret);
+ }
+#endif
+ }
+ };
+};
+
+typedef mld_condition_t mld_condition, *mld_condition_ptr;
+
+class mld_thread_t {
+#ifdef _USE_OMNI_THREADS_
+ typedef omni_thread l_thread, *l_thread_ptr;
+#else
+ typedef pthread_t l_thread, *l_thread_ptr;
+#endif
+
+private:
+#ifndef _USE_OMNI_THREADS_
+ l_thread d_thread;
+ void (*d_start_routine)(void*);
+ void *d_arg;
+#else
+ l_thread_ptr d_thread;
+#endif
+
+#ifndef _USE_OMNI_THREADS_
+ static void* local_start_routine (void *arg) {
+ mld_thread_t* This = (mld_thread_t*) arg;
+ (*(This->d_start_routine))(This->d_arg);
+ return (NULL);
+ };
+#endif
+
+public:
+ __INLINE__ mld_thread_t (void (*start_routine)(void *), void *arg) {
+#ifdef _USE_OMNI_THREADS_
+ d_thread = new omni_thread (start_routine, arg);
+ d_thread->start ();
+#else
+ d_start_routine = start_routine;
+ d_arg = arg;
+ int l_ret = pthread_create (&d_thread, NULL, local_start_routine, this);
+ if (l_ret != 0) {
+ fprintf (stderr, "Error %d creating thread.\n", l_ret);
+ throw std::runtime_error ("mld_thread_t::mld_thread_t()\n");
+ }
+#endif
+ };
+
+ __INLINE__ ~mld_thread_t () {
+#ifdef _USE_OMNI_THREADS_
+// delete d_thread;
+ d_thread = NULL;
+#else
+ int l_ret = pthread_detach (d_thread);
+ if (l_ret != 0) {
+ fprintf (stderr, "Error %d detaching thread.\n", l_ret);
+ throw std::runtime_error ("mld_thread_t::~mld_thread_t()\n");
+ }
+#endif
+ };
+};
+
+typedef mld_thread_t mld_thread, *mld_thread_ptr;
+
+#endif /* _INCLUDED_MLD_THREADS_H_ */
diff --git a/usrp/host/lib/rate_to_regval.h b/usrp/host/lib/rate_to_regval.h
new file mode 100644
index 000000000..1ffdc0f69
--- /dev/null
+++ b/usrp/host/lib/rate_to_regval.h
@@ -0,0 +1,97 @@
+ { 1, 0x00 },
+ { 2, 0x01 },
+ { 3, 0x02 },
+ { 4, 0x11 },
+ { 5, 0x04 },
+ { 6, 0x05 },
+ { 7, 0x06 },
+ { 8, 0x13 },
+ { 9, 0x08 },
+ { 10, 0x09 },
+ { 11, 0x0a },
+ { 12, 0x15 },
+ { 13, 0x0c },
+ { 14, 0x0d },
+ { 15, 0x0e },
+ { 16, 0x33 },
+ { 18, 0x18 },
+ { 20, 0x19 },
+ { 21, 0x26 },
+ { 22, 0x1a },
+ { 24, 0x35 },
+ { 25, 0x44 },
+ { 26, 0x1c },
+ { 27, 0x28 },
+ { 28, 0x1d },
+ { 30, 0x1e },
+ { 32, 0x37 },
+ { 33, 0x2a },
+ { 35, 0x46 },
+ { 36, 0x55 },
+ { 39, 0x2c },
+ { 40, 0x39 },
+ { 42, 0x56 },
+ { 44, 0x3a },
+ { 45, 0x2e },
+ { 48, 0x57 },
+ { 49, 0x66 },
+ { 50, 0x49 },
+ { 52, 0x3c },
+ { 54, 0x58 },
+ { 55, 0x4a },
+ { 56, 0x3d },
+ { 60, 0x59 },
+ { 63, 0x68 },
+ { 64, 0x77 },
+ { 65, 0x4c },
+ { 66, 0x5a },
+ { 70, 0x69 },
+ { 72, 0x5b },
+ { 75, 0x4e },
+ { 77, 0x6a },
+ { 78, 0x5c },
+ { 80, 0x79 },
+ { 81, 0x88 },
+ { 84, 0x5d },
+ { 88, 0x7a },
+ { 90, 0x5e },
+ { 91, 0x6c },
+ { 96, 0x7b },
+ { 98, 0x6d },
+ { 99, 0x8a },
+ { 100, 0x99 },
+ { 104, 0x7c },
+ { 105, 0x6e },
+ { 108, 0x8b },
+ { 110, 0x9a },
+ { 112, 0x7d },
+ { 117, 0x8c },
+ { 120, 0x9b },
+ { 121, 0xaa },
+ { 126, 0x8d },
+ { 128, 0x7f },
+ { 130, 0x9c },
+ { 132, 0xab },
+ { 135, 0x8e },
+ { 140, 0x9d },
+ { 143, 0xac },
+ { 144, 0xbb },
+ { 150, 0x9e },
+ { 154, 0xad },
+ { 156, 0xbc },
+ { 160, 0x9f },
+ { 165, 0xae },
+ { 168, 0xbd },
+ { 169, 0xcc },
+ { 176, 0xaf },
+ { 180, 0xbe },
+ { 182, 0xcd },
+ { 192, 0xbf },
+ { 195, 0xce },
+ { 196, 0xdd },
+ { 208, 0xcf },
+ { 210, 0xde },
+ { 224, 0xdf },
+ { 225, 0xee },
+ { 240, 0xef },
+ { 256, 0xff }
diff --git a/usrp/host/lib/std_paths.h.in b/usrp/host/lib/std_paths.h.in
new file mode 100644
index 000000000..fe973e3c9
--- /dev/null
+++ b/usrp/host/lib/std_paths.h.in
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+static char *std_paths[] = {
+ "@prefix@/share/usrp",
+ "/usr/local/share/usrp",
+ 0
+};
diff --git a/usrp/host/lib/usrp_basic.cc b/usrp/host/lib/usrp_basic.cc
new file mode 100644
index 000000000..2029480ab
--- /dev/null
+++ b/usrp/host/lib/usrp_basic.cc
@@ -0,0 +1,1239 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,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 "usrp_basic.h"
+#include "usrp_prims.h"
+#include "usrp_interfaces.h"
+#include "fpga_regs_common.h"
+#include "fusb.h"
+#include <usb.h>
+#include <stdexcept>
+#include <assert.h>
+#include <math.h>
+#include <ad9862.h>
+
+using namespace ad9862;
+
+#define NELEM(x) (sizeof (x) / sizeof (x[0]))
+
+// These set the buffer size used for each end point using the fast
+// usb interface. The kernel ends up locking down this much memory.
+
+static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB (was 8 MB)
+//static const int FUSB_BUFFER_SIZE = 256 * (1L << 10); // 256 kB
+static const int FUSB_BLOCK_SIZE = fusb_sysconfig::max_block_size();
+static const int FUSB_NBLOCKS = FUSB_BUFFER_SIZE / FUSB_BLOCK_SIZE;
+
+
+static const double POLLING_INTERVAL = 0.1; // seconds
+
+////////////////////////////////////////////////////////////////
+
+static struct usb_dev_handle *
+open_rx_interface (struct usb_device *dev)
+{
+ struct usb_dev_handle *udh = usrp_open_rx_interface (dev);
+ if (udh == 0){
+ fprintf (stderr, "usrp_basic_rx: can't open rx interface\n");
+ usb_strerror ();
+ }
+ return udh;
+}
+
+static struct usb_dev_handle *
+open_tx_interface (struct usb_device *dev)
+{
+ struct usb_dev_handle *udh = usrp_open_tx_interface (dev);
+ if (udh == 0){
+ fprintf (stderr, "usrp_basic_tx: can't open tx interface\n");
+ usb_strerror ();
+ }
+ return udh;
+}
+
+
+//////////////////////////////////////////////////////////////////
+//
+// usrp_basic
+//
+////////////////////////////////////////////////////////////////
+
+
+// Given:
+// CLKIN = 64 MHz
+// CLKSEL pin = high
+//
+// These settings give us:
+// CLKOUT1 = CLKIN = 64 MHz
+// CLKOUT2 = CLKIN = 64 MHz
+// ADC is clocked at 64 MHz
+// DAC is clocked at 128 MHz
+
+static unsigned char common_regs[] = {
+ REG_GENERAL, 0,
+ REG_DLL, (DLL_DISABLE_INTERNAL_XTAL_OSC
+ | DLL_MULT_2X
+ | DLL_FAST),
+ REG_CLKOUT, CLKOUT2_EQ_DLL_OVER_2,
+ REG_AUX_ADC_CLK, AUX_ADC_CLK_CLK_OVER_4
+};
+
+
+usrp_basic::usrp_basic (int which_board,
+ struct usb_dev_handle *
+ open_interface (struct usb_device *dev),
+ const std::string fpga_filename,
+ const std::string firmware_filename)
+ : d_udh (0),
+ d_usb_data_rate (16000000), // SWAG, see below
+ d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)),
+ d_verbose (false)
+{
+ /*
+ * SWAG: Scientific Wild Ass Guess.
+ *
+ * d_usb_data_rate is used only to determine how often to poll for over- and under-runs.
+ * We defualt it to 1/2 of our best case. Classes derived from usrp_basic (e.g.,
+ * usrp_standard_tx and usrp_standard_rx) call set_usb_data_rate() to tell us the
+ * actual rate. This doesn't change our throughput, that's determined by the signal
+ * processing code in the FPGA (which we know nothing about), and the system limits
+ * determined by libusb, fusb_*, and the underlying drivers.
+ */
+ memset (d_fpga_shadows, 0, sizeof (d_fpga_shadows));
+
+ usrp_one_time_init ();
+
+ if (!usrp_load_standard_bits (which_board, false, fpga_filename, firmware_filename))
+ throw std::runtime_error ("usrp_basic/usrp_load_standard_bits");
+
+ struct usb_device *dev = usrp_find_device (which_board);
+ if (dev == 0){
+ fprintf (stderr, "usrp_basic: can't find usrp[%d]\n", which_board);
+ throw std::runtime_error ("usrp_basic/usrp_find_device");
+ }
+
+ if (!(usrp_usrp_p(dev) && usrp_hw_rev(dev) >= 1)){
+ fprintf (stderr, "usrp_basic: sorry, this code only works with USRP revs >= 1\n");
+ throw std::runtime_error ("usrp_basic/bad_rev");
+ }
+
+ if ((d_udh = open_interface (dev)) == 0)
+ throw std::runtime_error ("usrp_basic/open_interface");
+
+ // initialize registers that are common to rx and tx
+
+ if (!usrp_9862_write_many_all (d_udh, common_regs, sizeof (common_regs))){
+ fprintf (stderr, "usrp_basic: failed to init common AD9862 regs\n");
+ throw std::runtime_error ("usrp_basic/init_9862");
+ }
+
+ _write_fpga_reg (FR_MODE, 0); // ensure we're in normal mode
+ _write_fpga_reg (FR_DEBUG_EN, 0); // disable debug outputs
+}
+
+usrp_basic::~usrp_basic ()
+{
+ if (d_udh)
+ usb_close (d_udh);
+}
+
+bool
+usrp_basic::start ()
+{
+ return true; // nop
+}
+
+bool
+usrp_basic::stop ()
+{
+ return true; // nop
+}
+
+void
+usrp_basic::set_usb_data_rate (int usb_data_rate)
+{
+ d_usb_data_rate = usb_data_rate;
+ d_bytes_per_poll = (int) (usb_data_rate * POLLING_INTERVAL);
+}
+
+bool
+usrp_basic::write_aux_dac (int slot, int which_dac, int value)
+{
+ return usrp_write_aux_dac (d_udh, slot, which_dac, value);
+}
+
+bool
+usrp_basic::read_aux_adc (int slot, int which_adc, int *value)
+{
+ return usrp_read_aux_adc (d_udh, slot, which_adc, value);
+}
+
+int
+usrp_basic::read_aux_adc (int slot, int which_adc)
+{
+ int value;
+ if (!read_aux_adc (slot, which_adc, &value))
+ return READ_FAILED;
+
+ return value;
+}
+
+bool
+usrp_basic::write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf)
+{
+ return usrp_eeprom_write (d_udh, i2c_addr, eeprom_offset, buf.data (), buf.size ());
+}
+
+std::string
+usrp_basic::read_eeprom (int i2c_addr, int eeprom_offset, int len)
+{
+ if (len <= 0)
+ return "";
+
+ char buf[len];
+
+ if (!usrp_eeprom_read (d_udh, i2c_addr, eeprom_offset, buf, len))
+ return "";
+
+ return std::string (buf, len);
+}
+
+bool
+usrp_basic::write_i2c (int i2c_addr, const std::string buf)
+{
+ return usrp_i2c_write (d_udh, i2c_addr, buf.data (), buf.size ());
+}
+
+std::string
+usrp_basic::read_i2c (int i2c_addr, int len)
+{
+ if (len <= 0)
+ return "";
+
+ char buf[len];
+
+ if (!usrp_i2c_read (d_udh, i2c_addr, buf, len))
+ return "";
+
+ return std::string (buf, len);
+}
+
+std::string
+usrp_basic::serial_number()
+{
+ return usrp_serial_number(d_udh);
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_basic::set_adc_offset (int which, int offset)
+{
+ if (which < 0 || which > 3)
+ return false;
+
+ return _write_fpga_reg (FR_ADC_OFFSET_0 + which, offset);
+}
+
+bool
+usrp_basic::set_dac_offset (int which, int offset, int offset_pin)
+{
+ if (which < 0 || which > 3)
+ return false;
+
+ int which_codec = which >> 1;
+ int tx_a = (which & 0x1) == 0;
+ int lo = ((offset & 0x3) << 6) | (offset_pin & 0x1);
+ int hi = (offset >> 2);
+ bool ok;
+
+ if (tx_a){
+ ok = _write_9862 (which_codec, REG_TX_A_OFFSET_LO, lo);
+ ok &= _write_9862 (which_codec, REG_TX_A_OFFSET_HI, hi);
+ }
+ else {
+ ok = _write_9862 (which_codec, REG_TX_B_OFFSET_LO, lo);
+ ok &= _write_9862 (which_codec, REG_TX_B_OFFSET_HI, hi);
+ }
+ return ok;
+}
+
+bool
+usrp_basic::set_adc_buffer_bypass (int which, bool bypass)
+{
+ if (which < 0 || which > 3)
+ return false;
+
+ int codec = which >> 1;
+ int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+ unsigned char cur_rx;
+ unsigned char cur_pwr_dn;
+
+ // If the input buffer is bypassed, we need to power it down too.
+
+ bool ok = _read_9862 (codec, reg, &cur_rx);
+ ok &= _read_9862 (codec, REG_RX_PWR_DN, &cur_pwr_dn);
+ if (!ok)
+ return false;
+
+ if (bypass){
+ cur_rx |= RX_X_BYPASS_INPUT_BUFFER;
+ cur_pwr_dn |= ((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B;
+ }
+ else {
+ cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER;
+ cur_pwr_dn &= ~(((which & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B);
+ }
+
+ ok &= _write_9862 (codec, reg, cur_rx);
+ ok &= _write_9862 (codec, REG_RX_PWR_DN, cur_pwr_dn);
+ return ok;
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_basic::_write_fpga_reg (int regno, int value)
+{
+ if (d_verbose){
+ fprintf (stdout, "_write_fpga_reg(%3d, 0x%08x)\n", regno, value);
+ fflush (stdout);
+ }
+
+ if (regno >= 0 && regno < MAX_REGS)
+ d_fpga_shadows[regno] = value;
+
+ return usrp_write_fpga_reg (d_udh, regno, value);
+}
+
+bool
+usrp_basic::_write_fpga_reg_masked (int regno, int value, int mask)
+{
+ //Only use this for registers who actually use a mask in the verilog firmware, like FR_RX_MASTER_SLAVE
+ //value is a 16 bits value and mask is a 16 bits mask
+ if (d_verbose){
+ fprintf (stdout, "_write_fpga_reg_masked(%3d, 0x%04x,0x%04x)\n", regno, value, mask);
+ fflush (stdout);
+ }
+
+ if (regno >= 0 && regno < MAX_REGS)
+ d_fpga_shadows[regno] = value;
+
+ return usrp_write_fpga_reg (d_udh, regno, (value & 0xffff) | ((mask & 0xffff)<<16));
+}
+
+
+bool
+usrp_basic::_read_fpga_reg (int regno, int *value)
+{
+ return usrp_read_fpga_reg (d_udh, regno, value);
+}
+
+int
+usrp_basic::_read_fpga_reg (int regno)
+{
+ int value;
+ if (!_read_fpga_reg (regno, &value))
+ return READ_FAILED;
+ return value;
+}
+
+bool
+usrp_basic::_write_9862 (int which_codec, int regno, unsigned char value)
+{
+ if (0 && d_verbose){
+ // FIXME really want to enable logging in usrp_prims:usrp_9862_write
+ fprintf(stdout, "_write_9862(codec = %d, regno = %2d, val = 0x%02x)\n", which_codec, regno, value);
+ fflush(stdout);
+ }
+
+ return usrp_9862_write (d_udh, which_codec, regno, value);
+}
+
+
+bool
+usrp_basic::_read_9862 (int which_codec, int regno, unsigned char *value) const
+{
+ return usrp_9862_read (d_udh, which_codec, regno, value);
+}
+
+int
+usrp_basic::_read_9862 (int which_codec, int regno) const
+{
+ unsigned char value;
+ if (!_read_9862 (which_codec, regno, &value))
+ return READ_FAILED;
+ return value;
+}
+
+bool
+usrp_basic::_write_spi (int optional_header, int enables, int format, std::string buf)
+{
+ return usrp_spi_write (d_udh, optional_header, enables, format,
+ buf.data(), buf.size());
+}
+
+std::string
+usrp_basic::_read_spi (int optional_header, int enables, int format, int len)
+{
+ if (len <= 0)
+ return "";
+
+ char buf[len];
+
+ if (!usrp_spi_read (d_udh, optional_header, enables, format, buf, len))
+ return "";
+
+ return std::string (buf, len);
+}
+
+
+bool
+usrp_basic::_set_led (int which, bool on)
+{
+ return usrp_set_led (d_udh, which, on);
+}
+
+////////////////////////////////////////////////////////////////
+//
+// usrp_basic_rx
+//
+////////////////////////////////////////////////////////////////
+
+static unsigned char rx_init_regs[] = {
+ REG_RX_PWR_DN, 0,
+ REG_RX_A, 0, // minimum gain = 0x00 (max gain = 0x14)
+ REG_RX_B, 0, // minimum gain = 0x00 (max gain = 0x14)
+ REG_RX_MISC, (RX_MISC_HS_DUTY_CYCLE | RX_MISC_CLK_DUTY),
+ REG_RX_IF, (RX_IF_USE_CLKOUT1
+ | RX_IF_2S_COMP),
+ REG_RX_DIGITAL, (RX_DIGITAL_2_CHAN)
+};
+
+
+usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int fusb_nblocks,
+ const std::string fpga_filename,
+ const std::string firmware_filename
+ )
+ : usrp_basic (which_board, open_rx_interface, fpga_filename, firmware_filename),
+ d_devhandle (0), d_ephandle (0),
+ d_bytes_seen (0), d_first_read (true),
+ d_rx_enable (false)
+{
+ // initialize rx specific registers
+
+ if (!usrp_9862_write_many_all (d_udh, rx_init_regs, sizeof (rx_init_regs))){
+ fprintf (stderr, "usrp_basic_rx: failed to init AD9862 RX regs\n");
+ throw std::runtime_error ("usrp_basic_rx/init_9862");
+ }
+
+ if (0){
+ // FIXME power down 2nd codec rx path
+ usrp_9862_write (d_udh, 1, REG_RX_PWR_DN, 0x1); // power down everything
+ }
+
+ // Reset the rx path and leave it disabled.
+ set_rx_enable (false);
+ usrp_set_fpga_rx_reset (d_udh, true);
+ usrp_set_fpga_rx_reset (d_udh, false);
+
+ set_fpga_rx_sample_rate_divisor (2); // usually correct
+
+ set_dc_offset_cl_enable(0xf, 0xf); // enable DC offset removal control loops
+
+ probe_rx_slots (false);
+
+ // check fusb buffering parameters
+
+ if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+ throw std::out_of_range ("usrp_basic_rx: invalid fusb_block_size");
+
+ if (fusb_nblocks < 0)
+ throw std::out_of_range ("usrp_basic_rx: invalid fusb_nblocks");
+
+ if (fusb_block_size == 0)
+ fusb_block_size = FUSB_BLOCK_SIZE;
+
+ if (fusb_nblocks == 0)
+ fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
+
+ d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+ d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true,
+ fusb_block_size, fusb_nblocks);
+
+ _write_fpga_reg(FR_ATR_MASK_1, 0); // zero Rx side Auto Transmit/Receive regs
+ _write_fpga_reg(FR_ATR_TXVAL_1, 0);
+ _write_fpga_reg(FR_ATR_RXVAL_1, 0);
+ _write_fpga_reg(FR_ATR_MASK_3, 0);
+ _write_fpga_reg(FR_ATR_TXVAL_3, 0);
+ _write_fpga_reg(FR_ATR_RXVAL_3, 0);
+}
+
+static unsigned char rx_fini_regs[] = {
+ REG_RX_PWR_DN, 0x1 // power down everything
+};
+
+usrp_basic_rx::~usrp_basic_rx ()
+{
+ if (!set_rx_enable (false)){
+ fprintf (stderr, "usrp_basic_rx: set_fpga_rx_enable failed\n");
+ usb_strerror ();
+ }
+
+ d_ephandle->stop ();
+ delete d_ephandle;
+ delete d_devhandle;
+
+ if (!usrp_9862_write_many_all (d_udh, rx_fini_regs, sizeof (rx_fini_regs))){
+ fprintf (stderr, "usrp_basic_rx: failed to fini AD9862 RX regs\n");
+ }
+}
+
+
+bool
+usrp_basic_rx::start ()
+{
+ if (!usrp_basic::start ()) // invoke parent's method
+ return false;
+
+ // fire off reads before asserting rx_enable
+
+ if (!d_ephandle->start ()){
+ fprintf (stderr, "usrp_basic_rx: failed to start end point streaming");
+ usb_strerror ();
+ return false;
+ }
+
+ if (!set_rx_enable (true)){
+ fprintf (stderr, "usrp_basic_rx: set_rx_enable failed\n");
+ usb_strerror ();
+ return false;
+ }
+
+ return true;
+}
+
+bool
+usrp_basic_rx::stop ()
+{
+ bool ok = usrp_basic::stop();
+
+ if (!d_ephandle->stop()){
+ fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming");
+ usb_strerror ();
+ ok = false;
+ }
+ if (!set_rx_enable(false)){
+ fprintf (stderr, "usrp_basic_rx: set_rx_enable(false) failed\n");
+ usb_strerror ();
+ ok = false;
+ }
+ return false;
+}
+
+usrp_basic_rx *
+usrp_basic_rx::make (int which_board, int fusb_block_size, int fusb_nblocks,
+ const std::string fpga_filename,
+ const std::string firmware_filename)
+{
+ usrp_basic_rx *u = 0;
+
+ try {
+ u = new usrp_basic_rx (which_board, fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename);
+ return u;
+ }
+ catch (...){
+ delete u;
+ return 0;
+ }
+
+ return u;
+}
+
+bool
+usrp_basic_rx::set_fpga_rx_sample_rate_divisor (unsigned int div)
+{
+ return _write_fpga_reg (FR_RX_SAMPLE_RATE_DIV, div - 1);
+}
+
+
+/*
+ * \brief read data from the D/A's via the FPGA.
+ * \p len must be a multiple of 512 bytes.
+ *
+ * \returns the number of bytes read, or -1 on error.
+ *
+ * If overrun is non-NULL it will be set true iff an RX overrun is detected.
+ */
+int
+usrp_basic_rx::read (void *buf, int len, bool *overrun)
+{
+ int r;
+
+ if (overrun)
+ *overrun = false;
+
+ if (len < 0 || (len % 512) != 0){
+ fprintf (stderr, "usrp_basic_rx::read: invalid length = %d\n", len);
+ return -1;
+ }
+
+ r = d_ephandle->read (buf, len);
+ if (r > 0)
+ d_bytes_seen += r;
+
+ /*
+ * In many cases, the FPGA reports an rx overrun right after we
+ * enable the Rx path. If this is our first read, check for the
+ * overrun to clear the condition, then ignore the result.
+ */
+ if (0 && d_first_read){ // FIXME
+ d_first_read = false;
+ bool bogus_overrun;
+ usrp_check_rx_overrun (d_udh, &bogus_overrun);
+ }
+
+ if (overrun != 0 && d_bytes_seen >= d_bytes_per_poll){
+ d_bytes_seen = 0;
+ if (!usrp_check_rx_overrun (d_udh, overrun)){
+ fprintf (stderr, "usrp_basic_rx: usrp_check_rx_overrun failed\n");
+ usb_strerror ();
+ }
+ }
+
+ return r;
+}
+
+bool
+usrp_basic_rx::set_rx_enable (bool on)
+{
+ d_rx_enable = on;
+ return usrp_set_fpga_rx_enable (d_udh, on);
+}
+
+// conditional disable, return prev state
+bool
+usrp_basic_rx::disable_rx ()
+{
+ bool enabled = rx_enable ();
+ if (enabled)
+ set_rx_enable (false);
+ return enabled;
+}
+
+// conditional set
+void
+usrp_basic_rx::restore_rx (bool on)
+{
+ if (on != rx_enable ())
+ set_rx_enable (on);
+}
+
+bool
+usrp_basic_rx::set_pga (int which, double gain)
+{
+ if (which < 0 || which > 3)
+ return false;
+
+ gain = std::max (pga_min (), gain);
+ gain = std::min (pga_max (), gain);
+
+ int codec = which >> 1;
+ int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+ // read current value to get input buffer bypass flag.
+ unsigned char cur_rx;
+ if (!_read_9862 (codec, reg, &cur_rx))
+ return false;
+
+ int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());
+
+ cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
+ return _write_9862 (codec, reg, cur_rx);
+}
+
+double
+usrp_basic_rx::pga (int which) const
+{
+ if (which < 0 || which > 3)
+ return READ_FAILED;
+
+ int codec = which >> 1;
+ int reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
+ unsigned char v;
+ bool ok = _read_9862 (codec, reg, &v);
+ if (!ok)
+ return READ_FAILED;
+
+ return (pga_db_per_step() * (v & 0x1f)) + pga_min();
+}
+
+static int
+slot_id_to_oe_reg (int slot_id)
+{
+ static int reg[4] = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_io_reg (int slot_id)
+{
+ static int reg[4] = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+void
+usrp_basic_rx::probe_rx_slots (bool verbose)
+{
+ struct usrp_dboard_eeprom eeprom;
+ static int slot_id_map[2] = { SLOT_RX_A, SLOT_RX_B };
+ static const char *slot_name[2] = { "RX d'board A", "RX d'board B" };
+
+ for (int i = 0; i < 2; i++){
+ int slot_id = slot_id_map [i];
+ const char *msg = 0;
+ usrp_dbeeprom_status_t s = usrp_read_dboard_eeprom (d_udh, slot_id, &eeprom);
+
+ switch (s){
+ case UDBE_OK:
+ d_dbid[i] = eeprom.id;
+ msg = usrp_dbid_to_string (eeprom.id).c_str ();
+ set_adc_offset (2*i+0, eeprom.offset[0]);
+ set_adc_offset (2*i+1, eeprom.offset[1]);
+ _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | eeprom.oe);
+ _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+ break;
+
+ case UDBE_NO_EEPROM:
+ d_dbid[i] = -1;
+ msg = "<none>";
+ _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+ _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+ break;
+
+ case UDBE_INVALID_EEPROM:
+ d_dbid[i] = -2;
+ msg = "Invalid EEPROM contents";
+ _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+ _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+ break;
+
+ case UDBE_BAD_SLOT:
+ default:
+ assert (0);
+ }
+
+ if (verbose){
+ fflush (stdout);
+ fprintf (stderr, "%s: %s\n", slot_name[i], msg);
+ }
+ }
+}
+
+bool
+usrp_basic_rx::_write_oe (int which_dboard, int value, int mask)
+{
+ if (! (0 <= which_dboard && which_dboard <= 1))
+ return false;
+
+ return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (which_dboard)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_rx::write_io (int which_dboard, int value, int mask)
+{
+ if (! (0 <= which_dboard && which_dboard <= 1))
+ return false;
+
+ return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (which_dboard)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_rx::read_io (int which_dboard, int *value)
+{
+ if (! (0 <= which_dboard && which_dboard <= 1))
+ return false;
+
+ int t;
+ int reg = which_dboard + 1; // FIXME, *very* magic number (fix in serial_io.v)
+ bool ok = _read_fpga_reg (reg, &t);
+ if (!ok)
+ return false;
+
+ *value = (t >> 16) & 0xffff; // FIXME, more magic
+ return true;
+}
+
+int
+usrp_basic_rx::read_io (int which_dboard)
+{
+ int value;
+ if (!read_io (which_dboard, &value))
+ return READ_FAILED;
+ return value;
+}
+
+bool
+usrp_basic_rx::write_aux_dac (int which_dboard, int which_dac, int value)
+{
+ return usrp_basic::write_aux_dac (dboard_to_slot (which_dboard),
+ which_dac, value);
+}
+
+bool
+usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc, int *value)
+{
+ return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard),
+ which_adc, value);
+}
+
+int
+usrp_basic_rx::read_aux_adc (int which_dboard, int which_adc)
+{
+ return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), which_adc);
+}
+
+int
+usrp_basic_rx::block_size () const { return d_ephandle->block_size(); }
+
+bool
+usrp_basic_rx::set_dc_offset_cl_enable(int bits, int mask)
+{
+ return _write_fpga_reg(FR_DC_OFFSET_CL_EN,
+ (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & mask));
+}
+
+////////////////////////////////////////////////////////////////
+//
+// usrp_basic_tx
+//
+////////////////////////////////////////////////////////////////
+
+
+//
+// DAC input rate 64 MHz interleaved for a total input rate of 128 MHz
+// DAC input is latched on rising edge of CLKOUT2
+// NCO is disabled
+// interpolate 2x
+// coarse modulator disabled
+//
+
+static unsigned char tx_init_regs[] = {
+ REG_TX_PWR_DN, 0,
+ REG_TX_A_OFFSET_LO, 0,
+ REG_TX_A_OFFSET_HI, 0,
+ REG_TX_B_OFFSET_LO, 0,
+ REG_TX_B_OFFSET_HI, 0,
+ REG_TX_A_GAIN, (TX_X_GAIN_COARSE_FULL | 0),
+ REG_TX_B_GAIN, (TX_X_GAIN_COARSE_FULL | 0),
+ REG_TX_PGA, 0xff, // maximum gain (0 dB)
+ REG_TX_MISC, 0,
+ REG_TX_IF, (TX_IF_USE_CLKOUT1
+ | TX_IF_I_FIRST
+ | TX_IF_INV_TX_SYNC
+ | TX_IF_2S_COMP
+ | TX_IF_INTERLEAVED),
+ REG_TX_DIGITAL, (TX_DIGITAL_2_DATA_PATHS
+ | TX_DIGITAL_INTERPOLATE_4X),
+ REG_TX_MODULATOR, (TX_MODULATOR_DISABLE_NCO
+ | TX_MODULATOR_COARSE_MODULATION_NONE),
+ REG_TX_NCO_FTW_7_0, 0,
+ REG_TX_NCO_FTW_15_8, 0,
+ REG_TX_NCO_FTW_23_16, 0
+};
+
+usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nblocks,
+ const std::string fpga_filename,
+ const std::string firmware_filename)
+ : usrp_basic (which_board, open_tx_interface, fpga_filename, firmware_filename),
+ d_devhandle (0), d_ephandle (0),
+ d_bytes_seen (0), d_first_write (true),
+ d_tx_enable (false)
+{
+ if (!usrp_9862_write_many_all (d_udh, tx_init_regs, sizeof (tx_init_regs))){
+ fprintf (stderr, "usrp_basic_tx: failed to init AD9862 TX regs\n");
+ throw std::runtime_error ("usrp_basic_tx/init_9862");
+ }
+
+ if (0){
+ // FIXME power down 2nd codec tx path
+ usrp_9862_write (d_udh, 1, REG_TX_PWR_DN,
+ (TX_PWR_DN_TX_DIGITAL
+ | TX_PWR_DN_TX_ANALOG_BOTH));
+ }
+
+ // Reset the tx path and leave it disabled.
+ set_tx_enable (false);
+ usrp_set_fpga_tx_reset (d_udh, true);
+ usrp_set_fpga_tx_reset (d_udh, false);
+
+ set_fpga_tx_sample_rate_divisor (4); // we're using interp x4
+
+ probe_tx_slots (false);
+
+ // check fusb buffering parameters
+
+ if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+ throw std::out_of_range ("usrp_basic_rx: invalid fusb_block_size");
+
+ if (fusb_nblocks < 0)
+ throw std::out_of_range ("usrp_basic_rx: invalid fusb_nblocks");
+
+ if (fusb_block_size == 0)
+ fusb_block_size = FUSB_BLOCK_SIZE;
+
+ if (fusb_nblocks == 0)
+ fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
+
+ d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+ d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false,
+ fusb_block_size, fusb_nblocks);
+
+ _write_fpga_reg(FR_ATR_MASK_0, 0); // zero Tx side Auto Transmit/Receive regs
+ _write_fpga_reg(FR_ATR_TXVAL_0, 0);
+ _write_fpga_reg(FR_ATR_RXVAL_0, 0);
+ _write_fpga_reg(FR_ATR_MASK_2, 0);
+ _write_fpga_reg(FR_ATR_TXVAL_2, 0);
+ _write_fpga_reg(FR_ATR_RXVAL_2, 0);
+}
+
+
+static unsigned char tx_fini_regs[] = {
+ REG_TX_PWR_DN, (TX_PWR_DN_TX_DIGITAL
+ | TX_PWR_DN_TX_ANALOG_BOTH),
+ REG_TX_MODULATOR, (TX_MODULATOR_DISABLE_NCO
+ | TX_MODULATOR_COARSE_MODULATION_NONE)
+};
+
+usrp_basic_tx::~usrp_basic_tx ()
+{
+ d_ephandle->stop ();
+ delete d_ephandle;
+ delete d_devhandle;
+
+ if (!usrp_9862_write_many_all (d_udh, tx_fini_regs, sizeof (tx_fini_regs))){
+ fprintf (stderr, "usrp_basic_tx: failed to fini AD9862 TX regs\n");
+ }
+}
+
+bool
+usrp_basic_tx::start ()
+{
+ if (!usrp_basic::start ())
+ return false;
+
+ if (!set_tx_enable (true)){
+ fprintf (stderr, "usrp_basic_tx: set_tx_enable failed\n");
+ usb_strerror ();
+ return false;
+ }
+
+ if (!d_ephandle->start ()){
+ fprintf (stderr, "usrp_basic_tx: failed to start end point streaming");
+ usb_strerror ();
+ return false;
+ }
+
+ return true;
+}
+
+bool
+usrp_basic_tx::stop ()
+{
+ bool ok = usrp_basic::stop ();
+
+ if (!set_tx_enable (false)){
+ fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n");
+ usb_strerror ();
+ ok = false;
+ }
+ if (!d_ephandle->stop ()){
+ fprintf (stderr, "usrp_basic_tx: failed to stop end point streaming");
+ usb_strerror ();
+ ok = false;
+ }
+ return ok;
+}
+
+usrp_basic_tx *
+usrp_basic_tx::make (int which_board, int fusb_block_size, int fusb_nblocks,
+ const std::string fpga_filename,
+ const std::string firmware_filename)
+{
+ usrp_basic_tx *u = 0;
+
+ try {
+ u = new usrp_basic_tx (which_board, fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename);
+ return u;
+ }
+ catch (...){
+ delete u;
+ return 0;
+ }
+
+ return u;
+}
+
+bool
+usrp_basic_tx::set_fpga_tx_sample_rate_divisor (unsigned int div)
+{
+ return _write_fpga_reg (FR_TX_SAMPLE_RATE_DIV, div - 1);
+}
+
+/*!
+ * \brief Write data to the A/D's via the FPGA.
+ *
+ * \p len must be a multiple of 512 bytes.
+ * \returns number of bytes written or -1 on error.
+ *
+ * if \p underrun is non-NULL, it will be set to true iff
+ * a transmit underrun condition is detected.
+ */
+int
+usrp_basic_tx::write (const void *buf, int len, bool *underrun)
+{
+ int r;
+
+ if (underrun)
+ *underrun = false;
+
+ if (len < 0 || (len % 512) != 0){
+ fprintf (stderr, "usrp_basic_tx::write: invalid length = %d\n", len);
+ return -1;
+ }
+
+ r = d_ephandle->write (buf, len);
+ if (r > 0)
+ d_bytes_seen += r;
+
+ /*
+ * In many cases, the FPGA reports an tx underrun right after we
+ * enable the Tx path. If this is our first write, check for the
+ * underrun to clear the condition, then ignore the result.
+ */
+ if (d_first_write && d_bytes_seen >= 4 * FUSB_BLOCK_SIZE){
+ d_first_write = false;
+ bool bogus_underrun;
+ usrp_check_tx_underrun (d_udh, &bogus_underrun);
+ }
+
+ if (underrun != 0 && d_bytes_seen >= d_bytes_per_poll){
+ d_bytes_seen = 0;
+ if (!usrp_check_tx_underrun (d_udh, underrun)){
+ fprintf (stderr, "usrp_basic_tx: usrp_check_tx_underrun failed\n");
+ usb_strerror ();
+ }
+ }
+
+ return r;
+}
+
+void
+usrp_basic_tx::wait_for_completion ()
+{
+ d_ephandle->wait_for_completion ();
+}
+
+bool
+usrp_basic_tx::set_tx_enable (bool on)
+{
+ d_tx_enable = on;
+ // fprintf (stderr, "set_tx_enable %d\n", on);
+ return usrp_set_fpga_tx_enable (d_udh, on);
+}
+
+// conditional disable, return prev state
+bool
+usrp_basic_tx::disable_tx ()
+{
+ bool enabled = tx_enable ();
+ if (enabled)
+ set_tx_enable (false);
+ return enabled;
+}
+
+// conditional set
+void
+usrp_basic_tx::restore_tx (bool on)
+{
+ if (on != tx_enable ())
+ set_tx_enable (on);
+}
+
+bool
+usrp_basic_tx::set_pga (int which, double gain)
+{
+ if (which < 0 || which > 3)
+ return false;
+
+ gain = std::max (pga_min (), gain);
+ gain = std::min (pga_max (), gain);
+
+ int codec = which >> 1; // 0 and 1 are same, as are 2 and 3
+
+ int int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());
+
+ return _write_9862 (codec, REG_TX_PGA, int_gain);
+}
+
+double
+usrp_basic_tx::pga (int which) const
+{
+ if (which < 0 || which > 3)
+ return READ_FAILED;
+
+ int codec = which >> 1;
+ unsigned char v;
+ bool ok = _read_9862 (codec, REG_TX_PGA, &v);
+ if (!ok)
+ return READ_FAILED;
+
+ return (pga_db_per_step() * v) + pga_min();
+}
+
+void
+usrp_basic_tx::probe_tx_slots (bool verbose)
+{
+ struct usrp_dboard_eeprom eeprom;
+ static int slot_id_map[2] = { SLOT_TX_A, SLOT_TX_B };
+ static const char *slot_name[2] = { "TX d'board A", "TX d'board B" };
+
+ for (int i = 0; i < 2; i++){
+ int slot_id = slot_id_map [i];
+ const char *msg = 0;
+ usrp_dbeeprom_status_t s = usrp_read_dboard_eeprom (d_udh, slot_id, &eeprom);
+
+ switch (s){
+ case UDBE_OK:
+ d_dbid[i] = eeprom.id;
+ msg = usrp_dbid_to_string (eeprom.id).c_str ();
+ // FIXME, figure out interpretation of dc offset for TX d'boards
+ // offset = (eeprom.offset[1] << 16) | (eeprom.offset[0] & 0xffff);
+ _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | eeprom.oe);
+ _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+ break;
+
+ case UDBE_NO_EEPROM:
+ d_dbid[i] = -1;
+ msg = "<none>";
+ _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+ _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+ break;
+
+ case UDBE_INVALID_EEPROM:
+ d_dbid[i] = -2;
+ msg = "Invalid EEPROM contents";
+ _write_fpga_reg (slot_id_to_oe_reg(slot_id), (0xffff << 16) | 0x0000);
+ _write_fpga_reg (slot_id_to_io_reg(slot_id), (0xffff << 16) | 0x0000);
+ break;
+
+ case UDBE_BAD_SLOT:
+ default:
+ assert (0);
+ }
+
+ if (verbose){
+ fflush (stdout);
+ fprintf (stderr, "%s: %s\n", slot_name[i], msg);
+ }
+ }
+}
+
+bool
+usrp_basic_tx::_write_oe (int which_dboard, int value, int mask)
+{
+ if (! (0 <= which_dboard && which_dboard <= 1))
+ return false;
+
+ return _write_fpga_reg (slot_id_to_oe_reg (dboard_to_slot (which_dboard)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_tx::write_io (int which_dboard, int value, int mask)
+{
+ if (! (0 <= which_dboard && which_dboard <= 1))
+ return false;
+
+ return _write_fpga_reg (slot_id_to_io_reg (dboard_to_slot (which_dboard)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic_tx::read_io (int which_dboard, int *value)
+{
+ if (! (0 <= which_dboard && which_dboard <= 1))
+ return false;
+
+ int t;
+ int reg = which_dboard + 1; // FIXME, *very* magic number (fix in serial_io.v)
+ bool ok = _read_fpga_reg (reg, &t);
+ if (!ok)
+ return false;
+
+ *value = t & 0xffff; // FIXME, more magic
+ return true;
+}
+
+int
+usrp_basic_tx::read_io (int which_dboard)
+{
+ int value;
+ if (!read_io (which_dboard, &value))
+ return READ_FAILED;
+ return value;
+}
+
+bool
+usrp_basic_tx::write_aux_dac (int which_dboard, int which_dac, int value)
+{
+ return usrp_basic::write_aux_dac (dboard_to_slot (which_dboard),
+ which_dac, value);
+}
+
+bool
+usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc, int *value)
+{
+ return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard),
+ which_adc, value);
+}
+
+int
+usrp_basic_tx::read_aux_adc (int which_dboard, int which_adc)
+{
+ return usrp_basic::read_aux_adc (dboard_to_slot (which_dboard), which_adc);
+}
+
+int
+usrp_basic_tx::block_size () const { return d_ephandle->block_size(); }
+
diff --git a/usrp/host/lib/usrp_basic.h b/usrp/host/lib/usrp_basic.h
new file mode 100644
index 000000000..df775c5e9
--- /dev/null
+++ b/usrp/host/lib/usrp_basic.h
@@ -0,0 +1,776 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,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.
+ */
+
+/*
+ * ----------------------------------------------------------------------
+ * Mid level interface to the Universal Software Radio Peripheral (Rev 1)
+ *
+ * These classes implement the basic functionality for talking to the
+ * USRP. They try to be as independent of the signal processing code
+ * in FPGA as possible. They implement access to the low level
+ * peripherals on the board, provide a common way for reading and
+ * writing registers in the FPGA, and provide the high speed interface
+ * to streaming data across the USB.
+ *
+ * It is expected that subclasses will be derived that provide
+ * access to the functionality to a particular FPGA configuration.
+ * ----------------------------------------------------------------------
+ */
+
+#ifndef INCLUDED_USRP_BASIC_H
+#define INCLUDED_USRP_BASIC_H
+
+#include <usrp_slots.h>
+#include <string>
+
+struct usb_dev_handle;
+class fusb_devhandle;
+class fusb_ephandle;
+
+/*!
+ * \brief base class for usrp operations
+ */
+class usrp_basic
+{
+private:
+ // NOT IMPLEMENTED
+ usrp_basic (const usrp_basic &rhs); // no copy constructor
+ usrp_basic &operator= (const usrp_basic &rhs); // no assignment operator
+
+
+protected:
+ struct usb_dev_handle *d_udh;
+ int d_usb_data_rate; // bytes/sec
+ int d_bytes_per_poll; // how often to poll for overruns
+ bool d_verbose;
+
+ static const int MAX_REGS = 128;
+ unsigned int d_fpga_shadows[MAX_REGS];
+
+ usrp_basic (int which_board,
+ struct usb_dev_handle *open_interface (struct usb_device *dev),
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = "");
+
+ /*!
+ * \brief advise usrp_basic of usb data rate (bytes/sec)
+ *
+ * N.B., this doesn't tweak any hardware. Derived classes
+ * should call this to inform us of the data rate whenever it's
+ * first set or if it changes.
+ *
+ * \param usb_data_rate bytes/sec
+ */
+ void set_usb_data_rate (int usb_data_rate);
+
+ /*!
+ * \brief Write auxiliary digital to analog converter.
+ *
+ * \param slot Which Tx or Rx slot to write.
+ * 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 [0,3] RX slots must use only 0 and 1. TX slots must use only 2 and 3.
+ * \param value [0,4095]
+ * \returns true iff successful
+ */
+ bool write_aux_dac (int slot, int which_dac, int value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param slot 2-bit slot number. E.g., SLOT_TX_A
+ * \param which_adc [0,1]
+ * \param value return 12-bit value [0,4095]
+ * \returns true iff successful
+ */
+ bool read_aux_adc (int slot, int which_adc, int *value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param slot 2-bit slot number. E.g., SLOT_TX_A
+ * \param which_adc [0,1]
+ * \returns value in the range [0,4095] if successful, else READ_FAILED.
+ */
+ int read_aux_adc (int slot, int which_adc);
+
+public:
+ virtual ~usrp_basic ();
+
+ /*!
+ * \brief return frequency of master oscillator on USRP
+ */
+ long fpga_master_clock_freq () const { return 64000000; }
+
+ /*!
+ * \returns usb data rate in bytes/sec
+ */
+ int usb_data_rate () const { return d_usb_data_rate; }
+
+ void set_verbose (bool on) { d_verbose = on; }
+
+ //! magic value used on alternate register read interfaces
+ static const int READ_FAILED = -99999;
+
+ /*!
+ * \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 Read EEPROM on motherboard or any daughterboard.
+ * \param i2c_addr I2C bus address of EEPROM
+ * \param eeprom_offset byte offset in EEPROM to begin reading
+ * \param len number of bytes to read
+ * \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 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();
+
+ // ----------------------------------------------------------------
+ // Low level implementation routines.
+ // You probably shouldn't be using these...
+ //
+
+ bool _set_led (int which, bool on);
+
+ /*!
+ * \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
+ * \param value 32-bit value
+ * \returns true iff successful
+ */
+ bool _read_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 FPGA register with mask.
+ * \param regno 7-bit register number
+ * \param value 16-bit value
+ * \param mask 16-bit value
+ * \returns true if successful
+ * Only use this for registers who actually implement a mask in the verilog firmware, like FR_RX_MASTER_SLAVE
+ */
+ bool _write_fpga_reg_masked (int regno, int value, int mask);
+
+ /*!
+ * \brief Write AD9862 register.
+ * \param which_codec 0 or 1
+ * \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
+ * \param value 8-bit value
+ * \returns true iff successful
+ */
+ bool _read_9862 (int which_codec, int regno, unsigned char *value) const;
+
+ /*!
+ * \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);
+
+ /*!
+ * \brief Start data transfers.
+ * Called in base class to derived class order.
+ */
+ bool start ();
+
+ /*!
+ * \brief Stop data transfers.
+ * Called in base class to derived class order.
+ */
+ bool stop ();
+};
+
+ /*!
+ * \brief class for accessing the receive side of the USRP
+ */
+class usrp_basic_rx : public usrp_basic
+{
+private:
+ fusb_devhandle *d_devhandle;
+ fusb_ephandle *d_ephandle;
+ int d_bytes_seen; // how many bytes we've seen
+ bool d_first_read;
+ bool d_rx_enable;
+
+protected:
+ int d_dbid[2]; // Rx daughterboard ID's
+
+ /*!
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ */
+ usrp_basic_rx (int which_board,
+ int fusb_block_size=0,
+ int fusb_nblocks=0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ ); // throws if trouble
+
+ bool set_rx_enable (bool on);
+ bool rx_enable () const { return d_rx_enable; }
+
+ bool disable_rx (); // conditional disable, return prev state
+ void restore_rx (bool on); // conditional set
+
+ void probe_rx_slots (bool verbose);
+ int dboard_to_slot (int dboard) { return (dboard << 1) | 1; }
+
+public:
+ ~usrp_basic_rx ();
+
+ /*!
+ * \brief invokes constructor, returns instance or 0 if trouble
+ *
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ */
+ static usrp_basic_rx *make (int which_board,
+ int fusb_block_size=0,
+ int fusb_nblocks=0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+
+ // MANIPULATORS
+
+ /*!
+ * \brief tell the fpga the rate rx samples are coming from the A/D's
+ *
+ * div = fpga_master_clock_freq () / sample_rate
+ *
+ * sample_rate is determined by a myriad of registers
+ * in the 9862. That's why you have to tell us, so
+ * we can tell the fpga.
+ */
+ bool set_fpga_rx_sample_rate_divisor (unsigned int div);
+
+ /*!
+ * \brief read data from the D/A's via the FPGA.
+ * \p len must be a multiple of 512 bytes.
+ *
+ * \returns the number of bytes read, or -1 on error.
+ *
+ * If overrun is non-NULL it will be set true iff an RX overrun is detected.
+ */
+ int read (void *buf, int len, bool *overrun);
+
+ // ACCESSORS
+
+ //! sampling rate of A/D converter
+ virtual long converter_rate() const { return fpga_master_clock_freq(); } // 64M
+ long adc_rate() const { return converter_rate(); }
+ long adc_freq() const { return converter_rate(); } //!< deprecated method name
+
+ /*!
+ * \brief Return daughterboard ID for given Rx daughterboard slot [0,1].
+ *
+ * \param which_dboard [0,1] which Rx daughterboard
+ *
+ * \return daughterboard id >= 0 if successful
+ * \return -1 if no daugherboard
+ * \return -2 if invalid EEPROM on daughterboard
+ */
+ int daughterboard_id (int which_dboard) const { return d_dbid[which_dboard & 0x1]; }
+
+ // ----------------------------------------------------------------
+ // routines for controlling the Programmable Gain Amplifier
+ /*!
+ * \brief Set Programmable Gain Amplifier (PGA)
+ *
+ * \param which which A/D [0,3]
+ * \param gain_in_db gain value (linear in dB)
+ *
+ * gain is rounded to closest setting supported by hardware.
+ *
+ * \returns true iff sucessful.
+ *
+ * \sa pga_min(), pga_max(), pga_db_per_step()
+ */
+ bool set_pga (int which, double gain_in_db);
+
+ /*!
+ * \brief Return programmable gain amplifier gain setting in dB.
+ *
+ * \param which which A/D [0,3]
+ */
+ double pga (int which) const;
+
+ /*!
+ * \brief Return minimum legal PGA gain in dB.
+ */
+ double pga_min () const { return 0.0; }
+
+ /*!
+ * \brief Return maximum legal PGA gain in dB.
+ */
+ double pga_max () const { return 20.0; }
+
+ /*!
+ * \brief Return hardware step size of PGA (linear in dB).
+ */
+ double pga_db_per_step () const { return 20.0 / 20; }
+
+ /*!
+ * \brief Write direction register (output enables) for pins that go to daughterboard.
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ *
+ * Each d'board has 16-bits of general purpose i/o.
+ * Setting the bit makes it an output from the FPGA to the d'board.
+ *
+ * This register is initialized based on a value stored in the
+ * d'board EEPROM. In general, you shouldn't be using this routine
+ * without a very good reason. Using this method incorrectly will
+ * kill your USRP motherboard and/or daughterboard.
+ */
+ bool _write_oe (int which_dboard, int value, int mask);
+
+ /*!
+ * \brief Write daughterboard i/o pin value
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ */
+ bool write_io (int which_dboard, int value, int mask);
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param value output
+ */
+ bool read_io (int which_dboard, int *value);
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param which_dboard [0,1] which d'board
+ * \returns register value if successful, else READ_FAILED
+ */
+ int read_io (int which_dboard);
+
+ /*!
+ * \brief Write auxiliary digital to analog converter.
+ *
+ * \param which_dboard [0,1] which d'board
+ * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
+ * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
+ * \param which_dac [2,3] TX slots must use only 2 and 3.
+ * \param value [0,4095]
+ * \returns true iff successful
+ */
+ bool write_aux_dac (int which_board, int which_dac, int value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param which_adc [0,1]
+ * \param value return 12-bit value [0,4095]
+ * \returns true iff successful
+ */
+ bool read_aux_adc (int which_dboard, int which_adc, int *value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param which_adc [0,1]
+ * \returns value in the range [0,4095] if successful, else READ_FAILED.
+ */
+ int read_aux_adc (int which_dboard, int which_adc);
+
+ /*!
+ * \brief returns current fusb block size
+ */
+ int block_size() const;
+
+ /*!
+ * \brief Enable/disable automatic DC offset removal control loop in FPGA
+ *
+ * \param bits which control loops to enable
+ * \param mask which \p bits to pay attention to
+ *
+ * If the corresponding bit is set, enable the automatic DC
+ * offset correction control loop.
+ *
+ * <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);
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+ /*!
+ * \brief class for accessing the transmit side of the USRP
+ */
+class usrp_basic_tx : public usrp_basic
+{
+private:
+ fusb_devhandle *d_devhandle;
+ fusb_ephandle *d_ephandle;
+ int d_bytes_seen; // how many bytes we've seen
+ bool d_first_write;
+ bool d_tx_enable;
+
+ protected:
+ int d_dbid[2]; // Tx daughterboard ID's
+
+ /*!
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ */
+ usrp_basic_tx (int which_board,
+ int fusb_block_size=0,
+ int fusb_nblocks=0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ ); // throws if trouble
+
+ bool set_tx_enable (bool on);
+ bool tx_enable () const { return d_tx_enable; }
+
+ bool disable_tx (); // conditional disable, return prev state
+ void restore_tx (bool on); // conditional set
+
+ void probe_tx_slots (bool verbose);
+ int dboard_to_slot (int dboard) { return (dboard << 1) | 0; }
+
+public:
+
+ ~usrp_basic_tx ();
+
+ /*!
+ * \brief invokes constructor, returns instance or 0 if trouble
+ *
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ */
+ static usrp_basic_tx *make (int which_board, int fusb_block_size=0, int fusb_nblocks=0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+
+ // MANIPULATORS
+
+ /*!
+ * \brief tell the fpga the rate tx samples are going to the D/A's
+ *
+ * div = fpga_master_clock_freq () * 2
+ *
+ * sample_rate is determined by a myriad of registers
+ * in the 9862. That's why you have to tell us, so
+ * we can tell the fpga.
+ */
+ bool set_fpga_tx_sample_rate_divisor (unsigned int div);
+
+ /*!
+ * \brief Write data to the A/D's via the FPGA.
+ *
+ * \p len must be a multiple of 512 bytes.
+ * \returns number of bytes written or -1 on error.
+ *
+ * if \p underrun is non-NULL, it will be set to true iff
+ * a transmit underrun condition is detected.
+ */
+ int write (const void *buf, int len, bool *underrun);
+
+ /*
+ * Block until all outstanding writes have completed.
+ * This is typically used to assist with benchmarking
+ */
+ void wait_for_completion ();
+
+ // ACCESSORS
+
+ //! sampling rate of D/A converter
+ virtual long converter_rate() const { return fpga_master_clock_freq () * 2; } // 128M
+ long dac_rate() const { return converter_rate(); }
+ long dac_freq() const { return converter_rate(); } //!< deprecated method name
+
+ /*!
+ * \brief Return daughterboard ID for given Tx daughterboard slot [0,1].
+ *
+ * \return daughterboard id >= 0 if successful
+ * \return -1 if no daugherboard
+ * \return -2 if invalid EEPROM on daughterboard
+ */
+ int daughterboard_id (int which_dboard) const { return d_dbid[which_dboard & 0x1]; }
+
+ // ----------------------------------------------------------------
+ // routines for controlling the Programmable Gain Amplifier
+ /*!
+ * \brief Set Programmable Gain Amplifier (PGA)
+ *
+ * \param which which D/A [0,3]
+ * \param gain_in_db gain value (linear in dB)
+ *
+ * gain is rounded to closest setting supported by hardware.
+ * Note that DAC 0 and DAC 1 share a gain setting as do DAC 2 and DAC 3.
+ * Setting DAC 0 affects DAC 1 and vice versa. Same with DAC 2 and DAC 3.
+ *
+ * \returns true iff sucessful.
+ *
+ * \sa pga_min(), pga_max(), pga_db_per_step()
+ */
+ bool set_pga (int which, double gain_in_db);
+
+ /*!
+ * \brief Return programmable gain amplifier gain in dB.
+ *
+ * \param which which D/A [0,3]
+ */
+ double pga (int which) const;
+
+ /*!
+ * \brief Return minimum legal PGA gain in dB.
+ */
+ double pga_min () const { return -20.0; }
+
+ /*!
+ * \brief Return maximum legal PGA gain in dB.
+ */
+ double pga_max () const { return 0.0; }
+
+ /*!
+ * \brief Return hardware step size of PGA (linear in dB).
+ */
+ double pga_db_per_step () const { return 20.0/255; }
+
+ /*!
+ * \brief Write direction register (output enables) for pins that go to daughterboard.
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ *
+ * Each d'board has 16-bits of general purpose i/o.
+ * Setting the bit makes it an output from the FPGA to the d'board.
+ *
+ * This register is initialized based on a value stored in the
+ * d'board EEPROM. In general, you shouldn't be using this routine
+ * without a very good reason. Using this method incorrectly will
+ * kill your USRP motherboard and/or daughterboard.
+ */
+ bool _write_oe (int which_dboard, int value, int mask);
+
+ /*!
+ * \brief Write daughterboard i/o pin value
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ */
+ bool write_io (int which_dboard, int value, int mask);
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param value return value
+ */
+ bool read_io (int which_dboard, int *value);
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param which_dboard [0,1] which d'board
+ * \returns register value if successful, else READ_FAILED
+ */
+ int read_io (int which_dboard);
+
+ /*!
+ * \brief Write auxiliary digital to analog converter.
+ *
+ * \param which_dboard [0,1] which d'board
+ * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
+ * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
+ * \param which_dac [2,3] TX slots must use only 2 and 3.
+ * \param value [0,4095]
+ * \returns true iff successful
+ */
+ bool write_aux_dac (int which_board, int which_dac, int value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param which_adc [0,1]
+ * \param value return 12-bit value [0,4095]
+ * \returns true iff successful
+ */
+ bool read_aux_adc (int which_dboard, int which_adc, int *value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param which_dboard [0,1] which d'board
+ * \param which_adc [0,1]
+ * \returns value in the range [0,4095] if successful, else READ_FAILED.
+ */
+ int read_aux_adc (int which_dboard, int which_adc);
+
+ /*!
+ * \brief returns current fusb block size
+ */
+ int block_size() const;
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+#endif
diff --git a/usrp/host/lib/usrp_bytesex.h b/usrp/host/lib/usrp_bytesex.h
new file mode 100644
index 000000000..de34c053d
--- /dev/null
+++ b/usrp/host/lib/usrp_bytesex.h
@@ -0,0 +1,74 @@
+/* -*- 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_USRP_BYTESEX_H
+#define INCLUDED_USRP_BYTESEX_H
+
+/*!
+ * \brief routines for convertering between host and usrp byte order
+ *
+ * Prior to including this file, the user must include "config.h"
+ * which will or won't define WORDS_BIGENDIAN based on the
+ * result of the AC_C_BIGENDIAN autoconf test.
+ */
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+static inline unsigned short int
+bswap_16 (unsigned short int x)
+{
+ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+#endif
+
+
+#ifdef WORDS_BIGENDIAN
+
+static inline short int
+host_to_usrp_short (short int x)
+{
+ return bswap_16 (x);
+}
+
+static inline short int
+usrp_to_host_short (short int x)
+{
+ return bswap_16 (x);
+}
+
+#else
+
+static inline short int
+host_to_usrp_short (short int x)
+{
+ return x;
+}
+
+static inline short int
+usrp_to_host_short (unsigned short int x)
+{
+ return x;
+}
+
+#endif
+
+#endif /* INCLUDED_USRP_BYTESEX_H */
diff --git a/usrp/host/lib/usrp_config.cc b/usrp/host/lib/usrp_config.cc
new file mode 100644
index 000000000..04303cd8d
--- /dev/null
+++ b/usrp/host/lib/usrp_config.cc
@@ -0,0 +1,35 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 "usrp_config.h"
+
+int
+usrp_rx_config_stream_count (unsigned int usrp_rx_config)
+{
+ return 1;
+}
+
+int
+usrp_tx_config_stream_count (unsigned int usrp_tx_config)
+{
+ return 1;
+}
diff --git a/usrp/host/lib/usrp_config.h b/usrp/host/lib/usrp_config.h
new file mode 100644
index 000000000..3675a108a
--- /dev/null
+++ b/usrp/host/lib/usrp_config.h
@@ -0,0 +1,67 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003 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 _USRP_CONFIG_H_
+#define _USRP_CONFIG_H_
+
+/*
+ * ----------------------------------------------------------------
+ * USRP Rx configurations.
+ *
+ * For now this is a placeholder, but will eventually specify the
+ * mapping from A/D outputs to DDC inputs (I & Q).
+ *
+ * What's implemented today is a single DDC that has its I input
+ * connected to ADC0 and its Q input connected to ADC1
+ * ----------------------------------------------------------------
+ */
+
+#define USRP_RX_CONFIG_DEFAULT 0
+
+/*!
+ * given a usrp_rx_config word, return the number of I & Q streams that
+ * are interleaved on the USB.
+ */
+
+int usrp_rx_config_stream_count (unsigned int usrp_rx_config);
+
+/*
+ * USRP Tx configurations.
+ *
+ * For now this is a placeholder, but will eventually specify the
+ * mapping from DUC outputs to D/A inputs.
+ *
+ * What's implemented today is a single DUC that has its I output
+ * connected to DAC0 and its Q output connected to DAC1
+ */
+
+#define USRP_TX_CONFIG_DEFAULT 0
+
+/*!
+ * given a usrp_tx_config word, return the number of I & Q streams that
+ * are interleaved on the USB.
+ */
+
+int usrp_tx_config_stream_count (unsigned int usrp_tx_config);
+
+
+#endif /* _USRP_CONFIG_H_ */
diff --git a/usrp/host/lib/usrp_dbid.dat b/usrp/host/lib/usrp_dbid.dat
new file mode 100644
index 000000000..fe3ed1e07
--- /dev/null
+++ b/usrp/host/lib/usrp_dbid.dat
@@ -0,0 +1,75 @@
+#
+# 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.
+#
+
+# This file is used to generate usrp_dbid.h, usrp_dbid.cc and usrp_dbid.py
+
+"Basic Tx" 0x0000
+"Basic Rx" 0x0001
+"DBS Rx" 0x0002
+"TV Rx" 0x0003
+
+"Flex 400 Rx" 0x0004
+"Flex 900 Rx" 0x0005
+"Flex 1200 Rx" 0x0006
+"Flex 2400 Rx" 0x0007
+
+"Flex 400 Tx" 0x0008
+"Flex 900 Tx" 0x0009
+"Flex 1200 Tx" 0x000a
+"Flex 2400 Tx" 0x000b
+
+"TV Rx Rev 2" 0x000c
+"DBS Rx Rev 2_1" 0x000d
+
+"LF Tx" 0x000e
+"LF Rx" 0x000f
+
+"Flex 400 Rx MIMO A" 0x0014
+"Flex 900 Rx MIMO A" 0x0015
+"Flex 1200 Rx MIMO A" 0x0016
+"Flex 2400 Rx MIMO A" 0x0017
+
+"Flex 400 Tx MIMO A" 0x0018
+"Flex 900 Tx MIMO A" 0x0019
+"Flex 1200 Tx MIMO A" 0x001a
+"Flex 2400 Tx MIMO A" 0x001b
+
+"Flex 400 Rx MIMO B" 0x0024
+"Flex 900 Rx MIMO B" 0x0025
+"Flex 1200 Rx MIMO B" 0x0026
+"Flex 2400 Rx MIMO B" 0x0027
+
+"Flex 400 Tx MIMO B" 0x0028
+"Flex 900 Tx MIMO B" 0x0029
+"Flex 1200 Tx MIMO B" 0x002a
+"Flex 2400 Tx MIMO B" 0x002b
+
+"Flex 1800 Rx" 0x0030
+"Flex 1800 Tx" 0x0031
+"Flex 1800 Rx MIMO A" 0x0032
+"Flex 1800 Tx MIMO A" 0x0033
+"Flex 1800 Rx MIMO B" 0x0034
+"Flex 1800 Tx MIMO B" 0x0035
+
+"TV Rx Rev 3" 0x0040
+
+"Experimental Tx" 0xfffe
+"Experimental Rx" 0xffff
diff --git a/usrp/host/lib/usrp_local_sighandler.cc b/usrp/host/lib/usrp_local_sighandler.cc
new file mode 100644
index 000000000..567d7d069
--- /dev/null
+++ b/usrp/host/lib/usrp_local_sighandler.cc
@@ -0,0 +1,190 @@
+/* -*- 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.
+ */
+
+/*
+ * This is actually the same as gr_local_signhandler, but with a different name.
+ * We don't have a common library to put this in, so...
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp_local_sighandler.h>
+#include <stdexcept>
+#include <stdio.h>
+
+usrp_local_sighandler::usrp_local_sighandler (int signum,
+ void (*new_handler)(int))
+ : d_signum (signum)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction new_action;
+ memset (&new_action, 0, sizeof (new_action));
+
+ new_action.sa_handler = new_handler;
+ sigemptyset (&new_action.sa_mask);
+ new_action.sa_flags = 0;
+
+ if (sigaction (d_signum, &new_action, &d_old_action) < 0){
+ perror ("sigaction (install new)");
+ throw std::runtime_error ("sigaction");
+ }
+#endif
+}
+
+usrp_local_sighandler::~usrp_local_sighandler ()
+{
+#ifdef HAVE_SIGACTION
+ if (sigaction (d_signum, &d_old_action, 0) < 0){
+ perror ("sigaction (restore old)");
+ throw std::runtime_error ("sigaction");
+ }
+#endif
+}
+
+void
+usrp_local_sighandler::throw_signal(int signum) throw(usrp_signal)
+{
+ throw usrp_signal (signum);
+}
+
+/*
+ * Semi-hideous way to may a signal number into a signal name
+ */
+
+#define SIGNAME(x) case x: return #x
+
+std::string
+usrp_signal::name () const
+{
+ char tmp[128];
+
+ switch (signal ()){
+#ifdef SIGHUP
+ SIGNAME (SIGHUP);
+#endif
+#ifdef SIGINT
+ SIGNAME (SIGINT);
+#endif
+#ifdef SIGQUIT
+ SIGNAME (SIGQUIT);
+#endif
+#ifdef SIGILL
+ SIGNAME (SIGILL);
+#endif
+#ifdef SIGTRAP
+ SIGNAME (SIGTRAP);
+#endif
+#ifdef SIGABRT
+ SIGNAME (SIGABRT);
+#endif
+#ifdef SIGBUS
+ SIGNAME (SIGBUS);
+#endif
+#ifdef SIGFPE
+ SIGNAME (SIGFPE);
+#endif
+#ifdef SIGKILL
+ SIGNAME (SIGKILL);
+#endif
+#ifdef SIGUSR1
+ SIGNAME (SIGUSR1);
+#endif
+#ifdef SIGSEGV
+ SIGNAME (SIGSEGV);
+#endif
+#ifdef SIGUSR2
+ SIGNAME (SIGUSR2);
+#endif
+#ifdef SIGPIPE
+ SIGNAME (SIGPIPE);
+#endif
+#ifdef SIGALRM
+ SIGNAME (SIGALRM);
+#endif
+#ifdef SIGTERM
+ SIGNAME (SIGTERM);
+#endif
+#ifdef SIGSTKFLT
+ SIGNAME (SIGSTKFLT);
+#endif
+#ifdef SIGCHLD
+ SIGNAME (SIGCHLD);
+#endif
+#ifdef SIGCONT
+ SIGNAME (SIGCONT);
+#endif
+#ifdef SIGSTOP
+ SIGNAME (SIGSTOP);
+#endif
+#ifdef SIGTSTP
+ SIGNAME (SIGTSTP);
+#endif
+#ifdef SIGTTIN
+ SIGNAME (SIGTTIN);
+#endif
+#ifdef SIGTTOU
+ SIGNAME (SIGTTOU);
+#endif
+#ifdef SIGURG
+ SIGNAME (SIGURG);
+#endif
+#ifdef SIGXCPU
+ SIGNAME (SIGXCPU);
+#endif
+#ifdef SIGXFSZ
+ SIGNAME (SIGXFSZ);
+#endif
+#ifdef SIGVTALRM
+ SIGNAME (SIGVTALRM);
+#endif
+#ifdef SIGPROF
+ SIGNAME (SIGPROF);
+#endif
+#ifdef SIGWINCH
+ SIGNAME (SIGWINCH);
+#endif
+#ifdef SIGIO
+ SIGNAME (SIGIO);
+#endif
+#ifdef SIGPWR
+ SIGNAME (SIGPWR);
+#endif
+#ifdef SIGSYS
+ SIGNAME (SIGSYS);
+#endif
+ default:
+#if defined (HAVE_SNPRINTF)
+#if defined (SIGRTMIN) && defined (SIGRTMAX)
+ if (signal () >= SIGRTMIN && signal () <= SIGRTMAX){
+ snprintf (tmp, sizeof (tmp), "SIGRTMIN + %d", signal ());
+ return tmp;
+ }
+#endif
+ snprintf (tmp, sizeof (tmp), "SIGNAL %d", signal ());
+ return tmp;
+#else
+ return "Unknown signal";
+#endif
+ }
+}
diff --git a/usrp/host/lib/usrp_local_sighandler.h b/usrp/host/lib/usrp_local_sighandler.h
new file mode 100644
index 000000000..0bb29c2b2
--- /dev/null
+++ b/usrp/host/lib/usrp_local_sighandler.h
@@ -0,0 +1,61 @@
+/* -*- 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_USRP_LOCAL_SIGHANDLER_H
+#define INCLUDED_USRP_LOCAL_SIGHANDLER_H
+
+#include <signal.h>
+#include <string>
+
+/*!
+ * \brief Representation of signal.
+ */
+class usrp_signal
+{
+ int d_signum;
+public:
+ usrp_signal (int signum) : d_signum (signum) {}
+ int signal () const { return d_signum; }
+ std::string name () const;
+};
+
+
+/*!
+ * \brief Get and set signal handler.
+ *
+ * Constructor installs new handler, destructor reinstalls
+ * original value.
+ */
+class usrp_local_sighandler {
+ int d_signum;
+#ifdef HAVE_SIGACTION
+ struct sigaction d_old_action;
+#endif
+public:
+ usrp_local_sighandler (int signum, void (*new_handler)(int));
+ ~usrp_local_sighandler ();
+
+ /* throw usrp_signal (signum) */
+ static void throw_signal (int signum) throw (usrp_signal);
+};
+
+#endif /* INCLUDED_USRP_LOCAL_SIGHANDLER_H */
diff --git a/usrp/host/lib/usrp_prims.cc b/usrp/host/lib/usrp_prims.cc
new file mode 100644
index 000000000..5d1c26da6
--- /dev/null
+++ b/usrp/host/lib/usrp_prims.cc
@@ -0,0 +1,1355 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,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 "usrp_prims.h"
+#include "usrp_commands.h"
+#include "usrp_ids.h"
+#include "usrp_i2c_addr.h"
+#include "fpga_regs_common.h"
+#include "fpga_regs_standard.h"
+#include <usb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h> // FIXME should check with autoconf (nanosleep)
+#include <algorithm>
+#include <ad9862.h>
+#include <assert.h>
+
+extern "C" {
+#include "md5.h"
+};
+
+#define VERBOSE 0
+
+using namespace ad9862;
+
+static const int FIRMWARE_HASH_SLOT = 0;
+static const int FPGA_HASH_SLOT = 1;
+
+static const int hash_slot_addr[2] = {
+ USRP_HASH_SLOT_0_ADDR,
+ USRP_HASH_SLOT_1_ADDR
+};
+
+static char *default_firmware_filename = "std.ihx";
+static char *default_fpga_filename = "std_2rxhb_2tx.rbf";
+
+#include "std_paths.h"
+
+static char *
+find_file (const char *filename, int hw_rev)
+{
+ char **sp = std_paths;
+ static char path[1000];
+ char *s;
+
+ s = getenv("USRP_PATH");
+ if (s) {
+ snprintf (path, sizeof (path), "%s/rev%d/%s", s, hw_rev, filename);
+ if (access (path, R_OK) == 0)
+ return path;
+ }
+
+ while (*sp){
+ snprintf (path, sizeof (path), "%s/rev%d/%s", *sp, hw_rev, filename);
+ if (access (path, R_OK) == 0)
+ return path;
+ sp++;
+ }
+ return 0;
+}
+
+static const char *
+get_proto_filename(const std::string user_filename, const char *env_var, const char *def)
+{
+ if (user_filename.length() != 0)
+ return user_filename.c_str();
+
+ char *s = getenv(env_var);
+ if (s && *s)
+ return s;
+
+ return def;
+}
+
+
+static void power_down_9862s (struct usb_dev_handle *udh);
+
+void
+usrp_one_time_init ()
+{
+ static bool first = true;
+
+ if (first){
+ first = false;
+ usb_init (); // usb library init
+ usb_find_busses ();
+ usb_find_devices ();
+ }
+}
+
+void
+usrp_rescan ()
+{
+ usb_find_busses ();
+ usb_find_devices ();
+}
+
+
+// ----------------------------------------------------------------
+// Danger, big, fragile KLUDGE. The problem is that we want to be
+// able to get from a usb_dev_handle back to a usb_device, and the
+// right way to do this is buried in a non-installed include file.
+
+static struct usb_device *
+dev_handle_to_dev (usb_dev_handle *udh)
+{
+ struct usb_dev_handle_kludge {
+ int fd;
+ struct usb_bus *bus;
+ struct usb_device *device;
+ };
+
+ return ((struct usb_dev_handle_kludge *) udh)->device;
+}
+
+// ----------------------------------------------------------------
+
+/*
+ * q must be a real USRP, not an FX2. Return its hardware rev number.
+ */
+int
+usrp_hw_rev (struct usb_device *q)
+{
+ return q->descriptor.bcdDevice & 0x00FF;
+}
+
+/*
+ * q must be a real USRP, not an FX2. Return true if it's configured.
+ */
+static bool
+_usrp_configured_p (struct usb_device *q)
+{
+ return (q->descriptor.bcdDevice & 0xFF00) != 0;
+}
+
+bool
+usrp_usrp_p (struct usb_device *q)
+{
+ return (q->descriptor.idVendor == USB_VID_FSF
+ && q->descriptor.idProduct == USB_PID_FSF_USRP);
+}
+
+bool
+usrp_fx2_p (struct usb_device *q)
+{
+ return (q->descriptor.idVendor == USB_VID_CYPRESS
+ && q->descriptor.idProduct == USB_PID_CYPRESS_FX2);
+}
+
+bool
+usrp_usrp0_p (struct usb_device *q)
+{
+ return usrp_usrp_p (q) && usrp_hw_rev (q) == 0;
+}
+
+bool
+usrp_usrp1_p (struct usb_device *q)
+{
+ return usrp_usrp_p (q) && usrp_hw_rev (q) == 1;
+}
+
+bool
+usrp_usrp2_p (struct usb_device *q)
+{
+ return usrp_usrp_p (q) && usrp_hw_rev (q) == 2;
+}
+
+
+bool
+usrp_unconfigured_usrp_p (struct usb_device *q)
+{
+ return usrp_usrp_p (q) && !_usrp_configured_p (q);
+}
+
+bool
+usrp_configured_usrp_p (struct usb_device *q)
+{
+ return usrp_usrp_p (q) && _usrp_configured_p (q);
+}
+
+// ----------------------------------------------------------------
+
+struct usb_device *
+usrp_find_device (int nth, bool fx2_ok_p)
+{
+ struct usb_bus *p;
+ struct usb_device *q;
+ int n_found = 0;
+
+ usrp_one_time_init ();
+
+ p = usb_get_busses();
+ while (p != NULL){
+ q = p->devices;
+ while (q != NULL){
+ if (usrp_usrp_p (q) || (fx2_ok_p && usrp_fx2_p (q))){
+ if (n_found == nth) // return this one
+ return q;
+ n_found++; // keep looking
+ }
+ q = q->next;
+ }
+ p = p->next;
+ }
+ return 0; // not found
+}
+
+static struct usb_dev_handle *
+usrp_open_interface (struct usb_device *dev, int interface, int altinterface)
+{
+ struct usb_dev_handle *udh = usb_open (dev);
+ if (udh == 0)
+ return 0;
+
+ if (dev != dev_handle_to_dev (udh)){
+ fprintf (stderr, "%s:%d: internal error!\n", __FILE__, __LINE__);
+ abort ();
+ }
+
+#if defined(WIN32)
+ // There's no get get_configuration function, and with some of the newer kernels
+ // setting the configuration, even if to the same value, hoses any other processes
+ // that have it open. Hence we opt to not set it at all (We've only
+ // got a single configuration anyway). This may hose the win32 stuff...
+
+ if (usb_set_configuration (udh, 1) < 0){
+ /*
+ * Ignore this error.
+ *
+ * Seems that something changed in drivers/usb/core/devio.c:proc_setconfig such that
+ * it returns -EBUSY if _any_ of the interfaces of a device are open.
+ * We've only got a single configuration, so setting it doesn't even seem
+ * like it should be required.
+ */
+ }
+#endif
+
+ if (usb_claim_interface (udh, interface) < 0){
+ fprintf (stderr, "%s:usb_claim_interface: failed interface %d\n", __FUNCTION__,interface);
+ fprintf (stderr, "%s\n", usb_strerror());
+ usb_close (udh);
+ return 0;
+ }
+
+ if (usb_set_altinterface (udh, altinterface) < 0){
+ fprintf (stderr, "%s:usb_set_alt_interface: failed\n", __FUNCTION__);
+ fprintf (stderr, "%s\n", usb_strerror());
+ usb_release_interface (udh, interface);
+ usb_close (udh);
+ return 0;
+ }
+
+ return udh;
+}
+
+struct usb_dev_handle *
+usrp_open_cmd_interface (struct usb_device *dev)
+{
+ return usrp_open_interface (dev, USRP_CMD_INTERFACE, USRP_CMD_ALTINTERFACE);
+}
+
+struct usb_dev_handle *
+usrp_open_rx_interface (struct usb_device *dev)
+{
+ return usrp_open_interface (dev, USRP_RX_INTERFACE, USRP_RX_ALTINTERFACE);
+}
+
+struct usb_dev_handle *
+usrp_open_tx_interface (struct usb_device *dev)
+{
+ return usrp_open_interface (dev, USRP_TX_INTERFACE, USRP_TX_ALTINTERFACE);
+}
+
+bool
+usrp_close_interface (struct usb_dev_handle *udh)
+{
+ // we're assuming that closing an interface automatically releases it.
+ return usb_close (udh) == 0;
+}
+
+// ----------------------------------------------------------------
+// write internal ram using Cypress vendor extension
+
+static bool
+write_internal_ram (struct usb_dev_handle *udh, unsigned char *buf,
+ int start_addr, size_t len)
+{
+ int addr;
+ int n;
+ int a;
+ int quanta = MAX_EP0_PKTSIZE;
+
+ for (addr = start_addr; addr < start_addr + (int) len; addr += quanta){
+ n = len + start_addr - addr;
+ if (n > quanta)
+ n = quanta;
+
+ a = usb_control_msg (udh, 0x40, 0xA0,
+ addr, 0, (char *)(buf + (addr - start_addr)), n, 1000);
+
+ if (a < 0){
+ fprintf(stderr,"write_internal_ram failed: %s\n", usb_strerror());
+ return false;
+ }
+ }
+ return true;
+}
+
+// ----------------------------------------------------------------
+// whack the CPUCS register using the upload RAM vendor extension
+
+static bool
+reset_cpu (struct usb_dev_handle *udh, bool reset_p)
+{
+ unsigned char v;
+
+ if (reset_p)
+ v = 1; // hold processor in reset
+ else
+ v = 0; // release reset
+
+ return write_internal_ram (udh, &v, 0xE600, 1);
+}
+
+// ----------------------------------------------------------------
+// Load intel format file into cypress FX2 (8051)
+
+static bool
+_usrp_load_firmware (struct usb_dev_handle *udh, const char *filename,
+ unsigned char hash[USRP_HASH_SIZE])
+{
+ FILE *f = fopen (filename, "ra");
+ if (f == 0){
+ perror (filename);
+ return false;
+ }
+
+ if (!reset_cpu (udh, true)) // hold CPU in reset while loading firmware
+ goto fail;
+
+
+ char s[1024];
+ int length;
+ int addr;
+ int type;
+ unsigned char data[256];
+ unsigned char checksum, a;
+ unsigned int b;
+ int i;
+
+ while (!feof(f)){
+ fgets(s, sizeof (s), f); /* we should not use more than 263 bytes normally */
+ if(s[0]!=':'){
+ fprintf(stderr,"%s: invalid line: \"%s\"\n", filename, s);
+ goto fail;
+ }
+ sscanf(s+1, "%02x", &length);
+ sscanf(s+3, "%04x", &addr);
+ sscanf(s+7, "%02x", &type);
+
+ if(type==0){
+
+ a=length+(addr &0xff)+(addr>>8)+type;
+ for(i=0;i<length;i++){
+ sscanf (s+9+i*2,"%02x", &b);
+ data[i]=b;
+ a=a+data[i];
+ }
+
+ sscanf (s+9+length*2,"%02x", &b);
+ checksum=b;
+ if (((a+checksum)&0xff)!=0x00){
+ fprintf (stderr, " ** Checksum failed: got 0x%02x versus 0x%02x\n", (-a)&0xff, checksum);
+ goto fail;
+ }
+ if (!write_internal_ram (udh, data, addr, length))
+ goto fail;
+ }
+ else if (type == 0x01){ // EOF
+ break;
+ }
+ else if (type == 0x02){
+ fprintf(stderr, "Extended address: whatever I do with it?\n");
+ fprintf (stderr, "%s: invalid line: \"%s\"\n", filename, s);
+ goto fail;
+ }
+ }
+
+ // we jam the hash value into the FX2 memory before letting
+ // the cpu out of reset. When it comes out of reset it
+ // may renumerate which will invalidate udh.
+
+ if (!usrp_set_hash (udh, FIRMWARE_HASH_SLOT, hash))
+ fprintf (stderr, "usrp: failed to write firmware hash slot\n");
+
+ if (!reset_cpu (udh, false)) // take CPU out of reset
+ goto fail;
+
+ fclose (f);
+ return true;
+
+ fail:
+ fclose (f);
+ return false;
+}
+
+// ----------------------------------------------------------------
+// write vendor extension command to USRP
+
+static int
+write_cmd (struct usb_dev_handle *udh,
+ int request, int value, int index,
+ unsigned char *bytes, int len)
+{
+ int requesttype = (request & 0x80) ? VRT_VENDOR_IN : VRT_VENDOR_OUT;
+
+ int r = usb_control_msg (udh, requesttype, request, value, index,
+ (char *) bytes, len, 1000);
+ if (r < 0){
+ // we get EPIPE if the firmware stalls the endpoint.
+ if (errno != EPIPE)
+ fprintf (stderr, "usb_control_msg failed: %s\n", usb_strerror ());
+ }
+
+ return r;
+}
+
+// ----------------------------------------------------------------
+// load fpga
+
+static bool
+_usrp_load_fpga (struct usb_dev_handle *udh, const char *filename,
+ unsigned char hash[USRP_HASH_SIZE])
+{
+ bool ok = true;
+
+ FILE *fp = fopen (filename, "rb");
+ if (fp == 0){
+ perror (filename);
+ return false;
+ }
+
+ unsigned char buf[MAX_EP0_PKTSIZE]; // 64 is max size of EP0 packet on FX2
+ int n;
+
+ usrp_set_led (udh, 1, 1); // led 1 on
+
+
+ // reset FPGA (and on rev1 both AD9862's, thus killing clock)
+ usrp_set_fpga_reset (udh, 1); // hold fpga in reset
+
+ if (write_cmd (udh, VRQ_FPGA_LOAD, 0, FL_BEGIN, 0, 0) != 0)
+ goto fail;
+
+ while ((n = fread (buf, 1, sizeof (buf), fp)) > 0){
+ if (write_cmd (udh, VRQ_FPGA_LOAD, 0, FL_XFER, buf, n) != n)
+ goto fail;
+ }
+
+ if (write_cmd (udh, VRQ_FPGA_LOAD, 0, FL_END, 0, 0) != 0)
+ goto fail;
+
+ fclose (fp);
+
+ if (!usrp_set_hash (udh, FPGA_HASH_SLOT, hash))
+ fprintf (stderr, "usrp: failed to write fpga hash slot\n");
+
+ // On the rev1 USRP, the {tx,rx}_{enable,reset} bits are
+ // controlled over the serial bus, and hence aren't observed until
+ // we've got a good fpga bitstream loaded.
+
+ usrp_set_fpga_reset (udh, 0); // fpga out of master reset
+
+ // now these commands will work
+
+ ok &= usrp_set_fpga_tx_enable (udh, 0);
+ ok &= usrp_set_fpga_rx_enable (udh, 0);
+
+ ok &= usrp_set_fpga_tx_reset (udh, 1); // reset tx and rx paths
+ ok &= usrp_set_fpga_rx_reset (udh, 1);
+ ok &= usrp_set_fpga_tx_reset (udh, 0); // reset tx and rx paths
+ ok &= usrp_set_fpga_rx_reset (udh, 0);
+
+ if (!ok)
+ fprintf (stderr, "usrp: failed to reset tx and/or rx path\n");
+
+ // Manually reset all regs except master control to zero.
+ // FIXME may want to remove this when we rework FPGA reset strategy.
+ // In the mean while, this gets us reproducible behavior.
+ for (int i = 0; i < FR_USER_0; i++){
+ if (i == FR_MASTER_CTRL)
+ continue;
+ usrp_write_fpga_reg(udh, i, 0);
+ }
+
+ power_down_9862s (udh); // on the rev1, power these down!
+ usrp_set_led (udh, 1, 0); // led 1 off
+
+ return true;
+
+ fail:
+ power_down_9862s (udh); // on the rev1, power these down!
+ fclose (fp);
+ return false;
+}
+
+// ----------------------------------------------------------------
+
+bool
+usrp_set_led (struct usb_dev_handle *udh, int which, bool on)
+{
+ int r = write_cmd (udh, VRQ_SET_LED, on, which, 0, 0);
+
+ return r == 0;
+}
+
+bool
+usrp_set_hash (struct usb_dev_handle *udh, int which,
+ const unsigned char hash[USRP_HASH_SIZE])
+{
+ which &= 1;
+
+ // we use the Cypress firmware down load command to jam it in.
+ int r = usb_control_msg (udh, 0x40, 0xa0, hash_slot_addr[which], 0,
+ (char *) hash, USRP_HASH_SIZE, 1000);
+ return r == USRP_HASH_SIZE;
+}
+
+bool
+usrp_get_hash (struct usb_dev_handle *udh, int which,
+ unsigned char hash[USRP_HASH_SIZE])
+{
+ which &= 1;
+
+ // we use the Cypress firmware upload command to fetch it.
+ int r = usb_control_msg (udh, 0xc0, 0xa0, hash_slot_addr[which], 0,
+ (char *) hash, USRP_HASH_SIZE, 1000);
+ return r == USRP_HASH_SIZE;
+}
+
+static bool
+usrp_set_switch (struct usb_dev_handle *udh, int cmd_byte, bool on)
+{
+ return write_cmd (udh, cmd_byte, on, 0, 0, 0) == 0;
+}
+
+
+static bool
+usrp1_fpga_write (struct usb_dev_handle *udh,
+ int regno, int value)
+{
+ // on the rev1 usrp, we use the generic spi_write interface
+
+ unsigned char buf[4];
+
+ buf[0] = (value >> 24) & 0xff; // MSB first
+ buf[1] = (value >> 16) & 0xff;
+ buf[2] = (value >> 8) & 0xff;
+ buf[3] = (value >> 0) & 0xff;
+
+ return usrp_spi_write (udh, 0x00 | (regno & 0x7f),
+ SPI_ENABLE_FPGA,
+ SPI_FMT_MSB | SPI_FMT_HDR_1,
+ buf, sizeof (buf));
+}
+
+static bool
+usrp1_fpga_read (struct usb_dev_handle *udh,
+ int regno, int *value)
+{
+ *value = 0;
+ unsigned char buf[4];
+
+ bool ok = usrp_spi_read (udh, 0x80 | (regno & 0x7f),
+ SPI_ENABLE_FPGA,
+ SPI_FMT_MSB | SPI_FMT_HDR_1,
+ buf, sizeof (buf));
+
+ if (ok)
+ *value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+
+ return ok;
+}
+
+
+bool
+usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value)
+{
+ switch (usrp_hw_rev (dev_handle_to_dev (udh))){
+ case 0: // not supported ;)
+ abort();
+
+ default:
+ return usrp1_fpga_write (udh, reg, value);
+ }
+}
+
+bool
+usrp_read_fpga_reg (struct usb_dev_handle *udh, int reg, int *value)
+{
+ switch (usrp_hw_rev (dev_handle_to_dev (udh))){
+ case 0: // not supported ;)
+ abort();
+
+ default:
+ return usrp1_fpga_read (udh, reg, value);
+ }
+}
+
+bool
+usrp_set_fpga_reset (struct usb_dev_handle *udh, bool on)
+{
+ return usrp_set_switch (udh, VRQ_FPGA_SET_RESET, on);
+}
+
+bool
+usrp_set_fpga_tx_enable (struct usb_dev_handle *udh, bool on)
+{
+ return usrp_set_switch (udh, VRQ_FPGA_SET_TX_ENABLE, on);
+}
+
+bool
+usrp_set_fpga_rx_enable (struct usb_dev_handle *udh, bool on)
+{
+ return usrp_set_switch (udh, VRQ_FPGA_SET_RX_ENABLE, on);
+}
+
+bool
+usrp_set_fpga_tx_reset (struct usb_dev_handle *udh, bool on)
+{
+ return usrp_set_switch (udh, VRQ_FPGA_SET_TX_RESET, on);
+}
+
+bool
+usrp_set_fpga_rx_reset (struct usb_dev_handle *udh, bool on)
+{
+ return usrp_set_switch (udh, VRQ_FPGA_SET_RX_RESET, on);
+}
+
+
+// ----------------------------------------------------------------
+// conditional load stuff
+
+static bool
+compute_hash (const char *filename, unsigned char hash[USRP_HASH_SIZE])
+{
+ assert (USRP_HASH_SIZE == 16);
+ memset (hash, 0, USRP_HASH_SIZE);
+
+ FILE *fp = fopen (filename, "rb");
+ if (fp == 0){
+ perror (filename);
+ return false;
+ }
+ int r = md5_stream (fp, hash);
+ fclose (fp);
+
+ return r == 0;
+}
+
+static usrp_load_status_t
+usrp_conditionally_load_something (struct usb_dev_handle *udh,
+ const char *filename,
+ bool force,
+ int slot,
+ bool loader (struct usb_dev_handle *,
+ const char *,
+ unsigned char [USRP_HASH_SIZE]))
+{
+ unsigned char file_hash[USRP_HASH_SIZE];
+ unsigned char usrp_hash[USRP_HASH_SIZE];
+
+ if (access (filename, R_OK) != 0){
+ perror (filename);
+ return ULS_ERROR;
+ }
+
+ if (!compute_hash (filename, file_hash))
+ return ULS_ERROR;
+
+ if (!force
+ && usrp_get_hash (udh, slot, usrp_hash)
+ && memcmp (file_hash, usrp_hash, USRP_HASH_SIZE) == 0)
+ return ULS_ALREADY_LOADED;
+
+ bool r = loader (udh, filename, file_hash);
+
+ if (!r)
+ return ULS_ERROR;
+
+ return ULS_OK;
+}
+
+usrp_load_status_t
+usrp_load_firmware (struct usb_dev_handle *udh,
+ const char *filename,
+ bool force)
+{
+ return usrp_conditionally_load_something (udh, filename, force,
+ FIRMWARE_HASH_SLOT,
+ _usrp_load_firmware);
+}
+
+usrp_load_status_t
+usrp_load_fpga (struct usb_dev_handle *udh,
+ const char *filename,
+ bool force)
+{
+ return usrp_conditionally_load_something (udh, filename, force,
+ FPGA_HASH_SLOT,
+ _usrp_load_fpga);
+}
+
+static usb_dev_handle *
+open_nth_cmd_interface (int nth)
+{
+ struct usb_device *udev = usrp_find_device (nth);
+ if (udev == 0){
+ fprintf (stderr, "usrp: failed to find usrp[%d]\n", nth);
+ return 0;
+ }
+
+ struct usb_dev_handle *udh;
+
+ udh = usrp_open_cmd_interface (udev);
+ if (udh == 0){
+ // FIXME this could be because somebody else has it open.
+ // We should delay and retry...
+ fprintf (stderr, "open_nth_cmd_interface: open_cmd_interface failed\n");
+ usb_strerror ();
+ return 0;
+ }
+
+ return udh;
+ }
+
+static bool
+our_nanosleep (const struct timespec *delay)
+{
+ struct timespec new_delay = *delay;
+ struct timespec remainder;
+
+ while (1){
+ int r = nanosleep (&new_delay, &remainder);
+ if (r == 0)
+ return true;
+ if (errno == EINTR)
+ new_delay = remainder;
+ else {
+ perror ("nanosleep");
+ return false;
+ }
+ }
+}
+
+static bool
+mdelay (int millisecs)
+{
+ struct timespec ts;
+ ts.tv_sec = millisecs / 1000;
+ ts.tv_nsec = (millisecs - (1000 * ts.tv_sec)) * 1000000;
+ return our_nanosleep (&ts);
+}
+
+usrp_load_status_t
+usrp_load_firmware_nth (int nth, const char *filename, bool force){
+ struct usb_dev_handle *udh = open_nth_cmd_interface (nth);
+ if (udh == 0)
+ return ULS_ERROR;
+
+ usrp_load_status_t s = usrp_load_firmware (udh, filename, force);
+ usrp_close_interface (udh);
+
+ switch (s){
+
+ case ULS_ALREADY_LOADED: // nothing changed...
+ return ULS_ALREADY_LOADED;
+ break;
+
+ case ULS_OK:
+ // we loaded firmware successfully.
+
+ // It's highly likely that the board will renumerate (simulate a
+ // disconnect/reconnect sequence), invalidating our current
+ // handle.
+
+ // FIXME. Turn this into a loop that rescans until we refind ourselves
+
+ struct timespec t; // delay for 1 second
+ t.tv_sec = 2;
+ t.tv_nsec = 0;
+ our_nanosleep (&t);
+
+ usb_find_busses (); // rescan busses and devices
+ usb_find_devices ();
+
+ return ULS_OK;
+
+ default:
+ case ULS_ERROR: // some kind of problem
+ return ULS_ERROR;
+ }
+}
+
+static void
+load_status_msg (usrp_load_status_t s, const char *type, const char *filename)
+{
+ char *e = getenv("USRP_VERBOSE");
+ bool verbose = e != 0;
+
+ switch (s){
+ case ULS_ERROR:
+ fprintf (stderr, "usrp: failed to load %s %s.\n", type, filename);
+ break;
+
+ case ULS_ALREADY_LOADED:
+ if (verbose)
+ fprintf (stderr, "usrp: %s %s already loaded.\n", type, filename);
+ break;
+
+ case ULS_OK:
+ if (verbose)
+ fprintf (stderr, "usrp: %s %s loaded successfully.\n", type, filename);
+ break;
+ }
+}
+
+bool
+usrp_load_standard_bits (int nth, bool force,
+ const std::string fpga_filename,
+ const std::string firmware_filename)
+{
+ usrp_load_status_t s;
+ const char *filename;
+ const char *proto_filename;
+ int hw_rev;
+
+ // first, figure out what hardware rev we're dealing with
+ {
+ struct usb_device *udev = usrp_find_device (nth);
+ if (udev == 0){
+ fprintf (stderr, "usrp: failed to find usrp[%d]\n", nth);
+ return false;
+ }
+ hw_rev = usrp_hw_rev (udev);
+ }
+
+ // start by loading the firmware
+
+ proto_filename = get_proto_filename(firmware_filename, "USRP_FIRMWARE",
+ default_firmware_filename);
+ filename = find_file(proto_filename, hw_rev);
+ if (filename == 0){
+ fprintf (stderr, "Can't find firmware: %s\n", proto_filename);
+ return false;
+ }
+
+ s = usrp_load_firmware_nth (nth, filename, force);
+ load_status_msg (s, "firmware", filename);
+
+ if (s == ULS_ERROR)
+ return false;
+
+ // if we actually loaded firmware, we must reload fpga ...
+ if (s == ULS_OK)
+ force = true;
+
+ // now move on to the fpga configuration bitstream
+
+ proto_filename = get_proto_filename(fpga_filename, "USRP_FPGA",
+ default_fpga_filename);
+ filename = find_file (proto_filename, hw_rev);
+ if (filename == 0){
+ fprintf (stderr, "Can't find fpga bitstream: %s\n", proto_filename);
+ return false;
+ }
+
+ struct usb_dev_handle *udh = open_nth_cmd_interface (nth);
+ if (udh == 0)
+ return false;
+
+ s = usrp_load_fpga (udh, filename, force);
+ usrp_close_interface (udh);
+ load_status_msg (s, "fpga bitstream", filename);
+
+ if (s == ULS_ERROR)
+ return false;
+
+ return true;
+}
+
+bool
+_usrp_get_status (struct usb_dev_handle *udh, int which, bool *trouble)
+{
+ unsigned char status;
+ *trouble = true;
+
+ if (write_cmd (udh, VRQ_GET_STATUS, 0, which,
+ &status, sizeof (status)) != sizeof (status))
+ return false;
+
+ *trouble = status;
+ return true;
+}
+
+bool
+usrp_check_rx_overrun (struct usb_dev_handle *udh, bool *overrun_p)
+{
+ return _usrp_get_status (udh, GS_RX_OVERRUN, overrun_p);
+}
+
+bool
+usrp_check_tx_underrun (struct usb_dev_handle *udh, bool *underrun_p)
+{
+ return _usrp_get_status (udh, GS_TX_UNDERRUN, underrun_p);
+}
+
+
+bool
+usrp_i2c_write (struct usb_dev_handle *udh, int i2c_addr,
+ const void *buf, int len)
+{
+ if (len < 1 || len > MAX_EP0_PKTSIZE)
+ return false;
+
+ return write_cmd (udh, VRQ_I2C_WRITE, i2c_addr, 0,
+ (unsigned char *) buf, len) == len;
+}
+
+
+bool
+usrp_i2c_read (struct usb_dev_handle *udh, int i2c_addr,
+ void *buf, int len)
+{
+ if (len < 1 || len > MAX_EP0_PKTSIZE)
+ return false;
+
+ return write_cmd (udh, VRQ_I2C_READ, i2c_addr, 0,
+ (unsigned char *) buf, len) == len;
+}
+
+bool
+usrp_spi_write (struct usb_dev_handle *udh,
+ int optional_header, int enables, int format,
+ const void *buf, int len)
+{
+ if (len < 0 || len > MAX_EP0_PKTSIZE)
+ return false;
+
+ return write_cmd (udh, VRQ_SPI_WRITE,
+ optional_header,
+ ((enables & 0xff) << 8) | (format & 0xff),
+ (unsigned char *) buf, len) == len;
+}
+
+
+bool
+usrp_spi_read (struct usb_dev_handle *udh,
+ int optional_header, int enables, int format,
+ void *buf, int len)
+{
+ if (len < 0 || len > MAX_EP0_PKTSIZE)
+ return false;
+
+ return write_cmd (udh, VRQ_SPI_READ,
+ optional_header,
+ ((enables & 0xff) << 8) | (format & 0xff),
+ (unsigned char *) buf, len) == len;
+}
+
+bool
+usrp_9862_write (struct usb_dev_handle *udh, int which_codec,
+ int regno, int value)
+{
+ if (0)
+ fprintf (stderr, "usrp_9862_write which = %d, reg = %2d, val = %3d (0x%02x)\n",
+ which_codec, regno, value, value);
+
+ unsigned char buf[1];
+
+ buf[0] = value;
+
+ return usrp_spi_write (udh, 0x00 | (regno & 0x3f),
+ which_codec == 0 ? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B,
+ SPI_FMT_MSB | SPI_FMT_HDR_1,
+ buf, 1);
+}
+
+bool
+usrp_9862_read (struct usb_dev_handle *udh, int which_codec,
+ int regno, unsigned char *value)
+{
+ return usrp_spi_read (udh, 0x80 | (regno & 0x3f),
+ which_codec == 0 ? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B,
+ SPI_FMT_MSB | SPI_FMT_HDR_1,
+ value, 1);
+}
+
+bool
+usrp_9862_write_many (struct usb_dev_handle *udh,
+ int which_codec,
+ const unsigned char *buf,
+ int len)
+{
+ if (len & 0x1)
+ return false; // must be even
+
+ bool result = true;
+
+ while (len > 0){
+ result &= usrp_9862_write (udh, which_codec, buf[0], buf[1]);
+ len -= 2;
+ buf += 2;
+ }
+
+ return result;
+}
+
+
+bool
+usrp_9862_write_many_all (struct usb_dev_handle *udh,
+ const unsigned char *buf, int len)
+{
+ // FIXME handle 2/2 and 4/4 versions
+
+ bool result;
+ result = usrp_9862_write_many (udh, 0, buf, len);
+ result &= usrp_9862_write_many (udh, 1, buf, len);
+ return result;
+}
+
+static void
+power_down_9862s (struct usb_dev_handle *udh)
+{
+ static const unsigned char regs[] = {
+ REG_RX_PWR_DN, 0x01, // everything
+ REG_TX_PWR_DN, 0x0f, // pwr dn digital and analog_both
+ REG_TX_MODULATOR, 0x00 // coarse & fine modulators disabled
+ };
+
+ switch (usrp_hw_rev (dev_handle_to_dev (udh))){
+ case 0:
+ break;
+
+ default:
+ usrp_9862_write_many_all (udh, regs, sizeof (regs));
+ break;
+ }
+}
+
+
+
+static const int EEPROM_PAGESIZE = 16;
+
+bool
+usrp_eeprom_write (struct usb_dev_handle *udh, int i2c_addr,
+ int eeprom_offset, const void *buf, int len)
+{
+ unsigned char cmd[2];
+ const unsigned char *p = (unsigned char *) buf;
+
+ // The simplest thing that could possibly work:
+ // all writes are single byte writes.
+ //
+ // We could speed this up using the page write feature,
+ // but we write so infrequently, why bother...
+
+ while (len-- > 0){
+ cmd[0] = eeprom_offset++;
+ cmd[1] = *p++;
+ bool r = usrp_i2c_write (udh, i2c_addr, cmd, sizeof (cmd));
+ mdelay (10); // delay 10ms worst case write time
+ if (!r)
+ return false;
+ }
+
+ return true;
+}
+
+bool
+usrp_eeprom_read (struct usb_dev_handle *udh, int i2c_addr,
+ int eeprom_offset, void *buf, int len)
+{
+ unsigned char *p = (unsigned char *) buf;
+
+ // We setup a random read by first doing a "zero byte write".
+ // Writes carry an address. Reads use an implicit address.
+
+ unsigned char cmd[1];
+ cmd[0] = eeprom_offset;
+ if (!usrp_i2c_write (udh, i2c_addr, cmd, sizeof (cmd)))
+ return false;
+
+ while (len > 0){
+ int n = std::min (len, MAX_EP0_PKTSIZE);
+ if (!usrp_i2c_read (udh, i2c_addr, p, n))
+ return false;
+ len -= n;
+ p += n;
+ }
+ return true;
+}
+
+// ----------------------------------------------------------------
+
+static bool
+slot_to_codec (int slot, int *which_codec)
+{
+ *which_codec = 0;
+
+ switch (slot){
+ case SLOT_TX_A:
+ case SLOT_RX_A:
+ *which_codec = 0;
+ break;
+
+ case SLOT_TX_B:
+ case SLOT_RX_B:
+ *which_codec = 1;
+ break;
+
+ default:
+ fprintf (stderr, "usrp_prims:slot_to_codec: invalid slot = %d\n", slot);
+ return false;
+ }
+ return true;
+}
+
+static bool
+tx_slot_p (int slot)
+{
+ switch (slot){
+ case SLOT_TX_A:
+ case SLOT_TX_B:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool
+usrp_write_aux_dac (struct usb_dev_handle *udh, int slot,
+ int which_dac, int value)
+{
+ int which_codec;
+
+ if (!slot_to_codec (slot, &which_codec))
+ return false;
+
+ if (!(0 <= which_dac && which_dac < 4)){
+ fprintf (stderr, "usrp_write_aux_dac: invalid dac = %d\n", which_dac);
+ return false;
+ }
+
+ value &= 0x0fff; // mask to 12-bits
+
+ if (which_dac == 3){
+ // dac 3 is really 12-bits. Use value as is.
+ bool r = true;
+ r &= usrp_9862_write (udh, which_codec, 43, (value >> 4)); // most sig
+ r &= usrp_9862_write (udh, which_codec, 42, (value & 0xf) << 4); // least sig
+ return r;
+ }
+ else {
+ // dac 0, 1, and 2 are really 8 bits.
+ value = value >> 4; // shift value appropriately
+ return usrp_9862_write (udh, which_codec, 36 + which_dac, value);
+ }
+}
+
+
+bool
+usrp_read_aux_adc (struct usb_dev_handle *udh, int slot,
+ int which_adc, int *value)
+{
+ *value = 0;
+ int which_codec;
+
+ if (!slot_to_codec (slot, &which_codec))
+ return false;
+
+ if (!(0 <= which_codec && which_codec < 2)){
+ fprintf (stderr, "usrp_read_aux_adc: invalid adc = %d\n", which_adc);
+ return false;
+ }
+
+ unsigned char aux_adc_control =
+ AUX_ADC_CTRL_REFSEL_A // on chip reference
+ | AUX_ADC_CTRL_REFSEL_B; // on chip reference
+
+ int rd_reg = 26; // base address of two regs to read for result
+
+ // program the ADC mux bits
+ if (tx_slot_p (slot))
+ aux_adc_control |= AUX_ADC_CTRL_SELECT_A2 | AUX_ADC_CTRL_SELECT_B2;
+ else {
+ rd_reg += 2;
+ aux_adc_control |= AUX_ADC_CTRL_SELECT_A1 | AUX_ADC_CTRL_SELECT_B1;
+ }
+
+ // I'm not sure if we can set the mux and issue a start conversion
+ // in the same cycle, so let's do them one at a time.
+
+ usrp_9862_write (udh, which_codec, 34, aux_adc_control);
+
+ if (which_adc == 0)
+ aux_adc_control |= AUX_ADC_CTRL_START_A;
+ else {
+ rd_reg += 4;
+ aux_adc_control |= AUX_ADC_CTRL_START_B;
+ }
+
+ // start the conversion
+ usrp_9862_write (udh, which_codec, 34, aux_adc_control);
+
+ // read the 10-bit result back
+ unsigned char v_lo = 0;
+ unsigned char v_hi = 0;
+ bool r = usrp_9862_read (udh, which_codec, rd_reg, &v_lo);
+ r &= usrp_9862_read (udh, which_codec, rd_reg + 1, &v_hi);
+
+ if (r)
+ *value = ((v_hi << 2) | ((v_lo >> 6) & 0x3)) << 2; // format as 12-bit
+
+ return r;
+}
+
+// ----------------------------------------------------------------
+
+static int slot_to_i2c_addr (int slot)
+{
+ switch (slot){
+ case SLOT_TX_A: return I2C_ADDR_TX_A;
+ case SLOT_RX_A: return I2C_ADDR_RX_A;
+ case SLOT_TX_B: return I2C_ADDR_TX_B;
+ case SLOT_RX_B: return I2C_ADDR_RX_B;
+ default: return -1;
+ }
+}
+
+static void
+set_chksum (unsigned char *buf)
+{
+ int sum = 0;
+ unsigned int i;
+ for (i = 0; i < DB_EEPROM_CLEN - 1; i++)
+ sum += buf[i];
+ buf[i] = -sum;
+}
+
+static usrp_dbeeprom_status_t
+read_dboard_eeprom (struct usb_dev_handle *udh,
+ int slot_id, unsigned char *buf)
+{
+ int i2c_addr = slot_to_i2c_addr (slot_id);
+ if (i2c_addr == -1)
+ return UDBE_BAD_SLOT;
+
+ if (!usrp_eeprom_read (udh, i2c_addr, 0, buf, DB_EEPROM_CLEN))
+ return UDBE_NO_EEPROM;
+
+ if (buf[DB_EEPROM_MAGIC] != DB_EEPROM_MAGIC_VALUE)
+ return UDBE_INVALID_EEPROM;
+
+ int sum = 0;
+ for (unsigned int i = 0; i < DB_EEPROM_CLEN; i++)
+ sum += buf[i];
+
+ if ((sum & 0xff) != 0)
+ return UDBE_INVALID_EEPROM;
+
+ return UDBE_OK;
+}
+
+usrp_dbeeprom_status_t
+usrp_read_dboard_eeprom (struct usb_dev_handle *udh,
+ int slot_id, usrp_dboard_eeprom *eeprom)
+{
+ unsigned char buf[DB_EEPROM_CLEN];
+
+ memset (eeprom, 0, sizeof (*eeprom));
+
+ usrp_dbeeprom_status_t s = read_dboard_eeprom (udh, slot_id, buf);
+ if (s != UDBE_OK)
+ return s;
+
+ eeprom->id = (buf[DB_EEPROM_ID_MSB] << 8) | buf[DB_EEPROM_ID_LSB];
+ eeprom->oe = (buf[DB_EEPROM_OE_MSB] << 8) | buf[DB_EEPROM_OE_LSB];
+ eeprom->offset[0] = (buf[DB_EEPROM_OFFSET_0_MSB] << 8) | buf[DB_EEPROM_OFFSET_0_LSB];
+ eeprom->offset[1] = (buf[DB_EEPROM_OFFSET_1_MSB] << 8) | buf[DB_EEPROM_OFFSET_1_LSB];
+
+ return UDBE_OK;
+}
+
+bool
+usrp_write_dboard_offsets (struct usb_dev_handle *udh, int slot_id,
+ short offset0, short offset1)
+{
+ unsigned char buf[DB_EEPROM_CLEN];
+
+ usrp_dbeeprom_status_t s = read_dboard_eeprom (udh, slot_id, buf);
+ if (s != UDBE_OK)
+ return false;
+
+ buf[DB_EEPROM_OFFSET_0_LSB] = (offset0 >> 0) & 0xff;
+ buf[DB_EEPROM_OFFSET_0_MSB] = (offset0 >> 8) & 0xff;
+ buf[DB_EEPROM_OFFSET_1_LSB] = (offset1 >> 0) & 0xff;
+ buf[DB_EEPROM_OFFSET_1_MSB] = (offset1 >> 8) & 0xff;
+ set_chksum (buf);
+
+ return usrp_eeprom_write (udh, slot_to_i2c_addr (slot_id),
+ 0, buf, sizeof (buf));
+}
+
+std::string
+usrp_serial_number(struct usb_dev_handle *udh)
+{
+ u_int8_t iserial = usb_device(udh)->descriptor.iSerialNumber;
+ if (iserial == 0)
+ return "";
+
+ char buf[1024];
+ if (usb_get_string_simple(udh, iserial, buf, sizeof(buf)) < 0)
+ return "";
+
+ return buf;
+}
diff --git a/usrp/host/lib/usrp_prims.h b/usrp/host/lib/usrp_prims.h
new file mode 100644
index 000000000..a4bbb620d
--- /dev/null
+++ b/usrp/host/lib/usrp_prims.h
@@ -0,0 +1,294 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,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.
+ */
+
+/*
+ * Low level primitives for directly messing with USRP hardware.
+ *
+ * If you're trying to use the USRP, you'll probably want to take a look
+ * at the usrp_rx and usrp_tx classes. They hide a bunch of low level details
+ * and provide high performance streaming i/o.
+ *
+ * This interface is built on top of libusb, which allegedly works under
+ * Linux, *BSD and Mac OS/X. http://libusb.sourceforge.net
+ */
+
+#ifndef _USRP_PRIMS_H_
+#define _USRP_PRIMS_H_
+
+#include <usrp_slots.h>
+#include <string>
+
+static const int USRP_HASH_SIZE = 16;
+
+enum usrp_load_status_t { ULS_ERROR = 0, ULS_OK, ULS_ALREADY_LOADED };
+
+struct usb_dev_handle;
+struct usb_device;
+
+/*!
+ * \brief initialize libusb; probe busses and devices.
+ * Safe to call more than once.
+ */
+void usrp_one_time_init ();
+
+/*
+ * force a rescan of the buses and devices
+ */
+void usrp_rescan ();
+
+/*!
+ * \brief locate Nth (zero based) USRP device in system.
+ * Return pointer or 0 if not found.
+ *
+ * The following kinds of devices are considered USRPs:
+ *
+ * unconfigured USRP (no firwmare loaded)
+ * configured USRP (firmware loaded)
+ * unconfigured Cypress FX2 (only if fx2_ok_p is true)
+ */
+struct usb_device *usrp_find_device (int nth, bool fx2_ok_p = false);
+
+bool usrp_usrp_p (struct usb_device *q); //< is this a USRP
+bool usrp_usrp0_p (struct usb_device *q); //< is this a USRP Rev 0
+bool usrp_usrp1_p (struct usb_device *q); //< is this a USRP Rev 1
+bool usrp_usrp2_p (struct usb_device *q); //< is this a USRP Rev 2
+int usrp_hw_rev (struct usb_device *q); //< return h/w rev code
+
+bool usrp_fx2_p (struct usb_device *q); //< is this an unconfigured Cypress FX2
+
+bool usrp_unconfigured_usrp_p (struct usb_device *q); //< some kind of unconfigured USRP
+bool usrp_configured_usrp_p (struct usb_device *q); //< some kind of configured USRP
+
+/*!
+ * \brief given a usb_device return an instance of the appropriate usb_dev_handle
+ *
+ * These routines claim the specified interface and select the
+ * correct alternate interface. (USB nomenclature is totally screwed!)
+ *
+ * If interface can't be opened, or is already claimed by some other
+ * process, 0 is returned.
+ */
+struct usb_dev_handle *usrp_open_cmd_interface (struct usb_device *dev);
+struct usb_dev_handle *usrp_open_rx_interface (struct usb_device *dev);
+struct usb_dev_handle *usrp_open_tx_interface (struct usb_device *dev);
+
+/*!
+ * \brief close interface.
+ */
+bool usrp_close_interface (struct usb_dev_handle *udh);
+
+/*!
+ * \brief load intel hex format file into USRP/Cypress FX2 (8051).
+ *
+ * The filename extension is typically *.ihx
+ *
+ * Note that loading firmware may cause the device to renumerate. I.e.,
+ * change its configuration, invalidating the current device handle.
+ */
+
+usrp_load_status_t
+usrp_load_firmware (struct usb_dev_handle *udh, const char *filename, bool force);
+
+/*!
+ * \brief load intel hex format file into USRP FX2 (8051).
+ *
+ * The filename extension is typically *.ihx
+ *
+ * Note that loading firmware may cause the device to renumerate. I.e.,
+ * change its configuration, invalidating the current device handle.
+ * If the result is ULS_OK, usrp_load_firmware_nth delays 1 second
+ * then rescans the busses and devices.
+ */
+usrp_load_status_t
+usrp_load_firmware_nth (int nth, const char *filename, bool force);
+
+/*!
+ * \brief load fpga configuration bitstream
+ */
+usrp_load_status_t
+usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, bool force);
+
+/*!
+ * \brief load the regular firmware and fpga bitstream in the Nth USRP.
+ *
+ * This is the normal starting point...
+ */
+bool usrp_load_standard_bits (int nth, bool force,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = "");
+
+/*!
+ * \brief copy the given \p hash into the USRP hash slot \p which.
+ * The usrp implements two hash slots, 0 and 1.
+ */
+bool usrp_set_hash (struct usb_dev_handle *udh, int which,
+ const unsigned char hash[USRP_HASH_SIZE]);
+
+/*!
+ * \brief retrieve the \p hash from the USRP hash slot \p which.
+ * The usrp implements two hash slots, 0 and 1.
+ */
+bool usrp_get_hash (struct usb_dev_handle *udh, int which,
+ unsigned char hash[USRP_HASH_SIZE]);
+
+bool usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value);
+bool usrp_read_fpga_reg (struct usb_dev_handle *udh, int reg, int *value);
+bool usrp_set_fpga_reset (struct usb_dev_handle *udh, bool on);
+bool usrp_set_fpga_tx_enable (struct usb_dev_handle *udh, bool on);
+bool usrp_set_fpga_rx_enable (struct usb_dev_handle *udh, bool on);
+bool usrp_set_fpga_tx_reset (struct usb_dev_handle *udh, bool on);
+bool usrp_set_fpga_rx_reset (struct usb_dev_handle *udh, bool on);
+bool usrp_set_led (struct usb_dev_handle *udh, int which, bool on);
+
+bool usrp_check_rx_overrun (struct usb_dev_handle *udh, bool *overrun_p);
+bool usrp_check_tx_underrun (struct usb_dev_handle *udh, bool *underrun_p);
+
+// i2c_read and i2c_write are limited to a maximum len of 64 bytes.
+
+bool usrp_i2c_write (struct usb_dev_handle *udh, int i2c_addr,
+ const void *buf, int len);
+
+bool usrp_i2c_read (struct usb_dev_handle *udh, int i2c_addr,
+ void *buf, int len);
+
+// spi_read and spi_write are limited to a maximum of 64 bytes
+// See usrp_spi_defs.h for more info
+
+bool usrp_spi_write (struct usb_dev_handle *udh,
+ int optional_header, int enables, int format,
+ const void *buf, int len);
+
+bool usrp_spi_read (struct usb_dev_handle *udh,
+ int optional_header, int enables, int format,
+ void *buf, int len);
+
+
+bool usrp_9862_write (struct usb_dev_handle *udh,
+ int which_codec, // [0, 1]
+ int regno, // [0, 63]
+ int value); // [0, 255]
+
+bool usrp_9862_read (struct usb_dev_handle *udh,
+ int which_codec, // [0, 1]
+ int regno, // [0, 63]
+ unsigned char *value); // [0, 255]
+
+/*!
+ * \brief Write multiple 9862 regs at once.
+ *
+ * \p buf contains alternating register_number, register_value pairs.
+ * \p len must be even and is the length of buf in bytes.
+ */
+bool usrp_9862_write_many (struct usb_dev_handle *udh, int which_codec,
+ const unsigned char *buf, int len);
+
+
+/*!
+ * \brief write specified regs to all 9862's in the system
+ */
+bool usrp_9862_write_many_all (struct usb_dev_handle *udh,
+ const unsigned char *buf, int len);
+
+
+// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
+// Which EEPROM is determined by i2c_addr. See i2c_addr.h
+
+bool usrp_eeprom_write (struct usb_dev_handle *udh, int i2c_addr,
+ int eeprom_offset, const void *buf, int len);
+
+
+// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
+// Which EEPROM is determined by i2c_addr. See i2c_addr.h
+
+bool usrp_eeprom_read (struct usb_dev_handle *udh, int i2c_addr,
+ int eeprom_offset, void *buf, int len);
+
+
+// Slot specific i/o routines
+
+/*!
+ * \brief write to the specified aux dac.
+ *
+ * \p slot: which Tx or Rx slot to write.
+ * 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
+ *
+ * \p which_dac: [0,3] RX slots must use only 0 and 1.
+ * TX slots must use only 2 and 3.
+ *
+ * AUX DAC 3 is really the 9862 sigma delta output.
+ *
+ * \p value to write to aux dac. All dacs take straight
+ * binary values. Although dacs 0, 1 and 2 are 8-bit and dac 3 is 12-bit,
+ * the interface is in terms of 12-bit values [0,4095]
+ */
+bool usrp_write_aux_dac (struct usb_dev_handle *uhd, int slot,
+ int which_dac, int value);
+
+/*!
+ * \brief Read the specified aux adc
+ *
+ * \p slot: which Tx or Rx slot to read aux dac
+ * \p which_adc: [0,1] which of the two adcs to read
+ * \p *value: return value, 12-bit straight binary.
+ */
+bool usrp_read_aux_adc (struct usb_dev_handle *udh, int slot,
+ int which_adc, int *value);
+
+
+/*!
+ * \brief usrp daughterboard id to name mapping
+ */
+const std::string usrp_dbid_to_string (int dbid);
+
+
+enum usrp_dbeeprom_status_t { UDBE_OK, UDBE_BAD_SLOT, UDBE_NO_EEPROM, UDBE_INVALID_EEPROM };
+
+struct usrp_dboard_eeprom {
+ unsigned short id; // d'board identifier code
+ unsigned short oe; // fpga output enables:
+ // If bit set, i/o pin is an output from FPGA.
+ short offset[2]; // ADC/DAC offset correction
+};
+
+/*!
+ * \brief Read and return parsed daughterboard eeprom
+ */
+usrp_dbeeprom_status_t
+usrp_read_dboard_eeprom (struct usb_dev_handle *udh,
+ int slot_id, usrp_dboard_eeprom *eeprom);
+
+/*!
+ * \brief write ADC/DAC offset calibration constants to d'board eeprom
+ */
+bool usrp_write_dboard_offsets (struct usb_dev_handle *udh, int slot_id,
+ short offset0, short offset1);
+
+/*!
+ * \brief return a usrp's serial number.
+ *
+ * Note that this only works on a configured usrp.
+ * \returns non-zero length string iff successful.
+ */
+std::string usrp_serial_number(struct usb_dev_handle *udh);
+
+#endif /* _USRP_PRIMS_H_ */
diff --git a/usrp/host/lib/usrp_slots.h b/usrp/host/lib/usrp_slots.h
new file mode 100644
index 000000000..1568ce726
--- /dev/null
+++ b/usrp/host/lib/usrp_slots.h
@@ -0,0 +1,33 @@
+/* -*- 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_USRP_SLOTS_H
+#define INCLUDED_USRP_SLOTS_H
+
+// daughterboard slot numbers used in some calls
+
+static const int SLOT_TX_A = 0;
+static const int SLOT_RX_A = 1;
+static const int SLOT_TX_B = 2;
+static const int SLOT_RX_B = 3;
+
+#endif /* INCLUDED_USRP_SLOTS_H */
diff --git a/usrp/host/lib/usrp_standard.cc b/usrp/host/lib/usrp_standard.cc
new file mode 100644
index 000000000..d59920fd1
--- /dev/null
+++ b/usrp/host/lib/usrp_standard.cc
@@ -0,0 +1,831 @@
+/* -*- 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.
+ */
+
+#include <usrp_standard.h>
+
+#include "usrp_prims.h"
+#include "fpga_regs_common.h"
+#include "fpga_regs_standard.h"
+#include <stdexcept>
+#include <assert.h>
+#include <math.h>
+#include <ad9862.h>
+
+
+static const int OLD_CAPS_VAL = 0xaa55ff77;
+static const int DEFAULT_CAPS_VAL = ((2 << bmFR_RB_CAPS_NDUC_SHIFT)
+ | (2 << bmFR_RB_CAPS_NDDC_SHIFT)
+ | bmFR_RB_CAPS_RX_HAS_HALFBAND);
+
+// #define USE_FPGA_TX_CORDIC
+
+
+using namespace ad9862;
+
+#define NELEM(x) (sizeof (x) / sizeof (x[0]))
+
+
+static unsigned int
+compute_freq_control_word_fpga (double master_freq, double target_freq,
+ double *actual_freq, bool verbose)
+{
+ static const int NBITS = 14;
+
+ int v = (int) rint (target_freq / master_freq * pow (2.0, 32.0));
+
+ if (0)
+ v = (v >> (32 - NBITS)) << (32 - NBITS); // keep only top NBITS
+
+ *actual_freq = v * master_freq / pow (2.0, 32.0);
+
+ if (verbose)
+ fprintf (stderr,
+ "compute_freq_control_word_fpga: target = %g actual = %g delta = %g\n",
+ target_freq, *actual_freq, *actual_freq - target_freq);
+
+ return (unsigned int) v;
+}
+
+// The 9862 uses an unsigned 24-bit frequency tuning word and
+// a separate register to control the sign.
+
+static unsigned int
+compute_freq_control_word_9862 (double master_freq, double target_freq,
+ double *actual_freq, bool verbose)
+{
+ double sign = 1.0;
+
+ if (target_freq < 0)
+ sign = -1.0;
+
+ int v = (int) rint (fabs (target_freq) / master_freq * pow (2.0, 24.0));
+ *actual_freq = v * master_freq / pow (2.0, 24.0) * sign;
+
+ if (verbose)
+ fprintf (stderr,
+ "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n",
+ target_freq, *actual_freq, *actual_freq - target_freq, v);
+
+ return (unsigned int) v;
+}
+
+// ----------------------------------------------------------------
+
+usrp_standard_common::usrp_standard_common(usrp_basic *parent)
+{
+ // read new FPGA capability register
+ if (!parent->_read_fpga_reg(FR_RB_CAPS, &d_fpga_caps)){
+ fprintf (stderr, "usrp_standard_common: failed to read FPGA cap register.\n");
+ throw std::runtime_error ("usrp_standard_common::ctor");
+ }
+ // If we don't have the cap register, set the value to what it would
+ // have had if we did have one ;)
+ if (d_fpga_caps == OLD_CAPS_VAL)
+ d_fpga_caps = DEFAULT_CAPS_VAL;
+
+ if (0){
+ fprintf(stdout, "has_rx_halfband = %d\n", has_rx_halfband());
+ fprintf(stdout, "nddcs = %d\n", nddcs());
+ fprintf(stdout, "has_tx_halfband = %d\n", has_tx_halfband());
+ fprintf(stdout, "nducs = %d\n", nducs());
+ }
+}
+
+bool
+usrp_standard_common::has_rx_halfband() const
+{
+ return (d_fpga_caps & bmFR_RB_CAPS_RX_HAS_HALFBAND) ? true : false;
+}
+
+int
+usrp_standard_common::nddcs() const
+{
+ return (d_fpga_caps & bmFR_RB_CAPS_NDDC_MASK) >> bmFR_RB_CAPS_NDDC_SHIFT;
+}
+
+bool
+usrp_standard_common::has_tx_halfband() const
+{
+ return (d_fpga_caps & bmFR_RB_CAPS_TX_HAS_HALFBAND) ? true : false;
+}
+
+int
+usrp_standard_common::nducs() const
+{
+ return (d_fpga_caps & bmFR_RB_CAPS_NDUC_MASK) >> bmFR_RB_CAPS_NDUC_SHIFT;
+}
+
+// ----------------------------------------------------------------
+
+static int
+real_rx_mux_value (int mux, int nchan)
+{
+ if (mux != -1)
+ return mux;
+
+ return 0x32103210;
+}
+
+usrp_standard_rx::usrp_standard_rx (int which_board,
+ unsigned int decim_rate,
+ int nchan, int mux, int mode,
+ int fusb_block_size, int fusb_nblocks,
+ const std::string fpga_filename,
+ const std::string firmware_filename
+ )
+ : usrp_basic_rx (which_board, fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename),
+ usrp_standard_common(this),
+ d_nchan (1), d_sw_mux (0x0), d_hw_mux (0x0)
+{
+ if (!set_format(make_format())){
+ fprintf (stderr, "usrp_standard_rx: set_format failed\n");
+ throw std::runtime_error ("usrp_standard_rx::ctor");
+ }
+ if (!set_nchannels (nchan)){
+ fprintf (stderr, "usrp_standard_rx: set_nchannels failed\n");
+ throw std::runtime_error ("usrp_standard_rx::ctor");
+ }
+ if (!set_decim_rate (decim_rate)){
+ fprintf (stderr, "usrp_standard_rx: set_decim_rate failed\n");
+ throw std::runtime_error ("usrp_standard_rx::ctor");
+ }
+ if (!set_mux (real_rx_mux_value (mux, nchan))){
+ fprintf (stderr, "usrp_standard_rx: set_mux failed\n");
+ throw std::runtime_error ("usrp_standard_rx::ctor");
+ }
+ if (!set_fpga_mode (mode)){
+ fprintf (stderr, "usrp_standard_rx: set_fpga_mode failed\n");
+ throw std::runtime_error ("usrp_standard_rx::ctor");
+ }
+
+ for (int i = 0; i < MAX_CHAN; i++){
+ set_rx_freq(i, 0);
+ set_ddc_phase(i, 0);
+ }
+}
+
+usrp_standard_rx::~usrp_standard_rx ()
+{
+ // fprintf(stderr, "\nusrp_standard_rx: dtor\n");
+}
+
+bool
+usrp_standard_rx::start ()
+{
+ if (!usrp_basic_rx::start ())
+ return false;
+
+ // add our code here
+
+ return true;
+}
+
+bool
+usrp_standard_rx::stop ()
+{
+ bool ok = usrp_basic_rx::stop ();
+
+ // add our code here
+
+ return ok;
+}
+
+usrp_standard_rx *
+usrp_standard_rx::make (int which_board,
+ unsigned int decim_rate,
+ int nchan, int mux, int mode,
+ int fusb_block_size, int fusb_nblocks,
+ const std::string fpga_filename,
+ const std::string firmware_filename
+ )
+{
+ usrp_standard_rx *u = 0;
+
+ try {
+ u = new usrp_standard_rx (which_board, decim_rate,
+ nchan, mux, mode,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename);
+ return u;
+ }
+ catch (...){
+ delete u;
+ return 0;
+ }
+
+ return u;
+}
+
+bool
+usrp_standard_rx::set_decim_rate(unsigned int rate)
+{
+ if ((rate & 0x1) || rate < 4 || rate > 256){
+ fprintf (stderr, "usrp_standard_rx::set_decim_rate: rate must be EVEN and in [4, 256]\n");
+ return false;
+ }
+
+ d_decim_rate = rate;
+ set_usb_data_rate ((adc_rate () / rate * nchannels ())
+ * (2 * sizeof (short)));
+
+ bool s = disable_rx ();
+ int v = has_rx_halfband() ? d_decim_rate/2 - 1 : d_decim_rate - 1;
+ bool ok = _write_fpga_reg (FR_DECIM_RATE, v);
+ restore_rx (s);
+ return ok;
+}
+
+bool usrp_standard_rx::set_nchannels (int nchan)
+{
+ if (!(nchan == 1 || nchan == 2 || nchan == 4))
+ return false;
+
+ if (nchan > nddcs())
+ return false;
+
+ d_nchan = nchan;
+
+ return write_hw_mux_reg ();
+}
+
+
+// map software mux value to hw mux value
+//
+// Software mux value:
+//
+// 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
+// +-------+-------+-------+-------+-------+-------+-------+-------+
+// | Q3 | I3 | Q2 | I2 | Q1 | I1 | Q0 | I0 |
+// +-------+-------+-------+-------+-------+-------+-------+-------+
+//
+// Each 4-bit I field is either 0,1,2,3
+// Each 4-bit Q field is either 0,1,2,3 or 0xf (input is const zero)
+// All Q's must be 0xf or none of them may be 0xf
+//
+//
+// Hardware mux value:
+//
+// 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
+// +-----------------------+-------+-------+-------+-------+-+-----+
+// | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH |
+// +-----------------------+-------+-------+-------+-------+-+-----+
+
+
+static bool
+map_sw_mux_to_hw_mux (int sw_mux, int *hw_mux_ptr)
+{
+ // confirm that all I's are either 0,1,2,3
+
+ for (int i = 0; i < 8; i += 2){
+ int t = (sw_mux >> (4 * i)) & 0xf;
+ if (!(0 <= t && t <= 3))
+ return false;
+ }
+
+ // confirm that all Q's are either 0,1,2,3 or 0xf
+
+ for (int i = 1; i < 8; i += 2){
+ int t = (sw_mux >> (4 * i)) & 0xf;
+ if (!(t == 0xf || (0 <= t && t <= 3)))
+ return false;
+ }
+
+ // confirm that all Q inputs are 0xf (const zero input),
+ // or none of them are 0xf
+
+ int q_and = 1;
+ int q_or = 0;
+
+ for (int i = 0; i < 4; i++){
+ int qx_is_0xf = ((sw_mux >> (8 * i + 4)) & 0xf) == 0xf;
+ q_and &= qx_is_0xf;
+ q_or |= qx_is_0xf;
+ }
+
+ if (q_and || !q_or){ // OK
+ int hw_mux_value = 0;
+
+ for (int i = 0; i < 8; i++){
+ int t = (sw_mux >> (4 * i)) & 0x3;
+ hw_mux_value |= t << (2 * i + 4);
+ }
+
+ if (q_and)
+ hw_mux_value |= 0x8; // all Q's zero
+
+ *hw_mux_ptr = hw_mux_value;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+usrp_standard_rx::set_mux (int mux)
+{
+ if (!map_sw_mux_to_hw_mux (mux, &d_hw_mux))
+ return false;
+
+ // fprintf (stderr, "sw_mux = 0x%08x hw_mux = 0x%08x\n", mux, d_hw_mux);
+
+ d_sw_mux = mux;
+ return write_hw_mux_reg ();
+}
+
+bool
+usrp_standard_rx::write_hw_mux_reg ()
+{
+ bool s = disable_rx ();
+ bool ok = _write_fpga_reg (FR_RX_MUX, d_hw_mux | d_nchan);
+ restore_rx (s);
+ return ok;
+}
+
+
+bool
+usrp_standard_rx::set_rx_freq (int channel, double freq)
+{
+ if (channel < 0 || channel > MAX_CHAN)
+ return false;
+
+ unsigned int v =
+ compute_freq_control_word_fpga (adc_freq(),
+ freq, &d_rx_freq[channel],
+ d_verbose);
+
+ return _write_fpga_reg (FR_RX_FREQ_0 + channel, v);
+}
+
+unsigned int
+usrp_standard_rx::decim_rate () const { return d_decim_rate; }
+
+int
+usrp_standard_rx::nchannels () const { return d_nchan; }
+
+int
+usrp_standard_rx::mux () const { return d_sw_mux; }
+
+double
+usrp_standard_rx::rx_freq (int channel) const
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return 0;
+
+ return d_rx_freq[channel];
+}
+
+bool
+usrp_standard_rx::set_fpga_mode (int mode)
+{
+ return _write_fpga_reg (FR_MODE, mode);
+}
+
+bool
+usrp_standard_rx::set_ddc_phase(int channel, int phase)
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return false;
+
+ return _write_fpga_reg(FR_RX_PHASE_0 + channel, phase);
+}
+
+
+// To avoid quiet failures, check for things that our code cares about.
+
+static bool
+rx_format_is_valid(unsigned int format)
+{
+ int width = usrp_standard_rx::format_width(format);
+ int want_q = usrp_standard_rx::format_want_q(format);
+
+ if (!(width == 8 || width == 16)) // FIXME add other widths when valid
+ return false;
+
+ if (!want_q) // FIXME remove check when the rest of the code can handle I only
+ return false;
+
+ return true;
+}
+
+bool
+usrp_standard_rx::set_format(unsigned int format)
+{
+ if (!rx_format_is_valid(format))
+ return false;
+
+ return _write_fpga_reg(FR_RX_FORMAT, format);
+}
+
+unsigned int
+usrp_standard_rx::format() const
+{
+ return d_fpga_shadows[FR_RX_FORMAT];
+}
+
+// ----------------------------------------------------------------
+
+unsigned int
+usrp_standard_rx::make_format(int width, int shift, bool want_q, bool bypass_halfband)
+{
+ unsigned int format =
+ (((width << bmFR_RX_FORMAT_WIDTH_SHIFT) & bmFR_RX_FORMAT_WIDTH_MASK)
+ | (shift << bmFR_RX_FORMAT_SHIFT_SHIFT) & bmFR_RX_FORMAT_SHIFT_MASK);
+
+ if (want_q)
+ format |= bmFR_RX_FORMAT_WANT_Q;
+ if (bypass_halfband)
+ format |= bmFR_RX_FORMAT_BYPASS_HB;
+
+ return format;
+}
+
+int
+usrp_standard_rx::format_width(unsigned int format)
+{
+ return (format & bmFR_RX_FORMAT_WIDTH_MASK) >> bmFR_RX_FORMAT_WIDTH_SHIFT;
+}
+
+int
+usrp_standard_rx::format_shift(unsigned int format)
+{
+ return (format & bmFR_RX_FORMAT_SHIFT_MASK) >> bmFR_RX_FORMAT_SHIFT_SHIFT;
+}
+
+bool
+usrp_standard_rx::format_want_q(unsigned int format)
+{
+ return (format & bmFR_RX_FORMAT_WANT_Q) != 0;
+}
+
+bool
+usrp_standard_rx::format_bypass_halfband(unsigned int format)
+{
+ return (format & bmFR_RX_FORMAT_BYPASS_HB) != 0;
+}
+
+//////////////////////////////////////////////////////////////////
+
+
+// tx data is timed to CLKOUT1 (64 MHz)
+// interpolate 4x
+// fine modulator enabled
+
+
+static unsigned char tx_regs_use_nco[] = {
+ REG_TX_IF, (TX_IF_USE_CLKOUT1
+ | TX_IF_I_FIRST
+ | TX_IF_2S_COMP
+ | TX_IF_INTERLEAVED),
+ REG_TX_DIGITAL, (TX_DIGITAL_2_DATA_PATHS
+ | TX_DIGITAL_INTERPOLATE_4X)
+};
+
+
+static int
+real_tx_mux_value (int mux, int nchan)
+{
+ if (mux != -1)
+ return mux;
+
+ switch (nchan){
+ case 1:
+ return 0x0098;
+ case 2:
+ return 0xba98;
+ default:
+ assert (0);
+ }
+}
+
+usrp_standard_tx::usrp_standard_tx (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
+ )
+ : usrp_basic_tx (which_board, fusb_block_size, fusb_nblocks, fpga_filename, firmware_filename),
+ usrp_standard_common(this),
+ d_sw_mux (0x8), d_hw_mux (0x81)
+{
+ if (!usrp_9862_write_many_all (d_udh, tx_regs_use_nco, sizeof (tx_regs_use_nco))){
+ fprintf (stderr, "usrp_standard_tx: failed to init AD9862 TX regs\n");
+ throw std::runtime_error ("usrp_standard_tx::ctor");
+ }
+ if (!set_nchannels (nchan)){
+ fprintf (stderr, "usrp_standard_tx: set_nchannels failed\n");
+ throw std::runtime_error ("usrp_standard_tx::ctor");
+ }
+ if (!set_interp_rate (interp_rate)){
+ fprintf (stderr, "usrp_standard_tx: set_interp_rate failed\n");
+ throw std::runtime_error ("usrp_standard_tx::ctor");
+ }
+ if (!set_mux (real_tx_mux_value (mux, nchan))){
+ fprintf (stderr, "usrp_standard_tx: set_mux failed\n");
+ throw std::runtime_error ("usrp_standard_tx::ctor");
+ }
+
+ for (int i = 0; i < MAX_CHAN; i++){
+ d_tx_modulator_shadow[i] = (TX_MODULATOR_DISABLE_NCO
+ | TX_MODULATOR_COARSE_MODULATION_NONE);
+ d_coarse_mod[i] = CM_OFF;
+ set_tx_freq (i, 0);
+ }
+}
+
+usrp_standard_tx::~usrp_standard_tx ()
+{
+ // fprintf(stderr, "\nusrp_standard_tx: dtor\n");
+}
+
+bool
+usrp_standard_tx::start ()
+{
+ if (!usrp_basic_tx::start ())
+ return false;
+
+ // add our code here
+
+ return true;
+}
+
+bool
+usrp_standard_tx::stop ()
+{
+ bool ok = usrp_basic_tx::stop ();
+
+ // add our code here
+
+ return ok;
+}
+
+usrp_standard_tx *
+usrp_standard_tx::make (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
+ )
+{
+ usrp_standard_tx *u = 0;
+
+ try {
+ u = new usrp_standard_tx (which_board, interp_rate, nchan, mux,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename);
+ return u;
+ }
+ catch (...){
+ delete u;
+ return 0;
+ }
+
+ return u;
+}
+
+bool
+usrp_standard_tx::set_interp_rate (unsigned int rate)
+{
+ // fprintf (stderr, "usrp_standard_tx::set_interp_rate\n");
+
+ if ((rate & 0x3) || rate < 4 || rate > 512){
+ fprintf (stderr, "usrp_standard_tx::set_interp_rate: rate must be in [4, 512] and a multiple of 4.\n");
+ return false;
+ }
+
+ d_interp_rate = rate;
+ set_usb_data_rate ((dac_rate () / rate * nchannels ())
+ * (2 * sizeof (short)));
+
+ // We're using the interp by 4 feature of the 9862 so that we can
+ // use its fine modulator. Thus, we reduce the FPGA's interpolation rate
+ // by a factor of 4.
+
+ bool s = disable_tx ();
+ bool ok = _write_fpga_reg (FR_INTERP_RATE, d_interp_rate/4 - 1);
+ restore_tx (s);
+ return ok;
+}
+
+bool
+usrp_standard_tx::set_nchannels (int nchan)
+{
+ if (!(nchan == 1 || nchan == 2))
+ return false;
+
+ if (nchan > nducs())
+ return false;
+
+ d_nchan = nchan;
+ return write_hw_mux_reg ();
+}
+
+bool
+usrp_standard_tx::set_mux (int mux)
+{
+ d_sw_mux = mux;
+ d_hw_mux = mux << 4;
+ return write_hw_mux_reg ();
+}
+
+bool
+usrp_standard_tx::write_hw_mux_reg ()
+{
+ bool s = disable_tx ();
+ bool ok = _write_fpga_reg (FR_TX_MUX, d_hw_mux | d_nchan);
+ restore_tx (s);
+ return ok;
+}
+
+#ifdef USE_FPGA_TX_CORDIC
+
+bool
+usrp_standard_tx::set_tx_freq (int channel, double freq)
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return false;
+
+ // This assumes we're running the 4x on-chip interpolator.
+
+ unsigned int v =
+ compute_freq_control_word_fpga (dac_freq () / 4,
+ freq, &d_tx_freq[channel],
+ d_verbose);
+
+ return _write_fpga_reg (FR_TX_FREQ_0 + channel, v);
+}
+
+
+#else
+
+bool
+usrp_standard_tx::set_tx_freq (int channel, double freq)
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return false;
+
+ // split freq into fine and coarse components
+
+ coarse_mod_t cm;
+ double coarse;
+
+ assert (dac_freq () == 128000000);
+
+ if (freq < -44e6) // too low
+ return false;
+ else if (freq < -24e6){ // [-44, -24)
+ cm = CM_NEG_FDAC_OVER_4;
+ coarse = -dac_freq () / 4;
+ }
+ else if (freq < -8e6){ // [-24, -8)
+ cm = CM_NEG_FDAC_OVER_8;
+ coarse = -dac_freq () / 8;
+ }
+ else if (freq < 8e6){ // [-8, 8)
+ cm = CM_OFF;
+ coarse = 0;
+ }
+ else if (freq < 24e6){ // [8, 24)
+ cm = CM_POS_FDAC_OVER_8;
+ coarse = dac_freq () / 8;
+ }
+ else if (freq <= 44e6){ // [24, 44]
+ cm = CM_POS_FDAC_OVER_4;
+ coarse = dac_freq () / 4;
+ }
+ else // too high
+ return false;
+
+
+ set_coarse_modulator (channel, cm); // set bits in d_tx_modulator_shadow
+
+ double fine = freq - coarse;
+
+
+ // Compute fine tuning word...
+ // This assumes we're running the 4x on-chip interpolator.
+ // (This is required to use the fine modulator.)
+
+ unsigned int v =
+ compute_freq_control_word_9862 (dac_freq () / 4,
+ fine, &d_tx_freq[channel], d_verbose);
+
+ d_tx_freq[channel] += coarse; // adjust actual
+
+ unsigned char high, mid, low;
+
+ high = (v >> 16) & 0xff;
+ mid = (v >> 8) & 0xff;
+ low = (v >> 0) & 0xff;
+
+ bool ok = true;
+
+ // write the fine tuning word
+ ok &= _write_9862 (channel, REG_TX_NCO_FTW_23_16, high);
+ ok &= _write_9862 (channel, REG_TX_NCO_FTW_15_8, mid);
+ ok &= _write_9862 (channel, REG_TX_NCO_FTW_7_0, low);
+
+
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_ENABLE_NCO;
+
+ if (fine < 0)
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_NEG_FINE_TUNE;
+ else
+ d_tx_modulator_shadow[channel] &= ~TX_MODULATOR_NEG_FINE_TUNE;
+
+ ok &=_write_9862 (channel, REG_TX_MODULATOR, d_tx_modulator_shadow[channel]);
+
+ return ok;
+}
+#endif
+
+bool
+usrp_standard_tx::set_coarse_modulator (int channel, coarse_mod_t cm)
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return false;
+
+ switch (cm){
+ case CM_NEG_FDAC_OVER_4:
+ d_tx_modulator_shadow[channel] &= ~TX_MODULATOR_CM_MASK;
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_COARSE_MODULATION_F_OVER_4;
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_NEG_COARSE_TUNE;
+ break;
+
+ case CM_NEG_FDAC_OVER_8:
+ d_tx_modulator_shadow[channel] &= ~TX_MODULATOR_CM_MASK;
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_COARSE_MODULATION_F_OVER_8;
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_NEG_COARSE_TUNE;
+ break;
+
+ case CM_OFF:
+ d_tx_modulator_shadow[channel] &= ~TX_MODULATOR_CM_MASK;
+ break;
+
+ case CM_POS_FDAC_OVER_8:
+ d_tx_modulator_shadow[channel] &= ~TX_MODULATOR_CM_MASK;
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_COARSE_MODULATION_F_OVER_8;
+ break;
+
+ case CM_POS_FDAC_OVER_4:
+ d_tx_modulator_shadow[channel] &= ~TX_MODULATOR_CM_MASK;
+ d_tx_modulator_shadow[channel] |= TX_MODULATOR_COARSE_MODULATION_F_OVER_4;
+ break;
+
+ default:
+ return false;
+ }
+
+ d_coarse_mod[channel] = cm;
+ return true;
+}
+
+unsigned int
+usrp_standard_tx::interp_rate () const { return d_interp_rate; }
+
+int
+usrp_standard_tx::nchannels () const { return d_nchan; }
+
+int
+usrp_standard_tx::mux () const { return d_sw_mux; }
+
+double
+usrp_standard_tx::tx_freq (int channel) const
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return 0;
+
+ return d_tx_freq[channel];
+}
+
+usrp_standard_tx::coarse_mod_t
+usrp_standard_tx::coarse_modulator (int channel) const
+{
+ if (channel < 0 || channel >= MAX_CHAN)
+ return CM_OFF;
+
+ return d_coarse_mod[channel];
+}
diff --git a/usrp/host/lib/usrp_standard.h b/usrp/host/lib/usrp_standard.h
new file mode 100644
index 000000000..9f468a68d
--- /dev/null
+++ b/usrp/host/lib/usrp_standard.h
@@ -0,0 +1,366 @@
+/* -*- 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_USRP_STANDARD_H
+#define INCLUDED_USRP_STANDARD_H
+
+#include <usrp_basic.h>
+
+class usrp_standard_common
+{
+ int d_fpga_caps; // capability register val
+
+protected:
+ usrp_standard_common(usrp_basic *parent);
+
+public:
+ /*!
+ *\brief does the FPGA implement the final Rx half-band filter?
+ * If it doesn't, the maximum decimation factor with proper gain
+ * is 1/2 of what it would otherwise be.
+ */
+ bool has_rx_halfband() const;
+
+ /*!
+ * \brief number of digital downconverters implemented in the FPGA
+ * This will be 0, 1, 2 or 4.
+ */
+ int nddcs() const;
+
+ /*!
+ *\brief does the FPGA implement the initial Tx half-band filter?
+ */
+ bool has_tx_halfband() const;
+
+ /*!
+ * \brief number of digital upconverters implemented in the FPGA
+ * This will be 0, 1, or 2.
+ */
+ int nducs() const;
+};
+
+/*!
+ * \brief standard usrp RX class.
+ *
+ * Assumes digital down converter in FPGA
+ */
+class usrp_standard_rx : public usrp_basic_rx, usrp_standard_common
+{
+ private:
+ static const int MAX_CHAN = 4;
+ unsigned int d_decim_rate;
+ int d_nchan;
+ int d_sw_mux;
+ int d_hw_mux;
+ double d_rx_freq[MAX_CHAN];
+
+ protected:
+ usrp_standard_rx (int which_board,
+ unsigned int decim_rate,
+ int nchan = 1,
+ int mux = -1,
+ int mode = 0,
+ int fusb_block_size = 0,
+ int fusb_nblocks = 0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ ); // throws if trouble
+
+ bool write_hw_mux_reg ();
+
+ public:
+
+ enum {
+ FPGA_MODE_NORMAL = 0x00,
+ FPGA_MODE_LOOPBACK = 0x01,
+ FPGA_MODE_COUNTING = 0x02,
+ FPGA_MODE_COUNTING_32BIT = 0x04
+ };
+
+ ~usrp_standard_rx ();
+
+ /*!
+ * \brief invokes constructor, returns instance or 0 if trouble
+ *
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ */
+ static usrp_standard_rx *make (int which_board,
+ unsigned int decim_rate,
+ int nchan = 1,
+ int mux = -1,
+ int mode = 0,
+ int fusb_block_size = 0,
+ int fusb_nblocks = 0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+ /*!
+ * \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 () * nchannels ()
+ */
+ bool set_decim_rate (unsigned int rate);
+
+ /*!
+ * \brief Set number of active channels. \p nchannels must be 1, 2 or 4.
+ *
+ * The final complex sample rate across the USB is
+ * adc_freq () / decim_rate () * nchannels ()
+ */
+ bool set_nchannels (int nchannels);
+
+ /*!
+ * \brief Set input mux configuration.
+ *
+ * This determines which ADC (or constant zero) is connected to
+ * each DDC input. There are 4 DDCs. Each has two inputs.
+ *
+ * <pre>
+ * Mux value:
+ *
+ * 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
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Q3 | I3 | Q2 | I2 | Q1 | I1 | Q0 | I0 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * Each 4-bit I field is either 0,1,2,3
+ * Each 4-bit Q field is either 0,1,2,3 or 0xf (input is const zero)
+ * All Q's must be 0xf or none of them may be 0xf
+ * </pre>
+ */
+ bool set_mux (int mux);
+
+ /*!
+ * \brief set the frequency of the digital down converter.
+ *
+ * \p channel must be in the range [0,3]. \p freq is the center
+ * frequency in Hz. \p freq may be either negative or postive.
+ * 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 mode
+ */
+ 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);
+
+ /*!
+ * \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);
+
+ 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);
+
+ // ACCESSORS
+ unsigned int decim_rate () const;
+ double rx_freq (int channel) const;
+ int nchannels () const;
+ int mux () const;
+ unsigned int format () const;
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+// ----------------------------------------------------------------
+
+/*!
+ * \brief standard usrp TX class.
+ *
+ * Uses digital upconverter (coarse & fine modulators) in AD9862...
+ */
+class usrp_standard_tx : public usrp_basic_tx, usrp_standard_common
+{
+ public:
+ enum coarse_mod_t {
+ CM_NEG_FDAC_OVER_4, // -32 MHz
+ CM_NEG_FDAC_OVER_8, // -16 MHz
+ CM_OFF,
+ CM_POS_FDAC_OVER_8, // +16 MHz
+ CM_POS_FDAC_OVER_4 // +32 MHz
+ };
+
+ protected:
+ static const int MAX_CHAN = 2;
+ unsigned int d_interp_rate;
+ int d_nchan;
+ int d_sw_mux;
+ int d_hw_mux;
+ double d_tx_freq[MAX_CHAN];
+ coarse_mod_t d_coarse_mod[MAX_CHAN];
+ unsigned char d_tx_modulator_shadow[MAX_CHAN];
+
+ virtual bool set_coarse_modulator (int channel, coarse_mod_t cm);
+ usrp_standard_tx::coarse_mod_t coarse_modulator (int channel) const;
+
+ protected:
+ usrp_standard_tx (int which_board,
+ unsigned int interp_rate,
+ int nchan = 1,
+ int mux = -1,
+ int fusb_block_size = 0,
+ int fusb_nblocks = 0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ ); // throws if trouble
+
+ bool write_hw_mux_reg ();
+
+ public:
+ ~usrp_standard_tx ();
+
+ /*!
+ * \brief invokes constructor, returns instance or 0 if trouble
+ *
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ */
+ static usrp_standard_tx *make (int which_board,
+ unsigned int interp_rate,
+ int nchan = 1,
+ int mux = -1,
+ int fusb_block_size = 0,
+ int fusb_nblocks = 0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+
+ /*!
+ * \brief Set interpolator rate. \p rate must be in [4, 512] and a multiple of 4.
+ *
+ * The final complex sample rate across the USB is
+ * dac_freq () / interp_rate () * nchannels ()
+ */
+ virtual bool set_interp_rate (unsigned int rate);
+
+ /*!
+ * \brief Set number of active channels. \p nchannels must be 1 or 2.
+ *
+ * The final complex sample rate across the USB is
+ * dac_freq () / decim_rate () * nchannels ()
+ */
+ bool set_nchannels (int nchannels);
+
+ /*!
+ * \brief Set output mux configuration.
+ *
+ * <pre>
+ * 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
+ * +-------------------------------+-------+-------+-------+-------+
+ * | | DAC3 | DAC2 | DAC1 | DAC0 |
+ * +-------------------------------+-------+-------+-------+-------+
+ *
+ * There are two interpolators with complex inputs and outputs.
+ * There are four DACs.
+ *
+ * Each 4-bit DACx field specifies the source for the DAC and
+ * whether or not that DAC is enabled. Each subfield is coded
+ * like this:
+ *
+ * 3 2 1 0
+ * +-+-----+
+ * |E| N |
+ * +-+-----+
+ *
+ * Where E is set if the DAC is enabled, and N specifies which
+ * interpolator output is connected to this DAC.
+ *
+ * N which interp output
+ * --- -------------------
+ * 0 chan 0 I
+ * 1 chan 0 Q
+ * 2 chan 1 I
+ * 3 chan 1 Q
+ * </pre>
+ */
+ bool set_mux (int mux);
+
+ /*!
+ * \brief set the frequency of the digital up converter.
+ *
+ * \p channel must be in the range [0,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.
+ */
+ virtual bool set_tx_freq (int channel, double freq); // chan: [0,1]
+
+ // ACCESSORS
+ unsigned int interp_rate () const;
+ double tx_freq (int channel) const;
+ int nchannels () const;
+ int mux () const;
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+#endif /* INCLUDED_USRP_STANDARD_H */