USRP_INCLUDES = @usrp_INCLUDES@
USRP_LA = @usrp_LA@
-# How to link in usrp-inband library from inside the tree
-USRP_INBAND_INCLUDES = @usrp_inband_INCLUDES@
-USRP_INBAND_LA = @usrp_inband_LA@
-
# How to link the PMT library from inside the tree
PMT_INCLUDES = @pmt_INCLUDES@
PMT_LA = @pmt_LA@
AC_DEFUN([GRC_USRP],[
GRC_ENABLE(usrp)
- GRC_WITH(usrp, [GRC_WITH_PKG_CONFIG_CHECK(usrp-inband)])
+ GRC_WITH(usrp)
- dnl Don't do usrp if omnithread, mblock, or pmt skipped
+ dnl Don't do usrp if omnithread skipped
GRC_CHECK_DEPENDENCY(usrp, omnithread)
- GRC_CHECK_DEPENDENCY(usrp, mblock)
- GRC_CHECK_DEPENDENCY(usrp, pmt)
dnl Make sure the fast usb technique is set, OS dependent.
dnl This is always performed, since it puts out CLI flags.
AC_CHECK_FUNCS([getrusage sched_setscheduler pthread_setschedparam])
AC_CHECK_FUNCS([sigaction snprintf])
- dnl Don't do usrp if guile not available (inband requires it)
- GRC_CHECK_GUILE(usrp)
-
dnl Make sure libusb is installed; required for legacy USB
USRP_LIBUSB([],[passed=no;AC_MSG_RESULT([Unable to find dependency libusb.])])
fi
if test $passed != with; then
dnl how and where to find INCLUDES and LA
- usrp_INCLUDES="-I\${abs_top_srcdir}/usrp/host/lib/legacy \
- -I\${abs_top_srcdir}/usrp/firmware/include \
- -I\${abs_top_builddir}/usrp/host/lib/legacy"
- usrp_LA="\${abs_top_builddir}/usrp/host/lib/legacy/libusrp.la"
- usrp_inband_INCLUDES="-I\${abs_top_srcdir}/usrp/host/lib/inband"
- usrp_inband_LA="\${abs_top_builddir}/usrp/host/lib/inband/libusrp-inband.la"
+ usrp_INCLUDES=" \
+ -I\${abs_top_srcdir}/usrp/host/include \
+ -I\${abs_top_builddir}/usrp/host/include \
+ -I\${abs_top_srcdir}/usrp/firmware/include"
+ usrp_LA="\${abs_top_builddir}/usrp/host/lib/libusrp.la"
fi
- dnl Include the usrp-inband INCLUDES and LA
- AC_SUBST(usrp_inband_INCLUDES)
- AC_SUBST(usrp_inband_LA)
-
- dnl There are 2 pkg-config files (usrp, and usrp-inband); the one
- dnl for usrp requires omnithread for Darwin only. Create a variable
+ dnl There pkg-config file for usrp requires omnithread for Darwin only. Create a variable
dnl for just the usrp.pc.in case.
case "$host_os" in
darwin*)
AC_CONFIG_FILES([ \
usrp/Makefile \
usrp/usrp.pc \
- usrp/usrp-inband.pc \
usrp/usrp.iss \
usrp/doc/Doxyfile \
usrp/doc/Makefile \
usrp/doc/other/Makefile \
usrp/host/Makefile \
+ usrp/host/include/Makefile \
+ usrp/host/include/usrp/Makefile \
usrp/host/misc/Makefile \
usrp/host/lib/Makefile \
- usrp/host/lib/inband/Makefile \
- usrp/host/lib/legacy/Makefile \
- usrp/host/lib/legacy/std_paths.h \
+ usrp/host/lib/std_paths.h \
usrp/host/swig/Makefile \
usrp/host/apps/Makefile \
- usrp/host/apps-inband/Makefile \
usrp/firmware/Makefile \
usrp/firmware/include/Makefile \
usrp/firmware/lib/Makefile \
// WAV files are always little-endian, so we need some byte switching macros
-// FIXME: These need to be refactored into a separate endianess header file
-// as they duplicate routines defined in usrp/host/lib/legacy/usrp_bytesex.h
+// FIXME: Use libgruel versions
#ifdef WORDS_BIGENDIAN
# For compiling within the GNU Radio build tree
AM_CPPFLAGS=$(STD_DEFINES_AND_INCLUDES) \
-I$(top_srcdir)/gr-usrp/src \
- -I$(top_srcdir)/usrp/host/lib/legacy \
- -I\${abs_top_builddir}/usrp/host/lib/legacy \
- -I$(top_srcdir)/usrp/firmware/include \
+ $(USRP_INCLUDES) \
$(WITH_INCLUDES)
GR_USRP_LA=$(top_builddir)/gr-usrp/src/libgnuradio-usrp.la
/* -*- c++ -*- */
/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <config.h>
#endif
#include <usrp_base.h>
-#include <usrp_basic.h>
+#include <usrp/usrp_basic.h>
class truth_table_element_t
{
/* -*- c++ -*- */
/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <gr_sync_block.h>
#include <stdexcept>
#include <boost/shared_ptr.hpp>
-#include <db_base.h>
-#include <usrp_subdev_spec.h>
+#include <usrp/db_base.h>
+#include <usrp/usrp_subdev_spec.h>
class usrp_basic;
/* -*- c++ -*- */
/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_sink_base.h>
#include <gr_io_signature.h>
-#include <usrp_standard.h>
+#include <usrp/usrp_standard.h>
#include <assert.h>
#include <cstdio>
/* -*- c++ -*- */
/*
- * Copyright 2004,2006,2008 Free Software Foundation, Inc.
+ * Copyright 2004,2006,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_base.h>
#include <stdexcept>
-#include <usrp_tune_result.h>
-#include <usrp_dbid.h>
+#include <usrp/usrp_tune_result.h>
+#include <usrp/usrp_dbid.h>
class usrp_standard_tx;
/* -*- c++ -*- */
/*
- * Copyright 2004,2006 Free Software Foundation, Inc.
+ * Copyright 2004,2006,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_sink_c.h>
#include <gr_io_signature.h>
-#include <usrp_standard.h>
-#include <usrp_bytesex.h>
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
usrp_sink_c_sptr
usrp_make_sink_c (int which_board,
/* -*- c++ -*- */
/*
- * Copyright 2004,2006 Free Software Foundation, Inc.
+ * Copyright 2004,2006,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_sink_s.h>
#include <gr_io_signature.h>
-#include <usrp_standard.h>
-#include <usrp_bytesex.h>
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
usrp_sink_s_sptr
usrp_make_sink_s (int which_board,
/* -*- c++ -*- */
/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_source_base.h>
#include <gr_io_signature.h>
-#include <usrp_standard.h>
+#include <usrp/usrp_standard.h>
#include <assert.h>
#include <cstdio>
/* -*- c++ -*- */
/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_base.h>
#include <stdexcept>
-#include <usrp_tune_result.h>
-#include <usrp_dbid.h>
+#include <usrp/usrp_tune_result.h>
+#include <usrp/usrp_dbid.h>
class usrp_standard_rx;
/* -*- c++ -*- */
/*
- * Copyright 2004,2006 Free Software Foundation, Inc.
+ * Copyright 2004,2006,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_source_c.h>
#include <gr_io_signature.h>
-#include <usrp_standard.h>
-#include <usrp_bytesex.h>
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
static const int NBASIC_SAMPLES_PER_ITEM = 2; // I & Q
/* -*- c++ -*- */
/*
- * Copyright 2004,2006 Free Software Foundation, Inc.
+ * Copyright 2004,2006,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <usrp_source_s.h>
#include <gr_io_signature.h>
-#include <usrp_standard.h>
-#include <usrp_bytesex.h>
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
static const int NBASIC_SAMPLES_PER_ITEM = 1;
/* -*- c++ -*- */
/*
- * Copyright 2008 Free Software Foundation, Inc.
+ * Copyright 2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
// FIXME: move to usrp/usrpm component
%{
-#include <usrp_standard.h>
+#include <usrp/usrp_standard.h>
#include <usrp_spi_defs.h>
-#include <usrp_dbid.h>
+#include <usrp/usrp_dbid.h>
%}
%include <usrp_spi_defs.h>
-%include <usrp_dbid.h>
+%include <usrp/usrp_dbid.h>
%constant int FPGA_MODE_NORMAL = usrp_standard_rx::FPGA_MODE_NORMAL;
%constant int FPGA_MODE_LOOPBACK = usrp_standard_rx::FPGA_MODE_LOOPBACK;
#include <vector>
%}
-%include <usrp_subdev_spec.h>
-%include <db_base.i>
+%include <usrp/usrp_subdev_spec.h>
+%include <usrp/db_base.i>
%include <fpga_regs_common.h>
%include <fpga_regs_standard.h>
%include "usrp_standard.i"
EXTRA_DIST = \
usrp.pc.in \
- usrp-inband.pc.in \
usrp.iss.in \
usrp.inf
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
- usrp.pc \
- usrp-inband.pc
-
+ usrp.pc
# Boston, MA 02110-1301, USA.
#
-include_HEADERS = \
+usrpincludedir = $(includedir)/usrp
+
+usrpinclude_HEADERS = \
usrp_i2c_addr.h \
usrp_spi_defs.h \
fpga_regs_common.h \
# Boston, MA 02110-1301, USA.
#
-SUBDIRS = misc lib apps apps-inband
+SUBDIRS = misc lib include apps
if PYTHON
SUBDIRS += swig
+++ /dev/null
-#
-# Copyright 2003,2006,2008 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-include $(top_srcdir)/Makefile.common
-
-AM_CPPFLAGS = \
- $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \
- $(USRP_INCLUDES) $(USRP_INBAND_INCLUDES) $(BOOST_CPPFLAGS) \
- $(CPPUNIT_INCLUDES) $(WITH_INCLUDES) -I$(top_srcdir)/mblock/src/lib
-
-
-bin_PROGRAMS =
-
-noinst_PROGRAMS = \
- test_usrp_inband_ping \
- test_usrp_inband_registers \
- test_usrp_inband_rx \
- test_usrp_inband_2rx \
- test_usrp_inband_tx \
- test_usrp_inband_2tx \
- test_usrp_inband_timestamps \
- test_usrp_inband_overrun \
- test_usrp_inband_underrun \
- read_packets
-
-noinst_HEADERS = \
- ui_nco.h \
- ui_sincos.h
-
-
-test_usrp_inband_ping_SOURCES = test_usrp_inband_ping.cc
-test_usrp_inband_ping_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_tx_SOURCES = test_usrp_inband_tx.cc ui_sincos.c
-test_usrp_inband_tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_2tx_SOURCES = test_usrp_inband_2tx.cc ui_sincos.c
-test_usrp_inband_2tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_timestamps_SOURCES = test_usrp_inband_timestamps.cc ui_sincos.c
-test_usrp_inband_timestamps_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_registers_SOURCES = test_usrp_inband_registers.cc ui_sincos.c
-test_usrp_inband_registers_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_overrun_SOURCES = test_usrp_inband_overrun.cc
-test_usrp_inband_overrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_underrun_SOURCES = test_usrp_inband_underrun.cc
-test_usrp_inband_underrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_rx_SOURCES = test_usrp_inband_rx.cc ui_sincos.c
-test_usrp_inband_rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-test_usrp_inband_2rx_SOURCES = test_usrp_inband_2rx.cc ui_sincos.c
-test_usrp_inband_2rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
-
-read_packets_SOURCES = read_packets.cc
-read_packets_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <iostream>
-#include <usrp_inband_usb_packet.h>
-#include <mblock/class_registry.h>
-#include <vector>
-#include <usrp_usb_interface.h>
-#include <fstream>
-
-typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
-
-int main(int argc, char *argv[]) {
-
- if(argc !=2) {
- std::cout << "Usage: ./read_packets <data_file>\n";
- return -1;
- }
-
- std::ifstream infile;
- std::ofstream outfile;
-
- unsigned int pkt_size = transport_pkt::max_pkt_size();
- unsigned int pkt_num=0;
-
- transport_pkt *pkt;
- char pkt_data[pkt_size]; // allocate the number of bytes for a single packet
-
- pkt = (transport_pkt *)pkt_data; // makes operations cleaner to read
-
- // Open the file and read the packets, dumping information
- infile.open(argv[1], std::ios::binary|std::ios::in);
- if(!infile.is_open())
- exit(-1);
-
- //outfile.open("dump.dat",std::ios::out|std::ios::binary);
-
- // read 1 packet in to the memory
- infile.read(pkt_data, pkt_size);
-
- while(!infile.eof()) {
-
- printf("Packet %u\n", pkt_num);
-
- if(pkt->start_of_burst())
- printf("\tstart of burst\n");
-
- if(pkt->end_of_burst())
- printf("\tend of burst\n");
-
-// if(pkt->carrier_sense())
-// printf("\tcarrier sense\n");
-
- if(pkt->underrun())
- printf("\tunderrun\n");
-
- if(pkt->overrun())
- printf("\toverrun\n");
-
- printf("\tchannel: \t0x%x\n", pkt->chan());
- printf("\ttimestamp: \t0x%x\n", pkt->timestamp());
- //printf("\ttimestamp: \t%u\n", pkt->timestamp());
- printf("\tlength: \t%u\n", pkt->payload_len());
- printf("\trssi: \t%u\n", pkt->rssi());
-
- printf("\tpayload: \n");
- for(int i=0; i < pkt->payload_len(); i++)
- //for(int i=0; i < pkt->max_payload(); i++)
- {
- printf("\t%d\t0x%x\n", i, *(pkt->payload()+i));
- //outfile.write((const char*)(pkt->payload()+i),1);
- //printf("\t\t0x%x\n", pkt->payload()+i);
-
- }
- printf("\n\n");
-
- pkt_num++;
-
- // read 1 packet in to the memory
- infile.read(pkt_data, pkt_size);
-
- }
-
- infile.close();
- //outfile.close();
-
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mb_runtime_nop.h> // QA only
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mb_mblock_impl.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <iostream>
-#include <fstream>
-
-// Include the symbols needed for communication with USRP server
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_rx.h>
-
-static bool verbose = true;
-
-class test_usrp_rx : public mb_mblock
-{
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
- pmt_t d_rx_chan0, d_rx_chan1;
-
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNEL,
- RECEIVING,
- CLOSING_CHANNEL,
- CLOSING_USRP,
- };
-
- state_t d_state;
-
- std::ofstream d_ofile;
-
- long d_samples_recvd;
- long d_samples_to_recv;
-
- public:
- test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_rx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void open_usrp();
- void close_usrp();
- void allocate_channel();
- void send_packets();
- void enter_receiving();
- void build_and_send_next_frame();
- void handle_response_recv_raw_samples(pmt_t invocation_handle);
- void enter_closing_channel();
-};
-
-test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_rx_chan0(PMT_NIL), d_rx_chan1(PMT_NIL),
- d_samples_recvd(0),
- d_samples_to_recv(20e6)
-{
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
- pmt_t usrp_dict = pmt_make_dict();
-
- // To test the application without a USRP
- bool fake_usrp_p = false;
- if(fake_usrp_p) {
- pmt_dict_set(usrp_dict,
- pmt_intern("fake-usrp"),
- PMT_T);
- }
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_2rxhb_2tx.rbf"));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(64));
-
- define_component("server", "usrp_server", usrp_dict);
-
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-test_usrp_rx::~test_usrp_rx()
-{
-}
-
-void
-test_usrp_rx::initial_transition()
-{
- open_usrp();
-}
-
-void
-test_usrp_rx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- switch(d_state){
-
- //----------------------------- OPENING_USRP ----------------------------//
- // We only expect a response from opening the USRP which should be succesful
- // or failed.
- case OPENING_USRP:
- if (pmt_eq(event, s_response_open)){
- status = pmt_nth(1, data);
- if (pmt_eq(status, PMT_T)){
- allocate_channel();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
- }
- goto unhandled;
-
- //----------------------- ALLOCATING CHANNELS --------------------//
- // Allocate an RX channel to perform the overrun test.
- case ALLOCATING_CHANNEL:
- if (pmt_eq(event, s_response_allocate_channel)){
- status = pmt_nth(1, data);
- if(pmt_eqv(d_rx_chan0, PMT_NIL))
- d_rx_chan0 = pmt_nth(2, data);
- else
- d_rx_chan1 = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T) && !pmt_eqv(d_rx_chan1, PMT_NIL)){
- enter_receiving();
- return;
- }
- else if(pmt_eq(status, PMT_F)){
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- return;
- }
- goto unhandled;
-
- //--------------------------- RECEIVING ------------------------------//
- // In the receiving state, we receive samples until the specified amount
- // while counting the number of overruns.
- case RECEIVING:
- if (pmt_eq(event, s_response_recv_raw_samples)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_response_recv_raw_samples(data);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
- goto unhandled;
-
- //------------------------- CLOSING CHANNEL ----------------------------//
- // Check deallocation response for the RX channel
- case CLOSING_CHANNEL:
- if (pmt_eq(event, s_response_deallocate_channel)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- close_usrp();
- return;
- }
- else {
- error_msg = "failed to deallocate channel:";
- goto bail;
- }
- }
-
- // Alternately, we ignore all response recv samples while waiting for the
- // channel to actually close
- if (pmt_eq(event, s_response_recv_raw_samples))
- return;
-
- goto unhandled;
-
- //--------------------------- CLOSING USRP ------------------------------//
- // Once we have received a successful USRP close response, we shutdown all
- // mblocks and exit.
- case CLOSING_USRP:
- if (pmt_eq(event, s_response_close)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- fflush(stdout);
- shutdown_all(PMT_T);
- return;
- }
- else {
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
- goto unhandled;
-
- default:
- goto unhandled;
- }
- return;
-
- // An error occured, print it, and shutdown all m-blocks
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- // Received an unhandled message for a specific state
- unhandled:
- if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-}
-
-
-void
-test_usrp_rx::open_usrp()
-{
- pmt_t which_usrp = pmt_from_long(0);
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
- d_state = OPENING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n";
-}
-
-void
-test_usrp_rx::close_usrp()
-{
-
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
- d_state = CLOSING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n";
-}
-
-void
-test_usrp_rx::allocate_channel()
-{
- long capacity = (long) 16e6;
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_state = ALLOCATING_CHANNEL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n";
-}
-
-void
-test_usrp_rx::enter_receiving()
-{
- d_state = RECEIVING;
-
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan0));
-
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan1));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n";
-}
-
-void
-test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t v_samples = pmt_nth(2, data);
- pmt_t timestamp = pmt_nth(3, data);
- pmt_t channel = pmt_nth(4, data);
- pmt_t properties = pmt_nth(5, data);
-
- d_samples_recvd += pmt_length(v_samples) / 4;
-
- // Check for overrun
- if(!pmt_is_dict(properties)) {
- std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n";
- return;
- }
-
- // Check if the number samples we have received meets the test
- if(d_samples_recvd >= d_samples_to_recv) {
- d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan0));
- d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan1));
- enter_closing_channel();
- return;
- }
-
-}
-
-void
-test_usrp_rx::enter_closing_channel()
-{
- d_state = CLOSING_CHANNEL;
-
- d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan0));
- d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan1));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n";
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_rx);
-
-
-// ----------------------------------------------------------------
-
-int
-main (int argc, char **argv)
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_rx", PMT_F, &result);
-
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mb_runtime_nop.h> // QA only
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mb_mblock_impl.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <iostream>
-
-#include <ui_nco.h>
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_tx.h>
-
-static bool verbose = true;
-
-class test_usrp_tx : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_cs;
- pmt_t d_tx_chan0, d_tx_chan1;
-
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNEL,
- TRANSMITTING,
- CLOSING_CHANNEL,
- CLOSING_USRP,
- };
-
- state_t d_state;
- long d_nsamples_to_send;
- long d_nsamples_xmitted;
- long d_nframes_xmitted;
- long d_samples_per_frame;
- bool d_done_sending;
-
- // for generating sine wave output
- ui_nco<float,float> d_nco;
- double d_amplitude;
-
- public:
- test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_tx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void open_usrp();
- void close_usrp();
- void allocate_channel();
- void send_packets();
- void enter_transmitting();
- void build_and_send_next_frame();
- void handle_xmit_response(pmt_t invocation_handle);
- void enter_closing_channel();
-};
-
-test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_tx_chan0(PMT_NIL), d_tx_chan1(PMT_NIL),
- d_state(INIT), d_nsamples_to_send((long) 80e6),
- d_nsamples_xmitted(0),
- d_nframes_xmitted(0),
- d_samples_per_frame((long)(126 * 4)), // full packet
- d_done_sending(false),
- d_amplitude(16384)
-{
- // std::cout << "[TEST_USRP_TX] Initializing...\n";
-
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- //bool fake_usrp_p = true;
- bool fake_usrp_p = false;
-
- // Test the TX side
-
- pmt_t usrp_dict = pmt_make_dict();
-
- if(fake_usrp_p) {
- pmt_dict_set(usrp_dict,
- pmt_intern("fake-usrp"),
- PMT_T);
- }
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_2rxhb_2tx.rbf"));
-
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("interp-tx"),
- pmt_from_long(128));
-
-// pmt_dict_set(usrp_dict,
-// pmt_intern("rf-freq"),
-// pmt_from_long(10e6));
-
- define_component("server", "usrp_server", usrp_dict);
-
- connect("self", "tx0", "server", "tx0");
- connect("self", "cs", "server", "cs");
-
- // initialize NCO
- double freq = 100e3;
- int interp = 32; // 32 -> 4MS/s
- double sample_rate = 128e6 / interp;
- d_nco.set_freq(2*M_PI * freq/sample_rate);
-
- // FIXME need to somehow set the interp rate in the USRP.
- // for now, we'll have the low-level code hardwire it.
-}
-
-test_usrp_tx::~test_usrp_tx()
-{
-}
-
-void
-test_usrp_tx::initial_transition()
-{
- open_usrp();
-}
-
-void
-test_usrp_tx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- //std::cout << msg << std::endl;
-
- switch(d_state){
- case OPENING_USRP:
- if (pmt_eq(event, s_response_open)){
- status = pmt_nth(1, data);
- if (pmt_eq(status, PMT_T)){
- allocate_channel();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
- }
- goto unhandled;
-
- case ALLOCATING_CHANNEL:
- if (pmt_eq(event, s_response_allocate_channel)){
- status = pmt_nth(1, data);
- if(pmt_eqv(d_tx_chan0, PMT_NIL))
- d_tx_chan0 = pmt_nth(2, data);
- else
- d_tx_chan1 = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T) && !pmt_eqv(d_tx_chan1, PMT_NIL)){
- enter_transmitting();
- return;
- }
- else if(pmt_eq(status, PMT_F)){
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- return;
- }
- goto unhandled;
-
- case TRANSMITTING:
- if (pmt_eq(event, s_response_xmit_raw_frame)){
- handle = pmt_nth(0, data);
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_xmit_response(handle);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
- goto unhandled;
-
- case CLOSING_CHANNEL:
- if (pmt_eq(event, s_response_deallocate_channel)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- close_usrp();
- return;
- }
- else {
- error_msg = "failed to deallocate channel:";
- goto bail;
- }
- }
- goto unhandled;
-
- case CLOSING_USRP:
- if (pmt_eq(event, s_response_close)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- shutdown_all(PMT_T);
- return;
- }
- else {
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
- goto unhandled;
-
- default:
- goto unhandled;
- }
- return;
-
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- unhandled:
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-}
-
-
-void
-test_usrp_tx::open_usrp()
-{
- pmt_t which_usrp = pmt_from_long(0);
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
- d_state = OPENING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n";
-}
-
-void
-test_usrp_tx::close_usrp()
-{
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
- d_state = CLOSING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n";
-}
-
-void
-test_usrp_tx::allocate_channel()
-{
- long capacity = (long) 16e6;
-
- // Send two capacity requests, which will allocate us two channels
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_state = ALLOCATING_CHANNEL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n";
-}
-
-void
-test_usrp_tx::enter_transmitting()
-{
- d_state = TRANSMITTING;
- d_nsamples_xmitted = 0;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n";
-
- build_and_send_next_frame(); // fire off 4 to start pipeline
- build_and_send_next_frame();
- build_and_send_next_frame();
- build_and_send_next_frame();
-}
-
-void
-test_usrp_tx::build_and_send_next_frame()
-{
- // allocate the uniform vector for the samples
- // FIXME perhaps hold on to this between calls
-
-#if 1
- long nsamples_this_frame =
- std::min(d_nsamples_to_send - d_nsamples_xmitted,
- d_samples_per_frame);
-#else
- long nsamples_this_frame = d_samples_per_frame;
-#endif
-
- if (nsamples_this_frame == 0){
- d_done_sending = true;
- return;
- }
-
-
- size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
- pmt_t uvec = pmt_make_s16vector(nshorts, 0);
- size_t ignore;
- int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
-
- // fill in the complex sinusoid
-
- for (int i = 0; i < nsamples_this_frame; i++){
-
- if (1){
- gr_complex s;
- d_nco.sincos(&s, 1, d_amplitude);
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- else {
- gr_complex s(d_amplitude, d_amplitude);
-
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- }
-
- pmt_t tx_properties = pmt_make_dict();
-
- pmt_t timestamp = pmt_from_long(0xffffffff); // NOW
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle
- d_tx_chan0, // channel
- uvec, // the samples
- timestamp,
- tx_properties));
-
- // Resend on channel 1
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle
- d_tx_chan1, // channel
- uvec, // the samples
- timestamp,
- tx_properties));
-
- d_nsamples_xmitted += nsamples_this_frame;
- d_nframes_xmitted++;
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n";
-}
-
-
-void
-test_usrp_tx::handle_xmit_response(pmt_t handle)
-{
- if (d_done_sending &&
- pmt_to_long(handle) == (d_nframes_xmitted - 1)){
- // We're done sending and have received all responses
- enter_closing_channel();
- }
-
- build_and_send_next_frame();
-}
-
-void
-test_usrp_tx::enter_closing_channel()
-{
- d_state = CLOSING_CHANNEL;
-
- // Deallocate both channels
- d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan0));
- d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan1));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n";
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_tx);
-
-
-// ----------------------------------------------------------------
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_tx", PMT_F, &result);
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <iostream>
-#include <fstream>
-
-// Include the symbols needed for communication with USRP server
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_rx.h>
-
-static bool verbose = true;
-
-class test_usrp_rx : public mb_mblock
-{
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
- pmt_t d_rx_chan; // returned tx channel handle
-
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNEL,
- RECEIVING,
- CLOSING_CHANNEL,
- CLOSING_USRP,
- };
-
- state_t d_state;
-
- std::ofstream d_ofile;
-
- long d_n_overruns;
-
- long d_samples_recvd;
- long d_samples_to_recv;
-
- public:
- test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_rx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void open_usrp();
- void close_usrp();
- void allocate_channel();
- void send_packets();
- void enter_receiving();
- void build_and_send_next_frame();
- void handle_response_recv_raw_samples(pmt_t invocation_handle);
- void enter_closing_channel();
-};
-
-test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_n_overruns(0),
- d_samples_recvd(0),
- d_samples_to_recv(10e6)
-{
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
- pmt_t usrp_dict = pmt_make_dict();
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_1rxhb_1tx.rbf"));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(128));
-
- define_component("server", "usrp_server", usrp_dict);
-
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-test_usrp_rx::~test_usrp_rx()
-{
-}
-
-void
-test_usrp_rx::initial_transition()
-{
- open_usrp();
-}
-
-void
-test_usrp_rx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- switch(d_state){
-
- //----------------------------- OPENING_USRP ----------------------------//
- // We only expect a response from opening the USRP which should be succesful
- // or failed.
- case OPENING_USRP:
- if (pmt_eq(event, s_response_open)){
- status = pmt_nth(1, data);
- if (pmt_eq(status, PMT_T)){
- allocate_channel();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
- }
- goto unhandled;
-
- //----------------------- ALLOCATING CHANNELS --------------------//
- // Allocate an RX channel to perform the overrun test.
- case ALLOCATING_CHANNEL:
- if (pmt_eq(event, s_response_allocate_channel)){
- status = pmt_nth(1, data);
- d_rx_chan = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T)){
- enter_receiving();
- return;
- }
- else {
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- }
- goto unhandled;
-
- //--------------------------- RECEIVING ------------------------------//
- // In the receiving state, we receive samples until the specified amount
- // while counting the number of overruns.
- case RECEIVING:
- if (pmt_eq(event, s_response_recv_raw_samples)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_response_recv_raw_samples(data);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
- goto unhandled;
-
- //------------------------- CLOSING CHANNEL ----------------------------//
- // Check deallocation response for the RX channel
- case CLOSING_CHANNEL:
- if (pmt_eq(event, s_response_deallocate_channel)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- close_usrp();
- return;
- }
- else {
- error_msg = "failed to deallocate channel:";
- goto bail;
- }
- }
-
- // Alternately, we ignore all response recv samples while waiting for the
- // channel to actually close
- if (pmt_eq(event, s_response_recv_raw_samples))
- return;
-
- goto unhandled;
-
- //--------------------------- CLOSING USRP ------------------------------//
- // Once we have received a successful USRP close response, we shutdown all
- // mblocks and exit.
- case CLOSING_USRP:
- if (pmt_eq(event, s_response_close)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- std::cout << "\nOverruns: " << d_n_overruns << std::endl;
- fflush(stdout);
- shutdown_all(PMT_T);
- return;
- }
- else {
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
- goto unhandled;
-
- default:
- goto unhandled;
- }
- return;
-
- // An error occured, print it, and shutdown all m-blocks
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- // Received an unhandled message for a specific state
- unhandled:
- if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-}
-
-
-void
-test_usrp_rx::open_usrp()
-{
- pmt_t which_usrp = pmt_from_long(0);
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
- d_state = OPENING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Opening the USRP\n";
-}
-
-void
-test_usrp_rx::close_usrp()
-{
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
- d_state = CLOSING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Closing the USRP\n";
-}
-
-void
-test_usrp_rx::allocate_channel()
-{
- long capacity = (long) 16e6;
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_state = ALLOCATING_CHANNEL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Requesting RX channel allocation\n";
-}
-
-void
-test_usrp_rx::enter_receiving()
-{
- d_state = RECEIVING;
-
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Receiving...\n";
-}
-
-void
-test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t v_samples = pmt_nth(2, data);
- pmt_t timestamp = pmt_nth(3, data);
- pmt_t channel = pmt_nth(4, data);
- pmt_t properties = pmt_nth(5, data);
-
- d_samples_recvd += pmt_length(v_samples) / 4;
-
- // Check for overrun
- if(!pmt_is_dict(properties)) {
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Recv samples dictionary is improper\n";
- return;
- }
-
- if(pmt_t overrun = pmt_dict_ref(properties,
- pmt_intern("overrun"),
- PMT_NIL)) {
- if(pmt_eqv(overrun, PMT_T)) {
- d_n_overruns++;
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Underrun\n";
- }
- else {
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n" << overrun <<std::endl;
- }
- } else {
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n";
- }
-
- // Check if the number samples we have received meets the test
- if(d_samples_recvd >= d_samples_to_recv) {
- d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan));
- enter_closing_channel();
- return;
- }
-
-}
-
-void
-test_usrp_rx::enter_closing_channel()
-{
- d_state = CLOSING_CHANNEL;
-
- sleep(2);
-
- d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_OVERRUN] Deallocating RX channel\n";
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_rx);
-
-
-// ----------------------------------------------------------------
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_rx", PMT_F, &result);
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <iostream>
-
-// Include the symbols needed for communication with USRP server
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_tx.h>
-#include <symbols_usrp_rx.h>
-
-static bool verbose = false;
-
-class test_usrp_inband_ping : public mb_mblock
-{
-
- mb_port_sptr d_tx; // Ports connected to the USRP server
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- pmt_t d_tx_chan; // Returned channel from TX allocation
- pmt_t d_rx_chan; // Returned channel from RX allocation
-
- pmt_t d_which_usrp; // The USRP to use for the test
-
- long d_warm_msgs; // The number of messages to 'warm' the USRP
- long d_warm_recvd; // The number of msgs received in the 'warm' state
-
- // Keep track of current state
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNELS,
- WARMING_USRP,
- PINGING,
- CLOSING_CHANNELS,
- CLOSING_USRP,
- };
- state_t d_state;
-
- public:
- test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_inband_ping();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void opening_usrp();
- void allocating_channels();
- void enter_warming_usrp();
- void enter_pinging();
- void build_and_send_ping();
- void closing_channels();
- void closing_usrp();
-};
-
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_inband_ping", PMT_F, &result);
-}
-
-
-test_usrp_inband_ping::test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_tx_chan(PMT_NIL),
- d_rx_chan(PMT_NIL),
- d_which_usrp(pmt_from_long(0)),
- d_state(INIT)
-{
-
- // A dictionary is used to pass parameters to the USRP
- pmt_t usrp_dict = pmt_make_dict();
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("fixed1.rbf"));
-
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("interp-tx"),
- pmt_from_long(128));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(16));
-
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Create an instance of USRP server and connect ports
- define_component("server", "usrp_server", usrp_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-test_usrp_inband_ping::~test_usrp_inband_ping()
-{
-}
-
-void
-test_usrp_inband_ping::initial_transition()
-{
- opening_usrp();
-}
-
-// Handle message reads all incoming messages from USRP server which will be
-// initialization and ping responses. We perform actions based on the current
-// state and the event (ie, ping response)
-void
-test_usrp_inband_ping::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
- pmt_t port_id = msg->port_id();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- // Dispatch based on state
- switch(d_state) {
-
- //----------------------------- OPENING_USRP ----------------------------//
- // We only expect a response from opening the USRP which should be succesful
- // or failed.
- case OPENING_USRP:
-
- if(pmt_eq(event, s_response_open)) {
-
- status = pmt_nth(1, data); // failed/succes
-
- if(pmt_eq(status, PMT_T)) {
- allocating_channels();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
-
- }
-
- goto unhandled; // all other messages not handled in this state
-
-
- //----------------------- ALLOCATING CHANNELS --------------------//
- // When allocating channels, we need to wait for 2 responses from
- // USRP server: one for TX and one for RX. Both are initialized to
- // NIL so we know to continue to the next state once both are set.
- case ALLOCATING_CHANNELS:
-
- // A TX allocation response
- if(pmt_eq(event, s_response_allocate_channel)
- && pmt_eq(d_tx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful response, extract the channel
- if(pmt_eq(status, PMT_T)) {
-
- d_tx_chan = pmt_nth(2, data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation"
- << " on channel " << d_tx_chan << std::endl;
-
- // If the RX has also been allocated already, we can continue
- if(!pmt_eqv(d_rx_chan, PMT_NIL))
- enter_warming_usrp();
-
- return;
- }
- else { // TX allocation failed
- error_msg = "failed to allocate TX channel:";
- goto bail;
- }
- }
-
- // A RX allocation response
- if(pmt_eq(event, s_response_allocate_channel)
- && pmt_eq(d_rx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful response, extract the channel
- if(pmt_eq(status, PMT_T)) {
-
- d_rx_chan = pmt_nth(2, data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation"
- << " on channel " << d_rx_chan << std::endl;
-
- // If the TX has also been allocated already, we can continue
- if(!pmt_eqv(d_tx_chan, PMT_NIL))
- enter_warming_usrp();
-
- return;
- }
- else { // RX allocation failed
- error_msg = "failed to allocate RX channel:";
- goto bail;
- }
- }
-
- goto unhandled;
-
- //----------------------- WARMING USRP --------------------//
- // The FX2 seems to need some amount of data to be buffered
- // before it begins reading. We use this state to simply
- // warm up the USRP before benchmarking pings.
- case WARMING_USRP:
-
- // We really don't care about the responses from the
- // control channel in the warming stage, but once we receive
- // the proper number of responses we switch states.
- if(pmt_eq(event, s_response_from_control_channel)
- && pmt_eq(d_rx->port_symbol(), port_id))
- {
- d_warm_recvd++;
-
- if(d_warm_recvd > d_warm_msgs)
- enter_pinging();
-
- return;
- }
-
- goto unhandled;
-
- case PINGING:
- goto unhandled;
-
- case CLOSING_CHANNELS:
- goto unhandled;
-
- case CLOSING_USRP:
- goto unhandled;
-
- case INIT:
- goto unhandled;
-
- }
-
- // An error occured, print it, and shutdown all m-blocks
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- // Received an unhandled message for a specific state
- unhandled:
- if(verbose)
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-
-}
-
-
-// Sends a command to USRP server to open up a connection to the
-// specified USRP, which is defaulted to USRP 0 on the system
-void
-test_usrp_inband_ping::opening_usrp()
-{
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Opening USRP "
- << d_which_usrp << std::endl;
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp));
- d_state = OPENING_USRP;
-}
-
-// RX and TX channels must be allocated so that the USRP server can
-// properly share bandwidth across multiple USRPs. No commands will be
-// successful to the USRP through the USRP server on the TX or RX channels until
-// a bandwidth allocation has been received.
-void
-test_usrp_inband_ping::allocating_channels()
-{
- d_state = ALLOCATING_CHANNELS;
-
- long capacity = (long) 16e6;
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
-}
-
-// The USRP needs some amount of initial data to pass a buffering point such
-// that it begins to pull and read data from the FX2. We send an arbitrary
-// amount of data to start the pipeline, which are just pings.
-void
-test_usrp_inband_ping::enter_warming_usrp()
-{
- d_state = WARMING_USRP;
-
- for(int i=0; i < d_warm_msgs; i++)
- build_and_send_ping();
-}
-
-void
-test_usrp_inband_ping::enter_pinging()
-{
- d_state = PINGING;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Running ping tests\n";
-
-}
-
-// Pings are sent over the TX channel using the signal 'cmd-to-control-channel'
-// to the USRP server. Within this message there can be infinite subpackets
-// stored as a list (the second parameter) and sent. The only subpacket we send
-// is a ping, interpreted by the 'op-ping-fixed' signal.
-void
-test_usrp_inband_ping::build_and_send_ping()
-{
-
- d_tx->send(s_cmd_to_control_channel, // USRP server signal
- pmt_list2(PMT_NIL, // invocation handle
- pmt_list1(pmt_list3(s_op_ping_fixed,
- pmt_from_long(0),
- pmt_from_long(0)))));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Ping!!" << std::endl;
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_inband_ping);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-//#include <mb_mblock_impl.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <iostream>
-
-// Include the symbols needed for communication with USRP server
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_tx.h>
-#include <symbols_usrp_rx.h>
-
-static bool verbose = true;
-
-class test_usrp_inband_registers : public mb_mblock
-{
-
- mb_port_sptr d_tx; // Ports connected to the USRP server
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- pmt_t d_tx_chan; // Returned channel from TX allocation
- pmt_t d_rx_chan; // Returned channel from RX allocation
-
- pmt_t d_which_usrp; // The USRP to use for the test
-
- long d_warm_msgs; // The number of messages to 'warm' the USRP
- long d_warm_recvd; // The number of msgs received in the 'warm' state
-
- // Keep track of current state
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNELS,
- WRITE_REGISTER,
- READ_REGISTER,
- CLOSING_CHANNELS,
- CLOSING_USRP,
- };
- state_t d_state;
-
- public:
- test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_inband_registers();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void opening_usrp();
- void allocating_channels();
- void write_register();
- void read_register();
- void closing_channels();
- void closing_usrp();
- void enter_receiving();
- void build_and_send_ping();
-};
-
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_inband_registers", PMT_F, &result);
-}
-
-
-test_usrp_inband_registers::test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_tx_chan(PMT_NIL),
- d_rx_chan(PMT_NIL),
- d_which_usrp(pmt_from_long(0)),
- d_state(INIT)
-{
-
- // A dictionary is used to pass parameters to the USRP
- pmt_t usrp_dict = pmt_make_dict();
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_1rxhb_1tx.rbf"));
-
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("interp-tx"),
- pmt_from_long(128));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(16));
-
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Create an instance of USRP server and connect ports
- define_component("server", "usrp_server", usrp_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-test_usrp_inband_registers::~test_usrp_inband_registers()
-{
-}
-
-void
-test_usrp_inband_registers::initial_transition()
-{
- opening_usrp();
-}
-
-// Handle message reads all incoming messages from USRP server which will be
-// initialization and ping responses. We perform actions based on the current
-// state and the event (ie, ping response)
-void
-test_usrp_inband_registers::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
- pmt_t port_id = msg->port_id();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- // Dispatch based on state
- switch(d_state) {
-
- //----------------------------- OPENING_USRP ----------------------------//
- // We only expect a response from opening the USRP which should be succesful
- // or failed.
- case OPENING_USRP:
-
- if(pmt_eq(event, s_response_open)) {
-
- status = pmt_nth(1, data); // failed/succes
-
- if(pmt_eq(status, PMT_T)) {
- allocating_channels();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
-
- }
-
- goto unhandled; // all other messages not handled in this state
-
-
- //----------------------- ALLOCATING CHANNELS --------------------//
- // When allocating channels, we need to wait for 2 responses from
- // USRP server: one for TX and one for RX. Both are initialized to
- // NIL so we know to continue to the next state once both are set.
- case ALLOCATING_CHANNELS:
-
- // A TX allocation response
- if(pmt_eq(event, s_response_allocate_channel)
- && pmt_eq(d_tx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful response, extract the channel
- if(pmt_eq(status, PMT_T)) {
-
- d_tx_chan = pmt_nth(2, data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation"
- << " on channel " << d_tx_chan << std::endl;
-
- // If the RX has also been allocated already, we can continue
- if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
- enter_receiving();
- write_register();
- }
-
- return;
- }
- else { // TX allocation failed
- error_msg = "failed to allocate TX channel:";
- goto bail;
- }
- }
-
- // A RX allocation response
- if(pmt_eq(event, s_response_allocate_channel)
- && pmt_eq(d_rx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful response, extract the channel
- if(pmt_eq(status, PMT_T)) {
-
- d_rx_chan = pmt_nth(2, data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation"
- << " on channel " << d_rx_chan << std::endl;
-
- // If the TX has also been allocated already, we can continue
- if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
- enter_receiving();
- write_register();
- }
-
- return;
- }
- else { // RX allocation failed
- error_msg = "failed to allocate RX channel:";
- goto bail;
- }
- }
-
- goto unhandled;
-
- //-------------------------- WRITE REGISTER ----------------------------//
- // In the write register state, we do not expect to receive any messages
- // since the write does not directly generate a response until the USRP
- // responds.
- case WRITE_REGISTER:
- goto unhandled;
-
- //-------------------------- READ REGISTER ----------------------------//
- // In the read register state, we only expect a read register response back
- // that has the value we expect to have in it. We read the response, ensure
- // that the read was successful and display the register value.
- case READ_REGISTER:
-
- if(pmt_eq(event, s_response_from_control_channel)
- && pmt_eq(d_tx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If the read was successful, we extract the subpacket information
- if(pmt_eq(status, PMT_T)) {
-
- pmt_t subp = pmt_nth(2, data); // subpacket should be the read reg reply
-
- pmt_t subp_sig = pmt_nth(0, subp);
- pmt_t subp_data = pmt_nth(1, subp);
-
- if(!pmt_eqv(subp_sig, s_op_read_reg_reply)) {
- error_msg = "received improper subpacket when expecting reg reply.";
- goto bail;
- }
-
- pmt_t rid = pmt_nth(0, subp_data);
- pmt_t reg_num = pmt_nth(1, subp_data);
- pmt_t reg_val = pmt_nth(2, subp_data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_REGISTERS] Received read reg reply "
- << "("
- << "RID: " << rid << ", "
- << "Reg: " << reg_num << ", "
- << "Val: " << reg_val
- << ")\n";
-
- // read_register(); FIX ME STATE TRANSITION
- return;
-
- } else { // bail on unsuccessful write
- error_msg = "failed to write to register.";
- goto bail;
- }
- }
- goto unhandled;
-
- case CLOSING_CHANNELS:
- goto unhandled;
-
- case CLOSING_USRP:
- goto unhandled;
-
- case INIT:
- goto unhandled;
-
- }
-
- // An error occured, print it, and shutdown all m-blocks
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- // Received an unhandled message for a specific state
- unhandled:
- if(verbose && !pmt_eq(event, s_response_recv_raw_samples))
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-
-}
-
-
-// Sends a command to USRP server to open up a connection to the
-// specified USRP, which is defaulted to USRP 0 on the system
-void
-test_usrp_inband_registers::opening_usrp()
-{
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_PING] Opening USRP "
- << d_which_usrp << std::endl;
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp));
- d_state = OPENING_USRP;
-}
-
-// RX and TX channels must be allocated so that the USRP server can
-// properly share bandwidth across multiple USRPs. No commands will be
-// successful to the USRP through the USRP server on the TX or RX channels until
-// a bandwidth allocation has been received.
-void
-test_usrp_inband_registers::allocating_channels()
-{
- d_state = ALLOCATING_CHANNELS;
-
- long capacity = (long) 16e6;
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
-}
-
-// After allocating the channels, a write register command will be sent to the
-// USRP.
-void
-test_usrp_inband_registers::write_register()
-{
- d_state = WRITE_REGISTER;
-
- long reg = 0;
-
- d_tx->send(s_cmd_to_control_channel, // C/S packet
- pmt_list2(PMT_NIL, // invoc handle
- pmt_list1(
- pmt_list2(s_op_write_reg,
- pmt_list2(
- pmt_from_long(reg),
- pmt_from_long(0xbeef))))));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to "
- << reg << std::endl;
-
- read_register(); // immediately transition to read the register
-}
-
-// Temporary: for testing pings
-void
-test_usrp_inband_registers::build_and_send_ping()
-{
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
- pmt_list2(pmt_from_long(0),
- pmt_from_long(0))))));
-
- std::cout << "[TEST_USRP_INBAND_CS] Ping sent" << std::endl;
-}
-
-// After writing to the register, we want to read the value back and ensure that
-// it is the same value that we wrote.
-void
-test_usrp_inband_registers::read_register()
-{
- d_state = READ_REGISTER;
-
- long reg = 9;
-
- d_tx->send(s_cmd_to_control_channel, // C/S packet
- pmt_list2(PMT_NIL, // invoc handle
- pmt_list1(
- pmt_list2(s_op_read_reg,
- pmt_list2(
- pmt_from_long(0), // rid
- pmt_from_long(reg))))));
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_REGISTERS] Reading from register "
- << reg << std::endl;
-}
-
-// Used to enter the receiving state
-void
-test_usrp_inband_registers::enter_receiving()
-{
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan));
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_inband_registers);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <iostream>
-#include <fstream>
-
-// Include the symbols needed for communication with USRP server
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_rx.h>
-
-static bool verbose = true;
-
-class test_usrp_rx : public mb_mblock
-{
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
- pmt_t d_rx_chan; // returned tx channel handle
-
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNEL,
- RECEIVING,
- CLOSING_CHANNEL,
- CLOSING_USRP,
- };
-
- state_t d_state;
-
- std::ofstream d_ofile;
-
- long d_samples_recvd;
- long d_samples_to_recv;
-
- public:
- test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_rx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void open_usrp();
- void close_usrp();
- void allocate_channel();
- void send_packets();
- void enter_receiving();
- void build_and_send_next_frame();
- void handle_response_recv_raw_samples(pmt_t invocation_handle);
- void enter_closing_channel();
-};
-
-test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_samples_recvd(0),
- d_samples_to_recv(20e6)
-{
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
- pmt_t usrp_dict = pmt_make_dict();
-
- // To test the application without a USRP
- bool fake_usrp_p = false;
- if(fake_usrp_p) {
- pmt_dict_set(usrp_dict,
- pmt_intern("fake-usrp"),
- PMT_T);
- }
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_1rxhb_1tx.rbf"));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(64));
-
-// If unspecified, chooses center frequency from range
-// pmt_dict_set(usrp_dict,
-// pmt_intern("rf-freq"),
-// pmt_from_long(10e6));
-
- define_component("server", "usrp_server", usrp_dict);
-
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-test_usrp_rx::~test_usrp_rx()
-{
-}
-
-void
-test_usrp_rx::initial_transition()
-{
- open_usrp();
-}
-
-void
-test_usrp_rx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- switch(d_state){
-
- //----------------------------- OPENING_USRP ----------------------------//
- // We only expect a response from opening the USRP which should be succesful
- // or failed.
- case OPENING_USRP:
- if (pmt_eq(event, s_response_open)){
- status = pmt_nth(1, data);
- if (pmt_eq(status, PMT_T)){
- allocate_channel();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
- }
- goto unhandled;
-
- //----------------------- ALLOCATING CHANNELS --------------------//
- // Allocate an RX channel to perform the overrun test.
- case ALLOCATING_CHANNEL:
- if (pmt_eq(event, s_response_allocate_channel)){
- status = pmt_nth(1, data);
- d_rx_chan = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T)){
- enter_receiving();
- return;
- }
- else {
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- }
- goto unhandled;
-
- //--------------------------- RECEIVING ------------------------------//
- // In the receiving state, we receive samples until the specified amount
- // while counting the number of overruns.
- case RECEIVING:
- if (pmt_eq(event, s_response_recv_raw_samples)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_response_recv_raw_samples(data);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
- goto unhandled;
-
- //------------------------- CLOSING CHANNEL ----------------------------//
- // Check deallocation response for the RX channel
- case CLOSING_CHANNEL:
- if (pmt_eq(event, s_response_deallocate_channel)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- close_usrp();
- return;
- }
- else {
- error_msg = "failed to deallocate channel:";
- goto bail;
- }
- }
-
- // Alternately, we ignore all response recv samples while waiting for the
- // channel to actually close
- if (pmt_eq(event, s_response_recv_raw_samples))
- return;
-
- goto unhandled;
-
- //--------------------------- CLOSING USRP ------------------------------//
- // Once we have received a successful USRP close response, we shutdown all
- // mblocks and exit.
- case CLOSING_USRP:
- if (pmt_eq(event, s_response_close)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- fflush(stdout);
- shutdown_all(PMT_T);
- return;
- }
- else {
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
- goto unhandled;
-
- default:
- goto unhandled;
- }
- return;
-
- // An error occured, print it, and shutdown all m-blocks
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- // Received an unhandled message for a specific state
- unhandled:
- if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-}
-
-
-void
-test_usrp_rx::open_usrp()
-{
- pmt_t which_usrp = pmt_from_long(0);
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
- d_state = OPENING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n";
-}
-
-void
-test_usrp_rx::close_usrp()
-{
-
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
- d_state = CLOSING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n";
-}
-
-void
-test_usrp_rx::allocate_channel()
-{
- long capacity = (long) 16e6;
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_state = ALLOCATING_CHANNEL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n";
-}
-
-void
-test_usrp_rx::enter_receiving()
-{
- d_state = RECEIVING;
-
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n";
-}
-
-void
-test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t v_samples = pmt_nth(2, data);
- pmt_t timestamp = pmt_nth(3, data);
- pmt_t channel = pmt_nth(4, data);
- pmt_t properties = pmt_nth(5, data);
-
- d_samples_recvd += pmt_length(v_samples) / 4;
-
- // Check for overrun
- if(!pmt_is_dict(properties)) {
- std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n";
- return;
- }
-
- // Check if the number samples we have received meets the test
- if(d_samples_recvd >= d_samples_to_recv) {
- d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan));
- enter_closing_channel();
- return;
- }
-
-}
-
-void
-test_usrp_rx::enter_closing_channel()
-{
- d_state = CLOSING_CHANNEL;
-
- d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n";
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_rx);
-
-
-// ----------------------------------------------------------------
-
-int
-main (int argc, char **argv)
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_rx", PMT_F, &result);
-
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <iostream>
-
-#include <ui_nco.h>
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_tx.h>
-#include <symbols_usrp_rx.h>
-
-#define NBPING 10
-
-static bool verbose = true;
-bool bskip = false;
-long bstep = 10000;
-long bcurr = 0;
-long incr = 0x500;
-long ptime = 0x000;
-
-class test_usrp_inband_timestamps : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
- pmt_t d_tx_chan; // returned tx channel handle
- pmt_t d_rx_chan; // returned tx channel handle
-
- struct timeval times[NBPING];
-
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNEL,
- TRANSMITTING,
- CLOSING_CHANNEL,
- CLOSING_USRP,
- };
-
- state_t d_state;
- long d_nsamples_to_send;
- long d_nsamples_xmitted;
- long d_nframes_xmitted;
- long d_samples_per_frame;
- bool d_done_sending;
-
- // for generating sine wave output
- ui_nco<float,float> d_nco;
- double d_amplitude;
-
- public:
- test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_inband_timestamps();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void open_usrp();
- void close_usrp();
- void allocate_channel();
- void send_packets();
- void enter_receiving();
- void enter_transmitting();
- void build_and_send_ping();
- void build_and_send_next_frame();
- void handle_xmit_response(pmt_t invocation_handle);
- void enter_closing_channel();
-};
-
-test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_tx_chan(PMT_NIL),
- d_rx_chan(PMT_NIL),
- d_state(INIT), d_nsamples_to_send((long) 40e6),
- d_nsamples_xmitted(0),
- d_nframes_xmitted(0),
- //d_samples_per_frame((long)(126)),
- d_samples_per_frame((long)(126 * 2)), // non-full packet
- //d_samples_per_frame((long)(126 * 3.5)), // non-full packet
- //d_samples_per_frame((long)(126 * 4)), // full packet
- d_done_sending(false),
- d_amplitude(16384)
-{
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Initializing...\n";
-
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- bool fake_usrp_p = false;
-
- // Test the TX side
-
- pmt_t usrp_dict = pmt_make_dict();
-
- if(fake_usrp_p) {
- pmt_dict_set(usrp_dict,
- pmt_intern("fake-usrp"),
- PMT_T);
- }
-
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("interp-tx"),
- pmt_from_long(128));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(16));
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_1rxhb_1tx.rbf"));
-
- define_component("server", "usrp_server", usrp_dict);
-
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
- // initialize NCO
- double freq = 100e3;
- int interp = 32; // 32 -> 4MS/s
- double sample_rate = 128e6 / interp;
- d_nco.set_freq(2*M_PI * freq/sample_rate);
-
-}
-
-test_usrp_inband_timestamps::~test_usrp_inband_timestamps()
-{
-}
-
-void
-test_usrp_inband_timestamps::initial_transition()
-{
- open_usrp();
-}
-
-void
-test_usrp_inband_timestamps::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
- pmt_t port_id = msg->port_id();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- //std::cout << msg << std::endl;
-
- switch(d_state){
- case OPENING_USRP:
- if (pmt_eq(event, s_response_open)){
- status = pmt_nth(1, data);
- if (pmt_eq(status, PMT_T)){
- allocate_channel();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
- }
- goto unhandled;
-
- case ALLOCATING_CHANNEL:
- if (pmt_eq(event, s_response_allocate_channel)){
-
- if(pmt_eq(d_tx->port_symbol(), port_id)) {
- status = pmt_nth(1, data);
- d_tx_chan = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T)){
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n";
-
- if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
- enter_receiving();
- enter_transmitting();
- }
- return;
- }
- else {
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- }
-
- if(pmt_eq(d_rx->port_symbol(), port_id)) {
- status = pmt_nth(1, data);
- d_rx_chan = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T)){
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n";
-
- if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
- enter_receiving();
- enter_transmitting();
- }
- return;
- }
- else {
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- }
- }
- goto unhandled;
-
- case TRANSMITTING:
- if (pmt_eq(event, s_response_xmit_raw_frame)){
- handle = pmt_nth(0, data);
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_xmit_response(handle);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
-
- if (pmt_eq(event, s_response_from_control_channel)) {
- std::cout << "ping response!\n";
- }
- goto unhandled;
-
- case CLOSING_CHANNEL:
- if (pmt_eq(event, s_response_deallocate_channel)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- close_usrp();
- return;
- }
- else {
- error_msg = "failed to deallocate channel:";
- goto bail;
- }
- }
- goto unhandled;
-
- case CLOSING_USRP:
- if (pmt_eq(event, s_response_close)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- shutdown_all(PMT_T);
- return;
- }
- else {
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
- goto unhandled;
-
- default:
- goto unhandled;
- }
- return;
-
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- unhandled:
- if(verbose && 0)
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-}
-
-
-void
-test_usrp_inband_timestamps::open_usrp()
-{
- pmt_t which_usrp = pmt_from_long(0);
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
- d_state = OPENING_USRP;
-}
-
-void
-test_usrp_inband_timestamps::close_usrp()
-{
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
- d_state = CLOSING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing USRP\n";
-}
-
-void
-test_usrp_inband_timestamps::allocate_channel()
-{
- long capacity = (long) 16e6;
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_state = ALLOCATING_CHANNEL;
-}
-
-void
-test_usrp_inband_timestamps::enter_receiving()
-{
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan));
-}
-
-void
-test_usrp_inband_timestamps::enter_transmitting()
-{
- d_state = TRANSMITTING;
- d_nsamples_xmitted = 0;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Beginning transmission\n";
-
- sleep(1);
-
- build_and_send_next_frame();
- build_and_send_next_frame();
- build_and_send_next_frame();
- build_and_send_next_frame();
-
-}
-
-void
-test_usrp_inband_timestamps::build_and_send_ping()
-{
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
- pmt_list2(pmt_from_long(0),
- pmt_from_long(0))))));
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Ping sent" << std::endl;
-}
-
-void
-test_usrp_inband_timestamps::build_and_send_next_frame()
-{
- // allocate the uniform vector for the samples
- // FIXME perhaps hold on to this between calls
-
-#if 0
- long nsamples_this_frame =
- std::min(d_nsamples_to_send - d_nsamples_xmitted,
- d_samples_per_frame);
-#else
- long nsamples_this_frame = d_samples_per_frame;
-#endif
-
- if (nsamples_this_frame == 0){
- d_done_sending = true;
- return;
- }
-
-
- size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
- pmt_t uvec = pmt_make_s16vector(nshorts, 0);
- size_t ignore;
- int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
-
- // fill in the complex sinusoid
-
- for (int i = 0; i < nsamples_this_frame; i++){
-
- if (1){
- gr_complex s;
- d_nco.sincos(&s, 1, d_amplitude);
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- else {
- gr_complex s(d_amplitude, d_amplitude);
-
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- }
-
- pmt_t timestamp;
-
- if(bskip) {
- timestamp = pmt_from_long(0x0); // throw away
- bcurr++;
- if(bcurr == bstep) {
- bskip = false;
- bcurr = 0;
- }
- } else {
- timestamp = pmt_from_long(0xffffffff); // NOW
- timestamp = pmt_from_long(ptime);
- ptime += incr;
- bcurr++;
- if(bcurr == bstep) {
- //bskip = true;
- bcurr = 0;
- }
- }
-
- std::cout << bskip << " -- " << bcurr << std::endl;
-
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle
- d_tx_chan, // channel
- uvec, // the samples
- timestamp));
-
- d_nsamples_xmitted += nsamples_this_frame;
- d_nframes_xmitted++;
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Transmitted frame\n";
-
- //build_and_send_next_frame();
-}
-
-
-void
-test_usrp_inband_timestamps::handle_xmit_response(pmt_t handle)
-{
- if (d_done_sending &&
- pmt_to_long(handle) == (d_nframes_xmitted - 1)){
- // We're done sending and have received all responses
- enter_closing_channel();
- }
-
- build_and_send_next_frame();
- //build_and_send_ping();
-}
-
-void
-test_usrp_inband_timestamps::enter_closing_channel()
-{
- d_state = CLOSING_CHANNEL;
-
- d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing channel\n";
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_inband_timestamps);
-
-
-// ----------------------------------------------------------------
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_inband_timestamps", PMT_F, &result);
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <iostream>
-
-#include <ui_nco.h>
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_tx.h>
-
-static bool verbose = true;
-
-class test_usrp_tx : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_cs;
- pmt_t d_tx_chan; // returned tx channel handle
-
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNEL,
- TRANSMITTING,
- CLOSING_CHANNEL,
- CLOSING_USRP,
- };
-
- state_t d_state;
- long d_nsamples_to_send;
- long d_nsamples_xmitted;
- long d_nframes_xmitted;
- long d_samples_per_frame;
- bool d_done_sending;
-
- // for generating sine wave output
- ui_nco<float,float> d_nco;
- double d_amplitude;
-
- public:
- test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_tx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void open_usrp();
- void close_usrp();
- void allocate_channel();
- void send_packets();
- void enter_transmitting();
- void build_and_send_next_frame();
- void handle_xmit_response(pmt_t invocation_handle);
- void enter_closing_channel();
-};
-
-test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_state(INIT), d_nsamples_to_send((long) 80e6),
- d_nsamples_xmitted(0),
- d_nframes_xmitted(0),
- d_samples_per_frame((long)(126 * 4)), // full packet
- d_done_sending(false),
- d_amplitude(16384)
-{
- // std::cout << "[TEST_USRP_TX] Initializing...\n";
-
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- //bool fake_usrp_p = true;
- bool fake_usrp_p = false;
-
- // Test the TX side
-
- pmt_t usrp_dict = pmt_make_dict();
-
- if(fake_usrp_p) {
- pmt_dict_set(usrp_dict,
- pmt_intern("fake-usrp"),
- PMT_T);
- }
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_1rxhb_1tx.rbf"));
-
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("interp-tx"),
- pmt_from_long(64));
-
-// If unspecified, chooses center frequency from range
-// pmt_dict_set(usrp_dict,
-// pmt_intern("rf-freq"),
-// pmt_from_long(10e6));
-
- define_component("server", "usrp_server", usrp_dict);
-
- connect("self", "tx0", "server", "tx0");
- connect("self", "cs", "server", "cs");
-
- // initialize NCO
- double freq = 100e3;
- int interp = 32; // 32 -> 4MS/s
- double sample_rate = 128e6 / interp;
- d_nco.set_freq(2*M_PI * freq/sample_rate);
-
- // FIXME need to somehow set the interp rate in the USRP.
- // for now, we'll have the low-level code hardwire it.
-}
-
-test_usrp_tx::~test_usrp_tx()
-{
-}
-
-void
-test_usrp_tx::initial_transition()
-{
- open_usrp();
-}
-
-void
-test_usrp_tx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- std::string error_msg;
-
- //std::cout << msg << std::endl;
-
- switch(d_state){
- case OPENING_USRP:
- if (pmt_eq(event, s_response_open)){
- status = pmt_nth(1, data);
- if (pmt_eq(status, PMT_T)){
- allocate_channel();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
- }
- goto unhandled;
-
- case ALLOCATING_CHANNEL:
- if (pmt_eq(event, s_response_allocate_channel)){
- status = pmt_nth(1, data);
- d_tx_chan = pmt_nth(2, data);
-
- if (pmt_eq(status, PMT_T)){
- enter_transmitting();
- return;
- }
- else {
- error_msg = "failed to allocate channel:";
- goto bail;
- }
- }
- goto unhandled;
-
- case TRANSMITTING:
- if (pmt_eq(event, s_response_xmit_raw_frame)){
- handle = pmt_nth(0, data);
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_xmit_response(handle);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
- goto unhandled;
-
- case CLOSING_CHANNEL:
- if (pmt_eq(event, s_response_deallocate_channel)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- close_usrp();
- return;
- }
- else {
- error_msg = "failed to deallocate channel:";
- goto bail;
- }
- }
- goto unhandled;
-
- case CLOSING_USRP:
- if (pmt_eq(event, s_response_close)){
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- shutdown_all(PMT_T);
- return;
- }
- else {
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
- goto unhandled;
-
- default:
- goto unhandled;
- }
- return;
-
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- unhandled:
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-}
-
-
-void
-test_usrp_tx::open_usrp()
-{
- pmt_t which_usrp = pmt_from_long(0);
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
- d_state = OPENING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n";
-}
-
-void
-test_usrp_tx::close_usrp()
-{
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
- d_state = CLOSING_USRP;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n";
-}
-
-void
-test_usrp_tx::allocate_channel()
-{
- long capacity = (long) 16e6;
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_state = ALLOCATING_CHANNEL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n";
-}
-
-void
-test_usrp_tx::enter_transmitting()
-{
- d_state = TRANSMITTING;
- d_nsamples_xmitted = 0;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n";
-
- build_and_send_next_frame(); // fire off 4 to start pipeline
- build_and_send_next_frame();
- build_and_send_next_frame();
- build_and_send_next_frame();
-}
-
-void
-test_usrp_tx::build_and_send_next_frame()
-{
- // allocate the uniform vector for the samples
- // FIXME perhaps hold on to this between calls
-
-#if 1
- long nsamples_this_frame =
- std::min(d_nsamples_to_send - d_nsamples_xmitted,
- d_samples_per_frame);
-#else
- long nsamples_this_frame = d_samples_per_frame;
-#endif
-
- if (nsamples_this_frame == 0){
- d_done_sending = true;
- return;
- }
-
-
- size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
- pmt_t uvec = pmt_make_s16vector(nshorts, 0);
- size_t ignore;
- int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
-
- // fill in the complex sinusoid
-
- for (int i = 0; i < nsamples_this_frame; i++){
-
- if (1){
- gr_complex s;
- d_nco.sincos(&s, 1, d_amplitude);
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- else {
- gr_complex s(d_amplitude, d_amplitude);
-
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- }
-
- pmt_t tx_properties = pmt_make_dict();
-
- pmt_t timestamp = pmt_from_long(0xffffffff); // NOW
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle
- d_tx_chan, // channel
- uvec, // the samples
- timestamp,
- tx_properties));
-
- d_nsamples_xmitted += nsamples_this_frame;
- d_nframes_xmitted++;
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n";
-}
-
-
-void
-test_usrp_tx::handle_xmit_response(pmt_t handle)
-{
- if (d_done_sending &&
- pmt_to_long(handle) == (d_nframes_xmitted - 1)){
- // We're done sending and have received all responses
- enter_closing_channel();
- }
-
- build_and_send_next_frame();
-}
-
-void
-test_usrp_tx::enter_closing_channel()
-{
- d_state = CLOSING_CHANNEL;
-
- d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n";
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_tx);
-
-
-// ----------------------------------------------------------------
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_tx", PMT_F, &result);
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/exception.h>
-#include <mblock/msg_queue.h>
-#include <mblock/message.h>
-#include <mblock/msg_accepter.h>
-#include <mblock/class_registry.h>
-#include <pmt.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <iostream>
-#include <ui_nco.h>
-
-// Include the symbols needed for communication with USRP server
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_tx.h>
-#include <symbols_usrp_rx.h>
-
-static bool verbose = true;
-
-class test_usrp_inband_underrun : public mb_mblock
-{
-
- mb_port_sptr d_tx; // Ports connected to the USRP server
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- pmt_t d_tx_chan; // Returned channel from TX allocation
- pmt_t d_rx_chan; // Returned channel from RX allocation
-
- pmt_t d_which_usrp; // The USRP to use for the test
-
- long d_warm_msgs; // The number of messages to 'warm' the USRP
- long d_warm_recvd; // The number of msgs received in the 'warm' state
-
- // Keep track of current state
- enum state_t {
- INIT,
- OPENING_USRP,
- ALLOCATING_CHANNELS,
- WRITE_REGISTER,
- READ_REGISTER,
- TRANSMITTING,
- CLOSING_CHANNELS,
- CLOSING_USRP,
- };
- state_t d_state;
-
- long d_nsamples_to_send;
- long d_nsamples_xmitted;
- long d_nframes_xmitted;
- long d_samples_per_frame;
- bool d_done_sending;
-
- // for generating sine wave output
- ui_nco<float,float> d_nco;
- double d_amplitude;
-
- long d_n_underruns;
-
- public:
- test_usrp_inband_underrun(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~test_usrp_inband_underrun();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void opening_usrp();
- void allocating_channels();
- void write_register();
- void read_register();
- void closing_channels();
- void closing_usrp();
- void enter_receiving();
- void enter_transmitting();
- void build_and_send_ping();
- void build_and_send_next_frame();
- void handle_xmit_response(pmt_t handle);
- void handle_recv_response(pmt_t dict);
-};
-
-
-int
-main (int argc, char **argv)
-{
- // handle any command line args here
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_NIL;
-
- rt->run("top", "test_usrp_inband_underrun", PMT_F, &result);
-}
-
-
-test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_tx_chan(PMT_NIL),
- d_rx_chan(PMT_NIL),
- d_which_usrp(pmt_from_long(0)),
- d_state(INIT),
- d_nsamples_to_send((long) 27e6),
- d_nsamples_xmitted(0),
- d_nframes_xmitted(0),
- d_samples_per_frame(d_nsamples_to_send), // full packet
-
- d_done_sending(false),
- d_amplitude(16384),
- d_n_underruns(0)
-{
-
- // A dictionary is used to pass parameters to the USRP
- pmt_t usrp_dict = pmt_make_dict();
-
- // Specify the RBF to use
- pmt_dict_set(usrp_dict,
- pmt_intern("rbf"),
- pmt_intern("inband_1rxhb_1tx.rbf"));
-
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("interp-tx"),
- pmt_from_long(64));
-
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(128));
-
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Create an instance of USRP server and connect ports
- define_component("server", "usrp_server", usrp_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
- // initialize NCO
- double freq = 100e3;
- int interp = 32; // 32 -> 4MS/s
- double sample_rate = 128e6 / interp;
- d_nco.set_freq(2*M_PI * freq/sample_rate);
-}
-
-test_usrp_inband_underrun::~test_usrp_inband_underrun()
-{
-}
-
-void
-test_usrp_inband_underrun::initial_transition()
-{
- opening_usrp();
-}
-
-// Handle message reads all incoming messages from USRP server which will be
-// initialization and ping responses. We perform actions based on the current
-// state and the event (ie, ping response)
-void
-test_usrp_inband_underrun::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t data = msg->data();
- pmt_t port_id = msg->port_id();
-
- pmt_t handle = PMT_F;
- pmt_t status = PMT_F;
- pmt_t dict = PMT_NIL;
- std::string error_msg;
-
- // Check the recv sample responses for underruns and count
- if(pmt_eq(event, s_response_recv_raw_samples)) {
- handle = pmt_nth(0, data);
- status = pmt_nth(1, data);
- dict = pmt_nth(4, data);
-
- if(pmt_eq(status, PMT_T)) {
- handle_recv_response(dict);
- return;
- }
- else {
- error_msg = "error while receiving samples:";
- goto bail;
- }
- }
-
-
- // Dispatch based on state
- switch(d_state) {
-
- //----------------------------- OPENING_USRP ----------------------------//
- // We only expect a response from opening the USRP which should be succesful
- // or failed.
- case OPENING_USRP:
-
- if(pmt_eq(event, s_response_open)) {
-
- status = pmt_nth(1, data); // failed/succes
-
- if(pmt_eq(status, PMT_T)) {
- allocating_channels();
- return;
- }
- else {
- error_msg = "failed to open usrp:";
- goto bail;
- }
-
- }
-
- goto unhandled; // all other messages not handled in this state
-
-
- //----------------------- ALLOCATING CHANNELS --------------------//
- // When allocating channels, we need to wait for 2 responses from
- // USRP server: one for TX and one for RX. Both are initialized to
- // NIL so we know to continue to the next state once both are set.
- case ALLOCATING_CHANNELS:
-
- // A TX allocation response
- if(pmt_eq(event, s_response_allocate_channel)
- && pmt_eq(d_tx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful response, extract the channel
- if(pmt_eq(status, PMT_T)) {
-
- d_tx_chan = pmt_nth(2, data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received TX allocation"
- << " on channel " << d_tx_chan << std::endl;
-
- // If the RX has also been allocated already, we can continue
- if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
- enter_receiving();
- enter_transmitting();
- }
-
- return;
- }
- else { // TX allocation failed
- error_msg = "failed to allocate TX channel:";
- goto bail;
- }
- }
-
- // A RX allocation response
- if(pmt_eq(event, s_response_allocate_channel)
- && pmt_eq(d_rx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful response, extract the channel
- if(pmt_eq(status, PMT_T)) {
-
- d_rx_chan = pmt_nth(2, data);
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received RX allocation"
- << " on channel " << d_rx_chan << std::endl;
-
- // If the TX has also been allocated already, we can continue
- if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
- enter_receiving();
- enter_transmitting();
- }
-
- return;
- }
- else { // RX allocation failed
- error_msg = "failed to allocate RX channel:";
- goto bail;
- }
- }
-
- goto unhandled;
-
- case WRITE_REGISTER:
- goto unhandled;
-
- case READ_REGISTER:
- goto unhandled;
-
- //-------------------------- TRANSMITTING ----------------------------//
- // In the transmit state we count the number of underruns received and
- // ballpark the number with an expected count (something >1 for starters)
- case TRANSMITTING:
-
- // Check that the transmits are OK
- if (pmt_eq(event, s_response_xmit_raw_frame)){
- handle = pmt_nth(0, data);
- status = pmt_nth(1, data);
-
- if (pmt_eq(status, PMT_T)){
- handle_xmit_response(handle);
- return;
- }
- else {
- error_msg = "bad response-xmit-raw-frame:";
- goto bail;
- }
- }
-
- goto unhandled;
-
- //------------------------- CLOSING CHANNELS ----------------------------//
- // Check deallocation responses, once the TX and RX channels are both
- // deallocated then we close the USRP.
- case CLOSING_CHANNELS:
-
- if (pmt_eq(event, s_response_deallocate_channel)
- && pmt_eq(d_tx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful, set the port to NIL
- if(pmt_eq(status, PMT_T)) {
- d_tx_chan = PMT_NIL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received TX deallocation\n";
-
- // If the RX is also deallocated, we can close the USRP
- if(pmt_eq(d_rx_chan, PMT_NIL))
- closing_usrp();
-
- return;
-
- } else {
-
- error_msg = "failed to deallocate TX channel:";
- goto bail;
-
- }
- }
-
- if (pmt_eq(event, s_response_deallocate_channel)
- && pmt_eq(d_rx->port_symbol(), port_id))
- {
- status = pmt_nth(1, data);
-
- // If successful, set the port to NIL
- if(pmt_eq(status, PMT_T)) {
- d_rx_chan = PMT_NIL;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received RX deallocation\n";
-
- // If the TX is also deallocated, we can close the USRP
- if(pmt_eq(d_tx_chan, PMT_NIL))
- closing_usrp();
-
- return;
-
- } else {
-
- error_msg = "failed to deallocate RX channel:";
- goto bail;
-
- }
- }
-
- goto unhandled;
-
- //--------------------------- CLOSING USRP ------------------------------//
- // Once we have received a successful USRP close response, we shutdown all
- // mblocks and exit.
- case CLOSING_USRP:
-
- if (pmt_eq(event, s_response_close)) {
-
- status = pmt_nth(1, data);
-
- if(pmt_eq(status, PMT_T)) {
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Successfully closed USRP\n";
-
- std::cout << "\nUnderruns: " << d_n_underruns << std::endl;
- fflush(stdout);
-
- shutdown_all(PMT_T);
- return;
-
- } else {
-
- error_msg = "failed to close USRP:";
- goto bail;
- }
- }
-
- goto unhandled;
-
- case INIT:
- goto unhandled;
-
- }
-
- // An error occured, print it, and shutdown all m-blocks
- bail:
- std::cerr << error_msg << data
- << "status = " << status << std::endl;
- shutdown_all(PMT_F);
- return;
-
- // Received an unhandled message for a specific state
- unhandled:
- if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
- std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
- << "in state "<< d_state << std::endl;
-
-}
-
-
-// Sends a command to USRP server to open up a connection to the
-// specified USRP, which is defaulted to USRP 0 on the system
-void
-test_usrp_inband_underrun::opening_usrp()
-{
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Opening USRP "
- << d_which_usrp << std::endl;
-
- d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp));
- d_state = OPENING_USRP;
-}
-
-// RX and TX channels must be allocated so that the USRP server can
-// properly share bandwidth across multiple USRPs. No commands will be
-// successful to the USRP through the USRP server on the TX or RX channels until
-// a bandwidth allocation has been received.
-void
-test_usrp_inband_underrun::allocating_channels()
-{
- d_state = ALLOCATING_CHANNELS;
-
- long capacity = (long) 16e6;
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
-}
-
-// After allocating the channels, a write register command will be sent to the
-// USRP.
-void
-test_usrp_inband_underrun::write_register()
-{
- d_state = WRITE_REGISTER;
-
- long reg = 0;
-
- d_tx->send(s_cmd_to_control_channel, // C/S packet
- pmt_list2(PMT_NIL, // invoc handle
- pmt_list1(
- pmt_list2(s_op_write_reg,
- pmt_list2(
- pmt_from_long(reg),
- pmt_from_long(0xbeef))))));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to "
- << reg << std::endl;
-
- read_register(); // immediately transition to read the register
-}
-
-// Temporary: for testing pings
-void
-test_usrp_inband_underrun::build_and_send_ping()
-{
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
- pmt_list2(pmt_from_long(0),
- pmt_from_long(0))))));
-
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Ping sent" << std::endl;
-}
-
-// After writing to the register, we want to read the value back and ensure that
-// it is the same value that we wrote.
-void
-test_usrp_inband_underrun::read_register()
-{
- d_state = READ_REGISTER;
-
- long reg = 9;
-
- d_tx->send(s_cmd_to_control_channel, // C/S packet
- pmt_list2(PMT_NIL, // invoc handle
- pmt_list1(
- pmt_list2(s_op_read_reg,
- pmt_list2(
- pmt_from_long(0), // rid
- pmt_from_long(reg))))));
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Reading from register "
- << reg << std::endl;
-}
-
-// Used to enter the receiving state
-void
-test_usrp_inband_underrun::enter_receiving()
-{
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_F,
- d_rx_chan));
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Started RX sample stream\n";
-}
-
-void
-test_usrp_inband_underrun::enter_transmitting()
-{
- d_state = TRANSMITTING;
- d_nsamples_xmitted = 0;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Entering transmit state...\n";
-
- build_and_send_next_frame(); // fire off 4 to start pipeline
- build_and_send_next_frame();
- build_and_send_next_frame();
- build_and_send_next_frame();
-}
-
-void
-test_usrp_inband_underrun::build_and_send_next_frame()
-{
-
- long nsamples_this_frame =
- std::min(d_nsamples_to_send - d_nsamples_xmitted,
- d_samples_per_frame);
-
- if (nsamples_this_frame == 0){
- d_done_sending = true;
- return;
- }
-
- size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
- pmt_t uvec = pmt_make_s16vector(nshorts, 0);
- size_t ignore;
- int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
-
- // fill in the complex sinusoid
-
- for (int i = 0; i < nsamples_this_frame; i++){
-
- if (1){
- gr_complex s;
- d_nco.sincos(&s, 1, d_amplitude);
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- else {
- gr_complex s(d_amplitude, d_amplitude);
-
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- }
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Transmitting frame...\n";
-
- pmt_t timestamp = pmt_from_long(0xffffffff); // NOW
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle
- d_tx_chan, // channel
- uvec, // the samples
- timestamp));
-
- d_nsamples_xmitted += nsamples_this_frame;
- d_nframes_xmitted++;
-
- if(verbose)
- std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n";
-
-}
-
-void
-test_usrp_inband_underrun::handle_xmit_response(pmt_t handle)
-{
- if (d_done_sending &&
- pmt_to_long(handle) == (d_nframes_xmitted - 1)){
- // We're done sending and have received all responses
- closing_channels();
- return;
- }
-
- build_and_send_next_frame();
-}
-
-void
-test_usrp_inband_underrun::handle_recv_response(pmt_t dict)
-{
- if(!pmt_is_dict(dict)) {
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Recv samples dictionary is improper\n";
- return;
- }
-
- // Read the TX interpolations
- if(pmt_t underrun = pmt_dict_ref(dict,
- pmt_intern("underrun"),
- PMT_NIL)) {
- if(pmt_eqv(underrun, PMT_T)) {
- d_n_underruns++;
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] Underrun\n";
- }
- else {
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] No underrun\n" << underrun <<std::endl;
- }
- } else {
-
- if(verbose && 0)
- std::cout << "[TEST_USRP_INBAND_UNDERRUN] No underrun\n";
- }
-
-}
-
-void
-test_usrp_inband_underrun::closing_channels()
-{
- d_state = CLOSING_CHANNELS;
-
- d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
- d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
-}
-
-void
-test_usrp_inband_underrun::closing_usrp()
-{
- d_state = CLOSING_USRP;
-
- d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
-}
-
-REGISTER_MBLOCK_CLASS(test_usrp_inband_underrun);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2002 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-#ifndef INCLUDED_UI_NCO_H
-#define INCLUDED_UI_NCO_H
-
-
-#include <vector>
-#include <ui_sincos.h>
-#include <cmath>
-
-#include <complex>
-typedef std::complex<float> gr_complex;
-
-
-/*!
- * \brief base class template for Numerically Controlled Oscillator (NCO)
- */
-
-
-//FIXME Eventually generalize this to fixed point
-
-template<class o_type, class i_type>
-class ui_nco {
-public:
- ui_nco () : phase (0), phase_inc(0) {}
-
- virtual ~ui_nco () {}
-
- // radians
- void set_phase (double angle) {
- phase = angle;
- }
-
- void adjust_phase (double delta_phase) {
- phase += delta_phase;
- }
-
-
- // angle_rate is in radians / step
- void set_freq (double angle_rate){
- phase_inc = angle_rate;
- }
-
- // angle_rate is a delta in radians / step
- void adjust_freq (double delta_angle_rate)
- {
- phase_inc += delta_angle_rate;
- }
-
- // increment current phase angle
-
- void step ()
- {
- phase += phase_inc;
- if (fabs (phase) > M_PI){
-
- while (phase > M_PI)
- phase -= 2*M_PI;
-
- while (phase < -M_PI)
- phase += 2*M_PI;
- }
- }
-
- void step (int n)
- {
- phase += phase_inc * n;
- if (fabs (phase) > M_PI){
-
- while (phase > M_PI)
- phase -= 2*M_PI;
-
- while (phase < -M_PI)
- phase += 2*M_PI;
- }
- }
-
- // units are radians / step
- double get_phase () const { return phase; }
- double get_freq () const { return phase_inc; }
-
- // compute sin and cos for current phase angle
- void sincos (float *sinx, float *cosx) const;
-
- // compute cos or sin for current phase angle
- float cos () const { return std::cos (phase); }
- float sin () const { return std::sin (phase); }
-
- // compute a block at a time
- void sin (float *output, int noutput_items, double ampl = 1.0);
- void cos (float *output, int noutput_items, double ampl = 1.0);
- void sincos (gr_complex *output, int noutput_items, double ampl = 1.0);
- void sin (short *output, int noutput_items, double ampl = 1.0);
- void cos (short *output, int noutput_items, double ampl = 1.0);
- void sin (int *output, int noutput_items, double ampl = 1.0);
- void cos (int *output, int noutput_items, double ampl = 1.0);
-
-protected:
- double phase;
- double phase_inc;
-};
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::sincos (float *sinx, float *cosx) const
-{
- ui_sincosf (phase, sinx, cosx);
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::sin (float *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- output[i] = (float)(sin () * ampl);
- step ();
- }
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::cos (float *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- output[i] = (float)(cos () * ampl);
- step ();
- }
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::sin (short *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- output[i] = (short)(sin() * ampl);
- step ();
- }
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::cos (short *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- output[i] = (short)(cos () * ampl);
- step ();
- }
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::sin (int *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- output[i] = (int)(sin () * ampl);
- step ();
- }
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::cos (int *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- output[i] = (int)(cos () * ampl);
- step ();
- }
-}
-
-template<class o_type, class i_type>
-void
-ui_nco<o_type,i_type>::sincos (gr_complex *output, int noutput_items, double ampl)
-{
- for (int i = 0; i < noutput_items; i++){
- float cosx, sinx;
- sincos (&sinx, &cosx);
- output[i] = gr_complex(cosx * ampl, sinx * ampl);
- step ();
- }
-}
-
-#endif /* INCLUDED_UI_NCO_H */
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define _GNU_SOURCE // ask for GNU extensions if available
-
-#include "ui_sincos.h"
-#include <math.h>
-
-// ----------------------------------------------------------------
-
-#if defined (HAVE_SINCOS)
-
-void
-ui_sincos (double x, double *sinx, double *cosx)
-{
- sincos (x, sinx, cosx);
-}
-
-#else
-
-void
-ui_sincos (double x, double *sinx, double *cosx)
-{
- *sinx = sin (x);
- *cosx = cos (x);
-}
-
-#endif
-
-// ----------------------------------------------------------------
-
-#if defined (HAVE_SINCOSF)
-
-void
-ui_sincosf (float x, float *sinx, float *cosx)
-{
- sincosf (x, sinx, cosx);
-}
-
-#elif defined (HAVE_SINF) && defined (HAVE_COSF)
-
-void
-ui_sincosf (float x, float *sinx, float *cosx)
-{
- *sinx = sinf (x);
- *cosx = cosf (x);
-}
-
-#else
-
-void
-ui_sincosf (float x, float *sinx, float *cosx)
-{
- *sinx = sin (x);
- *cosx = cos (x);
-}
-
-#endif
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2002,2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_UI_SINCOS_H
-#define INCLUDED_UI_SINCOS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// compute sine and cosine at the same time
-
-void ui_sincos (double x, double *sin, double *cos);
-void ui_sincosf (float x, float *sin, float *cos);
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif /* INCLUDED_UI_SINCOS_H */
/* -*- c++ -*- */
/*
- * Copyright 2003,2006,2008 Free Software Foundation, Inc.
+ * Copyright 2003,2006,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <assert.h>
#include <math.h>
#include "time_stuff.h"
-#include "usrp_standard.h"
-#include "usrp_bytesex.h"
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
#include "fpga_regs_common.h"
#include "fpga_regs_standard.h"
#include <assert.h>
#include <math.h>
#include "time_stuff.h"
-#include "usrp_standard.h"
-#include "usrp_bytesex.h"
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
#include <boost/program_options.hpp>
enum {
/* -*- c++ -*- */
/*
- * Copyright 2005,2008 Free Software Foundation, Inc.
+ * Copyright 2005,2008,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
#include <assert.h>
#include <math.h>
#include <boost/scoped_ptr.hpp>
-#include "usrp_local_sighandler.h"
-#include "usrp_standard.h"
-#include "usrp_bytesex.h"
+#include <usrp/usrp_local_sighandler.h>
+#include <usrp/usrp_standard.h>
+#include <usrp/usrp_bytesex.h>
char *prog_name;
/*
* USRP - Universal Software Radio Peripheral
*
- * Copyright (C) 2003,2004 Free Software Foundation, Inc.
+ * Copyright (C) 2003,2004,2009 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
#include <assert.h>
#include <errno.h>
-#include "usrp_prims.h"
+#include "usrp/usrp_prims.h"
#include "usrp_spi_defs.h"
#include <string.h>
--- /dev/null
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+SUBDIRS = usrp
+
--- /dev/null
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+usrpincludedir = $(includedir)/usrp
+
+usrpinclude_HEADERS = \
+ db_base.h \
+ db_basic.h \
+ db_dbs_rx.h \
+ db_dtt754.h \
+ db_dtt768.h \
+ db_flexrf.h \
+ db_flexrf_mimo.h \
+ db_tv_rx.h \
+ db_xcvr2450.h \
+ usrp_basic.h \
+ usrp_bytesex.h \
+ usrp_dbid.h \
+ usrp_local_sighandler.h \
+ usrp_prims.h \
+ usrp_slots.h \
+ usrp_standard.h \
+ usrp_subdev_spec.h \
+ usrp_tune_result.h
+
+if PYTHON
+swiginclude_HEADERS = \
+ db_base.i
+endif
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+//
+
+#ifndef INCLUDED_DB_BASE_H
+#define INCLUDED_DB_BASE_H
+
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <iosfwd>
+
+class db_base;
+typedef boost::shared_ptr<db_base> db_base_sptr;
+
+class usrp_basic;
+typedef boost::shared_ptr<usrp_basic> usrp_basic_sptr;
+
+struct freq_result_t
+{
+ bool ok;
+ double baseband_freq;
+};
+
+/******************************************************************************/
+
+/*!
+ * \brief Abstract base class for all USRP daughterboards
+ * \ingroup usrp
+ */
+class db_base
+{
+ protected:
+ bool d_is_shutdown;
+ usrp_basic *d_raw_usrp;
+ int d_which;
+ double d_lo_offset;
+
+ void _enable_refclk(bool enable);
+ virtual double _refclk_freq();
+ virtual int _refclk_divisor();
+
+ usrp_basic *usrp(){
+ return d_raw_usrp;
+ }
+
+ public:
+ db_base(boost::shared_ptr<usrp_basic> usrp, int which);
+ virtual ~db_base();
+
+ int dbid();
+ std::string name();
+ std::string side_and_name();
+ int which() { return d_which; }
+
+ bool bypass_adc_buffers(bool bypass);
+ bool set_atr_mask(int v);
+ bool set_atr_txval(int v);
+ bool set_atr_rxval(int v);
+ bool set_atr_tx_delay(int v);
+ bool set_atr_rx_delay(int v);
+ bool set_lo_offset(double offset);
+ double lo_offset() { return d_lo_offset; }
+
+
+ ////////////////////////////////////////////////////////
+ // derived classes should override the following methods
+
+protected:
+ friend class usrp_basic;
+
+ /*!
+ * Called to shutdown daughterboard. Called from dtor and usrp_basic dtor.
+ *
+ * N.B., any class that overrides shutdown MUST call shutdown in its destructor.
+ */
+ virtual void shutdown();
+
+
+public:
+ virtual float gain_min() = 0;
+ virtual float gain_max() = 0;
+ virtual float gain_db_per_step() = 0;
+ virtual double freq_min() = 0;
+ virtual double freq_max() = 0;
+ virtual struct freq_result_t set_freq(double target_freq) = 0;
+ virtual bool set_gain(float gain) = 0;
+ virtual bool is_quadrature() = 0;
+ virtual bool i_and_q_swapped();
+ virtual bool spectrum_inverted();
+ virtual bool set_enable(bool on);
+ virtual bool set_auto_tr(bool on);
+ virtual bool select_rx_antenna(int which_antenna);
+ virtual bool select_rx_antenna(const std::string &which_antenna);
+ virtual bool set_bw(float bw);
+};
+
+
+std::ostream & operator<<(std::ostream &os, db_base &x);
+
+#endif /* INCLUDED_DB_BASE_H */
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+//
+
+
+%{
+#include <usrp/db_base.h>
+%}
+
+%include <gr_shared_ptr.i>
+
+class usrp_tune_result
+{
+public:
+ usrp_tune_result(double baseband=0, double dxc=0,
+ double residual=0, bool inv=0);
+ ~usrp_tune_result();
+
+ double baseband_freq;
+ double dxc_freq;
+ double residual_freq;
+ bool inverted;
+};
+
+struct freq_result_t
+{
+ bool ok;
+ double baseband_freq;
+};
+
+class db_base
+{
+ private:
+ db_base(boost::shared_ptr<usrp_basic> usrp, int which);
+
+ public:
+ virtual ~db_base();
+
+ int dbid();
+ std::string name();
+ std::string side_and_name();
+ int which() { return d_which; }
+
+ bool bypass_adc_buffers(bool bypass);
+ bool set_atr_mask(int v);
+ bool set_atr_txval(int v);
+ bool set_atr_rxval(int v);
+ bool set_atr_tx_delay(int v);
+ bool set_atr_rx_delay(int v);
+ bool set_lo_offset(double offset);
+ double lo_offset() { return d_lo_offset; }
+
+ virtual float gain_min() = 0;
+ virtual float gain_max() = 0;
+ virtual float gain_db_per_step() = 0;
+ virtual double freq_min() = 0;
+ virtual double freq_max() = 0;
+ virtual struct freq_result_t set_freq(double target_freq) = 0;
+ virtual bool set_gain(float gain) = 0;
+ virtual bool is_quadrature() = 0;
+ virtual bool i_and_q_swapped();
+ virtual bool spectrum_inverted();
+ virtual bool set_enable(bool on);
+ virtual bool set_auto_tr(bool on);
+ virtual bool select_rx_antenna(int which_antenna);
+ virtual bool select_rx_antenna(const std::string &antenna);
+ virtual bool set_bw(float bw);
+};
+
+// Create templates for db's, vectors of db's, and vector of vectors of db's
+typedef boost::shared_ptr<db_base> db_base_sptr;
+%template(db_base_sptr) boost::shared_ptr<db_base>;
+%template(db_base_sptr_vector) std::vector<db_base_sptr>;
+%template(db_base_sptr_vector_vector) std::vector<std::vector<db_base_sptr> >;
+
+// Set better class name in Python
+// Enable freq_range and gain_range from public methods of class not implemented in C++
+// And create a dummy wrapper for backwards compatability with some of the example code
+%pythoncode %{
+ db_base_sptr.__repr__ = lambda self: "<db_base::%s>" % (self.name(),)
+ db_base_sptr.freq_range = lambda self: (self.freq_min(), self.freq_max(), 1)
+ db_base_sptr.gain_range = lambda self: (self.gain_min(), self.gain_max(), self.gain_db_per_step())
+
+%}
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_BASIC_H
+#define DB_BASIC_H
+
+#include <usrp/db_base.h>
+
+
+/******************************************************************************/
+
+
+class db_basic_tx : public db_base
+{
+public:
+ db_basic_tx(usrp_basic_sptr usrp, int which);
+ ~db_basic_tx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ double freq_min();
+ double freq_max();
+ struct freq_result_t set_freq(double target_freq);
+ bool set_gain(float gain);
+ bool is_quadrature();
+};
+
+
+/******************************************************************************/
+
+
+class db_basic_rx : public db_base
+{
+ public:
+ db_basic_rx(usrp_basic_sptr usrp, int which, int subdev);
+ ~db_basic_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ double freq_min();
+ double freq_max();
+ struct freq_result_t set_freq(double target_freq);
+ bool set_gain(float gain);
+ bool is_quadrature();
+
+private:
+ int d_subdev;
+};
+
+
+/******************************************************************************/
+
+
+class db_lf_rx : public db_basic_rx
+{
+ public:
+ db_lf_rx(usrp_basic_sptr usrp, int which, int subdev);
+ ~db_lf_rx();
+
+ double freq_min();
+ double freq_max();
+};
+
+
+/******************************************************************************/
+
+
+class db_lf_tx : public db_basic_tx
+{
+ public:
+ db_lf_tx(usrp_basic_sptr usrp, int which);
+ ~db_lf_tx();
+
+ double freq_min();
+ double freq_max();
+};
+
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_DBS_RX_H
+#define DB_DBS_RX_H
+
+#include <usrp/db_base.h>
+#include <vector>
+
+#if 0
+struct bw_t {
+ int m;
+ int fdac;
+ float div;
+};
+#endif
+
+class db_dbs_rx : public db_base
+{
+private:
+ int d_osc, d_cp, d_n, d_div2, d_r, d_r_int;
+ int d_fdac, d_m, d_dl, d_ade, d_adl, d_gc1, d_gc2, d_diag;
+ int d_i2c_addr;
+
+ // Internal gain functions
+ void _write_reg(int regno, int v);
+ void _write_regs(int starting_regno, const std::vector<int> &vals);
+ std::vector<int> _read_status();
+ void _send_reg(int regno);
+ void _set_m(int m);
+ void _set_fdac(int fdac);
+ void _set_dl(int dl);
+ void _set_gc2(int gc2);
+ void _set_gc1(int gc1);
+ void _set_pga(int pga_gain);
+
+ // Internal frequency function
+ void _set_osc(int osc);
+ void _set_cp(int cp);
+ void _set_n(int n);
+ void _set_div2(int div2);
+ void _set_r(int r);
+ void _set_ade(int ade);
+
+ int _refclk_divisor();
+
+protected:
+ void shutdown();
+
+public:
+ db_dbs_rx(usrp_basic_sptr usrp, int which);
+ ~db_dbs_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ double freq_min();
+ double freq_max();
+ struct freq_result_t set_freq(double freq);
+ bool set_gain(float gain);
+ bool is_quadrature();
+ bool set_bw(float bw);
+};
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_DTT754_H
+#define DB_DTT754_H
+
+#include <usrp/db_base.h>
+#include <boost/shared_ptr.hpp>
+
+class db_dtt754 : public db_base
+{
+public:
+ db_dtt754(usrp_basic_sptr usrp, int which);
+ ~db_dtt754();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool set_gain(float gain);
+
+ double freq_min();
+ double freq_max();
+ struct freq_result_t set_freq(double target_freq);
+
+ bool is_quadrature();
+ bool spectrum_inverted();
+ bool set_bw(float bw);
+
+private:
+ void _set_rfagc(float gain);
+ void _set_ifagc(float gain);
+ void _set_pga(float pga_gain);
+
+ int d_i2c_addr;
+ float d_bw, d_freq, d_IF, d_f_ref;
+ bool d_inverted;
+};
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_DTT768_H
+#define DB_DTT768_H
+
+#include <usrp/db_base.h>
+#include <boost/shared_ptr.hpp>
+
+class db_dtt768 : public db_base
+{
+public:
+ db_dtt768(usrp_basic_sptr usrp, int which);
+ ~db_dtt768();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool set_gain(float gain);
+
+ double freq_min();
+ double freq_max();
+ struct freq_result_t set_freq(double target_freq);
+
+ bool is_quadrature();
+ bool spectrum_inverted();
+ bool set_bw(float bw);
+
+private:
+ void _set_rfagc(float gain);
+ void _set_ifagc(float gain);
+ void _set_pga(float pga_gain);
+
+ int d_i2c_addr;
+ float d_bw, d_freq, d_IF, d_f_ref;
+ bool d_inverted;
+};
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_FLEXRF_H
+#define DB_FLEXRF_H
+
+#include <usrp/db_base.h>
+#include <cmath>
+
+//debug_using_gui = true // Must be set to True or False
+#define debug_using_gui false // Must be set to True or False
+
+class _AD4360_common;
+
+class flexrf_base : public db_base
+{
+public:
+ flexrf_base(usrp_basic_sptr usrp, int which, int _power_on=0);
+ ~flexrf_base();
+
+ struct freq_result_t set_freq(double freq);
+
+ bool is_quadrature();
+ double freq_min();
+ double freq_max();
+
+protected:
+ void _write_all(int R, int control, int N);
+ void _write_control(int control);
+ void _write_R(int R);
+ void _write_N(int N);
+ void _write_it(int v);
+ bool _lock_detect();
+
+ virtual bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+ int _compute_control_reg();
+ int _refclk_divisor();
+ double _refclk_freq();
+
+ bool _set_pga(float pga_gain);
+
+ int power_on() { return d_power_on; }
+ int power_off() { return 0; }
+
+ bool d_first;
+ int d_spi_format;
+ int d_spi_enable;
+ int d_power_on;
+ int d_PD;
+
+ _AD4360_common *d_common;
+};
+
+// ----------------------------------------------------------------
+
+class flexrf_base_tx : public flexrf_base
+{
+protected:
+ void shutdown();
+
+public:
+ flexrf_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0);
+ ~flexrf_base_tx();
+
+ // All RFX tx d'boards have fixed gain
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+
+ bool set_auto_tr(bool on);
+ bool set_enable(bool on);
+ bool set_gain(float gain);
+};
+
+class flexrf_base_rx : public flexrf_base
+{
+protected:
+ void shutdown();
+
+public:
+ flexrf_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0);
+ ~flexrf_base_rx();
+
+ bool set_auto_tr(bool on);
+ bool select_rx_antenna(int which_antenna);
+ bool select_rx_antenna(const std::string &which_antenna);
+ bool set_gain(float gain);
+
+};
+
+// ----------------------------------------------------------------
+
+
+class _AD4360_common
+{
+public:
+ _AD4360_common();
+ virtual ~_AD4360_common();
+
+ virtual double freq_min() = 0;
+ virtual double freq_max() = 0;
+
+ bool _compute_regs(double refclk_freq, double freq, int &retR,
+ int &retcontrol, int &retN, double &retfreq);
+ int _compute_control_reg();
+ virtual int _refclk_divisor();
+ int _prescaler();
+
+ void R_DIV(int div) { d_R_DIV = div; }
+
+protected:
+ int d_R_RSV, d_BSC, d_TEST, d_LDP, d_ABP, d_N_RSV, d_PL, d_MTLD;
+ int d_CPG, d_CP3S, d_PDP, d_MUXOUT, d_CR, d_PC;
+
+ // FIXME: d_PD might cause conflict from flexrf_base
+ int d_A_DIV, d_B_DIV, d_R_DIV, d_P, d_PD, d_CP2, d_CP1, d_DIVSEL;
+ int d_DIV2, d_CPGAIN, d_freq_mult;
+
+};
+
+//----------------------------------------------------------------------
+
+class _2400_common : public _AD4360_common
+{
+ public:
+ _2400_common();
+ ~_2400_common() {}
+
+ double freq_min();
+ double freq_max();
+};
+
+//----------------------------------------------------------------------
+
+class _1200_common : public _AD4360_common
+{
+public:
+ _1200_common();
+ ~_1200_common() {}
+
+ double freq_min();
+ double freq_max();
+};
+
+//-------------------------------------------------------------------------
+
+class _1800_common : public _AD4360_common
+{
+ public:
+ _1800_common();
+ ~_1800_common() {}
+
+ double freq_min();
+ double freq_max();
+};
+
+//-------------------------------------------------------------------------
+
+class _900_common : public _AD4360_common
+{
+public:
+ _900_common();
+ ~_900_common() {}
+
+ double freq_min();
+ double freq_max();
+};
+
+//-------------------------------------------------------------------------
+
+class _400_common : public _AD4360_common
+{
+public:
+ _400_common();
+ ~_400_common() {}
+
+ double freq_min();
+ double freq_max();
+};
+
+class _400_tx : public _400_common
+{
+public:
+ _400_tx();
+ ~_400_tx() {}
+};
+
+class _400_rx : public _400_common
+{
+public:
+ _400_rx();
+ ~_400_rx() {}
+};
+
+//------------------------------------------------------------
+
+class db_flexrf_2400_tx : public flexrf_base_tx
+{
+ public:
+ db_flexrf_2400_tx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_2400_tx();
+
+ // Wrapper calls to d_common functions
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+class db_flexrf_2400_rx : public flexrf_base_rx
+{
+public:
+ db_flexrf_2400_rx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_2400_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool i_and_q_swapped();
+
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+//------------------------------------------------------------
+
+class db_flexrf_1200_tx : public flexrf_base_tx
+{
+public:
+ db_flexrf_1200_tx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_1200_tx();
+
+ // Wrapper calls to d_common functions
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+class db_flexrf_1200_rx : public flexrf_base_rx
+{
+public:
+ db_flexrf_1200_rx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_1200_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool i_and_q_swapped();
+
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+//------------------------------------------------------------
+
+class db_flexrf_1800_tx : public flexrf_base_tx
+{
+ public:
+ db_flexrf_1800_tx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_1800_tx();
+
+ // Wrapper calls to d_common functions
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+class db_flexrf_1800_rx : public flexrf_base_rx
+{
+public:
+ db_flexrf_1800_rx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_1800_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool i_and_q_swapped();
+
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+//------------------------------------------------------------
+
+class db_flexrf_900_tx : public flexrf_base_tx
+{
+ public:
+ db_flexrf_900_tx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_900_tx();
+
+ // Wrapper calls to d_common functions
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+class db_flexrf_900_rx : public flexrf_base_rx
+{
+public:
+ db_flexrf_900_rx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_900_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool i_and_q_swapped();
+
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+
+//------------------------------------------------------------
+
+class db_flexrf_400_tx : public flexrf_base_tx
+{
+ public:
+ db_flexrf_400_tx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_400_tx();
+
+ // Wrapper calls to d_common functions
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+class db_flexrf_400_rx : public flexrf_base_rx
+{
+public:
+ db_flexrf_400_rx(usrp_basic_sptr usrp, int which);
+ ~db_flexrf_400_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool i_and_q_swapped();
+
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright 2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <usrp/db_flexrf.h>
+
+class db_flexrf_2400_tx_mimo_a : public db_flexrf_2400_tx
+{
+ public:
+ db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_2400_rx_mimo_a : public db_flexrf_2400_rx
+{
+ public:
+ db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_2400_tx_mimo_b : public db_flexrf_2400_tx
+{
+ public:
+ db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_2400_rx_mimo_b : public db_flexrf_2400_rx
+{
+ public:
+ db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+
+class db_flexrf_1800_tx_mimo_a : public db_flexrf_1800_tx
+{
+ public:
+ db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1800_rx_mimo_a : public db_flexrf_1800_rx
+{
+ public:
+ db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1800_tx_mimo_b : public db_flexrf_1800_tx
+{
+ public:
+ db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1800_rx_mimo_b : public db_flexrf_1800_rx
+{
+ public:
+ db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1200_tx_mimo_a : public db_flexrf_1200_tx
+{
+ public:
+ db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1200_rx_mimo_a : public db_flexrf_1200_rx
+{
+ public:
+ db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1200_tx_mimo_b : public db_flexrf_1200_tx
+{
+ public:
+ db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_1200_rx_mimo_b : public db_flexrf_1200_rx
+{
+ public:
+ db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_900_tx_mimo_a : public db_flexrf_900_tx
+{
+ public:
+ db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_900_rx_mimo_a : public db_flexrf_900_rx
+{
+ public:
+ db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_900_tx_mimo_b : public db_flexrf_900_tx
+{
+ public:
+ db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_900_rx_mimo_b : public db_flexrf_900_rx
+{
+ public:
+ db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_400_tx_mimo_a : public db_flexrf_400_tx
+{
+ public:
+ db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_400_rx_mimo_a : public db_flexrf_400_rx
+{
+ public:
+ db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_400_tx_mimo_b : public db_flexrf_400_tx
+{
+ public:
+ db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
+
+class db_flexrf_400_rx_mimo_b : public db_flexrf_400_rx
+{
+ public:
+ db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which);
+ int _refclk_divisor();
+};
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_TV_RX_H
+#define DB_TV_RX_H
+
+#include <usrp/db_base.h>
+
+class db_tv_rx : public db_base
+{
+private:
+ void _set_rfagc(float gain);
+ void _set_ifagc(float gain);
+ void _set_pga(float pga_gain);
+
+ int d_i2c_addr;
+ double d_first_IF, d_second_IF;
+ int d_reference_divisor;
+ bool d_fast_tuning;
+ bool d_inverted;
+
+public:
+ db_tv_rx(usrp_basic_sptr usrp, int which,
+ double first_IF, double second_IF);
+ ~db_tv_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ double freq_min();
+ double freq_max();
+ struct freq_result_t set_freq(double target_freq);
+ bool set_gain(float gain);
+ bool is_quadrature();
+ bool spectrum_inverted();
+};
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_XCVR2450_H
+#define DB_XCVR2450_H
+
+#include <usrp/db_base.h>
+#include <boost/shared_ptr.hpp>
+
+class xcvr2450;
+typedef boost::shared_ptr<xcvr2450> xcvr2450_sptr;
+
+
+/******************************************************************************/
+
+
+class db_xcvr2450_base: public db_base
+{
+ /*
+ * Abstract base class for all xcvr2450 boards.
+ *
+ * Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
+ */
+public:
+ db_xcvr2450_base(usrp_basic_sptr usrp, int which);
+ ~db_xcvr2450_base();
+ struct freq_result_t set_freq(double target_freq);
+ bool is_quadrature();
+ double freq_min();
+ double freq_max();
+
+protected:
+ xcvr2450_sptr d_xcvr;
+ void shutdown_common();
+};
+
+
+/******************************************************************************/
+
+
+class db_xcvr2450_tx : public db_xcvr2450_base
+{
+protected:
+ void shutdown();
+
+public:
+ db_xcvr2450_tx(usrp_basic_sptr usrp, int which);
+ ~db_xcvr2450_tx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool set_gain(float gain);
+ bool i_and_q_swapped();
+};
+
+class db_xcvr2450_rx : public db_xcvr2450_base
+{
+protected:
+ void shutdown();
+
+public:
+ db_xcvr2450_rx(usrp_basic_sptr usrp, int which);
+ ~db_xcvr2450_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool set_gain(float gain);
+};
+
+
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * ----------------------------------------------------------------------
+ * 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/db_base.h>
+#include <usrp/usrp_slots.h>
+#include <string>
+#include <vector>
+#include <boost/utility.hpp>
+#include <usrp/usrp_subdev_spec.h>
+
+struct usb_dev_handle;
+class fusb_devhandle;
+class fusb_ephandle;
+
+enum txrx_t {
+ C_RX = 0,
+ C_TX = 1
+};
+
+/*!
+ * \brief abstract base class for usrp operations
+ * \ingroup usrp
+ */
+class usrp_basic : boost::noncopyable
+{
+protected:
+ void shutdown_daughterboards();
+
+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;
+ long d_fpga_master_clock_freq;
+
+ static const int MAX_REGS = 128;
+ unsigned int d_fpga_shadows[MAX_REGS];
+
+ int d_dbid[2]; // daughterboard ID's (side A, side B)
+
+ /*!
+ * Shared pointers to subclasses of db_base.
+ *
+ * The outer vector is of length 2 (0 = side A, 1 = side B). The
+ * inner vectors are of length 1, 2 or 3 depending on the number of
+ * subdevices implemented by the daugherboard. At this time, only
+ * the Basic Rx and LF Rx implement more than 1 subdevice.
+ */
+ std::vector< std::vector<db_base_sptr> > d_db;
+
+ //! One time call, made only only from usrp_standard_*::make after shared_ptr is created.
+ void init_db(usrp_basic_sptr u);
+
+
+ usrp_basic (int which_board,
+ struct usb_dev_handle *open_interface (struct usb_device *dev),
+ const std::string fpga_filename = "",
+ 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 ();
+
+
+ /*!
+ * Return a vector of vectors that contain shared pointers
+ * to the daughterboard instance(s) associated with the specified side.
+ *
+ * It is an error to use the returned objects after the usrp_basic
+ * object has been destroyed.
+ */
+ std::vector<std::vector<db_base_sptr> > db() const { return d_db; }
+
+ /*!
+ * Return a vector of size >= 1 that contains shared pointers
+ * to the daughterboard instance(s) associated with the specified side.
+ *
+ * \param which_side [0,1] which daughterboard
+ *
+ * It is an error to use the returned objects after the usrp_basic
+ * object has been destroyed.
+ */
+ std::vector<db_base_sptr> db(int which_side);
+
+ /*!
+ * \brief is the subdev_spec valid?
+ */
+ bool is_valid(const usrp_subdev_spec &ss);
+
+ /*!
+ * \brief given a subdev_spec, return the corresponding daughterboard object.
+ * \throws std::invalid_ argument if ss is invalid.
+ *
+ * \param ss specifies the side and subdevice
+ */
+ db_base_sptr selected_subdev(const usrp_subdev_spec &ss);
+
+ /*!
+ * \brief return frequency of master oscillator on USRP
+ */
+ long fpga_master_clock_freq () const { return d_fpga_master_clock_freq; }
+
+ /*!
+ * Tell API that the master oscillator on the USRP is operating at a non-standard
+ * fixed frequency. This is only needed for custom USRP hardware modified to
+ * operate at a different frequency from the default factory configuration. This
+ * function must be called prior to any other API function.
+ * \param master_clock USRP2 FPGA master clock frequency in Hz (10..64 MHz)
+ */
+ void set_fpga_master_clock_freq (long master_clock) { d_fpga_master_clock_freq = master_clock; }
+
+ /*!
+ * \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_adc 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_adc, int offset);
+
+ /*!
+ * \brief Set DAC offset correction
+ * \param which_dac 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_dac, int offset, int offset_pin);
+
+ /*!
+ * \brief Control ADC input buffer
+ * \param which_adc which ADC[0,3]
+ * \param bypass if non-zero, bypass input buffer and connect input
+ * directly to switched cap SHA input of RxPGA.
+ */
+ bool set_adc_buffer_bypass (int which_adc, bool bypass);
+
+ /*!
+ * \brief Enable/disable automatic DC offset removal control loop in FPGA
+ *
+ * \param bits which control loops to enable
+ * \param mask which \p bits to pay attention to
+ *
+ * If the corresponding bit is set, enable the automatic DC
+ * offset correction control loop.
+ *
+ * <pre>
+ * The 4 low bits are significant:
+ *
+ * ADC0 = (1 << 0)
+ * ADC1 = (1 << 1)
+ * ADC2 = (1 << 2)
+ * ADC3 = (1 << 3)
+ * </pre>
+ *
+ * By default the control loop is enabled on all ADC's.
+ */
+ bool set_dc_offset_cl_enable(int bits, int mask);
+
+ /*!
+ * \brief return the usrp's serial number.
+ *
+ * \returns non-zero length string iff successful.
+ */
+ std::string serial_number();
+
+ /*!
+ * \brief Return daughterboard ID for given side [0,1].
+ *
+ * \param which_side [0,1] which daughterboard
+ *
+ * \return daughterboard id >= 0 if successful
+ * \return -1 if no daugherboard
+ * \return -2 if invalid EEPROM on daughterboard
+ */
+ virtual int daughterboard_id (int which_side) const = 0;
+
+ /*!
+ * \brief Clock ticks to delay rising of T/R signal
+ * \sa write_atr_mask, write_atr_txval, write_atr_rxval
+ */
+ bool write_atr_tx_delay(int value);
+
+ /*!
+ * \brief Clock ticks to delay falling edge of T/R signal
+ * \sa write_atr_mask, write_atr_txval, write_atr_rxval
+ */
+ bool write_atr_rx_delay(int value);
+
+
+\f // ================================================================
+ // Routines to access and control daughterboard specific i/o
+ //
+ // Those with a common_ prefix access either the Tx or Rx side depending
+ // on the txrx parameter. Those without the common_ prefix are virtual
+ // and are overriden in usrp_basic_rx and usrp_basic_tx to access the
+ // the Rx or Tx sides automatically. We provide the common_ versions
+ // for those daughterboards such as the WBX and XCVR2450 that share
+ // h/w resources (such as the LO) between the Tx and Rx sides.
+
+ // ----------------------------------------------------------------
+ // BEGIN common_ daughterboard control functions
+
+ /*!
+ * \brief Set Programmable Gain Amplifier(PGA)
+ *
+ * \param txrx Tx or Rx?
+ * \param which_amp which amp [0,3]
+ * \param gain_in_db gain value(linear in dB)
+ *
+ * gain is rounded to closest setting supported by hardware.
+ *
+ * \returns true iff sucessful.
+ *
+ * \sa pga_min(), pga_max(), pga_db_per_step()
+ */
+ bool common_set_pga(txrx_t txrx, int which_amp, double gain_in_db);
+
+ /*!
+ * \brief Return programmable gain amplifier gain setting in dB.
+ *
+ * \param txrx Tx or Rx?
+ * \param which_amp which amp [0,3]
+ */
+ double common_pga(txrx_t txrx, int which_amp) const;
+
+ /*!
+ * \brief Return minimum legal PGA gain in dB.
+ * \param txrx Tx or Rx?
+ */
+ double common_pga_min(txrx_t txrx) const;
+
+ /*!
+ * \brief Return maximum legal PGA gain in dB.
+ * \param txrx Tx or Rx?
+ */
+ double common_pga_max(txrx_t txrx) const;
+
+ /*!
+ * \brief Return hardware step size of PGA(linear in dB).
+ * \param txrx Tx or Rx?
+ */
+ double common_pga_db_per_step(txrx_t txrx) const;
+
+ /*!
+ * \brief Write direction register(output enables) for pins that go to daughterboard.
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which size
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ *
+ * Each d'board has 16-bits of general purpose i/o.
+ * Setting the bit makes it an output from the FPGA to the d'board.
+ *
+ * This register is initialized based on a value stored in the
+ * d'board EEPROM. In general, you shouldn't be using this routine
+ * without a very good reason. Using this method incorrectly will
+ * kill your USRP motherboard and/or daughterboard.
+ */
+ bool _common_write_oe(txrx_t txrx, int which_side, int value, int mask);
+
+ /*!
+ * \brief Write daughterboard i/o pin value
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ */
+ bool common_write_io(txrx_t txrx, int which_side, int value, int mask);
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * \param value output
+ */
+ bool common_read_io(txrx_t txrx, int which_side, int *value);
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * \returns register value if successful, else READ_FAILED
+ */
+ int common_read_io(txrx_t txrx, int which_side);
+
+ /*!
+ * \brief Write daughterboard refclk config register
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * \param value value to write into register, see below
+ *
+ * <pre>
+ * Control whether a reference clock is sent to the daughterboards,
+ * and what frequency. The refclk is sent on d'board i/o pin 0.
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------------------------------+-+------------+
+ * | Reserved (Must be zero) |E| DIVISOR |
+ * +-----------------------------------------------+-+------------+
+ *
+ * Bit 7 -- 1 turns on refclk, 0 allows IO use
+ * Bits 6:0 Divider value
+ * </pre>
+ */
+ bool common_write_refclk(txrx_t txrx, int which_side, int value);
+
+ /*!
+ * \brief Automatic Transmit/Receive switching
+ * <pre>
+ *
+ * If automatic transmit/receive (ATR) switching is enabled in the
+ * FR_ATR_CTL register, the presence or absence of data in the FPGA
+ * transmit fifo selects between two sets of values for each of the 4
+ * banks of daughterboard i/o pins.
+ *
+ * Each daughterboard slot has 3 16-bit registers associated with it:
+ * FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_*
+ *
+ * FR_ATR_MASK_{0,1,2,3}:
+ *
+ * These registers determine which of the daugherboard i/o pins are
+ * affected by ATR switching. If a bit in the mask is set, the
+ * corresponding i/o bit is controlled by ATR, else it's output
+ * value comes from the normal i/o pin output register:
+ * FR_IO_{0,1,2,3}.
+ *
+ * FR_ATR_TXVAL_{0,1,2,3}:
+ * FR_ATR_RXVAL_{0,1,2,3}:
+ *
+ * If the Tx fifo contains data, then the bits from TXVAL that are
+ * selected by MASK are output. Otherwise, the bits from RXVAL that
+ * are selected by MASK are output.
+ * </pre>
+ */
+ bool common_write_atr_mask(txrx_t txrx, int which_side, int value);
+ bool common_write_atr_txval(txrx_t txrx, int which_side, int value);
+ bool common_write_atr_rxval(txrx_t txrx, int which_side, int value);
+
+ /*!
+ * \brief Write auxiliary digital to analog converter.
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
+ * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
+ * \param which_dac [2,3] TX slots must use only 2 and 3.
+ * \param value [0,4095]
+ * \returns true iff successful
+ */
+ bool common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * \param which_adc [0,1]
+ * \param value return 12-bit value [0,4095]
+ * \returns true iff successful
+ */
+ bool common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value);
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param txrx Tx or Rx?
+ * \param which_side [0,1] which d'board
+ * \param which_adc [0,1]
+ * \returns value in the range [0,4095] if successful, else READ_FAILED.
+ */
+ int common_read_aux_adc(txrx_t txrx, int which_side, int which_adc);
+
+ // END common_ daughterboard control functions\f
+ // ----------------------------------------------------------------
+ // BEGIN virtual daughterboard control functions
+
+ /*!
+ * \brief Set Programmable Gain Amplifier (PGA)
+ *
+ * \param which_amp which amp [0,3]
+ * \param gain_in_db gain value (linear in dB)
+ *
+ * gain is rounded to closest setting supported by hardware.
+ *
+ * \returns true iff sucessful.
+ *
+ * \sa pga_min(), pga_max(), pga_db_per_step()
+ */
+ virtual bool set_pga (int which_amp, double gain_in_db) = 0;
+
+ /*!
+ * \brief Return programmable gain amplifier gain setting in dB.
+ *
+ * \param which_amp which amp [0,3]
+ */
+ virtual double pga (int which_amp) const = 0;
+
+ /*!
+ * \brief Return minimum legal PGA gain in dB.
+ */
+ virtual double pga_min () const = 0;
+
+ /*!
+ * \brief Return maximum legal PGA gain in dB.
+ */
+ virtual double pga_max () const = 0;
+
+ /*!
+ * \brief Return hardware step size of PGA (linear in dB).
+ */
+ virtual double pga_db_per_step () const = 0;
+
+ /*!
+ * \brief Write direction register (output enables) for pins that go to daughterboard.
+ *
+ * \param which_side [0,1] which size
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ *
+ * Each d'board has 16-bits of general purpose i/o.
+ * Setting the bit makes it an output from the FPGA to the d'board.
+ *
+ * This register is initialized based on a value stored in the
+ * d'board EEPROM. In general, you shouldn't be using this routine
+ * without a very good reason. Using this method incorrectly will
+ * kill your USRP motherboard and/or daughterboard.
+ */
+ virtual bool _write_oe (int which_side, int value, int mask) = 0;
+
+ /*!
+ * \brief Write daughterboard i/o pin value
+ *
+ * \param which_side [0,1] which d'board
+ * \param value value to write into register
+ * \param mask which bits of value to write into reg
+ */
+ virtual bool write_io (int which_side, int value, int mask) = 0;
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param which_side [0,1] which d'board
+ * \param value output
+ */
+ virtual bool read_io (int which_side, int *value) = 0;
+
+ /*!
+ * \brief Read daughterboard i/o pin value
+ *
+ * \param which_side [0,1] which d'board
+ * \returns register value if successful, else READ_FAILED
+ */
+ virtual int read_io (int which_side) = 0;
+
+ /*!
+ * \brief Write daughterboard refclk config register
+ *
+ * \param which_side [0,1] which d'board
+ * \param value value to write into register, see below
+ *
+ * <pre>
+ * Control whether a reference clock is sent to the daughterboards,
+ * and what frequency. The refclk is sent on d'board i/o pin 0.
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------------------------------+-+------------+
+ * | Reserved (Must be zero) |E| DIVISOR |
+ * +-----------------------------------------------+-+------------+
+ *
+ * Bit 7 -- 1 turns on refclk, 0 allows IO use
+ * Bits 6:0 Divider value
+ * </pre>
+ */
+ virtual bool write_refclk(int which_side, int value) = 0;
+
+ virtual bool write_atr_mask(int which_side, int value) = 0;
+ virtual bool write_atr_txval(int which_side, int value) = 0;
+ virtual bool write_atr_rxval(int which_side, int value) = 0;
+
+ /*!
+ * \brief Write auxiliary digital to analog converter.
+ *
+ * \param which_side [0,1] which d'board
+ * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
+ * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
+ * \param which_dac [2,3] TX slots must use only 2 and 3.
+ * \param value [0,4095]
+ * \returns true iff successful
+ */
+ virtual bool write_aux_dac (int which_side, int which_dac, int value) = 0;
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param which_side [0,1] which d'board
+ * \param which_adc [0,1]
+ * \param value return 12-bit value [0,4095]
+ * \returns true iff successful
+ */
+ virtual bool read_aux_adc (int which_side, int which_adc, int *value) = 0;
+
+ /*!
+ * \brief Read auxiliary analog to digital converter.
+ *
+ * \param which_side [0,1] which d'board
+ * \param which_adc [0,1]
+ * \returns value in the range [0,4095] if successful, else READ_FAILED.
+ */
+ virtual int read_aux_adc (int which_side, int which_adc) = 0;
+
+ /*!
+ * \brief returns current fusb block size
+ */
+ virtual int block_size() const = 0;
+
+ /*!
+ * \brief returns A/D or D/A converter rate in Hz
+ */
+ virtual long converter_rate() const = 0;
+
+ // END virtual daughterboard control functions\f
+
+ // ----------------------------------------------------------------
+ // Low level implementation routines.
+ // You probably shouldn't be using these...
+ //
+
+ bool _set_led (int which_led, 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 ();
+};
+
+\f/*!
+ * \brief class for accessing the receive side of the USRP
+ * \ingroup 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:
+ /*!
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ * \param fpga_filename name of the rbf file to load
+ * \param firmware_filename name of ihx file to load
+ */
+ 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);
+
+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.
+ * \param fpga_filename name of file that contains image to load into FPGA
+ * \param firmware_filename name of file that contains image to load into FX2
+ */
+ static usrp_basic_rx *make (int which_board,
+ int fusb_block_size=0,
+ int fusb_nblocks=0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+
+ /*!
+ * \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);
+
+
+ //! sampling rate of A/D converter
+ virtual long converter_rate() const { return fpga_master_clock_freq(); } // 64M
+ long adc_rate() const { return converter_rate(); }
+ int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; }
+
+ bool set_pga (int which_amp, double gain_in_db);
+ double pga (int which_amp) const;
+ double pga_min () const;
+ double pga_max () const;
+ double pga_db_per_step () const;
+
+ bool _write_oe (int which_side, int value, int mask);
+ bool write_io (int which_side, int value, int mask);
+ bool read_io (int which_side, int *value);
+ int read_io (int which_side);
+ bool write_refclk(int which_side, int value);
+ bool write_atr_mask(int which_side, int value);
+ bool write_atr_txval(int which_side, int value);
+ bool write_atr_rxval(int which_side, int value);
+
+ bool write_aux_dac (int which_side, int which_dac, int value);
+ bool read_aux_adc (int which_side, int which_adc, int *value);
+ int read_aux_adc (int which_side, int which_adc);
+
+ int block_size() const;
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+\f/*!
+ * \brief class for accessing the transmit side of the USRP
+ * \ingroup 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:
+ /*!
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ * \param fpga_filename name of file that contains image to load into FPGA
+ * \param firmware_filename name of file that contains image to load into FX2
+ */
+ usrp_basic_tx (int which_board,
+ int fusb_block_size=0,
+ 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);
+
+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.
+ * \param fpga_filename name of file that contains image to load into FPGA
+ * \param firmware_filename name of file that contains image to load into FX2
+ */
+ static usrp_basic_tx *make (int which_board, int fusb_block_size=0, int fusb_nblocks=0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+
+ /*!
+ * \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 ();
+
+ //! 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(); }
+ int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; }
+
+ bool set_pga (int which_amp, double gain_in_db);
+ double pga (int which_amp) const;
+ double pga_min () const;
+ double pga_max () const;
+ double pga_db_per_step () const;
+
+ bool _write_oe (int which_side, int value, int mask);
+ bool write_io (int which_side, int value, int mask);
+ bool read_io (int which_side, int *value);
+ int read_io (int which_side);
+ bool write_refclk(int which_side, int value);
+ bool write_atr_mask(int which_side, int value);
+ bool write_atr_txval(int which_side, int value);
+ bool write_atr_rxval(int which_side, int value);
+
+ bool write_aux_dac (int which_side, int which_dac, int value);
+ bool read_aux_adc (int which_side, int which_adc, int *value);
+ int read_aux_adc (int which_side, int which_adc);
+
+ int block_size() const;
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#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
+
+#warning Using non-portable code (likely wrong other than ILP32).
+
+static inline unsigned short int
+bswap_16 (unsigned short int x)
+{
+ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+
+static inline unsigned int
+bswap_32 (unsigned int x)
+{
+ return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
+ | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
+}
+#endif
+
+
+#ifdef WORDS_BIGENDIAN
+
+static inline unsigned int
+host_to_usrp_u32 (unsigned int x)
+{
+ return bswap_32(x);
+}
+
+static inline unsigned int
+usrp_to_host_u32 (unsigned int x)
+{
+ return bswap_32(x);
+}
+
+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 unsigned int
+host_to_usrp_u32 (unsigned int x)
+{
+ return x;
+}
+
+static inline unsigned int
+usrp_to_host_u32 (unsigned int x)
+{
+ return x;
+}
+
+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 */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#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 */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,2006,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * 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/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_ */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#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 */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_USRP_STANDARD_H
+#define INCLUDED_USRP_STANDARD_H
+
+#include <usrp/usrp_basic.h>
+#include <boost/shared_ptr.hpp>
+#include <usrp/usrp_tune_result.h>
+
+class usrp_standard_tx;
+class usrp_standard_rx;
+
+typedef boost::shared_ptr<usrp_standard_tx> usrp_standard_tx_sptr;
+typedef boost::shared_ptr<usrp_standard_rx> usrp_standard_rx_sptr;
+
+/*!
+ * \ingroup usrp
+ */
+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 Calculate the frequency to use for setting the digital up or down converter.
+ *
+ * \param target_freq is the desired RF frequency (Hz).
+ * \param baseband_freq is the RF frequency that corresponds to DC in the IF coming from the d'board.
+ * \param fs is the sampling frequency.
+ * \param[out] dxc_freq the frequency to program into the DDC (or DUC).
+ * \param[out] inverted is true if we're operating in an inverted Nyquist zone.
+ */
+ static void calc_dxc_freq(double target_freq, double baseband_freq, double fs,
+ double *dxc_freq, bool *inverted);
+};
+
+/*!
+ * \brief The C++ interface the receive side of the USRP
+ * \ingroup usrp
+ *
+ * This is the recommended interface to USRP receive functionality
+ * for applications that use the USRP but not GNU Radio.
+ */
+class usrp_standard_rx : public usrp_basic_rx, public 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 shared_ptr or shared_ptr equivalent of 0 if trouble
+ *
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param decim_rate decimation factor
+ * \param nchan number of channels
+ * \param mux Rx mux setting, \sa set_mux
+ * \param mode mode
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ * \param fpga_filename Name of rbf file to load
+ * \param firmware_filename Name of ihx file to load
+ */
+ static usrp_standard_rx_sptr make(int which_board,
+ unsigned int decim_rate,
+ int nchan = 1,
+ int mux = -1,
+ int mode = 0,
+ int fusb_block_size = 0,
+ int fusb_nblocks = 0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+ /*!
+ * \brief Set decimator rate. \p rate MUST BE EVEN and in [8, 256].
+ *
+ * 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);
+
+ /*!
+ * Determine the appropriate Rx mux value as a function of the subdevice choosen
+ * and the characteristics of the respective daughterboard.
+ */
+ int determine_rx_mux_value(const usrp_subdev_spec &ss);
+ int determine_rx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b);
+
+ /*!
+ * \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);
+
+ /*!
+ * \brief High-level "tune" method. Works for the single channel case.
+ *
+ * This method adjusts both the daughterboard LO and the DDC so that
+ * target_freq ends up at DC in the complex baseband samples.
+ *
+ * \param chan which DDC channel we're controlling (almost always 0).
+ * \param db the daughterboard we're controlling.
+ * \param target_freq the RF frequency we want at DC in the complex baseband.
+ * \param[out] result details how the hardware was configured.
+ *
+ * \returns true iff everything was successful.
+ */
+ bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result);
+
+
+ // ACCESSORS
+ unsigned int decim_rate () const;
+ double rx_freq (int channel) const;
+ int nchannels () const;
+ int mux () const;
+ unsigned int format () const;
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+// ----------------------------------------------------------------
+
+/*!
+ * \brief The C++ interface the transmit side of the USRP
+ * \ingroup usrp
+ *
+ * This is the recommended interface to USRP transmit functionality
+ * for applications that use the USRP but not GNU Radio.
+ *
+ * Uses digital upconverter (coarse & fine modulators) in AD9862...
+ */
+class usrp_standard_tx : public usrp_basic_tx, public 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 shared_ptr or shared_ptr equivalent of 0 if trouble
+ *
+ * \param which_board Which USRP board on usb (not particularly useful; use 0)
+ * \param interp_rate interpolation factor
+ * \param nchan number of channels
+ * \param mux Tx mux setting, \sa set_mux
+ * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
+ * Use zero for a reasonable default.
+ * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
+ * \param fpga_filename Name of rbf file to load
+ * \param firmware_filename Name of ihx file to load
+ */
+ static usrp_standard_tx_sptr make(int which_board,
+ unsigned int interp_rate,
+ int nchan = 1,
+ int mux = -1,
+ int fusb_block_size = 0,
+ int fusb_nblocks = 0,
+ const std::string fpga_filename = "",
+ const std::string firmware_filename = ""
+ );
+
+ /*!
+ * \brief Set interpolator rate. \p rate must be in [4, 512] and a multiple of 4.
+ *
+ * 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);
+
+ /*!
+ * Determine the appropriate Tx mux value as a function of the subdevice choosen
+ * and the characteristics of the respective daughterboard.
+ */
+ int determine_tx_mux_value(const usrp_subdev_spec &ss);
+ int determine_tx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b);
+
+ /*!
+ * \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;
+
+ /*!
+ * \brief High-level "tune" method. Works for the single channel case.
+ *
+ * This method adjusts both the daughterboard LO and the DUC so that
+ * DC in the complex baseband samples ends up at RF target_freq.
+ *
+ * \param chan which DUC channel we're controlling (usually == which_side).
+ * \param db the daughterboard we're controlling.
+ * \param target_freq the RF frequency we want our baseband translated to.
+ * \param[out] result details how the hardware was configured.
+ *
+ * \returns true iff everything was successful.
+ */
+ bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result);
+
+
+ // called in base class to derived class order
+ bool start ();
+ bool stop ();
+};
+
+#endif /* INCLUDED_USRP_STANDARD_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_USRP_SUBDEV_SPEC_H
+#define INCLUDED_USRP_SUBDEV_SPEC_H
+
+/*!
+ * \brief specify a daughterboard and subdevice on a daughterboard.
+ *
+ * In the USRP1, there are two sides, A and B.
+ *
+ * A daughterboard generally implements a single subdevice, but may in
+ * general implement any number of subdevices. At this time, all daughterboards
+ * with the exception of the Basic Rx and LF Rx implement a single subdevice.
+ *
+ * The Basic Rx and LF Rx implement 2 subdevices (soon 3). Subdevice
+ * 0 routes input RX-A to the DDC I input and routes a constant zero
+ * to the DDC Q input. Similarly, subdevice 1 routes input RX-B to
+ * the DDC I input and routes a constant zero to the DDC Q
+ * input. Subdevice 2 (when implemented) will route RX-A to the DDC I
+ * input and RX-B to the DDC Q input.
+ */
+
+struct usrp_subdev_spec {
+ unsigned int side; // 0 -> A; 1 -> B
+ unsigned int subdev; // which subdevice (usually zero)
+
+ usrp_subdev_spec(unsigned int _side = 0, unsigned int _subdev = 0)
+ : side(_side), subdev(_subdev) {}
+};
+
+#endif /* INCLUDED_USRP_SUBDEV_SPEC_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_TUNE_RESULT_H
+#define INCLUDED_USRP_TUNE_RESULT_H
+
+class usrp_tune_result
+{
+public:
+ // RF frequency that corresponds to DC in the IF
+ double baseband_freq;
+
+ // frequency programmed into the DDC/DUC
+ double dxc_freq;
+
+ // residual frequency (typically < 0.01 Hz)
+ double residual_freq;
+
+ // is the spectrum inverted?
+ bool inverted;
+
+ usrp_tune_result(double baseband=0, double dxc=0, double residual=0, bool _inverted=false)
+ : baseband_freq(baseband), dxc_freq(dxc),
+ residual_freq(residual), inverted(_inverted) {}
+};
+
+#endif /* INCLUDED_USRP_TUNE_RESULT_H */
#
# USRP - Universal Software Radio Peripheral
#
-# Copyright (C) 2003,2004,2006,2007 Free Software Foundation, Inc.
+# Copyright (C) 2003,2004,2006,2007,2008,2009 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
include $(top_srcdir)/Makefile.common
-SUBDIRS = legacy inband
+common_INCLUDES = $(USRP_INCLUDES)
+lib_LTLIBRARIES = libusrp.la
+
+libusrp_la_common_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 $(BOOST_LDFLAGS)
+
+libusrp_la_common_LIBADD = \
+ $(USB_LIBS) \
+ $(BOOST_THREAD_LIB) \
+ ../misc/libmisc.la
+
+# darwin fusb requires omnithreads
+if FUSB_TECH_darwin
+AM_CPPFLAGS = $(common_INCLUDES) $(OMNITHREAD_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
+libusrp_la_LIBADD = $(libusrp_la_common_LIBADD) $(OMNITHREAD_LA)
+libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS) -framework CoreFoundation
+else
+AM_CPPFLAGS = $(common_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
+libusrp_la_LIBADD = $(libusrp_la_common_LIBADD)
+libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS)
+endif
+
+EXTRA_DIST = \
+ std_paths.h.in \
+ usrp_dbid.dat
+
+BUILT_SOURCES = \
+ $(abs_top_builddir)/usrp/host/include/usrp/usrp_dbid.h
+
+BUILT_SOURCES += 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
+
+ra_wb_CODE = \
+ fusb_ra_wb.cc \
+ fusb_sysconfig_ra_wb.cc
+
+
+#
+# include each <foo>_CODE entry here...
+#
+EXTRA_libusrp_la_SOURCES = \
+ $(generic_CODE) \
+ $(darwin_CODE) \
+ $(win32_CODE) \
+ $(linux_CODE) \
+ $(ra_wb_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 \
+ db_boards.cc \
+ db_base.cc \
+ db_basic.cc \
+ db_tv_rx.cc \
+ db_flexrf.cc \
+ db_flexrf_mimo.cc \
+ db_dbs_rx.cc \
+ db_xcvr2450.cc \
+ db_dtt754.cc \
+ db_dtt768.cc \
+ db_util.cc
+
+
+
+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
+
+if FUSB_TECH_ra_wb
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE)
+endif
+
+noinst_HEADERS = \
+ ad9862.h \
+ db_base_impl.h \
+ db_boards.h \
+ db_util.h \
+ fusb.h \
+ fusb_darwin.h \
+ fusb_generic.h \
+ fusb_linux.h \
+ fusb_ra_wb.h \
+ fusb_win32.h \
+ md5.h \
+ rate_to_regval.h \
+ usrp_config.h
+
+if PYTHON
+usrppython_PYTHON = \
+ usrp_dbid.py
+
+noinst_PYTHON = \
+ gen_usrp_dbid.py \
+ check_data.py \
+ dump_data.py
+endif
+
+# common way for generating sources from templates when using
+# BUILT_SOURCES, using parallel build protection.
+gen_sources = $(BUILT_SOURCES)
+gen_sources_deps = gen_usrp_dbid.py usrp_dbid.dat
+par_gen_command = PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat
+include $(top_srcdir)/Makefile.par.gen
--- /dev/null
+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 function 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
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#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 */
--- /dev/null
+#!/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 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+import sys
+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
+
+
+
+
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CIRCULAR_BUFFER_H_
+#define _CIRCULAR_BUFFER_H_
+
+#include "mld_threads.h"
+#include <stdexcept>
+
+#ifndef DO_DEBUG
+#define DO_DEBUG 0
+#endif
+
+#if DO_DEBUG
+#define DEBUG(X) do{X} while(0);
+#else
+#define DEBUG(X) do{} while(0);
+#endif
+
+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 ();
+ 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")););
+ };
+
+ ~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 ();
+ // create a mutex to handle contention of shared resources;
+ // any routine needed access to shared resources uses lock()
+ // before doing anything, then unlock() when finished.
+ d_internal = new mld_mutex ();
+ // link the internal mutex to the read and write conditions;
+ // when wait() is called, the internal mutex will automatically
+ // be unlock()'ed. Upon return (from a signal() to the condition),
+ // the internal mutex will be lock()'ed.
+ d_readBlock = new mld_condition (d_internal);
+ d_writeBlock = new mld_condition (d_internal);
+ };
+
+/*
+ * 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) {
+ DEBUG (fprintf (stderr, "enqueue: buf = %X, bufLen = %ld, #av_wr = %ld, "
+ "#av_rd = %ld.\n", (unsigned int)buf, bufLen_I,
+ d_n_avail_write_I, d_n_avail_read_I););
+ 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);
+ }
+ // set the return value to 1: success; change if needed
+ int retval = 1;
+ if (bufLen_I > d_n_avail_write_I) {
+ if (d_doWriteBlock) {
+ while (bufLen_I > d_n_avail_write_I) {
+ DEBUG (fprintf (stderr, "enqueue: #len > #a, waiting.\n"););
+ // wait will automatically unlock() the internal mutex
+ d_writeBlock->wait ();
+ // and lock() it here.
+ if (d_doAbort) {
+ d_internal->unlock ();
+ DEBUG (fprintf (stderr, "enqueue: #len > #a, aborting.\n"););
+ return (2);
+ }
+ DEBUG (fprintf (stderr, "enqueue: #len > #a, done waiting.\n"););
+ }
+ } else {
+ d_n_avail_read_I = d_bufLen_I - bufLen_I;
+ d_n_avail_write_I = bufLen_I;
+ DEBUG (fprintf (stderr, "circular_buffer::enqueue: overflow\n"););
+ retval = -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 (retval);
+ };
+
+/*
+ * 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) {
+ DEBUG (fprintf (stderr, "dequeue: buf = %X, *bufLen = %ld, #av_wr = %ld, "
+ "#av_rd = %ld.\n", (unsigned int)buf, *bufLen_I,
+ d_n_avail_write_I, d_n_avail_read_I););
+ 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) {
+ DEBUG (fprintf (stderr, "dequeue: #a < #len, waiting.\n"););
+ // wait will automatically unlock() the internal mutex
+ d_readBlock->wait ();
+ // and lock() it here.
+ if (d_doAbort) {
+ d_internal->unlock ();
+ DEBUG (fprintf (stderr, "dequeue: #a < #len, aborting.\n"););
+ return (2);
+ }
+ DEBUG (fprintf (stderr, "dequeue: #a < #len, done waiting.\n"););
+ }
+ } else {
+ while (d_n_avail_read_I == 0) {
+ DEBUG (fprintf (stderr, "dequeue: #a == 0, waiting.\n"););
+ // wait will automatically unlock() the internal mutex
+ d_readBlock->wait ();
+ // and lock() it here.
+ if (d_doAbort) {
+ d_internal->unlock ();
+ DEBUG (fprintf (stderr, "dequeue: #a == 0, aborting.\n"););
+ return (2);
+ }
+ DEBUG (fprintf (stderr, "dequeue: #a == 0, done waiting.\n"););
+ }
+ }
+ 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_ */
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CIRCULAR_LINKED_LIST_H_
+#define _CIRCULAR_LINKED_LIST_H_
+
+#include <mld_threads.h>
+#include <stdexcept>
+
+#define __INLINE__ inline
+
+#ifndef DO_DEBUG
+#define DO_DEBUG 0
+#endif
+
+#if DO_DEBUG
+#define DEBUG(X) do{X} while(0);
+#else
+#define DEBUG(X) do{} while(0);
+#endif
+
+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_ioBlock = new mld_condition ();
+ d_internal = d_ioBlock->mutex ();
+ };
+
+ ~circular_linked_list () {
+ iterate_start ();
+ s_node_ptr l_node = iterate_next ();
+ while (l_node) {
+ delete l_node;
+ l_node = iterate_next ();
+ }
+ 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;
+ DEBUG (fprintf (stderr, "w "););
+ while (! l_node) {
+ DEBUG (fprintf (stderr, "x\n"););
+ // the ioBlock condition will automatically unlock() d_internal
+ d_ioBlock->wait ();
+ // and lock() is here
+ DEBUG (fprintf (stderr, "y\n"););
+ l_node = d_available;
+ }
+ DEBUG (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 ();
+ DEBUG (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--;
+
+ DEBUG (fprintf (stderr, "s%ld ", d_n_used););
+// signal the condition when new data arrives
+ d_ioBlock->signal ();
+ DEBUG (fprintf (stderr, "t "););
+
+// 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_ */
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * 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__ */
--- /dev/null
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+//
+
+#include <usrp/db_base.h>
+#include <db_base_impl.h>
+
+#if 0
+tune_result::tune_result(double baseband, double dxc, double residual, bool inv)
+ : ok(false), baseband_freq(baseband), dxc_freq(dxc),
+ residual_freq(residual), inverted(inv)
+{
+}
+
+tune_result::~tune_result()
+{
+}
+#endif
+
+
+/*****************************************************************************/
+
+db_base::db_base(usrp_basic_sptr usrp, int which)
+ : d_is_shutdown(false), d_raw_usrp(usrp.get()), d_which(which), d_lo_offset(0.0)
+{
+}
+
+db_base::~db_base()
+{
+ shutdown();
+}
+
+void
+db_base::shutdown()
+{
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ // do whatever there is to do to shutdown
+ }
+}
+
+int
+db_base::dbid()
+{
+ return usrp()->daughterboard_id(d_which);
+}
+
+std::string
+db_base::name()
+{
+ return usrp_dbid_to_string(dbid());
+}
+
+std::string
+db_base::side_and_name()
+{
+ if(d_which == 0)
+ return "A: " + name();
+ else
+ return "B: " + name();
+}
+
+// Function to bypass ADC buffers. Any board which is DC-coupled
+// should bypass the buffers
+
+bool
+db_base::bypass_adc_buffers(bool bypass)
+{
+ //if(d_tx) {
+ // throw std::runtime_error("TX Board has no adc buffers\n");
+ //}
+
+ bool ok = true;
+ if(d_which==0) {
+ ok &= usrp()->set_adc_buffer_bypass(0, bypass);
+ ok &= usrp()->set_adc_buffer_bypass(1, bypass);
+ }
+ else {
+ ok &= usrp()->set_adc_buffer_bypass(2, bypass);
+ ok &= usrp()->set_adc_buffer_bypass(3, bypass);
+ }
+ return ok;
+}
+
+bool
+db_base::set_atr_mask(int v)
+{
+ // Set Auto T/R mask.
+ return usrp()->write_atr_mask(d_which, v);
+}
+
+bool
+db_base::set_atr_txval(int v)
+{
+ // Set Auto T/R register value to be used when transmitting.
+ return usrp()->write_atr_txval(d_which, v);
+}
+
+bool
+db_base::set_atr_rxval(int v)
+{
+ // Set Auto T/R register value to be used when receiving.
+ return usrp()->write_atr_rxval(d_which, v);
+}
+
+bool
+db_base::set_atr_tx_delay(int v)
+{
+ // Set Auto T/R delay (in clock ticks) from when Tx fifo gets data to
+ // when T/R switches.
+ return usrp()->write_atr_tx_delay(v);
+}
+
+bool
+db_base::set_atr_rx_delay(int v)
+{
+ // Set Auto T/R delay (in clock ticks) from when Tx fifo goes empty to
+ // when T/R switches.
+ return usrp()->write_atr_rx_delay(v);
+}
+
+bool
+db_base::i_and_q_swapped()
+{
+ // Return True if this is a quadrature device and (for RX) ADC 0 is Q
+ // or (for TX) DAC 0 is Q
+ return false;
+}
+
+bool
+db_base::spectrum_inverted()
+{
+ // Return True if the dboard gives an inverted spectrum
+
+ return false;
+}
+
+bool
+db_base::set_enable(bool on)
+{
+ // For tx daughterboards, this controls the transmitter enable.
+
+ return true; // default is nop
+}
+
+bool
+db_base::set_auto_tr(bool on)
+{
+ // Enable automatic Transmit/Receive switching (ATR).
+ //
+ // Should be overridden in subclasses that care. This will typically
+ // set the atr_mask, txval and rxval.
+
+ return true;
+}
+
+bool
+db_base::set_lo_offset(double offset)
+{
+ // Set how much LO is offset from requested frequency
+
+ d_lo_offset = offset;
+ return true;
+}
+
+bool
+db_base::select_rx_antenna(int which_antenna)
+{
+ // Specify which antenna port to use for reception.
+ // Should be overriden by daughterboards that care.
+
+ return which_antenna == 0;
+}
+
+bool
+db_base::select_rx_antenna(const std::string &which_antenna)
+{
+ // Specify which antenna port to use for reception.
+ // Should be overriden by daughterboards that care.
+
+ return which_antenna == "";
+}
+
+
+// Reference Clock section
+//
+// Control whether a reference clock is sent to the daughterboards,
+// and what frequency
+//
+// Bit 7 -- 1 turns on refclk, 0 allows IO use
+// Bits 6:0 Divider value
+//
+
+double
+db_base::_refclk_freq()
+{
+ return usrp()->fpga_master_clock_freq() / _refclk_divisor();
+}
+
+void
+db_base::_enable_refclk(bool enable)
+{
+ int CLOCK_OUT = 1; // Clock is on lowest bit
+ int REFCLK_ENABLE = 0x80;
+ int REFCLK_DIVISOR_MASK = 0x7f;
+
+ if(enable) {
+ usrp()->_write_oe(d_which, CLOCK_OUT, CLOCK_OUT); // output enable
+ usrp()->write_refclk(d_which, (_refclk_divisor() & REFCLK_DIVISOR_MASK) | REFCLK_ENABLE);
+ }
+ else {
+ usrp()->write_refclk(d_which, 0);
+ }
+}
+
+int
+db_base::_refclk_divisor()
+{
+ // Return value to stick in REFCLK_DIVISOR register
+ throw std::runtime_error("_reflck_divisor() called from base class\n");;
+}
+
+bool
+db_base::set_bw(float bw)
+{
+ // Set baseband bandwidth (board specific)
+ // Should be overriden by boards that implement variable IF filtering (e.g., DBSRX)
+ return false;
+}
+
+std::ostream &operator<<(std::ostream &os, db_base &x)
+{
+ os << x.side_and_name();
+ return os;
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_DB_BASE_IMPL_H
+#define INCLUDED_DB_BASE_IMPL_H
+
+#include <usrp/db_base.h>
+#include <db_util.h>
+#include <usrp/usrp_basic.h>
+#include <fpga_regs_standard.h>
+#include <fpga_regs_common.h>
+#include <usrp/usrp_prims.h>
+#include <usrp_spi_defs.h>
+#include <stdexcept>
+
+#endif /* INCLUDED_DB_BASE_IMPL_H */
--- /dev/null
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_basic.h>
+#include <db_base_impl.h>
+
+db_basic_tx::db_basic_tx(boost::shared_ptr<usrp_basic> usrp, int which)
+ : db_base(usrp, which)
+{
+ // Handler for Basic Tx daughterboards.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively
+
+ set_gain((gain_min() + gain_max()) / 2); // initialize gain
+}
+
+db_basic_tx::~db_basic_tx()
+{
+}
+
+double
+db_basic_tx::freq_min()
+{
+ return -90e9;
+}
+
+double
+db_basic_tx::freq_max()
+{
+ return 90e9;
+}
+
+struct freq_result_t
+db_basic_tx::set_freq(double target_freq)
+{
+ // Set the frequency.
+ //
+ // @param freq: target RF frequency in Hz
+ // @type freq: double
+ //
+ // @returns (ok, actual_baseband_freq) where:
+ // ok is True or False and indicates success or failure,
+ // actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+
+ struct freq_result_t args = {false, 0};
+ args.ok = true;
+ args.baseband_freq = 0.0;
+ return args;
+}
+
+float
+db_basic_tx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_basic_tx::gain_max()
+{
+ return usrp()->pga_max();
+}
+
+float
+db_basic_tx::gain_db_per_step()
+{
+ return usrp()->pga_db_per_step();
+}
+
+bool
+db_basic_tx::set_gain(float gain)
+{
+ // Set the gain.
+ //
+ // @param gain: gain in decibels
+ // @returns True/False
+
+ bool ok = usrp()->set_pga(d_which * 2 + 0, gain);
+ ok = ok && usrp()->set_pga(d_which * 2 + 1, gain);
+ return ok;
+}
+
+bool
+db_basic_tx::is_quadrature()
+{
+ // Return True if this board requires both I & Q analog channels.
+
+ return true;
+}
+
+
+/******************************************************************************/
+
+
+db_basic_rx::db_basic_rx(usrp_basic_sptr usrp, int which, int subdev)
+ : db_base(usrp, which)
+{
+ // Handler for Basic Rx daughterboards.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively
+ // @param subdev: which analog i/o channel: 0 or 1
+ // @type subdev: int
+
+ d_subdev = subdev;
+
+ bypass_adc_buffers(true);
+
+ if(0) { // Doing this would give us a different default than the historical values...
+ set_gain(float(gain_min() + gain_max()) / 2.0); // initialize gain
+ }
+}
+
+db_basic_rx::~db_basic_rx()
+{
+}
+
+double
+db_basic_rx::freq_min()
+{
+ return -90e9;
+}
+
+double
+db_basic_rx::freq_max()
+{
+ return 90e9;
+}
+
+struct freq_result_t
+db_basic_rx::set_freq(double target_freq)
+{
+ // Set the frequency.
+ //
+ // @param freq: target RF frequency in Hz
+ // @type freq: double
+ //
+ // @returns (ok, actual_baseband_freq) where:
+ // ok is True or False and indicates success or failure,
+ // actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+
+ struct freq_result_t args = {true, 0.0};
+ return args;
+}
+
+float
+db_basic_rx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_basic_rx::gain_max()
+{
+ return usrp()->pga_max();
+}
+
+float
+db_basic_rx::gain_db_per_step()
+{
+ return usrp()->pga_db_per_step();
+}
+
+bool
+db_basic_rx::set_gain(float gain)
+{
+ // Set the gain.
+ //
+ // @param gain: gain in decibels
+ // @returns True/False
+
+ return usrp()->set_pga(d_which * 2 + d_subdev, gain);
+}
+
+bool
+db_basic_rx::is_quadrature()
+{
+ // Return True if this board requires both I & Q analog channels.
+
+ // This bit of info is useful when setting up the USRP Rx mux register.
+
+ return (d_subdev == 2);
+}
+
+
+
+/******************************************************************************/
+
+
+db_lf_tx::db_lf_tx(usrp_basic_sptr usrp, int which)
+ : db_basic_tx(usrp, which)
+{
+ // Handler for Low Freq Tx daughterboards.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
+}
+
+db_lf_tx::~db_lf_tx()
+{
+}
+
+double
+db_lf_tx::freq_min()
+{
+ return -32e6;
+}
+
+double
+db_lf_tx::freq_max()
+{
+ return 32e6;
+}
+
+/******************************************************************************/
+
+
+db_lf_rx::db_lf_rx(usrp_basic_sptr usrp, int which, int subdev)
+ : db_basic_rx(usrp, which, subdev)
+{
+ // Handler for Low Freq Rx daughterboards.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
+ // @param subdev: which analog i/o channel: 0 or 1
+ // @type subdev: int
+}
+
+db_lf_rx::~db_lf_rx()
+{
+}
+
+double
+db_lf_rx::freq_min()
+{
+ return 0.0;
+}
+
+double
+db_lf_rx::freq_max()
+{
+ return 32e6;
+}
+
+
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+//
+
+#include <db_boards.h>
+#include <usrp/usrp_dbid.h>
+#include <usrp/db_basic.h>
+#include <usrp/db_tv_rx.h>
+#include <usrp/db_dbs_rx.h>
+#include <usrp/db_flexrf.h>
+#include <usrp/db_flexrf_mimo.h>
+#include <usrp/db_xcvr2450.h>
+#include <usrp/db_dtt754.h>
+#include <usrp/db_dtt768.h>
+#include <cstdio>
+
+std::vector<db_base_sptr>
+instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side)
+{
+ std::vector<db_base_sptr> db;
+
+ switch(dbid) {
+
+ case(USRP_DBID_BASIC_TX):
+ db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side)));
+ break;
+
+ case(USRP_DBID_BASIC_RX):
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0)));
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1)));
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 2)));
+ break;
+
+ case(USRP_DBID_LF_TX):
+ db.push_back(db_base_sptr(new db_lf_tx(usrp, which_side)));
+ break;
+
+ case(USRP_DBID_LF_RX):
+ db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 0)));
+ db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 1)));
+ db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 2)));
+ break;
+
+ case(USRP_DBID_DBS_RX):
+ db.push_back(db_base_sptr(new db_dbs_rx(usrp, which_side)));
+ break;
+
+ case(USRP_DBID_TV_RX):
+ db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 43.75e6, 5.75e6)));
+ break;
+ case(USRP_DBID_TV_RX_REV_2):
+ db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 44e6, 20e6)));
+ break;
+ case(USRP_DBID_TV_RX_REV_3):
+ db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 44e6, 20e6)));
+ break;
+
+ case(USRP_DBID_FLEX_2400_TX):
+ db.push_back(db_base_sptr(new db_flexrf_2400_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_2400_RX):
+ db.push_back(db_base_sptr(new db_flexrf_2400_rx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1200_TX):
+ db.push_back(db_base_sptr(new db_flexrf_1200_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1200_RX):
+ db.push_back(db_base_sptr(new db_flexrf_1200_rx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1800_TX):
+ db.push_back(db_base_sptr(new db_flexrf_1800_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1800_RX):
+ db.push_back(db_base_sptr(new db_flexrf_1800_rx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_900_TX):
+ db.push_back(db_base_sptr(new db_flexrf_900_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_900_RX):
+ db.push_back(db_base_sptr(new db_flexrf_900_rx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_400_TX):
+ db.push_back(db_base_sptr(new db_flexrf_400_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_400_RX):
+ db.push_back(db_base_sptr(new db_flexrf_400_rx(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_2400_TX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_2400_tx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_2400_RX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_2400_rx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1800_TX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_1800_tx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1800_RX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_1800_rx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1200_TX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_1200_tx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1200_RX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_1200_rx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_900_TX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_900_tx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_900_RX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_900_rx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_400_TX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_400_tx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_400_RX_MIMO_A):
+ db.push_back(db_base_sptr(new db_flexrf_400_rx_mimo_a(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_2400_TX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_2400_tx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_2400_RX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_2400_rx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1800_TX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_1800_tx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1800_RX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_1800_rx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1200_TX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_1200_tx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_1200_RX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_1200_rx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_900_TX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_900_tx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_900_RX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_900_rx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_400_TX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_400_tx_mimo_b(usrp, which_side)));
+ break;
+ case(USRP_DBID_FLEX_400_RX_MIMO_B):
+ db.push_back(db_base_sptr(new db_flexrf_400_rx_mimo_b(usrp, which_side)));
+ break;
+
+ case(USRP_DBID_XCVR2450_TX):
+ db.push_back(db_base_sptr(new db_xcvr2450_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_XCVR2450_RX):
+ db.push_back(db_base_sptr(new db_xcvr2450_rx(usrp, which_side)));
+ break;
+
+#if 0 // FIXME wbx doesn't compile
+ case(USRP_DBID_WBX_LO_TX):
+ db.push_back(db_base_sptr(new db_wbx_lo_tx(usrp, which_side)));
+ break;
+ case(USRP_DBID_WBX_LO_RX):
+ db.push_back(db_base_sptr(new db_wbx_lo_rx(usrp, which_side)));
+ break;
+#endif
+
+ case(USRP_DBID_DTT754):
+ db.push_back(db_base_sptr(new db_dtt754(usrp, which_side)));
+ break;
+ case(USRP_DBID_DTT768):
+ db.push_back(db_base_sptr(new db_dtt768(usrp, which_side)));
+ break;
+
+ case(-1):
+ if (boost::dynamic_pointer_cast<usrp_basic_tx>(usrp)){
+ db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side)));
+ }
+ else {
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0)));
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1)));
+ }
+ break;
+
+ case(-2):
+ default:
+ if (boost::dynamic_pointer_cast<usrp_basic_tx>(usrp)){
+ fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Tx.\"\n");
+ fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n");
+ db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side)));
+ }
+ else {
+ fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Rx.\"\n");
+ fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n");
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0)));
+ db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1)));
+ }
+ break;
+ }
+
+ return db;
+}
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+//
+
+#ifndef DB_BOARDS_H
+#define DB_BOARDS_H
+
+#include <usrp/db_base.h>
+#include <usrp/usrp_basic.h>
+
+std::vector<db_base_sptr> instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side);
+
+#endif
+
+
--- /dev/null
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_dbs_rx.h>
+#include <db_base_impl.h>
+#include <cmath>
+#include <cstdio>
+
+
+/*****************************************************************************/
+
+
+db_dbs_rx::db_dbs_rx(usrp_basic_sptr _usrp, int which)
+ : db_base(_usrp, which)
+{
+ // Control DBS receiver based USRP daughterboard.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
+
+ usrp()->_write_oe(d_which, 0x0001, 0x0001);
+ if(which == 0) {
+ d_i2c_addr = 0x67;
+ }
+ else {
+ d_i2c_addr = 0x65;
+ }
+
+ d_n = 950;
+ d_div2 = 0;
+ d_osc = 5;
+ d_cp = 3;
+ d_r = 4;
+ d_r_int = 1;
+ d_fdac = 127;
+ d_m = 2;
+ d_dl = 0;
+ d_ade = 0;
+ d_adl = 0;
+ d_gc1 = 0;
+ d_gc2 = 31;
+ d_diag = 0;
+
+ _enable_refclk(true);
+
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+
+ bypass_adc_buffers(true);
+}
+
+db_dbs_rx::~db_dbs_rx()
+{
+ shutdown();
+}
+
+void
+db_dbs_rx::shutdown()
+{
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ // do whatever there is to do to shutdown orderly
+ _enable_refclk(false);
+ }
+}
+
+void
+db_dbs_rx::_write_reg (int regno, int v)
+{
+ //regno is in [0,5], v is value to write to register"""
+ assert (0 <= regno && regno <= 5);
+ std::vector<int> args(2);
+ args[0] = regno;
+ args[1] = v;
+ usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
+}
+
+void
+db_dbs_rx::_write_regs (int starting_regno, const std::vector<int> &vals)
+{
+ // starting_regno is in [0,5],
+ // vals is a seq of integers to write to consecutive registers"""
+
+ //FIXME
+ std::vector<int> args;
+ args.push_back(starting_regno);
+ args.insert(args.end(), vals.begin(), vals.end());
+ usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
+}
+
+std::vector<int>
+db_dbs_rx::_read_status ()
+{
+ //If successful, return list of two ints: [status_info, filter_DAC]"""
+ std::string s = usrp()->read_i2c (d_i2c_addr, 2);
+ if(s.size() != 2) {
+ std::vector<int> ret(0);
+ return ret;
+ }
+ return str_to_int_seq (s);
+}
+
+void
+db_dbs_rx::_send_reg(int regno)
+{
+ assert(0 <= regno && regno <= 5);
+ if(regno == 0)
+ _write_reg(0,(d_div2<<7) + (d_n>>8));
+ if(regno == 1)
+ _write_reg(1,d_n & 255);
+ if(regno == 2)
+ _write_reg(2,d_osc + (d_cp<<3) + (d_r_int<<5));
+ if(regno == 3)
+ _write_reg(3,d_fdac);
+ if(regno == 4)
+ _write_reg(4,d_m + (d_dl<<5) + (d_ade<<6) + (d_adl<<7));
+ if(regno == 5)
+ _write_reg(5,d_gc2 + (d_diag<<5));
+}
+
+// BW setting
+void
+db_dbs_rx::_set_m(int m)
+{
+ assert(m>0 && m<32);
+ d_m = m;
+ _send_reg(4);
+}
+
+void
+db_dbs_rx::_set_fdac(int fdac)
+{
+ assert(fdac>=0 && fdac<128);
+ d_fdac = fdac;
+ _send_reg(3);
+}
+
+bool
+db_dbs_rx::set_bw (float bw)
+{
+ if (bw < 1e6 || bw > 33e6) {
+ fprintf(stderr, "db_dbs_rx::set_bw: bw (=%f) must be between 1e6 and 33e6 inclusive\n", bw);
+ return false;
+ }
+
+ // struct bw_t ret = {0, 0, 0};
+ int m_max, m_min, m_test, fdac_test;
+ if(bw >= 4e6)
+ m_max = int(std::min(31, (int)floor(_refclk_freq()/1e6)));
+ else if(bw >= 2e6) // Outside of Specs!
+ m_max = int(std::min(31, (int)floor(_refclk_freq()/.5e6)));
+ else // Way outside of Specs!
+ m_max = int(std::min(31, (int)floor(_refclk_freq()/.25e6)));
+
+ m_min = int(ceil(_refclk_freq()/2.5e6));
+ m_test = m_max;
+ while(m_test >= m_min) {
+ fdac_test = static_cast<int>(round(((bw * m_test / _refclk_freq())-4)/.145));
+ if(fdac_test > 127)
+ m_test = m_test - 1;
+ else
+ break;
+ }
+
+ if(m_test>=m_min && fdac_test>=0) {
+ _set_m(m_test);
+ _set_fdac(fdac_test);
+
+ //ret.m = d_m;
+ //ret.fdac = d_fdac;
+ //ret.div = _refclk_freq()/d_m*(4+0.145*d_fdac);
+ }
+ else {
+ fprintf(stderr, "db_dbs_rx::set_bw: failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+// Gain setting
+void
+db_dbs_rx::_set_dl(int dl)
+{
+ assert(dl == 0 || dl == 1);
+ d_dl = dl;
+ _send_reg(4);
+}
+
+void
+db_dbs_rx::_set_gc2(int gc2)
+{
+ assert(gc2<32 && gc2>=0);
+ d_gc2 = gc2;
+ _send_reg(5);
+}
+
+void
+db_dbs_rx::_set_gc1(int gc1)
+{
+ assert(gc1>=0 && gc1<4096);
+ d_gc1 = gc1;
+ usrp()->write_aux_dac(d_which, 0, gc1);
+}
+
+void
+db_dbs_rx::_set_pga(int pga_gain)
+{
+ assert(pga_gain>=0 && pga_gain<=20);
+ if(d_which == 0) {
+ usrp()->set_pga (0, pga_gain);
+ usrp()->set_pga (1, pga_gain);
+ }
+ else {
+ usrp()->set_pga (2, pga_gain);
+ usrp()->set_pga (3, pga_gain);
+ }
+}
+
+float
+db_dbs_rx::gain_min()
+{
+ return 0;
+}
+
+float
+db_dbs_rx::gain_max()
+{
+ return 104;
+}
+
+float
+db_dbs_rx::gain_db_per_step()
+{
+ return 1;
+}
+
+bool
+db_dbs_rx::set_gain(float gain)
+{
+ // Set the gain.
+ //
+ // @param gain: gain in decibels
+ // @returns True/False
+
+ if(!(gain>=0 && gain<105)) {
+ throw std::runtime_error("gain out of range\n");
+ }
+
+ int gc1=0, gc2=0, dl=0, pga=0;
+
+ if(gain < 56) {
+ gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3);
+ gain = 0;
+ }
+ else {
+ gc1 = 0;
+ gain -= 56;
+ }
+
+ if(gain < 24) {
+ gc2 = static_cast<int>(round(31.0 * (1-gain/24.0)));
+ gain = 0;
+ }
+ else {
+ gc2 = 0;
+ gain -=24;
+ }
+
+ if(gain >= 4.58) {
+ dl = 1;
+ gain -= 4.58;
+ }
+
+ pga = gain;
+ _set_gc1(gc1);
+ _set_gc2(gc2);
+ _set_dl(dl);
+ _set_pga(pga);
+
+ return true;
+}
+
+// Frequency setting
+void
+db_dbs_rx::_set_osc(int osc)
+{
+ assert(osc>=0 && osc<8);
+ d_osc = osc;
+ _send_reg(2);
+}
+
+void
+db_dbs_rx::_set_cp(int cp)
+{
+ assert(cp>=0 && cp<4);
+ d_cp = cp;
+ _send_reg(2);
+}
+
+void
+db_dbs_rx::_set_n(int n)
+{
+ assert(n>256 && n<32768);
+ d_n = n;
+ _send_reg(0);
+ _send_reg(1);
+}
+
+void
+db_dbs_rx::_set_div2(int div2)
+{
+ assert(div2 == 0 || div2 == 1);
+ d_div2 = div2;
+ _send_reg(0);
+}
+
+void
+db_dbs_rx::_set_r(int r)
+{
+ assert(r>=0 && r<128);
+ d_r = r;
+ d_r_int = static_cast<int>(round(log10(r)/log10(2)) - 1);
+ _send_reg(2);
+}
+
+// FIXME How do we handle ADE and ADL properly?
+void
+db_dbs_rx::_set_ade(int ade)
+{
+ assert(ade == 0 || ade == 1);
+ d_ade = ade;
+ _send_reg(4);
+}
+
+double
+db_dbs_rx::freq_min()
+{
+ return 500e6;
+}
+
+double
+db_dbs_rx::freq_max()
+{
+ return 2.6e9;
+}
+
+struct freq_result_t
+db_dbs_rx::set_freq(double freq)
+{
+ // Set the frequency.
+ //
+ // @param freq: target RF frequency in Hz
+ // @type freq: double
+ //
+ // @returns (ok, actual_baseband_freq) where:
+ // ok is True or False and indicates success or failure,
+ // actual_baseband_freq is RF frequency that corresponds to DC in the IF.
+
+ freq_result_t args = {false, 0};
+
+ if(!(freq>=freq_min() && freq<=freq_max())) {
+ return args;
+ }
+
+ double vcofreq;
+ if(freq<1150e6) {
+ _set_div2(0);
+ vcofreq = 4 * freq;
+ }
+ else {
+ _set_div2(1);
+ vcofreq = 2 * freq;
+ }
+
+ _set_ade(1);
+ int rmin = std::max(2, (int)(_refclk_freq()/2e6));
+ int rmax = std::min(128, (int)(_refclk_freq()/500e3));
+ int r = 2;
+ int n = 0;
+ int best_r = 2;
+ int best_n = 0;
+ int best_delta = 10e6;
+ int delta;
+
+ while(r <= rmax) {
+ n = static_cast<int>(round(freq/(_refclk_freq()/r)));
+ if(r<rmin || n<256) {
+ r = r * 2;
+ continue;
+ }
+ delta = (int)fabs(n*_refclk_freq()/r - freq);
+ if(delta < 75e3) {
+ best_r = r;
+ best_n = n;
+ break;
+ }
+ if(delta < best_delta*0.9) {
+ best_r = r;
+ best_n = n;
+ best_delta = delta;
+ }
+ r = r * 2;
+ }
+ _set_r(best_r);
+
+ _set_n(static_cast<int>(round(best_n)));
+
+ int vco;
+ if(vcofreq < 2433e6)
+ vco = 0;
+ else if(vcofreq < 2711e6)
+ vco=1;
+ else if(vcofreq < 3025e6)
+ vco=2;
+ else if(vcofreq < 3341e6)
+ vco=3;
+ else if(vcofreq < 3727e6)
+ vco=4;
+ else if(vcofreq < 4143e6)
+ vco=5;
+ else if(vcofreq < 4493e6)
+ vco=6;
+ else
+ vco=7;
+
+ _set_osc(vco);
+
+ // Set CP current
+ int adc_val = 0;
+ std::vector<int> bytes(2);
+ while(adc_val == 0 || adc_val == 7) {
+ bytes = _read_status();
+ adc_val = bytes[0] >> 2;
+ if(adc_val == 0) {
+ if(vco <= 0) {
+ return args;
+ }
+ else {
+ vco = vco - 1;
+ }
+ }
+ else if(adc_val == 7) {
+ if(vco >= 7) {
+ return args;
+ }
+ else {
+ vco = vco + 1;
+ }
+ }
+ _set_osc(vco);
+ }
+
+ if(adc_val == 1 || adc_val == 2) {
+ _set_cp(1);
+ }
+ else if(adc_val == 3 || adc_val == 4) {
+ _set_cp(2);
+ }
+ else {
+ _set_cp(3);
+ }
+
+ args.ok = true;
+ args.baseband_freq = d_n * _refclk_freq() / d_r;
+ return args;
+}
+
+int
+db_dbs_rx::_refclk_divisor()
+{
+ //Return value to stick in REFCLK_DIVISOR register
+ return 16;
+}
+
+bool
+db_dbs_rx::is_quadrature()
+{
+ // Return True if this board requires both I & Q analog channels.
+ return true;
+}
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_dtt754.h>
+#include <db_base_impl.h>
+
+int
+control_byte_1()
+{
+ int RS = 0; // 0 = 166.66kHz reference
+ int ATP = 7; // Disable internal AGC
+ return (0x80 | ATP<<3 | RS);
+}
+
+int
+control_byte_2()
+{
+ int STBY = 0; // powered on
+ int XTO = 1; // turn off xtal out, which we don't have
+ int ATC = 0; // not clear exactly, possibly speeds up or slows down AGC, which we are not using
+
+ int c = 0xc2 | ATC<<5 | STBY<<4 | XTO;
+ return c;
+}
+
+int
+bandswitch_byte(float freq, float bw)
+{
+ int P5, CP, BS;
+
+ if(bw>7.5e6) {
+ P5 = 1;
+ }
+ else {
+ P5 = 0;
+ }
+
+ if(freq < 121e6) {
+ CP = 0;
+ BS = 1;
+ }
+ else if(freq < 141e6) {
+ CP = 1;
+ BS = 1;
+ }
+ else if(freq < 166e6) {
+ CP = 2;
+ BS = 1;
+ }
+ else if(freq < 182e6) {
+ CP = 3;
+ BS = 1;
+ }
+ else if(freq < 286e6) {
+ CP = 0;
+ BS = 2;
+ }
+ else if(freq < 386e6) {
+ CP = 1;
+ BS = 2;
+ }
+ else if(freq < 446e6) {
+ CP = 2;
+ BS = 2;
+ }
+ else if(freq < 466e6) {
+ CP = 3;
+ BS = 2;
+ }
+ else if(freq < 506e6) {
+ CP = 0;
+ BS = 8;
+ }
+ else if(freq < 761e6) {
+ CP = 1;
+ BS = 8;
+ }
+ else if(freq < 846e6) {
+ CP = 2;
+ BS = 8;
+ }
+ else { // limit is ~905 MHz
+ CP = 3;
+ BS = 8;
+ }
+ return (CP<<6 | P5 << 4 | BS);
+}
+
+db_dtt754::db_dtt754(usrp_basic_sptr _usrp, int which)
+ : db_base(_usrp, which)
+{
+ /*
+ * Control custom DTT75403-based daughterboard.
+ *
+ * @param usrp: instance of usrp.source_c
+ * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
+ * @type which: int
+ */
+
+ // FIXME: DTT754 and DTT768 can probably inherit from a DTT class
+
+ if(d_which == 0) {
+ d_i2c_addr = 0x60;
+ }
+ else {
+ d_i2c_addr = 0x62;
+ }
+
+ d_bw = 7e6;
+ d_IF = 36e6;
+
+ d_f_ref = 166.6666e3;
+ d_inverted = false;
+
+ set_gain((gain_min() + gain_max()) / 2.0);
+
+ bypass_adc_buffers(false);
+}
+
+db_dtt754::~db_dtt754()
+{
+}
+
+float
+db_dtt754::gain_min()
+{
+ return 0;
+}
+
+float
+db_dtt754::gain_max()
+{
+ return 115;
+}
+
+float
+db_dtt754::gain_db_per_step()
+{
+ return 1;
+}
+
+bool
+db_dtt754::set_gain(float gain)
+{
+ assert(gain>=0 && gain<=115);
+
+ float rfgain, ifgain, pgagain;
+ if(gain > 60) {
+ rfgain = 60;
+ gain = gain - 60;
+ }
+ else {
+ rfgain = gain;
+ gain = 0;
+ }
+
+ if(gain > 35) {
+ ifgain = 35;
+ gain = gain - 35;
+ }
+ else {
+ ifgain = gain;
+ gain = 0;
+ }
+ pgagain = gain;
+
+ _set_rfagc(rfgain);
+ _set_ifagc(ifgain);
+ _set_pga(pgagain);
+
+ return true; // can't fail with the assert in place
+}
+
+double
+db_dtt754::freq_min()
+{
+ return 44e6;
+}
+
+double
+db_dtt754::freq_max()
+{
+ return 900e6;
+}
+
+struct freq_result_t
+db_dtt754::set_freq(double target_freq)
+{
+ /*
+ * @returns (ok, actual_baseband_freq) where:
+ * ok is True or False and indicates success or failure,
+ * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+ */
+
+ freq_result_t ret = {false, 0.0};
+
+ if(target_freq < freq_min() || target_freq > freq_max()) {
+ return ret;
+ }
+
+ double target_lo_freq = target_freq + d_IF; // High side mixing
+
+ int divisor = (int)(0.5+(target_lo_freq / d_f_ref));
+ double actual_lo_freq = d_f_ref*divisor;
+
+ if((divisor & ~0x7fff) != 0) { // must be 15-bits or less
+ return ret;
+ }
+
+ // build i2c command string
+ std::vector<int> buf(5);
+ buf[0] = (divisor >> 8) & 0xff; // DB1
+ buf[1] = divisor & 0xff; // DB2
+ buf[2] = control_byte_1();
+ buf[3] = bandswitch_byte(actual_lo_freq, d_bw);
+ buf[4] = control_byte_2();
+
+ bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
+
+ d_freq = actual_lo_freq - d_IF;
+
+ ret.ok = ok;
+ ret.baseband_freq = actual_lo_freq;
+
+ return ret;
+
+}
+
+bool
+db_dtt754::is_quadrature()
+{
+ /*
+ * Return True if this board requires both I & Q analog channels.
+ *
+ * This bit of info is useful when setting up the USRP Rx mux register.
+ */
+
+ return false;
+}
+
+bool
+db_dtt754::spectrum_inverted()
+{
+ /*
+ * The 43.75 MHz version is inverted
+ */
+
+ return d_inverted;
+}
+
+bool
+db_dtt754::set_bw(float bw)
+{
+ /*
+ * Choose the SAW filter bandwidth, either 7MHz or 8MHz)
+ */
+
+ d_bw = bw;
+ set_freq(d_freq);
+
+ return true; // FIXME: propagate set_freq result
+}
+
+void
+db_dtt754::_set_rfagc(float gain)
+{
+ assert(gain <= 60 && gain >= 0);
+ // FIXME this has a 0.5V step between gain = 60 and gain = 59.
+ // Why are there two cases instead of a single linear case?
+ float voltage;
+ if(gain == 60) {
+ voltage = 4;
+ }
+ else {
+ voltage = gain/60.0 * 2.25 + 1.25;
+ }
+
+ int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
+
+ assert(dacword>=0 && dacword<4096);
+ usrp()->write_aux_dac(d_which, 1, dacword);
+}
+
+void
+db_dtt754::_set_ifagc(float gain)
+{
+ assert(gain <= 35 && gain >= 0);
+ float voltage = gain/35.0 * 2.1 + 1.4;
+ int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
+
+ assert(dacword>=0 && dacword<4096);
+ usrp()->write_aux_dac(d_which, 0, dacword);
+}
+
+void
+db_dtt754::_set_pga(float pga_gain)
+{
+ assert(pga_gain >=0 && pga_gain <=20);
+ if(d_which == 0) {
+ usrp()->set_pga (0, pga_gain);
+ }
+ else {
+ usrp()->set_pga (2, pga_gain);
+ }
+}
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_dtt768.h>
+#include <db_base_impl.h>
+
+int
+control_byte_4()
+{
+ int C = 0; // Charge Pump Current, no info on how to choose
+ int R = 4; // 125 kHz fref
+
+ // int ATP = 7; // Disable internal AGC
+ return (0x80 | C<<5 | R);
+}
+
+int
+control_byte_5(float freq, int agcmode = 1)
+{
+ if(agcmode) {
+ if(freq < 150e6) {
+ return 0x3B;
+ }
+ else if(freq < 420e6) {
+ return 0x7E;
+ }
+ else {
+ return 0xB7;
+ }
+ }
+ else {
+ if(freq < 150e6) {
+ return 0x39;
+ }
+ else if(freq < 420e6) {
+ return 0x7C;
+ }
+ else {
+ return 0xB5;
+ }
+ }
+}
+
+int
+control_byte_6()
+{
+ int ATC = 0; // AGC time constant = 100ms, 1 = 3S
+ int IFE = 1; // IF AGC amplifier enable
+ int AT = 0; // AGC control, ???
+
+ return (ATC << 5 | IFE << 4 | AT);
+}
+
+int
+control_byte_7()
+{
+ int SAS = 1; // SAW Digital mode
+ int AGD = 1; // AGC disable
+ int ADS = 0; // AGC detector into ADC converter
+ int T = 0; // Test mode, undocumented
+ return (SAS << 7 | AGD << 5 | ADS << 4 | T);
+}
+
+db_dtt768::db_dtt768(usrp_basic_sptr _usrp, int which)
+ : db_base(_usrp, which)
+{
+ /*
+ * Control custom DTT76803-based daughterboard.
+ *
+ * @param usrp: instance of usrp.source_c
+ * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
+ * @type which: int
+ */
+
+ if(d_which == 0) {
+ d_i2c_addr = 0x60;
+ }
+ else {
+ d_i2c_addr = 0x62;
+ }
+
+ d_IF = 44e6;
+
+ d_f_ref = 125e3;
+ d_inverted = false;
+
+ set_gain((gain_min() + gain_max()) / 2.0);
+
+ bypass_adc_buffers(false);
+}
+
+db_dtt768::~db_dtt768()
+{
+}
+
+float
+db_dtt768::gain_min()
+{
+ return 0;
+}
+
+float
+db_dtt768::gain_max()
+{
+ return 115;
+}
+
+float
+db_dtt768::gain_db_per_step()
+{
+ return 1;
+}
+
+bool
+db_dtt768::set_gain(float gain)
+{
+ assert(gain>=0 && gain<=115);
+
+ float rfgain, ifgain, pgagain;
+ if(gain > 60) {
+ rfgain = 60;
+ gain = gain - 60;
+ }
+ else {
+ rfgain = gain;
+ gain = 0;
+ }
+
+ if(gain > 35) {
+ ifgain = 35;
+ gain = gain - 35;
+ }
+ else {
+ ifgain = gain;
+ gain = 0;
+ }
+ pgagain = gain;
+
+ _set_rfagc(rfgain);
+ _set_ifagc(ifgain);
+ _set_pga(pgagain);
+
+ return true;
+}
+
+double
+db_dtt768::freq_min()
+{
+ return 44e6;
+}
+
+double
+db_dtt768::freq_max()
+{
+ return 900e6;
+}
+
+struct freq_result_t
+db_dtt768::set_freq(double target_freq)
+{
+ /*
+ * @returns (ok, actual_baseband_freq) where:
+ * ok is True or False and indicates success or failure,
+ * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+ */
+
+ freq_result_t ret = {false, 0.0};
+
+ if(target_freq < freq_min() || target_freq > freq_max()) {
+ return ret;
+ }
+
+ double target_lo_freq = target_freq + d_IF; // High side mixing
+
+ int divisor = (int)(0.5+(target_lo_freq / d_f_ref));
+ double actual_lo_freq = d_f_ref*divisor;
+
+ if((divisor & ~0x7fff) != 0) { // must be 15-bits or less
+ return ret;
+ }
+
+ // build i2c command string
+ std::vector<int> buf(6);
+ buf[0] = (divisor >> 8) & 0xff; // DB1
+ buf[1] = divisor & 0xff; // DB2
+ buf[2] = control_byte_4();
+ buf[3] = control_byte_5(target_freq);
+ buf[4] = control_byte_6();
+ buf[5] = control_byte_7();
+
+ bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
+
+ d_freq = actual_lo_freq - d_IF;
+
+ ret.ok = ok;
+ ret.baseband_freq = actual_lo_freq;
+
+ return ret;
+
+}
+
+bool
+db_dtt768::is_quadrature()
+{
+ /*
+ * Return True if this board requires both I & Q analog channels.
+ *
+ * This bit of info is useful when setting up the USRP Rx mux register.
+ */
+
+ return false;
+}
+
+bool
+db_dtt768::spectrum_inverted()
+{
+ /*
+ * The 43.75 MHz version is inverted
+ */
+
+ return d_inverted;
+}
+
+bool
+db_dtt768::set_bw(float bw)
+{
+ /*
+ * Choose the SAW filter bandwidth, either 7MHz or 8MHz)
+ */
+
+ d_bw = bw;
+ set_freq(d_freq);
+
+ return true; // FIXME: propagate set_freq result
+}
+
+void
+db_dtt768::_set_rfagc(float gain)
+{
+ assert(gain <= 60 && gain >= 0);
+ // FIXME this has a 0.5V step between gain = 60 and gain = 59.
+ // Why are there two cases instead of a single linear case?
+ float voltage;
+ if(gain == 60) {
+ voltage = 4;
+ }
+ else {
+ voltage = gain/60.0 * 2.25 + 1.25;
+ }
+
+ int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
+
+ assert(dacword>=0 && dacword<4096);
+ usrp()->write_aux_dac(d_which, 1, dacword);
+}
+
+void
+db_dtt768::_set_ifagc(float gain)
+{
+ assert(gain <= 35 && gain >= 0);
+ float voltage = gain/35.0 * 2.1 + 1.4;
+ int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
+
+ assert(dacword>=0 && dacword<4096);
+ usrp()->write_aux_dac(d_which, 0, dacword);
+}
+
+void
+db_dtt768::_set_pga(float pga_gain)
+{
+ assert(pga_gain >=0 && pga_gain <=20);
+ if(d_which == 0) {
+ usrp()->set_pga (0, pga_gain);
+ }
+ else {
+ usrp()->set_pga (2, pga_gain);
+ }
+}
--- /dev/null
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_flexrf.h>
+#include <db_base_impl.h>
+
+// d'board i/o pin defs
+// Tx and Rx have shared defs, but different i/o regs
+#define AUX_RXAGC (1 << 8)
+#define POWER_UP (1 << 7) // enables power supply
+#define RX_TXN (1 << 6) // Tx only: T/R antenna switch for TX/RX port
+#define RX2_RX1N (1 << 6) // Rx only: antenna switch between RX2 and TX/RX port
+#define ENABLE (1 << 5) // enables mixer
+#define AUX_SEN (1 << 4)
+#define AUX_SCLK (1 << 3)
+#define PLL_LOCK_DETECT (1 << 2)
+#define AUX_SDO (1 << 1)
+#define CLOCK_OUT (1 << 0)
+
+flexrf_base::flexrf_base(usrp_basic_sptr _usrp, int which, int _power_on)
+ : db_base(_usrp, which), d_power_on(_power_on)
+{
+ /*
+ @param usrp: instance of usrp.source_c
+ @param which: which side: 0 or 1 corresponding to side A or B respectively
+ @type which: int
+ */
+
+ d_first = true;
+ d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
+
+ usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs
+ _enable_refclk(false); // disable refclk
+
+ set_auto_tr(false);
+}
+
+flexrf_base::~flexrf_base()
+{
+ delete d_common;
+}
+
+void
+flexrf_base::_write_all(int R, int control, int N)
+{
+ /*
+ Write R counter latch, control latch and N counter latch to VCO.
+
+ Adds 10ms delay between writing control and N if this is first call.
+ This is the required power-up sequence.
+
+ @param R: 24-bit R counter latch
+ @type R: int
+ @param control: 24-bit control latch
+ @type control: int
+ @param N: 24-bit N counter latch
+ @type N: int
+ */
+ timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 10000000;
+
+ _write_R(R);
+ _write_control(control);
+ if(d_first) {
+ //time.sleep(0.010);
+ nanosleep(&t, NULL);
+ d_first = false;
+ }
+ _write_N(N);
+}
+
+void
+flexrf_base::_write_control(int control)
+{
+ _write_it((control & ~0x3) | 0);
+}
+
+void
+flexrf_base::_write_R(int R)
+{
+ _write_it((R & ~0x3) | 1);
+}
+
+void
+flexrf_base::_write_N(int N)
+{
+ _write_it((N & ~0x3) | 2);
+}
+
+void
+flexrf_base::_write_it(int v)
+{
+ char s[3];
+ s[0] = (char)((v >> 16) & 0xff);
+ s[1] = (char)((v >> 8) & 0xff);
+ s[2] = (char)(v & 0xff);
+ std::string str(s, 3);
+ usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
+}
+
+bool
+flexrf_base::_lock_detect()
+{
+ /*
+ @returns: the value of the VCO/PLL lock detect bit.
+ @rtype: 0 or 1
+ */
+ if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
+ return true;
+ }
+ else { // Give it a second chance
+ // FIXME: make portable sleep
+ timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 100000000;
+ nanosleep(&t, NULL);
+
+ if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+}
+
+bool
+flexrf_base::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ /*
+ Determine values of R, control, and N registers, along with actual freq.
+
+ @param freq: target frequency in Hz
+ @type freq: float
+ @returns: (R, control, N, actual_freq)
+ @rtype: tuple(int, int, int, float)
+
+ Override this in derived classes.
+ */
+
+ //raise NotImplementedError;
+ throw std::runtime_error("_compute_regs called from flexrf_base\n");
+}
+
+int
+flexrf_base::_compute_control_reg()
+{
+ return d_common->_compute_control_reg();
+}
+
+int
+flexrf_base::_refclk_divisor()
+{
+ return d_common->_refclk_divisor();
+}
+
+double
+flexrf_base::_refclk_freq()
+{
+ return 64e6/_refclk_divisor();
+}
+
+struct freq_result_t
+flexrf_base::set_freq(double freq)
+{
+ /*
+ @returns (ok, actual_baseband_freq) where:
+ ok is True or False and indicates success or failure,
+ actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+ */
+
+ struct freq_result_t args = {false, 0};
+
+ // Offsetting the LO helps get the Tx carrier leakage out of the way.
+ // This also ensures that on Rx, we're not getting hosed by the
+ // FPGA's DC removal loop's time constant. We were seeing a
+ // problem when running with discontinuous transmission.
+ // Offsetting the LO made the problem go away.
+ freq += d_lo_offset;
+
+ int R, control, N;
+ double actual_freq;
+ _compute_regs(freq, R, control, N, actual_freq);
+
+ if(R==0) {
+ return args;
+ }
+
+ _write_all(R, control, N);
+ args.ok = _lock_detect();
+ args.baseband_freq = actual_freq;
+ return args;
+}
+
+bool
+flexrf_base::_set_pga(float pga_gain)
+{
+ if(d_which == 0) {
+ usrp()->set_pga(0, pga_gain);
+ usrp()->set_pga(1, pga_gain);
+ }
+ else {
+ usrp()->set_pga(2, pga_gain);
+ usrp()->set_pga(3, pga_gain);
+ }
+ return true;
+}
+
+bool
+flexrf_base::is_quadrature()
+{
+ /*
+ Return True if this board requires both I & Q analog channels.
+
+ This bit of info is useful when setting up the USRP Rx mux register.
+ */
+ return true;
+}
+
+double
+flexrf_base::freq_min()
+{
+ return d_common->freq_min();
+}
+
+double
+flexrf_base::freq_max()
+{
+ return d_common->freq_max();
+}
+
+// ----------------------------------------------------------------
+
+flexrf_base_tx::flexrf_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
+ : flexrf_base(_usrp, which, _power_on)
+{
+ /*
+ @param usrp: instance of usrp.sink_c
+ @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
+ */
+
+ if(which == 0) {
+ d_spi_enable = SPI_ENABLE_TX_A;
+ }
+ else {
+ d_spi_enable = SPI_ENABLE_TX_B;
+ }
+
+ // power up the transmit side, but don't enable the mixer
+ usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff);
+ usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
+ set_lo_offset(4e6);
+
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+}
+
+flexrf_base_tx::~flexrf_base_tx()
+{
+ shutdown();
+}
+
+
+void
+flexrf_base_tx::shutdown()
+{
+ // fprintf(stderr, "flexrf_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
+
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ // do whatever there is to do to shutdown
+
+ // Power down and leave the T/R switch in the R position
+ usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
+
+ // Power down VCO/PLL
+ d_PD = 3;
+
+ _write_control(_compute_control_reg());
+ _enable_refclk(false); // turn off refclk
+ set_auto_tr(false);
+ }
+}
+
+bool
+flexrf_base_tx::set_auto_tr(bool on)
+{
+ bool ok = true;
+ if(on) {
+ ok &= set_atr_mask (RX_TXN | ENABLE);
+ ok &= set_atr_txval(0 | ENABLE);
+ ok &= set_atr_rxval(RX_TXN | 0);
+ }
+ else {
+ ok &= set_atr_mask (0);
+ ok &= set_atr_txval(0);
+ ok &= set_atr_rxval(0);
+ }
+ return ok;
+}
+
+bool
+flexrf_base_tx::set_enable(bool on)
+{
+ /*
+ Enable transmitter if on is true
+ */
+
+ int v;
+ int mask = RX_TXN | ENABLE;
+ if(on) {
+ v = ENABLE;
+ }
+ else {
+ v = RX_TXN;
+ }
+ return usrp()->write_io(d_which, v, mask);
+}
+
+float
+flexrf_base_tx::gain_min()
+{
+ return usrp()->pga_max();
+}
+
+float
+flexrf_base_tx::gain_max()
+{
+ return usrp()->pga_max();
+}
+
+float
+flexrf_base_tx::gain_db_per_step()
+{
+ return 1;
+}
+
+bool
+flexrf_base_tx::set_gain(float gain)
+{
+ /*
+ Set the gain.
+
+ @param gain: gain in decibels
+ @returns True/False
+ */
+ return _set_pga(usrp()->pga_max());
+}
+
+
+/**************************************************************************/
+
+
+flexrf_base_rx::flexrf_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
+ : flexrf_base(_usrp, which, _power_on)
+{
+ /*
+ @param usrp: instance of usrp.source_c
+ @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
+ */
+
+ if(which == 0) {
+ d_spi_enable = SPI_ENABLE_RX_A;
+ }
+ else {
+ d_spi_enable = SPI_ENABLE_RX_B;
+ }
+
+ usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff);
+ usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE),
+ (POWER_UP|RX2_RX1N|ENABLE));
+
+ // set up for RX on TX/RX port
+ select_rx_antenna("TX/RX");
+
+ bypass_adc_buffers(true);
+
+ set_lo_offset(-4e6);
+}
+
+flexrf_base_rx::~flexrf_base_rx()
+{
+ shutdown();
+}
+
+void
+flexrf_base_rx::shutdown()
+{
+ // fprintf(stderr, "flexrf_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
+
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ // do whatever there is to do to shutdown
+
+ // Power down
+ usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE));
+
+ // Power down VCO/PLL
+ d_PD = 3;
+
+
+ // fprintf(stderr, "flexrf_base_rx::shutdown before _write_control\n");
+ _write_control(_compute_control_reg());
+
+ // fprintf(stderr, "flexrf_base_rx::shutdown before _enable_refclk\n");
+ _enable_refclk(false); // turn off refclk
+
+ // fprintf(stderr, "flexrf_base_rx::shutdown before set_auto_tr\n");
+ set_auto_tr(false);
+
+ // fprintf(stderr, "flexrf_base_rx::shutdown after set_auto_tr\n");
+ }
+}
+
+bool
+flexrf_base_rx::set_auto_tr(bool on)
+{
+ bool ok = true;
+ if(on) {
+ ok &= set_atr_mask (ENABLE);
+ ok &= set_atr_txval( 0);
+ ok &= set_atr_rxval(ENABLE);
+ }
+ else {
+ ok &= set_atr_mask (0);
+ ok &= set_atr_txval(0);
+ ok &= set_atr_rxval(0);
+ }
+ return true;
+}
+
+bool
+flexrf_base_rx::select_rx_antenna(int which_antenna)
+{
+ /*
+ Specify which antenna port to use for reception.
+ @param which_antenna: either 'TX/RX' or 'RX2'
+ */
+
+ if(which_antenna == 0) {
+ usrp()->write_io(d_which, 0,RX2_RX1N);
+ }
+ else if(which_antenna == 1) {
+ usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
+ }
+ else {
+ return false;
+ // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
+ }
+ return true;
+}
+
+bool
+flexrf_base_rx::select_rx_antenna(const std::string &which_antenna)
+{
+ /*
+ Specify which antenna port to use for reception.
+ @param which_antenna: either 'TX/RX' or 'RX2'
+ */
+
+ if(which_antenna == "TX/RX") {
+ usrp()->write_io(d_which, 0, RX2_RX1N);
+ }
+ else if(which_antenna == "RX2") {
+ usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
+ }
+ else {
+ // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
+ return false;
+ }
+ return true;
+}
+
+bool
+flexrf_base_rx::set_gain(float gain)
+{
+ /*
+ Set the gain.
+
+ @param gain: gain in decibels
+ @returns True/False
+ */
+
+ // clamp gain
+ gain = std::max(gain_min(), std::min(gain, gain_max()));
+
+ float pga_gain, agc_gain;
+ float V_maxgain, V_mingain, V_fullscale, dac_value;
+
+ float maxgain = gain_max() - usrp()->pga_max();
+ float mingain = gain_min();
+ if(gain > maxgain) {
+ pga_gain = gain-maxgain;
+ assert(pga_gain <= usrp()->pga_max());
+ agc_gain = maxgain;
+ }
+ else {
+ pga_gain = 0;
+ agc_gain = gain;
+ }
+
+ V_maxgain = .2;
+ V_mingain = 1.2;
+ V_fullscale = 3.3;
+ dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
+
+ assert(dac_value>=0 && dac_value<4096);
+
+ return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
+ && _set_pga(int(pga_gain)));
+}
+
+// ----------------------------------------------------------------
+
+
+_AD4360_common::_AD4360_common()
+{
+ // R-Register Common Values
+ d_R_RSV = 0; // bits 23,22
+ d_BSC = 3; // bits 21,20 Div by 8 to be safe
+ d_TEST = 0; // bit 19
+ d_LDP = 1; // bit 18
+ d_ABP = 0; // bit 17,16 3ns
+
+ // N-Register Common Values
+ d_N_RSV = 0; // bit 7
+
+ // Control Register Common Values
+ d_PD = 0; // bits 21,20 Normal operation
+ d_PL = 0; // bits 13,12 11mA
+ d_MTLD = 1; // bit 11 enabled
+ d_CPG = 0; // bit 10 CP setting 1
+ d_CP3S = 0; // bit 9 Normal
+ d_PDP = 1; // bit 8 Positive
+ d_MUXOUT = 1; // bits 7:5 Digital Lock Detect
+ d_CR = 0; // bit 4 Normal
+ d_PC = 1; // bits 3,2 Core power 10mA
+}
+
+_AD4360_common::~_AD4360_common()
+{
+}
+
+bool
+_AD4360_common::_compute_regs(double refclk_freq, double freq, int &retR,
+ int &retcontrol, int &retN, double &retfreq)
+{
+ /*
+ Determine values of R, control, and N registers, along with actual freq.
+
+ @param freq: target frequency in Hz
+ @type freq: float
+ @returns: (R, control, N, actual_freq)
+ @rtype: tuple(int, int, int, float)
+ */
+
+ // Band-specific N-Register Values
+ //float phdet_freq = _refclk_freq()/d_R_DIV;
+ double phdet_freq = refclk_freq/d_R_DIV;
+ double desired_n = round(freq*d_freq_mult/phdet_freq);
+ double actual_freq = desired_n * phdet_freq;
+ int B = floor(desired_n/_prescaler());
+ int A = desired_n - _prescaler()*B;
+ d_B_DIV = int(B); // bits 20:8
+ d_A_DIV = int(A); // bit 6:2
+
+ //assert db_B_DIV >= db_A_DIV
+ if(d_B_DIV < d_A_DIV) {
+ retR = 0;
+ retcontrol = 0;
+ retN = 0;
+ retfreq = 0;
+ return false;
+ }
+
+ int R = (d_R_RSV<<22) | (d_BSC<<20) | (d_TEST<<19) |
+ (d_LDP<<18) | (d_ABP<<16) | (d_R_DIV<<2);
+
+ int control = _compute_control_reg();
+
+ int N = (d_DIVSEL<<23) | (d_DIV2<<22) | (d_CPGAIN<<21) |
+ (d_B_DIV<<8) | (d_N_RSV<<7) | (d_A_DIV<<2);
+
+ retR = R;
+ retcontrol = control;
+ retN = N;
+ retfreq = actual_freq/d_freq_mult;
+ return true;
+}
+
+int
+_AD4360_common::_compute_control_reg()
+{
+ int control = (d_P<<22) | (d_PD<<20) | (d_CP2<<17) | (d_CP1<<14)
+ | (d_PL<<12) | (d_MTLD<<11) | (d_CPG<<10) | (d_CP3S<<9) | (d_PDP<<8)
+ | (d_MUXOUT<<5) | (d_CR<<4) | (d_PC<<2);
+
+ return control;
+}
+
+int
+_AD4360_common::_refclk_divisor()
+{
+ /*
+ Return value to stick in REFCLK_DIVISOR register
+ */
+ return 1;
+}
+
+int
+_AD4360_common::_prescaler()
+{
+ if(d_P == 0) {
+ return 8;
+ }
+ else if(d_P == 1) {
+ return 16;
+ }
+ else {
+ return 32;
+ }
+}
+
+//----------------------------------------------------------------------
+
+_2400_common::_2400_common()
+ : _AD4360_common()
+{
+ // Band-specific R-Register Values
+ d_R_DIV = 16; // bits 15:2
+
+ // Band-specific C-Register values
+ d_P = 1; // bits 23,22 Div by 16/17
+ d_CP2 = 7; // bits 19:17
+ d_CP1 = 7; // bits 16:14
+
+ // Band specifc N-Register Values
+ d_DIVSEL = 0; // bit 23
+ d_DIV2 = 0; // bit 22
+ d_CPGAIN = 0; // bit 21
+ d_freq_mult = 1;
+}
+
+double
+_2400_common::freq_min()
+{
+ return 2300e6;
+}
+
+double
+_2400_common::freq_max()
+{
+ return 2700e6;
+}
+
+//----------------------------------------------------------------------
+
+_1200_common::_1200_common()
+ : _AD4360_common()
+{
+ // Band-specific R-Register Values
+ d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq
+
+ // Band-specific C-Register values
+ d_P = 1; // bits 23,22 Div by 16/17
+ d_CP2 = 7; // bits 19:17 1.25 mA
+ d_CP1 = 7; // bits 16:14 1.25 mA
+
+ // Band specifc N-Register Values
+ d_DIVSEL = 0; // bit 23
+ d_DIV2 = 1; // bit 22
+ d_CPGAIN = 0; // bit 21
+ d_freq_mult = 2;
+}
+
+double
+_1200_common::freq_min()
+{
+ return 1150e6;
+}
+
+double
+_1200_common::freq_max()
+{
+ return 1350e6;
+}
+
+//-------------------------------------------------------------------------
+
+_1800_common::_1800_common()
+ : _AD4360_common()
+{
+ // Band-specific R-Register Values
+ d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq
+
+ // Band-specific C-Register values
+ d_P = 1; // bits 23,22 Div by 16/17
+ d_CP2 = 7; // bits 19:17 1.25 mA
+ d_CP1 = 7; // bits 16:14 1.25 mA
+
+ // Band specifc N-Register Values
+ d_DIVSEL = 0; // bit 23
+ d_DIV2 = 0; // bit 22
+ d_freq_mult = 1;
+ d_CPGAIN = 0; // bit 21
+}
+
+double
+_1800_common::freq_min()
+{
+ return 1600e6;
+}
+
+double
+_1800_common::freq_max()
+{
+ return 2000e6;
+}
+
+//-------------------------------------------------------------------------
+
+_900_common::_900_common()
+ : _AD4360_common()
+{
+ // Band-specific R-Register Values
+ d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq
+
+ // Band-specific C-Register values
+ d_P = 1; // bits 23,22 Div by 16/17
+ d_CP2 = 7; // bits 19:17 1.25 mA
+ d_CP1 = 7; // bits 16:14 1.25 mA
+
+ // Band specifc N-Register Values
+ d_DIVSEL = 0; // bit 23
+ d_DIV2 = 1; // bit 22
+ d_freq_mult = 2;
+ d_CPGAIN = 0; // bit 21
+}
+
+double
+_900_common::freq_min()
+{
+ return 800e6;
+}
+
+double
+_900_common::freq_max()
+{
+ return 1000e6;
+}
+
+//-------------------------------------------------------------------------
+
+_400_common::_400_common()
+ : _AD4360_common()
+{
+ // Band-specific R-Register Values
+ d_R_DIV = 16; // bits 15:2
+
+ // Band-specific C-Register values
+ d_P = 0; // bits 23,22 Div by 8/9
+ d_CP2 = 7; // bits 19:17 1.25 mA
+ d_CP1 = 7; // bits 16:14 1.25 mA
+
+ // Band specifc N-Register Values These are different for TX/RX
+ d_DIVSEL = 0; // bit 23
+ d_freq_mult = 2;
+
+ d_CPGAIN = 0; // bit 21
+}
+
+double
+_400_common::freq_min()
+{
+ return 400e6;
+}
+
+double
+_400_common::freq_max()
+{
+ return 500e6;
+}
+
+_400_tx::_400_tx()
+ : _400_common()
+{
+ d_DIV2 = 1; // bit 22
+}
+
+_400_rx::_400_rx()
+ : _400_common()
+{
+ d_DIV2 = 0; // bit 22 // RX side has built-in DIV2 in AD8348
+}
+
+//------------------------------------------------------------
+
+db_flexrf_2400_tx::db_flexrf_2400_tx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_tx(usrp, which)
+{
+ d_common = new _2400_common();
+}
+
+db_flexrf_2400_tx::~db_flexrf_2400_tx()
+{
+}
+
+bool
+db_flexrf_2400_tx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+
+db_flexrf_2400_rx::db_flexrf_2400_rx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_rx(usrp, which)
+{
+ d_common = new _2400_common();
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+}
+
+db_flexrf_2400_rx::~db_flexrf_2400_rx()
+{
+}
+
+float
+db_flexrf_2400_rx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_flexrf_2400_rx::gain_max()
+{
+ return usrp()->pga_max()+70;
+}
+
+float
+db_flexrf_2400_rx::gain_db_per_step()
+{
+ return 0.05;
+}
+
+
+bool
+db_flexrf_2400_rx::i_and_q_swapped()
+{
+ return true;
+}
+
+bool
+db_flexrf_2400_rx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+//------------------------------------------------------------
+
+
+db_flexrf_1200_tx::db_flexrf_1200_tx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_tx(usrp, which)
+{
+ d_common = new _1200_common();
+}
+
+db_flexrf_1200_tx::~db_flexrf_1200_tx()
+{
+}
+
+bool
+db_flexrf_1200_tx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+
+
+db_flexrf_1200_rx::db_flexrf_1200_rx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_rx(usrp, which)
+{
+ d_common = new _1200_common();
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+}
+
+db_flexrf_1200_rx::~db_flexrf_1200_rx()
+{
+}
+
+float
+db_flexrf_1200_rx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_flexrf_1200_rx::gain_max()
+{
+ return usrp()->pga_max()+70;
+}
+
+float
+db_flexrf_1200_rx::gain_db_per_step()
+{
+ return 0.05;
+}
+
+bool
+db_flexrf_1200_rx::i_and_q_swapped()
+{
+ return true;
+}
+
+bool
+db_flexrf_1200_rx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+//------------------------------------------------------------
+
+
+db_flexrf_1800_tx::db_flexrf_1800_tx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_tx(usrp, which)
+{
+ d_common = new _1800_common();
+}
+
+db_flexrf_1800_tx::~db_flexrf_1800_tx()
+{
+}
+
+bool
+db_flexrf_1800_tx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+
+db_flexrf_1800_rx::db_flexrf_1800_rx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_rx(usrp, which)
+{
+ d_common = new _1800_common();
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+}
+
+db_flexrf_1800_rx::~db_flexrf_1800_rx()
+{
+}
+
+
+float
+db_flexrf_1800_rx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_flexrf_1800_rx::gain_max()
+{
+ return usrp()->pga_max()+70;
+}
+
+float
+db_flexrf_1800_rx::gain_db_per_step()
+{
+ return 0.05;
+}
+
+bool
+db_flexrf_1800_rx::i_and_q_swapped()
+{
+ return true;
+}
+
+bool
+db_flexrf_1800_rx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+//------------------------------------------------------------
+
+
+db_flexrf_900_tx::db_flexrf_900_tx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_tx(usrp, which)
+{
+ d_common = new _900_common();
+}
+
+db_flexrf_900_tx::~db_flexrf_900_tx()
+{
+}
+
+bool
+db_flexrf_900_tx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+db_flexrf_900_rx::db_flexrf_900_rx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_rx(usrp, which)
+{
+ d_common = new _900_common();
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+}
+
+db_flexrf_900_rx::~db_flexrf_900_rx()
+{
+}
+
+float
+db_flexrf_900_rx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_flexrf_900_rx::gain_max()
+{
+ return usrp()->pga_max()+70;
+}
+
+float
+db_flexrf_900_rx::gain_db_per_step()
+{
+ return 0.05;
+}
+
+bool
+db_flexrf_900_rx::i_and_q_swapped()
+{
+ return true;
+}
+
+bool
+db_flexrf_900_rx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+//------------------------------------------------------------
+
+
+db_flexrf_400_tx::db_flexrf_400_tx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_tx(usrp, which, POWER_UP)
+{
+ d_common = new _400_tx();
+}
+
+db_flexrf_400_tx::~db_flexrf_400_tx()
+{
+}
+
+bool
+db_flexrf_400_tx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
+
+
+db_flexrf_400_rx::db_flexrf_400_rx(usrp_basic_sptr usrp, int which)
+ : flexrf_base_rx(usrp, which, POWER_UP)
+{
+ d_common = new _400_rx();
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+}
+
+db_flexrf_400_rx::~db_flexrf_400_rx()
+{
+}
+
+float
+db_flexrf_400_rx::gain_min()
+{
+ return usrp()->pga_min();
+}
+
+float
+db_flexrf_400_rx::gain_max()
+{
+ return usrp()->pga_max()+45;
+}
+
+float
+
+db_flexrf_400_rx::gain_db_per_step()
+{
+ return 0.035;
+}
+
+
+bool
+db_flexrf_400_rx::i_and_q_swapped()
+{
+ return true;
+}
+
+bool
+db_flexrf_400_rx::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ return d_common->_compute_regs(_refclk_freq(), freq, retR,
+ retcontrol, retN, retfreq);
+}
+
--- /dev/null
+/*
+ * Copyright 2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <usrp/db_flexrf_mimo.h>
+#include <fpga_regs_standard.h>
+#include <fpga_regs_common.h>
+#include <usrp/usrp_prims.h>
+#include <usrp_spi_defs.h>
+
+
+db_flexrf_2400_tx_mimo_a::db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_2400_tx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_2400_tx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_2400_rx_mimo_a::db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_2400_rx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_2400_rx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_2400_tx_mimo_b::db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_2400_tx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_2400_tx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_2400_rx_mimo_b::db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_2400_rx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_2400_rx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_1800_tx_mimo_a::db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1800_tx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_1800_tx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_1800_rx_mimo_a::db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1800_rx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_1800_rx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_1800_tx_mimo_b::db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1800_tx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_1800_tx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_1800_rx_mimo_b::db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1800_rx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_1800_rx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_1200_tx_mimo_a::db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1200_tx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_1200_tx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_1200_rx_mimo_a::db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1200_rx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_1200_rx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_1200_tx_mimo_b::db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1200_tx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_1200_tx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_1200_rx_mimo_b::db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_1200_rx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_1200_rx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_900_tx_mimo_a::db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_900_tx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_900_tx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_900_rx_mimo_a::db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_900_rx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_900_rx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_900_tx_mimo_b::db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_900_tx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_900_tx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_900_rx_mimo_b::db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_900_rx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int db_flexrf_900_rx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_400_tx_mimo_a::db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_400_tx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_400_tx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_400_rx_mimo_a::db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which)
+ : db_flexrf_400_rx(usrp, which)
+{
+ _enable_refclk(true);
+ d_common->R_DIV(1);
+}
+
+int
+db_flexrf_400_rx_mimo_a::_refclk_divisor()
+{
+ return 16;
+}
+
+db_flexrf_400_tx_mimo_b::db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_400_tx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_400_tx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
+
+db_flexrf_400_rx_mimo_b::db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which)
+ : db_flexrf_400_rx(usrp, which)
+{
+ d_common->R_DIV(16);
+}
+
+int
+db_flexrf_400_rx_mimo_b::_refclk_divisor()
+{
+ return 1;
+}
--- /dev/null
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_tv_rx.h>
+#include <db_base_impl.h>
+
+/*****************************************************************************/
+
+int
+control_byte_1(bool fast_tuning_p, int reference_divisor)
+{
+ int c = 0x88;
+ if(fast_tuning_p) {
+ c |= 0x40;
+ }
+
+ if(reference_divisor == 512) {
+ c |= 0x3 << 1;
+ }
+ else if(reference_divisor == 640) {
+ c |= 0x0 << 1;
+ }
+ else if(reference_divisor == 1024) {
+ c |= 0x1 << 1;
+ }
+ else {
+ assert(0);
+ }
+
+ return c;
+}
+
+int
+control_byte_2(double target_freq, bool shutdown_tx_PGA)
+{
+ int c;
+ if(target_freq < 158e6) { // VHF low
+ c = 0xa0;
+ }
+ else if(target_freq < 464e6) { // VHF high
+ c = 0x90;
+ }
+ else { // UHF
+ c = 0x30;
+ }
+
+ if(shutdown_tx_PGA) {
+ c |= 0x08;
+ }
+
+ return c;
+}
+
+
+/*****************************************************************************/
+
+
+db_tv_rx::db_tv_rx(usrp_basic_sptr usrp, int which,
+ double first_IF, double second_IF)
+ : db_base(usrp, which)
+{
+ // Handler for Tv Rx daughterboards.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
+
+ if(which == 0) {
+ d_i2c_addr = 0x60;
+ }
+ else {
+ d_i2c_addr = 0x61;
+ }
+
+ d_first_IF = first_IF;
+ d_second_IF = second_IF;
+ d_reference_divisor = 640;
+ d_fast_tuning = false;
+ d_inverted = false; // FIXME get rid of this
+
+ set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
+
+ bypass_adc_buffers(false);
+}
+
+db_tv_rx::~db_tv_rx()
+{
+}
+
+// Gain setting
+void
+db_tv_rx::_set_rfagc(float gain)
+{
+ float voltage;
+
+ assert(gain <= 60 && gain >= 0);
+ // FIXME this has a 0.5V step between gain = 60 and gain = 59.
+ // Why are there two cases instead of a single linear case?
+ if(gain == 60) {
+ voltage = 4;
+ }
+ else {
+ voltage = gain/60.0 * 2.25 + 1.25;
+ }
+ int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain
+
+ assert(dacword>=0 && dacword<4096);
+ usrp()->write_aux_dac(d_which, 1, dacword);
+}
+
+void
+db_tv_rx::_set_ifagc(float gain)
+{
+ float voltage;
+
+ assert(gain <= 35 && gain >= 0);
+ voltage = gain/35.0 * 2.1 + 1.4;
+ int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain
+
+ assert(dacword>=0 && dacword<4096);
+ usrp()->write_aux_dac(d_which, 0, dacword);
+}
+
+void
+db_tv_rx::_set_pga(float pga_gain)
+{
+ assert(pga_gain >=0 && pga_gain <=20);
+ if(d_which == 0) {
+ usrp()->set_pga(0, pga_gain);
+ }
+ else {
+ usrp()->set_pga (2, pga_gain);
+ }
+}
+
+double
+db_tv_rx::freq_min()
+{
+ return 50e6;
+}
+
+double
+db_tv_rx::freq_max()
+{
+ return 860e6;
+}
+
+struct freq_result_t
+db_tv_rx::set_freq(double target_freq)
+{
+ // Set the frequency.
+ //
+ // @param freq: target RF frequency in Hz
+ // @type freq: double
+ //
+ // @returns (ok, actual_baseband_freq) where:
+ // ok is True or False and indicates success or failure,
+ // actual_baseband_freq is RF frequency that corresponds to DC in the IF.
+
+ freq_result_t args = {false, 0};
+
+ double fmin = freq_min();
+ double fmax = freq_max();
+ if((target_freq < fmin) || (target_freq > fmax)) {
+ return args;
+ }
+
+ double target_lo_freq = target_freq + d_first_IF; // High side mixing
+ double f_ref = 4.0e6 / (double)(d_reference_divisor); // frequency steps
+
+ int divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8));
+ double actual_lo_freq = (f_ref * 8 * divisor);
+ double actual_freq = actual_lo_freq - d_first_IF;
+
+ if((divisor & ~0x7fff) != 0) { // must be 15-bits or less
+ return args;
+ }
+
+ // build i2c command string
+ std::vector<int> buf(4);
+ buf[0] = (divisor >> 8) & 0xff; // DB1
+ buf[1] = divisor & 0xff; // DB2
+ buf[2] = control_byte_1(d_fast_tuning, d_reference_divisor);
+ buf[3] = control_byte_2(actual_freq, true);
+
+ args.ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
+ args.baseband_freq = actual_freq - d_second_IF;
+ return args;
+}
+
+float
+db_tv_rx::gain_min()
+{
+ return 0;
+}
+
+float
+db_tv_rx::gain_max()
+{
+ return 115;
+}
+
+float
+db_tv_rx::gain_db_per_step()
+{
+ return 1;
+}
+
+bool
+db_tv_rx::set_gain(float gain)
+{
+ // Set the gain.
+ //
+ // @param gain: gain in decibels
+ // @returns True/False
+
+ float rfgain, ifgain, pgagain;
+
+ assert(gain>=0 && gain<=115);
+ if(gain>60) {
+ rfgain = 60;
+ gain = gain - 60;
+ }
+ else {
+ rfgain = gain;
+ gain = 0;
+ }
+
+ if(gain > 35) {
+ ifgain = 35;
+ gain = gain - 35;
+ }
+ else {
+ ifgain = gain;
+ gain = 0;
+ }
+
+ pgagain = gain;
+ _set_rfagc(rfgain);
+ _set_ifagc(ifgain);
+ _set_pga(pgagain);
+
+ return true;
+}
+
+bool
+db_tv_rx::is_quadrature()
+{
+ // Return True if this board requires both I & Q analog channels.
+ return false;
+}
+
+bool
+db_tv_rx::spectrum_inverted()
+{
+ // The 43.75 MHz version is inverted
+ return d_inverted;
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <db_util.h>
+#include <sstream>
+
+std::string
+int_seq_to_str(std::vector<int> &seq)
+{
+ //convert a sequence of integers into a string
+
+ std::stringstream str;
+ std::vector<int>::iterator i;
+ for(i = seq.begin(); i != seq.end(); i++) {
+ str << char((unsigned int)*i);
+ }
+ return str.str();
+}
+
+std::vector<int>
+str_to_int_seq(std::string str)
+{
+ //convert a string to a list of integers
+ std::vector<int> seq;
+ std::vector<int>::iterator sitr;
+ std::string::iterator i;
+ for(i=str.begin(); i != str.end(); i++) {
+ int a = (int)(*i);
+ seq.push_back(a);
+ }
+ return seq;
+}
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_DB_UTIL_H
+#define INCLUDED_DB_UTIL_H
+
+#include <string>
+#include <vector>
+
+std::string int_seq_to_str(std::vector<int> &seq);
+std::vector<int> str_to_int_seq(std::string str);
+
+#endif /* INCLUDED_DB_UTIL_H */
--- /dev/null
+//
+// Copyright 2008,2009 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <usrp/db_xcvr2450.h>
+#include <db_base_impl.h>
+#include <cmath>
+#include <boost/thread.hpp>
+#include <boost/weak_ptr.hpp>
+#include <cstdio>
+
+#if 0
+#define LO_OFFSET 4.25e6
+#else
+#define LO_OFFSET 0
+#define NO_LO_OFFSET
+#endif
+
+
+/* ------------------------------------------------------------------------
+ * A few comments about the XCVR2450:
+ *
+ * It is half-duplex. I.e., transmit and receive are mutually exclusive.
+ * There is a single LO for both the Tx and Rx sides.
+ * For our purposes the board is always either receiving or transmitting.
+ *
+ * Each board is uniquely identified by the *USRP hardware* instance and side
+ * This dictionary holds a weak reference to existing board controller so it
+ * can be created or retrieved as needed.
+ */
+
+
+
+// TX IO Pins
+#define HB_PA_OFF (1 << 15) // 5GHz PA, 1 = off, 0 = on
+#define LB_PA_OFF (1 << 14) // 2.4GHz PA, 1 = off, 0 = on
+#define ANTSEL_TX1_RX2 (1 << 13) // 1 = Ant 1 to TX, Ant 2 to RX
+#define ANTSEL_TX2_RX1 (1 << 12) // 1 = Ant 2 to TX, Ant 1 to RX
+#define TX_EN (1 << 11) // 1 = TX on, 0 = TX off
+#define AD9515DIV (1 << 4) // 1 = Div by 3, 0 = Div by 2
+
+#define TX_OE_MASK HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV
+#define TX_SAFE_IO HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV
+
+// RX IO Pins
+#define LOCKDET (1 << 15) // This is an INPUT!!!
+#define EN (1 << 14)
+#define RX_EN (1 << 13) // 1 = RX on, 0 = RX off
+#define RX_HP (1 << 12)
+#define RX_OE_MASK EN|RX_EN|RX_HP
+#define RX_SAFE_IO EN
+
+struct xcvr2450_key {
+ std::string serial_no;
+ int which;
+
+ bool operator==(const xcvr2450_key &x){
+ return x.serial_no ==serial_no && x.which == which;
+ }
+};
+
+class xcvr2450
+{
+private:
+ usrp_basic *d_raw_usrp;
+ int d_which;
+
+ bool d_is_shutdown;
+ int d_spi_format, d_spi_enable;
+
+ int d_mimo, d_int_div, d_frac_div, d_highband, d_five_gig;
+ int d_cp_current, d_ref_div, d_rssi_hbw;
+ int d_txlpf_bw, d_rxlpf_bw, d_rxlpf_fine, d_rxvga_ser;
+ int d_rssi_range, d_rssi_mode, d_rssi_mux;
+ int d_rx_hp_pin, d_rx_hpf, d_rx_ant;
+ int d_tx_ant, d_txvga_ser, d_tx_driver_lin;
+ int d_tx_vga_lin, d_tx_upconv_lin, d_tx_bb_gain;
+ int d_pabias_delay, d_pabias, rx_rf_gain, rx_bb_gain, d_txgain;
+ int d_rx_rf_gain, d_rx_bb_gain;
+
+ int d_reg_standby, d_reg_int_divider, d_reg_frac_divider, d_reg_bandselpll;
+ int d_reg_cal, dsend_reg, d_reg_lpf, d_reg_rxrssi_ctrl, d_reg_txlin_gain;
+ int d_reg_pabias, d_reg_rxgain, d_reg_txgain;
+
+ int d_ad9515_div;
+
+ void _set_rfagc(float gain);
+ void _set_ifagc(float gain);
+ void _set_pga(float pga_gain);
+
+public:
+ usrp_basic *usrp(){
+ return d_raw_usrp;
+ }
+
+ xcvr2450(usrp_basic_sptr usrp, int which);
+ ~xcvr2450();
+ void shutdown();
+
+ void set_reg_standby();
+
+ // Integer-Divider Ratio (3)
+ void set_reg_int_divider();
+
+ // Fractional-Divider Ratio (4)
+ void set_reg_frac_divider();
+
+ // Band Select and PLL (5)
+ void set_reg_bandselpll();
+
+ // Calibration (6)
+ void set_reg_cal();
+
+ // Lowpass Filter (7)
+ void set_reg_lpf();
+
+ // Rx Control/RSSI (8)
+ void set_reg_rxrssi_ctrl();
+
+ // Tx Linearity/Baseband Gain (9)
+ void set_reg_txlin_gain();
+
+ // PA Bias DAC (10)
+ void set_reg_pabias();
+
+ // Rx Gain (11)
+ void set_reg_rxgain();
+
+ // Tx Gain (12)
+ void set_reg_txgain();
+
+ // Send register write to SPI
+ void send_reg(int v);
+
+ void set_gpio();
+ bool lock_detect();
+ bool set_rx_gain(float gain);
+ bool set_tx_gain(float gain);
+
+ struct freq_result_t set_freq(double target_freq);
+};
+
+
+/*****************************************************************************/
+
+
+xcvr2450::xcvr2450(usrp_basic_sptr _usrp, int which)
+ : d_raw_usrp(_usrp.get()), d_which(which), d_is_shutdown(false)
+{
+ // Handler for Tv Rx daughterboards.
+ //
+ // @param usrp: instance of usrp.source_c
+ // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
+
+ // Use MSB with no header
+ d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
+
+ if(which == 0) {
+ d_spi_enable = SPI_ENABLE_RX_A;
+ }
+ else {
+ d_spi_enable = SPI_ENABLE_RX_B;
+ }
+
+ // Sane defaults
+ d_mimo = 1; // 0 = OFF, 1 = ON
+ d_int_div = 192; // 128 = min, 255 = max
+ d_frac_div = 0; // 0 = min, 65535 = max
+ d_highband = 0; // 0 = freq <= 5.4e9, 1 = freq > 5.4e9
+ d_five_gig = 0; // 0 = freq <= 3.e9, 1 = freq > 3e9
+ d_cp_current = 1; // 0 = 2mA, 1 = 4mA
+ d_ref_div = 1; // 1 to 7
+ d_rssi_hbw = 0; // 0 = 2 MHz, 1 = 6 MHz
+ d_txlpf_bw = 1; // 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
+ d_rxlpf_bw = 1; // 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
+ d_rxlpf_fine = 2; // 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
+ d_rxvga_ser = 1; // 0 = RXVGA controlled by B7:1, 1=controlled serially
+ d_rssi_range = 1; // 0 = low range (datasheet typo), 1=high range (0.5V - 2.0V)
+ d_rssi_mode = 1; // 0 = enable follows RXHP, 1 = enabled
+ d_rssi_mux = 0; // 0 = RSSI, 1 = TEMP
+ d_rx_hp_pin = 0; // 0 = Fc set by rx_hpf, 1 = 600 KHz
+ d_rx_hpf = 0; // 0 = 100Hz, 1 = 30KHz
+ d_rx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2
+ d_tx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2
+ d_txvga_ser = 1; // 0 = TXVGA controlled by B6:1, 1=controlled serially
+ d_tx_driver_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
+ d_tx_vga_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
+ d_tx_upconv_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
+ d_tx_bb_gain = 3; // 0=maxgain-5dB, 1=max-3dB, 2=max-1.5dB, 3=max
+ d_pabias_delay = 15; // 0 = 0, 15 = 7uS
+ d_pabias = 0; // 0 = 0 uA, 63 = 315uA
+ d_rx_rf_gain = 0; // 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB
+ d_rx_bb_gain = 16; // 0 = min, 31 = max (0 - 62 dB)
+
+ d_txgain = 63; // 0 = min, 63 = max
+
+ // Initialize GPIO and ATR
+ usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK);
+ usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff);
+ usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO);
+ usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO);
+ usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK);
+
+ usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK);
+ usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff);
+ usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO);
+ usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO);
+ usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK);
+
+ // Initialize chipset
+ // TODO: perform reset sequence to ensure power up defaults
+ set_reg_standby();
+ set_reg_bandselpll();
+ set_reg_cal();
+ set_reg_lpf();
+ set_reg_rxrssi_ctrl();
+ set_reg_txlin_gain();
+ set_reg_pabias();
+ set_reg_rxgain();
+ set_reg_txgain();
+ //FIXME: set_freq(2.45e9);
+}
+
+xcvr2450::~xcvr2450()
+{
+ //printf("xcvr2450::destructor\n");
+ shutdown();
+}
+
+void
+xcvr2450::shutdown()
+{
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO);
+ usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO);
+ usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO);
+ usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO);
+ }
+}
+
+
+void
+xcvr2450::set_reg_standby()
+{
+ d_reg_standby = ((d_mimo<<17) |
+ (1<<16) |
+ (1<<6) |
+ (1<<5) |
+ (1<<4) | 2);
+ send_reg(d_reg_standby);
+}
+
+void
+xcvr2450::set_reg_int_divider()
+{
+ d_reg_int_divider = (((d_frac_div & 0x03)<<16) |
+ (d_int_div<<4) | 3);
+ send_reg(d_reg_int_divider);
+}
+
+void
+xcvr2450::set_reg_frac_divider()
+{
+ d_reg_frac_divider = ((d_frac_div & 0xfffc)<<2) | 4;
+ send_reg(d_reg_frac_divider);
+}
+
+void
+xcvr2450::set_reg_bandselpll()
+{
+ d_reg_bandselpll = ((d_mimo<<17) |
+ (1<<16) |
+ (1<<15) |
+ (0<<11) |
+ (d_highband<<10) |
+ (d_cp_current<<9) |
+ (d_ref_div<<5) |
+ (d_five_gig<<4) | 5);
+ send_reg(d_reg_bandselpll);
+ d_reg_bandselpll = ((d_mimo<<17) |
+ (1<<16) |
+ (1<<15) |
+ (1<<11) |
+ (d_highband<<10) |
+ (d_cp_current<<9) |
+ (d_ref_div<<5) |
+ (d_five_gig<<4) | 5);
+ send_reg(d_reg_bandselpll);
+}
+
+void
+xcvr2450::set_reg_cal()
+{
+ // FIXME do calibration
+ d_reg_cal = (1<<14)|6;
+ send_reg(d_reg_cal);
+}
+
+void
+xcvr2450::set_reg_lpf()
+{
+ d_reg_lpf = (
+ (d_rssi_hbw<<15) |
+ (d_txlpf_bw<<10) |
+ (d_rxlpf_bw<<9) |
+ (d_rxlpf_fine<<4) | 7);
+ send_reg(d_reg_lpf);
+}
+
+void
+xcvr2450::set_reg_rxrssi_ctrl()
+{
+ d_reg_rxrssi_ctrl = ((d_rxvga_ser<<16) |
+ (d_rssi_range<<15) |
+ (d_rssi_mode<<14) |
+ (d_rssi_mux<<12) |
+ (1<<9) |
+ (d_rx_hpf<<6) |
+ (1<<4) | 8);
+ send_reg(d_reg_rxrssi_ctrl);
+}
+
+void
+xcvr2450::set_reg_txlin_gain()
+{
+ d_reg_txlin_gain = ((d_txvga_ser<<14) |
+ (d_tx_driver_lin<<12) |
+ (d_tx_vga_lin<<10) |
+ (d_tx_upconv_lin<<6) |
+ (d_tx_bb_gain<<4) | 9);
+ send_reg(d_reg_txlin_gain);
+}
+
+void
+xcvr2450::set_reg_pabias()
+{
+ d_reg_pabias = (
+ (d_pabias_delay<<10) |
+ (d_pabias<<4) | 10);
+ send_reg(d_reg_pabias);
+}
+
+void
+xcvr2450::set_reg_rxgain()
+{
+ d_reg_rxgain = (
+ (d_rx_rf_gain<<9) |
+ (d_rx_bb_gain<<4) | 11);
+ send_reg(d_reg_rxgain);
+}
+
+void
+xcvr2450::set_reg_txgain()
+{
+ d_reg_txgain = (d_txgain<<4) | 12;
+ send_reg(d_reg_txgain);
+}
+
+void
+xcvr2450::send_reg(int v)
+{
+ // Send 24 bits, it keeps last 18 clocked in
+ char c[3];
+ c[0] = (char)((v >> 16) & 0xff);
+ c[1] = (char)((v >> 8) & 0xff);
+ c[2] = (char)((v & 0xff));
+ std::string s(c, 3);
+
+ usrp()->_write_spi(0, d_spi_enable, d_spi_format, s);
+ //printf("xcvr2450: Setting reg %d to %X\n", (v&15), v);
+}
+
+// ----------------------------------------------------------------
+
+void
+xcvr2450::set_gpio()
+{
+ // We calculate four values:
+ //
+ // io_rx_while_rx: what to drive onto io_rx_* when receiving
+ // io_rx_while_tx: what to drive onto io_rx_* when transmitting
+ // io_tx_while_rx: what to drive onto io_tx_* when receiving
+ // io_tx_while_tx: what to drive onto io_tx_* when transmitting
+ //
+ // B1-B7 is ignored as gain is set serially for now.
+
+ int rx_hp, tx_antsel, rx_antsel, tx_pa_sel;
+ if(d_rx_hp_pin)
+ rx_hp = RX_HP;
+ else
+ rx_hp = 0;
+
+ if(d_tx_ant)
+ tx_antsel = ANTSEL_TX2_RX1;
+ else
+ tx_antsel = ANTSEL_TX1_RX2;
+
+ if(d_rx_ant)
+ rx_antsel = ANTSEL_TX2_RX1;
+ else
+ rx_antsel = ANTSEL_TX1_RX2;
+
+ if(d_five_gig)
+ tx_pa_sel = LB_PA_OFF;
+ else
+ tx_pa_sel = HB_PA_OFF;
+
+ // Reset GPIO and ATR
+ // FIXME: dont set io, oe, atr mask once basic code stops overriding our settings
+ usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK);
+ usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff);
+ usrp()->common_write_atr_txval(C_TX, d_which, tx_pa_sel|tx_antsel|TX_EN|AD9515DIV);
+ usrp()->common_write_atr_rxval(C_TX, d_which, HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV);
+ usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK);
+
+ usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK);
+ usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff);
+ usrp()->common_write_atr_txval(C_RX, d_which, EN|rx_hp);
+ usrp()->common_write_atr_rxval(C_RX, d_which, EN|rx_hp|RX_EN);
+ usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK);
+
+ //printf("GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X\n",
+ // io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx);
+}
+
+
+struct freq_result_t
+xcvr2450::set_freq(double target_freq)
+{
+ struct freq_result_t args = {false, 0};
+
+ double scaler;
+
+ if(target_freq > 3e9) {
+ d_five_gig = 1;
+ d_ad9515_div = 3;
+ scaler = 4.0/5.0;
+ }
+ else {
+ d_five_gig = 0;
+ d_ad9515_div = 3;
+ scaler = 4.0/3.0;
+ }
+
+ if(target_freq > 5.408e9) {
+ d_highband = 1;
+ }
+ else {
+ d_highband = 0;
+ }
+
+ double vco_freq = target_freq*scaler;
+ double sys_clk = usrp()->fpga_master_clock_freq(); // Usually 64e6
+ double ref_clk = sys_clk / d_ad9515_div;
+
+ double phdet_freq = ref_clk/d_ref_div;
+ double div = vco_freq/phdet_freq;
+ d_int_div = int(floor(div));
+ d_frac_div = int((div-d_int_div)*65536.0);
+ // double actual_freq = phdet_freq*(d_int_div+(d_frac_div/65536.0))/scaler;
+
+ //printf("RF=%f VCO=%f R=%d PHD=%f DIV=%3.5f I=%3d F=%5d ACT=%f\n",
+ // target_freq, vco_freq, d_ref_div, phdet_freq,
+ // div, d_int_div, d_frac_div, actual_freq);
+
+ set_gpio();
+ set_reg_int_divider();
+ set_reg_frac_divider();
+ set_reg_bandselpll();
+
+ args.ok = lock_detect();
+#ifdef NO_LO_OFFSET
+ args.baseband_freq = target_freq;
+#else
+ args.baseband_freq = actual_freq;
+#endif
+
+ if(!args.ok){
+ printf("Fail %f\n", target_freq);
+ }
+ return args;
+}
+
+bool
+xcvr2450::lock_detect()
+{
+ /*
+ @returns: the value of the VCO/PLL lock detect bit.
+ @rtype: 0 or 1
+ */
+ if(usrp()->common_read_io(C_RX, d_which) & LOCKDET) {
+ return true;
+ }
+ else { // Give it a second chance
+ if(usrp()->common_read_io(C_RX, d_which) & LOCKDET)
+ return true;
+ else
+ return false;
+ }
+}
+
+bool
+xcvr2450::set_rx_gain(float gain)
+{
+ if(gain < 0.0)
+ gain = 0.0;
+ if(gain > 92.0)
+ gain = 92.0;
+
+ // Split the gain between RF and baseband
+ // This is experimental, not prescribed
+ if(gain < 31.0) {
+ d_rx_rf_gain = 0; // 0 dB RF gain
+ rx_bb_gain = int(gain/2.0);
+ }
+
+ if(gain >= 30.0 and gain < 60.5) {
+ d_rx_rf_gain = 2; // 15 dB RF gain
+ d_rx_bb_gain = int((gain-15.0)/2.0);
+ }
+
+ if(gain >= 60.5) {
+ d_rx_rf_gain = 3; // 30.5 dB RF gain
+ d_rx_bb_gain = int((gain-30.5)/2.0);
+ }
+
+ set_reg_rxgain();
+
+ return true;
+}
+
+bool
+xcvr2450::set_tx_gain(float gain)
+{
+ if(gain < 0.0) {
+ gain = 0.0;
+ }
+ if(gain > 30.0) {
+ gain = 30.0;
+ }
+
+ d_txgain = int((gain/30.0)*63);
+ set_reg_txgain();
+
+ return true;
+}
+
+
+/*****************************************************************************/
+
+
+struct xcvr2450_table_entry {
+ xcvr2450_key key;
+ boost::weak_ptr<xcvr2450> value;
+
+ xcvr2450_table_entry(const xcvr2450_key &_key, boost::weak_ptr<xcvr2450> _value)
+ : key(_key), value(_value) {}
+};
+
+typedef std::vector<xcvr2450_table_entry> xcvr2450_table;
+
+static boost::mutex s_table_mutex;
+static xcvr2450_table s_table;
+
+static xcvr2450_sptr
+_get_or_make_xcvr2450(usrp_basic_sptr usrp, int which)
+{
+ xcvr2450_key key = {usrp->serial_number(), which};
+
+ boost::mutex::scoped_lock guard(s_table_mutex);
+
+ for (xcvr2450_table::iterator p = s_table.begin(); p != s_table.end();){
+ if (p->value.expired()) // weak pointer is now dead
+ p = s_table.erase(p); // erase it
+ else {
+ if (key == p->key){ // found it
+ return xcvr2450_sptr(p->value);
+ }
+ else
+ ++p; // keep looking
+ }
+ }
+
+ // We don't have the xcvr2450 we're looking for
+
+ // create a new one and stick it in the table.
+ xcvr2450_sptr r(new xcvr2450(usrp, which));
+ xcvr2450_table_entry t(key, r);
+ s_table.push_back(t);
+
+ return r;
+}
+
+
+/*****************************************************************************/
+
+
+db_xcvr2450_base::db_xcvr2450_base(usrp_basic_sptr usrp, int which)
+ : db_base(usrp, which)
+{
+ /*
+ * Abstract base class for all xcvr2450 boards.
+ *
+ * Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
+ *
+ * @param usrp: instance of usrp.source_c
+ * @param which: which side: 0 or 1 corresponding to side A or B respectively
+ * @type which: int
+ */
+
+ d_xcvr = _get_or_make_xcvr2450(usrp, which);
+}
+
+db_xcvr2450_base::~db_xcvr2450_base()
+{
+}
+
+void
+db_xcvr2450_base::shutdown_common()
+{
+ // If the usrp_basic in the xcvr2450 is the same as the usrp_basic
+ // in the daughterboard, shutdown the xcvr now (when only one of Tx
+ // and Rx is open, this is always true).
+
+ if (d_xcvr->usrp() == usrp()){
+ //std::cerr << "db_xcvr2450_base::shutdown_common: same -> shutting down\n";
+ d_xcvr->shutdown();
+ }
+ else {
+ //std::cerr << "db_xcvr2450_base::shutdown_common: different -> ignoring\n";
+ }
+}
+
+struct freq_result_t
+db_xcvr2450_base::set_freq(double target_freq)
+{
+ /*
+ * @returns (ok, actual_baseband_freq) where:
+ * ok is True or False and indicates success or failure,
+ * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+ */
+ return d_xcvr->set_freq(target_freq+d_lo_offset);
+}
+
+bool
+db_xcvr2450_base::is_quadrature()
+{
+ /*
+ * Return True if this board requires both I & Q analog channels.
+ *
+ * This bit of info is useful when setting up the USRP Rx mux register.
+ */
+ return true;
+}
+
+double
+db_xcvr2450_base::freq_min()
+{
+ return 2.4e9;
+}
+
+double
+db_xcvr2450_base::freq_max()
+{
+ return 6.0e9;
+}
+
+
+/******************************************************************************/
+
+
+db_xcvr2450_tx::db_xcvr2450_tx(usrp_basic_sptr usrp, int which)
+ : db_xcvr2450_base(usrp, which)
+{
+ set_lo_offset(LO_OFFSET);
+ //printf("db_xcvr2450_tx::db_xcvr2450_tx\n");
+}
+
+db_xcvr2450_tx::~db_xcvr2450_tx()
+{
+ shutdown();
+}
+
+void
+db_xcvr2450_tx::shutdown()
+{
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ shutdown_common();
+ }
+}
+
+float
+db_xcvr2450_tx::gain_min()
+{
+ return 0;
+}
+
+float
+db_xcvr2450_tx::gain_max()
+{
+ return 30;
+}
+
+float
+db_xcvr2450_tx::gain_db_per_step()
+{
+ return (30.0/63.0);
+}
+
+bool
+db_xcvr2450_tx::set_gain(float gain)
+{
+ return d_xcvr->set_tx_gain(gain);
+}
+
+bool
+db_xcvr2450_tx::i_and_q_swapped()
+{
+ return true;
+}
+
+
+/******************************************************************************/
+
+
+db_xcvr2450_rx::db_xcvr2450_rx(usrp_basic_sptr usrp, int which)
+ : db_xcvr2450_base(usrp, which)
+{
+ /*
+ * @param usrp: instance of usrp.source_c
+ * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
+ */
+ set_lo_offset(LO_OFFSET);
+ //printf("db_xcvr2450_rx:d_xcvr_2450_rx\n");
+}
+
+db_xcvr2450_rx::~db_xcvr2450_rx()
+{
+ shutdown();
+}
+
+void
+db_xcvr2450_rx::shutdown()
+{
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ shutdown_common();
+ }
+}
+
+float
+db_xcvr2450_rx::gain_min()
+{
+ return 0.0;
+}
+
+float
+db_xcvr2450_rx::gain_max()
+{
+ return 92.0;
+}
+
+float
+db_xcvr2450_rx::gain_db_per_step()
+{
+ return 1;
+}
+
+bool
+db_xcvr2450_rx::set_gain(float gain)
+{
+ return d_xcvr->set_rx_gain(gain);
+}
--- /dev/null
+#!/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 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+import sys
+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
+
+
+
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <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
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// 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 in bytes (hard limit).
+ */
+ static int max_block_size ();
+
+ /*!
+ * \brief Returns default block size in bytes.
+ */
+ static int default_block_size ();
+
+ /*!
+ * \brief Returns the default buffer size in bytes.
+ */
+ static int default_buffer_size ();
+
+};
+
+#endif /* _FUSB_H_ */
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// tell mld_threads to NOT use omni_threads,
+// but rather Darwin's pthreads
+#define _USE_OMNI_THREADS_
+#define DO_DEBUG 0
+
+#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;
+
+ // lock the runBlock mutex, before creating the run thread.
+ // this guarantees that we can control execution between these 2 threads
+ d_runBlock->mutex ()->lock ();
+
+ // create the run thread, which allows OSX to process I/O separately
+ d_runThread = new mld_thread (run_thread, this);
+
+ // wait until the run thread (and possibky read thread) are -really-
+ // going; this will unlock the mutex before waiting for a signal ()
+ 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);
+
+ // lock the run thread running mutex; if ::stop() is called, it will
+ // first abort() the pipe then wait for the run thread to finish,
+ // via a lock() on this mutex
+ 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;
+ mld_mutex_ptr l_readBlock_mutex = l_readBlock->mutex ();
+
+ 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) {
+ // lock the readBlock mutex, before creating the read thread.
+ // this guarantees that we can control execution between these 2 threads
+ l_readBlock_mutex->lock ();
+ // create the read thread, which just issues all of the starting
+ // async read commands, then returns
+ l_rwThread = new mld_thread (read_thread, arg);
+ // wait until the the read thread is -really- going; this will
+ // unlock the read block mutex before waiting for a signal ()
+ l_readBlock->wait ();
+ }
+
+ // now signal the run condition to release and finish ::start().
+
+ // lock the runBlock mutex first; this will force waiting until the
+ // ->wait() command is issued in ::start()
+ mld_mutex_ptr l_run_block_mutex = This->d_runBlock->mutex ();
+ l_run_block_mutex->lock ();
+
+ // now that the lock is in place, signal the parent thread that
+ // things are running
+ This->d_runBlock->signal ();
+
+ // release the run_block mutex, just in case
+ l_run_block_mutex->unlock ();
+
+ // run the loop
+ CFRunLoopRun ();
+
+ if (l_input_p) {
+ // wait for read_thread () to finish, if needed
+ 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");
+
+ // release the run thread running mutex
+ 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);
+
+ // before doing anything else, lock the read running mutex. this
+ // mutex does flow control between this thread and the run_thread
+ mld_mutex_ptr l_readRunning = This->d_readRunning;
+ l_readRunning->lock ();
+
+ // signal the read condition from run_thread() to continue
+
+ // lock the readBlock mutex first; this will force waiting until the
+ // ->wait() command is issued in ::run_thread()
+ mld_condition_ptr l_readBlock = This->d_readBlock;
+ mld_mutex_ptr l_read_block_mutex = l_readBlock->mutex ();
+ l_read_block_mutex->lock ();
+
+ // now that the lock is in place, signal the parent thread that
+ // things are running here
+ l_readBlock->signal ();
+
+ // release the run_block mutex, just in case
+ l_read_block_mutex->unlock ();
+
+ // queue up all of the available read requests
+ 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");
+
+ // release the read running mutex, to let the parent thread knows
+ // that this thread is finished
+ l_readRunning->unlock ();
+}
+
+void
+fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
+{
+ if ((! l_both) || (! d_started)) {
+ if (usb_debug > 4)
+ fprintf (stderr, "fusb_ephandle_darwin::read_issue: Doing nothing; "
+ "l_both is %X; started is %s\n", (unsigned int) l_both,
+ d_started ? "TRUE" : "FALSE");
+ 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));
+ else if (usb_debug > 4)
+ fprintf (stderr, "fusb_ephandle_darwin::read_issue: "
+ "Queued %X (%ld Bytes)\n", (unsigned int) l_both, bufLen);
+}
+
+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);
+ else if (usb_debug > 4)
+ fprintf (stderr, "fusb_ephandle_darwin::read_completed: "
+ "Read %X (%ld bytes)\n",
+ (unsigned int) l_both, 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);
+
+ if (usb_debug > 4)
+ fprintf (stderr, "fusb_ephandle_darwin::read: request for %d bytes, %ld bytes retrieved.\n", nbytes, l_nbytes);
+
+ return ((int) l_nbytes);
+}
+
+int
+fusb_ephandle_darwin::write (const void* buffer, int nbytes)
+{
+ UInt32 l_nbytes = (UInt32) nbytes;
+
+ if (! d_started) {
+ if (usb_debug)
+ fprintf (stderr, "fusb_ephandle_darwin::write: Not yet started.\n");
+
+ 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, t_nbytes,
+ (IOAsyncCallback1) write_completed, (void*) l_both);
+ else
+ result = d_interface->WritePipeAsyncTO
+ (d_interfaceRef, d_pipeRef, v_buffer, t_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));
+ else if (usb_debug > 4) {
+ fprintf (stderr, "fusb_ephandle_darwin::write_thread: "
+ "Queued %X (%ld Bytes)\n", (unsigned int) l_both, t_nbytes);
+ }
+ 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);
+ else if (usb_debug > 4)
+ fprintf (stderr, "fusb_ephandle_darwin::write_completed: "
+ "Wrote %X (%ld Bytes)\n", (unsigned int) l_both, 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);
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _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_ */
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <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);
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _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_ */
+
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fusb_linux.h>
+#include <usb.h> // libusb header
+#include <stdexcept>
+#ifdef HAVE_LINUX_COMPILER_H
+#include <linux/compiler.h>
+#endif
+#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>
+#include <cstdio>
+
+#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 or an unrecoverable error occurs.
+ */
+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 ())
+ if (!_reap(true))
+ break;
+}
+\f// ------------------------------------------------------------------------
+// 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;
+
+ 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;
+ }
+
+ d_devhandle->_cancel_pending_rqsts (this);
+ d_devhandle->_reap (false);
+
+ while (1){
+ usbdevfs_urb *urb;
+ while ((urb = completed_list_get ()) != 0)
+ free_list_add (urb);
+
+ if (d_free_list.size () == (unsigned) d_nblocks)
+ break;
+
+ if (!d_devhandle->_reap(true))
+ break;
+ }
+
+ 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();
+ if (!urb)
+ return -1;
+ 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 ();
+ if (!urb)
+ return -1;
+ 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.
+
+ if (!d_devhandle->_reap (true))
+ return 0;
+ }
+}
+
+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)
+ if (!d_devhandle->_reap (true))
+ return false;
+
+ // check result of completed read
+
+ if (urb->status != 0){
+ // We've got a problem. Report it and fail.
+ fprintf (stderr, "fusb: (rd status %d) %s\n", urb->status, strerror (-urb->status));
+ urb->actual_length = 0;
+ free_list_add (urb);
+ return false;
+ }
+
+ // 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;
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// 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 ();
+};
+
+\f/*!
+ * \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_ */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fusb_ra_wb.h>
+#include <usb.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/event.h>
+#include <dev/usb/usb.h>
+
+static const int USB_TIMEOUT = 1000; // in milliseconds
+
+// the following comment and function is from fusb_linux.cc
+#if 0
+// 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);
+}
+#endif
+
+// the control endpoint doesn't actually do us any good so here is a
+// new "fragile extraction"
+static int
+ep_fd_from_usb_dev_handle (usb_dev_handle *udh, int endpoint)
+{
+ struct usb_dev_handle_kludge2 { // see also usrp_prims.cc
+ int fd;
+ struct usb_bus *bus;
+ struct usb_device *device;
+ int config;
+ int interface;
+ int altsetting;
+ void *impl_info;
+ };
+ struct bsd_usb_dev_handle_info_kludge {
+ int ep_fd[USB_MAX_ENDPOINTS];
+ };
+ struct bsd_usb_dev_handle_info_kludge *info
+ = (struct bsd_usb_dev_handle_info_kludge *)
+ ((struct usb_dev_handle_kludge2 *)udh)->impl_info;
+ return info->ep_fd[UE_GET_ADDR(endpoint)];
+}
+
+
+fusb_devhandle_ra_wb::fusb_devhandle_ra_wb (usb_dev_handle *udh)
+ : fusb_devhandle (udh)
+{
+ // that's it
+}
+
+fusb_devhandle_ra_wb::~fusb_devhandle_ra_wb ()
+{
+ // nop
+}
+
+fusb_ephandle *
+fusb_devhandle_ra_wb::make_ephandle (int endpoint, bool input_p,
+ int block_size, int nblocks)
+{
+ return new fusb_ephandle_ra_wb (this, endpoint, input_p,
+ block_size, nblocks);
+}
+
+// ----------------------------------------------------------------
+
+fusb_ephandle_ra_wb::fusb_ephandle_ra_wb (fusb_devhandle_ra_wb *dh,
+ int endpoint, bool input_p,
+ int block_size, int nblocks)
+ : fusb_ephandle (endpoint, input_p, block_size, nblocks),
+ d_devhandle (dh), d_ra_wb_on (false)
+{
+ // that's it
+}
+
+fusb_ephandle_ra_wb::~fusb_ephandle_ra_wb ()
+{
+ // nop
+}
+
+bool
+fusb_ephandle_ra_wb::start ()
+{
+ d_started = true;
+
+ char buf = '\0';
+ int fd;
+
+ // this is to cause libusb to open the endpoint
+ if (!d_input_p) {
+ write(&buf, 0);
+ fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
+ d_endpoint);
+ }
+ else {
+ read(&buf, 0);
+ fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
+ d_endpoint|USB_ENDPOINT_IN);
+ }
+
+ // enable read ahead/write behind
+ int ret;
+ struct usb_bulk_ra_wb_opt opts;
+ int enable = 1;
+
+ opts.ra_wb_buffer_size = d_block_size*d_nblocks;
+ opts.ra_wb_request_size = d_block_size;
+// fprintf (stderr, "setting buffer size to %d, request size to %d\n",
+// opts.ra_wb_buffer_size, opts.ra_wb_request_size);
+ if (!d_input_p) {
+ ret = ioctl (fd, USB_SET_BULK_WB_OPT, &opts);
+ if (ret < 0)
+ fprintf (stderr, "USB_SET_BULK_WB_OPT: %s\n", strerror(errno));
+ else {
+ ret = ioctl (fd, USB_SET_BULK_WB, &enable);
+ if (ret < 0)
+ fprintf (stderr, "USB_SET_BULK_WB: %s\n", strerror(errno));
+ else
+ d_ra_wb_on = true;
+ }
+ }
+ else {
+ ret = ioctl (fd, USB_SET_BULK_RA_OPT, &opts);
+ if (ret < 0)
+ fprintf (stderr, "USB_SET_BULK_RA_OPT: %s\n", strerror(errno));
+ else {
+ ret = ioctl (fd, USB_SET_BULK_RA, &enable);
+ if (ret < 0)
+ fprintf (stderr, "USB_SET_BULK_RA: %s\n", strerror(errno));
+ else
+ d_ra_wb_on = true;
+ }
+ }
+
+ return true;
+}
+
+bool
+fusb_ephandle_ra_wb::stop ()
+{
+ int fd;
+ int ret;
+ int enable = 0;
+ if (d_ra_wb_on) {
+ if (!d_input_p) {
+ fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
+ d_endpoint);
+ ret = ioctl (fd, USB_SET_BULK_WB, &enable);
+ if (ret < 0)
+ fprintf (stderr, "USB_SET_BULK_WB: %s\n", strerror(errno));
+ else
+ d_ra_wb_on = false;
+ }
+ else {
+ fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
+ d_endpoint|USB_ENDPOINT_IN);
+ ret = ioctl (fd, USB_SET_BULK_RA, &enable);
+ if (ret < 0)
+ fprintf (stderr, "USB_SET_BULK_RA: %s\n", strerror(errno));
+ else
+ d_ra_wb_on = false;
+ }
+ }
+
+ d_started = false;
+ return true;
+}
+
+int
+fusb_ephandle_ra_wb::write (const void *buffer, int nbytes)
+{
+ if (!d_started)
+ 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_ra_wb::read (void *buffer, int nbytes)
+{
+ if (!d_started)
+ 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);
+}
+
+void
+fusb_ephandle_ra_wb::wait_for_completion ()
+{
+ // as the driver is implemented this only makes sense for write
+ if (d_ra_wb_on && !d_input_p) {
+ int fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
+ d_endpoint);
+ int kq = kqueue();
+ if (kq < 0)
+ return;
+ struct kevent evt;
+ int nevents;
+ EV_SET (&evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0/*NULL*/);
+ nevents = kevent (kq, &evt, 1, &evt, 1, NULL);
+ if (nevents < 1) {
+ close(kq);
+ return;
+ }
+ while (!(evt.flags & EV_ERROR) && evt.data < (d_block_size*d_nblocks)) {
+ // it's a busy loop, but that's all I can do at the moment
+ nevents = kevent (kq, NULL, 0, &evt, 1, NULL);
+ // let's see if this improves the test_usrp_standard_tx throughput &
+ // "CPU usage" by looping less frequently
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1000; // 1 ms
+ select (0, NULL, NULL, NULL, &timeout);
+ }
+ close (kq);
+ }
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _FUSB_RA_WB_H_
+#define _FUSB_RA_WB_H_
+
+#include <fusb.h>
+
+/*!
+ * \brief generic implementation of fusb_devhandle using only libusb
+ */
+class fusb_devhandle_ra_wb : public fusb_devhandle
+{
+public:
+ // CREATORS
+ fusb_devhandle_ra_wb (usb_dev_handle *udh);
+ virtual ~fusb_devhandle_ra_wb ();
+
+ // 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_ra_wb : public fusb_ephandle
+{
+private:
+ fusb_devhandle_ra_wb *d_devhandle;
+ bool d_ra_wb_on;
+
+public:
+ // CREATORS
+ fusb_ephandle_ra_wb (fusb_devhandle_ra_wb *dh, int endpoint, bool input_p,
+ int block_size = 0, int nblocks = 0);
+ virtual ~fusb_ephandle_ra_wb ();
+
+ // 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_RA_WB_H_ */
+
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <fusb.h>
+#include <fusb_darwin.h>
+
+static const int MAX_BLOCK_SIZE = 32 * 1024; // hard limit
+static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB
+
+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;
+}
+
+int fusb_sysconfig::default_block_size ()
+{
+ return fusb_sysconfig::max_block_size ();
+}
+
+int fusb_sysconfig::default_buffer_size ()
+{
+ return FUSB_BUFFER_SIZE;
+}
+
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <fusb.h>
+#include <fusb_generic.h>
+
+static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
+static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB
+
+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;
+}
+
+int fusb_sysconfig::default_block_size ()
+{
+ return fusb_sysconfig::max_block_size ();
+}
+
+int fusb_sysconfig::default_buffer_size ()
+{
+ return FUSB_BUFFER_SIZE;
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <fusb.h>
+#include <fusb_linux.h>
+
+static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
+static const int DEFAULT_BLOCK_SIZE = 4 * 1024; // fewer kernel memory problems
+static const int FUSB_BUFFER_SIZE = 1 * (1L << 20); // 1MB
+
+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;
+}
+
+int fusb_sysconfig::default_block_size ()
+{
+ return DEFAULT_BLOCK_SIZE;
+}
+
+int fusb_sysconfig::default_buffer_size ()
+{
+ return FUSB_BUFFER_SIZE;
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <fusb.h>
+#include <fusb_ra_wb.h>
+
+//static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
+// there's no hard limit, even before making any changes to the driver
+// 64k is empirically a pretty good number
+static const int MAX_BLOCK_SIZE = 64 * 1024;
+// there is a limit of 1 MB in the driver for the buffer size
+static const int FUSB_BUFFER_SIZE = 256 * (1L << 10); // 256 kB
+
+fusb_devhandle *
+fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
+{
+ return new fusb_devhandle_ra_wb (udh);
+}
+
+int fusb_sysconfig::max_block_size ()
+{
+ return MAX_BLOCK_SIZE;
+}
+
+int fusb_sysconfig::default_block_size ()
+{
+ return fusb_sysconfig::max_block_size ();
+}
+
+int fusb_sysconfig::default_buffer_size ()
+{
+ return FUSB_BUFFER_SIZE;
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <fusb.h>
+#include <fusb_win32.h>
+
+static const int MAX_BLOCK_SIZE = 64 * 1024; // Windows kernel hard limit
+static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB
+
+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;
+}
+
+int fusb_sysconfig::default_block_size ()
+{
+ return fusb_sysconfig::max_block_size ();
+}
+
+int fusb_sysconfig::default_buffer_size ()
+{
+ return FUSB_BUFFER_SIZE;
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fusb_win32.h>
+#include <usb.h>
+#include <assert.h>
+#include <stdexcept>
+#include <string.h>
+
+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);
+ }
+
+ while (bytes_to_write > 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;
+ }
+ }
+
+ int ncopy = std::min(bytes_to_write, d_block_size);
+ memcpy(buf, (void *) &(((char*)buffer)[a]), ncopy);
+ bytes_to_write -= ncopy;
+ a += ncopy;
+
+ d_output_short = d_block_size - ncopy;
+ 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);
+ }
+
+ while (bytes_to_read > 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());
+
+ int ncopy = std::min(bytes_to_read, d_block_size);
+ memcpy((void *) &(((char*)buffer)[a]), buf, ncopy);
+ bytes_to_read -= ncopy;
+ a += ncopy;
+
+ d_input_leftover = d_block_size - ncopy;
+ 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;
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _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_ */
+
--- /dev/null
+#!/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('../include/usrp/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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <usrp/usrp_prims.h>
+#include <usrp/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()
+++ /dev/null
-#
-# Copyright 2007,2008 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-
-include $(top_srcdir)/Makefile.common
-
-AM_CPPFLAGS = \
- $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \
- $(USRP_INCLUDES) $(BOOST_CPPFLAGS) $(CPPUNIT_INCLUDES) \
- -I$(srcdir)/../../apps-inband $(WITH_INCLUDES)
-
-TESTS = test_inband
-
-EXTRA_DIST = \
- usrp_server.mbh \
- usrp_interface.mbh
-
-lib_LTLIBRARIES = \
- libusrp-inband.la \
- libusrp-inband-qa.la
-
-# ------------------------------------------------------------------------
-# Build the inband library
-
-BUILT_SOURCES = \
- usrp_server_mbh.cc \
- usrp_interface_mbh.cc
-
-usrp_server_mbh.cc : usrp_server.mbh
- $(COMPILE_MBH) $(srcdir)/usrp_server.mbh usrp_server_mbh.cc
-
-usrp_interface_mbh.cc : usrp_interface.mbh
- $(COMPILE_MBH) $(srcdir)/usrp_interface.mbh usrp_interface_mbh.cc
-
-libusrp_inband_la_SOURCES = \
- $(BUILT_SOURCES) \
- $(srcdir)/../../apps-inband/ui_sincos.c \
- usrp_inband_usb_packet.cc \
- usrp_rx.cc \
- usrp_rx_stub.cc \
- usrp_server.cc \
- usrp_tx.cc \
- usrp_tx_stub.cc \
- usrp_usb_interface.cc
-
-libusrp_inband_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
-
-libusrp_inband_la_LIBADD = \
- $(MBLOCK_LA) \
- $(USRP_LA) \
- -lstdc++
-
-include_HEADERS = \
- usrp_inband_usb_packet.h \
- usrp_rx.h \
- usrp_rx_stub.h \
- usrp_server.h \
- usrp_tx.h \
- usrp_tx_stub.h \
- usrp_usb_interface.h
-
-noinst_HEADERS = \
- qa_inband.h \
- qa_inband_packet_prims.h \
- qa_inband_usrp_server.h \
- symbols_usrp_channel.h \
- symbols_usrp_interface_cs.h \
- symbols_usrp_low_level_cs.h \
- symbols_usrp_rx.h \
- symbols_usrp_rx_cs.h \
- symbols_usrp_server_cs.h \
- symbols_usrp_tx.h \
- symbols_usrp_tx_cs.h
-
-# ------------------------------------------------------------------------
-# Build the qa code in its own library
-
-libusrp_inband_qa_la_SOURCES = \
- qa_inband.cc \
- qa_inband_packet_prims.cc \
- qa_inband_usrp_server.cc
-
-# magic flags
-libusrp_inband_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version
-
-libusrp_inband_qa_la_LIBADD = \
- libusrp-inband.la \
- $(PMT_LA) \
- $(CPPUNIT_LIBS) \
- -lstdc++
-
-# ------------------------------------------------------------------------
-
-noinst_PROGRAMS = \
- test_inband
-
-test_inband_SOURCES = test_inband.cc
-test_inband_LDADD = libusrp-inband-qa.la
+++ /dev/null
-#!/usr/bin/env python
-#
-# Copyright 2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-
-import sys
-import struct
-from optparse import OptionParser
-
-from usb_packet import *
-
-def dump_packet(raw_pkt, outfile, dump_payload):
- pkt = usb_packet(raw_pkt)
- outfile.write(pkt.decoded_flags())
- outfile.write(' chan= %2d len= %3d timestamp= 0x%08x rssi= % 2d tag= %2d\n' % (
- pkt.chan(), pkt.payload_len(), pkt.timestamp(), pkt.rssi(), pkt.tag()))
- if dump_payload:
- assert pkt.payload_len() % 4 == 0
- shorts = struct.unpack('<%dh' % (pkt.payload_len() // 2), pkt.payload())
- for i in range(0, len(shorts), 2):
- outfile.write(' %6d, %6d\n' % (shorts[i], shorts[i+1]))
-
-
-def dump_packets(infile, outfile, dump_payload):
- raw_pkt = infile.read(512)
- while raw_pkt:
- if len(raw_pkt) != 512:
- sys.stderr.write("File length is not a multiple of 512 bytes")
- raise SystemExit, 1
-
- dump_packet(raw_pkt, outfile, dump_payload)
- raw_pkt = infile.read(512)
-
-
-def main():
- parser = OptionParser()
- parser.add_option('-p', '--dump-payload', action='store_true', default=False,
- help='dump payload in decimal and hex')
-
- (options, files) = parser.parse_args()
- if len(files) == 0:
- dump_packets(sys.stdin, sys.stdout, options.dump_payload)
- else:
- for f in files:
- dump_packets(open(f, "r"), sys.stdout, options.dump_payload)
-
-
-if __name__ == '__main__':
- main()
+++ /dev/null
-#!/usr/bin/env python
-
-import random
-import struct
-from pprint import pprint
-from usb_packet import *
-
-MAX_PAYLOAD = 504
-TIME_NOW = 0xffffffff
-
-
-class sequence_generator(object):
- def __init__(self):
- self.i = 0
-
- def __call__(self):
- t = self.i
- self.i += 1
- return t
-
-def gen_shuffled_lengths():
- valid_lengths = range(0, MAX_PAYLOAD+1, 4) # [0, 4, 8, ... 504]
- random.shuffle(valid_lengths)
- return valid_lengths
-
-
-class packet_sequence_generator(object):
- def __init__(self, channel, lengths):
- self.next = sequence_generator()
- self.channel = channel
- self.lengths = lengths
-
- def __call__(self, output_file):
- gen_packet(output_file, self.channel, self.next, self.lengths[0])
- del self.lengths[0]
-
-
-def gen_packet(output_file, channel, content_generator, payload_len):
- assert (payload_len % 4) == 0
- payload = []
- n_iq = payload_len // 4
- for n in range(n_iq):
- payload.append(content_generator()) # I
- payload.append(content_generator()) # Q
- for n in range(MAX_PAYLOAD // 4 - n_iq):
- payload.append(0x0000)
- payload.append(0xffff)
-
- assert (len(payload) == MAX_PAYLOAD // 2)
-
- #print "\npayload_len =", payload_len
- #pprint(payload)
-
- output_file.write(make_header(FL_START_OF_BURST|FL_END_OF_BURST,
- channel, payload_len, TIME_NOW))
- output_file.write(struct.pack('<252h', *payload))
-
-
-def gen_all_valid_packet_lengths_1_channel(output_file):
- lengths = gen_shuffled_lengths()
- npkts = len(lengths) # number of packets we'll generator on each stream
- pkt_gen_0 = packet_sequence_generator(0, lengths)
- for i in range(npkts):
- pkt_gen_0(output_file)
-
- assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
-
-
-def gen_all_valid_packet_lengths_2_channels(output_file):
- lengths = gen_shuffled_lengths()
- npkts = len(lengths) # number of packets we'll generator on each stream
- pkt_gen_0 = packet_sequence_generator(0, lengths)
- pkt_gen_1 = packet_sequence_generator(0x1f, gen_shuffled_lengths())
- pkt_gen = (pkt_gen_0, pkt_gen_1)
-
- which_gen = (npkts * [0]) + (npkts * [1])
- random.shuffle(which_gen)
-
- for i in which_gen:
- pkt_gen[i](output_file)
-
- assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
- assert pkt_gen_1.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
-
-if __name__ == '__main__':
- random.seed(0)
- gen_all_valid_packet_lengths_1_channel(open("all_valid_packet_lengths_1_channel.dat", "w"))
- gen_all_valid_packet_lengths_2_channels(open("all_valid_packet_lengths_2_channels.dat", "w"))
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <qa_inband.h>
-#include <qa_inband_packet_prims.h>
-#include <qa_inband_usrp_server.h>
-
-CppUnit::TestSuite *
-qa_inband::suite()
-{
- CppUnit::TestSuite *s = new CppUnit::TestSuite("inband");
-
- s->addTest (qa_inband_packet_prims::suite());
- s->addTest (qa_inband_usrp_server::suite());
-
- return s;
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef INCLUDED_QA_INBAND_H
-#define INCLUDED_QA_INBAND_H
-
-#include <cppunit/TestSuite.h>
-
-//! collect all the tests for the user server
-
-class qa_inband {
- public:
- //! return suite of tests for all of usrp server
- static CppUnit::TestSuite *suite();
-};
-
-#endif /* INCLUDED_QA_INBAND_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <qa_inband_packet_prims.h>
-#include <cppunit/TestAssert.h>
-#include <stdio.h>
-#include <string.h>
-#include <usrp_inband_usb_packet.h> // will change on gigabit crossover
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-void
-qa_inband_packet_prims::test_flags()
-{
- transport_pkt pkt;
-
- // Test each one of the flags while ensuring no other fields become set in the process
- pkt.set_header(pkt.FL_START_OF_BURST,0,0,0);
- CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
- pkt.set_header(pkt.FL_END_OF_BURST,0,0,0);
- CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
- pkt.set_header(pkt.FL_OVERRUN,0,0,0);
- CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
- pkt.set_header(pkt.FL_UNDERRUN,0,0,0);
- CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
- pkt.set_header(pkt.FL_DROPPED,0,0,0);
- CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
- // test of all fields set
- pkt.set_header(
- pkt.FL_START_OF_BURST |
- pkt.FL_END_OF_BURST |
- pkt.FL_UNDERRUN |
- pkt.FL_OVERRUN |
- pkt.FL_DROPPED
- ,0,0,0);
- CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
-
-}
-//////////////////////////////////////////////////////////////////////
-
-void
-qa_inband_packet_prims::test_fields()
-{
- transport_pkt pkt;
- void * payload;
-
- // test word0 field exclusiveness
- //
- // I want to test max values of each field to ensure field boundaries
- // but these max values could change based on technology? The
- // max payload is returned by a private method so the code is not
- // technology dependent
- pkt.set_header(0,16,0,0);
- CPPUNIT_ASSERT_EQUAL(16, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
-
- pkt.set_header(0,0,8,0);
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(8, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0,pkt.payload_len());
-
- pkt.set_header(0,0,0,pkt.max_payload());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(pkt.max_payload(), pkt.payload_len());
-
- // test timestamp, shouldn't have to test other fields since
- // setting the timestamp only has the ability to affect one word
- pkt.set_timestamp(54);
- CPPUNIT_ASSERT_EQUAL(uint32_t(54), pkt.timestamp());
-
- // test the payload, ensure no other fields overwritten
- //
- // is there a better test for this?
- pkt.set_header(0,0,0,0);
- payload = malloc(pkt.payload_len());
- memset(payload, 'f', pkt.payload_len());
- memcpy(pkt.payload(), payload, pkt.payload_len());
- CPPUNIT_ASSERT_EQUAL(0, memcmp(pkt.payload(), payload, pkt.payload_len()));
- CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
- CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
- CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
- CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
- CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
- CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
- free(payload);
-
-}
-//////////////////////////////////////////////////////////////////////
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef QA_INBAND_PACKET_PRIMS_H
-#define QA_INBAND_PACKET_PRIMS_H
-
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/TestCase.h>
-
-class qa_inband_packet_prims : public CppUnit::TestCase {
-
- CPPUNIT_TEST_SUITE(qa_inband_packet_prims);
- CPPUNIT_TEST(test_flags);
- CPPUNIT_TEST(test_fields);
- CPPUNIT_TEST_SUITE_END();
-
- private:
- void test_flags();
- void test_fields();
-
-};
-
-#endif /* INCLUDED_QA_INBAND_PACKET_PRIMS_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <usrp_inband_usb_packet.h>
-#include <qa_inband_usrp_server.h>
-#include <cppunit/TestAssert.h>
-#include <stdio.h>
-#include <usrp_server.h>
-#include <mblock/mblock.h>
-#include <mblock/runtime.h>
-#include <mblock/protocol_class.h>
-#include <mblock/class_registry.h>
-#include <vector>
-#include <iostream>
-#include <pmt.h>
-
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_tx.h>
-#include <symbols_usrp_rx.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_low_level_cs.h>
-
-typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
-
-static bool verbose = false;
-
-static pmt_t s_timeout = pmt_intern("%timeout");
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_alloc_top : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- long d_nmsgs_to_recv;
- long d_nrecvd;
-
- long d_max_capacity;
- long d_ntx_chan, d_nrx_chan;
-
- long d_nstatus;
- long d_nstatus_to_recv;
-
- public:
- qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_alloc_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void check_message(mb_message_sptr msg);
- void run_tests();
-};
-
-qa_alloc_top::qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg)
-{
- d_nrecvd=0;
- d_nmsgs_to_recv = 6;
- d_nstatus=0;
- d_nstatus_to_recv = 50;
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_server_dict = pmt_make_dict();
- pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_server_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-qa_alloc_top::~qa_alloc_top(){}
-
-void
-qa_alloc_top::initial_transition()
-{
- // Allocations should fail before open
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel,
- s_err_usrp_not_opened),
- pmt_from_long(1)));
-
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel,
- s_err_usrp_not_opened),
- pmt_from_long(1)));
-
- // Retrieve information about the USRP, then run tests
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open, PMT_T),
- pmt_from_long(0)));
-
- d_cs->send(s_cmd_max_capacity,
- pmt_list1(pmt_list2(s_response_max_capacity, PMT_T)));
-
- d_cs->send(s_cmd_ntx_chan,
- pmt_list1(pmt_list2(s_response_ntx_chan, PMT_T)));
-
- d_cs->send(s_cmd_nrx_chan,
- pmt_list1(pmt_list2(s_response_nrx_chan,PMT_T)));
-}
-
-void
-qa_alloc_top::run_tests()
-{
- if(verbose)
- std::cout << "[qa_alloc_top] Starting tests...\n";
-
- // should be able to allocate 1 byte
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(PMT_T, pmt_from_long(1)));
-
- // should not be able to allocate max capacity after 100 bytes were allocated
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(s_err_requested_capacity_unavailable,
- pmt_from_long(d_max_capacity)));
-
- // keep allocating a little more until all of the channels are used and test
- // the error response we start at 1 since we've already allocated 1 channel
- for(int i=1; i < d_ntx_chan; i++) {
-
- if(verbose)
- std::cout << "[qa_alloc_top] Sent allocation request...\n";
-
- d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
-
- d_nmsgs_to_recv++;
- }
-
- // No more channels after allocating all of them is expected
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(s_err_channel_unavailable,
- pmt_from_long(1)));
-
- // test out the same on the RX side
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
-
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(s_err_requested_capacity_unavailable,
- pmt_from_long(d_max_capacity)));
-
- for(int i=1; i < d_nrx_chan; i++) {
-
- d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
-
- d_nmsgs_to_recv++;
- }
-
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(s_err_channel_unavailable,
- pmt_from_long(1)));
-
- // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes
- // allocated
- d_cs->send(s_cmd_current_capacity_allocation,
- pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan)));
-}
-
-void
-qa_alloc_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
-
- if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
- || pmt_eq(msg->port_id(), d_rx->port_symbol()))
- && pmt_eq(msg->signal(), s_response_allocate_channel))
- check_message(msg);
-
- if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
-
- if(pmt_eq(msg->signal(), s_response_max_capacity)) {
- d_max_capacity = pmt_to_long(pmt_nth(2, data));
- if(verbose)
- std::cout << "[qa_alloc_top] USRP has max capacity of "
- << d_max_capacity << "\n";
- }
- else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
- d_ntx_chan = pmt_to_long(pmt_nth(2, data));
- if(verbose)
- std::cout << "[qa_alloc_top] USRP tx channels: "
- << d_ntx_chan << "\n";
- }
- else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
- d_nrx_chan = pmt_to_long(pmt_nth(2, data));
- if(verbose)
- std::cout << "[qa_alloc_top] USRP rx channels: "
- << d_nrx_chan << "\n";
- }
- else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
- check_message(msg);
- }
-
- d_nstatus++;
-
- check_message(msg);
-
- if(d_nstatus==d_nstatus_to_recv)
- run_tests();
- }
-}
-
-void
-qa_alloc_top::check_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
-
- pmt_t e_event = pmt_nth(0, expected);
- pmt_t e_status = pmt_nth(1, expected);
-
- d_nrecvd++;
-
-
- if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
- if(verbose)
- std::cout << "Got: " << status << " Expected: " << e_status << "\n";
- shutdown_all(PMT_F);
- return;
- } else {
- if(verbose)
- std::cout << "[qa_alloc_top] Received expected response for message "
- << d_nrecvd << " (" << event << ")\n";
- }
-
- if(d_nrecvd == d_nmsgs_to_recv)
- shutdown_all(PMT_T);
-}
-
-REGISTER_MBLOCK_CLASS(qa_alloc_top);
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_dealloc_top : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- long d_max_capacity;
- long d_ntx_chan, d_nrx_chan;
-
- long d_nstatus;
- long d_nstatus_to_recv;
-
- long d_nalloc_to_recv;
- long d_nalloc_recvd;
-
- long d_ndealloc_to_recv;
- long d_ndealloc_recvd;
-
- std::vector<long> d_tx_chans;
- std::vector<long> d_rx_chans;
-
- public:
- qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_dealloc_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void check_allocation(mb_message_sptr msg);
- void check_deallocation(mb_message_sptr msg);
- void allocate_max();
- void deallocate_all();
-};
-
-qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg)
-{
- d_ndealloc_recvd=0;
- d_ndealloc_to_recv = 0;
- d_nalloc_recvd=0;
- d_nalloc_to_recv = 0; // auto-set
- d_nstatus=0;
- d_nstatus_to_recv = 4;
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_server_dict = pmt_make_dict();
- pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_server_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-}
-
-qa_dealloc_top::~qa_dealloc_top(){}
-
-void
-qa_dealloc_top::initial_transition()
-{
-
- if(verbose)
- std::cout << "[qa_dealloc_top] Initializing...\n";
-
- // Retrieve information about the USRP, then run tests
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open,PMT_T),
- pmt_from_long(0)));
-
- d_cs->send(s_cmd_max_capacity,
- pmt_list1(pmt_list2(s_response_max_capacity,PMT_T)));
-
- d_cs->send(s_cmd_ntx_chan,
- pmt_list1(pmt_list2(s_response_ntx_chan,PMT_T)));
-
- d_cs->send(s_cmd_nrx_chan,
- pmt_list1(pmt_list2(s_response_nrx_chan,PMT_T)));
-}
-
-void
-qa_dealloc_top::allocate_max()
-{
-
- // Keep allocating until we hit the maximum number of channels
- for(int i=0; i < d_ntx_chan; i++) {
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T),
- pmt_from_long(1))); // 1 byte is good enough
-
- d_nalloc_to_recv++;
- }
-
- for(int i=0; i < d_nrx_chan; i++) {
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T),
- pmt_from_long(1)));
-
- d_nalloc_to_recv++;
- }
-
-}
-
-void
-qa_dealloc_top::deallocate_all() {
-
- // Deallocate all of the channels that were allocated from allocate_max()
- for(int i=0; i < (int)d_tx_chans.size(); i++) {
-
- if(verbose)
- std::cout << "[qa_dealloc_top] Trying to dealloc TX "
- << d_tx_chans[i] << std::endl;
-
- d_tx->send(s_cmd_deallocate_channel,
- pmt_list2(pmt_list2(s_response_deallocate_channel,PMT_T),
- pmt_from_long(d_tx_chans[i])));
-
- d_ndealloc_to_recv++;
- }
-
- // Deallocate the RX side now
- for(int i=0; i < (int)d_rx_chans.size(); i++) {
-
- if(verbose)
- std::cout << "[qa_dealloc_top] Trying to dealloc RX "
- << d_tx_chans[i] << std::endl;
-
- d_rx->send(s_cmd_deallocate_channel,
- pmt_list2(pmt_list2(s_response_deallocate_channel,PMT_T),
- pmt_from_long(d_rx_chans[i])));
-
- d_ndealloc_to_recv++;
- }
-
- // Should get permission denied errors trying to re-dealloc the channels, as
- // we no longer have permission to them after deallocating
- for(int i=0; i < (int)d_tx_chans.size(); i++) {
-
- d_tx->send(s_cmd_deallocate_channel,
- pmt_list2(pmt_list2(s_response_deallocate_channel,
- s_err_channel_permission_denied),
- pmt_from_long(d_tx_chans[i])));
-
- d_ndealloc_to_recv++;
- }
-
- // Same for RX
- for(int i=0; i < (int)d_rx_chans.size(); i++) {
-
- d_rx->send(s_cmd_deallocate_channel,
- pmt_list2(pmt_list2(s_response_deallocate_channel,
- s_err_channel_permission_denied),
- pmt_from_long(d_rx_chans[i])));
-
- d_ndealloc_to_recv++;
- }
-
- // Try to deallocate a channel that doesn't exist on both sides, the last
- // element in the vectors is the highest channel number, so we take that plus
- // 1
- d_ndealloc_to_recv+=2;
- d_tx->send(s_cmd_deallocate_channel,
- pmt_list2(pmt_list2(s_response_deallocate_channel,
- s_err_channel_invalid),
- pmt_from_long(d_rx_chans.back()+1)));
-
- d_rx->send(s_cmd_deallocate_channel,
- pmt_list2(pmt_list2(s_response_deallocate_channel,
- s_err_channel_invalid),
- pmt_from_long(d_rx_chans.back()+1)));
-
-
- // The used capacity should be back to 0 now that we've deallocated everything
- d_cs->send(s_cmd_current_capacity_allocation,
- pmt_list1(pmt_list2(s_response_current_capacity_allocation,
- PMT_T)));
-}
-
-void
-qa_dealloc_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- if(pmt_eq(event, pmt_intern("%shutdown")))
- return;
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
-
- pmt_t e_event = pmt_nth(0, expected);
- pmt_t e_status = pmt_nth(1, expected);
-
- if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
- if(verbose)
- std::cout << "Got: " << status << " Expected: " << e_status << "\n";
- shutdown_all(PMT_F);
- return;
- } else {
- if(verbose)
- std::cout << "[qa_alloc_top] Received expected response for message "
- << d_ndealloc_recvd
- << " (" << event << ")\n";
- }
-
- if (pmt_eq(msg->port_id(), d_tx->port_symbol())
- || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
-
- if(pmt_eq(msg->signal(), s_response_allocate_channel)) {
- check_allocation(msg);
- }
-
- }
-
- if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
-
- if(pmt_eq(msg->signal(), s_response_max_capacity)) {
- d_max_capacity = pmt_to_long(pmt_nth(2, data));
- }
- else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
- d_ntx_chan = pmt_to_long(pmt_nth(2, data));
- }
- else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
- d_nrx_chan = pmt_to_long(pmt_nth(2, data));
- }
- else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
- // the final command is a capacity check which should be 0, then we
- // shutdown
- pmt_t expected_result = pmt_from_long(0);
- pmt_t result = pmt_nth(2, data);
-
- if(pmt_eqv(expected_result, result)) {
- shutdown_all(PMT_T);
- return;
- } else {
- shutdown_all(PMT_F);
- return;
- }
- }
-
- d_nstatus++;
-
- if(d_nstatus==d_nstatus_to_recv)
- allocate_max();
- }
-}
-
-
-void
-qa_dealloc_top::check_allocation(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t channel = pmt_nth(2, data);
-
- d_nalloc_recvd++;
-
- if(!pmt_eqv(status, PMT_T)) {
- shutdown_all(PMT_F);
- return;
- } else {
- // store all of the allocate channel numbers
- if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
- d_tx_chans.push_back(pmt_to_long(channel));
- if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
- d_rx_chans.push_back(pmt_to_long(channel));
- }
-
- if(d_nalloc_recvd == d_nalloc_to_recv) {
-
- if(verbose) {
- std::cout << "[qa_dealloc_top] Allocated TX channels: ";
- for(int i=0; i < (int)d_tx_chans.size(); i++)
- std::cout << d_tx_chans[i] << " ";
-
- std::cout << "\n[qa_dealloc_top] Allocated RX channels: ";
- for(int i=0; i < (int)d_rx_chans.size(); i++)
- std::cout << d_rx_chans[i] << " ";
- std::cout << "\n";
- }
-
- deallocate_all(); // once we've allocated all of our channels, try to
- // dealloc them
- }
-}
-
-REGISTER_MBLOCK_CLASS(qa_dealloc_top);
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_open_close_top : public mb_mblock
-{
- mb_port_sptr d_cs;
-
- long d_max_capacity;
-
- long d_nmsg_to_recv;
- long d_nmsg_recvd;
-
- public:
- qa_open_close_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_open_close_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void check_cs(mb_message_sptr msg);
- void run_tests();
-};
-
-qa_open_close_top::qa_open_close_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg)
-{
-
- d_nmsg_to_recv=7;
- d_nmsg_recvd=0;
-
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_server_dict = pmt_make_dict();
- pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_server_dict);
- connect("self", "cs", "server", "cs");
-}
-
-qa_open_close_top::~qa_open_close_top(){}
-
-void
-qa_open_close_top::initial_transition()
-{
- run_tests();
-}
-
-void
-qa_open_close_top::run_tests()
-{
- // std::cout << "[qa_open_close_top] Starting tests\n";
-
- // A close before an open should fail
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,
- s_err_usrp_already_closed)));
-
- // Perform an open, and a second open which should fail
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open,PMT_T),
- pmt_from_long(0)));
-
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open,
- s_err_usrp_already_opened),
- pmt_from_long(0)));
-
- // A close should now be successful since the interface is open
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
-
- // But, a second close should fail
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,
- s_err_usrp_already_closed)));
-
- // Just to be thorough, try an open and close again
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open,PMT_T),
- pmt_from_long(0)));
-
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
-
-}
-
-
-void
-qa_open_close_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
-
- if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
- check_cs(msg);
- }
-
- d_nmsg_recvd++;
-
- if(d_nmsg_to_recv == d_nmsg_recvd)
- shutdown_all(PMT_T);
-}
-
-void
-qa_open_close_top::check_cs(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
-
- pmt_t e_event = pmt_nth(0, expected);
- pmt_t e_status = pmt_nth(1, expected);
-
- if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
-
- if(verbose)
- std::cout << "[qa_open_close_top] FAILED check_cs... Got: " << status
- << " Expected: " << e_status
- << " for event " << event << "\n";
-
- shutdown_all(PMT_F);
- } else {
- if(verbose)
- std::cout << "[qa_open_close_top] Received expected CS response ("
- << event << ")\n";
- }
-
-}
-
-REGISTER_MBLOCK_CLASS(qa_open_close_top);
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_tx_top : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- long d_max_capacity;
- long d_ntx_chan, d_nrx_chan;
-
- long d_tx_chan;
- long d_rx_chan;
-
- long d_nmsg_to_recv;
- long d_nmsg_recvd;
-
- public:
- qa_tx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_tx_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void check_allocation(mb_message_sptr msg);
- void check_deallocation(mb_message_sptr msg);
- void check_xmit(mb_message_sptr msg);
- void check_cs(mb_message_sptr msg);
- void run_tests();
-};
-
-qa_tx_top::qa_tx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg)
-{
-
- d_nmsg_to_recv=10;
- d_nmsg_recvd=0;
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_server_dict = pmt_make_dict();
- pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_server_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-}
-
-qa_tx_top::~qa_tx_top(){}
-
-void
-qa_tx_top::initial_transition()
-{
- run_tests();
-}
-
-void
-qa_tx_top::run_tests()
-{
- if(verbose)
- std::cout << "[qa_tx_top] Starting tests\n";
-
- // A transmit before an open should fail
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_list2(s_response_xmit_raw_frame,
- s_err_usrp_not_opened),
- pmt_from_long(0),
- pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
- pmt_from_long(0)));
-
- // Now open
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open,PMT_T),
- pmt_from_long(0)));
-
- // Try to transmit on a channel that we have no allocation for
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_list2(s_response_xmit_raw_frame,
- s_err_channel_permission_denied),
- pmt_from_long(0),
- pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
- pmt_from_long(0)));
-
- // Get a channel allocation and send on it, we assume 0 (FIXME) until 'defer'
- // is implemented for simplicity
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
- pmt_from_long(1)));
-
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_list2(s_response_xmit_raw_frame, PMT_T),
- pmt_from_long(0),
- pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
- pmt_from_long(0)));
-
- // Close should be successful
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
-
- // After closing, a new transmit raw frame should fail again
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_list2(s_response_xmit_raw_frame,
- s_err_usrp_not_opened),
- pmt_from_long(0),
- pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
- pmt_from_long(0)));
-
- // Reopen and retry before getting an allocation, the first xmit should fail,
- // after we allocate it should work again
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open, PMT_T),
- pmt_from_long(0)));
-
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_list2(s_response_xmit_raw_frame,
- s_err_channel_permission_denied),
- pmt_from_long(0),
- pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
- pmt_from_long(0)));
-
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
- pmt_from_long(1)));
-
- d_tx->send(s_cmd_xmit_raw_frame,
- pmt_list4(pmt_list2(s_response_xmit_raw_frame,PMT_T),
- pmt_from_long(0),
- pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
- pmt_from_long(0)));
-
- // A final close which should be successful
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
-
-}
-
-
-void
-qa_tx_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- if(pmt_eq(event, pmt_intern("%shutdown")))
- return;
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
-
- pmt_t e_event = pmt_nth(0, expected);
- pmt_t e_status = pmt_nth(1, expected);
-
- if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
- if(verbose)
- std::cout << "[qa_xmit_top] Got: " << status
- << " Expected: " << e_status
- << "For signal: " << event << "\n";
- shutdown_all(PMT_F);
- return;
- } else {
- if(verbose)
- std::cout << "[qa_xmit_top] Received expected response for message "
- << d_nmsg_recvd
- << " (" << event << ")\n";
- }
-
- if (pmt_eq(msg->port_id(), d_tx->port_symbol())
- || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
-
- if(pmt_eq(msg->signal(), s_response_allocate_channel))
- check_allocation(msg);
-
- }
-
- d_nmsg_recvd++;
-
- if(d_nmsg_to_recv == d_nmsg_recvd){
- shutdown_all(PMT_T);
- return;
- }
-}
-
-void
-qa_tx_top::check_allocation(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t channel = pmt_nth(2, data);
-
- if(pmt_eqv(status, PMT_T)) {
- // store all of the allocate channel numbers
- if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
- d_tx_chan = pmt_to_long(channel);
- if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
- d_rx_chan = pmt_to_long(channel);
- }
-}
-
-REGISTER_MBLOCK_CLASS(qa_tx_top);
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_rx_top : public mb_mblock
-{
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- long d_max_capacity;
- long d_ntx_chan, d_nrx_chan;
-
- long d_rx_chan;
-
- bool d_got_response_recv;
-
- mb_time d_t0;
- double d_delta_t;
-
- public:
- qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_rx_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void check_allocation(mb_message_sptr msg);
- void check_deallocation(mb_message_sptr msg);
- void check_xmit(mb_message_sptr msg);
- void check_cs(mb_message_sptr msg);
- void run_tests();
-};
-
-qa_rx_top::qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg),
- d_got_response_recv(false)
-{
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_dict = pmt_make_dict();
- // Set TX and RX interpolations
- pmt_dict_set(usrp_dict,
- pmt_intern("decim-rx"),
- pmt_from_long(128));
- pmt_dict_set(usrp_dict, pmt_intern("fake-usrp"), PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_dict);
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-}
-
-qa_rx_top::~qa_rx_top(){}
-
-void
-qa_rx_top::initial_transition()
-{
- run_tests();
-}
-
-void
-qa_rx_top::run_tests()
-{
- if(verbose)
- std::cout << "[qa_rx_top] Starting tests\n";
-
- d_cs->send(s_cmd_open, pmt_list2(pmt_list2(s_response_open,PMT_T), pmt_from_long(0)));
-
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T),
- pmt_from_long(1)));
-
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_NIL,
- pmt_from_long(0)));
-
- // Schedule a small timeout in which we expect to have received at least one
- // packet worth of samples from the stub
- d_t0 = mb_time::time();
- schedule_one_shot_timeout(d_t0 + 0.01, PMT_NIL);
-}
-
-
-void
-qa_rx_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- if(pmt_eq(event, pmt_intern("%shutdown")))
- return;
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
-
- // If we get a timeout we shutdown
- if(pmt_eq(event, s_timeout)) {
- if(verbose)
- std::cout << "[qa_rx_top] Got timeout\n";
- d_rx->send(s_cmd_stop_recv_raw_samples,
- pmt_list2(PMT_NIL,
- pmt_from_long(0)));
-
- d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
- return;
- }
-
- // For testing RX, an invocation handle is not generated by the stub,
- // therefore the same approach for testing is not used. We simply
- // expect all responses to be true.
- if(pmt_eq(event, s_response_recv_raw_samples)) {
- if(pmt_eqv(status, PMT_T)) {
-
- if(verbose)
- std::cout << "[qa_rx_top] Received expected response for message "
- << " (" << event << ")\n";
-
- // All we want is 1 response receive! Can't guarantee exact numbers
- d_got_response_recv = true;
- }
- else {
- if(verbose)
- std::cout << "Got: " << status << " Expected: " << PMT_T << "\n";
- shutdown_all(PMT_F);
- }
- return;
- }
-
- pmt_t e_event = pmt_nth(0, expected);
- pmt_t e_status = pmt_nth(1, expected);
-
- if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
- if(verbose)
- std::cout << "Got: " << status << " Expected: " << e_status << "\n";
- shutdown_all(PMT_F);
- return;
- } else {
- if(verbose)
- std::cout << "[qa_rx_top] Received expected response for message "
- << " (" << event << ")\n";
- }
-
- if (pmt_eq(msg->port_id(), d_rx->port_symbol())) {
-
- if(pmt_eq(msg->signal(), s_response_allocate_channel))
- check_allocation(msg);
-
- }
-
- // We stop when we get a close, we are successful if we
- // got a response from recv, fail if we never got a recv response
- if(pmt_eq(msg->signal(), s_response_close)) {
-
- if(d_got_response_recv) {
- shutdown_all(PMT_T);
- return;
- }
- else {
- shutdown_all(PMT_F);
- if(verbose)
- std::cout << "[qa_rx_top] No response message before close\n";
- return;
- }
- }
-}
-
-
-void
-qa_rx_top::check_allocation(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t channel = pmt_nth(2, data);
-
- if(pmt_eqv(status, PMT_T)) {
- // store all of the allocate channel numbers
- if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
- d_rx_chan = pmt_to_long(channel);
- }
-}
-
-REGISTER_MBLOCK_CLASS(qa_rx_top);
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_rid_top : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- long d_npongs;
- long d_tcycles;
- long d_cycles;
- long d_max_rid;
-
- mb_time d_t0;
- double d_delta_t;
-
- public:
- qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_rid_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void run_tests();
- void send_max_pings();
-};
-
-qa_rid_top::qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg)
-{
- d_npongs = 0;
- d_tcycles = 3;
- d_cycles = d_tcycles;
- d_max_rid = usrp_server::D_MAX_RID;
- d_delta_t = 0.1;
-
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_server_dict = pmt_make_dict();
- pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_server_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-qa_rid_top::~qa_rid_top(){}
-
-void
-qa_rid_top::initial_transition()
-{
- run_tests();
-}
-
-void
-qa_rid_top::run_tests()
-{
- if(verbose)
- std::cout << "[qa_rid_top] Starting tests...\n";
-
- // Retrieve information about the USRP, then run tests
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open, PMT_T),
- pmt_from_long(0)));
-
- // should be able to allocate 1 byte
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
- pmt_from_long(1)));
-
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
- pmt_from_long(1)));
-
- // Need to start receiving to read from the USRP to get C/S responses
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_NIL,
- pmt_from_long(0)));
-
- // Build a subpacket of MAX_RID pings and wait a small amount for all of the
- // responses and fire off another MAX_RID. If MAX_RID*2 responses are
- // received, the RID recycling is working correctly.
- // Schedule a timer in which we expect to have received all of the responses,
- // which will send off another MAX_RID worth.
- send_max_pings();
- d_t0 = mb_time::time();
- schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL);
-}
-
-void
-qa_rid_top::send_max_pings()
-{
- pmt_t ping = pmt_list2(s_op_ping_fixed,
- pmt_list2(pmt_from_long(0),
- pmt_from_long(0)));
-
- pmt_t sub_packets = PMT_NIL;
-
- for(int i=0; i<d_max_rid; i++)
- sub_packets = pmt_list_add(sub_packets, ping);
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- sub_packets));
-}
-
-void
-qa_rid_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- // If we get a timeout we ensure we got a maximum RID number of responses.
- if(pmt_eq(event, s_timeout)) {
- if(verbose)
- std::cout << "[qa_rid_top] Got timeout, received so far: "
- << d_npongs << "\n";
-
- d_cycles--;
-
- if(d_cycles==0 && d_npongs == d_max_rid*d_tcycles) {
- shutdown_all(PMT_T);
- }
- else if(d_cycles==0) {
-
- std::cout << "[qa_rid_top] d_npongs: " << d_npongs
- << " expected: " << d_max_rid*d_tcycles
- << std::endl;
-
- shutdown_all(PMT_F);
- }
- else {
- send_max_pings();
- d_t0 = mb_time::time();
- schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL);
- }
-
- }
- else if(pmt_eq(event, s_response_from_control_channel))
- {
- d_npongs++;
- }
-
-}
-
-REGISTER_MBLOCK_CLASS(qa_rid_top);
-
-
-// ----------------------------------------------------------------------------------------------
-
-class qa_cs_top : public mb_mblock
-{
- mb_port_sptr d_tx;
- mb_port_sptr d_rx;
- mb_port_sptr d_cs;
-
- long d_nmsgs_to_recv;
- long d_nrecvd;
-
- long d_max_capacity;
- long d_ntx_chan, d_nrx_chan;
-
- long d_nstatus;
- long d_nstatus_to_recv;
-
- public:
- qa_cs_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
- ~qa_cs_top();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- protected:
- void check_message(mb_message_sptr msg);
- void run_tests();
-};
-
-qa_cs_top::qa_cs_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(runtime, instance_name, user_arg)
-{
- d_nrecvd=0;
- d_nmsgs_to_recv = 8;
- d_nstatus=0;
- d_nstatus_to_recv = 50;
-
- d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
- d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
- d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
-
- // Use the stub with the usrp_server
- pmt_t usrp_server_dict = pmt_make_dict();
- pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
-
- // Test the TX side
- define_component("server", "usrp_server", usrp_server_dict);
- connect("self", "tx0", "server", "tx0");
- connect("self", "rx0", "server", "rx0");
- connect("self", "cs", "server", "cs");
-
-}
-
-qa_cs_top::~qa_cs_top(){}
-
-void
-qa_cs_top::initial_transition()
-{
- run_tests();
-}
-
-void
-qa_cs_top::run_tests()
-{
- if(verbose)
- std::cout << "[qa_cs_top] Starting tests...\n";
-
- // Retrieve information about the USRP, then run tests
- d_cs->send(s_cmd_open,
- pmt_list2(pmt_list2(s_response_open, PMT_T),
- pmt_from_long(0)));
-
- // should be able to allocate 1 byte
- d_tx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
- pmt_from_long(1)));
-
- d_rx->send(s_cmd_allocate_channel,
- pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
- pmt_from_long(1)));
-
- // Need to start receiving to read from the USRP to get C/S responses
- d_rx->send(s_cmd_start_recv_raw_samples,
- pmt_list2(PMT_NIL,
- pmt_from_long(0)));
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- pmt_list1(
- pmt_list2(s_op_ping_fixed,
- pmt_list2(pmt_from_long(3),
- pmt_from_long(0))))));
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- pmt_list1(
- pmt_list2(s_op_write_reg,
- pmt_list2(
- pmt_from_long(0x3),
- pmt_from_long(0x4))))));
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- pmt_list1(
- pmt_list2(s_op_write_reg_masked,
- pmt_list3(
- pmt_from_long(0x3),
- pmt_from_long(0x4),
- pmt_from_long(0x5))))));
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- pmt_list1(
- pmt_list2(s_op_read_reg,
- pmt_list2(pmt_from_long(0),
- pmt_from_long(0x6))))));
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- pmt_list1(
- pmt_list2(s_op_delay,
- pmt_list1(pmt_from_long(0x7))))));
-
- pmt_t subpackets = pmt_list5(
- pmt_list2(s_op_ping_fixed, pmt_list2(pmt_from_long(0), pmt_from_long(0))),
- pmt_list2(s_op_delay, pmt_list1(pmt_from_long(0x7))),
- pmt_list2(s_op_write_reg_masked, pmt_list3(pmt_from_long(3),
- pmt_from_long(4),
- pmt_from_long(5))),
- pmt_list2(s_op_write_reg, pmt_list2(pmt_from_long(3),
- pmt_from_long(4))),
- pmt_list2(s_op_read_reg, pmt_list2(pmt_from_long(0),
- pmt_from_long(6)))
- );
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- subpackets));
-
- pmt_t i2c_data = pmt_make_u8vector(8, 0xff);
-
- subpackets = pmt_list2(
- pmt_list2(s_op_i2c_write,
- pmt_list2(pmt_from_long(8), i2c_data)),
- pmt_list2(s_op_i2c_read,
- pmt_list3(pmt_from_long(0), pmt_from_long(9), pmt_from_long(1)))
-
- );
-
- d_tx->send(s_cmd_to_control_channel,
- pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
- subpackets));
-
-}
-
-void
-qa_cs_top::handle_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
-
- if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
- || pmt_eq(msg->port_id(), d_rx->port_symbol()))
- && pmt_eq(msg->signal(), s_response_allocate_channel))
- check_message(msg);
-
- if (pmt_eq(msg->port_id(), d_tx->port_symbol())
- && pmt_eq(msg->signal(), s_response_from_control_channel))
- check_message(msg);
-
- if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
-
- if(pmt_eq(msg->signal(), s_response_max_capacity)) {
- d_max_capacity = pmt_to_long(pmt_nth(2, data));
- if(verbose)
- std::cout << "[qa_cs_top] USRP has max capacity of "
- << d_max_capacity << "\n";
- }
- else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
- d_ntx_chan = pmt_to_long(pmt_nth(2, data));
- if(verbose)
- std::cout << "[qa_cs_top] USRP tx channels: "
- << d_ntx_chan << "\n";
- }
- else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
- d_nrx_chan = pmt_to_long(pmt_nth(2, data));
- if(verbose)
- std::cout << "[qa_cs_top] USRP rx channels: "
- << d_nrx_chan << "\n";
- }
- else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
- check_message(msg);
- }
-
- d_nstatus++;
-
- check_message(msg);
-
- if(d_nstatus==d_nstatus_to_recv)
- run_tests();
- }
-}
-
-void
-qa_cs_top::check_message(mb_message_sptr msg)
-{
- pmt_t data = msg->data();
- pmt_t event = msg->signal();
-
- pmt_t expected = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
-
- pmt_t e_event = pmt_nth(0, expected);
- pmt_t e_status = pmt_nth(1, expected);
-
- d_nrecvd++;
-
-
- if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
- if(verbose)
- std::cout << "[qa_cs_top] Got: " << status << " Expected: " << e_status << "\n";
- shutdown_all(PMT_F);
- return;
- } else {
- if(verbose)
- std::cout << "[qa_cs_top] Received expected response for message "
- << d_nrecvd << " (" << event << ")\n";
- }
-
- if(d_nrecvd == d_nmsgs_to_recv)
- shutdown_all(PMT_T);
-}
-
-REGISTER_MBLOCK_CLASS(qa_cs_top);
-
-// ----------------------------------------------------------------------------------------------
-
-void
-qa_inband_usrp_server::test_open_close()
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n----------------------------\n";
- // std::cout << " RUNNING OPEN/CLOSE TESTS \n";
-
- rt->run("top", "qa_open_close_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
-
-void
-qa_inband_usrp_server::test_chan_allocation()
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n----------------------------\n";
- // std::cout << " RUNNING ALLOCATION TESTS \n";
-
- rt->run("qa_alloc_top", "qa_alloc_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
-
-void
-qa_inband_usrp_server::test_chan_deallocation()
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n----------------------------\n";
- // std::cout << " RUNNING DEALLOCATION TESTS \n";
-
- rt->run("qa_dealloc_top", "qa_dealloc_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
-
-void
-qa_inband_usrp_server::test_tx()
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n-----------------\n";
- // std::cout << " RUNNING TX TESTS \n";
-
- rt->run("top", "qa_tx_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
-
-void
-qa_inband_usrp_server::test_rx()
-{
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n-----------------\n";
- // std::cout << " RUNNING RX TESTS \n";
-
- rt->run("top", "qa_rx_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
-
-void
-qa_inband_usrp_server::test_cs()
-{
- // FIXME This test is disabled because it hangs with the change to use usrp_standard_*_sptr's
- return;
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n-----------------\n";
- // std::cout << " RUNNING CS TESTS \n";
-
- rt->run("top", "qa_cs_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
-
-void
-qa_inband_usrp_server::test_rid()
-{
- // FIXME This test is disabled because it hangs with the change to use usrp_standard_*_sptr's
- return;
-
- mb_runtime_sptr rt = mb_make_runtime();
- pmt_t result = PMT_T;
-
- // std::cout << "\n\n-----------------\n";
- // std::cout << " RUNNING RID TESTS \n";
-
- rt->run("top", "qa_rid_top", PMT_F, &result);
-
- CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef QA_INBAND_USRP_SERVER_H
-#define QA_INBAND_USRP_SERVER_H
-
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/TestCase.h>
-
-class qa_inband_usrp_server : public CppUnit::TestCase {
-
- CPPUNIT_TEST_SUITE(qa_inband_usrp_server);
- CPPUNIT_TEST(test_open_close);
- CPPUNIT_TEST(test_chan_allocation);
- CPPUNIT_TEST(test_chan_deallocation);
- CPPUNIT_TEST(test_tx);
- CPPUNIT_TEST(test_rx);
- CPPUNIT_TEST(test_cs);
- CPPUNIT_TEST(test_rid);
- CPPUNIT_TEST_SUITE_END();
-
- private:
- void test_chan_allocation();
- void test_chan_deallocation();
- void test_open_close();
- void test_tx();
- void test_rx();
- void test_cs();
- void test_rid();
-};
-
-#endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_CHANNEL_H
-#define INCLUDED_SYMBOLS_USRP_CHANNEL_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel");
-static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel");
-
-// Incoming
-static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel");
-static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel");
-
-// Errors
-static pmt_t s_err_requested_capacity_unavailable = pmt_intern("err-requested-capacity-unavailable");
-static pmt_t s_err_channel_unavailable = pmt_intern("err-channel-unavailable");
-static pmt_t s_err_channel_invalid = pmt_intern("err-channel-invalid");
-static pmt_t s_err_channel_permission_denied = pmt_intern("err-channel-permission-denied");
-
-#endif /* INCLUDED_SYMBOLS_USRP_CHANNEL_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H
-#define INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_usrp_open = pmt_intern("cmd-usrp-open");
-static pmt_t s_cmd_usrp_close = pmt_intern("cmd-usrp-close");
-static pmt_t s_cmd_usrp_ntx_chan = pmt_intern("cmd-usrp-ntx-chan");
-static pmt_t s_cmd_usrp_nrx_chan = pmt_intern("cmd-usrp-nrx-chan");
-static pmt_t s_cmd_usrp_write = pmt_intern("cmd-usrp-write");
-static pmt_t s_cmd_usrp_start_reading = pmt_intern("cmd-usrp-start-reading");
-static pmt_t s_cmd_usrp_stop_reading = pmt_intern("cmd-usrp-stop-reading");
-
-// Incoming
-static pmt_t s_response_usrp_open = pmt_intern("response-usrp-open");
-static pmt_t s_response_usrp_close = pmt_intern("response-usrp-close");
-static pmt_t s_response_usrp_ntx_chan = pmt_intern("response-usrp-ntx-chan");
-static pmt_t s_response_usrp_nrx_chan = pmt_intern("response-usrp-nrx-chan");
-static pmt_t s_response_usrp_write = pmt_intern("response-usrp-write");
-static pmt_t s_response_usrp_read = pmt_intern("response-usrp-read");
-
-#endif /* INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H
-#define INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel");
-
-// Incoming
-static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel");
-
-// Subpackets
-static pmt_t s_op_ping_fixed = pmt_intern("op-ping-fixed");
-static pmt_t s_op_ping_fixed_reply = pmt_intern("op-ping-fixed-reply");
-static pmt_t s_op_write_reg = pmt_intern("op-write-reg");
-static pmt_t s_op_write_reg_masked = pmt_intern("op-write-reg-masked");
-static pmt_t s_op_read_reg = pmt_intern("op-read-reg");
-static pmt_t s_op_read_reg_reply = pmt_intern("op-read-reg-reply");
-static pmt_t s_op_i2c_write = pmt_intern("op-i2c-write");
-static pmt_t s_op_i2c_read = pmt_intern("op-i2c-read");
-static pmt_t s_op_i2c_read_reply = pmt_intern("op-i2c-read-reply");
-static pmt_t s_op_spi_write = pmt_intern("op-spi-write");
-static pmt_t s_op_spi_read = pmt_intern("op-spi-read");
-static pmt_t s_op_spi_read_reply = pmt_intern("op-spi-read-reply");
-static pmt_t s_op_delay = pmt_intern("op-delay");
-
-#endif /* INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_RX_H
-#define INCLUDED_SYMBOLS_USRP_RX_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples");
-static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples");
-
-// Incoming
-static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples");
-
-// Errors
-static pmt_t s_err_already_receiving = pmt_intern("err-already-receiving");
-
-#endif /* INCLUDED_SYMBOLS_USRP_RX_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_RX_CS_H
-#define INCLUDED_SYMBOLS_USRP_RX_CS_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_usrp_rx_start_reading = pmt_intern("cmd-usrp-rx-start-reading");
-
-// Incoming
-static pmt_t s_response_usrp_rx_read = pmt_intern("response-usrp-rx-read");
-
-#endif /* INCLUDED_SYMBOLS_USRP_RX_CS_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_SERVER_CS_H
-#define INCLUDED_SYMBOLS_USRP_SERVER_CS_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_open = pmt_intern("cmd-open");
-static pmt_t s_cmd_close = pmt_intern("cmd-close");
-static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity");
-static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan");
-static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan");
-static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation");
-
-// Incoming
-static pmt_t s_response_open = pmt_intern("response-open");
-static pmt_t s_response_close = pmt_intern("response-close");
-static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity");
-static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan");
-static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan");
-static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation");
-
-// Errors
-static pmt_t s_err_usrp_not_opened = pmt_intern("err-usrp-not-opened");
-static pmt_t s_err_usrp_already_opened = pmt_intern("err-usrp-already-opened");
-static pmt_t s_err_usrp_already_closed = pmt_intern("err-usrp-already-closed");
-
-#endif /* INCLUDED_SYMBOLS_USRP_SERVER_CS_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_TX_H
-#define INCLUDED_SYMBOLS_USRP_TX_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame");
-
-// Incoming
-static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame");
-
-#endif /* INCLUDED_SYMBOLS_USRP_TX_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_SYMBOLS_USRP_TX_CS_H
-#define INCLUDED_SYMBOLS_USRP_TX_CS_H
-
-#include <pmt.h>
-
-// Outgoing
-static pmt_t s_cmd_usrp_tx_write = pmt_intern("cmd-usrp-tx-write");
-
-// Incoming
-static pmt_t s_response_usrp_tx_write = pmt_intern("response-usrp-tx-write");
-
-#endif /* INCLUDED_SYMBOLS_USRP_TX_CS_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <cppunit/TextTestRunner.h>
-#include <qa_inband.h>
-
-int
-main(int argc, char **argv)
-{
-
- CppUnit::TextTestRunner runner;
-
- runner.addTest(qa_inband::suite ());
-
- bool was_successful = runner.run("", false);
-
- return was_successful ? 0 : 1;
-}
+++ /dev/null
-#
-# Copyright 2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-
-import struct
-
-
-FL_OVERRUN = 0x80000000
-FL_UNDERRUN = 0x40000000
-FL_DROPPED = 0x20000000
-FL_END_OF_BURST = 0x10000000
-FL_START_OF_BURST = 0x08000000
-
-FL_ALL_FLAGS = 0xf8000000
-
-FL_OVERRUN_SHIFT = 31
-FL_UNDERRUN_SHIFT = 30
-FL_DROPPED_SHIFT = 29
-FL_END_OF_BURST_SHIFT = 28
-FL_START_OF_BURST_SHIFT = 27
-
-RSSI_MASK = 0x3f
-RSSI_SHIFT = 21
-
-CHAN_MASK = 0x1f
-CHAN_SHIFT = 16
-
-TAG_MASK = 0xf
-TAG_SHIFT = 9
-
-PAYLOAD_LEN_MASK = 0x1ff
-PAYLOAD_LEN_SHIFT = 0
-
-def make_header(flags, chan, payload_len, timestamp, rssi=0, tag=0):
- word0 = ((flags & FL_ALL_FLAGS)
- | ((rssi & RSSI_MASK) << RSSI_SHIFT)
- | ((chan & CHAN_MASK) << CHAN_SHIFT)
- | ((tag & TAG_MASK) << TAG_SHIFT)
- | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT))
- word1 = timestamp
- return struct.pack('<2I', word0, word1)
-
-
-def _decode(pred, indicator):
- if pred:
- return indicator
- else:
- return '-'
-
-
-class usb_packet(object):
- def __init__(self, raw_pkt):
- assert isinstance(raw_pkt, str) and len(raw_pkt) == 512
- self._raw_pkt = raw_pkt;
- (self._word0, self._word1) = struct.unpack('<2I', self._raw_pkt[0:8])
-
- def timestamp(self):
- return self._word1
-
- def rssi(self):
- return (self._word0 >> RSSI_SHIFT) & RSSI_MASK
-
- def chan(self):
- return (self._word0 >> CHAN_SHIFT) & CHAN_MASK
-
- def tag(self):
- return (self._word0 >> TAG_SHIFT) & TAG_MASK
-
- def payload_len(self):
- return (self._word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK
-
- def flags(self):
- return self._word0 & FL_ALL_FLAGS
-
- def overrun(self):
- return (self._word0 >> FL_OVERRUN_SHIFT) & 0x1
-
- def underrun(self):
- return (self._word0 >> FL_UNDERRUN_SHIFT) & 0x1
-
- def start_of_burst(self):
- return (self._word0 >> FL_START_OF_BURST_SHIFT) & 0x1
-
- def end_of_burst(self):
- return (self._word0 >> FL_END_OF_BURST_SHIFT) & 0x1
-
- def dropped(self):
- return (self._word0 >> FL_DROPPED_SHIFT) & 0x1
-
- def payload(self):
- return self._raw_pkt[8:8+self.payload_len()]
-
- def decoded_flags(self):
- s = (_decode(self.overrun(), 'O')
- + _decode(self.underrun(), 'U')
- + _decode(self.dropped(), 'D')
- + _decode(self.end_of_burst(), 'E')
- + _decode(self.start_of_burst(), 'S'))
- return s
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <usrp_inband_usb_packet.h>
-
-#include <usrp_bytesex.h>
-#include <iostream>
-#include <stdio.h>
-#include <string.h>
-
-/*!
- * \brief Aligns the packet payload on a 32 bit boundary. This is essential to
- * all control/status packets so that the inband FPGA code can parse them
- * easily.
- *
- * \returns true if successful or if the packet was already aligned; false if it
- * cannot be aligned.
- */
-bool usrp_inband_usb_packet::align32()
-{
- int p_len = payload_len();
-
- int bytes_needed = 4 - (p_len % 4);
-
- if(bytes_needed == 4)
- return true;
-
- // If the room left in the packet is less than the number of bytes
- // needed, return false to indicate no room to align
- if((MAX_PAYLOAD - p_len) < bytes_needed)
- return false;
-
- incr_header_len(bytes_needed);
-
- return true;
-}
-
-/*!
- * \brief Adds a ping command to the current control packet.
- *
- * The \p rid is the rid to be associated with the ping response and \p ping_val
- * is currently unused.
- *
- * \returns true if adding the ping command was successful, false otherwise
- * (i.e. no space in the current packet).
- */
-bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_PING_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t ping = (
- ((OP_PING_FIXED & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_PING_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- | (ping_val & CS_PINGVAL_MASK)
-
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(ping);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_PING_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds a ping response to the packet. This is used by the fake USRP
- * code to generate fake responses for pings.
- *
- * The \p rid is the RID to be associated with the response and \p ping_val is
- * currently unused.
- *
- * \returns true if the ping reply was added successfully, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_PING_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t ping = (
- ((OP_PING_FIXED_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_PING_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- | ((ping_val & CS_PINGVAL_MASK) << CS_PINGVAL_SHIFT)
-
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(ping);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_PING_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds a write register command to the packet.
- *
- * The \p reg_num is the register number for which the value \p val will be
- * written to.
- *
- * \returns true if the command was added to the packet successfully, false
- * otherwise.
- */
-bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_WRITEREG_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t word0 = 0;
-
- // Build the first word which includes the register number
- word0 = (
- ((OP_WRITE_REG & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_WRITEREG_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word0);
-
- // The second word is solely the register value to be written
- // FIXME: should this be unsigned?
- payload += 1;
- *payload = host_to_usrp_u32((uint32_t) val);
-
- // Rebuild the header to update the payload length
- incr_header_len(CS_FIXED_LEN + CS_WRITEREG_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds a write register masked command to the packet.
- *
- * The \p reg_num is the register number for which the value \p val will be
- * written, masked by \p mask
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long mask)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_WRITEREGMASKED_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t word0 = 0;
-
- // Build the first word which includes the register number
- word0 = (
- ((OP_WRITE_REG_MASKED & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_WRITEREGMASKED_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word0);
-
- // Skip over the first word and write the register value
- payload += 1;
- *payload = host_to_usrp_u32((uint32_t) val);
-
- // Skip over the register value and write the mask
- payload += 1;
- *payload = host_to_usrp_u32((uint32_t) mask);
-
- // Rebuild the header to update the payload length
- incr_header_len(CS_FIXED_LEN + CS_WRITEREGMASKED_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds a read register message to the packet.
- *
- * The \p rid will be the associated RID returned with the response, and \p
- * reg_num is the register to be read.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_READREG_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t read_reg = (
- ((OP_READ_REG & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_READREG_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
-
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(read_reg);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_READREG_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds a read register reply response to the current packet. This is
- * used by the fake USRP code to generate fake register read responses for
- * testing.
- *
- * The \p rid is the associated RID to be included in the response, \p reg_num
- * is the register the read is coming from, and \p reg_val is the value of the
- * read.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_val)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_READREGREPLY_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t word0 = (
- ((OP_READ_REG_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_READREGREPLY_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
-
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word0);
-
- // Hop to the next word and write the reg value
- payload += 1;
- *payload = host_to_usrp_u32((uint32_t) reg_val);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_READREGREPLY_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds a delay command to the current packet.
- *
- * The \p ticks parameter is the number of clock ticks the FPGA should delay
- * parsing for, which is added to the packet.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_delay(long ticks)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_DELAY_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t delay = (
- ((OP_DELAY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_DELAY_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((ticks & CS_DELAY_MASK) << CS_DELAY_SHIFT)
-
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(delay);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_DELAY_LEN);
-
- return true;
-}
-
-/*!
- * \brief
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- int i2c_len = data_len + 2; // 2 bytes between mbz and addr
-
- if((MAX_PAYLOAD - p_len) < (i2c_len + CS_FIXED_LEN))
- return false;
-
- uint32_t word0 = 0;
-
- word0 = (
- ((OP_I2C_WRITE & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((i2c_len & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT)
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word0);
-
- // Jump over the first word and write the data
- // FIXME: Should the data be changed to usrp byte order?
- payload += 1;
- memcpy(payload, i2c_data, data_len);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + i2c_len);
-
- return true;
-}
-
-/*!
- * \brief Adds an I2C read command to the current packet.
- *
- * The \p rid is the associated RID to return with the read response, \p
- * i2c_addr is the address to read from on the I2C bus, and \p n_bytes is the
- * number of bytes to be read from the bus.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_I2CREAD_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t word0 = 0;
-
- word0 = (
- ((OP_I2C_READ & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_I2CREAD_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT)
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word0);
-
- // Jump a word and write the number of bytes to read
- payload += 1;
- uint32_t word1 =
- (n_bytes & CS_I2CREADBYTES_MASK) << CS_I2CREADBYTES_SHIFT;
- *payload = host_to_usrp_u32(word1);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_I2CREAD_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds an I2C read reply response to the current packet. This is used
- * by the fake USRP code to generate fake I2C responses.
- *
- * The \p rid is the RID to be associated with the response, \p i2c_addr is the
- * address on the I2C bus that the \p i2c_data of \p i2c_data_len was read from.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- int i2c_len = i2c_data_len + 2;
-
- if((MAX_PAYLOAD - p_len) < (i2c_len + CS_FIXED_LEN))
- return false;
-
- uint32_t word0 = 0;
-
- word0 = (
- ((OP_I2C_READ_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((i2c_len & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT)
- );
-
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word0);
-
- // Jump a word and write the actual data
- payload += 1;
- memcpy(payload, i2c_data, i2c_data_len);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + i2c_len);
-
- return true;
-}
-
-/*!
- * \brief Adds a SPI write command to the current packet.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- int spi_len = spi_data_len + 6;
-
- if((MAX_PAYLOAD - p_len) < (spi_len + CS_FIXED_LEN))
- return false;
-
- uint32_t word = 0;
-
- // First word contains the opcode and length, then mbz
- word = (
- ((OP_SPI_WRITE & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((spi_len & CS_LEN_MASK) << CS_LEN_SHIFT)
- );
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word);
-
- payload += 1;
-
- // Second word contains the enables, format, and optional tx bytes
- word = 0;
- word = (
- ((enables & CS_SPIENABLES_MASK) << CS_SPIENABLES_SHIFT)
- | ((format & CS_SPIFORMAT_MASK) << CS_SPIFORMAT_SHIFT)
- | ((opt_header_bytes & CS_SPIOPT_MASK) << CS_SPIOPT_SHIFT)
- );
- payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word);
-
- payload += 1;
- memcpy(payload, spi_data, spi_data_len);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + spi_len);
-
- return true;
-}
-
-/*!
- * \brief Adds a SPI bus read command to the packet.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- if((MAX_PAYLOAD - p_len) < (CS_SPIREAD_LEN + CS_FIXED_LEN))
- return false;
-
- uint32_t word = 0;
-
- // First word contains the opcode, length, and RID
- word = (
- ((OP_SPI_READ & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((CS_SPIREAD_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- );
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word);
-
- payload += 1;
-
- // Second word contains the enables, format, and optional tx bytes
- word = 0;
- word = (
- ((enables & CS_SPIENABLES_MASK) << CS_SPIENABLES_SHIFT)
- | ((format & CS_SPIFORMAT_MASK) << CS_SPIFORMAT_SHIFT)
- | ((opt_header_bytes & CS_SPIOPT_MASK) << CS_SPIOPT_SHIFT)
- );
- payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word);
-
- payload += 1;
-
- // The third word contains the number of bytes
- word = 0;
- word = (
- ((n_bytes & CS_SPINBYTES_MASK) << CS_SPINBYTES_SHIFT)
- );
- payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + CS_SPIREAD_LEN);
-
- return true;
-}
-
-/*!
- * \brief Adds an SPI read reply to the current packet. This is used by the
- * fake USRP code to generate fake responses for SPI reads.
- *
- * \returns true if the command was added to the packet, false otherwise.
- */
-bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len)
-{
- if(!align32())
- return false;
-
- int p_len = payload_len();
-
- int spi_len = spi_data_len + 2;
-
- if((MAX_PAYLOAD - p_len) < (spi_len + CS_FIXED_LEN))
- return false;
-
- uint32_t word = 0;
-
- // First word contains the opcode, length, and RID
- word = (
- ((OP_SPI_READ_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
- | ((spi_len & CS_LEN_MASK) << CS_LEN_SHIFT)
- | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
- );
- uint32_t *payload = (uint32_t *) (d_payload + p_len);
- *payload = host_to_usrp_u32(word);
-
- // Jump a word and write the actual data
- payload += 1;
- memcpy(payload, spi_data, spi_data_len);
-
- // Update payload length
- incr_header_len(CS_FIXED_LEN + spi_len);
-
- return true;
-}
-
-/*!
- * \brief Since all control packets contain subpackets which have the length of
- * the subpacket at a uniform location in the subpacket, this will return the
- * subpacket length given a byte offset of the start of the subpacket from the beginning of the packet.
- *
- * \returns the length of the subpacket
- */
-int usrp_inband_usb_packet::cs_len(int payload_offset) {
- uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset)));
- return (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK;
-}
-
-/*!
- * \brief The following method takes an offset within the packet payload to
- * extract a control/status subpacket and constructs a pmt response which
- * includes the proper signal and arguments specified by usrp-low-level-cs. The
- * USRP server could therefore use this to read subpackets and pass them
- * responses back up to the application. It's arguable that only reply packets
- * should be parsed here, however we parse others for use in debugging or
- * failure reporting on the transmit side of packets.
- */
-pmt_t usrp_inband_usb_packet::read_subpacket(int payload_offset) {
-
- uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset)));
- uint32_t opcode = (subpkt >> CS_OPCODE_SHIFT) & CS_OPCODE_MASK;
- uint32_t len = (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK;
-
- switch(opcode) {
-
- case OP_PING_FIXED_REPLY:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
- pmt_t pingval = pmt_from_long((subpkt >> CS_PINGVAL_SHIFT) & CS_PINGVAL_MASK);
- return pmt_list3(s_op_ping_fixed_reply, rid, pingval);
- }
-
- case OP_READ_REG_REPLY:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
- pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
-
- // To get the register value we just read the next 32 bits
- uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
- pmt_t reg_val = pmt_from_long(val);
-
- return pmt_list4(s_op_read_reg_reply, rid, reg_num, reg_val);
- }
-
- case OP_I2C_READ_REPLY:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
- pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK);
-
- // Make a u8 vector to dump the data from the packet into
- size_t i2c_data_len;
- pmt_t i2c_data = pmt_make_u8vector(len - 2, 0); // skip rid+mbz+addr = 2 bytes
- uint8_t *w_data =
- (uint8_t *) pmt_u8vector_writable_elements(i2c_data, i2c_data_len);
-
- memcpy(w_data, d_payload + payload_offset + 4, i2c_data_len); // skip first word
-
- return pmt_list4(s_op_i2c_read_reply, rid, i2c_addr, i2c_data);
- }
-
- case OP_SPI_READ_REPLY:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
-
- // Make a u8 vector to dump the data from the packet into
- size_t spi_data_len;
- pmt_t spi_data = pmt_make_u8vector(len - 2, 0); // skip rid+mbz+addr = 2 bytes
- uint8_t *w_data =
- (uint8_t *) pmt_u8vector_writable_elements(spi_data, spi_data_len);
-
- memcpy(w_data, d_payload + payload_offset + 4, spi_data_len); // skip first word
-
- return pmt_list3(s_op_spi_read_reply, rid, spi_data);
- }
-
- case OP_PING_FIXED:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
- pmt_t pingval = pmt_from_long((subpkt >> CS_PINGVAL_SHIFT) & CS_PINGVAL_MASK);
- return pmt_list3(s_op_ping_fixed, rid, pingval);
- }
-
- case OP_WRITE_REG:
- {
- pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
-
- // To get the register value we just read the next 32 bits
- uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
- pmt_t reg_val = pmt_from_long(val);
-
- return pmt_list3(s_op_write_reg, reg_num, reg_val);
- }
-
- case OP_WRITE_REG_MASKED:
- {
- pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
-
- // To get the register value we just read the next 32 bits
- uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
- pmt_t reg_val = pmt_from_long(val);
-
- // The mask is the next 32 bits
- uint32_t mask = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 8)));
- pmt_t reg_mask = pmt_from_long(mask);
-
- return pmt_list4(s_op_write_reg_masked, reg_num, reg_val, reg_mask);
- }
-
- case OP_READ_REG:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
- pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
-
- return pmt_list3(s_op_read_reg, rid, reg_num);
- }
-
- case OP_I2C_WRITE:
- {
- pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK);
-
- // The length includes an extra 2 bytes for storing the mbz and addr
- pmt_t i2c_data = pmt_make_u8vector(len-2, 0);
-
- // Get a writable address to copy the data from the packet
- size_t ignore;
- uint8_t *w_data = (uint8_t *) pmt_u8vector_writable_elements(i2c_data, ignore);
- memcpy(w_data, d_payload + payload_offset + 4, len-2);
-
-
- return pmt_list3(s_op_i2c_write, i2c_addr, i2c_data);
- }
-
- case OP_I2C_READ:
- {
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
- pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK);
-
- // The number of bytes is in the next word
- uint32_t bytes = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
- bytes = (bytes >> CS_I2CREADBYTES_SHIFT) & CS_I2CREADBYTES_MASK;
- pmt_t i2c_bytes = pmt_from_long(bytes);
-
- return pmt_list4(s_op_i2c_read, rid, i2c_addr, i2c_bytes);
- }
-
- case OP_SPI_WRITE:
- {
- // Nothing interesting in the first word, skip to the next
- uint32_t word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
- pmt_t enables = pmt_from_long((word >> CS_SPIENABLES_SHIFT) & CS_SPIENABLES_MASK);
- pmt_t format = pmt_from_long((word >> CS_SPIFORMAT_SHIFT) & CS_SPIFORMAT_MASK);
- pmt_t opt = pmt_from_long((word >> CS_SPIOPT_SHIFT) & CS_SPIOPT_MASK);
-
- // From the next word and on is data
- size_t spi_data_len;
- pmt_t spi_data = pmt_make_u8vector(len - 6, 0); // skip rid+mbz+addr = 2 bytes
- uint8_t *w_data =
- (uint8_t *) pmt_u8vector_writable_elements(spi_data, spi_data_len);
-
- memcpy(w_data, d_payload + payload_offset + 8, spi_data_len); // skip first 2 words
-
- return pmt_list5(s_op_spi_write, enables, format, opt, spi_data);
- }
-
- case OP_SPI_READ:
- {
- // Read the RID from the first word, the rest is mbz
- pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
-
- // Continue at the next word...
- uint32_t word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
- pmt_t enables = pmt_from_long((word >> CS_SPIENABLES_SHIFT) & CS_SPIENABLES_MASK);
- pmt_t format = pmt_from_long((word >> CS_SPIFORMAT_SHIFT) & CS_SPIFORMAT_MASK);
- pmt_t opt = pmt_from_long((word >> CS_SPIOPT_SHIFT) & CS_SPIOPT_MASK);
-
- // The number of bytes is the only thing to read in the next word
- word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 8)));
- pmt_t n_bytes = pmt_from_long((word >> CS_SPINBYTES_SHIFT) & CS_SPINBYTES_MASK);
-
- return pmt_list6(s_op_spi_read, rid, enables, format, opt, n_bytes);
- }
-
- case OP_DELAY:
- {
- pmt_t ticks = pmt_from_long((subpkt >> CS_DELAY_SHIFT) & CS_DELAY_MASK);
-
- return pmt_list2(s_op_delay, ticks);
- }
-
- default:
- return PMT_NIL;
-
- }
-}
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef INCLUDED_USRP_INBAND_USB_PACKET_H_
-#define INCLUDED_USRP_INBAND_USB_PACKET_H_
-
-#include <usrp_bytesex.h>
-#include <mblock/mblock.h>
-#include <pmt.h>
-#include <iostream>
-
-#include <symbols_usrp_low_level_cs.h>
-
-static const int USB_PKT_SIZE = 512; // bytes
-static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t);
-static const int CONTROL_CHAN = 0x1f;
-
-class usrp_inband_usb_packet {
- //
- // keep raw packet in USRP-endian order
- //
- uint32_t d_word0;
- uint32_t d_timestamp;
- unsigned char d_payload[MAX_PAYLOAD];
-
-public:
-
- enum opcodes {
- OP_PING_FIXED = 0x00,
- OP_PING_FIXED_REPLY = 0x01,
- OP_WRITE_REG = 0x02,
- OP_WRITE_REG_MASKED = 0x03,
- OP_READ_REG = 0x04,
- OP_READ_REG_REPLY = 0x05,
- OP_I2C_WRITE = 0x06,
- OP_I2C_READ = 0x07,
- OP_I2C_READ_REPLY = 0x08,
- OP_SPI_WRITE = 0x09,
- OP_SPI_READ = 0x0a,
- OP_SPI_READ_REPLY = 0x0b,
- OP_DELAY = 0x0c
- };
-
- enum flags {
- FL_OVERRUN = 0x80000000,
- FL_UNDERRUN = 0x40000000,
- FL_DROPPED = 0x20000000,
- FL_START_OF_BURST = 0x10000000,
- FL_END_OF_BURST = 0x08000000,
- FL_CARRIER_SENSE = 0x04000000,
-
- FL_ALL_FLAGS = 0xfc000000
- };
-
- static const int FL_OVERRUN_SHIFT = 31;
- static const int FL_UNDERRUN_SHIFT = 30;
- static const int FL_DROPPED_SHIFT = 29;
- static const int FL_END_OF_BURST_SHIFT = 27;
- static const int FL_START_OF_BURST_SHIFT = 28;
-
- static const int RSSI_MASK = 0x3f;
- static const int RSSI_SHIFT = 21;
-
- static const int CHAN_MASK = 0x1f;
- static const int CHAN_SHIFT = 16;
-
- static const int TAG_MASK = 0xf;
- static const int TAG_SHIFT = 9;
-
- static const int PAYLOAD_LEN_MASK = 0x1ff;
- static const int PAYLOAD_LEN_SHIFT = 0;
-
- // Fixed size for opcode and length fields
- static const int CS_FIXED_LEN = 2;
-
- static const int CS_OPCODE_MASK = 0xff;
- static const int CS_OPCODE_SHIFT = 24;
-
- static const int CS_LEN_MASK = 0xff;
- static const int CS_LEN_SHIFT = 16;
-
- static const int CS_RID_MASK = 0x3f;
- static const int CS_RID_SHIFT = 10;
-
- static const int CS_PING_LEN = 2;
- static const int CS_PINGVAL_MASK = 0x3ff;
- static const int CS_PINGVAL_SHIFT = 0;
-
- static const int CS_WRITEREG_LEN = 6;
- static const int CS_WRITEREGMASKED_LEN = 10;
- static const int CS_READREG_LEN = 2;
- static const int CS_READREGREPLY_LEN = 6;
- static const int CS_REGNUM_MASK = 0x3ff;
- static const int CS_REGNUM_SHIFT = 0;
-
- static const int CS_DELAY_LEN = 2;
- static const int CS_DELAY_MASK = 0xffff;
- static const int CS_DELAY_SHIFT = 0;
-
- static const int CS_I2CADDR_MASK = 0x7f;
- static const int CS_I2CADDR_SHIFT = 0;
-
- static const int CS_I2CREAD_LEN = 3;
- static const int CS_I2CREADBYTES_MASK = 0x7f;
- static const int CS_I2CREADBYTES_SHIFT = 24;
-
- static const int CS_SPIOPT_MASK = 0xffff;
- static const int CS_SPIOPT_SHIFT = 0;
- static const int CS_SPIFORMAT_MASK = 0xff;
- static const int CS_SPIFORMAT_SHIFT = 16;
- static const int CS_SPIENABLES_MASK = 0xff;
- static const int CS_SPIENABLES_SHIFT = 24;
- static const int CS_SPIREAD_LEN = 7;
- static const int CS_SPINBYTES_MASK = 0xff;
- static const int CS_SPINBYTES_SHIFT = 24;
-
-public:
-
- void set_timestamp(uint32_t timestamp){
- d_timestamp = host_to_usrp_u32(timestamp);
- }
-
- void set_end_of_burst() {
- uint32_t word0 = usrp_to_host_u32(d_word0);
- word0 |= 1<<FL_END_OF_BURST_SHIFT;
- d_word0 = host_to_usrp_u32(word0);
- }
-
- void set_header(int flags, int chan, int tag, int payload_len){
- uint32_t word0 = ((flags & FL_ALL_FLAGS)
- | ((chan & CHAN_MASK) << CHAN_SHIFT)
- | ((tag & TAG_MASK) << TAG_SHIFT)
- | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT));
- d_word0 = host_to_usrp_u32(word0);
- }
-
- void incr_header_len(int val) {
- set_header(flags(), chan(), tag(), payload_len() + val);
- }
-
- uint32_t timestamp() const {
- return usrp_to_host_u32(d_timestamp);
- }
-
- int rssi() const {
- uint32_t word0 = usrp_to_host_u32(d_word0);
- return (word0 >> RSSI_SHIFT) & RSSI_MASK;
- }
-
- int chan() const {
- uint32_t word0 = usrp_to_host_u32(d_word0);
- return (word0 >> CHAN_SHIFT) & CHAN_MASK;
- }
-
- int tag() const {
- uint32_t word0 = usrp_to_host_u32(d_word0);
- return (word0 >> TAG_SHIFT) & TAG_MASK;
- }
-
- int payload_len() const {
- uint32_t word0 = usrp_to_host_u32(d_word0);
- return (word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK;
- }
-
- int flags() const {
- return usrp_to_host_u32(d_word0) & FL_ALL_FLAGS;
- }
-
- int overrun() const {
- return (usrp_to_host_u32(d_word0) & FL_OVERRUN) >> FL_OVERRUN_SHIFT;
- }
-
-
- int underrun() const {
- return (usrp_to_host_u32(d_word0) & FL_UNDERRUN) >> FL_UNDERRUN_SHIFT;
- }
-
-
- int start_of_burst() const {
- return (usrp_to_host_u32(d_word0) & FL_START_OF_BURST) >> FL_START_OF_BURST_SHIFT;
- }
-
- int end_of_burst() const {
- return (usrp_to_host_u32(d_word0) & FL_END_OF_BURST) >> FL_END_OF_BURST_SHIFT;
- }
-
- int dropped() const {
- return (usrp_to_host_u32(d_word0) & FL_DROPPED) >> FL_DROPPED_SHIFT;
- }
-
- unsigned char *payload() {
- return d_payload;
- }
-
- static int max_payload() {
- return MAX_PAYLOAD;
- }
-
- static int max_pkt_size() {
- return USB_PKT_SIZE;
- }
-
- // C/S methods
- bool align32();
- bool cs_ping(long rid, long ping_val);
- bool cs_ping_reply(long rid, long ping_val);
- bool cs_write_reg(long reg_num, long val);
- bool cs_write_reg_masked(long reg_num, long val, long mask);
- bool cs_read_reg(long rid, long reg_num);
- bool cs_read_reg_reply(long rid, long reg_num, long reg_val);
- bool cs_delay(long ticks);
- bool cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len);
- bool cs_i2c_read(long rid, long i2c_addr, long n_bytes);
- bool cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len);
- bool cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len);
- bool cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes);
- bool cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len);
- int cs_len(int payload_offset);
- pmt_t read_subpacket(int payload_offset);
-};
-
-#endif
+++ /dev/null
-;; -*- scheme -*- ; not really, but tells emacs how to format this
-;;
-;; Copyright 2007 Free Software Foundation, Inc.
-;;
-;; This file is part of GNU Radio
-;;
-;; GNU Radio is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-;;
-;; GNU Radio is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License along
-;; with this program; if not, write to the Free Software Foundation, Inc.,
-;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-;;
-
-;; ----------------------------------------------------------------
-;; This is an mblock header file
-;;
-;; The format is very much a work-in-progress.
-;; It'll be compiled to C++.
-;; ----------------------------------------------------------------
-
-;; ----------------------------------------------------------------
-;; usrp-interface-cs
-;;
-;; Handles interaction between the usrp_sever and the USB interface
-
-(define-protocol-class usrp-interface-cs
-
- (:outgoing
- (cmd-usrp-open invocation-handle which-usrp)
- (cmd-usrp-close invocation-handle)
- (cmd-usrp-ntx-chan invocation-handle)
- (cmd-usrp-nrx-chan invocation-handle)
- (cmd-usrp-write invocation-handle channel data)
- (cmd-usrp-start-reading invocation-handle channel)
- )
-
- (:incoming
- (response-usrp-open invocation-handle status)
- (response-usrp-close invocation-handle status)
- (response-usrp-ntx-chan invocation-handle ntx-chan)
- (response-usrp-nrx-chan invocation-handle nrx-chan)
- (response-usrp-write invocation-handle status channel)
- (response-usrp-read invocation-handle status data)
- )
- )
-
-;; ----------------------------------------------------------------
-;; usrp-tx-cs
-;;
-;; Handles interaction between the USB interface and TX interface
-
-(define-protocol-class usrp-tx-cs
-
- (:outgoing
- (cmd-usrp-tx-write invocation-handle channel data tx-handle)
- )
-
- (:incoming
- (response-usrp-tx-write invocation-handle status channel)
- )
- )
-
-;; ----------------------------------------------------------------
-;; usrp-rx-cs
-;;
-;; Handles interaction between the USB interface and RX interface
-
-(define-protocol-class usrp-rx-cs
-
- (:outgoing
- (cmd-usrp-rx-start-reading invocation-handle rx-handle)
- (cmd-usrp-rx-stop-reading invocation-handle)
- )
-
- (:incoming
- (response-usrp-rx-read invocation-handle status data)
-
- ;; There is currently no response to a stop reading
- )
- )
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <usrp_rx.h>
-
-#include <usrp_standard.h>
-#include <iostream>
-#include <vector>
-#include <usb.h>
-#include <mblock/class_registry.h>
-#include <usrp_inband_usb_packet.h>
-#include <fpga_regs_common.h>
-#include <stdio.h>
-
-#include <symbols_usrp_rx_cs.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-static const bool verbose = false;
-
-bool usrp_rx_stop;
-
-usrp_rx::usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(rt, instance_name, user_arg),
- d_disk_write(false),
- d_disk_write_pkt(false) // if true, writes full packet, else just the payload
-{
- d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL);
-
- if(d_disk_write) {
- d_ofile0.open("rx_data_chan0.dat",std::ios::binary|std::ios::out);
- d_ofile1.open("rx_data_chan1.dat",std::ios::binary|std::ios::out);
- d_cs_ofile.open("rx_cs.dat",std::ios::binary|std::ios::out);
- }
-
- usrp_rx_stop = false;
-
-}
-
-usrp_rx::~usrp_rx()
-{
- if(d_disk_write) {
- d_ofile0.close();
- d_ofile1.close();
- d_cs_ofile.close();
- }
-}
-
-void
-usrp_rx::initial_transition()
-{
-
-}
-
-/*!
- * \brief Handles incoming signals to to the m-block, wihch should only ever be
- * a single message: cmd-usrrp-rx-start-reading. There is no signal to stop
- * reading as the m-block goes in to a forever loop to read inband packets from
- * the bus.
- */
-void
-usrp_rx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t port_id = msg->port_id();
- pmt_t data = msg->data();
-
- // Theoretically only have 1 message to ever expect, but
- // want to make sure its at least what we want
- if(pmt_eq(port_id, d_cs->port_symbol())) {
-
- if(pmt_eqv(event, s_cmd_usrp_rx_start_reading))
- read_and_respond(data);
- }
-}
-
-/*!
- * \brief Performs the actual reading of data from the USB bus, called by
- * handle_message() when a cmd-usrp-rx-start-reading signal is received.
- *
- * The method enters a forever loop where it continues to read data from the bus
- * and generate read responses to the higher layer. Currently, shared memory is
- * used to exit this loop.
- *
- * The \p data parameter is a PMT list which contains only a single element, an
- * invocation handle which will be returned with all read respones.
- */
-void
-usrp_rx::read_and_respond(pmt_t data)
-{
- size_t ignore;
- bool underrun;
- unsigned int n_read;
- unsigned int pkt_size = sizeof(transport_pkt);
-
- pmt_t invocation_handle = pmt_nth(0, data);
-
- // Need the handle to the RX port to send responses, this is passed
- // by the USRP interface m-block
- pmt_t handle = pmt_nth(1, data);
- d_urx =
- boost::any_cast<usrp_standard_rx_sptr>(pmt_any_ref(handle));
-
- if(verbose)
- std::cout << "[usrp_rx] Waiting for packets..\n";
-
- // Read by 512 which is packet size and send them back up
- while(!usrp_rx_stop) {
-
- pmt_t v_pkt = pmt_make_u8vector(pkt_size, 0);
- transport_pkt *pkt =
- (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, ignore);
-
- n_read = d_urx->read(pkt, pkt_size, &underrun);
-
- if(n_read != pkt_size) {
- std::cerr << "[usrp_rx] Error reading packet, shutting down\n";
- d_cs->send(s_response_usrp_rx_read,
- pmt_list3(PMT_NIL, PMT_F, PMT_NIL));
- return;
- }
-
- if(underrun && verbose && 0)
- std::cout << "[usrp_rx] Underrun\n";
-
- d_cs->send(s_response_usrp_rx_read,
- pmt_list3(PMT_NIL, PMT_T, v_pkt));
- if(verbose && 0)
- std::cout << "[usrp_rx] Read 1 packet\n";
-
- if(d_disk_write) {
- if(pkt->chan() == CONTROL_CHAN)
- d_cs_ofile.write((const char *)pkt, transport_pkt::max_pkt_size());
- else {
- if(d_disk_write_pkt) {
- if(pkt->chan() == 0)
- d_ofile0.write((const char *)pkt, transport_pkt::max_pkt_size());
- else if(pkt->chan() == 1)
- d_ofile1.write((const char *)pkt, transport_pkt::max_pkt_size());
- } else {
- if(pkt->chan() == 0)
- d_ofile0.write((const char *)pkt->payload(), transport_pkt::max_payload());
- else if(pkt->chan() == 1)
- d_ofile1.write((const char *)pkt->payload(), transport_pkt::max_payload());
- }
- }
-
- d_cs_ofile.flush();
- d_ofile0.flush();
- d_ofile1.flush();
- }
- }
-
- usrp_rx_stop = false;
-
- if(verbose) {
- std::cout << "[USRP_RX] Stopping...\n";
- fflush(stdout);
- }
-}
-
-REGISTER_MBLOCK_CLASS(usrp_rx);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_RX_H
-#define INCLUDED_USRP_RX_H
-
-#include <mblock/mblock.h>
-#include <fstream>
-#include "usrp_standard.h"
-
-extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub
-
-/*!
- * \brief Implements the low level usb interface to the USRP
- */
-class usrp_rx : public mb_mblock
-{
- mb_port_sptr d_cs;
- usrp_standard_rx_sptr d_urx;
-
- bool d_disk_write;
- bool d_disk_write_pkt;
- std::ofstream d_ofile0;
- std::ofstream d_ofile1;
- std::ofstream d_cs_ofile;
-
- public:
- usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
- ~usrp_rx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- private:
- void read_and_respond(pmt_t data);
- void read_data();
-
-};
-
-
-#endif /* INCLUDED_USRP_RX_H */
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <usrp_rx_stub.h>
-
-#include <iostream>
-#include <vector>
-#include <usb.h>
-#include <mblock/class_registry.h>
-#include <usrp_inband_usb_packet.h>
-#include <fpga_regs_common.h>
-#include "usrp_standard.h"
-#include <stdio.h>
-#include <string.h>
-#include <ui_nco.h>
-#include <fstream>
-
-#include <symbols_usrp_rx_cs.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-static const bool verbose = false;
-
-bool usrp_rx_stop_stub;
-
-// Used for the fake control packet response code to send the responses back up
-// the RX. The TX stub dumps responses in to this queue.
-std::queue<pmt_t> d_cs_queue;
-
-usrp_rx_stub::usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(rt, instance_name, user_arg),
- d_samples_per_frame((long)(126)),
- d_decim_rx(128),
- d_amplitude(16384),
- d_disk_write(false)
-{
-
- // Information about the rates are passed all the way from the app in the form
- // of a dictionary. We use this to read the RX decimation rate and compute
- // the approximate number of MS/s as a form of flow control for the stub.
- pmt_t usrp_dict = user_arg;
-
- if (pmt_is_dict(usrp_dict)) {
- // Read the RX decimation rate
- if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
- pmt_intern("decim-rx"),
- PMT_NIL)) {
- if(!pmt_eqv(decim_rx, PMT_NIL))
- d_decim_rx = pmt_to_long(decim_rx);
- }
- }
-
- d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL);
-
- // initialize NCO
- double freq = 100e3;
- int interp = 32; // 32 -> 4MS/s
- double sample_rate = 64e6 / interp;
- d_nco.set_freq(2*M_PI * freq/sample_rate);
-
- //d_disk_write = true;
-
- if(d_disk_write)
- d_ofile.open("raw_rx.dat",std::ios::binary|std::ios::out);
-
- usrp_rx_stop_stub = false;
-}
-
-usrp_rx_stub::~usrp_rx_stub()
-{
- if(d_disk_write)
- d_ofile.close();
-}
-
-void
-usrp_rx_stub::initial_transition()
-{
-}
-
-void
-usrp_rx_stub::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t port_id = msg->port_id();
- pmt_t data = msg->data();
-
- if (pmt_eq(msg->signal(), s_timeout)
- && !pmt_eq(msg->data(), s_done)) {
-
- if(!usrp_rx_stop_stub)
- read_and_respond();
- else { // requested to stop
- cancel_timeout(msg->metadata());
- usrp_rx_stop_stub=false;
- if(verbose)
- std::cout << "[USRP_RX_STUB] Stopping RX stub\n";
- }
-
- }
-
- // Theoretically only have 1 message to ever expect, but
- // want to make sure its at least what we want
- if(pmt_eq(port_id, d_cs->port_symbol())
- && pmt_eqv(event, s_cmd_usrp_rx_start_reading)) {
-
- if(verbose)
- std::cout << "[USRP_RX_STUB] Starting with decim @ "
- << d_decim_rx << std::endl;
-
- start_packet_timer();
- }
-}
-
-// Setup a periodic timer which will drive packet generation
-void
-usrp_rx_stub::start_packet_timer()
-{
- d_t0 = mb_time::time(); // current time
-
- // Calculate the inter-packet arrival time.
- double samples_per_sec = (64.0/(double)d_decim_rx)*1000000.0;
- double frames_per_sec = samples_per_sec / (double)d_samples_per_frame;
- double frame_rate = 1.0 / frames_per_sec;
-
- if(verbose) {
- std::cout << "[USRP_RX_STUB] Scheduling periodic packet generator\n";
- std::cout << "\tsamples_per_sec: " << samples_per_sec << std::endl;
- std::cout << "\tframes_per_sec: " << frames_per_sec << std::endl;
- std::cout << "\tframe_rate: " << frame_rate << std::endl;
- }
-
- schedule_periodic_timeout(d_t0 + frame_rate, mb_time(frame_rate), PMT_T);
-}
-
-void
-usrp_rx_stub::read_and_respond()
-{
-
- long nsamples_this_frame = d_samples_per_frame;
-
- size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
- long channel = 0;
- long n_bytes = nshorts*2;
- pmt_t uvec = pmt_make_s16vector(nshorts, 0);
- size_t ignore;
- int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
-
- // fill in the complex sinusoid
-
- for (int i = 0; i < nsamples_this_frame; i++){
-
- if (1){
- gr_complex s;
- d_nco.sincos(&s, 1, d_amplitude);
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- else {
- gr_complex s(d_amplitude, d_amplitude);
-
- // write 16-bit i & q
- samples[2*i] = (int16_t) s.real();
- samples[2*i+1] = (int16_t) s.imag();
- }
- }
-
- if(d_disk_write)
- d_ofile.write((const char *)samples, n_bytes);
-
- pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0);
- transport_pkt *pkt =
- (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, ignore);
-
- pkt->set_header(0, channel, 0, n_bytes);
- pkt->set_timestamp(0xffffffff);
- memcpy(pkt->payload(), samples, n_bytes);
-
- d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt));
-
- // Now lets check the shared CS queue between the TX and RX stub. Each
- // element in a queue is a list where the first element is an invocation
- // handle and the second element is a PMT u8 vect representation of the
- // CS packet response which can just be passed transparently.
- while(!d_cs_queue.empty()) {
-
- pmt_t cs_pkt = d_cs_queue.front();
- d_cs_queue.pop();
-
- pmt_t invocation_handle = pmt_nth(0, cs_pkt);
- pmt_t v_pkt = pmt_nth(1, cs_pkt);
-
- d_cs->send(s_response_usrp_rx_read,
- pmt_list3(invocation_handle,
- PMT_T,
- v_pkt)); // Take the front CS pkt
-
-
- if(verbose)
- std::cout << "[USRP_RX_STUB] Received CS response from TX stub\n";
- }
-
-}
-
-REGISTER_MBLOCK_CLASS(usrp_rx_stub);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_RX_STUB_H
-#define INCLUDED_USRP_RX_STUB_H
-
-#include <mblock/mblock.h>
-#include <vector>
-#include "usrp_standard.h"
-#include <ui_nco.h>
-#include <fstream>
-#include <queue>
-#include <usrp_inband_usb_packet.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-extern bool usrp_rx_stop_stub; // used to communicate a 'stop' to the RX stub
-extern std::queue<pmt_t> d_cs_queue;
-
-static pmt_t s_timeout = pmt_intern("%timeout");
-static pmt_t s_done = pmt_intern("done");
-
-/*!
- * \brief Implements the low level usb interface to the USRP
- */
-class usrp_rx_stub : public mb_mblock
-{
- public:
-
- mb_port_sptr d_cs;
- usrp_standard_rx* d_urx;
-
- long d_samples_per_frame;
- long d_decim_rx;
-
- mb_time d_t0;
- double d_delta_t;
-
- // for generating sine wave output
- ui_nco<float,float> d_nco;
- double d_amplitude;
-
- bool d_disk_write;
-
- std::ofstream d_ofile;
-
- public:
- usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
- ~usrp_rx_stub();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- private:
- void read_and_respond();
- void read_data();
- void start_packet_timer();
-
-};
-
-
-#endif /* INCLUDED_USRP_RX_H */
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <usrp_server.h>
-#include <iostream>
-#include <usrp_inband_usb_packet.h>
-#include <mblock/class_registry.h>
-#include <vector>
-#include <usrp_usb_interface.h>
-#include <string.h>
-#include <fpga_regs_common.h>
-#include <fpga_regs_standard.h>
-
-#include <symbols_usrp_server_cs.h>
-#include <symbols_usrp_channel.h>
-#include <symbols_usrp_tx.h>
-#include <symbols_usrp_rx.h>
-#include <symbols_usrp_low_level_cs.h>
-#include <symbols_usrp_interface_cs.h>
-
-static pmt_t s_shutdown = pmt_intern("%shutdown");
-
-typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
-
-const static bool verbose = false;
-
-static std::string
-str(long x)
-{
- std::ostringstream s;
- s << x;
- return s.str();
-}
-
-usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(rt, instance_name, user_arg),
- d_fpga_debug(false),
- d_interp_tx(128), // these should match the lower level defaults (rx also)
- d_decim_rx(128),
- d_fake_rx(false)
-{
- if(verbose)
- std::cout << "[USRP_SERVER] Initializing...\n";
-
- // Dictionary for arguments to all of the components
- d_usrp_dict = user_arg;
-
- if (pmt_is_dict(d_usrp_dict)) {
-
- if(pmt_t fpga_debug = pmt_dict_ref(d_usrp_dict,
- pmt_intern("fpga-debug"),
- PMT_NIL)) {
- if(pmt_eqv(fpga_debug, PMT_T))
- d_fpga_debug=true;
- }
-
- // Read the TX interpolations
- if(pmt_t interp_tx = pmt_dict_ref(d_usrp_dict,
- pmt_intern("interp-tx"),
- PMT_NIL)) {
- if(!pmt_eqv(interp_tx, PMT_NIL))
- d_interp_tx = pmt_to_long(interp_tx);
- }
-
- // Read the RX decimation rate
- if(pmt_t decim_rx = pmt_dict_ref(d_usrp_dict,
- pmt_intern("decim-rx"),
- PMT_NIL)) {
- if(!pmt_eqv(decim_rx, PMT_NIL))
- d_decim_rx = pmt_to_long(decim_rx);
- }
- }
-
- // control & status port
- d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL);
- d_cs_usrp = define_port("cs_usrp", "usrp-interface-cs", false, mb_port::INTERNAL);
-
- // ports
- //
- // (if/when we do replicated ports, these will be replaced by a
- // single replicated port)
- for(int port=0; port < N_PORTS; port++) {
-
- d_tx.push_back(define_port("tx"+str(port),
- "usrp-tx",
- true,
- mb_port::EXTERNAL));
-
- d_rx.push_back(define_port("rx"+str(port),
- "usrp-rx",
- true,
- mb_port::EXTERNAL));
- }
-
- define_component("usrp", "usrp_usb_interface", d_usrp_dict);
- connect("self", "cs_usrp", "usrp", "cs");
-
- d_defer=false;
- d_opened=false;
-
- // FIXME: needs to be returned from open, if we want to use this
- d_nrx_chan = 2;
- d_ntx_chan = 2;
-
- // Initialize capacity on each channel to 0 and to no owner
- // Also initialize the USRP standard tx/rx pointers to NULL
- for(int chan=0; chan < d_ntx_chan; chan++)
- d_chaninfo_tx.push_back(channel_info());
-
- for(int chan=0; chan < d_nrx_chan; chan++)
- d_chaninfo_rx.push_back(channel_info());
-
- d_rx_chan_mask = 0;
-
- for(int i=0; i < D_MAX_RID; i++)
- d_rids.push_back(rid_info());
-
- //d_fake_rx=true;
-}
-
-/*!
- * \brief resets the assigned capacity and owners of each RX and TX channel from
- * allocations.
- */
-void
-usrp_server::reset_channels()
-{
-
- for(int chan=0; chan < d_ntx_chan; chan++) {
- d_chaninfo_tx[chan].assigned_capacity = 0;
- d_chaninfo_tx[chan].owner = PMT_NIL;
- }
-
- for(int chan=0; chan < d_nrx_chan; chan++) {
- d_chaninfo_rx[chan].assigned_capacity = 0;
- d_chaninfo_rx[chan].owner = PMT_NIL;
- }
-
- d_rx_chan_mask = 0;
-}
-
-usrp_server::~usrp_server()
-{
-}
-
-
-void
-usrp_server::initial_transition()
-{
- // the initial transition
-}
-
-/*!
- * \brief Reads all incoming messages to USRP server from the TX, RX, and the CS
- * ports. This drives the state of USRP server and dispatches based on the
- * message.
- */
-void
-usrp_server::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal(); // the "name" of the message
- pmt_t port_id = msg->port_id(); // which port it came in on
- pmt_t data = msg->data();
- pmt_t invocation_handle;
- pmt_t metadata = msg->metadata();
- pmt_t status;
-
- long port;
-
- if (pmt_eq(event, s_shutdown)) // ignore (for now)
- return;
-
- invocation_handle = pmt_nth(0, data);
-
- if (0){
- std::cout << "[USRP_SERVER] event: " << event << std::endl;
- std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl;
- }
-
- // It would be nice if this were all table driven, and we could compute our
- // state transition as f(current_state, port_id, signal)
-
- // A message from the USRP CS, which should *only* be responses
- //
- // It is important that this set come before checking messages of any other
- // components. This is since we always want to listen to the low level USRP
- // server, even if we aren't initialized we are waiting for responses to
- // become initialized. Likewise, after the usrp_server is "closed", we still
- // want to pass responses back from the low level.
-
- //---------------- USRP RESPONSE ---------------//
- if (pmt_eq(port_id, d_cs_usrp->port_symbol())) {
-
- //-------------- USRP OPEN ------------------//
- if(pmt_eq(event, s_response_usrp_open)) {
- // pass the response back over the regular CS port
- pmt_t status = pmt_nth(1, data);
- d_cs->send(s_response_open, pmt_list2(invocation_handle, status));
-
- //reset_all_registers();
- //initialize_registers();
-
- if(pmt_eqv(status,PMT_T)) {
- d_opened = true;
- d_defer = false;
- recall_defer_queue();
- }
-
- return;
- }
- //------------- USRP CLOSE -------------------//
- else if (pmt_eq(event, s_response_usrp_close)) {
- pmt_t status = pmt_nth(1, data);
- d_cs->send(s_response_close, pmt_list2(invocation_handle, status));
-
- if(pmt_eqv(status,PMT_T)) {
- d_opened = false;
- d_defer = false;
- reset_channels();
- recall_defer_queue();
- }
-
- return;
- }
- //--------------- USRP WRITE --------------//
- else if (pmt_eq(event, s_response_usrp_write)) {
-
- pmt_t status = pmt_nth(1, data);
- long channel = pmt_to_long(pmt_nth(2, data));
- long port;
-
- // Do not report back responses if they were generated from a
- // command packet
- if(channel == CONTROL_CHAN)
- return;
-
- // Find the port through the owner of the channel
- if((port = tx_port_index(d_chaninfo_tx[channel].owner)) !=-1 )
- d_tx[port]->send(s_response_xmit_raw_frame,
- pmt_list2(invocation_handle, status));
- return;
- }
- //--------------- USRP READ ---------------//
- else if (pmt_eq(event, s_response_usrp_read)) {
-
- pmt_t status = pmt_nth(1, data);
-
- if(!pmt_eqv(status, PMT_T)) {
- std::cerr << "[USRP_SERVER] Error receiving packet\n";
- return;
- }
- else {
- handle_response_usrp_read(data);
- return;
- }
- }
-
- goto unhandled;
- }
-
- // Checking for defer on all other messages
- if(d_defer) {
- if (verbose)
- std::cout << "[USRP_SERVER] Received msg while deferring ("
- << msg->signal() << ")\n";
- d_defer_queue.push(msg);
- return;
- }
-
- //--------- CONTROL / STATUS ------------//
- if (pmt_eq(port_id, d_cs->port_symbol())){
-
- //----------- OPEN -----------//
- if (pmt_eq(event, s_cmd_open)){
-
- // Reject if already open
- if(d_opened) {
- d_cs->send(s_response_open, pmt_list2(invocation_handle, s_err_usrp_already_opened));
- return;
- }
-
- // the parameters are the same to the low level interface, so we just pass 'data' along
- d_cs_usrp->send(s_cmd_usrp_open, data);
-
- d_defer = true;
-
- return;
- }
- //---------- CLOSE -----------//
- else if (pmt_eq(event, s_cmd_close)){
-
- if(!d_opened) {
- d_cs->send(s_response_close, pmt_list2(invocation_handle, s_err_usrp_already_closed));
- return;
- }
-
- d_defer = true;
- d_cs_usrp->send(s_cmd_usrp_close, pmt_list1(invocation_handle));
-
- return;
- }
- //---------- MAX CAPACITY ----------//
- else if (pmt_eq(event, s_cmd_max_capacity)) {
-
- if(!d_opened) {
- d_cs->send(s_response_max_capacity,
- pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
- return;
- }
-
- d_cs->send(s_response_max_capacity,
- pmt_list3(invocation_handle,
- PMT_T,
- pmt_from_long(max_capacity())));
- return;
- }
- //---------- NTX CHAN --------------//
- else if (pmt_eq(event, s_cmd_ntx_chan)) {
-
- if(!d_opened) {
- d_cs->send(s_response_ntx_chan,
- pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
- return;
- }
-
- d_cs->send(s_response_ntx_chan,
- pmt_list3(invocation_handle,
- PMT_T,
- pmt_from_long(d_ntx_chan)));
- return;
- }
- //---------- NRX CHAN -----------//
- else if (pmt_eq(event, s_cmd_nrx_chan)) {
-
- if(!d_opened) {
- d_cs->send(s_response_nrx_chan,
- pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
- return;
- }
-
- d_cs->send(s_response_nrx_chan,
- pmt_list3(invocation_handle,
- PMT_T,
- pmt_from_long(d_nrx_chan)));
- return;
- }
- //--------- ALLOCATION? -----------//
- else if (pmt_eq(event, s_cmd_current_capacity_allocation)) {
-
- if(!d_opened) {
- d_cs->send(s_response_current_capacity_allocation,
- pmt_list3(invocation_handle,
- s_err_usrp_not_opened,
- pmt_from_long(0)));
- return;
- }
-
- d_cs->send(s_response_current_capacity_allocation,
- pmt_list3(invocation_handle,
- PMT_T,
- pmt_from_long(current_capacity_allocation())));
- return;
- }
- goto unhandled;
- }
-
- //-------------- TX ---------------//
- if ((port = tx_port_index(port_id)) != -1) {
-
- //------------ ALLOCATE (TX) ----------------//
- if (pmt_eq(event, s_cmd_allocate_channel)){
-
- if(!d_opened) {
- d_tx[port]->send(s_response_allocate_channel,
- pmt_list3(invocation_handle,
- s_err_usrp_not_opened,
- pmt_from_long(0)));
- return;
- }
-
- handle_cmd_allocate_channel(d_tx[port], d_chaninfo_tx, data);
- return;
- }
-
- //----------- DEALLOCATE (TX) ---------------//
- if (pmt_eq(event, s_cmd_deallocate_channel)) {
-
- if(!d_opened) {
- d_tx[port]->send(s_response_deallocate_channel,
- pmt_list3(invocation_handle,
- s_err_usrp_not_opened,
- pmt_from_long(0)));
- return;
- }
-
- handle_cmd_deallocate_channel(d_tx[port], d_chaninfo_tx, data);
- return;
- }
-
- //-------------- XMIT RAW FRAME -----------------/
- if (pmt_eq(event, s_cmd_xmit_raw_frame)){
-
- if(!d_opened) {
- d_tx[port]->send(s_response_xmit_raw_frame,
- pmt_list2(invocation_handle, s_err_usrp_not_opened));
- return;
- }
-
- handle_cmd_xmit_raw_frame(d_tx[port], d_chaninfo_tx, data);
- return;
- }
-
- //-------------- CONTROL PACKET -----------------/
- if (pmt_eq(event, s_cmd_to_control_channel)) {
-
- if(!d_opened) {
- d_tx[port]->send(s_response_xmit_raw_frame,
- pmt_list2(invocation_handle, s_err_usrp_not_opened));
- return;
- }
-
- handle_cmd_to_control_channel(d_tx[port], d_chaninfo_tx, data);
- return;
-
- }
-
- goto unhandled;
- }
-
- //-------------- RX ---------------//
- if ((port = rx_port_index(port_id)) != -1) {
-
- //------------ ALLOCATE (RX) ----------------//
- if (pmt_eq(event, s_cmd_allocate_channel)) {
-
- if(!d_opened) {
- d_rx[port]->send(s_response_allocate_channel,
- pmt_list3(invocation_handle,
- s_err_usrp_not_opened,
- pmt_from_long(0)));
- return;
- }
-
- handle_cmd_allocate_channel(d_rx[port], d_chaninfo_rx, data);
- return;
- }
-
- //----------- DEALLOCATE (RX) ---------------//
- if (pmt_eq(event, s_cmd_deallocate_channel)) {
-
- if(!d_opened) {
- d_rx[port]->send(s_response_deallocate_channel,
- pmt_list3(invocation_handle,
- s_err_usrp_not_opened,
- pmt_from_long(0)));
- return;
- }
-
- handle_cmd_deallocate_channel(d_rx[port], d_chaninfo_rx, data);
- return;
- }
-
- //-------------- START RECV ----------------//
- if (pmt_eq(event, s_cmd_start_recv_raw_samples)) {
-
- if(!d_opened) {
- d_rx[port]->send(s_response_recv_raw_samples,
- pmt_list2(invocation_handle, s_err_usrp_not_opened));
- return;
- }
-
- handle_cmd_start_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
- return;
- }
-
- //-------------- STOP RECV ----------------//
- if (pmt_eq(event, s_cmd_stop_recv_raw_samples)) {
-
- if(!d_opened)
- return;
-
- // FIX ME : no response for stopping? even if error? (permissions)
- handle_cmd_stop_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
-
- return;
- }
-
- goto unhandled;
- }
-
- unhandled:
- std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl;
-}
-
-/*!
- * \brief Takes a port_symbol() as parameter \p port_id and is used to determine
- * if the port is a TX port, or to find an index in the d_tx vector which stores
- * the port.
- *
- * \returns -1 if \p port_id is not in the d_tx vector (i.e., it's not a TX
- * port), otherwise returns an index in the d_tx vector which stores the port.
- */
-int usrp_server::tx_port_index(pmt_t port_id) {
-
- for(int i=0; i < (int) d_tx.size(); i++)
- if(pmt_eq(d_tx[i]->port_symbol(), port_id))
- return i;
-
- return -1;
-}
-
-/*!
- * \brief Takes a port_symbol() as parameter \p port_id and is used to determine
- * if the port is an RX port, or to find an index in the d_rx vector which
- * stores the port.
- *
- * \returns -1 if \p port_id is not in the d_rx vector (i.e., it's not an RX
- * port), otherwise returns an index in the d_rx vector which stores the port.
- */
-int usrp_server::rx_port_index(pmt_t port_id) {
-
- for(int i=0; i < (int) d_rx.size(); i++)
- if(pmt_eq(d_rx[i]->port_symbol(), port_id))
- return i;
-
- return -1;
-}
-
-/*!
- * \brief Determines the current total capacity allocated by all RX and TX
- * channels.
- *
- * \returns the total allocated capacity
- */
-long usrp_server::current_capacity_allocation() {
- long capacity = 0;
-
- for(int chan=0; chan < d_ntx_chan; chan++)
- capacity += d_chaninfo_tx[chan].assigned_capacity;
-
- for(int chan=0; chan < d_nrx_chan; chan++)
- capacity += d_chaninfo_rx[chan].assigned_capacity;
-
- return capacity;
-}
-
-
-/*!
- * \brief Called by the handle_message() method if the incoming message to
- * usrp_server is to allocate a channel (cmd-allocate-channel). The method
- * checks if the requested capacity exists and if so it will reserve it for the
- * caller on the channel that is returned via a response-allocate-channel
- * signal.
- */
-void
-usrp_server::handle_cmd_allocate_channel(
- mb_port_sptr port,
- std::vector<struct channel_info> &chan_info,
- pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- long rqstd_capacity = pmt_to_long(pmt_nth(1, data));
- long chan;
-
- // Check capacity exists
- if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
-
- // no capacity available
- port->send(s_response_allocate_channel,
- pmt_list3(invocation_handle,
- s_err_requested_capacity_unavailable,
- PMT_NIL));
- return;
- }
-
- // Find a free channel, assign the capacity and respond
- for(chan=0; chan < (long)chan_info.size(); chan++) {
-
- if(verbose)
- std::cout << "[USRP_SERVER] Checking chan: " << chan
- << " owner " << chan_info[chan].owner
- << " size " << chan_info.size()
- << std::endl;
-
- if(chan_info[chan].owner == PMT_NIL) {
-
- chan_info[chan].owner = port->port_symbol();
- chan_info[chan].assigned_capacity = rqstd_capacity;
-
- port->send(s_response_allocate_channel,
- pmt_list3(invocation_handle,
- PMT_T,
- pmt_from_long(chan)));
-
- if(verbose)
- std::cout << "[USRP_SERVER] Assigning channel: " << chan
- << " to " << chan_info[chan].owner
- << std::endl;
- return;
- }
-
- }
-
- if (verbose)
- std::cout << "[USRP_SERVER] Couldnt find a TX chan\n";
-
- // no free TX chan found
- port->send(s_response_allocate_channel,
- pmt_list3(invocation_handle,
- s_err_channel_unavailable,
- PMT_NIL));
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method if the incoming message to
- * usrp_server is to deallocate a channel (cmd-deallocate-channel). The method
- * ensures that the sender of the signal owns the channel and that the channel
- * number is valid. A response-deallocate-channel signal is sent back with the
- * result of the deallocation.
- */
-void
-usrp_server::handle_cmd_deallocate_channel(
- mb_port_sptr port,
- std::vector<struct channel_info> &chan_info,
- pmt_t data)
-{
-
- pmt_t invocation_handle = pmt_nth(0, data);
- long channel = pmt_to_long(pmt_nth(1, data));
-
- // Ensure the channel is valid and the caller owns the port
- if(!check_valid(port, channel, chan_info,
- pmt_list2(s_response_deallocate_channel, invocation_handle)))
- return;
-
- chan_info[channel].assigned_capacity = 0;
- chan_info[channel].owner = PMT_NIL;
-
- port->send(s_response_deallocate_channel,
- pmt_list2(invocation_handle,
- PMT_T));
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method if the incoming message to
- * usrp_server is to transmit a frame (cmd-xmit-raw-frame). The method
- * allocates enough memory to support a burst of packets which contain the frame
- * over the bus of the frame, sets the packet headers, and sends a signal to the
- * lower block for the data (packets) to be written to the bus.
- *
- * The \p port the command was sent on and the channel info (\p chan_info) of
- * the channel the frame is to be transmitted on are passed to ensure that the
- * caller owns the channel.
- *
- * The \p data parameter is in the format of a cmd-xmit-raw-frame signal.
- *
- * The properties
- */
-void usrp_server::handle_cmd_xmit_raw_frame(
- mb_port_sptr port,
- std::vector<struct channel_info> &chan_info,
- pmt_t data)
-{
- size_t n_bytes, psize;
- long max_payload_len = transport_pkt::max_payload();
-
- pmt_t invocation_handle = pmt_nth(0, data);
- long channel = pmt_to_long(pmt_nth(1, data));
- const void *samples = pmt_uniform_vector_elements(pmt_nth(2, data), n_bytes);
- long timestamp = pmt_to_long(pmt_nth(3, data));
- pmt_t properties = pmt_nth(4, data);
-
- // Ensure the channel is valid and the caller owns the port
- if(!check_valid(port, channel, chan_info,
- pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
- return;
-
- // Read information from the properties of the packet
- bool carrier_sense = false;
- if(pmt_is_dict(properties)) {
-
- // Check if carrier sense is enabled for the frame
- if(pmt_t p_carrier_sense = pmt_dict_ref(properties,
- pmt_intern("carrier-sense"),
- PMT_NIL)) {
- if(pmt_eqv(p_carrier_sense, PMT_T))
- carrier_sense = true;
- }
- }
-
-
- // Determine the number of packets to allocate contiguous memory for
- // bursting over the USB and get a pointer to the memory to be used in
- // building the packets
- long n_packets =
- static_cast<long>(std::ceil(n_bytes / (double)max_payload_len));
-
- pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
-
- transport_pkt *pkts =
- (transport_pkt *) pmt_u8vector_writable_elements(v_packets, psize);
-
- for(int n=0; n < n_packets; n++) {
-
- long payload_len =
- std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len);
-
- if(n == 0) { // first packet gets start of burst flag and timestamp
-
- if(carrier_sense)
- pkts[n].set_header(pkts[n].FL_START_OF_BURST
- | pkts[n].FL_CARRIER_SENSE,
- channel, 0, payload_len);
- else
- pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len);
-
- pkts[n].set_timestamp(timestamp);
-
- } else {
- pkts[n].set_header(0, channel, 0, payload_len);
- pkts[n].set_timestamp(0xffffffff);
- }
-
- memcpy(pkts[n].payload(),
- (uint8_t *)samples+(max_payload_len * n),
- payload_len);
-
- }
-
-
- pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst
-
- if (verbose && 0)
- std::cout << "[USRP_SERVER] Received raw frame invocation: "
- << invocation_handle << std::endl;
-
- // The actual response to the write will be generated by a
- // s_response_usrp_write since we cannot determine whether to transmit was
- // successful until we hear from the lower layers.
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packets));
-
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method to parse incoming control/status
- * signals (cmd-to-control-channel).
- *
- * The \p port the command was sent on and the channel info (\p chan_info) of
- * the channel are passed to ensure that the caller owns the channel.
- *
- * The \p data parameter is in the format of a PMT list, where each element
- * follows the format of a control/status signal (i.e. op-ping-fixed).
- *
- * The method will parse all of the C/S commands included in \p data and place
- * the commands in to a lower level packet sent to the control channel. The
- * method will pack as many commands as possible in t oa single packet, and once
- * it is fill generate as many lower level packets as needed.
- *
- * Anything that needs to be returned to the sender of the signal (i.e. the
- * value of a register) will be generated by the parse_control_pkt() method as
- * the responses to the commands are read back from the USRP.
- */
-void usrp_server::handle_cmd_to_control_channel(
- mb_port_sptr port,
- std::vector<struct channel_info> &chan_info,
- pmt_t data)
-{
-
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t subpackets = pmt_nth(1, data);
-
- long n_subpkts = pmt_length(subpackets);
- long curr_subpkt = 0;
-
- size_t psize;
- long payload_len = 0;
- long channel = CONTROL_CHAN;
-
- if(verbose)
- std::cout << "[USRP_SERVER] Handling " << n_subpkts << " commands\n";
-
- // The design of the following code is optimized for simplicity, not
- // performance. To performance optimize this code, the total size in bytes
- // needed for all of the CS packets is needed to allocate contiguous memory
- // which contains the USB packets for bursting over the bus. However to do
- // this the packets subpackets would need to be parsed twice and their sizes
- // would need to be determined.
- //
- // The approach taken is to keep parsing the subpackets and putting them in to
- // USB packets. Once the USB packet is full, a write is sent for it and
- // another packet is created.
- //
- // The subpacket creation methods will return false if the subpacket will not
- // fit in to the current USB packet. In these cases a new USB packet is
- // created and the old is sent.
-
- new_packet:
- // This code needs to become "smart" and only make a new packet when full
- pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
- transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_packet, psize);
- payload_len = 0;
-
- pkt->set_header(0, channel, 0, payload_len);
- pkt->set_timestamp(0xffffffff);
-
- while(curr_subpkt < n_subpkts) {
-
- pmt_t subp = pmt_nth(curr_subpkt, subpackets);
- pmt_t subp_cmd = pmt_nth(0, subp);
- pmt_t subp_data = pmt_nth(1, subp);
-
- //--------- PING FIXED --------------//
- if(pmt_eq(subp_cmd, s_op_ping_fixed)) {
-
- long urid = pmt_to_long(pmt_nth(0, subp_data));
- long pingval = pmt_to_long(pmt_nth(1, subp_data));
-
- // USRP server sets request ID's to keep track of which application gets
- // what response back. To allow a full 6-bits for an RID to the user, we
- // keep a mapping and replace the RID's as the packets go in and out. If
- // there are no RID's available, the command is thrown away silently.
- long srid;
- if((srid = next_rid()) == -1)
- goto subpkt_bail;
-
- // We use a vector to store the owner of the ping request and will use it
- // to send the request on any RX port they own.
- d_rids[srid].owner = port->port_symbol();
- d_rids[srid].user_rid = urid;
-
- // Adds a ping after the previous command in the pkt
- if(!pkt->cs_ping(srid, pingval))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- // Return the RID
- d_rids[srid].owner = PMT_NIL;
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received ping command request"
- << " assigning RID " << srid << std::endl;
-
- }
-
- //----------- WRITE REG ---------------//
- if(pmt_eq(subp_cmd, s_op_write_reg)) {
-
- long reg_num = pmt_to_long(pmt_nth(0, subp_data));
- long val = pmt_to_long(pmt_nth(1, subp_data));
-
- if(!pkt->cs_write_reg(reg_num, val))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received write register request "
- << "("
- << "Reg: " << reg_num << ", "
- << "Val: " << val
- << ")\n";
- }
-
- //------- WRITE REG MASKED ----------//
- if(pmt_eq(subp_cmd, s_op_write_reg_masked)) {
-
- long reg_num = pmt_to_long(pmt_nth(0, subp_data));
- long val = pmt_to_long(pmt_nth(1, subp_data));
- long mask = pmt_to_long(pmt_nth(2, subp_data));
-
- if(!pkt->cs_write_reg_masked(reg_num, val, mask))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received write register masked request\n";
- }
-
- //------------ READ REG --------------//
- if(pmt_eq(subp_cmd, s_op_read_reg)) {
-
- long urid = pmt_to_long(pmt_nth(0, subp_data));
- long reg_num = pmt_to_long(pmt_nth(1, subp_data));
-
- long srid;
- if((srid = next_rid()) == -1)
- goto subpkt_bail;
-
- d_rids[srid].owner = port->port_symbol();
- d_rids[srid].user_rid = urid;
-
- if(!pkt->cs_read_reg(srid, reg_num))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- // Return the rid
- d_rids[srid].owner = PMT_NIL;
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received read register request"
- << " assigning RID " << srid << std::endl;
- }
-
- //------------ DELAY --------------//
- if(pmt_eq(subp_cmd, s_op_delay)) {
-
- long ticks = pmt_to_long(pmt_nth(0, subp_data));
-
- if(!pkt->cs_delay(ticks))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received delay request of "
- << ticks << " ticks\n";
- }
-
- //--------- I2C WRITE -----------//
- // FIXME: could check that byte count does not exceed 2^8 which
- // is the max length in the subpacket for # of bytes to read.
- if(pmt_eq(subp_cmd, s_op_i2c_write)) {
-
- long i2c_addr = pmt_to_long(pmt_nth(0, subp_data));
- pmt_t data = pmt_nth(1, subp_data);
-
- // Get a readable address to the data which also gives us the length
- size_t data_len;
- uint8_t *i2c_data = (uint8_t *) pmt_u8vector_writable_elements(data, data_len);
-
- // Make the USB packet
- if(!pkt->cs_i2c_write(i2c_addr, i2c_data, data_len))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received I2C write\n";
- }
-
- //----------- I2C Read -------------//
- if(pmt_eq(subp_cmd, s_op_i2c_read)) {
-
- long urid = pmt_to_long(pmt_nth(0, subp_data));
- long i2c_addr = pmt_to_long(pmt_nth(1, subp_data));
- long i2c_bytes = pmt_to_long(pmt_nth(2, subp_data));
-
- long srid;
- if((srid = next_rid()) == -1)
- goto subpkt_bail;
-
- d_rids[srid].owner = port->port_symbol();
- d_rids[srid].user_rid = urid;
-
- if(!pkt->cs_i2c_read(srid, i2c_addr, i2c_bytes))
- {
-
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- d_rids[srid].owner = PMT_NIL;
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received I2C read\n";
- }
-
- //--------- SPI WRITE -----------//
- if(pmt_eq(subp_cmd, s_op_spi_write)) {
-
- long enables = pmt_to_long(pmt_nth(0, subp_data));
- long format = pmt_to_long(pmt_nth(1, subp_data));
- long opt = pmt_to_long(pmt_nth(2, subp_data));
- pmt_t data = pmt_nth(3, subp_data);
-
- // Get a readable address to the data which also gives us the length
- size_t data_len;
- uint8_t *spi_data = (uint8_t *) pmt_u8vector_writable_elements(data, data_len);
-
- // Make the USB packet
- if(!pkt->cs_spi_write(enables, format, opt, spi_data, data_len))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received SPI write\n";
- }
-
- //--------- SPI READ -----------//
- if(pmt_eq(subp_cmd, s_op_spi_read)) {
-
- long urid = pmt_to_long(pmt_nth(0, subp_data));
- long enables = pmt_to_long(pmt_nth(1, subp_data));
- long format = pmt_to_long(pmt_nth(2, subp_data));
- long opt = pmt_to_long(pmt_nth(3, subp_data));
- long n_bytes = pmt_to_long(pmt_nth(4, subp_data));
-
- long srid;
- if((srid = next_rid()) == -1)
- goto subpkt_bail;
-
- d_rids[srid].owner = port->port_symbol();
- d_rids[srid].user_rid = urid;
-
- // Make the USB packet
- if(!pkt->cs_spi_read(srid, enables, format, opt, n_bytes))
- {
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- // Return the rid
- d_rids[srid].owner = PMT_NIL;
-
- goto new_packet;
- }
-
- if(verbose)
- std::cout << "[USRP_SERVER] Received SPI read\n";
- }
-
- subpkt_bail:
- curr_subpkt++;
-
- }
-
-
- // If the current packets length is > 0, we know there are subpackets that
- // need to be sent out still.
- if(pkt->payload_len() > 0)
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(invocation_handle,
- pmt_from_long(channel),
- v_packet));
-
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is a
- * command to start reading samples from the USRP (cmd-start-recv-raw-samples).
- *
- * The \p port the command was sent on and the channel info (\p chan_info) of
- * the channel are passed to ensure that the caller owns the channel.
- *
- * The \p data parameter should be in the format of a cmd-start-recv-raw-samples
- * command where the first element in the list is an invocation handle, and the
- * second is the channel the signal generator wants to receive the samples on.
- */
-void
-usrp_server::handle_cmd_start_recv_raw_samples(
- mb_port_sptr port,
- std::vector<struct channel_info> &chan_info,
- pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- long channel = pmt_to_long(pmt_nth(1, data));
-
- // Ensure the channel is valid and the caller owns the port
- if(!check_valid(port, channel, chan_info,
- pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
- return;
-
- // Already started receiving samples? (another start before a stop)
- // Check the RX channel bitmask.
- if(d_rx_chan_mask & (1 << channel)) {
- port->send(s_response_recv_raw_samples,
- pmt_list5(invocation_handle,
- s_err_already_receiving,
- PMT_NIL,
- PMT_NIL,
- PMT_NIL));
- return;
- }
-
- // We only need to generate a 'start reading' command down to the
- // low level interface if no other channel is already reading
- //
- // We carry this over the CS interface because the lower level
- // interface does not care about the channel, we only demux it
- // at the usrp_server on responses.
- if(d_rx_chan_mask == 0) {
-
- if(verbose)
- std::cout << "[USRP_SERVER] Sending read request down to start recv\n";
-
- d_cs_usrp->send(s_cmd_usrp_start_reading, pmt_list1(invocation_handle));
- }
-
- d_rx_chan_mask |= 1<<channel;
-
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is to
- * stop receiving samples from the USRP (cmd-stop-recv-raw-samples).
- *
- * The \p port the command was sent on and the channel info (\p chan_info) of
- * the channel are passed to ensure that the caller owns the channel.
- *
- * The \p data parameter should be in the format of a cmd-stop-recv-raw-samples
- * command where the first element in the list is an invocation handle, and the
- * second is the channel the signal generator wants to stop receiving the
- * samples from.
- */
-void
-usrp_server::handle_cmd_stop_recv_raw_samples(
- mb_port_sptr port,
- std::vector<struct channel_info> &chan_info,
- pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- long channel = pmt_to_long(pmt_nth(1, data));
-
- // FIX ME : we have no responses to send an error...
- // Ensure the channel is valid and the caller owns the port
- //if(!check_valid(port, channel, chan_info,
- // pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
- // return;
-
- // Remove this hosts bit from the receiver mask
- d_rx_chan_mask &= ~(1<<channel);
-
- // We only need to generate a 'start reading' command down to the
- // low level interface if no other channel is already reading
- //
- // We carry this over the CS interface because the lower level
- // interface does not care about the channel, we only demux it
- // at the usrp_server on responses.
- if(d_rx_chan_mask == 0) {
-
- if(verbose)
- std::cout << "[USRP_SERVER] Sending stop reading request down\n";
-
- d_cs_usrp->send(s_cmd_usrp_stop_reading, pmt_list1(invocation_handle));
- }
-
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method when an incoming signal is
- * generated to USRP server that contains raw samples from the USRP. This
- * method generates the response-recv-raw-samples signals that are the result of
- * a cmd-start-recv-raw-samples signal.
- *
- * The raw lower-level packet is extracted from \p data, where the format for \p
- * data is a PMT list. The PMT \p data list should contain an invocation handle
- * as the first element, the status of the lower-level read as the second
- * element, and a uniform vector representation of the packets as the third
- * element.
- *
- * The packet contains a channel field that the samples are destined to, and the
- * method determines where to send the samples based on this channel since each
- * channel has an associated port which allocated it.
- */
-void
-usrp_server::handle_response_usrp_read(pmt_t data)
-{
-
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t v_pkt = pmt_nth(2, data);
-
- size_t n_bytes;
- size_t ignore;
-
- if (d_fake_rx) {
-
- pmt_t pkt = pmt_nth(2, data);
-
- d_rx[0]->send(s_response_recv_raw_samples,
- pmt_list5(PMT_F,
- PMT_T,
- pkt,
- pmt_from_long(0xffff),
- PMT_NIL));
-
- return;
- }
-
- // Extract the packet and return appropriately
- transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, n_bytes);
-
- // The channel is used to find the port to pass the samples on
- long channel = pkt->chan();
- long payload_len = pkt->payload_len();
- long port;
-
- // Ignore packets which seem to have incorrect size or size 0
- if(payload_len > pkt->max_payload() || payload_len == 0)
- return;
-
- // If the packet is a C/S packet, parse it separately
- if(channel == CONTROL_CHAN) {
- parse_control_pkt(invocation_handle, pkt);
- return;
- }
-
- if((port = rx_port_index(d_chaninfo_rx[channel].owner)) == -1)
- return; // Don't know where to send the sample... possibility on abrupt close
-
- pmt_t v_samples = pmt_make_u8vector(payload_len, 0);
- uint8_t *samples = pmt_u8vector_writable_elements(v_samples, ignore);
-
- memcpy(samples, pkt->payload(), payload_len);
-
- // Build a properties dictionary to store things such as the RSSI
- pmt_t properties = pmt_make_dict();
-
- pmt_dict_set(properties,
- pmt_intern("rssi"),
- pmt_from_long(pkt->rssi()));
-
- if(pkt->overrun())
- pmt_dict_set(properties,
- pmt_intern("overrun"),
- PMT_T);
-
- if(pkt->underrun())
- pmt_dict_set(properties,
- pmt_intern("underrun"),
- PMT_T);
-
- d_rx[port]->send(s_response_recv_raw_samples,
- pmt_list6(invocation_handle,
- status,
- v_samples,
- pmt_from_long(pkt->timestamp()),
- pmt_from_long(channel),
- properties));
- return;
-}
-
-/*!
- * \brief Called by handle_response_usrp_read() when the incoming packet has a
- * channel of CONTROL_CHAN. This means that the incoming packet contains a
- * response for a command sent to the control channel, which this method will
- * parse.
- *
- * The \p pkt parameter is a pointer to the full packet (transport_pkt) in
- * memory.
- *
- * Given that all commands sent to the control channel that require responses
- * will carry an RID (request ID), the method will use the RID passed back with
- * the response to determine which port the response should be sent on.
- */
-void
-usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt)
-{
-
- long payload_len = pkt->payload_len();
- long curr_payload = 0;
- long port;
-
- // We dispatch based on the control packet type, however we can extract the
- // opcode and the length immediately which is consistent in all responses.
- //
- // Since each control packet can have multiple responses, we keep reading the
- // lengths of each subpacket until we reach the payload length.
- while(curr_payload < payload_len) {
-
- pmt_t sub_packet = pkt->read_subpacket(curr_payload);
- pmt_t op_symbol = pmt_nth(0, sub_packet);
-
- int len = pkt->cs_len(curr_payload);
-
- if(verbose)
- std::cout << "[USRP_SERVER] Parsing subpacket "
- << op_symbol << " ... length " << len << std::endl;
-
- //----------------- PING RESPONSE ------------------//
- if(pmt_eq(op_symbol, s_op_ping_fixed_reply)) {
-
- long srid = pmt_to_long(pmt_nth(1, sub_packet));
- pmt_t pingval = pmt_nth(2, sub_packet);
-
- long urid = d_rids[srid].user_rid;
-
- if(verbose)
- std::cout << "[USRP_SERVER] Found ping response "
- << "("
- << "URID: " << urid << ", "
- << "SRID: " << srid << ", "
- << "VAL: " << pingval
- << ")\n";
-
- // Do some bounds checking incase of bogus/corrupt responses
- if(srid > D_MAX_RID)
- return;
-
- pmt_t owner = d_rids[srid].owner;
-
- // Return the RID
- d_rids[srid].owner = PMT_NIL;
-
- // FIXME: should be 1 response for all subpackets here ?
- if((port = tx_port_index(owner)) != -1)
- d_tx[port]->send(s_response_from_control_channel,
- pmt_list4(invocation_handle,
- PMT_T,
- pmt_list2(s_op_ping_fixed_reply, // subp
- pmt_list2(pmt_from_long(urid),
- pingval)),
- pmt_from_long(pkt->timestamp())));
- }
-
- //----------------- READ REG RESPONSE ------------------//
- else if(pmt_eq(op_symbol, s_op_read_reg_reply)) {
-
- long srid = pmt_to_long(pmt_nth(1, sub_packet));
- pmt_t reg_num = pmt_nth(2, sub_packet);
- pmt_t reg_val = pmt_nth(3, sub_packet);
-
- long urid = d_rids[srid].user_rid;
-
- if(verbose)
- std::cout << "[USRP_SERVER] Found read register response "
- << "("
- << "URID: " << urid << ", "
- << "SRID: " << srid << ", "
- << "REG: " << reg_num << ", "
- << "VAL: " << reg_val
- << ")\n";
-
- // Do some bounds checking to avoid seg faults
- if(srid > D_MAX_RID)
- return;
-
- pmt_t owner = d_rids[srid].owner;
-
- // Return the RID
- d_rids[srid].owner = PMT_NIL;
-
- // FIXME: should be 1 response for all subpackets here ?
- if((port = tx_port_index(owner)) != -1)
- d_tx[port]->send(s_response_from_control_channel,
- pmt_list4(invocation_handle,
- PMT_T,
- pmt_list2(s_op_read_reg_reply, // subp
- pmt_list3(pmt_from_long(urid),
- reg_num,
- reg_val)),
- pmt_from_long(pkt->timestamp())));
- }
-
- //------------------ I2C READ REPLY -------------------//
- else if(pmt_eq(op_symbol, s_op_i2c_read_reply)) {
-
- long srid = pmt_to_long(pmt_nth(1, sub_packet));
- pmt_t i2c_addr = pmt_nth(2, sub_packet);
- pmt_t i2c_data = pmt_nth(3, sub_packet);
-
- long urid = d_rids[srid].user_rid;
-
- if(verbose)
- std::cout << "[USRP_SERVER] Found i2c read reply "
- << "("
- << "URID: " << urid << ", "
- << "SRID: " << srid << ", "
- << "Addr: " << i2c_addr << ", "
- << "Data: " << i2c_data
- << ")\n";
-
- // Do some bounds checking to avoid seg faults
- if(srid > D_MAX_RID)
- return;
-
- pmt_t owner = d_rids[srid].owner;
-
- // Return the RID
- d_rids[srid].owner = PMT_NIL;
-
- if((port = tx_port_index(owner)) != -1)
- d_tx[port]->send(s_response_from_control_channel,
- pmt_list4(invocation_handle,
- PMT_T,
- pmt_list2(s_op_i2c_read_reply,
- pmt_list3(pmt_from_long(urid),
- i2c_addr,
- i2c_data)),
- pmt_from_long(pkt->timestamp())));
- }
-
- //------------------ SPI READ REPLY -------------------//
- else if(pmt_eq(op_symbol, s_op_spi_read_reply)) {
-
- long srid = pmt_to_long(pmt_nth(1, sub_packet));
- pmt_t spi_data = pmt_nth(2, sub_packet);
-
- long urid = d_rids[srid].user_rid;
-
- if(verbose)
- std::cout << "[USRP_SERVER] Found SPI read reply "
- << "("
- << "URID: " << urid << ", "
- << "SRID: " << srid << ", "
- << "Data: " << spi_data
- << ")\n";
-
- // Bounds check the RID
- if(srid > D_MAX_RID)
- return;
-
- pmt_t owner = d_rids[srid].owner;
-
- // Return the RID
- d_rids[srid].owner = PMT_NIL;
-
- if((port = tx_port_index(owner)) != -1)
- d_tx[port]->send(s_response_from_control_channel,
- pmt_list4(invocation_handle,
- PMT_T,
- pmt_list2(s_op_spi_read_reply,
- pmt_list2(pmt_from_long(urid),
- spi_data)),
- pmt_from_long(pkt->timestamp())));
- }
-
- // Each subpacket has an unaccounted for 2 bytes which is the opcode
- // and the length field
- curr_payload += len + 2;
-
- // All subpackets are 32-bit aligned
- int align_offset = 4 - (curr_payload % 4);
-
- if(align_offset != 4)
- curr_payload += align_offset;
- }
-}
-
-/*!
- * \brief Used to recall all incoming signals that were deferred when USRP
- * server was in the initialization state.
- */
-void
-usrp_server::recall_defer_queue()
-{
-
- std::vector<mb_message_sptr> recall;
-
- while(!d_defer_queue.empty()) {
- recall.push_back(d_defer_queue.front());
- d_defer_queue.pop();
- }
-
- // Parse the messages that were queued while waiting for an open response
- for(int i=0; i < (int)recall.size(); i++)
- handle_message(recall[i]);
-
- return;
-}
-
-/*!
- * \brief Commonly called by any method which handles outgoing frames or control
- * packets to the USRP to check if the port on which the signal was sent owns
- * the channel the outgoing packet will be associated with. This helps ensure
- * that applications do not send data on other application's ports.
- *
- * The \p port parameter is the port symbol that the caller wishes to determine
- * owns the channel specified by \p chan_info.
- *
- * The \p signal_info parameter is a PMT list containing two elements: the
- * response signal to use if the permissions are invalid, and the invocation
- * handle that was passed. This allows the method to generate detailed failure
- * responses to signals without having to return some sort of structured
- * information which the caller must then parse and interpret to determine the
- * failure type.
- *
- * \returns true if \p port owns the channel specified by \p chan_info, false
- * otherwise.
- */
-bool
-usrp_server::check_valid(mb_port_sptr port,
- long channel,
- std::vector<struct channel_info> &chan_info,
- pmt_t signal_info)
-{
-
- pmt_t response_signal = pmt_nth(0, signal_info);
- pmt_t invocation_handle = pmt_nth(1, signal_info);
-
- // not a valid channel number?
- if(channel >= (long)chan_info.size() && channel != CONTROL_CHAN) {
- port->send(response_signal,
- pmt_list2(invocation_handle,
- s_err_channel_invalid));
-
- if(verbose)
- std::cout << "[USRP_SERVER] Invalid channel number for event "
- << response_signal << std::endl;
- return false;
- }
-
- // not the owner of the port?
- if(chan_info[channel].owner != port->port_symbol()) {
- port->send(response_signal,
- pmt_list2(invocation_handle,
- s_err_channel_permission_denied));
-
- if(verbose)
- std::cout << "[USRP_SERVER] Invalid permissions"
- << " for " << response_signal
- << " from " << port->port_symbol()
- << " proper owner is " << chan_info[channel].owner
- << " on channel " << channel
- << " invocation " << invocation_handle
- << std::endl;
- return false;
- }
-
- return true;
-}
-
-/*!
- * \brief Finds the next available RID for internal USRP server use with control
- * and status packets.
- *
- * \returns the next valid RID or -1 if no more RIDs are available.
- */
-long
-usrp_server::next_rid()
-{
- for(int i = 0; i < D_MAX_RID; i++)
- if(pmt_eqv(d_rids[i].owner, PMT_NIL))
- return i;
-
- if(verbose)
- std::cout << "[USRP_SERVER] No RIDs left\n";
- return -1;
-}
-
-/*!
- * \brief Called by handle_message() when USRP server gets a response that the
- * USRP was opened successfully to initialize the registers using the new
- * register read/write control packets.
- */
-void
-usrp_server::initialize_registers()
-{
- // We use handle_cmd_to_control_channel() to create the register writes using
- // PMT_NIL as the response port to tell usrp_server not to pass the response
- // up to any application.
- if(verbose)
- std::cout << "[USRP_SERVER] Initializing registers...\n";
-
- // RX mode to normal (0)
- set_register(FR_MODE, 0);
-
- // FPGA debugging?
- if(d_fpga_debug) {
- set_register(FR_DEBUG_EN, 1);
- // FIXME: need to figure out exact register writes to control daughterboard
- // pins that need to be written to
- } else {
- set_register(FR_DEBUG_EN, 0);
- }
-
- // Set the transmit sample rate divisor, which is 4-1
- set_register(FR_TX_SAMPLE_RATE_DIV, 3);
-
- // Dboard IO buffer and register settings
- set_register(FR_OE_0, (0xffff << 16) | 0x0000);
- set_register(FR_IO_0, (0xffff << 16) | 0x0000);
- set_register(FR_OE_1, (0xffff << 16) | 0x0000);
- set_register(FR_IO_1, (0xffff << 16) | 0x0000);
- set_register(FR_OE_2, (0xffff << 16) | 0x0000);
- set_register(FR_IO_2, (0xffff << 16) | 0x0000);
- set_register(FR_OE_3, (0xffff << 16) | 0x0000);
- set_register(FR_IO_3, (0xffff << 16) | 0x0000);
-
- // zero Tx side Auto Transmit/Receive regs
- set_register(FR_ATR_MASK_0, 0);
- set_register(FR_ATR_TXVAL_0, 0);
- set_register(FR_ATR_RXVAL_0, 0);
- set_register(FR_ATR_MASK_1, 0);
- set_register(FR_ATR_TXVAL_1, 0);
- set_register(FR_ATR_RXVAL_1, 0);
- set_register(FR_ATR_MASK_2, 0);
- set_register(FR_ATR_TXVAL_2, 0);
- set_register(FR_ATR_RXVAL_2, 0);
- set_register(FR_ATR_MASK_3, 0);
- set_register(FR_ATR_TXVAL_3, 0);
- set_register(FR_ATR_RXVAL_3, 0);
-
- // Configure TX mux, this is a hacked value
- set_register(FR_TX_MUX, 0x00000081);
-
- // Set the interpolation rate, which is the rate divided by 4, minus 1
- set_register(FR_INTERP_RATE, (d_interp_tx/4)-1);
-
- // Apparently this register changes again
- set_register(FR_TX_MUX, 0x00000981);
-
- // Set the receive sample rate divisor, which is 2-1
- set_register(FR_RX_SAMPLE_RATE_DIV, 1);
-
- // DC offset
- set_register(FR_DC_OFFSET_CL_EN, 0x0000000f);
-
- // Reset the DC correction offsets
- set_register(FR_ADC_OFFSET_0, 0);
- set_register(FR_ADC_OFFSET_1, 0);
-
- // Some hard-coded RX configuration
- set_register(FR_RX_FORMAT, 0x00000300);
- set_register(FR_RX_MUX, 1);
-
- // RX decimation rate is divided by two, then subtract 1
- set_register(FR_DECIM_RATE, (d_decim_rx/2)-1);
-
- // More hard coding
- set_register(FR_RX_MUX, 0x000e4e41);
-
- // Resetting RX registers
- set_register(FR_RX_PHASE_0, 0);
- set_register(FR_RX_PHASE_1, 0);
- set_register(FR_RX_PHASE_2, 0);
- set_register(FR_RX_PHASE_3, 0);
- set_register(FR_RX_FREQ_0, 0x28000000);
- set_register(FR_RX_FREQ_1, 0);
- set_register(FR_RX_FREQ_2, 0);
- set_register(FR_RX_FREQ_3, 0);
-
- // Enable debug bus
- set_register(FR_DEBUG_EN, 0xf);
- set_register(FR_OE_0, -1);
- set_register(FR_OE_1, -1);
- set_register(FR_OE_2, -1);
- set_register(FR_OE_3, -1);
-
- // DEBUGGING
- //check_register_initialization();
-}
-
-// FIXME: used for debugging to determine if all the registers are actually
-// being set correctly
-void
-usrp_server::check_register_initialization()
-{
- // RX mode to normal (0)
- read_register(FR_MODE);
-
- // FPGA debugging?
- if(d_fpga_debug) {
- read_register(FR_DEBUG_EN);
- // FIXME: need to figure out exact register writes to control daughterboard
- // pins that need to be written to
- } else {
- read_register(FR_DEBUG_EN);
- }
-
- // Set the transmit sample rate divisor, which is 4-1
- read_register(FR_TX_SAMPLE_RATE_DIV);
-
- // Dboard IO buffer and register settings
- read_register(FR_OE_0);
- read_register(FR_IO_0);
- read_register(FR_OE_1);
- read_register(FR_IO_1);
- read_register(FR_OE_2);
- read_register(FR_IO_2);
- read_register(FR_OE_3);
- read_register(FR_IO_3);
-
- // zero Tx side Auto Transmit/Receive regs
- read_register(FR_ATR_MASK_0);
- read_register(FR_ATR_TXVAL_0);
- read_register(FR_ATR_RXVAL_0);
- read_register(FR_ATR_MASK_1);
- read_register(FR_ATR_TXVAL_1);
- read_register(FR_ATR_RXVAL_1);
- read_register(FR_ATR_MASK_2);
- read_register(FR_ATR_TXVAL_2);
- read_register(FR_ATR_RXVAL_2);
- read_register(FR_ATR_MASK_3);
- read_register(FR_ATR_TXVAL_3);
- read_register(FR_ATR_RXVAL_3);
-
- // Configure TX mux, this is a hacked value
- read_register(FR_TX_MUX);
-
- // Set the interpolation rate, which is the rate divided by 4, minus 1
- read_register(FR_INTERP_RATE);
-
- // Apparently this register changes again
- read_register(FR_TX_MUX);
-
- // Set the receive sample rate divisor, which is 2-1
- read_register(FR_RX_SAMPLE_RATE_DIV);
-
- // DC offset
- read_register(FR_DC_OFFSET_CL_EN);
-
- // Reset the DC correction offsets
- read_register(FR_ADC_OFFSET_0);
- read_register(FR_ADC_OFFSET_1);
-
- // Some hard-coded RX configuration
- read_register(FR_RX_FORMAT);
- read_register(FR_RX_MUX);
-
- // RX decimation rate is divided by two, then subtract 1
- read_register(FR_DECIM_RATE);
-
- // More hard coding
- read_register(FR_RX_MUX);
-
- // Resetting RX registers
- read_register(FR_RX_PHASE_0);
- read_register(FR_RX_PHASE_1);
- read_register(FR_RX_PHASE_2);
- read_register(FR_RX_PHASE_3);
- read_register(FR_RX_FREQ_0);
- read_register(FR_RX_FREQ_1);
- read_register(FR_RX_FREQ_2);
- read_register(FR_RX_FREQ_3);
-}
-
-/*!
- * \brief Used to generate FPGA register write commands to reset all of the FPGA
- * registers to a value of 0.
- */
-void
-usrp_server::reset_all_registers()
-{
- for(int i=0; i<64; i++)
- set_register(i, 0);
-}
-
-/*!
- * \brief Used internally by USRP server to generate a control/status packet
- * which contains a register write.
- *
- * The \p reg parameter is the register number that the value \p val will be
- * written to.
- */
-void
-usrp_server::set_register(long reg, long val)
-{
- size_t psize;
- long payload_len = 0;
-
- pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
- transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_packet, psize);
-
- pkt->set_header(0, CONTROL_CHAN, 0, payload_len);
- pkt->set_timestamp(0xffffffff);
-
- pkt->cs_write_reg(reg, val);
-
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(PMT_NIL,
- pmt_from_long(CONTROL_CHAN),
- v_packet));
-}
-
-/*!
- * \brief Used internally by USRP server to generate a control/status packet
- * which contains a register read. This is important to use internally so that
- * USRP server can bypass the use of RIDs with register reads, as they are not
- * needed and it would use up the finite number of RIDs available for use for
- * applications to receive responses.
- *
- * The \p reg parameter is the register number that the value should be read
- * from.
- */
-void
-usrp_server::read_register(long reg)
-{
- size_t psize;
- long payload_len = 0;
-
- pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
- transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_packet, psize);
-
- pkt->set_header(0, CONTROL_CHAN, 0, payload_len);
- pkt->set_timestamp(0xffffffff);
-
- pkt->cs_read_reg(0, reg);
-
- d_cs_usrp->send(s_cmd_usrp_write,
- pmt_list3(PMT_NIL,
- pmt_from_long(CONTROL_CHAN),
- v_packet));
-}
-
-REGISTER_MBLOCK_CLASS(usrp_server);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_SERVER_H
-#define INCLUDED_USRP_SERVER_H
-
-#include <mblock/mblock.h>
-#include <vector>
-#include <queue>
-#include <fstream>
-#include <usrp_inband_usb_packet.h>
-
-typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
-
-/*!
- * \brief Implements the lowest-level mblock usb_interface to the USRP
- */
-class usrp_server : public mb_mblock
-{
-public:
-
- // our ports
- enum port_types {
- RX_PORT = 0,
- TX_PORT = 1
- };
- static const int N_PORTS = 4;
- std::vector<mb_port_sptr> d_tx, d_rx;
- mb_port_sptr d_cs;
- mb_port_sptr d_cs_usrp;
-
- static const int D_USB_CAPACITY = 32 * 1024 * 1024;
- static const int D_MAX_CHANNELS = 16;
- long d_ntx_chan;
- long d_nrx_chan;
-
- pmt_t d_usrp_dict;
-
- bool d_fpga_debug;
-
- long d_interp_tx;
- long d_decim_rx;
-
- // Keep track of the request IDs
- struct rid_info {
- pmt_t owner;
- long user_rid;
-
- rid_info() {
- owner = PMT_NIL;
- user_rid = 0;
- }
- };
-
- static const long D_MAX_RID = 64;
- std::vector<rid_info> d_rids;
-
- struct channel_info {
- long assigned_capacity; // the capacity currently assignedby the channel
- pmt_t owner; // port ID of the owner of the channel
-
- channel_info() {
- assigned_capacity = 0;
- owner = PMT_NIL;
- }
- };
-
- long d_rx_chan_mask; // A bitmask representing the channels in the
- // receiving state
-
- std::vector<struct channel_info> d_chaninfo_tx;
- std::vector<struct channel_info> d_chaninfo_rx;
-
- std::queue<mb_message_sptr> d_defer_queue;
-
- bool d_defer;
- bool d_opened;
-
- bool d_fake_rx;
-
-public:
- usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
- ~usrp_server();
-
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
-protected:
- static int max_capacity() { return D_USB_CAPACITY; }
-
-private:
- void handle_cmd_allocate_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
- void handle_cmd_deallocate_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
- void handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
- void handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
- void handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
- void handle_cmd_stop_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
- int rx_port_index(pmt_t port_id);
- int tx_port_index(pmt_t port_id);
- long current_capacity_allocation();
- void recall_defer_queue();
- void reset_channels();
- void handle_response_usrp_read(pmt_t data);
- bool check_valid(mb_port_sptr port, long channel, std::vector<struct channel_info> &chan_info, pmt_t signal_info);
- void parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt);
- long next_rid();
- void initialize_registers();
- void set_register(long reg, long val);
- void read_register(long reg);
- void check_register_initialization();
- void reset_all_registers();
-};
-
-#endif /* INCLUDED_USRP_SERVER_H */
+++ /dev/null
-;; -*- scheme -*- ; not really, but tells emacs how to format this
-;;
-;; Copyright 2007 Free Software Foundation, Inc.
-;;
-;; This file is part of GNU Radio
-;;
-;; GNU Radio is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; GNU Radio is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License along
-;; with this program; if not, write to the Free Software Foundation, Inc.,
-;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-;;
-
-;; ----------------------------------------------------------------
-;; This is an mblock header file
-;;
-;; The format is very much a work-in-progress.
-;; It'll be compiled to C++.
-;; ----------------------------------------------------------------
-
-;; In the outgoing messages described below, invocation-handle is an
-;; identifier provided by the client to tag the method invocation.
-;; The identifier will be returned with the response, to provide the
-;; client with a mechanism to match asynchronous responses with the
-;; commands that generate them. The value of the invocation-handle is
-;; opaque the the server, and is not required by the server to be
-;; unique.
-;;
-;; In the incoming messages described below, invocation-handle is the
-;; identifier provided by the client in the prompting invocation. The
-;; identifier is returned with the response, so that the client has a
-;; mechanism to match asynchronous responses with the commands that
-;; generated them.
-;;
-;; status is either #t, indicating success, or a symbol indicating an error.
-;; All symbol's names shall begin with %error-
-
-
-;; ----------------------------------------------------------------
-;; usrp-channel
-;;
-;; The protocol class is defined from the client's point-of-view.
-;; (The client port is unconjugated, the server port is conjugated.)
-
-(define-protocol-class usrp-channel
-
- (:outgoing
-
- (cmd-allocate-channel invocation-handle capacity-reservation)
-
- ;; The cmd-allocate-channel message requests that the server
- ;; allocates a logical channel in the FPGA for use.
- ;; capacity-reservation specifies the number of bytes/s of
- ;; interconnect capacity (USB or ethernet) to reserve for this
- ;; channel. (The reservation is just a sanity check, no OS
- ;; specific mechanism is used.)
-
- (cmd-deallocate-channel invocation-handle channel)
-
- ;; The integer channel specifies the channel to deallocate.
-
- )
-
- (:incoming
-
-
- (response-allocate-channel invocation-handle status channel)
-
- ;; If successful, a channel the specified capacity was allocated.
- ;; channel, an integer, indicates which channel was allocated.
-
- (response-deallocate-channel invocation-handle status)
-
- ;; If successful, the specified channel and associated interconnect
- ;; capacity were deallocated.
-
- )
- )
-
-;; ----------------------------------------------------------------
-;; usrp-low-level-cs
-;;
-;; The protocol class is defined from the client's point-of-view.
-;; (The client port is unconjugated, the server port is conjugated.)
-;;
-;; This defines a low level control and status interface to the usrp.
-;; This will probably be replaced (or at least augmented) with a
-;; higher level interface. For now, this will allow us to get on
-;; the air.
-;;
-;; The subpackets are lists containing the relevant parameters. The
-;; server will marshall them appropriately. Below is a list of
-;; subpackets. See inband-signaling-usb for details. The opcodes are
-;; symbols; unless otherwise indicated the remaining parameters are
-;; integers. rid values are limited to 3-bits.
-;;
-;; (op-ping-fixed rid ping-value)
-;; (op-ping-fixed-reply rid ping-value)
-;; (op-write-reg reg-number reg-value)
-;; (op-write-reg-masked reg-number reg-value mask-value)
-;; (op-read-reg rid reg-number)
-;; (op-read-reg-reply rid reg-number reg-value)
-;; (op-i2c-write i2c-addr u8-vec)
-;; (op-i2c-read rid i2c-addr nbytes)
-;; (op-i2c-read-reply rid i2c-addr u8-vec)
-;; (op-spi-write enables format opt-header-bytes u8-vec)
-;; (op-spi-read rid enables format opt-header-bytes nbytes)
-;; (op-spi-read-reply rid u8-vec)
-;; (op-delay ticks)
-
-
-(define-protocol-class usrp-low-level-cs
-
- (:outgoing
-
- (cmd-to-control-channel invocation-handle list-of-subpackets)
-
- )
-
- (:incoming
-
- (response-from-control-channel invocation-handle status list-of-subpackets timestamp)
-
- )
- )
-
-;; ----------------------------------------------------------------
-;; usrp-tx
-;;
-;; The protocol class is defined from the client's point-of-view.
-;; (The client port is unconjugated, the server port is conjugated.)
-
-(define-protocol-class usrp-tx
- (:include usrp-channel)
- (:include usrp-low-level-cs)
-
- (:outgoing
-
- (cmd-xmit-raw-frame invocation-handle channel samples timestamp properties)
-
- ;; The argument channel must be an integer. It specifies the
- ;; channel on which the frame of samples will be be sent.
- ;;
- ;; samples must be a uniform numeric vector. The contents of the
- ;; sample vector is treated as opaque and is passed on to the FPGA
- ;; unmodified. It is the responsibility of the sender to ensure
- ;; that the binary format is sensible for the current FPGA
- ;; configuration.
- ;;
- ;; timestamp is a 32-bit integer that specifies the time at which
- ;; the first sample in samples shall be sent to the D/A converter.
- ;; The format and interpration of time is specified in the file
- ;; inband-signaling-usb
- )
-
- (:incoming
-
- (response-xmit-raw-frame invocation-handle status)
-
- ;; If successful, the samples of the associated frame have been
- ;; transmitted to the USRP. This message may be used to implement
- ;; Tx flow control. The client could for example implement a
- ;; policy of never having more than 4 unacknowledged
- ;; cmd-xmit-raw-frame's outstanding.
-
- )
- )
-
-;; ----------------------------------------------------------------
-;; usrp-rx
-;;
-;; The protocol class is defined from the client's point-of-view.
-;; (The client port is unconjugated, the server port is conjugated.)
-
-(define-protocol-class usrp-rx
- (:include usrp-channel)
- (:include usrp-low-level-cs)
-
- (:outgoing
-
- (cmd-start-recv-raw-samples invocation-handle channel)
-
- ;; The argument channel must be an integer. It specifies the
- ;; channel from which frames of samples will be be received. The
- ;; server will return response-recv-raw-samples messages until a
- ;; cmd-stop-recv-raw-samples message is received.
-
- (cmd-stop-recv-raw-samples invocation-handle channel)
-
- ;; The argument channel must be an integer. There is no reply to
- ;; this message.
-
- )
-
- (:incoming
-
- (response-recv-raw-samples invocation-handle status samples timestamp channel properties)
-
- ;; samples is a uniform numeric vector. The contents of the sample
- ;; vector is treated as opaque and is passed from the FPGA
- ;; unmodified. It is the responsibility of the receiver to decode
- ;; the binary format as appropriate for the current FPGA
- ;; configuration.
- ;;
- ;; timestamp is a 32-bit integer that specifies the time at which
- ;; the first sample in samples was received from the A/D converter.
- ;; The format and interpretation of time is as specified in the
- ;; file inband-signaling-usb.
- ;;
- ;; properties is a dictionary containing additional (key, value)
- ;; pairs associated with the reception of these samples. In
- ;; particular, the map may contain the Received Signal Strength
- ;; Indication (RSSI) reported by the front end at the time the
- ;; first sample was received from the A/D.
-
- )
- )
-
-
-;; ----------------------------------------------------------------
-;; usrp-server-cs
-;;
-;; Control and status port for usrp-server
-;;
-;; The protocol class is defined from the client's point-of-view.
-;; (The client port is unconjugated, the server port is conjugated.)
-
-(define-protocol-class usrp-server-cs
-
- (:outgoing
- (cmd-open invocation-handle which-usrp)
- (cmd-close invocation-handle)
- (cmd-max-capacity invocation-handle)
- (cmd-ntx-chan invocation-handle)
- (cmd-nrx-chan invocation-handle)
- (cmd-current-capacity-allocation invocation-handle)
- )
-
- (:incoming
- (response-open invocation-handle status)
- (response-close invocation-handle status)
- (response-max-capacity invocation-handle status capacity)
- (response-ntx-chan invocation-handle status ntx-chan)
- (response-nrx-chan invocation-handle status nrx-chan)
- (response-current-capacity-allocation invocation-handle status capacity)
- )
- )
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <usrp_tx.h>
-#include <iostream>
-#include <usb.h>
-#include <mblock/class_registry.h>
-#include <usrp_inband_usb_packet.h>
-#include <fpga_regs_common.h>
-#include <usrp_standard.h>
-#include <stdio.h>
-
-#include <symbols_usrp_tx_cs.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-static const bool verbose = false;
-
-usrp_tx::usrp_tx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(rt, instance_name, user_arg),
- d_disk_write(false)
-{
- d_cs = define_port("cs", "usrp-tx-cs", true, mb_port::EXTERNAL);
-
- //d_disk_write=true;
-
- if(d_disk_write) {
- d_ofile.open("tx_data.dat",std::ios::binary|std::ios::out);
- d_cs_ofile.open("tx_cs.dat",std::ios::binary|std::ios::out);
- }
-}
-
-usrp_tx::~usrp_tx()
-{
- if(d_disk_write) {
- d_ofile.close();
- d_cs_ofile.close();
- }
-}
-
-void
-usrp_tx::initial_transition()
-{
-
-}
-
-/*!
- * \brief Handles incoming signals to to the m-block, wihch should only ever be
- * a single message: cmd-usrp-tx-write.
- */
-void
-usrp_tx::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t port_id = msg->port_id();
- pmt_t data = msg->data();
-
- // Theoretically only have 1 message to ever expect, but
- // want to make sure its at least what we want
- if(pmt_eq(port_id, d_cs->port_symbol())) {
-
- if(pmt_eqv(event, s_cmd_usrp_tx_write))
- write(data);
- }
-}
-
-/*!
- * \brief Performs the actual writing of data to the USB bus, called by
- * handle_message() when a cmd-usrp-tx-write signal is received.
- *
- * The \p data parameter is a PMT list which contains three mandatory elements,
- * in the following order: an invocation handle, a channel, and a uniform vector
- * of memory which contains the packets to be written to the bus.
- */
-void
-usrp_tx::write(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t channel = pmt_nth(1, data);
- pmt_t v_packets = pmt_nth(2, data);
- d_utx = boost::any_cast<usrp_standard_tx_sptr>(pmt_any_ref(pmt_nth(3, data)));
-
- size_t n_bytes;
- bool underrun; // this will need to go, as it is taken care of in the packet headers
-
- transport_pkt *pkts = (transport_pkt *) pmt_u8vector_writable_elements(v_packets, n_bytes);
-
- int ret = d_utx->write (pkts, n_bytes, &underrun);
-
- if (0 && underrun)
- fprintf(stderr, "uU");
-
- if (ret == (int) n_bytes) {
- if (verbose)
- std::cout << "[usrp_server] Write of " << n_bytes << " successful\n";
- // need to respond with the channel so the USRP server knows who to forward the result of
- // the write to by looking up the owner of the channel
- d_cs->send(s_response_usrp_tx_write,
- pmt_list3(invocation_handle, PMT_T, channel));
- }
- else {
- if (verbose)
- std::cout << "[usrp_server] Error writing " << n_bytes << " bytes to USB bus\n";
- d_cs->send(s_response_usrp_tx_write,
- pmt_list3(invocation_handle, PMT_F, channel));
- }
-
- long n_packets =
- static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size()));
-
- for(int i=0; i < n_packets; i++) {
-
- if(d_disk_write) {
- if(pkts[i].chan() == CONTROL_CHAN)
- d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
- else
- d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
-
- d_cs_ofile.flush();
- d_ofile.flush();
- }
- }
-
-
- return;
-}
-
-REGISTER_MBLOCK_CLASS(usrp_tx);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_TX_H
-#define INCLUDED_USRP_TX_H
-
-#include <mblock/mblock.h>
-#include <fstream>
-#include "usrp_standard.h"
-
-/*!
- * \brief Implements the low level usb interface to the USRP
- */
-class usrp_tx : public mb_mblock
-{
- mb_port_sptr d_cs;
- usrp_standard_tx_sptr d_utx;
-
- bool d_disk_write;
- std::ofstream d_ofile;
- std::ofstream d_cs_ofile;
-
- public:
- usrp_tx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
- ~usrp_tx();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- private:
- void write(pmt_t data);
-};
-
-
-#endif /* INCLUDED_USRP_TX_H */
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <iostream>
-#include <vector>
-#include <usb.h>
-#include <mblock/class_registry.h>
-#include <usrp_tx_stub.h>
-#include <usrp_inband_usb_packet.h>
-#include <fpga_regs_common.h>
-#include "usrp_standard.h"
-#include <stdio.h>
-#include <fstream>
-#include <usrp_rx_stub.h>
-
-#include <symbols_usrp_tx_cs.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-static const bool verbose = false;
-
-usrp_tx_stub::usrp_tx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(rt, instance_name, user_arg),
- d_disk_write(false)
-{
- d_cs = define_port("cs", "usrp-tx-cs", true, mb_port::EXTERNAL);
-
- //d_disk_write=true;
-
- if(d_disk_write) {
- d_ofile.open("tx_stub_data.dat",std::ios::binary|std::ios::out);
- d_cs_ofile.open("tx_stub_cs.dat",std::ios::binary|std::ios::out);
- }
-}
-
-usrp_tx_stub::~usrp_tx_stub()
-{
- if(d_disk_write) {
- d_ofile.close();
- d_cs_ofile.close();
- }
-}
-
-void
-usrp_tx_stub::initial_transition()
-{
-
-}
-
-void
-usrp_tx_stub::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal();
- pmt_t port_id = msg->port_id();
- pmt_t data = msg->data();
-
- // Theoretically only have 1 message to ever expect, but
- // want to make sure its at least what we want
- if(pmt_eq(port_id, d_cs->port_symbol())) {
-
- if(pmt_eqv(event, s_cmd_usrp_tx_write))
- write(data);
- }
-}
-
-void
-usrp_tx_stub::write(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t channel = pmt_nth(1, data);
- pmt_t v_packets = pmt_nth(2, data);
- d_utx = boost::any_cast<usrp_standard_tx *>(pmt_any_ref(pmt_nth(3, data)));
-
- size_t n_bytes;
-
- transport_pkt *pkts = (transport_pkt *) pmt_u8vector_writable_elements(v_packets, n_bytes);
- long n_packets = static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size()));
-
- // Parse the packets looking for C/S packets and dump them to a disk if
- // necessary
- for(long i=0; i<n_packets; i++) {
-
- if(d_disk_write) {
- if(pkts[i].chan() == CONTROL_CHAN)
- d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
- else
- d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
-
- d_cs_ofile.flush();
- d_ofile.flush();
- }
-
- if(pkts[i].chan() == CONTROL_CHAN)
- parse_cs(invocation_handle, pkts[i]);
- }
-
- d_cs->send(s_response_usrp_tx_write,
- pmt_list3(invocation_handle, PMT_T, channel));
-
- return;
-}
-
-void
-usrp_tx_stub::parse_cs(pmt_t invocation_handle, transport_pkt pkt)
-{
-
- long payload_len = pkt.payload_len();
- long curr_payload = 0;
-
- size_t ignore;
-
- // There is the possibility that the responses for a single USB packet full of
- // CS packets will not fit back in a single USB packet, considering some
- // responses are greater than their commands (read registers).
- new_packet:
- pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0);
-
- transport_pkt *q_pkt =
- (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, ignore);
-
- q_pkt->set_header(0, CONTROL_CHAN, 0, 0);
- q_pkt->set_timestamp(0xffffffff);
-
- // We dispatch based on the control packet type, however we can extract the
- // opcode and the length immediately which is consistent in all responses.
- //
- // Since each control packet can have multiple responses, we keep reading the
- // lengths of each subpacket until we reach the payload length.
- while(curr_payload < payload_len) {
-
- pmt_t sub_packet = pkt.read_subpacket(curr_payload);
- pmt_t op_symbol = pmt_nth(0, sub_packet);
-
- int len = pkt.cs_len(curr_payload);
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Parsing subpacket "
- << op_symbol << " ... length " << len << std::endl;
-
- //----------------- PING FIXED ------------------//
- if(pmt_eq(op_symbol, s_op_ping_fixed)) {
-
- long rid = pmt_to_long(pmt_nth(1, sub_packet));
- long pingval = pmt_to_long(pmt_nth(2, sub_packet));
-
- // Generate a reply and put it in the queue for the RX stub to read
- if(!q_pkt->cs_ping_reply(rid, pingval))
- goto new_packet;
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Generated ping response "
- << "("
- << "RID: " << rid << ", "
- << "VAL: " << pingval
- << ")\n";
- }
-
- //----------------- READ REG ------------------//
- if(pmt_eq(op_symbol, s_op_read_reg)) {
-
- long rid = pmt_to_long(pmt_nth(1, sub_packet));
- long reg_num = pmt_to_long(pmt_nth(2, sub_packet));
- long reg_val = 0xdeef;
-
- // Generate a reply and put it in the queue for the RX stub to read
- if(!q_pkt->cs_read_reg_reply(rid, reg_num, reg_val))
- goto new_packet;
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Generated read register response "
- << "("
- << "RID: " << rid << ", "
- << "REG: " << reg_num << ", "
- << "VAL: " << reg_val
- << ")\n";
- }
-
- //----------------- DELAY ------------------//
- if(pmt_eq(op_symbol, s_op_delay)) {
-
- long ticks = pmt_to_long(pmt_nth(1, sub_packet));
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received delay command "
- << "("
- << "Ticks: " << ticks
- << ")\n";
- }
-
- //----------------- WRITE REG ------------------//
- if(pmt_eq(op_symbol, s_op_write_reg)) {
-
- pmt_t reg_num = pmt_nth(1, sub_packet);
- pmt_t reg_val = pmt_nth(2, sub_packet);
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received write register command "
- << "("
- << "RegNum: " << reg_num << ", "
- << "Val: " << reg_val
- << ")\n";
- }
-
- //----------------- WRITE REG MASK ---------------//
- if(pmt_eq(op_symbol, s_op_write_reg_masked)) {
-
- pmt_t reg_num = pmt_nth(1, sub_packet);
- pmt_t reg_val = pmt_nth(2, sub_packet);
- pmt_t mask = pmt_nth(3, sub_packet);
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received write register command "
- << "("
- << "RegNum: " << reg_num << ", "
- << "Val: " << reg_val << ", "
- << "Mask: " << mask
- << ")\n";
- }
-
- //---------------- I2C WRITE ------------------//
- if(pmt_eq(op_symbol, s_op_i2c_write)) {
- pmt_t i2c_addr = pmt_nth(1, sub_packet);
- pmt_t i2c_data = pmt_nth(2, sub_packet);
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received i2c write command "
- << "("
- << "Addr: " << i2c_addr << ", "
- << "Data: " << i2c_data
- << ")\n";
- }
-
- //---------------- I2C READ ------------------//
- if(pmt_eq(op_symbol, s_op_i2c_read)) {
- long rid = pmt_to_long(pmt_nth(1, sub_packet));
- long i2c_addr = pmt_to_long(pmt_nth(2, sub_packet));
- long i2c_bytes = pmt_to_long(pmt_nth(3, sub_packet));
-
- // Create data to place as a response, filled with 0xff
- size_t ignore;
- pmt_t i2c_data = pmt_make_u8vector(i2c_bytes, 0xff);
- uint8_t *w_data = (uint8_t *) pmt_u8vector_writable_elements(i2c_data, ignore);
-
- // Generate a reply and put it in the queue for the RX stub to read
- if(!q_pkt->cs_i2c_read_reply(rid, i2c_addr, w_data, i2c_bytes))
- goto new_packet;
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received i2c read "
- << "("
- << "RID: " << rid << ", "
- << "Addr: " << i2c_addr << ", "
- << "Bytes: " << i2c_bytes
- << ")\n";
- }
-
- //---------------- SPI WRITE ------------------//
- if(pmt_eq(op_symbol, s_op_spi_write)) {
- long enables = pmt_to_long(pmt_nth(1, sub_packet));
- long format = pmt_to_long(pmt_nth(2, sub_packet));
- long opt = pmt_to_long(pmt_nth(3, sub_packet));
- pmt_t data = pmt_nth(4, sub_packet);
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received spi write command "
- << "("
- << "Enables: " << enables << ", "
- << "Format: " << format << ", "
- << "Options: " << opt << ", "
- << "Data: " << data
- << ")\n";
- }
-
- //---------------- SPI READ ------------------//
- if(pmt_eq(op_symbol, s_op_spi_read)) {
- long rid = pmt_to_long(pmt_nth(1, sub_packet));
- long enables = pmt_to_long(pmt_nth(2, sub_packet));
- long format = pmt_to_long(pmt_nth(3, sub_packet));
- long opt = pmt_to_long(pmt_nth(4, sub_packet));
- long n_bytes = pmt_to_long(pmt_nth(5, sub_packet));
-
- // Create data to place as a fake response
- size_t ignore;
- pmt_t spi_data = pmt_make_u8vector(n_bytes, 0xff);
- uint8_t *w_data = (uint8_t *) pmt_u8vector_writable_elements(spi_data, ignore);
-
- // Generate a reply and put it in the queue for the RX stub to read
- if(!q_pkt->cs_spi_read_reply(rid, w_data, n_bytes))
- goto new_packet;
-
- if(verbose)
- std::cout << "[USRP_TX_STUB] Received spi read command "
- << "("
- << "RID: " << rid << ", "
- << "Enables: " << enables << ", "
- << "Format: " << format << ", "
- << "Options: " << opt << ", "
- << "Bytes: " << n_bytes
- << ")\n";
-
- }
-
- // Each subpacket has an unaccounted for 2 bytes which is the opcode
- // and the length field
- curr_payload += len + 2;
-
- // All subpackets are 32-bit aligned
- int align_offset = 4 - (curr_payload % 4);
-
- if(align_offset != 4)
- curr_payload += align_offset;
-
- }
-
- // If the packet has data in the payload, it needs queued
- if(q_pkt->payload_len() > 0)
- d_cs_queue.push(pmt_list2(invocation_handle, v_pkt));
-
- return;
-}
-
-REGISTER_MBLOCK_CLASS(usrp_tx_stub);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_TX_STUB_H
-#define INCLUDED_USRP_TX_STUB_H
-
-#include <mblock/mblock.h>
-#include <vector>
-#include "usrp_standard.h"
-#include <fstream>
-#include <usrp_inband_usb_packet.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-/*!
- * \brief Implements the low level usb interface to the USRP
- */
-class usrp_tx_stub : public mb_mblock
-{
- public:
-
- mb_port_sptr d_cs;
- usrp_standard_tx* d_utx;
-
- std::ofstream d_ofile;
- std::ofstream d_cs_ofile;
-
- bool d_disk_write;
-
- public:
- usrp_tx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
- ~usrp_tx_stub();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
-
- private:
- void write(pmt_t data);
- void parse_cs(pmt_t invocation_handle, transport_pkt pkt);
-
-};
-
-
-#endif /* INCLUDED_USRP_TX_STUB_H */
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <usrp_usb_interface.h>
-
-#include <iostream>
-#include <vector>
-#include <usb.h>
-#include <mblock/class_registry.h>
-#include <usrp_inband_usb_packet.h>
-#include <fpga_regs_common.h>
-#include "usrp_rx.h"
-#include <usrp_rx_stub.h>
-#include "usrp_tx.h"
-#include "usrp_standard.h"
-#include <stdio.h>
-#include <usrp_dbid.h>
-
-typedef usrp_inband_usb_packet transport_pkt;
-
-#include <symbols_usrp_interface_cs.h>
-#include <symbols_usrp_tx_cs.h>
-#include <symbols_usrp_rx_cs.h>
-static pmt_t s_shutdown = pmt_intern("%shutdown");
-
-static const bool verbose = false;
-
-
-/*!
- * \brief Initializes the USB interface m-block.
- *
- * The \p user_arg should be a PMT dictionary which can contain optional
- * arguments for the block, such as the decimatoin and interpolation rate.
- */
-usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
- : mb_mblock(rt, instance_name, user_arg),
- d_fake_usrp(false),
- d_rx_reading(false),
- d_interp_tx(128),
- d_decim_rx(128),
- d_rf_freq(-1),
- d_rbf("inband_tx_rx.rbf")
-{
- // Dictionary for arguments to all of the components
- pmt_t usrp_dict = user_arg;
-
- // Default TX/RX interface
- std::string tx_interface = "usrp_tx";
- std::string rx_interface = "usrp_rx";
-
- if (pmt_is_dict(usrp_dict)) {
-
- // The 'fake-usrp' key enables the TX and RX stubs if PMT_T
- if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict,
- pmt_intern("fake-usrp"),
- PMT_NIL)) {
- if(pmt_eqv(fake_usrp, PMT_T)) {
- tx_interface = "usrp_tx_stub";
- rx_interface = "usrp_rx_stub";
- d_fake_usrp=true;
- }
- }
-
- // Read the TX interpolations
- if(pmt_t interp_tx = pmt_dict_ref(usrp_dict,
- pmt_intern("interp-tx"),
- PMT_NIL)) {
- if(!pmt_eqv(interp_tx, PMT_NIL))
- d_interp_tx = pmt_to_long(interp_tx);
- }
-
- // Read the RX decimation rate
- if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
- pmt_intern("decim-rx"),
- PMT_NIL)) {
- if(!pmt_eqv(decim_rx, PMT_NIL))
- d_decim_rx = pmt_to_long(decim_rx);
- }
-
- // Read the RBF
- if(pmt_t rbf = pmt_dict_ref(usrp_dict,
- pmt_intern("rbf"),
- PMT_NIL)) {
- if(!pmt_eqv(rbf, PMT_NIL))
- d_rbf = pmt_symbol_to_string(rbf);
- }
-
- // The RF center frequency
- if(pmt_t rf_freq = pmt_dict_ref(usrp_dict,
- pmt_intern("rf-freq"),
- PMT_NIL)) {
- if(!pmt_eqv(rf_freq, PMT_NIL))
- d_rf_freq = pmt_to_double(rf_freq);
- }
- }
-
- if (verbose) {
- std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to "
- << d_rbf << std::endl;
-
- std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to "
- << d_interp_tx << std::endl;
-
- std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to "
- << d_decim_rx << std::endl;
-
- std::cout << "[USRP_USB_INTERFACE] Using TX interface: "
- << tx_interface << "\n";
-
- std::cout << "[USRP_USB_INTERFACE] Using RX interface: "
- << rx_interface << "\n";
-
- }
-
- d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL);
- d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL);
- d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL);
-
- // Connect to TX and RX
- define_component("tx", tx_interface, usrp_dict);
- define_component("rx", rx_interface, usrp_dict);
- connect("self", "rx_cs", "rx", "cs");
- connect("self", "tx_cs", "tx", "cs");
-
- // FIXME: the code should query the FPGA to retrieve the number of channels and such
- d_ntx_chan = 2;
- d_nrx_chan = 2;
-}
-
-usrp_usb_interface::~usrp_usb_interface()
-{
-
-}
-
-void
-usrp_usb_interface::initial_transition()
-{
-
-}
-
-/*!
- * \brief Handles all incoming signals to the block from the lowest m-blocks
- * which read/write to the bus, or the higher m-block which is the USRP server.
- */
-void
-usrp_usb_interface::handle_message(mb_message_sptr msg)
-{
- pmt_t event = msg->signal(); // the "name" of the message
- pmt_t port_id = msg->port_id(); // which port it came in on
- pmt_t data = msg->data();
- pmt_t invocation_handle;
-
- if (pmt_eq(event, s_shutdown)) // ignore (for now)
- return;
-
- //------------- CONTROL / STATUS -------------//
- if (pmt_eq(port_id, d_cs->port_symbol())) {
-
- //------------ OPEN --------------//
- if (pmt_eq(event, s_cmd_usrp_open)){
- handle_cmd_open(data);
- return;
- }
- //----------- CLOSE -------------//
- else if (pmt_eq(event, s_cmd_usrp_close)) {
- handle_cmd_close(data);
- return;
- }
- //---------- NTX CHAN ----------//
- else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
- invocation_handle = pmt_nth(0, data);
- d_cs->send(s_response_usrp_ntx_chan,
- pmt_list2(invocation_handle,
- pmt_from_long(d_ntx_chan)));
- return;
- }
- //---------- NRX CHAN ----------//
- else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
- invocation_handle = pmt_nth(0, data);
- d_cs->send(s_response_usrp_nrx_chan,
- pmt_list2(invocation_handle,
- pmt_from_long(d_nrx_chan)));
- return;
- }
- //------------ WRITE -----------//
- else if(pmt_eq(event, s_cmd_usrp_write)) {
- handle_cmd_write(data);
- return;
- }
- //-------- START READING --------//
- else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
- handle_cmd_start_reading(data);
- return;
- }
- //-------- STOP READING --------//
- else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
- handle_cmd_stop_reading(data);
- return;
- }
-
- goto unhandled;
- }
-
- //---------------- RX ------------------//
- if (pmt_eq(port_id, d_rx_cs->port_symbol())) {
-
- // Relay reads back up
- if(pmt_eq(event, s_response_usrp_rx_read)) {
- d_cs->send(s_response_usrp_read, data);
- return;
- }
-
- goto unhandled;
- }
-
- //---------------- TX ------------------//
- if (pmt_eq(port_id, d_tx_cs->port_symbol())) {
-
- if(pmt_eq(event, s_response_usrp_tx_write)) {
-
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t status = pmt_nth(1, data);
- pmt_t channel = pmt_nth(2, data);
-
- d_cs->send(s_response_usrp_write,
- pmt_list3(invocation_handle,
- status,
- channel));
-
- return;
- }
-
- goto unhandled;
- }
-
- unhandled:
- std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is to
- * open a USB connection to the USRP (cmd-usrp-open).
- *
- * The \p data parameter is a PMT list, where the elements are an invocation
- * handle and the USRP number.
- */
-void
-usrp_usb_interface::handle_cmd_open(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- long which_usrp = pmt_to_long(pmt_nth(1, data));
- pmt_t reply_data;
-
- if(d_fake_usrp) {
- d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
- return;
- }
-
- if (verbose)
- std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
-
- // Open up a standard RX and TX for communication with the USRP
-
- d_utx = usrp_standard_tx::make(which_usrp,
- d_interp_tx,
- 1, // 1 channel
- -1, // mux
- 4096, // USB block size
- 16, // nblocks for async transfers
- d_rbf
- );
-
- if(d_utx==0) {
- if (verbose)
- std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
- reply_data = pmt_list2(invocation_handle, PMT_F);
- d_cs->send(s_response_usrp_open, reply_data);
- return;
- }
-
- // Perform TX daughterboard tuning
- double target_freq;
- unsigned int mux;
- int tgain, rgain;
- float input_rate;
- bool ok;
- usrp_tune_result r;
-
- // Cast to usrp_basic and then detect daughterboards
- d_ub_tx = d_utx;
- usrp_subdev_spec tspec = pick_tx_subdevice();
- db_base_sptr tsubdev = d_ub_tx->selected_subdev(tspec);
-
- // Set the TX mux value
- mux = d_utx->determine_tx_mux_value(tspec);
- d_utx->set_mux(mux);
-
- // Set the TX gain and determine rate
- tgain = tsubdev->gain_max();
- tsubdev->set_gain(tgain);
- input_rate = d_ub_tx->converter_rate() / d_utx->interp_rate();
-
- // Perform the actual tuning, if no frequency specified then pick
- if(d_rf_freq==-1)
- target_freq = tsubdev->freq_min()+((tsubdev->freq_max()-tsubdev->freq_min())/2.0);
- else
- target_freq = d_rf_freq;
- ok = d_utx->tune(tsubdev->which(), tsubdev, target_freq, &r);
- tsubdev->set_enable(true);
-
- if(verbose) {
- printf("TX Subdevice name is %s\n", tsubdev->name().c_str());
- printf("TX Subdevice freq range: (%g, %g)\n",
- tsubdev->freq_min(), tsubdev->freq_max());
- printf("mux: %#08x\n", mux);
- printf("target_freq: %f\n", target_freq);
- printf("ok: %s\n", ok ? "true" : "false");
- printf("gain: %d\n", tgain);
- printf("r.baseband_freq: %f\n", r.baseband_freq);
- printf("r.dxc_freq: %f\n", r.dxc_freq);
- printf("r.residual_freq: %f\n", r.residual_freq);
- printf("r.inverted: %d\n", r.inverted);
- }
-
- if(!ok) {
- std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
- reply_data = pmt_list2(invocation_handle, PMT_F);
- d_cs->send(s_response_usrp_open, reply_data);
- return;
- }
-
- d_utx->start();
-
- if (verbose)
- std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
-
- d_urx =
- usrp_standard_rx::make (which_usrp,
- d_decim_rx,
- 1, // nchan
- -1, // mux
- 0, // set blank mode to start
- 4096, // USB block size
- 16, // number of blocks for async transfers
- d_rbf);
-
- if(!d_urx) {
- if (verbose)
- std::cout << "[usrp_server] Failed to open RX\n";
- reply_data = pmt_list2(invocation_handle, PMT_F);
- d_cs->send(s_response_usrp_open, reply_data);
- return;
- }
-
- // Cast to usrp_basic and then detect daughterboards
- d_ub_rx = d_urx;
- usrp_subdev_spec rspec = pick_rx_subdevice();
- db_base_sptr rsubdev = d_ub_rx->selected_subdev(rspec);
-
- // Set the RX mux value
- mux = d_urx->determine_rx_mux_value(rspec);
- d_urx->set_mux(mux);
-
- // Set the RX gain and determine rate
- rgain = rsubdev->gain_max()/2.0;
- rsubdev->set_gain(rgain);
- input_rate = d_ub_rx->converter_rate() / d_urx->decim_rate();
-
- ok = d_urx->tune(rsubdev->which(), rsubdev, target_freq, &r);
- rsubdev->set_enable(true);
-
- if(verbose) {
- printf("RX Subdevice name is %s\n", rsubdev->name().c_str());
- printf("RX Subdevice freq range: (%g, %g)\n",
- rsubdev->freq_min(), rsubdev->freq_max());
- printf("mux: %#08x\n", mux);
- printf("target_freq: %f\n", target_freq);
- printf("ok: %s\n", ok ? "true" : "false");
- printf("gain: %d\n", rgain);
- printf("r.baseband_freq: %f\n", r.baseband_freq);
- printf("r.dxc_freq: %f\n", r.dxc_freq);
- printf("r.residual_freq: %f\n", r.residual_freq);
- printf("r.inverted: %d\n", r.inverted);
- }
-
- if(!ok) {
- std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on RX\n";
- reply_data = pmt_list2(invocation_handle, PMT_F);
- d_cs->send(s_response_usrp_open, reply_data);
- return;
- }
-
- if (verbose)
- std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
-
-// d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
-// d_utx->_write_oe(0, 0xffff, 0xffff);
-// d_urx->_write_oe(0, 0xffff, 0xffff);
-// d_utx->_write_oe(1, 0xffff, 0xffff);
-// d_urx->_write_oe(1, 0xffff, 0xffff);
-
- d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is to
- * write data to the USB bus (cmd-usrp-write).
- *
- * The \p data parameter is a PMT list containing 3 mandatory elements in the
- * following order: an invocation handle, channel, and a uniform vector
- * representation of the packets.
- */
-void
-usrp_usb_interface::handle_cmd_write(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
- pmt_t channel = pmt_nth(1, data);
- pmt_t pkts = pmt_nth(2, data);
-
- pmt_t tx_handle = pmt_make_any(d_utx);
-
- d_tx_cs->send(s_cmd_usrp_tx_write,
- pmt_list4(invocation_handle,
- channel,
- pkts,
- tx_handle));
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is to
- * start reading data from the USB bus (cmd-usrp-start-reading).
- *
- * The \p data parameter is a PMT list with a single element: an invocation
- * handle which can be returned with the response.
- */
-void
-usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
-
- if(verbose)
- std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
-
- if(!d_fake_usrp)
- d_urx->start();
-
- pmt_t rx_handle = pmt_make_any(d_urx);
-
- d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
-
- d_rx_reading = true;
-
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is to
- * stop reading data from the USB bus (cmd-usrp-stop-reading).
- *
- * The \p data parameter is a PMT list with a single element: an invocation
- * handle which can be returned with the response.
- */
-void
-usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
-
- if(!d_fake_usrp) {
- if(verbose)
- std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
- usrp_rx_stop = true;
-
- // Used to allow a read() being called by a lower layer to complete before
- // stopping, else there can be partial data left on the bus and can generate
- // errors.
- while(usrp_rx_stop) {usleep(1);}
- d_urx->stop();
- }
- else {
- if(verbose)
- std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
- usrp_rx_stop_stub = true; // extern to communicate with stub to wait
- }
-
- d_rx_reading = false;
-
- return;
-}
-
-/*!
- * \brief Called by the handle_message() method when the incoming signal is to
- * close the USB connection to the USRP.
- *
- * The \p data parameter is a PMT list with a single element: an invocation
- * handle which can be returned with the response.
- */
-void
-usrp_usb_interface::handle_cmd_close(pmt_t data)
-{
- pmt_t invocation_handle = pmt_nth(0, data);
-
- if(d_rx_reading)
- handle_cmd_stop_reading(PMT_NIL);
-
- if(d_fake_usrp) {
- d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
- return;
- }
-
- if (verbose)
- std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
-
- d_utx.reset();
- d_urx.reset();
-
- d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
-
- // FIXME This seems like a _very_ strange place to be calling shutdown_all.
- // That decision should be left to high-level code, not low-level code like this.
- shutdown_all(PMT_T);
-}
-
-usrp_subdev_spec
-usrp_usb_interface::pick_rx_subdevice()
-{
- int dbids[] = {
- USRP_DBID_FLEX_400_RX,
- USRP_DBID_FLEX_900_RX,
- USRP_DBID_FLEX_1200_RX,
- USRP_DBID_FLEX_2400_RX,
- USRP_DBID_TV_RX,
- USRP_DBID_TV_RX_REV_2,
- USRP_DBID_DBS_RX,
- USRP_DBID_BASIC_RX
- };
-
- std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
- return pick_subdev(d_ub_rx, candidates);
-}
-
-usrp_subdev_spec
-usrp_usb_interface::pick_tx_subdevice()
-{
- int dbids[] = {
- USRP_DBID_FLEX_400_TX,
- USRP_DBID_FLEX_900_TX,
- USRP_DBID_FLEX_1200_TX,
- USRP_DBID_FLEX_2400_TX,
- USRP_DBID_BASIC_TX
- };
-
- std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
- return pick_subdev(d_ub_tx, candidates);
-}
-
-usrp_subdev_spec
-usrp_usb_interface::pick_subdev(boost::shared_ptr<usrp_basic> d_usrp_basic, std::vector<int> candidates)
-{
- int dbid0 = d_usrp_basic->selected_subdev(usrp_subdev_spec(0, 0))->dbid();
- int dbid1 = d_usrp_basic->selected_subdev(usrp_subdev_spec(1, 0))->dbid();
-
- for (int i = 0; i < candidates.size(); i++) {
- int dbid = candidates[i];
- if (dbid0 == dbid)
- return usrp_subdev_spec(0, 0);
- if (dbid1 == dbid)
- return usrp_subdev_spec(1, 0);
- }
-
- if (dbid0 >= 0)
- return usrp_subdev_spec(0, 0);
- if (dbid1 >= 0)
- return usrp_subdev_spec(1, 0);
-
- throw std::runtime_error("No suitable daughterboard found!");
-}
-
-
-REGISTER_MBLOCK_CLASS(usrp_usb_interface);
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_USB_INTERFACE_H
-#define INCLUDED_USRP_USB_INTERFACE_H
-
-#include <mblock/mblock.h>
-#include <vector>
-#include "usrp_standard.h"
-
-/*!
- * \brief Implements the low level usb interface to the USRP
- */
-class usrp_usb_interface : public mb_mblock
-{
- public:
-
- usrp_standard_tx_sptr d_utx;
- usrp_standard_rx_sptr d_urx;
-
- boost::shared_ptr<usrp_basic> d_ub_tx;
- boost::shared_ptr<usrp_basic> d_ub_rx;
-
- mb_port_sptr d_cs;
- mb_port_sptr d_rx_cs;
- mb_port_sptr d_tx_cs;
-
- long d_ntx_chan;
- long d_nrx_chan;
-
- bool d_fake_usrp;
-
- bool d_rx_reading;
-
- long d_interp_tx;
- long d_decim_rx;
-
- double d_rf_freq;
-
- std::string d_rbf;
-
- public:
- usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
- ~usrp_usb_interface();
- void initial_transition();
- void handle_message(mb_message_sptr msg);
- usrp_subdev_spec pick_rx_subdevice();
- usrp_subdev_spec pick_tx_subdevice();
- usrp_subdev_spec pick_subdev(boost::shared_ptr<usrp_basic> d_usrp_basic, std::vector<int> candidates);
-
- private:
- void handle_cmd_open(pmt_t data);
- void handle_cmd_close(pmt_t data);
- void handle_cmd_write(pmt_t data);
- void handle_cmd_start_reading(pmt_t data);
- void handle_cmd_stop_reading(pmt_t data);
-
-};
-
-
-#endif /* INCLUDED_USRP_USB_INTERFACE_H */
+++ /dev/null
-#
-# USRP - Universal Software Radio Peripheral
-#
-# Copyright (C) 2003,2004,2006,2007,2008,2009 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 3 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., 51 Franklin Street, Boston, MA 02110-1301 USA
-#
-
-include $(top_srcdir)/Makefile.common
-
-common_INCLUDES = $(USRP_INCLUDES)
-
-lib_LTLIBRARIES = libusrp.la
-
-libusrp_la_common_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 $(BOOST_LDFLAGS)
-
-libusrp_la_common_LIBADD = \
- $(USB_LIBS) \
- $(BOOST_THREAD_LIB) \
- ../../misc/libmisc.la
-
-# darwin fusb requires omnithreads
-if FUSB_TECH_darwin
-AM_CPPFLAGS = $(common_INCLUDES) $(OMNITHREAD_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
-libusrp_la_LIBADD = $(libusrp_la_common_LIBADD) $(OMNITHREAD_LA)
-libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS) -framework CoreFoundation
-else
-AM_CPPFLAGS = $(common_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
-libusrp_la_LIBADD = $(libusrp_la_common_LIBADD)
-libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS)
-endif
-
-EXTRA_DIST = \
- std_paths.h.in \
- usrp_dbid.dat
-
-BUILT_SOURCES = \
- usrp_dbid.h
-
-BUILT_SOURCES += 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
-
-ra_wb_CODE = \
- fusb_ra_wb.cc \
- fusb_sysconfig_ra_wb.cc
-
-
-#
-# include each <foo>_CODE entry here...
-#
-EXTRA_libusrp_la_SOURCES = \
- $(generic_CODE) \
- $(darwin_CODE) \
- $(win32_CODE) \
- $(linux_CODE) \
- $(ra_wb_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 \
- db_boards.cc \
- db_base.cc \
- db_basic.cc \
- db_tv_rx.cc \
- db_flexrf.cc \
- db_flexrf_mimo.cc \
- db_dbs_rx.cc \
- db_xcvr2450.cc \
- db_dtt754.cc \
- db_dtt768.cc \
- db_util.cc
-
-
-
-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
-
-if FUSB_TECH_ra_wb
-libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE)
-endif
-
-include_HEADERS = \
- db_base.h \
- db_basic.h \
- db_dbs_rx.h \
- db_dtt754.h \
- db_dtt768.h \
- db_flexrf.h \
- db_flexrf_mimo.h \
- db_tv_rx.h \
- db_util.h \
- db_xcvr2450.h \
- usrp_basic.h \
- usrp_bytesex.h \
- usrp_config.h \
- usrp_dbid.h \
- usrp_prims.h \
- usrp_slots.h \
- usrp_standard.h \
- usrp_subdev_spec.h \
- usrp_tune_result.h
-
-noinst_HEADERS = \
- ad9862.h \
- db_base_impl.h \
- db_boards.h \
- db_wbx.h \
- fusb.h \
- fusb_darwin.h \
- fusb_generic.h \
- fusb_linux.h \
- fusb_ra_wb.h \
- fusb_win32.h \
- md5.h \
- rate_to_regval.h \
- usrp_local_sighandler.h
-
-if PYTHON
-usrppython_PYTHON = \
- usrp_dbid.py
-
-noinst_PYTHON = \
- gen_usrp_dbid.py \
- check_data.py \
- dump_data.py
-
-swiginclude_HEADERS = db_base.i
-endif
-
-# common way for generating sources from templates when using
-# BUILT_SOURCES, using parallel build protection.
-gen_sources = $(BUILT_SOURCES)
-gen_sources_deps = gen_usrp_dbid.py usrp_dbid.dat
-par_gen_command = PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat
-include $(top_srcdir)/Makefile.par.gen
+++ /dev/null
-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 function 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
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#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 */
+++ /dev/null
-#!/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 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-
-import sys
-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
-
-
-
-
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _CIRCULAR_BUFFER_H_
-#define _CIRCULAR_BUFFER_H_
-
-#include "mld_threads.h"
-#include <stdexcept>
-
-#ifndef DO_DEBUG
-#define DO_DEBUG 0
-#endif
-
-#if DO_DEBUG
-#define DEBUG(X) do{X} while(0);
-#else
-#define DEBUG(X) do{} while(0);
-#endif
-
-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 ();
- 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")););
- };
-
- ~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 ();
- // create a mutex to handle contention of shared resources;
- // any routine needed access to shared resources uses lock()
- // before doing anything, then unlock() when finished.
- d_internal = new mld_mutex ();
- // link the internal mutex to the read and write conditions;
- // when wait() is called, the internal mutex will automatically
- // be unlock()'ed. Upon return (from a signal() to the condition),
- // the internal mutex will be lock()'ed.
- d_readBlock = new mld_condition (d_internal);
- d_writeBlock = new mld_condition (d_internal);
- };
-
-/*
- * 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) {
- DEBUG (fprintf (stderr, "enqueue: buf = %X, bufLen = %ld, #av_wr = %ld, "
- "#av_rd = %ld.\n", (unsigned int)buf, bufLen_I,
- d_n_avail_write_I, d_n_avail_read_I););
- 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);
- }
- // set the return value to 1: success; change if needed
- int retval = 1;
- if (bufLen_I > d_n_avail_write_I) {
- if (d_doWriteBlock) {
- while (bufLen_I > d_n_avail_write_I) {
- DEBUG (fprintf (stderr, "enqueue: #len > #a, waiting.\n"););
- // wait will automatically unlock() the internal mutex
- d_writeBlock->wait ();
- // and lock() it here.
- if (d_doAbort) {
- d_internal->unlock ();
- DEBUG (fprintf (stderr, "enqueue: #len > #a, aborting.\n"););
- return (2);
- }
- DEBUG (fprintf (stderr, "enqueue: #len > #a, done waiting.\n"););
- }
- } else {
- d_n_avail_read_I = d_bufLen_I - bufLen_I;
- d_n_avail_write_I = bufLen_I;
- DEBUG (fprintf (stderr, "circular_buffer::enqueue: overflow\n"););
- retval = -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 (retval);
- };
-
-/*
- * 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) {
- DEBUG (fprintf (stderr, "dequeue: buf = %X, *bufLen = %ld, #av_wr = %ld, "
- "#av_rd = %ld.\n", (unsigned int)buf, *bufLen_I,
- d_n_avail_write_I, d_n_avail_read_I););
- 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) {
- DEBUG (fprintf (stderr, "dequeue: #a < #len, waiting.\n"););
- // wait will automatically unlock() the internal mutex
- d_readBlock->wait ();
- // and lock() it here.
- if (d_doAbort) {
- d_internal->unlock ();
- DEBUG (fprintf (stderr, "dequeue: #a < #len, aborting.\n"););
- return (2);
- }
- DEBUG (fprintf (stderr, "dequeue: #a < #len, done waiting.\n"););
- }
- } else {
- while (d_n_avail_read_I == 0) {
- DEBUG (fprintf (stderr, "dequeue: #a == 0, waiting.\n"););
- // wait will automatically unlock() the internal mutex
- d_readBlock->wait ();
- // and lock() it here.
- if (d_doAbort) {
- d_internal->unlock ();
- DEBUG (fprintf (stderr, "dequeue: #a == 0, aborting.\n"););
- return (2);
- }
- DEBUG (fprintf (stderr, "dequeue: #a == 0, done waiting.\n"););
- }
- }
- 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_ */
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _CIRCULAR_LINKED_LIST_H_
-#define _CIRCULAR_LINKED_LIST_H_
-
-#include <mld_threads.h>
-#include <stdexcept>
-
-#define __INLINE__ inline
-
-#ifndef DO_DEBUG
-#define DO_DEBUG 0
-#endif
-
-#if DO_DEBUG
-#define DEBUG(X) do{X} while(0);
-#else
-#define DEBUG(X) do{} while(0);
-#endif
-
-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_ioBlock = new mld_condition ();
- d_internal = d_ioBlock->mutex ();
- };
-
- ~circular_linked_list () {
- iterate_start ();
- s_node_ptr l_node = iterate_next ();
- while (l_node) {
- delete l_node;
- l_node = iterate_next ();
- }
- 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;
- DEBUG (fprintf (stderr, "w "););
- while (! l_node) {
- DEBUG (fprintf (stderr, "x\n"););
- // the ioBlock condition will automatically unlock() d_internal
- d_ioBlock->wait ();
- // and lock() is here
- DEBUG (fprintf (stderr, "y\n"););
- l_node = d_available;
- }
- DEBUG (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 ();
- DEBUG (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--;
-
- DEBUG (fprintf (stderr, "s%ld ", d_n_used););
-// signal the condition when new data arrives
- d_ioBlock->signal ();
- DEBUG (fprintf (stderr, "t "););
-
-// 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_ */
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-/*
- * 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__ */
+++ /dev/null
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-//
-
-#include <db_base.h>
-#include <db_base_impl.h>
-
-#if 0
-tune_result::tune_result(double baseband, double dxc, double residual, bool inv)
- : ok(false), baseband_freq(baseband), dxc_freq(dxc),
- residual_freq(residual), inverted(inv)
-{
-}
-
-tune_result::~tune_result()
-{
-}
-#endif
-
-
-/*****************************************************************************/
-
-db_base::db_base(usrp_basic_sptr usrp, int which)
- : d_is_shutdown(false), d_raw_usrp(usrp.get()), d_which(which), d_lo_offset(0.0)
-{
-}
-
-db_base::~db_base()
-{
- shutdown();
-}
-
-void
-db_base::shutdown()
-{
- if (!d_is_shutdown){
- d_is_shutdown = true;
- // do whatever there is to do to shutdown
- }
-}
-
-int
-db_base::dbid()
-{
- return usrp()->daughterboard_id(d_which);
-}
-
-std::string
-db_base::name()
-{
- return usrp_dbid_to_string(dbid());
-}
-
-std::string
-db_base::side_and_name()
-{
- if(d_which == 0)
- return "A: " + name();
- else
- return "B: " + name();
-}
-
-// Function to bypass ADC buffers. Any board which is DC-coupled
-// should bypass the buffers
-
-bool
-db_base::bypass_adc_buffers(bool bypass)
-{
- //if(d_tx) {
- // throw std::runtime_error("TX Board has no adc buffers\n");
- //}
-
- bool ok = true;
- if(d_which==0) {
- ok &= usrp()->set_adc_buffer_bypass(0, bypass);
- ok &= usrp()->set_adc_buffer_bypass(1, bypass);
- }
- else {
- ok &= usrp()->set_adc_buffer_bypass(2, bypass);
- ok &= usrp()->set_adc_buffer_bypass(3, bypass);
- }
- return ok;
-}
-
-bool
-db_base::set_atr_mask(int v)
-{
- // Set Auto T/R mask.
- return usrp()->write_atr_mask(d_which, v);
-}
-
-bool
-db_base::set_atr_txval(int v)
-{
- // Set Auto T/R register value to be used when transmitting.
- return usrp()->write_atr_txval(d_which, v);
-}
-
-bool
-db_base::set_atr_rxval(int v)
-{
- // Set Auto T/R register value to be used when receiving.
- return usrp()->write_atr_rxval(d_which, v);
-}
-
-bool
-db_base::set_atr_tx_delay(int v)
-{
- // Set Auto T/R delay (in clock ticks) from when Tx fifo gets data to
- // when T/R switches.
- return usrp()->write_atr_tx_delay(v);
-}
-
-bool
-db_base::set_atr_rx_delay(int v)
-{
- // Set Auto T/R delay (in clock ticks) from when Tx fifo goes empty to
- // when T/R switches.
- return usrp()->write_atr_rx_delay(v);
-}
-
-bool
-db_base::i_and_q_swapped()
-{
- // Return True if this is a quadrature device and (for RX) ADC 0 is Q
- // or (for TX) DAC 0 is Q
- return false;
-}
-
-bool
-db_base::spectrum_inverted()
-{
- // Return True if the dboard gives an inverted spectrum
-
- return false;
-}
-
-bool
-db_base::set_enable(bool on)
-{
- // For tx daughterboards, this controls the transmitter enable.
-
- return true; // default is nop
-}
-
-bool
-db_base::set_auto_tr(bool on)
-{
- // Enable automatic Transmit/Receive switching (ATR).
- //
- // Should be overridden in subclasses that care. This will typically
- // set the atr_mask, txval and rxval.
-
- return true;
-}
-
-bool
-db_base::set_lo_offset(double offset)
-{
- // Set how much LO is offset from requested frequency
-
- d_lo_offset = offset;
- return true;
-}
-
-bool
-db_base::select_rx_antenna(int which_antenna)
-{
- // Specify which antenna port to use for reception.
- // Should be overriden by daughterboards that care.
-
- return which_antenna == 0;
-}
-
-bool
-db_base::select_rx_antenna(const std::string &which_antenna)
-{
- // Specify which antenna port to use for reception.
- // Should be overriden by daughterboards that care.
-
- return which_antenna == "";
-}
-
-
-// Reference Clock section
-//
-// Control whether a reference clock is sent to the daughterboards,
-// and what frequency
-//
-// Bit 7 -- 1 turns on refclk, 0 allows IO use
-// Bits 6:0 Divider value
-//
-
-double
-db_base::_refclk_freq()
-{
- return usrp()->fpga_master_clock_freq() / _refclk_divisor();
-}
-
-void
-db_base::_enable_refclk(bool enable)
-{
- int CLOCK_OUT = 1; // Clock is on lowest bit
- int REFCLK_ENABLE = 0x80;
- int REFCLK_DIVISOR_MASK = 0x7f;
-
- if(enable) {
- usrp()->_write_oe(d_which, CLOCK_OUT, CLOCK_OUT); // output enable
- usrp()->write_refclk(d_which, (_refclk_divisor() & REFCLK_DIVISOR_MASK) | REFCLK_ENABLE);
- }
- else {
- usrp()->write_refclk(d_which, 0);
- }
-}
-
-int
-db_base::_refclk_divisor()
-{
- // Return value to stick in REFCLK_DIVISOR register
- throw std::runtime_error("_reflck_divisor() called from base class\n");;
-}
-
-bool
-db_base::set_bw(float bw)
-{
- // Set baseband bandwidth (board specific)
- // Should be overriden by boards that implement variable IF filtering (e.g., DBSRX)
- return false;
-}
-
-std::ostream &operator<<(std::ostream &os, db_base &x)
-{
- os << x.side_and_name();
- return os;
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-//
-
-#ifndef INCLUDED_DB_BASE_H
-#define INCLUDED_DB_BASE_H
-
-#include <string>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-#include <iosfwd>
-
-class db_base;
-typedef boost::shared_ptr<db_base> db_base_sptr;
-
-class usrp_basic;
-typedef boost::shared_ptr<usrp_basic> usrp_basic_sptr;
-
-struct freq_result_t
-{
- bool ok;
- double baseband_freq;
-};
-
-/******************************************************************************/
-
-/*!
- * \brief Abstract base class for all USRP daughterboards
- * \ingroup usrp
- */
-class db_base
-{
- protected:
- bool d_is_shutdown;
- usrp_basic *d_raw_usrp;
- int d_which;
- double d_lo_offset;
-
- void _enable_refclk(bool enable);
- virtual double _refclk_freq();
- virtual int _refclk_divisor();
-
- usrp_basic *usrp(){
- return d_raw_usrp;
- }
-
- public:
- db_base(boost::shared_ptr<usrp_basic> usrp, int which);
- virtual ~db_base();
-
- int dbid();
- std::string name();
- std::string side_and_name();
- int which() { return d_which; }
-
- bool bypass_adc_buffers(bool bypass);
- bool set_atr_mask(int v);
- bool set_atr_txval(int v);
- bool set_atr_rxval(int v);
- bool set_atr_tx_delay(int v);
- bool set_atr_rx_delay(int v);
- bool set_lo_offset(double offset);
- double lo_offset() { return d_lo_offset; }
-
-
- ////////////////////////////////////////////////////////
- // derived classes should override the following methods
-
-protected:
- friend class usrp_basic;
-
- /*!
- * Called to shutdown daughterboard. Called from dtor and usrp_basic dtor.
- *
- * N.B., any class that overrides shutdown MUST call shutdown in its destructor.
- */
- virtual void shutdown();
-
-
-public:
- virtual float gain_min() = 0;
- virtual float gain_max() = 0;
- virtual float gain_db_per_step() = 0;
- virtual double freq_min() = 0;
- virtual double freq_max() = 0;
- virtual struct freq_result_t set_freq(double target_freq) = 0;
- virtual bool set_gain(float gain) = 0;
- virtual bool is_quadrature() = 0;
- virtual bool i_and_q_swapped();
- virtual bool spectrum_inverted();
- virtual bool set_enable(bool on);
- virtual bool set_auto_tr(bool on);
- virtual bool select_rx_antenna(int which_antenna);
- virtual bool select_rx_antenna(const std::string &which_antenna);
- virtual bool set_bw(float bw);
-};
-
-
-std::ostream & operator<<(std::ostream &os, db_base &x);
-
-#endif /* INCLUDED_DB_BASE_H */
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008,2009 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-//
-
-
-%{
-#include "db_base.h"
-%}
-
-%include <gr_shared_ptr.i>
-
-class usrp_tune_result
-{
-public:
- usrp_tune_result(double baseband=0, double dxc=0,
- double residual=0, bool inv=0);
- ~usrp_tune_result();
-
- double baseband_freq;
- double dxc_freq;
- double residual_freq;
- bool inverted;
-};
-
-struct freq_result_t
-{
- bool ok;
- double baseband_freq;
-};
-
-class db_base
-{
- private:
- db_base(boost::shared_ptr<usrp_basic> usrp, int which);
-
- public:
- virtual ~db_base();
-
- int dbid();
- std::string name();
- std::string side_and_name();
- int which() { return d_which; }
-
- bool bypass_adc_buffers(bool bypass);
- bool set_atr_mask(int v);
- bool set_atr_txval(int v);
- bool set_atr_rxval(int v);
- bool set_atr_tx_delay(int v);
- bool set_atr_rx_delay(int v);
- bool set_lo_offset(double offset);
- double lo_offset() { return d_lo_offset; }
-
- virtual float gain_min() = 0;
- virtual float gain_max() = 0;
- virtual float gain_db_per_step() = 0;
- virtual double freq_min() = 0;
- virtual double freq_max() = 0;
- virtual struct freq_result_t set_freq(double target_freq) = 0;
- virtual bool set_gain(float gain) = 0;
- virtual bool is_quadrature() = 0;
- virtual bool i_and_q_swapped();
- virtual bool spectrum_inverted();
- virtual bool set_enable(bool on);
- virtual bool set_auto_tr(bool on);
- virtual bool select_rx_antenna(int which_antenna);
- virtual bool select_rx_antenna(const std::string &antenna);
- virtual bool set_bw(float bw);
-};
-
-// Create templates for db's, vectors of db's, and vector of vectors of db's
-typedef boost::shared_ptr<db_base> db_base_sptr;
-%template(db_base_sptr) boost::shared_ptr<db_base>;
-%template(db_base_sptr_vector) std::vector<db_base_sptr>;
-%template(db_base_sptr_vector_vector) std::vector<std::vector<db_base_sptr> >;
-
-// Set better class name in Python
-// Enable freq_range and gain_range from public methods of class not implemented in C++
-// And create a dummy wrapper for backwards compatability with some of the example code
-%pythoncode %{
- db_base_sptr.__repr__ = lambda self: "<db_base::%s>" % (self.name(),)
- db_base_sptr.freq_range = lambda self: (self.freq_min(), self.freq_max(), 1)
- db_base_sptr.gain_range = lambda self: (self.gain_min(), self.gain_max(), self.gain_db_per_step())
-
-%}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_DB_BASE_IMPL_H
-#define INCLUDED_DB_BASE_IMPL_H
-
-#include <db_base.h>
-#include <db_util.h>
-#include <usrp_basic.h>
-#include <fpga_regs_standard.h>
-#include <fpga_regs_common.h>
-#include <usrp_prims.h>
-#include <usrp_spi_defs.h>
-#include <stdexcept>
-
-#endif /* INCLUDED_DB_BASE_IMPL_H */
+++ /dev/null
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_basic.h>
-#include <db_base_impl.h>
-
-
-db_basic_tx::db_basic_tx(boost::shared_ptr<usrp_basic> usrp, int which)
- : db_base(usrp, which)
-{
- // Handler for Basic Tx daughterboards.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively
-
- set_gain((gain_min() + gain_max()) / 2); // initialize gain
-}
-
-db_basic_tx::~db_basic_tx()
-{
-}
-
-double
-db_basic_tx::freq_min()
-{
- return -90e9;
-}
-
-double
-db_basic_tx::freq_max()
-{
- return 90e9;
-}
-
-struct freq_result_t
-db_basic_tx::set_freq(double target_freq)
-{
- // Set the frequency.
- //
- // @param freq: target RF frequency in Hz
- // @type freq: double
- //
- // @returns (ok, actual_baseband_freq) where:
- // ok is True or False and indicates success or failure,
- // actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
-
- struct freq_result_t args = {false, 0};
- args.ok = true;
- args.baseband_freq = 0.0;
- return args;
-}
-
-float
-db_basic_tx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_basic_tx::gain_max()
-{
- return usrp()->pga_max();
-}
-
-float
-db_basic_tx::gain_db_per_step()
-{
- return usrp()->pga_db_per_step();
-}
-
-bool
-db_basic_tx::set_gain(float gain)
-{
- // Set the gain.
- //
- // @param gain: gain in decibels
- // @returns True/False
-
- bool ok = usrp()->set_pga(d_which * 2 + 0, gain);
- ok = ok && usrp()->set_pga(d_which * 2 + 1, gain);
- return ok;
-}
-
-bool
-db_basic_tx::is_quadrature()
-{
- // Return True if this board requires both I & Q analog channels.
-
- return true;
-}
-
-
-/******************************************************************************/
-
-
-db_basic_rx::db_basic_rx(usrp_basic_sptr usrp, int which, int subdev)
- : db_base(usrp, which)
-{
- // Handler for Basic Rx daughterboards.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively
- // @param subdev: which analog i/o channel: 0 or 1
- // @type subdev: int
-
- d_subdev = subdev;
-
- bypass_adc_buffers(true);
-
- if(0) { // Doing this would give us a different default than the historical values...
- set_gain(float(gain_min() + gain_max()) / 2.0); // initialize gain
- }
-}
-
-db_basic_rx::~db_basic_rx()
-{
-}
-
-double
-db_basic_rx::freq_min()
-{
- return -90e9;
-}
-
-double
-db_basic_rx::freq_max()
-{
- return 90e9;
-}
-
-struct freq_result_t
-db_basic_rx::set_freq(double target_freq)
-{
- // Set the frequency.
- //
- // @param freq: target RF frequency in Hz
- // @type freq: double
- //
- // @returns (ok, actual_baseband_freq) where:
- // ok is True or False and indicates success or failure,
- // actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
-
- struct freq_result_t args = {true, 0.0};
- return args;
-}
-
-float
-db_basic_rx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_basic_rx::gain_max()
-{
- return usrp()->pga_max();
-}
-
-float
-db_basic_rx::gain_db_per_step()
-{
- return usrp()->pga_db_per_step();
-}
-
-bool
-db_basic_rx::set_gain(float gain)
-{
- // Set the gain.
- //
- // @param gain: gain in decibels
- // @returns True/False
-
- return usrp()->set_pga(d_which * 2 + d_subdev, gain);
-}
-
-bool
-db_basic_rx::is_quadrature()
-{
- // Return True if this board requires both I & Q analog channels.
-
- // This bit of info is useful when setting up the USRP Rx mux register.
-
- return (d_subdev == 2);
-}
-
-
-
-/******************************************************************************/
-
-
-db_lf_tx::db_lf_tx(usrp_basic_sptr usrp, int which)
- : db_basic_tx(usrp, which)
-{
- // Handler for Low Freq Tx daughterboards.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
-}
-
-db_lf_tx::~db_lf_tx()
-{
-}
-
-double
-db_lf_tx::freq_min()
-{
- return -32e6;
-}
-
-double
-db_lf_tx::freq_max()
-{
- return 32e6;
-}
-
-/******************************************************************************/
-
-
-db_lf_rx::db_lf_rx(usrp_basic_sptr usrp, int which, int subdev)
- : db_basic_rx(usrp, which, subdev)
-{
- // Handler for Low Freq Rx daughterboards.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
- // @param subdev: which analog i/o channel: 0 or 1
- // @type subdev: int
-}
-
-db_lf_rx::~db_lf_rx()
-{
-}
-
-double
-db_lf_rx::freq_min()
-{
- return 0.0;
-}
-
-double
-db_lf_rx::freq_max()
-{
- return 32e6;
-}
-
-
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_BASIC_H
-#define DB_BASIC_H
-
-#include <db_base.h>
-
-
-/******************************************************************************/
-
-
-class db_basic_tx : public db_base
-{
-public:
- db_basic_tx(usrp_basic_sptr usrp, int which);
- ~db_basic_tx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- double freq_min();
- double freq_max();
- struct freq_result_t set_freq(double target_freq);
- bool set_gain(float gain);
- bool is_quadrature();
-};
-
-
-/******************************************************************************/
-
-
-class db_basic_rx : public db_base
-{
- public:
- db_basic_rx(usrp_basic_sptr usrp, int which, int subdev);
- ~db_basic_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- double freq_min();
- double freq_max();
- struct freq_result_t set_freq(double target_freq);
- bool set_gain(float gain);
- bool is_quadrature();
-
-private:
- int d_subdev;
-};
-
-
-/******************************************************************************/
-
-
-class db_lf_rx : public db_basic_rx
-{
- public:
- db_lf_rx(usrp_basic_sptr usrp, int which, int subdev);
- ~db_lf_rx();
-
- double freq_min();
- double freq_max();
-};
-
-
-/******************************************************************************/
-
-
-class db_lf_tx : public db_basic_tx
-{
- public:
- db_lf_tx(usrp_basic_sptr usrp, int which);
- ~db_lf_tx();
-
- double freq_min();
- double freq_max();
-};
-
-
-#endif
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-//
-
-#include <db_boards.h>
-#include <usrp_dbid.h>
-#include <db_basic.h>
-#include <db_tv_rx.h>
-#include <db_dbs_rx.h>
-#include <db_flexrf.h>
-#include <db_flexrf_mimo.h>
-#include <db_xcvr2450.h>
-#include <db_wbx.h>
-#include <db_dtt754.h>
-#include <db_dtt768.h>
-#include <cstdio>
-
-std::vector<db_base_sptr>
-instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side)
-{
- std::vector<db_base_sptr> db;
-
- switch(dbid) {
-
- case(USRP_DBID_BASIC_TX):
- db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side)));
- break;
-
- case(USRP_DBID_BASIC_RX):
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0)));
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1)));
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 2)));
- break;
-
- case(USRP_DBID_LF_TX):
- db.push_back(db_base_sptr(new db_lf_tx(usrp, which_side)));
- break;
-
- case(USRP_DBID_LF_RX):
- db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 0)));
- db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 1)));
- db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 2)));
- break;
-
- case(USRP_DBID_DBS_RX):
- db.push_back(db_base_sptr(new db_dbs_rx(usrp, which_side)));
- break;
-
- case(USRP_DBID_TV_RX):
- db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 43.75e6, 5.75e6)));
- break;
- case(USRP_DBID_TV_RX_REV_2):
- db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 44e6, 20e6)));
- break;
- case(USRP_DBID_TV_RX_REV_3):
- db.push_back(db_base_sptr(new db_tv_rx(usrp, which_side, 44e6, 20e6)));
- break;
-
- case(USRP_DBID_FLEX_2400_TX):
- db.push_back(db_base_sptr(new db_flexrf_2400_tx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_2400_RX):
- db.push_back(db_base_sptr(new db_flexrf_2400_rx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1200_TX):
- db.push_back(db_base_sptr(new db_flexrf_1200_tx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1200_RX):
- db.push_back(db_base_sptr(new db_flexrf_1200_rx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1800_TX):
- db.push_back(db_base_sptr(new db_flexrf_1800_tx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1800_RX):
- db.push_back(db_base_sptr(new db_flexrf_1800_rx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_900_TX):
- db.push_back(db_base_sptr(new db_flexrf_900_tx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_900_RX):
- db.push_back(db_base_sptr(new db_flexrf_900_rx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_400_TX):
- db.push_back(db_base_sptr(new db_flexrf_400_tx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_400_RX):
- db.push_back(db_base_sptr(new db_flexrf_400_rx(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_2400_TX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_2400_tx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_2400_RX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_2400_rx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1800_TX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_1800_tx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1800_RX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_1800_rx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1200_TX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_1200_tx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1200_RX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_1200_rx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_900_TX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_900_tx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_900_RX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_900_rx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_400_TX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_400_tx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_400_RX_MIMO_A):
- db.push_back(db_base_sptr(new db_flexrf_400_rx_mimo_a(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_2400_TX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_2400_tx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_2400_RX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_2400_rx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1800_TX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_1800_tx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1800_RX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_1800_rx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1200_TX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_1200_tx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_1200_RX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_1200_rx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_900_TX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_900_tx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_900_RX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_900_rx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_400_TX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_400_tx_mimo_b(usrp, which_side)));
- break;
- case(USRP_DBID_FLEX_400_RX_MIMO_B):
- db.push_back(db_base_sptr(new db_flexrf_400_rx_mimo_b(usrp, which_side)));
- break;
-
- case(USRP_DBID_XCVR2450_TX):
- db.push_back(db_base_sptr(new db_xcvr2450_tx(usrp, which_side)));
- break;
- case(USRP_DBID_XCVR2450_RX):
- db.push_back(db_base_sptr(new db_xcvr2450_rx(usrp, which_side)));
- break;
-
-#if 0 // FIXME wbx doesn't compile
- case(USRP_DBID_WBX_LO_TX):
- db.push_back(db_base_sptr(new db_wbx_lo_tx(usrp, which_side)));
- break;
- case(USRP_DBID_WBX_LO_RX):
- db.push_back(db_base_sptr(new db_wbx_lo_rx(usrp, which_side)));
- break;
-#endif
-
- case(USRP_DBID_DTT754):
- db.push_back(db_base_sptr(new db_dtt754(usrp, which_side)));
- break;
- case(USRP_DBID_DTT768):
- db.push_back(db_base_sptr(new db_dtt768(usrp, which_side)));
- break;
-
- case(-1):
- if (boost::dynamic_pointer_cast<usrp_basic_tx>(usrp)){
- db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side)));
- }
- else {
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0)));
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1)));
- }
- break;
-
- case(-2):
- default:
- if (boost::dynamic_pointer_cast<usrp_basic_tx>(usrp)){
- fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Tx.\"\n");
- fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n");
- db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side)));
- }
- else {
- fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Rx.\"\n");
- fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n");
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0)));
- db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1)));
- }
- break;
- }
-
- return db;
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-//
-
-#ifndef DB_BOARDS_H
-#define DB_BOARDS_H
-
-#include <db_base.h>
-#include <usrp_basic.h>
-
-std::vector<db_base_sptr> instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side);
-
-#endif
-
-
+++ /dev/null
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_dbs_rx.h>
-#include <db_base_impl.h>
-#include <cmath>
-#include <cstdio>
-
-
-/*****************************************************************************/
-
-
-db_dbs_rx::db_dbs_rx(usrp_basic_sptr _usrp, int which)
- : db_base(_usrp, which)
-{
- // Control DBS receiver based USRP daughterboard.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
-
- usrp()->_write_oe(d_which, 0x0001, 0x0001);
- if(which == 0) {
- d_i2c_addr = 0x67;
- }
- else {
- d_i2c_addr = 0x65;
- }
-
- d_n = 950;
- d_div2 = 0;
- d_osc = 5;
- d_cp = 3;
- d_r = 4;
- d_r_int = 1;
- d_fdac = 127;
- d_m = 2;
- d_dl = 0;
- d_ade = 0;
- d_adl = 0;
- d_gc1 = 0;
- d_gc2 = 31;
- d_diag = 0;
-
- _enable_refclk(true);
-
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-
- bypass_adc_buffers(true);
-}
-
-db_dbs_rx::~db_dbs_rx()
-{
- shutdown();
-}
-
-void
-db_dbs_rx::shutdown()
-{
- if (!d_is_shutdown){
- d_is_shutdown = true;
- // do whatever there is to do to shutdown orderly
- _enable_refclk(false);
- }
-}
-
-void
-db_dbs_rx::_write_reg (int regno, int v)
-{
- //regno is in [0,5], v is value to write to register"""
- assert (0 <= regno && regno <= 5);
- std::vector<int> args(2);
- args[0] = regno;
- args[1] = v;
- usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
-}
-
-void
-db_dbs_rx::_write_regs (int starting_regno, const std::vector<int> &vals)
-{
- // starting_regno is in [0,5],
- // vals is a seq of integers to write to consecutive registers"""
-
- //FIXME
- std::vector<int> args;
- args.push_back(starting_regno);
- args.insert(args.end(), vals.begin(), vals.end());
- usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
-}
-
-std::vector<int>
-db_dbs_rx::_read_status ()
-{
- //If successful, return list of two ints: [status_info, filter_DAC]"""
- std::string s = usrp()->read_i2c (d_i2c_addr, 2);
- if(s.size() != 2) {
- std::vector<int> ret(0);
- return ret;
- }
- return str_to_int_seq (s);
-}
-
-void
-db_dbs_rx::_send_reg(int regno)
-{
- assert(0 <= regno && regno <= 5);
- if(regno == 0)
- _write_reg(0,(d_div2<<7) + (d_n>>8));
- if(regno == 1)
- _write_reg(1,d_n & 255);
- if(regno == 2)
- _write_reg(2,d_osc + (d_cp<<3) + (d_r_int<<5));
- if(regno == 3)
- _write_reg(3,d_fdac);
- if(regno == 4)
- _write_reg(4,d_m + (d_dl<<5) + (d_ade<<6) + (d_adl<<7));
- if(regno == 5)
- _write_reg(5,d_gc2 + (d_diag<<5));
-}
-
-// BW setting
-void
-db_dbs_rx::_set_m(int m)
-{
- assert(m>0 && m<32);
- d_m = m;
- _send_reg(4);
-}
-
-void
-db_dbs_rx::_set_fdac(int fdac)
-{
- assert(fdac>=0 && fdac<128);
- d_fdac = fdac;
- _send_reg(3);
-}
-
-bool
-db_dbs_rx::set_bw (float bw)
-{
- if (bw < 1e6 || bw > 33e6) {
- fprintf(stderr, "db_dbs_rx::set_bw: bw (=%f) must be between 1e6 and 33e6 inclusive\n", bw);
- return false;
- }
-
- // struct bw_t ret = {0, 0, 0};
- int m_max, m_min, m_test, fdac_test;
- if(bw >= 4e6)
- m_max = int(std::min(31, (int)floor(_refclk_freq()/1e6)));
- else if(bw >= 2e6) // Outside of Specs!
- m_max = int(std::min(31, (int)floor(_refclk_freq()/.5e6)));
- else // Way outside of Specs!
- m_max = int(std::min(31, (int)floor(_refclk_freq()/.25e6)));
-
- m_min = int(ceil(_refclk_freq()/2.5e6));
- m_test = m_max;
- while(m_test >= m_min) {
- fdac_test = static_cast<int>(round(((bw * m_test / _refclk_freq())-4)/.145));
- if(fdac_test > 127)
- m_test = m_test - 1;
- else
- break;
- }
-
- if(m_test>=m_min && fdac_test>=0) {
- _set_m(m_test);
- _set_fdac(fdac_test);
-
- //ret.m = d_m;
- //ret.fdac = d_fdac;
- //ret.div = _refclk_freq()/d_m*(4+0.145*d_fdac);
- }
- else {
- fprintf(stderr, "db_dbs_rx::set_bw: failed\n");
- return false;
- }
-
- return true;
-}
-
-// Gain setting
-void
-db_dbs_rx::_set_dl(int dl)
-{
- assert(dl == 0 || dl == 1);
- d_dl = dl;
- _send_reg(4);
-}
-
-void
-db_dbs_rx::_set_gc2(int gc2)
-{
- assert(gc2<32 && gc2>=0);
- d_gc2 = gc2;
- _send_reg(5);
-}
-
-void
-db_dbs_rx::_set_gc1(int gc1)
-{
- assert(gc1>=0 && gc1<4096);
- d_gc1 = gc1;
- usrp()->write_aux_dac(d_which, 0, gc1);
-}
-
-void
-db_dbs_rx::_set_pga(int pga_gain)
-{
- assert(pga_gain>=0 && pga_gain<=20);
- if(d_which == 0) {
- usrp()->set_pga (0, pga_gain);
- usrp()->set_pga (1, pga_gain);
- }
- else {
- usrp()->set_pga (2, pga_gain);
- usrp()->set_pga (3, pga_gain);
- }
-}
-
-float
-db_dbs_rx::gain_min()
-{
- return 0;
-}
-
-float
-db_dbs_rx::gain_max()
-{
- return 104;
-}
-
-float
-db_dbs_rx::gain_db_per_step()
-{
- return 1;
-}
-
-bool
-db_dbs_rx::set_gain(float gain)
-{
- // Set the gain.
- //
- // @param gain: gain in decibels
- // @returns True/False
-
- if(!(gain>=0 && gain<105)) {
- throw std::runtime_error("gain out of range\n");
- }
-
- int gc1=0, gc2=0, dl=0, pga=0;
-
- if(gain < 56) {
- gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3);
- gain = 0;
- }
- else {
- gc1 = 0;
- gain -= 56;
- }
-
- if(gain < 24) {
- gc2 = static_cast<int>(round(31.0 * (1-gain/24.0)));
- gain = 0;
- }
- else {
- gc2 = 0;
- gain -=24;
- }
-
- if(gain >= 4.58) {
- dl = 1;
- gain -= 4.58;
- }
-
- pga = gain;
- _set_gc1(gc1);
- _set_gc2(gc2);
- _set_dl(dl);
- _set_pga(pga);
-
- return true;
-}
-
-// Frequency setting
-void
-db_dbs_rx::_set_osc(int osc)
-{
- assert(osc>=0 && osc<8);
- d_osc = osc;
- _send_reg(2);
-}
-
-void
-db_dbs_rx::_set_cp(int cp)
-{
- assert(cp>=0 && cp<4);
- d_cp = cp;
- _send_reg(2);
-}
-
-void
-db_dbs_rx::_set_n(int n)
-{
- assert(n>256 && n<32768);
- d_n = n;
- _send_reg(0);
- _send_reg(1);
-}
-
-void
-db_dbs_rx::_set_div2(int div2)
-{
- assert(div2 == 0 || div2 == 1);
- d_div2 = div2;
- _send_reg(0);
-}
-
-void
-db_dbs_rx::_set_r(int r)
-{
- assert(r>=0 && r<128);
- d_r = r;
- d_r_int = static_cast<int>(round(log10(r)/log10(2)) - 1);
- _send_reg(2);
-}
-
-// FIXME How do we handle ADE and ADL properly?
-void
-db_dbs_rx::_set_ade(int ade)
-{
- assert(ade == 0 || ade == 1);
- d_ade = ade;
- _send_reg(4);
-}
-
-double
-db_dbs_rx::freq_min()
-{
- return 500e6;
-}
-
-double
-db_dbs_rx::freq_max()
-{
- return 2.6e9;
-}
-
-struct freq_result_t
-db_dbs_rx::set_freq(double freq)
-{
- // Set the frequency.
- //
- // @param freq: target RF frequency in Hz
- // @type freq: double
- //
- // @returns (ok, actual_baseband_freq) where:
- // ok is True or False and indicates success or failure,
- // actual_baseband_freq is RF frequency that corresponds to DC in the IF.
-
- freq_result_t args = {false, 0};
-
- if(!(freq>=freq_min() && freq<=freq_max())) {
- return args;
- }
-
- double vcofreq;
- if(freq<1150e6) {
- _set_div2(0);
- vcofreq = 4 * freq;
- }
- else {
- _set_div2(1);
- vcofreq = 2 * freq;
- }
-
- _set_ade(1);
- int rmin = std::max(2, (int)(_refclk_freq()/2e6));
- int rmax = std::min(128, (int)(_refclk_freq()/500e3));
- int r = 2;
- int n = 0;
- int best_r = 2;
- int best_n = 0;
- int best_delta = 10e6;
- int delta;
-
- while(r <= rmax) {
- n = static_cast<int>(round(freq/(_refclk_freq()/r)));
- if(r<rmin || n<256) {
- r = r * 2;
- continue;
- }
- delta = (int)fabs(n*_refclk_freq()/r - freq);
- if(delta < 75e3) {
- best_r = r;
- best_n = n;
- break;
- }
- if(delta < best_delta*0.9) {
- best_r = r;
- best_n = n;
- best_delta = delta;
- }
- r = r * 2;
- }
- _set_r(best_r);
-
- _set_n(static_cast<int>(round(best_n)));
-
- int vco;
- if(vcofreq < 2433e6)
- vco = 0;
- else if(vcofreq < 2711e6)
- vco=1;
- else if(vcofreq < 3025e6)
- vco=2;
- else if(vcofreq < 3341e6)
- vco=3;
- else if(vcofreq < 3727e6)
- vco=4;
- else if(vcofreq < 4143e6)
- vco=5;
- else if(vcofreq < 4493e6)
- vco=6;
- else
- vco=7;
-
- _set_osc(vco);
-
- // Set CP current
- int adc_val = 0;
- std::vector<int> bytes(2);
- while(adc_val == 0 || adc_val == 7) {
- bytes = _read_status();
- adc_val = bytes[0] >> 2;
- if(adc_val == 0) {
- if(vco <= 0) {
- return args;
- }
- else {
- vco = vco - 1;
- }
- }
- else if(adc_val == 7) {
- if(vco >= 7) {
- return args;
- }
- else {
- vco = vco + 1;
- }
- }
- _set_osc(vco);
- }
-
- if(adc_val == 1 || adc_val == 2) {
- _set_cp(1);
- }
- else if(adc_val == 3 || adc_val == 4) {
- _set_cp(2);
- }
- else {
- _set_cp(3);
- }
-
- args.ok = true;
- args.baseband_freq = d_n * _refclk_freq() / d_r;
- return args;
-}
-
-int
-db_dbs_rx::_refclk_divisor()
-{
- //Return value to stick in REFCLK_DIVISOR register
- return 16;
-}
-
-bool
-db_dbs_rx::is_quadrature()
-{
- // Return True if this board requires both I & Q analog channels.
- return true;
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_DBS_RX_H
-#define DB_DBS_RX_H
-
-#include <db_base.h>
-#include <vector>
-
-#if 0
-struct bw_t {
- int m;
- int fdac;
- float div;
-};
-#endif
-
-class db_dbs_rx : public db_base
-{
-private:
- int d_osc, d_cp, d_n, d_div2, d_r, d_r_int;
- int d_fdac, d_m, d_dl, d_ade, d_adl, d_gc1, d_gc2, d_diag;
- int d_i2c_addr;
-
- // Internal gain functions
- void _write_reg(int regno, int v);
- void _write_regs(int starting_regno, const std::vector<int> &vals);
- std::vector<int> _read_status();
- void _send_reg(int regno);
- void _set_m(int m);
- void _set_fdac(int fdac);
- void _set_dl(int dl);
- void _set_gc2(int gc2);
- void _set_gc1(int gc1);
- void _set_pga(int pga_gain);
-
- // Internal frequency function
- void _set_osc(int osc);
- void _set_cp(int cp);
- void _set_n(int n);
- void _set_div2(int div2);
- void _set_r(int r);
- void _set_ade(int ade);
-
- int _refclk_divisor();
-
-protected:
- void shutdown();
-
-public:
- db_dbs_rx(usrp_basic_sptr usrp, int which);
- ~db_dbs_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- double freq_min();
- double freq_max();
- struct freq_result_t set_freq(double freq);
- bool set_gain(float gain);
- bool is_quadrature();
- bool set_bw(float bw);
-};
-
-#endif
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_dtt754.h>
-#include <db_base_impl.h>
-
-int
-control_byte_1()
-{
- int RS = 0; // 0 = 166.66kHz reference
- int ATP = 7; // Disable internal AGC
- return (0x80 | ATP<<3 | RS);
-}
-
-int
-control_byte_2()
-{
- int STBY = 0; // powered on
- int XTO = 1; // turn off xtal out, which we don't have
- int ATC = 0; // not clear exactly, possibly speeds up or slows down AGC, which we are not using
-
- int c = 0xc2 | ATC<<5 | STBY<<4 | XTO;
- return c;
-}
-
-int
-bandswitch_byte(float freq, float bw)
-{
- int P5, CP, BS;
-
- if(bw>7.5e6) {
- P5 = 1;
- }
- else {
- P5 = 0;
- }
-
- if(freq < 121e6) {
- CP = 0;
- BS = 1;
- }
- else if(freq < 141e6) {
- CP = 1;
- BS = 1;
- }
- else if(freq < 166e6) {
- CP = 2;
- BS = 1;
- }
- else if(freq < 182e6) {
- CP = 3;
- BS = 1;
- }
- else if(freq < 286e6) {
- CP = 0;
- BS = 2;
- }
- else if(freq < 386e6) {
- CP = 1;
- BS = 2;
- }
- else if(freq < 446e6) {
- CP = 2;
- BS = 2;
- }
- else if(freq < 466e6) {
- CP = 3;
- BS = 2;
- }
- else if(freq < 506e6) {
- CP = 0;
- BS = 8;
- }
- else if(freq < 761e6) {
- CP = 1;
- BS = 8;
- }
- else if(freq < 846e6) {
- CP = 2;
- BS = 8;
- }
- else { // limit is ~905 MHz
- CP = 3;
- BS = 8;
- }
- return (CP<<6 | P5 << 4 | BS);
-}
-
-db_dtt754::db_dtt754(usrp_basic_sptr _usrp, int which)
- : db_base(_usrp, which)
-{
- /*
- * Control custom DTT75403-based daughterboard.
- *
- * @param usrp: instance of usrp.source_c
- * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
- * @type which: int
- */
-
- // FIXME: DTT754 and DTT768 can probably inherit from a DTT class
-
- if(d_which == 0) {
- d_i2c_addr = 0x60;
- }
- else {
- d_i2c_addr = 0x62;
- }
-
- d_bw = 7e6;
- d_IF = 36e6;
-
- d_f_ref = 166.6666e3;
- d_inverted = false;
-
- set_gain((gain_min() + gain_max()) / 2.0);
-
- bypass_adc_buffers(false);
-}
-
-db_dtt754::~db_dtt754()
-{
-}
-
-float
-db_dtt754::gain_min()
-{
- return 0;
-}
-
-float
-db_dtt754::gain_max()
-{
- return 115;
-}
-
-float
-db_dtt754::gain_db_per_step()
-{
- return 1;
-}
-
-bool
-db_dtt754::set_gain(float gain)
-{
- assert(gain>=0 && gain<=115);
-
- float rfgain, ifgain, pgagain;
- if(gain > 60) {
- rfgain = 60;
- gain = gain - 60;
- }
- else {
- rfgain = gain;
- gain = 0;
- }
-
- if(gain > 35) {
- ifgain = 35;
- gain = gain - 35;
- }
- else {
- ifgain = gain;
- gain = 0;
- }
- pgagain = gain;
-
- _set_rfagc(rfgain);
- _set_ifagc(ifgain);
- _set_pga(pgagain);
-
- return true; // can't fail with the assert in place
-}
-
-double
-db_dtt754::freq_min()
-{
- return 44e6;
-}
-
-double
-db_dtt754::freq_max()
-{
- return 900e6;
-}
-
-struct freq_result_t
-db_dtt754::set_freq(double target_freq)
-{
- /*
- * @returns (ok, actual_baseband_freq) where:
- * ok is True or False and indicates success or failure,
- * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
- */
-
- freq_result_t ret = {false, 0.0};
-
- if(target_freq < freq_min() || target_freq > freq_max()) {
- return ret;
- }
-
- double target_lo_freq = target_freq + d_IF; // High side mixing
-
- int divisor = (int)(0.5+(target_lo_freq / d_f_ref));
- double actual_lo_freq = d_f_ref*divisor;
-
- if((divisor & ~0x7fff) != 0) { // must be 15-bits or less
- return ret;
- }
-
- // build i2c command string
- std::vector<int> buf(5);
- buf[0] = (divisor >> 8) & 0xff; // DB1
- buf[1] = divisor & 0xff; // DB2
- buf[2] = control_byte_1();
- buf[3] = bandswitch_byte(actual_lo_freq, d_bw);
- buf[4] = control_byte_2();
-
- bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
-
- d_freq = actual_lo_freq - d_IF;
-
- ret.ok = ok;
- ret.baseband_freq = actual_lo_freq;
-
- return ret;
-
-}
-
-bool
-db_dtt754::is_quadrature()
-{
- /*
- * Return True if this board requires both I & Q analog channels.
- *
- * This bit of info is useful when setting up the USRP Rx mux register.
- */
-
- return false;
-}
-
-bool
-db_dtt754::spectrum_inverted()
-{
- /*
- * The 43.75 MHz version is inverted
- */
-
- return d_inverted;
-}
-
-bool
-db_dtt754::set_bw(float bw)
-{
- /*
- * Choose the SAW filter bandwidth, either 7MHz or 8MHz)
- */
-
- d_bw = bw;
- set_freq(d_freq);
-
- return true; // FIXME: propagate set_freq result
-}
-
-void
-db_dtt754::_set_rfagc(float gain)
-{
- assert(gain <= 60 && gain >= 0);
- // FIXME this has a 0.5V step between gain = 60 and gain = 59.
- // Why are there two cases instead of a single linear case?
- float voltage;
- if(gain == 60) {
- voltage = 4;
- }
- else {
- voltage = gain/60.0 * 2.25 + 1.25;
- }
-
- int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
-
- assert(dacword>=0 && dacword<4096);
- usrp()->write_aux_dac(d_which, 1, dacword);
-}
-
-void
-db_dtt754::_set_ifagc(float gain)
-{
- assert(gain <= 35 && gain >= 0);
- float voltage = gain/35.0 * 2.1 + 1.4;
- int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
-
- assert(dacword>=0 && dacword<4096);
- usrp()->write_aux_dac(d_which, 0, dacword);
-}
-
-void
-db_dtt754::_set_pga(float pga_gain)
-{
- assert(pga_gain >=0 && pga_gain <=20);
- if(d_which == 0) {
- usrp()->set_pga (0, pga_gain);
- }
- else {
- usrp()->set_pga (2, pga_gain);
- }
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_DTT754_H
-#define DB_DTT754_H
-
-#include <db_base.h>
-#include <boost/shared_ptr.hpp>
-
-class db_dtt754 : public db_base
-{
-public:
- db_dtt754(usrp_basic_sptr usrp, int which);
- ~db_dtt754();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool set_gain(float gain);
-
- double freq_min();
- double freq_max();
- struct freq_result_t set_freq(double target_freq);
-
- bool is_quadrature();
- bool spectrum_inverted();
- bool set_bw(float bw);
-
-private:
- void _set_rfagc(float gain);
- void _set_ifagc(float gain);
- void _set_pga(float pga_gain);
-
- int d_i2c_addr;
- float d_bw, d_freq, d_IF, d_f_ref;
- bool d_inverted;
-};
-
-#endif
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_dtt768.h>
-#include <db_base_impl.h>
-
-int
-control_byte_4()
-{
- int C = 0; // Charge Pump Current, no info on how to choose
- int R = 4; // 125 kHz fref
-
- // int ATP = 7; // Disable internal AGC
- return (0x80 | C<<5 | R);
-}
-
-int
-control_byte_5(float freq, int agcmode = 1)
-{
- if(agcmode) {
- if(freq < 150e6) {
- return 0x3B;
- }
- else if(freq < 420e6) {
- return 0x7E;
- }
- else {
- return 0xB7;
- }
- }
- else {
- if(freq < 150e6) {
- return 0x39;
- }
- else if(freq < 420e6) {
- return 0x7C;
- }
- else {
- return 0xB5;
- }
- }
-}
-
-int
-control_byte_6()
-{
- int ATC = 0; // AGC time constant = 100ms, 1 = 3S
- int IFE = 1; // IF AGC amplifier enable
- int AT = 0; // AGC control, ???
-
- return (ATC << 5 | IFE << 4 | AT);
-}
-
-int
-control_byte_7()
-{
- int SAS = 1; // SAW Digital mode
- int AGD = 1; // AGC disable
- int ADS = 0; // AGC detector into ADC converter
- int T = 0; // Test mode, undocumented
- return (SAS << 7 | AGD << 5 | ADS << 4 | T);
-}
-
-db_dtt768::db_dtt768(usrp_basic_sptr _usrp, int which)
- : db_base(_usrp, which)
-{
- /*
- * Control custom DTT76803-based daughterboard.
- *
- * @param usrp: instance of usrp.source_c
- * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
- * @type which: int
- */
-
- if(d_which == 0) {
- d_i2c_addr = 0x60;
- }
- else {
- d_i2c_addr = 0x62;
- }
-
- d_IF = 44e6;
-
- d_f_ref = 125e3;
- d_inverted = false;
-
- set_gain((gain_min() + gain_max()) / 2.0);
-
- bypass_adc_buffers(false);
-}
-
-db_dtt768::~db_dtt768()
-{
-}
-
-float
-db_dtt768::gain_min()
-{
- return 0;
-}
-
-float
-db_dtt768::gain_max()
-{
- return 115;
-}
-
-float
-db_dtt768::gain_db_per_step()
-{
- return 1;
-}
-
-bool
-db_dtt768::set_gain(float gain)
-{
- assert(gain>=0 && gain<=115);
-
- float rfgain, ifgain, pgagain;
- if(gain > 60) {
- rfgain = 60;
- gain = gain - 60;
- }
- else {
- rfgain = gain;
- gain = 0;
- }
-
- if(gain > 35) {
- ifgain = 35;
- gain = gain - 35;
- }
- else {
- ifgain = gain;
- gain = 0;
- }
- pgagain = gain;
-
- _set_rfagc(rfgain);
- _set_ifagc(ifgain);
- _set_pga(pgagain);
-
- return true;
-}
-
-double
-db_dtt768::freq_min()
-{
- return 44e6;
-}
-
-double
-db_dtt768::freq_max()
-{
- return 900e6;
-}
-
-struct freq_result_t
-db_dtt768::set_freq(double target_freq)
-{
- /*
- * @returns (ok, actual_baseband_freq) where:
- * ok is True or False and indicates success or failure,
- * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
- */
-
- freq_result_t ret = {false, 0.0};
-
- if(target_freq < freq_min() || target_freq > freq_max()) {
- return ret;
- }
-
- double target_lo_freq = target_freq + d_IF; // High side mixing
-
- int divisor = (int)(0.5+(target_lo_freq / d_f_ref));
- double actual_lo_freq = d_f_ref*divisor;
-
- if((divisor & ~0x7fff) != 0) { // must be 15-bits or less
- return ret;
- }
-
- // build i2c command string
- std::vector<int> buf(6);
- buf[0] = (divisor >> 8) & 0xff; // DB1
- buf[1] = divisor & 0xff; // DB2
- buf[2] = control_byte_4();
- buf[3] = control_byte_5(target_freq);
- buf[4] = control_byte_6();
- buf[5] = control_byte_7();
-
- bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
-
- d_freq = actual_lo_freq - d_IF;
-
- ret.ok = ok;
- ret.baseband_freq = actual_lo_freq;
-
- return ret;
-
-}
-
-bool
-db_dtt768::is_quadrature()
-{
- /*
- * Return True if this board requires both I & Q analog channels.
- *
- * This bit of info is useful when setting up the USRP Rx mux register.
- */
-
- return false;
-}
-
-bool
-db_dtt768::spectrum_inverted()
-{
- /*
- * The 43.75 MHz version is inverted
- */
-
- return d_inverted;
-}
-
-bool
-db_dtt768::set_bw(float bw)
-{
- /*
- * Choose the SAW filter bandwidth, either 7MHz or 8MHz)
- */
-
- d_bw = bw;
- set_freq(d_freq);
-
- return true; // FIXME: propagate set_freq result
-}
-
-void
-db_dtt768::_set_rfagc(float gain)
-{
- assert(gain <= 60 && gain >= 0);
- // FIXME this has a 0.5V step between gain = 60 and gain = 59.
- // Why are there two cases instead of a single linear case?
- float voltage;
- if(gain == 60) {
- voltage = 4;
- }
- else {
- voltage = gain/60.0 * 2.25 + 1.25;
- }
-
- int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
-
- assert(dacword>=0 && dacword<4096);
- usrp()->write_aux_dac(d_which, 1, dacword);
-}
-
-void
-db_dtt768::_set_ifagc(float gain)
-{
- assert(gain <= 35 && gain >= 0);
- float voltage = gain/35.0 * 2.1 + 1.4;
- int dacword = (int)(4096*voltage/1.22/3.3); // 1.22 = opamp gain
-
- assert(dacword>=0 && dacword<4096);
- usrp()->write_aux_dac(d_which, 0, dacword);
-}
-
-void
-db_dtt768::_set_pga(float pga_gain)
-{
- assert(pga_gain >=0 && pga_gain <=20);
- if(d_which == 0) {
- usrp()->set_pga (0, pga_gain);
- }
- else {
- usrp()->set_pga (2, pga_gain);
- }
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_DTT768_H
-#define DB_DTT768_H
-
-#include <db_base.h>
-#include <boost/shared_ptr.hpp>
-
-class db_dtt768 : public db_base
-{
-public:
- db_dtt768(usrp_basic_sptr usrp, int which);
- ~db_dtt768();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool set_gain(float gain);
-
- double freq_min();
- double freq_max();
- struct freq_result_t set_freq(double target_freq);
-
- bool is_quadrature();
- bool spectrum_inverted();
- bool set_bw(float bw);
-
-private:
- void _set_rfagc(float gain);
- void _set_ifagc(float gain);
- void _set_pga(float pga_gain);
-
- int d_i2c_addr;
- float d_bw, d_freq, d_IF, d_f_ref;
- bool d_inverted;
-};
-
-#endif
+++ /dev/null
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_flexrf.h>
-#include <db_base_impl.h>
-
-// d'board i/o pin defs
-// Tx and Rx have shared defs, but different i/o regs
-#define AUX_RXAGC (1 << 8)
-#define POWER_UP (1 << 7) // enables power supply
-#define RX_TXN (1 << 6) // Tx only: T/R antenna switch for TX/RX port
-#define RX2_RX1N (1 << 6) // Rx only: antenna switch between RX2 and TX/RX port
-#define ENABLE (1 << 5) // enables mixer
-#define AUX_SEN (1 << 4)
-#define AUX_SCLK (1 << 3)
-#define PLL_LOCK_DETECT (1 << 2)
-#define AUX_SDO (1 << 1)
-#define CLOCK_OUT (1 << 0)
-
-flexrf_base::flexrf_base(usrp_basic_sptr _usrp, int which, int _power_on)
- : db_base(_usrp, which), d_power_on(_power_on)
-{
- /*
- @param usrp: instance of usrp.source_c
- @param which: which side: 0 or 1 corresponding to side A or B respectively
- @type which: int
- */
-
- d_first = true;
- d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
-
- usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs
- _enable_refclk(false); // disable refclk
-
- set_auto_tr(false);
-}
-
-flexrf_base::~flexrf_base()
-{
- delete d_common;
-}
-
-void
-flexrf_base::_write_all(int R, int control, int N)
-{
- /*
- Write R counter latch, control latch and N counter latch to VCO.
-
- Adds 10ms delay between writing control and N if this is first call.
- This is the required power-up sequence.
-
- @param R: 24-bit R counter latch
- @type R: int
- @param control: 24-bit control latch
- @type control: int
- @param N: 24-bit N counter latch
- @type N: int
- */
- timespec t;
- t.tv_sec = 0;
- t.tv_nsec = 10000000;
-
- _write_R(R);
- _write_control(control);
- if(d_first) {
- //time.sleep(0.010);
- nanosleep(&t, NULL);
- d_first = false;
- }
- _write_N(N);
-}
-
-void
-flexrf_base::_write_control(int control)
-{
- _write_it((control & ~0x3) | 0);
-}
-
-void
-flexrf_base::_write_R(int R)
-{
- _write_it((R & ~0x3) | 1);
-}
-
-void
-flexrf_base::_write_N(int N)
-{
- _write_it((N & ~0x3) | 2);
-}
-
-void
-flexrf_base::_write_it(int v)
-{
- char s[3];
- s[0] = (char)((v >> 16) & 0xff);
- s[1] = (char)((v >> 8) & 0xff);
- s[2] = (char)(v & 0xff);
- std::string str(s, 3);
- usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
-}
-
-bool
-flexrf_base::_lock_detect()
-{
- /*
- @returns: the value of the VCO/PLL lock detect bit.
- @rtype: 0 or 1
- */
- if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
- return true;
- }
- else { // Give it a second chance
- // FIXME: make portable sleep
- timespec t;
- t.tv_sec = 0;
- t.tv_nsec = 100000000;
- nanosleep(&t, NULL);
-
- if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
- return true;
- }
- else {
- return false;
- }
- }
-}
-
-bool
-flexrf_base::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- /*
- Determine values of R, control, and N registers, along with actual freq.
-
- @param freq: target frequency in Hz
- @type freq: float
- @returns: (R, control, N, actual_freq)
- @rtype: tuple(int, int, int, float)
-
- Override this in derived classes.
- */
-
- //raise NotImplementedError;
- throw std::runtime_error("_compute_regs called from flexrf_base\n");
-}
-
-int
-flexrf_base::_compute_control_reg()
-{
- return d_common->_compute_control_reg();
-}
-
-int
-flexrf_base::_refclk_divisor()
-{
- return d_common->_refclk_divisor();
-}
-
-double
-flexrf_base::_refclk_freq()
-{
- return 64e6/_refclk_divisor();
-}
-
-struct freq_result_t
-flexrf_base::set_freq(double freq)
-{
- /*
- @returns (ok, actual_baseband_freq) where:
- ok is True or False and indicates success or failure,
- actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
- */
-
- struct freq_result_t args = {false, 0};
-
- // Offsetting the LO helps get the Tx carrier leakage out of the way.
- // This also ensures that on Rx, we're not getting hosed by the
- // FPGA's DC removal loop's time constant. We were seeing a
- // problem when running with discontinuous transmission.
- // Offsetting the LO made the problem go away.
- freq += d_lo_offset;
-
- int R, control, N;
- double actual_freq;
- _compute_regs(freq, R, control, N, actual_freq);
-
- if(R==0) {
- return args;
- }
-
- _write_all(R, control, N);
- args.ok = _lock_detect();
- args.baseband_freq = actual_freq;
- return args;
-}
-
-bool
-flexrf_base::_set_pga(float pga_gain)
-{
- if(d_which == 0) {
- usrp()->set_pga(0, pga_gain);
- usrp()->set_pga(1, pga_gain);
- }
- else {
- usrp()->set_pga(2, pga_gain);
- usrp()->set_pga(3, pga_gain);
- }
- return true;
-}
-
-bool
-flexrf_base::is_quadrature()
-{
- /*
- Return True if this board requires both I & Q analog channels.
-
- This bit of info is useful when setting up the USRP Rx mux register.
- */
- return true;
-}
-
-double
-flexrf_base::freq_min()
-{
- return d_common->freq_min();
-}
-
-double
-flexrf_base::freq_max()
-{
- return d_common->freq_max();
-}
-
-// ----------------------------------------------------------------
-
-flexrf_base_tx::flexrf_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
- : flexrf_base(_usrp, which, _power_on)
-{
- /*
- @param usrp: instance of usrp.sink_c
- @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
- */
-
- if(which == 0) {
- d_spi_enable = SPI_ENABLE_TX_A;
- }
- else {
- d_spi_enable = SPI_ENABLE_TX_B;
- }
-
- // power up the transmit side, but don't enable the mixer
- usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff);
- usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
- set_lo_offset(4e6);
-
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-}
-
-flexrf_base_tx::~flexrf_base_tx()
-{
- shutdown();
-}
-
-
-void
-flexrf_base_tx::shutdown()
-{
- // fprintf(stderr, "flexrf_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
-
- if (!d_is_shutdown){
- d_is_shutdown = true;
- // do whatever there is to do to shutdown
-
- // Power down and leave the T/R switch in the R position
- usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
-
- // Power down VCO/PLL
- d_PD = 3;
-
- _write_control(_compute_control_reg());
- _enable_refclk(false); // turn off refclk
- set_auto_tr(false);
- }
-}
-
-bool
-flexrf_base_tx::set_auto_tr(bool on)
-{
- bool ok = true;
- if(on) {
- ok &= set_atr_mask (RX_TXN | ENABLE);
- ok &= set_atr_txval(0 | ENABLE);
- ok &= set_atr_rxval(RX_TXN | 0);
- }
- else {
- ok &= set_atr_mask (0);
- ok &= set_atr_txval(0);
- ok &= set_atr_rxval(0);
- }
- return ok;
-}
-
-bool
-flexrf_base_tx::set_enable(bool on)
-{
- /*
- Enable transmitter if on is true
- */
-
- int v;
- int mask = RX_TXN | ENABLE;
- if(on) {
- v = ENABLE;
- }
- else {
- v = RX_TXN;
- }
- return usrp()->write_io(d_which, v, mask);
-}
-
-float
-flexrf_base_tx::gain_min()
-{
- return usrp()->pga_max();
-}
-
-float
-flexrf_base_tx::gain_max()
-{
- return usrp()->pga_max();
-}
-
-float
-flexrf_base_tx::gain_db_per_step()
-{
- return 1;
-}
-
-bool
-flexrf_base_tx::set_gain(float gain)
-{
- /*
- Set the gain.
-
- @param gain: gain in decibels
- @returns True/False
- */
- return _set_pga(usrp()->pga_max());
-}
-
-
-/**************************************************************************/
-
-
-flexrf_base_rx::flexrf_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
- : flexrf_base(_usrp, which, _power_on)
-{
- /*
- @param usrp: instance of usrp.source_c
- @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
- */
-
- if(which == 0) {
- d_spi_enable = SPI_ENABLE_RX_A;
- }
- else {
- d_spi_enable = SPI_ENABLE_RX_B;
- }
-
- usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff);
- usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE),
- (POWER_UP|RX2_RX1N|ENABLE));
-
- // set up for RX on TX/RX port
- select_rx_antenna("TX/RX");
-
- bypass_adc_buffers(true);
-
- set_lo_offset(-4e6);
-}
-
-flexrf_base_rx::~flexrf_base_rx()
-{
- shutdown();
-}
-
-void
-flexrf_base_rx::shutdown()
-{
- // fprintf(stderr, "flexrf_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
-
- if (!d_is_shutdown){
- d_is_shutdown = true;
- // do whatever there is to do to shutdown
-
- // Power down
- usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE));
-
- // Power down VCO/PLL
- d_PD = 3;
-
-
- // fprintf(stderr, "flexrf_base_rx::shutdown before _write_control\n");
- _write_control(_compute_control_reg());
-
- // fprintf(stderr, "flexrf_base_rx::shutdown before _enable_refclk\n");
- _enable_refclk(false); // turn off refclk
-
- // fprintf(stderr, "flexrf_base_rx::shutdown before set_auto_tr\n");
- set_auto_tr(false);
-
- // fprintf(stderr, "flexrf_base_rx::shutdown after set_auto_tr\n");
- }
-}
-
-bool
-flexrf_base_rx::set_auto_tr(bool on)
-{
- bool ok = true;
- if(on) {
- ok &= set_atr_mask (ENABLE);
- ok &= set_atr_txval( 0);
- ok &= set_atr_rxval(ENABLE);
- }
- else {
- ok &= set_atr_mask (0);
- ok &= set_atr_txval(0);
- ok &= set_atr_rxval(0);
- }
- return true;
-}
-
-bool
-flexrf_base_rx::select_rx_antenna(int which_antenna)
-{
- /*
- Specify which antenna port to use for reception.
- @param which_antenna: either 'TX/RX' or 'RX2'
- */
-
- if(which_antenna == 0) {
- usrp()->write_io(d_which, 0,RX2_RX1N);
- }
- else if(which_antenna == 1) {
- usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
- }
- else {
- return false;
- // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
- }
- return true;
-}
-
-bool
-flexrf_base_rx::select_rx_antenna(const std::string &which_antenna)
-{
- /*
- Specify which antenna port to use for reception.
- @param which_antenna: either 'TX/RX' or 'RX2'
- */
-
- if(which_antenna == "TX/RX") {
- usrp()->write_io(d_which, 0, RX2_RX1N);
- }
- else if(which_antenna == "RX2") {
- usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
- }
- else {
- // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
- return false;
- }
- return true;
-}
-
-bool
-flexrf_base_rx::set_gain(float gain)
-{
- /*
- Set the gain.
-
- @param gain: gain in decibels
- @returns True/False
- */
-
- // clamp gain
- gain = std::max(gain_min(), std::min(gain, gain_max()));
-
- float pga_gain, agc_gain;
- float V_maxgain, V_mingain, V_fullscale, dac_value;
-
- float maxgain = gain_max() - usrp()->pga_max();
- float mingain = gain_min();
- if(gain > maxgain) {
- pga_gain = gain-maxgain;
- assert(pga_gain <= usrp()->pga_max());
- agc_gain = maxgain;
- }
- else {
- pga_gain = 0;
- agc_gain = gain;
- }
-
- V_maxgain = .2;
- V_mingain = 1.2;
- V_fullscale = 3.3;
- dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
-
- assert(dac_value>=0 && dac_value<4096);
-
- return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
- && _set_pga(int(pga_gain)));
-}
-
-// ----------------------------------------------------------------
-
-
-_AD4360_common::_AD4360_common()
-{
- // R-Register Common Values
- d_R_RSV = 0; // bits 23,22
- d_BSC = 3; // bits 21,20 Div by 8 to be safe
- d_TEST = 0; // bit 19
- d_LDP = 1; // bit 18
- d_ABP = 0; // bit 17,16 3ns
-
- // N-Register Common Values
- d_N_RSV = 0; // bit 7
-
- // Control Register Common Values
- d_PD = 0; // bits 21,20 Normal operation
- d_PL = 0; // bits 13,12 11mA
- d_MTLD = 1; // bit 11 enabled
- d_CPG = 0; // bit 10 CP setting 1
- d_CP3S = 0; // bit 9 Normal
- d_PDP = 1; // bit 8 Positive
- d_MUXOUT = 1; // bits 7:5 Digital Lock Detect
- d_CR = 0; // bit 4 Normal
- d_PC = 1; // bits 3,2 Core power 10mA
-}
-
-_AD4360_common::~_AD4360_common()
-{
-}
-
-bool
-_AD4360_common::_compute_regs(double refclk_freq, double freq, int &retR,
- int &retcontrol, int &retN, double &retfreq)
-{
- /*
- Determine values of R, control, and N registers, along with actual freq.
-
- @param freq: target frequency in Hz
- @type freq: float
- @returns: (R, control, N, actual_freq)
- @rtype: tuple(int, int, int, float)
- */
-
- // Band-specific N-Register Values
- //float phdet_freq = _refclk_freq()/d_R_DIV;
- double phdet_freq = refclk_freq/d_R_DIV;
- double desired_n = round(freq*d_freq_mult/phdet_freq);
- double actual_freq = desired_n * phdet_freq;
- int B = floor(desired_n/_prescaler());
- int A = desired_n - _prescaler()*B;
- d_B_DIV = int(B); // bits 20:8
- d_A_DIV = int(A); // bit 6:2
-
- //assert db_B_DIV >= db_A_DIV
- if(d_B_DIV < d_A_DIV) {
- retR = 0;
- retcontrol = 0;
- retN = 0;
- retfreq = 0;
- return false;
- }
-
- int R = (d_R_RSV<<22) | (d_BSC<<20) | (d_TEST<<19) |
- (d_LDP<<18) | (d_ABP<<16) | (d_R_DIV<<2);
-
- int control = _compute_control_reg();
-
- int N = (d_DIVSEL<<23) | (d_DIV2<<22) | (d_CPGAIN<<21) |
- (d_B_DIV<<8) | (d_N_RSV<<7) | (d_A_DIV<<2);
-
- retR = R;
- retcontrol = control;
- retN = N;
- retfreq = actual_freq/d_freq_mult;
- return true;
-}
-
-int
-_AD4360_common::_compute_control_reg()
-{
- int control = (d_P<<22) | (d_PD<<20) | (d_CP2<<17) | (d_CP1<<14)
- | (d_PL<<12) | (d_MTLD<<11) | (d_CPG<<10) | (d_CP3S<<9) | (d_PDP<<8)
- | (d_MUXOUT<<5) | (d_CR<<4) | (d_PC<<2);
-
- return control;
-}
-
-int
-_AD4360_common::_refclk_divisor()
-{
- /*
- Return value to stick in REFCLK_DIVISOR register
- */
- return 1;
-}
-
-int
-_AD4360_common::_prescaler()
-{
- if(d_P == 0) {
- return 8;
- }
- else if(d_P == 1) {
- return 16;
- }
- else {
- return 32;
- }
-}
-
-//----------------------------------------------------------------------
-
-_2400_common::_2400_common()
- : _AD4360_common()
-{
- // Band-specific R-Register Values
- d_R_DIV = 16; // bits 15:2
-
- // Band-specific C-Register values
- d_P = 1; // bits 23,22 Div by 16/17
- d_CP2 = 7; // bits 19:17
- d_CP1 = 7; // bits 16:14
-
- // Band specifc N-Register Values
- d_DIVSEL = 0; // bit 23
- d_DIV2 = 0; // bit 22
- d_CPGAIN = 0; // bit 21
- d_freq_mult = 1;
-}
-
-double
-_2400_common::freq_min()
-{
- return 2300e6;
-}
-
-double
-_2400_common::freq_max()
-{
- return 2700e6;
-}
-
-//----------------------------------------------------------------------
-
-_1200_common::_1200_common()
- : _AD4360_common()
-{
- // Band-specific R-Register Values
- d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq
-
- // Band-specific C-Register values
- d_P = 1; // bits 23,22 Div by 16/17
- d_CP2 = 7; // bits 19:17 1.25 mA
- d_CP1 = 7; // bits 16:14 1.25 mA
-
- // Band specifc N-Register Values
- d_DIVSEL = 0; // bit 23
- d_DIV2 = 1; // bit 22
- d_CPGAIN = 0; // bit 21
- d_freq_mult = 2;
-}
-
-double
-_1200_common::freq_min()
-{
- return 1150e6;
-}
-
-double
-_1200_common::freq_max()
-{
- return 1350e6;
-}
-
-//-------------------------------------------------------------------------
-
-_1800_common::_1800_common()
- : _AD4360_common()
-{
- // Band-specific R-Register Values
- d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq
-
- // Band-specific C-Register values
- d_P = 1; // bits 23,22 Div by 16/17
- d_CP2 = 7; // bits 19:17 1.25 mA
- d_CP1 = 7; // bits 16:14 1.25 mA
-
- // Band specifc N-Register Values
- d_DIVSEL = 0; // bit 23
- d_DIV2 = 0; // bit 22
- d_freq_mult = 1;
- d_CPGAIN = 0; // bit 21
-}
-
-double
-_1800_common::freq_min()
-{
- return 1600e6;
-}
-
-double
-_1800_common::freq_max()
-{
- return 2000e6;
-}
-
-//-------------------------------------------------------------------------
-
-_900_common::_900_common()
- : _AD4360_common()
-{
- // Band-specific R-Register Values
- d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq
-
- // Band-specific C-Register values
- d_P = 1; // bits 23,22 Div by 16/17
- d_CP2 = 7; // bits 19:17 1.25 mA
- d_CP1 = 7; // bits 16:14 1.25 mA
-
- // Band specifc N-Register Values
- d_DIVSEL = 0; // bit 23
- d_DIV2 = 1; // bit 22
- d_freq_mult = 2;
- d_CPGAIN = 0; // bit 21
-}
-
-double
-_900_common::freq_min()
-{
- return 800e6;
-}
-
-double
-_900_common::freq_max()
-{
- return 1000e6;
-}
-
-//-------------------------------------------------------------------------
-
-_400_common::_400_common()
- : _AD4360_common()
-{
- // Band-specific R-Register Values
- d_R_DIV = 16; // bits 15:2
-
- // Band-specific C-Register values
- d_P = 0; // bits 23,22 Div by 8/9
- d_CP2 = 7; // bits 19:17 1.25 mA
- d_CP1 = 7; // bits 16:14 1.25 mA
-
- // Band specifc N-Register Values These are different for TX/RX
- d_DIVSEL = 0; // bit 23
- d_freq_mult = 2;
-
- d_CPGAIN = 0; // bit 21
-}
-
-double
-_400_common::freq_min()
-{
- return 400e6;
-}
-
-double
-_400_common::freq_max()
-{
- return 500e6;
-}
-
-_400_tx::_400_tx()
- : _400_common()
-{
- d_DIV2 = 1; // bit 22
-}
-
-_400_rx::_400_rx()
- : _400_common()
-{
- d_DIV2 = 0; // bit 22 // RX side has built-in DIV2 in AD8348
-}
-
-//------------------------------------------------------------
-
-db_flexrf_2400_tx::db_flexrf_2400_tx(usrp_basic_sptr usrp, int which)
- : flexrf_base_tx(usrp, which)
-{
- d_common = new _2400_common();
-}
-
-db_flexrf_2400_tx::~db_flexrf_2400_tx()
-{
-}
-
-bool
-db_flexrf_2400_tx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-
-db_flexrf_2400_rx::db_flexrf_2400_rx(usrp_basic_sptr usrp, int which)
- : flexrf_base_rx(usrp, which)
-{
- d_common = new _2400_common();
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-}
-
-db_flexrf_2400_rx::~db_flexrf_2400_rx()
-{
-}
-
-float
-db_flexrf_2400_rx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_flexrf_2400_rx::gain_max()
-{
- return usrp()->pga_max()+70;
-}
-
-float
-db_flexrf_2400_rx::gain_db_per_step()
-{
- return 0.05;
-}
-
-
-bool
-db_flexrf_2400_rx::i_and_q_swapped()
-{
- return true;
-}
-
-bool
-db_flexrf_2400_rx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-//------------------------------------------------------------
-
-
-db_flexrf_1200_tx::db_flexrf_1200_tx(usrp_basic_sptr usrp, int which)
- : flexrf_base_tx(usrp, which)
-{
- d_common = new _1200_common();
-}
-
-db_flexrf_1200_tx::~db_flexrf_1200_tx()
-{
-}
-
-bool
-db_flexrf_1200_tx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-
-
-db_flexrf_1200_rx::db_flexrf_1200_rx(usrp_basic_sptr usrp, int which)
- : flexrf_base_rx(usrp, which)
-{
- d_common = new _1200_common();
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-}
-
-db_flexrf_1200_rx::~db_flexrf_1200_rx()
-{
-}
-
-float
-db_flexrf_1200_rx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_flexrf_1200_rx::gain_max()
-{
- return usrp()->pga_max()+70;
-}
-
-float
-db_flexrf_1200_rx::gain_db_per_step()
-{
- return 0.05;
-}
-
-bool
-db_flexrf_1200_rx::i_and_q_swapped()
-{
- return true;
-}
-
-bool
-db_flexrf_1200_rx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-//------------------------------------------------------------
-
-
-db_flexrf_1800_tx::db_flexrf_1800_tx(usrp_basic_sptr usrp, int which)
- : flexrf_base_tx(usrp, which)
-{
- d_common = new _1800_common();
-}
-
-db_flexrf_1800_tx::~db_flexrf_1800_tx()
-{
-}
-
-bool
-db_flexrf_1800_tx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-
-db_flexrf_1800_rx::db_flexrf_1800_rx(usrp_basic_sptr usrp, int which)
- : flexrf_base_rx(usrp, which)
-{
- d_common = new _1800_common();
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-}
-
-db_flexrf_1800_rx::~db_flexrf_1800_rx()
-{
-}
-
-
-float
-db_flexrf_1800_rx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_flexrf_1800_rx::gain_max()
-{
- return usrp()->pga_max()+70;
-}
-
-float
-db_flexrf_1800_rx::gain_db_per_step()
-{
- return 0.05;
-}
-
-bool
-db_flexrf_1800_rx::i_and_q_swapped()
-{
- return true;
-}
-
-bool
-db_flexrf_1800_rx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-//------------------------------------------------------------
-
-
-db_flexrf_900_tx::db_flexrf_900_tx(usrp_basic_sptr usrp, int which)
- : flexrf_base_tx(usrp, which)
-{
- d_common = new _900_common();
-}
-
-db_flexrf_900_tx::~db_flexrf_900_tx()
-{
-}
-
-bool
-db_flexrf_900_tx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-db_flexrf_900_rx::db_flexrf_900_rx(usrp_basic_sptr usrp, int which)
- : flexrf_base_rx(usrp, which)
-{
- d_common = new _900_common();
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-}
-
-db_flexrf_900_rx::~db_flexrf_900_rx()
-{
-}
-
-float
-db_flexrf_900_rx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_flexrf_900_rx::gain_max()
-{
- return usrp()->pga_max()+70;
-}
-
-float
-db_flexrf_900_rx::gain_db_per_step()
-{
- return 0.05;
-}
-
-bool
-db_flexrf_900_rx::i_and_q_swapped()
-{
- return true;
-}
-
-bool
-db_flexrf_900_rx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-//------------------------------------------------------------
-
-
-db_flexrf_400_tx::db_flexrf_400_tx(usrp_basic_sptr usrp, int which)
- : flexrf_base_tx(usrp, which, POWER_UP)
-{
- d_common = new _400_tx();
-}
-
-db_flexrf_400_tx::~db_flexrf_400_tx()
-{
-}
-
-bool
-db_flexrf_400_tx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
-
-
-db_flexrf_400_rx::db_flexrf_400_rx(usrp_basic_sptr usrp, int which)
- : flexrf_base_rx(usrp, which, POWER_UP)
-{
- d_common = new _400_rx();
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-}
-
-db_flexrf_400_rx::~db_flexrf_400_rx()
-{
-}
-
-float
-db_flexrf_400_rx::gain_min()
-{
- return usrp()->pga_min();
-}
-
-float
-db_flexrf_400_rx::gain_max()
-{
- return usrp()->pga_max()+45;
-}
-
-float
-
-db_flexrf_400_rx::gain_db_per_step()
-{
- return 0.035;
-}
-
-
-bool
-db_flexrf_400_rx::i_and_q_swapped()
-{
- return true;
-}
-
-bool
-db_flexrf_400_rx::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- return d_common->_compute_regs(_refclk_freq(), freq, retR,
- retcontrol, retN, retfreq);
-}
-
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_FLEXRF_H
-#define DB_FLEXRF_H
-
-#include <db_base.h>
-#include <cmath>
-
-//debug_using_gui = true // Must be set to True or False
-#define debug_using_gui false // Must be set to True or False
-
-class _AD4360_common;
-
-class flexrf_base : public db_base
-{
-public:
- flexrf_base(usrp_basic_sptr usrp, int which, int _power_on=0);
- ~flexrf_base();
-
- struct freq_result_t set_freq(double freq);
-
- bool is_quadrature();
- double freq_min();
- double freq_max();
-
-protected:
- void _write_all(int R, int control, int N);
- void _write_control(int control);
- void _write_R(int R);
- void _write_N(int N);
- void _write_it(int v);
- bool _lock_detect();
-
- virtual bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
- int _compute_control_reg();
- int _refclk_divisor();
- double _refclk_freq();
-
- bool _set_pga(float pga_gain);
-
- int power_on() { return d_power_on; }
- int power_off() { return 0; }
-
- bool d_first;
- int d_spi_format;
- int d_spi_enable;
- int d_power_on;
- int d_PD;
-
- _AD4360_common *d_common;
-};
-
-// ----------------------------------------------------------------
-
-class flexrf_base_tx : public flexrf_base
-{
-protected:
- void shutdown();
-
-public:
- flexrf_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0);
- ~flexrf_base_tx();
-
- // All RFX tx d'boards have fixed gain
- float gain_min();
- float gain_max();
- float gain_db_per_step();
-
- bool set_auto_tr(bool on);
- bool set_enable(bool on);
- bool set_gain(float gain);
-};
-
-class flexrf_base_rx : public flexrf_base
-{
-protected:
- void shutdown();
-
-public:
- flexrf_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0);
- ~flexrf_base_rx();
-
- bool set_auto_tr(bool on);
- bool select_rx_antenna(int which_antenna);
- bool select_rx_antenna(const std::string &which_antenna);
- bool set_gain(float gain);
-
-};
-
-// ----------------------------------------------------------------
-
-
-class _AD4360_common
-{
-public:
- _AD4360_common();
- virtual ~_AD4360_common();
-
- virtual double freq_min() = 0;
- virtual double freq_max() = 0;
-
- bool _compute_regs(double refclk_freq, double freq, int &retR,
- int &retcontrol, int &retN, double &retfreq);
- int _compute_control_reg();
- virtual int _refclk_divisor();
- int _prescaler();
-
- void R_DIV(int div) { d_R_DIV = div; }
-
-protected:
- int d_R_RSV, d_BSC, d_TEST, d_LDP, d_ABP, d_N_RSV, d_PL, d_MTLD;
- int d_CPG, d_CP3S, d_PDP, d_MUXOUT, d_CR, d_PC;
-
- // FIXME: d_PD might cause conflict from flexrf_base
- int d_A_DIV, d_B_DIV, d_R_DIV, d_P, d_PD, d_CP2, d_CP1, d_DIVSEL;
- int d_DIV2, d_CPGAIN, d_freq_mult;
-
-};
-
-//----------------------------------------------------------------------
-
-class _2400_common : public _AD4360_common
-{
- public:
- _2400_common();
- ~_2400_common() {}
-
- double freq_min();
- double freq_max();
-};
-
-//----------------------------------------------------------------------
-
-class _1200_common : public _AD4360_common
-{
-public:
- _1200_common();
- ~_1200_common() {}
-
- double freq_min();
- double freq_max();
-};
-
-//-------------------------------------------------------------------------
-
-class _1800_common : public _AD4360_common
-{
- public:
- _1800_common();
- ~_1800_common() {}
-
- double freq_min();
- double freq_max();
-};
-
-//-------------------------------------------------------------------------
-
-class _900_common : public _AD4360_common
-{
-public:
- _900_common();
- ~_900_common() {}
-
- double freq_min();
- double freq_max();
-};
-
-//-------------------------------------------------------------------------
-
-class _400_common : public _AD4360_common
-{
-public:
- _400_common();
- ~_400_common() {}
-
- double freq_min();
- double freq_max();
-};
-
-class _400_tx : public _400_common
-{
-public:
- _400_tx();
- ~_400_tx() {}
-};
-
-class _400_rx : public _400_common
-{
-public:
- _400_rx();
- ~_400_rx() {}
-};
-
-//------------------------------------------------------------
-
-class db_flexrf_2400_tx : public flexrf_base_tx
-{
- public:
- db_flexrf_2400_tx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_2400_tx();
-
- // Wrapper calls to d_common functions
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-class db_flexrf_2400_rx : public flexrf_base_rx
-{
-public:
- db_flexrf_2400_rx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_2400_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool i_and_q_swapped();
-
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-//------------------------------------------------------------
-
-class db_flexrf_1200_tx : public flexrf_base_tx
-{
-public:
- db_flexrf_1200_tx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_1200_tx();
-
- // Wrapper calls to d_common functions
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-class db_flexrf_1200_rx : public flexrf_base_rx
-{
-public:
- db_flexrf_1200_rx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_1200_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool i_and_q_swapped();
-
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-//------------------------------------------------------------
-
-class db_flexrf_1800_tx : public flexrf_base_tx
-{
- public:
- db_flexrf_1800_tx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_1800_tx();
-
- // Wrapper calls to d_common functions
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-class db_flexrf_1800_rx : public flexrf_base_rx
-{
-public:
- db_flexrf_1800_rx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_1800_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool i_and_q_swapped();
-
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-//------------------------------------------------------------
-
-class db_flexrf_900_tx : public flexrf_base_tx
-{
- public:
- db_flexrf_900_tx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_900_tx();
-
- // Wrapper calls to d_common functions
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-class db_flexrf_900_rx : public flexrf_base_rx
-{
-public:
- db_flexrf_900_rx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_900_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool i_and_q_swapped();
-
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-
-//------------------------------------------------------------
-
-class db_flexrf_400_tx : public flexrf_base_tx
-{
- public:
- db_flexrf_400_tx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_400_tx();
-
- // Wrapper calls to d_common functions
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-class db_flexrf_400_rx : public flexrf_base_rx
-{
-public:
- db_flexrf_400_rx(usrp_basic_sptr usrp, int which);
- ~db_flexrf_400_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool i_and_q_swapped();
-
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
-};
-
-#endif
+++ /dev/null
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <db_flexrf_mimo.h>
-#include <fpga_regs_standard.h>
-#include <fpga_regs_common.h>
-#include <usrp_prims.h>
-#include <usrp_spi_defs.h>
-
-
-db_flexrf_2400_tx_mimo_a::db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_2400_tx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_2400_tx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_2400_rx_mimo_a::db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_2400_rx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_2400_rx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_2400_tx_mimo_b::db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_2400_tx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_2400_tx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_2400_rx_mimo_b::db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_2400_rx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_2400_rx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_1800_tx_mimo_a::db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_1800_tx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_1800_tx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_1800_rx_mimo_a::db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_1800_rx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_1800_rx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_1800_tx_mimo_b::db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_1800_tx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_1800_tx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_1800_rx_mimo_b::db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_1800_rx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_1800_rx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_1200_tx_mimo_a::db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_1200_tx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_1200_tx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_1200_rx_mimo_a::db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_1200_rx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_1200_rx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_1200_tx_mimo_b::db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_1200_tx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_1200_tx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_1200_rx_mimo_b::db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_1200_rx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_1200_rx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_900_tx_mimo_a::db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_900_tx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_900_tx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_900_rx_mimo_a::db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_900_rx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_900_rx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_900_tx_mimo_b::db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_900_tx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_900_tx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_900_rx_mimo_b::db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_900_rx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int db_flexrf_900_rx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_400_tx_mimo_a::db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_400_tx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_400_tx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_400_rx_mimo_a::db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which)
- : db_flexrf_400_rx(usrp, which)
-{
- _enable_refclk(true);
- d_common->R_DIV(1);
-}
-
-int
-db_flexrf_400_rx_mimo_a::_refclk_divisor()
-{
- return 16;
-}
-
-db_flexrf_400_tx_mimo_b::db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_400_tx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_400_tx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
-
-db_flexrf_400_rx_mimo_b::db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which)
- : db_flexrf_400_rx(usrp, which)
-{
- d_common->R_DIV(16);
-}
-
-int
-db_flexrf_400_rx_mimo_b::_refclk_divisor()
-{
- return 1;
-}
+++ /dev/null
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <db_flexrf.h>
-
-class db_flexrf_2400_tx_mimo_a : public db_flexrf_2400_tx
-{
- public:
- db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_2400_rx_mimo_a : public db_flexrf_2400_rx
-{
- public:
- db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_2400_tx_mimo_b : public db_flexrf_2400_tx
-{
- public:
- db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_2400_rx_mimo_b : public db_flexrf_2400_rx
-{
- public:
- db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-
-class db_flexrf_1800_tx_mimo_a : public db_flexrf_1800_tx
-{
- public:
- db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1800_rx_mimo_a : public db_flexrf_1800_rx
-{
- public:
- db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1800_tx_mimo_b : public db_flexrf_1800_tx
-{
- public:
- db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1800_rx_mimo_b : public db_flexrf_1800_rx
-{
- public:
- db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1200_tx_mimo_a : public db_flexrf_1200_tx
-{
- public:
- db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1200_rx_mimo_a : public db_flexrf_1200_rx
-{
- public:
- db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1200_tx_mimo_b : public db_flexrf_1200_tx
-{
- public:
- db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_1200_rx_mimo_b : public db_flexrf_1200_rx
-{
- public:
- db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_900_tx_mimo_a : public db_flexrf_900_tx
-{
- public:
- db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_900_rx_mimo_a : public db_flexrf_900_rx
-{
- public:
- db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_900_tx_mimo_b : public db_flexrf_900_tx
-{
- public:
- db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_900_rx_mimo_b : public db_flexrf_900_rx
-{
- public:
- db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_400_tx_mimo_a : public db_flexrf_400_tx
-{
- public:
- db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_400_rx_mimo_a : public db_flexrf_400_rx
-{
- public:
- db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_400_tx_mimo_b : public db_flexrf_400_tx
-{
- public:
- db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
-
-class db_flexrf_400_rx_mimo_b : public db_flexrf_400_rx
-{
- public:
- db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which);
- int _refclk_divisor();
-};
+++ /dev/null
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_tv_rx.h>
-#include <db_base_impl.h>
-
-/*****************************************************************************/
-
-int
-control_byte_1(bool fast_tuning_p, int reference_divisor)
-{
- int c = 0x88;
- if(fast_tuning_p) {
- c |= 0x40;
- }
-
- if(reference_divisor == 512) {
- c |= 0x3 << 1;
- }
- else if(reference_divisor == 640) {
- c |= 0x0 << 1;
- }
- else if(reference_divisor == 1024) {
- c |= 0x1 << 1;
- }
- else {
- assert(0);
- }
-
- return c;
-}
-
-int
-control_byte_2(double target_freq, bool shutdown_tx_PGA)
-{
- int c;
- if(target_freq < 158e6) { // VHF low
- c = 0xa0;
- }
- else if(target_freq < 464e6) { // VHF high
- c = 0x90;
- }
- else { // UHF
- c = 0x30;
- }
-
- if(shutdown_tx_PGA) {
- c |= 0x08;
- }
-
- return c;
-}
-
-
-/*****************************************************************************/
-
-
-db_tv_rx::db_tv_rx(usrp_basic_sptr usrp, int which,
- double first_IF, double second_IF)
- : db_base(usrp, which)
-{
- // Handler for Tv Rx daughterboards.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
-
- if(which == 0) {
- d_i2c_addr = 0x60;
- }
- else {
- d_i2c_addr = 0x61;
- }
-
- d_first_IF = first_IF;
- d_second_IF = second_IF;
- d_reference_divisor = 640;
- d_fast_tuning = false;
- d_inverted = false; // FIXME get rid of this
-
- set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
-
- bypass_adc_buffers(false);
-}
-
-db_tv_rx::~db_tv_rx()
-{
-}
-
-// Gain setting
-void
-db_tv_rx::_set_rfagc(float gain)
-{
- float voltage;
-
- assert(gain <= 60 && gain >= 0);
- // FIXME this has a 0.5V step between gain = 60 and gain = 59.
- // Why are there two cases instead of a single linear case?
- if(gain == 60) {
- voltage = 4;
- }
- else {
- voltage = gain/60.0 * 2.25 + 1.25;
- }
- int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain
-
- assert(dacword>=0 && dacword<4096);
- usrp()->write_aux_dac(d_which, 1, dacword);
-}
-
-void
-db_tv_rx::_set_ifagc(float gain)
-{
- float voltage;
-
- assert(gain <= 35 && gain >= 0);
- voltage = gain/35.0 * 2.1 + 1.4;
- int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain
-
- assert(dacword>=0 && dacword<4096);
- usrp()->write_aux_dac(d_which, 0, dacword);
-}
-
-void
-db_tv_rx::_set_pga(float pga_gain)
-{
- assert(pga_gain >=0 && pga_gain <=20);
- if(d_which == 0) {
- usrp()->set_pga(0, pga_gain);
- }
- else {
- usrp()->set_pga (2, pga_gain);
- }
-}
-
-double
-db_tv_rx::freq_min()
-{
- return 50e6;
-}
-
-double
-db_tv_rx::freq_max()
-{
- return 860e6;
-}
-
-struct freq_result_t
-db_tv_rx::set_freq(double target_freq)
-{
- // Set the frequency.
- //
- // @param freq: target RF frequency in Hz
- // @type freq: double
- //
- // @returns (ok, actual_baseband_freq) where:
- // ok is True or False and indicates success or failure,
- // actual_baseband_freq is RF frequency that corresponds to DC in the IF.
-
- freq_result_t args = {false, 0};
-
- double fmin = freq_min();
- double fmax = freq_max();
- if((target_freq < fmin) || (target_freq > fmax)) {
- return args;
- }
-
- double target_lo_freq = target_freq + d_first_IF; // High side mixing
- double f_ref = 4.0e6 / (double)(d_reference_divisor); // frequency steps
-
- int divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8));
- double actual_lo_freq = (f_ref * 8 * divisor);
- double actual_freq = actual_lo_freq - d_first_IF;
-
- if((divisor & ~0x7fff) != 0) { // must be 15-bits or less
- return args;
- }
-
- // build i2c command string
- std::vector<int> buf(4);
- buf[0] = (divisor >> 8) & 0xff; // DB1
- buf[1] = divisor & 0xff; // DB2
- buf[2] = control_byte_1(d_fast_tuning, d_reference_divisor);
- buf[3] = control_byte_2(actual_freq, true);
-
- args.ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
- args.baseband_freq = actual_freq - d_second_IF;
- return args;
-}
-
-float
-db_tv_rx::gain_min()
-{
- return 0;
-}
-
-float
-db_tv_rx::gain_max()
-{
- return 115;
-}
-
-float
-db_tv_rx::gain_db_per_step()
-{
- return 1;
-}
-
-bool
-db_tv_rx::set_gain(float gain)
-{
- // Set the gain.
- //
- // @param gain: gain in decibels
- // @returns True/False
-
- float rfgain, ifgain, pgagain;
-
- assert(gain>=0 && gain<=115);
- if(gain>60) {
- rfgain = 60;
- gain = gain - 60;
- }
- else {
- rfgain = gain;
- gain = 0;
- }
-
- if(gain > 35) {
- ifgain = 35;
- gain = gain - 35;
- }
- else {
- ifgain = gain;
- gain = 0;
- }
-
- pgagain = gain;
- _set_rfagc(rfgain);
- _set_ifagc(ifgain);
- _set_pga(pgagain);
-
- return true;
-}
-
-bool
-db_tv_rx::is_quadrature()
-{
- // Return True if this board requires both I & Q analog channels.
- return false;
-}
-
-bool
-db_tv_rx::spectrum_inverted()
-{
- // The 43.75 MHz version is inverted
- return d_inverted;
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_TV_RX_H
-#define DB_TV_RX_H
-
-#include <db_base.h>
-
-class db_tv_rx : public db_base
-{
-private:
- void _set_rfagc(float gain);
- void _set_ifagc(float gain);
- void _set_pga(float pga_gain);
-
- int d_i2c_addr;
- double d_first_IF, d_second_IF;
- int d_reference_divisor;
- bool d_fast_tuning;
- bool d_inverted;
-
-public:
- db_tv_rx(usrp_basic_sptr usrp, int which,
- double first_IF, double second_IF);
- ~db_tv_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- double freq_min();
- double freq_max();
- struct freq_result_t set_freq(double target_freq);
- bool set_gain(float gain);
- bool is_quadrature();
- bool spectrum_inverted();
-};
-
-#endif
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <db_util.h>
-#include <sstream>
-
-std::string
-int_seq_to_str(std::vector<int> &seq)
-{
- //convert a sequence of integers into a string
-
- std::stringstream str;
- std::vector<int>::iterator i;
- for(i = seq.begin(); i != seq.end(); i++) {
- str << char((unsigned int)*i);
- }
- return str.str();
-}
-
-std::vector<int>
-str_to_int_seq(std::string str)
-{
- //convert a string to a list of integers
- std::vector<int> seq;
- std::vector<int>::iterator sitr;
- std::string::iterator i;
- for(i=str.begin(); i != str.end(); i++) {
- int a = (int)(*i);
- seq.push_back(a);
- }
- return seq;
-}
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef INCLUDED_DB_UTIL_H
-#define INCLUDED_DB_UTIL_H
-
-#include <string>
-#include <vector>
-
-std::string int_seq_to_str(std::vector<int> &seq);
-std::vector<int> str_to_int_seq(std::string str);
-
-#endif /* INCLUDED_DB_UTIL_H */
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_wbx.h>
-#include <fpga_regs_standard.h>
-#include <fpga_regs_common.h>
-#include <usrp_prims.h>
-#include <usrp_spi_defs.h>
-#include <stdexcept>
-#include <cmath>
-
-// d'board i/o pin defs
-
-// TX IO Pins
-#define TX_POWER (1 << 0) // TX Side Power
-#define RX_TXN (1 << 1) // T/R antenna switch for TX/RX port
-#define TX_ENB_MIX (1 << 2) // Enable IQ mixer
-#define TX_ENB_VGA (1 << 3)
-
-// RX IO Pins
-#define RX2_RX1N (1 << 0) // antenna switch between RX2 and TX/RX port
-#define RXENABLE (1 << 1) // enables mixer
-#define PLL_LOCK_DETECT (1 << 2) // Muxout pin from PLL -- MUST BE INPUT
-#define MReset (1 << 3) // NB6L239 Master Reset, asserted low
-#define SELA0 (1 << 4) // NB6L239 SelA0
-#define SELA1 (1 << 5) // NB6L239 SelA1
-#define SELB0 (1 << 6) // NB6L239 SelB0
-#define SELB1 (1 << 7) // NB6L239 SelB1
-#define PLL_ENABLE (1 << 8) // CE Pin on PLL
-#define AUX_SCLK (1 << 9) // ALT SPI SCLK
-#define AUX_SDO (1 << 10) // ALT SPI SDO
-#define AUX_SEN (1 << 11) // ALT SPI SEN
-
-
-wbx_base::wbx_base(usrp_basic_sptr usrp, int which)
- : db_base(usrp, which)
-{
- /*
- * @param usrp: instance of usrp.source_c
- * @param which: which side: 0 or 1 corresponding to side A or B respectively
- * @type which: int
- */
-
- d_first = true;
- d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
-
- // FIXME -- the write reg functions don't work with 0xffff for masks
- _rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff);
- _rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE));
-
- _tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff);
- _tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); // TX off, TR switch set to RX
-
- if(d_which == 0) {
- d_spi_enable = SPI_ENABLE_RX_A;
- }
- else {
- d_spi_enable = SPI_ENABLE_RX_B;
- }
-
- set_auto_tr(false);
-
-}
-
-wbx_base::~wbx_base()
-{
- shutdown();
-}
-
-
-void
-wbx_base::shutdown()
-{
- if (!d_is_shutdown){
- d_is_shutdown = true;
- // do whatever there is to do to shutdown
-
- write_io(d_which, d_power_off, POWER_UP); // turn off power to board
- _write_oe(d_which, 0, 0xffff); // turn off all outputs
- set_auto_tr(false); // disable auto transmit
- }
-}
-
-bool
-wbx_base::_lock_detect()
-{
- /*
- * @returns: the value of the VCO/PLL lock detect bit.
- * @rtype: 0 or 1
- */
-
- if(_rx_read_io() & PLL_LOCK_DETECT) {
- return true;
- }
- else { // Give it a second chance
- if(_rx_read_io() & PLL_LOCK_DETECT) {
- return true;
- }
- else {
- return false;
- }
- }
-}
-
-bool
-wbx_base::_tx_write_oe(int value, int mask)
-{
- int reg = (d_which == 0 ? FR_OE_0 : FR_OE_2);
- return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
-}
-
-bool
-wbx_base::_rx_write_oe(int value, int mask)
-{
- int reg = (d_which == 0 ? FR_OE_1 : FR_OE_3);
- return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
-}
-
-bool
-wbx_base::_tx_write_io(int value, int mask)
-{
- int reg = (d_which == 0 ? FR_IO_0 : FR_IO_2);
- return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
-}
-
-bool
-wbx_base::_rx_write_io(int value, int mask)
-{
- int reg = (d_which == 0 ? FR_IO_1 : FR_IO_3);
- return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
-}
-
-bool
-wbx_base::_rx_read_io()
-{
- int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B);
- int t = d_usrp->_read_fpga_reg(reg);
- return (t >> 16) & 0xffff;
-}
-
-bool
-wbx_base::_tx_read_io()
-{
- int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B);
- int t = d_usrp->_read_fpga_reg(reg);
- return (t & 0xffff);
-}
-
-bool
-wbx_base::_compute_regs(double freq)
-{
- /*
- * Determine values of registers, along with actual freq.
- *
- * @param freq: target frequency in Hz
- * @type freq: double
- * @returns: (R, N, func, init, actual_freq)
- * @rtype: tuple(int, int, int, int, double)
- *
- * Override this in derived classes.
- */
- throw std::runtime_error("_compute_regs called from base class\n");
-}
-
-double
-wbx_base::_refclk_freq()
-{
- return (double)(d_usrp->fpga_master_clock_freq())/_refclk_divisor();
-}
-
-int
-wbx_base::_refclk_divisor()
-{
- /*
- * Return value to stick in REFCLK_DIVISOR register
- */
- return 1;
-}
-
-struct freq_result_t
-wbx_base::set_freq(double freq)
-{
- /*
- * @returns (ok, actual_baseband_freq) where:
- * ok is True or False and indicates success or failure,
- * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
- */
- throw std::runtime_error("set_freq called from base class\n");
-}
-
-float
-wbx_base::gain_min()
-{
- throw std::runtime_error("gain_min called from base class\n");
-}
-
-float
-wbx_base::gain_max()
-{
- throw std::runtime_error("gain_max called from base class\n");
-}
-
-float
-wbx_base::gain_db_per_step()
-{
- throw std::runtime_error("gain_db_per_step called from base class\n");
-}
-
-bool
-wbx_base::set_gain(float gain)
-{
- /*
- * Set the gain.
- *
- * @param gain: gain in decibels
- * @returns True/False
- */
- throw std::runtime_error("set_gain called from base class\n");
-}
-
-bool
-wbx_base::_set_pga(float pga_gain)
-{
- bool ok;
- if(d_which == 0) {
- ok = d_usrp->set_pga(0, pga_gain);
- ok |= d_usrp->set_pga(1, pga_gain);
- }
- else {
- ok = d_usrp->set_pga(2, pga_gain);
- ok |= d_usrp->set_pga(3, pga_gain);
- }
- return ok;
-}
-
-bool
-wbx_base::is_quadrature()
-{
- /*
- * Return True if this board requires both I & Q analog channels.
- *
- * This bit of info is useful when setting up the USRP Rx mux register.
- */
- return true;
-}
-
-
-/****************************************************************************/
-
-
-wbx_base_tx::wbx_base_tx(usrp_basic_sptr usrp, int which)
- : wbx_base(usrp, which)
-{
- /*
- * @param usrp: instance of usrp.sink_c
- * @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
- */
-
- // power up the transmit side, NO -- but set antenna to receive
- d_usrp->write_io(d_which, (TX_POWER), (TX_POWER|RX_TXN));
- d_lo_offset = 0e6;
-
- // Gain is not set by the PGA, but the PGA must be set at max gain in the TX
- _set_pga(d_usrp->pga_max());
-}
-
-wbx_base_tx::~wbx_base_tx()
-{
- // Power down and leave the T/R switch in the R position
- d_usrp->write_io(d_which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA));
-}
-
-void
-wbx_base_tx::set_auto_tr(bool on)
-{
- if(on) {
- set_atr_mask (RX_TXN);
- set_atr_txval(0);
- set_atr_rxval(RX_TXN);
- }
- else {
- set_atr_mask (0);
- set_atr_txval(0);
- set_atr_rxval(0);
- }
-}
-
-void
-wbx_base_tx::set_enable(bool on)
-{
- /*
- * Enable transmitter if on is True
- */
-
- int mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA;
- //printf("HERE!!!!\n");
- if(on) {
- d_usrp->write_io(d_which, TX_ENB_MIX|TX_ENB_VGA, mask);
- }
- else {
- d_usrp->write_io(d_which, RX_TXN, mask);
- }
-}
-
-void
-wbx_base_tx::set_lo_offset(double offset)
-{
- /*
- * Set amount by which LO is offset from requested tuning frequency.
- *
- * @param offset: offset in Hz
- */
-
- d_lo_offset = offset;
-}
-
-double
-wbx_base_tx::lo_offset()
-{
- /*
- * Get amount by which LO is offset from requested tuning frequency.
- *
- * @returns Offset in Hz
- */
-
- return d_lo_offset;
-}
-
-
-/****************************************************************************/
-
-
-wbx_base_rx::wbx_base_rx(usrp_basic_sptr usrp, int which)
- : wbx_base(usrp, which)
-{
- /*
- * @param usrp: instance of usrp.source_c
- * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
- */
-
- // set up for RX on TX/RX port
- select_rx_antenna("TX/RX");
-
- bypass_adc_buffers(true);
-
- d_lo_offset = 0.0;
-}
-
-wbx_base_rx::~wbx_base_rx()
-{
- // Power down
- d_usrp->write_io(d_which, 0, (RXENABLE));
-}
-
-void
-wbx_base_rx::set_auto_tr(bool on)
-{
- if(on) {
- // FIXME: where does ENABLE come from?
- //set_atr_mask (ENABLE);
- set_atr_txval( 0);
- //set_atr_rxval(ENABLE);
- }
- else {
- set_atr_mask (0);
- set_atr_txval(0);
- set_atr_rxval(0);
- }
-}
-
-void
-wbx_base_rx::select_rx_antenna(int which_antenna)
-{
- /*
- * Specify which antenna port to use for reception.
- * @param which_antenna: either 'TX/RX' or 'RX2'
- */
-
- if(which_antenna == 0) {
- d_usrp->write_io(d_which, 0, RX2_RX1N);
- }
- else if(which_antenna == 1) {
- d_usrp->write_io(d_which, RX2_RX1N, RX2_RX1N);
- }
- else {
- throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
- }
-}
-
-void
-wbx_base_rx::select_rx_antenna(const std::string &which_antenna)
-{
- if(which_antenna == "TX/RX") {
- select_rx_antenna(0);
- }
- else if(which_antenna == "RX2") {
- select_rx_antenna(1);
- }
- else {
- throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
- }
-}
-
-bool
-wbx_base_rx::set_gain(float gain)
-{
- /*
- * Set the gain.
- *
- * @param gain: gain in decibels
- * @returns True/False
- */
-
- float pga_gain, agc_gain;
- float maxgain = gain_max() - d_usrp->pga_max();
- float mingain = gain_min();
- if(gain > maxgain) {
- pga_gain = gain-maxgain;
- assert(pga_gain <= d_usrp->pga_max());
- agc_gain = maxgain;
- }
- else {
- pga_gain = 0;
- agc_gain = gain;
- }
-
- float V_maxgain = .2;
- float V_mingain = 1.2;
- float V_fullscale = 3.3;
- float dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
-
- assert(dac_value>=0 && dac_value<4096);
-
- return d_usrp->write_aux_dac(d_which, 0, (int)(dac_value)) && _set_pga((int)(pga_gain));
-}
-
-void
-wbx_base_rx::set_lo_offset(double offset)
-{
- /*
- * Set amount by which LO is offset from requested tuning frequency.
- *
- * @param offset: offset in Hz
- */
- d_lo_offset = offset;
-}
-
-double
-wbx_base_rx::lo_offset()
-{
- /*
- * Get amount by which LO is offset from requested tuning frequency.
- *
- * @returns Offset in Hz
- */
- return d_lo_offset;
-}
-
-bool
-wbx_base_rx::i_and_q_swapped()
-{
- /*
- * Return True if this is a quadrature device and ADC 0 is Q.
- */
- return false;
-}
-
-
-/****************************************************************************/
-
-_ADF410X_common::_ADF410X_common()
-{
- // R-Register Common Values
- d_R_RSV = 0; // bits 23,22,21
- d_LDP = 1; // bit 20 Lock detect in 5 cycles
- d_TEST = 0; // bit 19,18 Normal
- d_ABP = 0; // bit 17,16 2.9ns
-
- // N-Register Common Values
- d_N_RSV = 0; // 23,22
- d_CP_GAIN = 0; // 21
-
- // Function Register Common Values
- d_P = 0; // bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65
- d_PD2 = 0; // bit 21 Normal operation
- d_CP2 = 4; // bits 20,19,18 CP Gain = 5mA
- d_CP1 = 4; // bits 17,16,15 CP Gain = 5mA
- d_TC = 0; // bits 14-11 PFD Timeout
- d_FL = 0; // bit 10,9 Fastlock Disabled
- d_CP3S = 0; // bit 8 CP Enabled
- d_PDP = 0; // bit 7 Phase detector polarity, Positive=1
- d_MUXOUT = 1; // bits 6:4 Digital Lock Detect
- d_PD1 = 0; // bit 3 Normal operation
- d_CR = 0; // bit 2 Normal operation
-}
-
-_ADF410X_common::~_ADF410X_common()
-{
-}
-
-bool
-_ADF410X_common::_compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq)
-{
- /*
- * Determine values of R, control, and N registers, along with actual freq.
- *
- * @param freq: target frequency in Hz
- * @type freq: double
- * @returns: (R, N, control, actual_freq)
- * @rtype: tuple(int, int, int, double)
- */
-
- // Band-specific N-Register Values
- double phdet_freq = _refclk_freq()/d_R_DIV;
- printf("phdet_freq = %f\n", phdet_freq);
-
- double desired_n = round(freq*d_freq_mult/phdet_freq);
- printf("desired_n %f\n", desired_n);
-
- double actual_freq = desired_n * phdet_freq;
- printf("actual freq %f\n", actual_freq);
-
- double B = floor(desired_n/_prescaler());
- double A = desired_n - _prescaler()*B;
- printf("A %f B %f\n", A, B);
-
- d_B_DIV = int(B); // bits 20:8;
- d_A_DIV = int(A); // bit 6:2;
-
- if(d_B_DIV < d_A_DIV) {
- retR = 0;
- retN = 0;
- retcontrol = 0;
- retfreq = 0;
- return false;
- }
-
- retR = (d_R_RSV<<21) | (d_LDP<<20) | (d_TEST<<18) |
- (d_ABP<<16) | (d_R_DIV<<2);
-
- retN = (d_N_RSV<<22) | (d_CP_GAIN<<21) | (d_B_DIV<<8) | (d_A_DIV<<2);
-
- retcontrol = (d_P<<22) | (d_PD2<<21) | (d_CP2<<18) | (d_CP1<<15) |
- (d_TC<<11) | (d_FL<<9) | (d_CP3S<<8) | (d_PDP<<7) |
- (d_MUXOUT<<4) | (d_PD1<<3) | (d_CR<<2);
-
- retfreq = actual_freq/d_freq_mult;
-
- return true;
-}
-
-void
-_ADF410X_common::_write_all(int R, int N, int control)
-{
- /*
- * Write all PLL registers:
- * R counter latch,
- * N counter latch,
- * Function latch,
- * Initialization latch
- *
- * Adds 10ms delay between writing control and N if this is first call.
- * This is the required power-up sequence.
- *
- * @param R: 24-bit R counter latch
- * @type R: int
- * @param N: 24-bit N counter latch
- * @type N: int
- * @param control: 24-bit control latch
- * @type control: int
- */
- static bool first = true;
-
- timespec t;
- t.tv_sec = 0;
- t.tv_nsec = 10000000;
-
- _write_R(R);
- _write_func(control);
- _write_init(control);
- if(first) {
- //time.sleep(0.010);
- nanosleep(&t, NULL);
- first = false;
- }
- _write_N(N);
-}
-
-void
-_ADF410X_common::_write_R(int R)
-{
- _write_it((R & ~0x3) | 0);
-}
-
-void
-_ADF410X_common::_write_N(int N)
-{
- _write_it((N & ~0x3) | 1);
-}
-
-void
-_ADF410X_common::_write_func(int func)
-{
- _write_it((func & ~0x3) | 2);
-}
-
-void
-_ADF410X_common::_write_init(int init)
-{
- _write_it((init & ~0x3) | 3);
-}
-
-void
-_ADF410X_common::_write_it(int v)
-{
- char c[3];
- c[0] = (char)((v >> 16) & 0xff);
- c[1] = (char)((v >> 8) & 0xff);
- c[2] = (char)((v & 0xff));
- std::string s(c, 3);
- //d_usrp->_write_spi(0, d_spi_enable, d_spi_format, s);
- usrp()->_write_spi(0, d_spi_enable, d_spi_format, s);
-}
-
-int
-_ADF410X_common::_prescaler()
-{
- if(d_P == 0) {
- return 8;
- }
- else if(d_P == 1) {
- return 16;
- }
- else if(d_P == 2) {
- return 32;
- }
- else if(d_P == 3) {
- return 64;
- }
- else {
- throw std::invalid_argument("Prescaler out of range\n");
- }
-}
-
-double
-_ADF410X_common::_refclk_freq()
-{
- throw std::runtime_error("_refclk_freq called from base class.");
-}
-
-bool
-_ADF410X_common::_rx_write_io(int value, int mask)
-{
- throw std::runtime_error("_rx_write_io called from base class.");
-}
-
-bool
-_ADF410X_common::_lock_detect()
-{
- throw std::runtime_error("_lock_detect called from base class.");
-}
-
-usrp_basic*
-_ADF410X_common::usrp()
-{
- throw std::runtime_error("usrp() called from base class.");
-}
-
-
-/****************************************************************************/
-
-
-_lo_common::_lo_common()
- : _ADF410X_common()
-{
- // Band-specific R-Register Values
- d_R_DIV = 4; // bits 15:2
-
- // Band-specific C-Register values
- d_P = 0; // bits 23,22 0 = Div by 8/9
- d_CP2 = 4; // bits 19:17
- d_CP1 = 4; // bits 16:14
-
- // Band specifc N-Register Values
- d_DIVSEL = 0; // bit 23
- d_DIV2 = 0; // bit 22
- d_CPGAIN = 0; // bit 21
- d_freq_mult = 1;
-
- d_div = 1;
- d_aux_div = 2;
- d_main_div = 0;
-}
-
-_lo_common::~_lo_common()
-{
-}
-
-double
-_lo_common::freq_min()
-{
- return 50e6;
-}
-
-double
-_lo_common::freq_max()
-{
- return 1000e6;
-}
-
-void
-_lo_common::set_divider(int main_or_aux, int divisor)
-{
- if(main_or_aux == 0) {
- if((divisor != 1) || (divisor != 2) || (divisor != 4) || (divisor != 8)) {
- throw std::invalid_argument("Main Divider Must be 1, 2, 4, or 8\n");
- }
- d_main_div = (int)(log10(divisor)/log10(2.0));
- }
- else if(main_or_aux == 1) {
- if((divisor != 2) || (divisor != 4) || (divisor != 8) || (divisor != 16)) {
- throw std::invalid_argument("Aux Divider Must be 2, 4, 8 or 16\n");
- }
- d_main_div = (int)(log10(divisor/2.0)/log10(2.0));
- }
- else {
- throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n");
- }
-
- int vala = d_main_div*SELA0;
- int valb = d_aux_div*SELB0;
- int mask = SELA0|SELA1|SELB0|SELB1;
-
- _rx_write_io((vala | valb), mask);
-}
-
-void
-_lo_common::set_divider(const std::string &main_or_aux, int divisor)
-{
- if(main_or_aux == "main") {
- set_divider(0, divisor);
- }
- else if(main_or_aux == "aux") {
- set_divider(1, divisor);
- }
- else {
- throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n");
- }
-}
-
-struct freq_result_t
-_lo_common::set_freq(double freq)
-{
- struct freq_result_t ret;
-
- if(freq < 20e6 or freq > 1200e6) {
- throw std::invalid_argument("Requested frequency out of range\n");
- }
-
- int div = 1;
- double lo_freq = freq * 2;
- while((lo_freq < 1e9) && (div < 8)) {
- div = div * 2;
- lo_freq = lo_freq * 2;
- }
-
- printf("For RF freq of %f, we set DIV=%d and LO Freq=%f\n", freq, div, lo_freq);
-
- set_divider("main", div);
- set_divider("aux", div*2);
-
- int R, N, control;
- double actual_freq;
- _compute_regs(lo_freq, R, N, control, actual_freq);
-
- printf("R %d N %d control %d actual freq %f\n", R, N, control, actual_freq);
- if(R==0) {
- ret.ok = false;
- ret.baseband_freq = 0.0;
- return ret;
- }
- _write_all(R, N, control);
-
- ret.ok = _lock_detect();
- ret.baseband_freq = actual_freq/div/2;
- return ret;
-}
-
-
-/****************************************************************************/
-
-
-db_wbx_lo_tx::db_wbx_lo_tx(usrp_basic_sptr usrp, int which)
- : _lo_common(),
- wbx_base_tx(usrp, which)
-{
-}
-
-db_wbx_lo_tx::~db_wbx_lo_tx()
-{
-}
-
-float
-db_wbx_lo_tx::gain_min()
-{
- return -56.0;
-}
-
-float
-db_wbx_lo_tx::gain_max()
-{
- return 0.0;
-}
-
-float
-db_wbx_lo_tx::gain_db_per_step()
-{
- return 0.1;
-}
-
-bool
-db_wbx_lo_tx::set_gain(float gain)
-{
- /*
- * Set the gain.
- *
- * @param gain: gain in decibels
- * @returns True/False
- */
-
- float txvga_gain;
- float maxgain = gain_max();
- float mingain = gain_min();
- if(gain > maxgain) {
- txvga_gain = maxgain;
- }
- else if(gain < mingain) {
- txvga_gain = mingain;
- }
- else {
- txvga_gain = gain;
- }
-
- float V_maxgain = 1.4;
- float V_mingain = 0.1;
- float V_fullscale = 3.3;
- float dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/
- (maxgain-mingain) + V_mingain)*4096/V_fullscale;
-
- assert(dac_value>=0 && dac_value<4096);
- printf("DAC value %f\n", dac_value);
-
- return d_usrp->write_aux_dac(d_which, 1, (int)(dac_value));
-}
-
-double
-db_wbx_lo_tx::_refclk_freq()
-{
- return wbx_base::_refclk_freq();
-}
-
-bool
-db_wbx_lo_tx::_rx_write_io(int value, int mask)
-{
- return wbx_base::_rx_write_io(value, mask);
-}
-
-bool
-db_wbx_lo_tx::_lock_detect()
-{
- return wbx_base::_lock_detect();
-}
-
-usrp_basic*
-db_wbx_lo_tx::usrp()
-{
- return d_usrp;
-}
-
-
-/****************************************************************************/
-
-
-db_wbx_lo_rx::db_wbx_lo_rx(usrp_basic_sptr usrp, int which)
- : _lo_common(),
- wbx_base_rx(usrp, which)
-{
-}
-
-db_wbx_lo_rx::~db_wbx_lo_rx()
-{
-}
-
-float
-db_wbx_lo_rx::gain_min()
-{
- return d_usrp->pga_min();
-}
-
-float
-db_wbx_lo_rx::gain_max()
-{
- return d_usrp->pga_max() + 45;
-}
-
-float
-db_wbx_lo_rx::gain_db_per_step()
-{
- return 0.05;
-}
-
-double
-db_wbx_lo_rx::_refclk_freq()
-{
- return wbx_base::_refclk_freq();
-}
-
-bool
-db_wbx_lo_rx::_rx_write_io(int value, int mask)
-{
- return wbx_base::_rx_write_io(value, mask);
-}
-
-bool
-db_wbx_lo_rx::_lock_detect()
-{
- return wbx_base::_lock_detect();
-}
-
-usrp_basic*
-db_wbx_lo_rx::usrp()
-{
- return d_usrp;
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_WBX_H
-#define DB_WBX_H
-
-#include <db_base.h>
-#include <boost/shared_ptr.hpp>
-
-
-/*
- A few comments about the WBX boards:
- They are half-duplex. I.e., transmit and receive are mutually exclusive.
- There is a single LO for both the Tx and Rx sides.
- The the shared control signals are hung off of the Rx side.
- The shared io controls are duplexed onto the Rx side pins.
- The wbx_high d'board always needs to be in 'auto_tr_mode'
-*/
-
-
-class wbx_base : public db_base
-{
-protected:
- void shutdown();
-
- /*
- * Abstract base class for all wbx boards.
- *
- * Derive board specific subclasses from db_wbx_base_{tx,rx}
- */
-
-public:
- wbx_base(usrp_basic_sptr usrp, int which);
- ~wbx_base();
-
- struct freq_result_t set_freq(double freq);
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool set_gain(float gain);
- bool is_quadrature();
-
-
-protected:
- virtual bool _lock_detect();
-
- // FIXME: After testing, replace these with usrp_basic::common_write_io/oe
- bool _tx_write_oe(int value, int mask);
- bool _rx_write_oe(int value, int mask);
- bool _tx_write_io(int value, int mask);
- bool _rx_write_io(int value, int mask);
- virtual bool _rx_read_io();
- bool _tx_read_io();
- bool _compute_regs(double freq);
- virtual double _refclk_freq();
- int _refclk_divisor();
-
- bool _set_pga(float pga_gain);
-
- bool d_first;
- int d_spi_format;
- int d_spi_enable;
- double d_lo_offset;
-};
-
-
-/****************************************************************************/
-
-
-class wbx_base_tx : public wbx_base
-{
-public:
- wbx_base_tx(usrp_basic_sptr usrp, int which);
- ~wbx_base_tx();
-
- bool set_auto_tr(bool on);
- bool set_enable(bool on);
-};
-
-
-/****************************************************************************/
-
-
-class wbx_base_rx : public wbx_base
-{
-public:
- wbx_base_rx(usrp_basic_sptr usrp, int which);
- ~wbx_base_rx();
-
- bool set_auto_tr(bool on);
- bool select_rx_antenna(int which_antenna);
- bool select_rx_antenna(const std::string &which_antenna);
- bool set_gain(float gain);
- bool i_and_q_swapped();
-};
-
-
-/****************************************************************************/
-
-
-class _ADF410X_common
-{
-public:
- _ADF410X_common();
- virtual ~_ADF410X_common();
-
- bool _compute_regs(double freq, int &retR, int &retcontrol,
- int &retN, double &retfreq);
- void _write_all(int R, int N, int control);
- void _write_R(int R);
- void _write_N(int N);
- void _write_func(int func);
- void _write_init(int init);
- int _prescaler();
- virtual void _write_it(int v);
- virtual double _refclk_freq();
- virtual bool _rx_write_io(int value, int mask);
- virtual bool _lock_detect();
-
-protected:
- virtual usrp_basic* usrp();
-
- int d_R_RSV, d_LDP, d_TEST, d_ABP;
- int d_N_RSV, d_CP_GAIN;
- int d_P, d_PD2, d_CP2, d_CP1, d_TC, d_FL;
- int d_CP3S, d_PDP, d_MUXOUT, d_PD1, d_CR;
- int d_R_DIV, d_A_DIV, d_B_DIV;
- int d_freq_mult;
-
- int d_spi_format;
- int d_spi_enable;
-};
-
-
-/****************************************************************************/
-
-
-class _lo_common : public _ADF410X_common
-{
-public:
- _lo_common();
- ~_lo_common();
-
- double freq_min();
- double freq_max();
-
- void set_divider(int main_or_aux, int divisor);
- void set_divider(const std::string &main_or_aux, int divisor);
-
- struct freq_result_t set_freq(double freq);
-
-protected:
- int d_R_DIV, d_P, d_CP2, d_CP1;
- int d_DIVSEL, d_DIV2, d_CPGAIN;
- int d_div, d_aux_div, d_main_div;
-};
-
-
-/****************************************************************************/
-
-
-class db_wbx_lo_tx : public _lo_common, public wbx_base_tx
-{
-public:
- db_wbx_lo_tx(usrp_basic_sptr usrp, int which);
- ~db_wbx_lo_tx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool set_gain(float gain);
-
- double _refclk_freq();
- bool _rx_write_io(int value, int mask);
- bool _lock_detect();
-
-protected:
- usrp_basic* usrp();
-};
-
-
-/****************************************************************************/
-
-
-class db_wbx_lo_rx : public _lo_common, public wbx_base_rx
-{
-public:
- db_wbx_lo_rx(usrp_basic_sptr usrp, int which);
- ~db_wbx_lo_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
-
- double _refclk_freq();
- bool _rx_write_io(int value, int mask);
- bool _lock_detect();
-
-protected:
- usrp_basic* usrp();
-};
-
-#endif
+++ /dev/null
-//
-// Copyright 2008,2009 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#include <db_xcvr2450.h>
-#include <db_base_impl.h>
-#include <cmath>
-#include <boost/thread.hpp>
-#include <boost/weak_ptr.hpp>
-#include <cstdio>
-
-#if 0
-#define LO_OFFSET 4.25e6
-#else
-#define LO_OFFSET 0
-#define NO_LO_OFFSET
-#endif
-
-
-/* ------------------------------------------------------------------------
- * A few comments about the XCVR2450:
- *
- * It is half-duplex. I.e., transmit and receive are mutually exclusive.
- * There is a single LO for both the Tx and Rx sides.
- * For our purposes the board is always either receiving or transmitting.
- *
- * Each board is uniquely identified by the *USRP hardware* instance and side
- * This dictionary holds a weak reference to existing board controller so it
- * can be created or retrieved as needed.
- */
-
-
-
-// TX IO Pins
-#define HB_PA_OFF (1 << 15) // 5GHz PA, 1 = off, 0 = on
-#define LB_PA_OFF (1 << 14) // 2.4GHz PA, 1 = off, 0 = on
-#define ANTSEL_TX1_RX2 (1 << 13) // 1 = Ant 1 to TX, Ant 2 to RX
-#define ANTSEL_TX2_RX1 (1 << 12) // 1 = Ant 2 to TX, Ant 1 to RX
-#define TX_EN (1 << 11) // 1 = TX on, 0 = TX off
-#define AD9515DIV (1 << 4) // 1 = Div by 3, 0 = Div by 2
-
-#define TX_OE_MASK HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV
-#define TX_SAFE_IO HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV
-
-// RX IO Pins
-#define LOCKDET (1 << 15) // This is an INPUT!!!
-#define EN (1 << 14)
-#define RX_EN (1 << 13) // 1 = RX on, 0 = RX off
-#define RX_HP (1 << 12)
-#define RX_OE_MASK EN|RX_EN|RX_HP
-#define RX_SAFE_IO EN
-
-struct xcvr2450_key {
- std::string serial_no;
- int which;
-
- bool operator==(const xcvr2450_key &x){
- return x.serial_no ==serial_no && x.which == which;
- }
-};
-
-class xcvr2450
-{
-private:
- usrp_basic *d_raw_usrp;
- int d_which;
-
- bool d_is_shutdown;
- int d_spi_format, d_spi_enable;
-
- int d_mimo, d_int_div, d_frac_div, d_highband, d_five_gig;
- int d_cp_current, d_ref_div, d_rssi_hbw;
- int d_txlpf_bw, d_rxlpf_bw, d_rxlpf_fine, d_rxvga_ser;
- int d_rssi_range, d_rssi_mode, d_rssi_mux;
- int d_rx_hp_pin, d_rx_hpf, d_rx_ant;
- int d_tx_ant, d_txvga_ser, d_tx_driver_lin;
- int d_tx_vga_lin, d_tx_upconv_lin, d_tx_bb_gain;
- int d_pabias_delay, d_pabias, rx_rf_gain, rx_bb_gain, d_txgain;
- int d_rx_rf_gain, d_rx_bb_gain;
-
- int d_reg_standby, d_reg_int_divider, d_reg_frac_divider, d_reg_bandselpll;
- int d_reg_cal, dsend_reg, d_reg_lpf, d_reg_rxrssi_ctrl, d_reg_txlin_gain;
- int d_reg_pabias, d_reg_rxgain, d_reg_txgain;
-
- int d_ad9515_div;
-
- void _set_rfagc(float gain);
- void _set_ifagc(float gain);
- void _set_pga(float pga_gain);
-
-public:
- usrp_basic *usrp(){
- return d_raw_usrp;
- }
-
- xcvr2450(usrp_basic_sptr usrp, int which);
- ~xcvr2450();
- void shutdown();
-
- void set_reg_standby();
-
- // Integer-Divider Ratio (3)
- void set_reg_int_divider();
-
- // Fractional-Divider Ratio (4)
- void set_reg_frac_divider();
-
- // Band Select and PLL (5)
- void set_reg_bandselpll();
-
- // Calibration (6)
- void set_reg_cal();
-
- // Lowpass Filter (7)
- void set_reg_lpf();
-
- // Rx Control/RSSI (8)
- void set_reg_rxrssi_ctrl();
-
- // Tx Linearity/Baseband Gain (9)
- void set_reg_txlin_gain();
-
- // PA Bias DAC (10)
- void set_reg_pabias();
-
- // Rx Gain (11)
- void set_reg_rxgain();
-
- // Tx Gain (12)
- void set_reg_txgain();
-
- // Send register write to SPI
- void send_reg(int v);
-
- void set_gpio();
- bool lock_detect();
- bool set_rx_gain(float gain);
- bool set_tx_gain(float gain);
-
- struct freq_result_t set_freq(double target_freq);
-};
-
-
-/*****************************************************************************/
-
-
-xcvr2450::xcvr2450(usrp_basic_sptr _usrp, int which)
- : d_raw_usrp(_usrp.get()), d_which(which), d_is_shutdown(false)
-{
- // Handler for Tv Rx daughterboards.
- //
- // @param usrp: instance of usrp.source_c
- // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
-
- // Use MSB with no header
- d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
-
- if(which == 0) {
- d_spi_enable = SPI_ENABLE_RX_A;
- }
- else {
- d_spi_enable = SPI_ENABLE_RX_B;
- }
-
- // Sane defaults
- d_mimo = 1; // 0 = OFF, 1 = ON
- d_int_div = 192; // 128 = min, 255 = max
- d_frac_div = 0; // 0 = min, 65535 = max
- d_highband = 0; // 0 = freq <= 5.4e9, 1 = freq > 5.4e9
- d_five_gig = 0; // 0 = freq <= 3.e9, 1 = freq > 3e9
- d_cp_current = 1; // 0 = 2mA, 1 = 4mA
- d_ref_div = 1; // 1 to 7
- d_rssi_hbw = 0; // 0 = 2 MHz, 1 = 6 MHz
- d_txlpf_bw = 1; // 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
- d_rxlpf_bw = 1; // 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
- d_rxlpf_fine = 2; // 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
- d_rxvga_ser = 1; // 0 = RXVGA controlled by B7:1, 1=controlled serially
- d_rssi_range = 1; // 0 = low range (datasheet typo), 1=high range (0.5V - 2.0V)
- d_rssi_mode = 1; // 0 = enable follows RXHP, 1 = enabled
- d_rssi_mux = 0; // 0 = RSSI, 1 = TEMP
- d_rx_hp_pin = 0; // 0 = Fc set by rx_hpf, 1 = 600 KHz
- d_rx_hpf = 0; // 0 = 100Hz, 1 = 30KHz
- d_rx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2
- d_tx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2
- d_txvga_ser = 1; // 0 = TXVGA controlled by B6:1, 1=controlled serially
- d_tx_driver_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
- d_tx_vga_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
- d_tx_upconv_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
- d_tx_bb_gain = 3; // 0=maxgain-5dB, 1=max-3dB, 2=max-1.5dB, 3=max
- d_pabias_delay = 15; // 0 = 0, 15 = 7uS
- d_pabias = 0; // 0 = 0 uA, 63 = 315uA
- d_rx_rf_gain = 0; // 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB
- d_rx_bb_gain = 16; // 0 = min, 31 = max (0 - 62 dB)
-
- d_txgain = 63; // 0 = min, 63 = max
-
- // Initialize GPIO and ATR
- usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK);
- usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff);
- usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO);
- usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO);
- usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK);
-
- usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK);
- usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff);
- usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO);
- usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO);
- usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK);
-
- // Initialize chipset
- // TODO: perform reset sequence to ensure power up defaults
- set_reg_standby();
- set_reg_bandselpll();
- set_reg_cal();
- set_reg_lpf();
- set_reg_rxrssi_ctrl();
- set_reg_txlin_gain();
- set_reg_pabias();
- set_reg_rxgain();
- set_reg_txgain();
- //FIXME: set_freq(2.45e9);
-}
-
-xcvr2450::~xcvr2450()
-{
- //printf("xcvr2450::destructor\n");
- shutdown();
-}
-
-void
-xcvr2450::shutdown()
-{
- if (!d_is_shutdown){
- d_is_shutdown = true;
- usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO);
- usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO);
- usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO);
- usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO);
- }
-}
-
-
-void
-xcvr2450::set_reg_standby()
-{
- d_reg_standby = ((d_mimo<<17) |
- (1<<16) |
- (1<<6) |
- (1<<5) |
- (1<<4) | 2);
- send_reg(d_reg_standby);
-}
-
-void
-xcvr2450::set_reg_int_divider()
-{
- d_reg_int_divider = (((d_frac_div & 0x03)<<16) |
- (d_int_div<<4) | 3);
- send_reg(d_reg_int_divider);
-}
-
-void
-xcvr2450::set_reg_frac_divider()
-{
- d_reg_frac_divider = ((d_frac_div & 0xfffc)<<2) | 4;
- send_reg(d_reg_frac_divider);
-}
-
-void
-xcvr2450::set_reg_bandselpll()
-{
- d_reg_bandselpll = ((d_mimo<<17) |
- (1<<16) |
- (1<<15) |
- (0<<11) |
- (d_highband<<10) |
- (d_cp_current<<9) |
- (d_ref_div<<5) |
- (d_five_gig<<4) | 5);
- send_reg(d_reg_bandselpll);
- d_reg_bandselpll = ((d_mimo<<17) |
- (1<<16) |
- (1<<15) |
- (1<<11) |
- (d_highband<<10) |
- (d_cp_current<<9) |
- (d_ref_div<<5) |
- (d_five_gig<<4) | 5);
- send_reg(d_reg_bandselpll);
-}
-
-void
-xcvr2450::set_reg_cal()
-{
- // FIXME do calibration
- d_reg_cal = (1<<14)|6;
- send_reg(d_reg_cal);
-}
-
-void
-xcvr2450::set_reg_lpf()
-{
- d_reg_lpf = (
- (d_rssi_hbw<<15) |
- (d_txlpf_bw<<10) |
- (d_rxlpf_bw<<9) |
- (d_rxlpf_fine<<4) | 7);
- send_reg(d_reg_lpf);
-}
-
-void
-xcvr2450::set_reg_rxrssi_ctrl()
-{
- d_reg_rxrssi_ctrl = ((d_rxvga_ser<<16) |
- (d_rssi_range<<15) |
- (d_rssi_mode<<14) |
- (d_rssi_mux<<12) |
- (1<<9) |
- (d_rx_hpf<<6) |
- (1<<4) | 8);
- send_reg(d_reg_rxrssi_ctrl);
-}
-
-void
-xcvr2450::set_reg_txlin_gain()
-{
- d_reg_txlin_gain = ((d_txvga_ser<<14) |
- (d_tx_driver_lin<<12) |
- (d_tx_vga_lin<<10) |
- (d_tx_upconv_lin<<6) |
- (d_tx_bb_gain<<4) | 9);
- send_reg(d_reg_txlin_gain);
-}
-
-void
-xcvr2450::set_reg_pabias()
-{
- d_reg_pabias = (
- (d_pabias_delay<<10) |
- (d_pabias<<4) | 10);
- send_reg(d_reg_pabias);
-}
-
-void
-xcvr2450::set_reg_rxgain()
-{
- d_reg_rxgain = (
- (d_rx_rf_gain<<9) |
- (d_rx_bb_gain<<4) | 11);
- send_reg(d_reg_rxgain);
-}
-
-void
-xcvr2450::set_reg_txgain()
-{
- d_reg_txgain = (d_txgain<<4) | 12;
- send_reg(d_reg_txgain);
-}
-
-void
-xcvr2450::send_reg(int v)
-{
- // Send 24 bits, it keeps last 18 clocked in
- char c[3];
- c[0] = (char)((v >> 16) & 0xff);
- c[1] = (char)((v >> 8) & 0xff);
- c[2] = (char)((v & 0xff));
- std::string s(c, 3);
-
- usrp()->_write_spi(0, d_spi_enable, d_spi_format, s);
- //printf("xcvr2450: Setting reg %d to %X\n", (v&15), v);
-}
-
-// ----------------------------------------------------------------
-
-void
-xcvr2450::set_gpio()
-{
- // We calculate four values:
- //
- // io_rx_while_rx: what to drive onto io_rx_* when receiving
- // io_rx_while_tx: what to drive onto io_rx_* when transmitting
- // io_tx_while_rx: what to drive onto io_tx_* when receiving
- // io_tx_while_tx: what to drive onto io_tx_* when transmitting
- //
- // B1-B7 is ignored as gain is set serially for now.
-
- int rx_hp, tx_antsel, rx_antsel, tx_pa_sel;
- if(d_rx_hp_pin)
- rx_hp = RX_HP;
- else
- rx_hp = 0;
-
- if(d_tx_ant)
- tx_antsel = ANTSEL_TX2_RX1;
- else
- tx_antsel = ANTSEL_TX1_RX2;
-
- if(d_rx_ant)
- rx_antsel = ANTSEL_TX2_RX1;
- else
- rx_antsel = ANTSEL_TX1_RX2;
-
- if(d_five_gig)
- tx_pa_sel = LB_PA_OFF;
- else
- tx_pa_sel = HB_PA_OFF;
-
- // Reset GPIO and ATR
- // FIXME: dont set io, oe, atr mask once basic code stops overriding our settings
- usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK);
- usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff);
- usrp()->common_write_atr_txval(C_TX, d_which, tx_pa_sel|tx_antsel|TX_EN|AD9515DIV);
- usrp()->common_write_atr_rxval(C_TX, d_which, HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV);
- usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK);
-
- usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK);
- usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff);
- usrp()->common_write_atr_txval(C_RX, d_which, EN|rx_hp);
- usrp()->common_write_atr_rxval(C_RX, d_which, EN|rx_hp|RX_EN);
- usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK);
-
- //printf("GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X\n",
- // io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx);
-}
-
-
-struct freq_result_t
-xcvr2450::set_freq(double target_freq)
-{
- struct freq_result_t args = {false, 0};
-
- double scaler;
-
- if(target_freq > 3e9) {
- d_five_gig = 1;
- d_ad9515_div = 3;
- scaler = 4.0/5.0;
- }
- else {
- d_five_gig = 0;
- d_ad9515_div = 3;
- scaler = 4.0/3.0;
- }
-
- if(target_freq > 5.408e9) {
- d_highband = 1;
- }
- else {
- d_highband = 0;
- }
-
- double vco_freq = target_freq*scaler;
- double sys_clk = usrp()->fpga_master_clock_freq(); // Usually 64e6
- double ref_clk = sys_clk / d_ad9515_div;
-
- double phdet_freq = ref_clk/d_ref_div;
- double div = vco_freq/phdet_freq;
- d_int_div = int(floor(div));
- d_frac_div = int((div-d_int_div)*65536.0);
- // double actual_freq = phdet_freq*(d_int_div+(d_frac_div/65536.0))/scaler;
-
- //printf("RF=%f VCO=%f R=%d PHD=%f DIV=%3.5f I=%3d F=%5d ACT=%f\n",
- // target_freq, vco_freq, d_ref_div, phdet_freq,
- // div, d_int_div, d_frac_div, actual_freq);
-
- set_gpio();
- set_reg_int_divider();
- set_reg_frac_divider();
- set_reg_bandselpll();
-
- args.ok = lock_detect();
-#ifdef NO_LO_OFFSET
- args.baseband_freq = target_freq;
-#else
- args.baseband_freq = actual_freq;
-#endif
-
- if(!args.ok){
- printf("Fail %f\n", target_freq);
- }
- return args;
-}
-
-bool
-xcvr2450::lock_detect()
-{
- /*
- @returns: the value of the VCO/PLL lock detect bit.
- @rtype: 0 or 1
- */
- if(usrp()->common_read_io(C_RX, d_which) & LOCKDET) {
- return true;
- }
- else { // Give it a second chance
- if(usrp()->common_read_io(C_RX, d_which) & LOCKDET)
- return true;
- else
- return false;
- }
-}
-
-bool
-xcvr2450::set_rx_gain(float gain)
-{
- if(gain < 0.0)
- gain = 0.0;
- if(gain > 92.0)
- gain = 92.0;
-
- // Split the gain between RF and baseband
- // This is experimental, not prescribed
- if(gain < 31.0) {
- d_rx_rf_gain = 0; // 0 dB RF gain
- rx_bb_gain = int(gain/2.0);
- }
-
- if(gain >= 30.0 and gain < 60.5) {
- d_rx_rf_gain = 2; // 15 dB RF gain
- d_rx_bb_gain = int((gain-15.0)/2.0);
- }
-
- if(gain >= 60.5) {
- d_rx_rf_gain = 3; // 30.5 dB RF gain
- d_rx_bb_gain = int((gain-30.5)/2.0);
- }
-
- set_reg_rxgain();
-
- return true;
-}
-
-bool
-xcvr2450::set_tx_gain(float gain)
-{
- if(gain < 0.0) {
- gain = 0.0;
- }
- if(gain > 30.0) {
- gain = 30.0;
- }
-
- d_txgain = int((gain/30.0)*63);
- set_reg_txgain();
-
- return true;
-}
-
-
-/*****************************************************************************/
-
-
-struct xcvr2450_table_entry {
- xcvr2450_key key;
- boost::weak_ptr<xcvr2450> value;
-
- xcvr2450_table_entry(const xcvr2450_key &_key, boost::weak_ptr<xcvr2450> _value)
- : key(_key), value(_value) {}
-};
-
-typedef std::vector<xcvr2450_table_entry> xcvr2450_table;
-
-static boost::mutex s_table_mutex;
-static xcvr2450_table s_table;
-
-static xcvr2450_sptr
-_get_or_make_xcvr2450(usrp_basic_sptr usrp, int which)
-{
- xcvr2450_key key = {usrp->serial_number(), which};
-
- boost::mutex::scoped_lock guard(s_table_mutex);
-
- for (xcvr2450_table::iterator p = s_table.begin(); p != s_table.end();){
- if (p->value.expired()) // weak pointer is now dead
- p = s_table.erase(p); // erase it
- else {
- if (key == p->key){ // found it
- return xcvr2450_sptr(p->value);
- }
- else
- ++p; // keep looking
- }
- }
-
- // We don't have the xcvr2450 we're looking for
-
- // create a new one and stick it in the table.
- xcvr2450_sptr r(new xcvr2450(usrp, which));
- xcvr2450_table_entry t(key, r);
- s_table.push_back(t);
-
- return r;
-}
-
-
-/*****************************************************************************/
-
-
-db_xcvr2450_base::db_xcvr2450_base(usrp_basic_sptr usrp, int which)
- : db_base(usrp, which)
-{
- /*
- * Abstract base class for all xcvr2450 boards.
- *
- * Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
- *
- * @param usrp: instance of usrp.source_c
- * @param which: which side: 0 or 1 corresponding to side A or B respectively
- * @type which: int
- */
-
- d_xcvr = _get_or_make_xcvr2450(usrp, which);
-}
-
-db_xcvr2450_base::~db_xcvr2450_base()
-{
-}
-
-void
-db_xcvr2450_base::shutdown_common()
-{
- // If the usrp_basic in the xcvr2450 is the same as the usrp_basic
- // in the daughterboard, shutdown the xcvr now (when only one of Tx
- // and Rx is open, this is always true).
-
- if (d_xcvr->usrp() == usrp()){
- //std::cerr << "db_xcvr2450_base::shutdown_common: same -> shutting down\n";
- d_xcvr->shutdown();
- }
- else {
- //std::cerr << "db_xcvr2450_base::shutdown_common: different -> ignoring\n";
- }
-}
-
-struct freq_result_t
-db_xcvr2450_base::set_freq(double target_freq)
-{
- /*
- * @returns (ok, actual_baseband_freq) where:
- * ok is True or False and indicates success or failure,
- * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
- */
- return d_xcvr->set_freq(target_freq+d_lo_offset);
-}
-
-bool
-db_xcvr2450_base::is_quadrature()
-{
- /*
- * Return True if this board requires both I & Q analog channels.
- *
- * This bit of info is useful when setting up the USRP Rx mux register.
- */
- return true;
-}
-
-double
-db_xcvr2450_base::freq_min()
-{
- return 2.4e9;
-}
-
-double
-db_xcvr2450_base::freq_max()
-{
- return 6.0e9;
-}
-
-
-/******************************************************************************/
-
-
-db_xcvr2450_tx::db_xcvr2450_tx(usrp_basic_sptr usrp, int which)
- : db_xcvr2450_base(usrp, which)
-{
- set_lo_offset(LO_OFFSET);
- //printf("db_xcvr2450_tx::db_xcvr2450_tx\n");
-}
-
-db_xcvr2450_tx::~db_xcvr2450_tx()
-{
- shutdown();
-}
-
-void
-db_xcvr2450_tx::shutdown()
-{
- if (!d_is_shutdown){
- d_is_shutdown = true;
- shutdown_common();
- }
-}
-
-float
-db_xcvr2450_tx::gain_min()
-{
- return 0;
-}
-
-float
-db_xcvr2450_tx::gain_max()
-{
- return 30;
-}
-
-float
-db_xcvr2450_tx::gain_db_per_step()
-{
- return (30.0/63.0);
-}
-
-bool
-db_xcvr2450_tx::set_gain(float gain)
-{
- return d_xcvr->set_tx_gain(gain);
-}
-
-bool
-db_xcvr2450_tx::i_and_q_swapped()
-{
- return true;
-}
-
-
-/******************************************************************************/
-
-
-db_xcvr2450_rx::db_xcvr2450_rx(usrp_basic_sptr usrp, int which)
- : db_xcvr2450_base(usrp, which)
-{
- /*
- * @param usrp: instance of usrp.source_c
- * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
- */
- set_lo_offset(LO_OFFSET);
- //printf("db_xcvr2450_rx:d_xcvr_2450_rx\n");
-}
-
-db_xcvr2450_rx::~db_xcvr2450_rx()
-{
- shutdown();
-}
-
-void
-db_xcvr2450_rx::shutdown()
-{
- if (!d_is_shutdown){
- d_is_shutdown = true;
- shutdown_common();
- }
-}
-
-float
-db_xcvr2450_rx::gain_min()
-{
- return 0.0;
-}
-
-float
-db_xcvr2450_rx::gain_max()
-{
- return 92.0;
-}
-
-float
-db_xcvr2450_rx::gain_db_per_step()
-{
- return 1;
-}
-
-bool
-db_xcvr2450_rx::set_gain(float gain)
-{
- return d_xcvr->set_rx_gain(gain);
-}
+++ /dev/null
-/* -*- c++ -*- */
-//
-// Copyright 2008,2009 Free Software Foundation, Inc.
-//
-// This file is part of GNU Radio
-//
-// GNU Radio is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either asversion 3, or (at your option)
-// any later version.
-//
-// GNU Radio is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with GNU Radio; see the file COPYING. If not, write to
-// the Free Software Foundation, Inc., 51 Franklin Street,
-// Boston, MA 02110-1301, USA.
-
-#ifndef DB_XCVR2450_H
-#define DB_XCVR2450_H
-
-#include <db_base.h>
-#include <boost/shared_ptr.hpp>
-
-class xcvr2450;
-typedef boost::shared_ptr<xcvr2450> xcvr2450_sptr;
-
-
-/******************************************************************************/
-
-
-class db_xcvr2450_base: public db_base
-{
- /*
- * Abstract base class for all xcvr2450 boards.
- *
- * Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
- */
-public:
- db_xcvr2450_base(usrp_basic_sptr usrp, int which);
- ~db_xcvr2450_base();
- struct freq_result_t set_freq(double target_freq);
- bool is_quadrature();
- double freq_min();
- double freq_max();
-
-protected:
- xcvr2450_sptr d_xcvr;
- void shutdown_common();
-};
-
-
-/******************************************************************************/
-
-
-class db_xcvr2450_tx : public db_xcvr2450_base
-{
-protected:
- void shutdown();
-
-public:
- db_xcvr2450_tx(usrp_basic_sptr usrp, int which);
- ~db_xcvr2450_tx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool set_gain(float gain);
- bool i_and_q_swapped();
-};
-
-class db_xcvr2450_rx : public db_xcvr2450_base
-{
-protected:
- void shutdown();
-
-public:
- db_xcvr2450_rx(usrp_basic_sptr usrp, int which);
- ~db_xcvr2450_rx();
-
- float gain_min();
- float gain_max();
- float gain_db_per_step();
- bool set_gain(float gain);
-};
-
-
-
-#endif
+++ /dev/null
-#!/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 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-
-import sys
-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
-
-
-
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <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
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-// 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 in bytes (hard limit).
- */
- static int max_block_size ();
-
- /*!
- * \brief Returns default block size in bytes.
- */
- static int default_block_size ();
-
- /*!
- * \brief Returns the default buffer size in bytes.
- */
- static int default_buffer_size ();
-
-};
-
-#endif /* _FUSB_H_ */
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-// tell mld_threads to NOT use omni_threads,
-// but rather Darwin's pthreads
-#define _USE_OMNI_THREADS_
-#define DO_DEBUG 0
-
-#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;
-
- // lock the runBlock mutex, before creating the run thread.
- // this guarantees that we can control execution between these 2 threads
- d_runBlock->mutex ()->lock ();
-
- // create the run thread, which allows OSX to process I/O separately
- d_runThread = new mld_thread (run_thread, this);
-
- // wait until the run thread (and possibky read thread) are -really-
- // going; this will unlock the mutex before waiting for a signal ()
- 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);
-
- // lock the run thread running mutex; if ::stop() is called, it will
- // first abort() the pipe then wait for the run thread to finish,
- // via a lock() on this mutex
- 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;
- mld_mutex_ptr l_readBlock_mutex = l_readBlock->mutex ();
-
- 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) {
- // lock the readBlock mutex, before creating the read thread.
- // this guarantees that we can control execution between these 2 threads
- l_readBlock_mutex->lock ();
- // create the read thread, which just issues all of the starting
- // async read commands, then returns
- l_rwThread = new mld_thread (read_thread, arg);
- // wait until the the read thread is -really- going; this will
- // unlock the read block mutex before waiting for a signal ()
- l_readBlock->wait ();
- }
-
- // now signal the run condition to release and finish ::start().
-
- // lock the runBlock mutex first; this will force waiting until the
- // ->wait() command is issued in ::start()
- mld_mutex_ptr l_run_block_mutex = This->d_runBlock->mutex ();
- l_run_block_mutex->lock ();
-
- // now that the lock is in place, signal the parent thread that
- // things are running
- This->d_runBlock->signal ();
-
- // release the run_block mutex, just in case
- l_run_block_mutex->unlock ();
-
- // run the loop
- CFRunLoopRun ();
-
- if (l_input_p) {
- // wait for read_thread () to finish, if needed
- 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");
-
- // release the run thread running mutex
- 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);
-
- // before doing anything else, lock the read running mutex. this
- // mutex does flow control between this thread and the run_thread
- mld_mutex_ptr l_readRunning = This->d_readRunning;
- l_readRunning->lock ();
-
- // signal the read condition from run_thread() to continue
-
- // lock the readBlock mutex first; this will force waiting until the
- // ->wait() command is issued in ::run_thread()
- mld_condition_ptr l_readBlock = This->d_readBlock;
- mld_mutex_ptr l_read_block_mutex = l_readBlock->mutex ();
- l_read_block_mutex->lock ();
-
- // now that the lock is in place, signal the parent thread that
- // things are running here
- l_readBlock->signal ();
-
- // release the run_block mutex, just in case
- l_read_block_mutex->unlock ();
-
- // queue up all of the available read requests
- 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");
-
- // release the read running mutex, to let the parent thread knows
- // that this thread is finished
- l_readRunning->unlock ();
-}
-
-void
-fusb_ephandle_darwin::read_issue (s_both_ptr l_both)
-{
- if ((! l_both) || (! d_started)) {
- if (usb_debug > 4)
- fprintf (stderr, "fusb_ephandle_darwin::read_issue: Doing nothing; "
- "l_both is %X; started is %s\n", (unsigned int) l_both,
- d_started ? "TRUE" : "FALSE");
- 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));
- else if (usb_debug > 4)
- fprintf (stderr, "fusb_ephandle_darwin::read_issue: "
- "Queued %X (%ld Bytes)\n", (unsigned int) l_both, bufLen);
-}
-
-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);
- else if (usb_debug > 4)
- fprintf (stderr, "fusb_ephandle_darwin::read_completed: "
- "Read %X (%ld bytes)\n",
- (unsigned int) l_both, 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);
-
- if (usb_debug > 4)
- fprintf (stderr, "fusb_ephandle_darwin::read: request for %d bytes, %ld bytes retrieved.\n", nbytes, l_nbytes);
-
- return ((int) l_nbytes);
-}
-
-int
-fusb_ephandle_darwin::write (const void* buffer, int nbytes)
-{
- UInt32 l_nbytes = (UInt32) nbytes;
-
- if (! d_started) {
- if (usb_debug)
- fprintf (stderr, "fusb_ephandle_darwin::write: Not yet started.\n");
-
- 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, t_nbytes,
- (IOAsyncCallback1) write_completed, (void*) l_both);
- else
- result = d_interface->WritePipeAsyncTO
- (d_interfaceRef, d_pipeRef, v_buffer, t_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));
- else if (usb_debug > 4) {
- fprintf (stderr, "fusb_ephandle_darwin::write_thread: "
- "Queued %X (%ld Bytes)\n", (unsigned int) l_both, t_nbytes);
- }
- 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);
- else if (usb_debug > 4)
- fprintf (stderr, "fusb_ephandle_darwin::write_completed: "
- "Wrote %X (%ld Bytes)\n", (unsigned int) l_both, 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);
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _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_ */
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <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);
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _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_ */
-
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <fusb_linux.h>
-#include <usb.h> // libusb header
-#include <stdexcept>
-#ifdef HAVE_LINUX_COMPILER_H
-#include <linux/compiler.h>
-#endif
-#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>
-#include <cstdio>
-
-#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 or an unrecoverable error occurs.
- */
-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 ())
- if (!_reap(true))
- break;
-}
-\f// ------------------------------------------------------------------------
-// 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;
-
- 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;
- }
-
- d_devhandle->_cancel_pending_rqsts (this);
- d_devhandle->_reap (false);
-
- while (1){
- usbdevfs_urb *urb;
- while ((urb = completed_list_get ()) != 0)
- free_list_add (urb);
-
- if (d_free_list.size () == (unsigned) d_nblocks)
- break;
-
- if (!d_devhandle->_reap(true))
- break;
- }
-
- 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();
- if (!urb)
- return -1;
- 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 ();
- if (!urb)
- return -1;
- 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.
-
- if (!d_devhandle->_reap (true))
- return 0;
- }
-}
-
-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)
- if (!d_devhandle->_reap (true))
- return false;
-
- // check result of completed read
-
- if (urb->status != 0){
- // We've got a problem. Report it and fail.
- fprintf (stderr, "fusb: (rd status %d) %s\n", urb->status, strerror (-urb->status));
- urb->actual_length = 0;
- free_list_add (urb);
- return false;
- }
-
- // 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;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-// 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 ();
-};
-
-\f/*!
- * \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_ */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <fusb_ra_wb.h>
-#include <usb.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-
-#include <sys/event.h>
-#include <dev/usb/usb.h>
-
-static const int USB_TIMEOUT = 1000; // in milliseconds
-
-// the following comment and function is from fusb_linux.cc
-#if 0
-// 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);
-}
-#endif
-
-// the control endpoint doesn't actually do us any good so here is a
-// new "fragile extraction"
-static int
-ep_fd_from_usb_dev_handle (usb_dev_handle *udh, int endpoint)
-{
- struct usb_dev_handle_kludge2 { // see also usrp_prims.cc
- int fd;
- struct usb_bus *bus;
- struct usb_device *device;
- int config;
- int interface;
- int altsetting;
- void *impl_info;
- };
- struct bsd_usb_dev_handle_info_kludge {
- int ep_fd[USB_MAX_ENDPOINTS];
- };
- struct bsd_usb_dev_handle_info_kludge *info
- = (struct bsd_usb_dev_handle_info_kludge *)
- ((struct usb_dev_handle_kludge2 *)udh)->impl_info;
- return info->ep_fd[UE_GET_ADDR(endpoint)];
-}
-
-
-fusb_devhandle_ra_wb::fusb_devhandle_ra_wb (usb_dev_handle *udh)
- : fusb_devhandle (udh)
-{
- // that's it
-}
-
-fusb_devhandle_ra_wb::~fusb_devhandle_ra_wb ()
-{
- // nop
-}
-
-fusb_ephandle *
-fusb_devhandle_ra_wb::make_ephandle (int endpoint, bool input_p,
- int block_size, int nblocks)
-{
- return new fusb_ephandle_ra_wb (this, endpoint, input_p,
- block_size, nblocks);
-}
-
-// ----------------------------------------------------------------
-
-fusb_ephandle_ra_wb::fusb_ephandle_ra_wb (fusb_devhandle_ra_wb *dh,
- int endpoint, bool input_p,
- int block_size, int nblocks)
- : fusb_ephandle (endpoint, input_p, block_size, nblocks),
- d_devhandle (dh), d_ra_wb_on (false)
-{
- // that's it
-}
-
-fusb_ephandle_ra_wb::~fusb_ephandle_ra_wb ()
-{
- // nop
-}
-
-bool
-fusb_ephandle_ra_wb::start ()
-{
- d_started = true;
-
- char buf = '\0';
- int fd;
-
- // this is to cause libusb to open the endpoint
- if (!d_input_p) {
- write(&buf, 0);
- fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
- d_endpoint);
- }
- else {
- read(&buf, 0);
- fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
- d_endpoint|USB_ENDPOINT_IN);
- }
-
- // enable read ahead/write behind
- int ret;
- struct usb_bulk_ra_wb_opt opts;
- int enable = 1;
-
- opts.ra_wb_buffer_size = d_block_size*d_nblocks;
- opts.ra_wb_request_size = d_block_size;
-// fprintf (stderr, "setting buffer size to %d, request size to %d\n",
-// opts.ra_wb_buffer_size, opts.ra_wb_request_size);
- if (!d_input_p) {
- ret = ioctl (fd, USB_SET_BULK_WB_OPT, &opts);
- if (ret < 0)
- fprintf (stderr, "USB_SET_BULK_WB_OPT: %s\n", strerror(errno));
- else {
- ret = ioctl (fd, USB_SET_BULK_WB, &enable);
- if (ret < 0)
- fprintf (stderr, "USB_SET_BULK_WB: %s\n", strerror(errno));
- else
- d_ra_wb_on = true;
- }
- }
- else {
- ret = ioctl (fd, USB_SET_BULK_RA_OPT, &opts);
- if (ret < 0)
- fprintf (stderr, "USB_SET_BULK_RA_OPT: %s\n", strerror(errno));
- else {
- ret = ioctl (fd, USB_SET_BULK_RA, &enable);
- if (ret < 0)
- fprintf (stderr, "USB_SET_BULK_RA: %s\n", strerror(errno));
- else
- d_ra_wb_on = true;
- }
- }
-
- return true;
-}
-
-bool
-fusb_ephandle_ra_wb::stop ()
-{
- int fd;
- int ret;
- int enable = 0;
- if (d_ra_wb_on) {
- if (!d_input_p) {
- fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
- d_endpoint);
- ret = ioctl (fd, USB_SET_BULK_WB, &enable);
- if (ret < 0)
- fprintf (stderr, "USB_SET_BULK_WB: %s\n", strerror(errno));
- else
- d_ra_wb_on = false;
- }
- else {
- fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
- d_endpoint|USB_ENDPOINT_IN);
- ret = ioctl (fd, USB_SET_BULK_RA, &enable);
- if (ret < 0)
- fprintf (stderr, "USB_SET_BULK_RA: %s\n", strerror(errno));
- else
- d_ra_wb_on = false;
- }
- }
-
- d_started = false;
- return true;
-}
-
-int
-fusb_ephandle_ra_wb::write (const void *buffer, int nbytes)
-{
- if (!d_started)
- 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_ra_wb::read (void *buffer, int nbytes)
-{
- if (!d_started)
- 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);
-}
-
-void
-fusb_ephandle_ra_wb::wait_for_completion ()
-{
- // as the driver is implemented this only makes sense for write
- if (d_ra_wb_on && !d_input_p) {
- int fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
- d_endpoint);
- int kq = kqueue();
- if (kq < 0)
- return;
- struct kevent evt;
- int nevents;
- EV_SET (&evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0/*NULL*/);
- nevents = kevent (kq, &evt, 1, &evt, 1, NULL);
- if (nevents < 1) {
- close(kq);
- return;
- }
- while (!(evt.flags & EV_ERROR) && evt.data < (d_block_size*d_nblocks)) {
- // it's a busy loop, but that's all I can do at the moment
- nevents = kevent (kq, NULL, 0, &evt, 1, NULL);
- // let's see if this improves the test_usrp_standard_tx throughput &
- // "CPU usage" by looping less frequently
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 1000; // 1 ms
- select (0, NULL, NULL, NULL, &timeout);
- }
- close (kq);
- }
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _FUSB_RA_WB_H_
-#define _FUSB_RA_WB_H_
-
-#include <fusb.h>
-
-/*!
- * \brief generic implementation of fusb_devhandle using only libusb
- */
-class fusb_devhandle_ra_wb : public fusb_devhandle
-{
-public:
- // CREATORS
- fusb_devhandle_ra_wb (usb_dev_handle *udh);
- virtual ~fusb_devhandle_ra_wb ();
-
- // 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_ra_wb : public fusb_ephandle
-{
-private:
- fusb_devhandle_ra_wb *d_devhandle;
- bool d_ra_wb_on;
-
-public:
- // CREATORS
- fusb_ephandle_ra_wb (fusb_devhandle_ra_wb *dh, int endpoint, bool input_p,
- int block_size = 0, int nblocks = 0);
- virtual ~fusb_ephandle_ra_wb ();
-
- // 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_RA_WB_H_ */
-
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <fusb.h>
-#include <fusb_darwin.h>
-
-static const int MAX_BLOCK_SIZE = 32 * 1024; // hard limit
-static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB
-
-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;
-}
-
-int fusb_sysconfig::default_block_size ()
-{
- return fusb_sysconfig::max_block_size ();
-}
-
-int fusb_sysconfig::default_buffer_size ()
-{
- return FUSB_BUFFER_SIZE;
-}
-
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <fusb.h>
-#include <fusb_generic.h>
-
-static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
-static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB
-
-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;
-}
-
-int fusb_sysconfig::default_block_size ()
-{
- return fusb_sysconfig::max_block_size ();
-}
-
-int fusb_sysconfig::default_buffer_size ()
-{
- return FUSB_BUFFER_SIZE;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <fusb.h>
-#include <fusb_linux.h>
-
-static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
-static const int DEFAULT_BLOCK_SIZE = 4 * 1024; // fewer kernel memory problems
-static const int FUSB_BUFFER_SIZE = 1 * (1L << 20); // 1MB
-
-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;
-}
-
-int fusb_sysconfig::default_block_size ()
-{
- return DEFAULT_BLOCK_SIZE;
-}
-
-int fusb_sysconfig::default_buffer_size ()
-{
- return FUSB_BUFFER_SIZE;
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <fusb.h>
-#include <fusb_ra_wb.h>
-
-//static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
-// there's no hard limit, even before making any changes to the driver
-// 64k is empirically a pretty good number
-static const int MAX_BLOCK_SIZE = 64 * 1024;
-// there is a limit of 1 MB in the driver for the buffer size
-static const int FUSB_BUFFER_SIZE = 256 * (1L << 10); // 256 kB
-
-fusb_devhandle *
-fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
-{
- return new fusb_devhandle_ra_wb (udh);
-}
-
-int fusb_sysconfig::max_block_size ()
-{
- return MAX_BLOCK_SIZE;
-}
-
-int fusb_sysconfig::default_block_size ()
-{
- return fusb_sysconfig::max_block_size ();
-}
-
-int fusb_sysconfig::default_buffer_size ()
-{
- return FUSB_BUFFER_SIZE;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <fusb.h>
-#include <fusb_win32.h>
-
-static const int MAX_BLOCK_SIZE = 64 * 1024; // Windows kernel hard limit
-static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB
-
-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;
-}
-
-int fusb_sysconfig::default_block_size ()
-{
- return fusb_sysconfig::max_block_size ();
-}
-
-int fusb_sysconfig::default_buffer_size ()
-{
- return FUSB_BUFFER_SIZE;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <fusb_win32.h>
-#include <usb.h>
-#include <assert.h>
-#include <stdexcept>
-#include <string.h>
-
-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);
- }
-
- while (bytes_to_write > 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;
- }
- }
-
- int ncopy = std::min(bytes_to_write, d_block_size);
- memcpy(buf, (void *) &(((char*)buffer)[a]), ncopy);
- bytes_to_write -= ncopy;
- a += ncopy;
-
- d_output_short = d_block_size - ncopy;
- 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);
- }
-
- while (bytes_to_read > 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());
-
- int ncopy = std::min(bytes_to_read, d_block_size);
- memcpy((void *) &(((char*)buffer)[a]), buf, ncopy);
- bytes_to_read -= ncopy;
- a += ncopy;
-
- d_input_leftover = d_block_size - ncopy;
- 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;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _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_ */
-
+++ /dev/null
-#!/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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <usrp_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()
+++ /dev/null
-/* 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 3, 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., 51 Franklin Street, Boston, MA 02110-1301, 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;
-}
+++ /dev/null
-/* 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 3, 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., 51 Franklin Street, Boston, MA 02110-1301, 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
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _INCLUDED_MLD_THREADS_H_
-#define _INCLUDED_MLD_THREADS_H_
-
-/* classes which allow for either pthreads or omni_threads */
-
-#define __macos__
-#ifdef _USE_OMNI_THREADS_
-#include <gnuradio/omnithread.h>
-#else
-#include <pthread.h>
-#endif
-
-#include <stdexcept>
-
-#define __INLINE__ inline
-
-#ifndef DO_DEBUG
-#define DO_DEBUG 0
-#endif
-
-#if DO_DEBUG
-#define DEBUG(X) do{X} while(0);
-#else
-#define DEBUG(X) do{} while(0);
-#endif
-
-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_i_own_mutex;
-
-public:
- __INLINE__ mld_condition_t (mld_mutex_ptr mutex = NULL) {
- if (mutex) {
- d_i_own_mutex = false;
- d_mutex = mutex;
- } else {
- d_i_own_mutex = true;
- 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;
- if (d_i_own_mutex)
- delete d_mutex;
- d_mutex = NULL;
- };
-
- __INLINE__ mld_mutex_ptr mutex () {return (d_mutex);};
-
- __INLINE__ void signal () {
- DEBUG (fprintf (stderr, "a "););
-
-#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
- DEBUG (fprintf (stderr, "b "););
- };
-
- __INLINE__ void wait () {
- DEBUG (fprintf (stderr, "c "););
-#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
- DEBUG (fprintf (stderr, "d "););
- };
-};
-
-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_ */
+++ /dev/null
- { 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 }
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-static const char *std_paths[] = {
- "@prefix@/share/usrp",
- "/usr/local/share/usrp",
- 0
-};
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2004,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "usrp_basic.h"
-#include "usrp_prims.h"
-#include "usrp_interfaces.h"
-#include "fpga_regs_common.h"
-#include "fpga_regs_standard.h"
-#include "fusb.h"
-#include "db_boards.h"
-#include <usb.h>
-#include <stdexcept>
-#include <assert.h>
-#include <math.h>
-#include <ad9862.h>
-#include <string.h>
-#include <cstdio>
-
-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 = fusb_sysconfig::default_buffer_size();
-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), d_fpga_master_clock_freq(64000000), d_db(2)
-{
- /*
- * 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
-}
-
-void
-usrp_basic::shutdown_daughterboards()
-{
- // nuke d'boards before we close down USB in ~usrp_basic
- // shutdown() will do any board shutdown while the USRP can still
- // be talked to
- for(size_t i = 0; i < d_db.size(); i++)
- for(size_t j = 0; j < d_db[i].size(); j++)
- d_db[i][j]->shutdown();
-}
-
-usrp_basic::~usrp_basic ()
-{
- // shutdown_daughterboards(); // call from ~usrp_basic_{tx,rx}
-
- d_db.resize(0); // forget db shared ptrs
-
- if (d_udh)
- usb_close (d_udh);
-}
-
-void
-usrp_basic::init_db(usrp_basic_sptr u)
-{
- if (u.get() != this)
- throw std::invalid_argument("u is not this");
-
- d_db[0] = instantiate_dbs(d_dbid[0], u, 0);
- d_db[1] = instantiate_dbs(d_dbid[1], u, 1);
-}
-
-std::vector<db_base_sptr>
-usrp_basic::db(int which_side)
-{
- which_side &= 0x1; // clamp it to avoid any reporting any errors
- return d_db[which_side];
-}
-
-bool
-usrp_basic::is_valid(const usrp_subdev_spec &ss)
-{
- if (ss.side < 0 || ss.side > 1)
- return false;
-
- if (ss.subdev < 0 || ss.subdev >= d_db[ss.side].size())
- return false;
-
- return true;
-}
-
-db_base_sptr
-usrp_basic::selected_subdev(const usrp_subdev_spec &ss)
-{
- if (!is_valid(ss))
- throw std::invalid_argument("invalid subdev_spec");
-
- return d_db[ss.side][ss.subdev];
-}
-
-bool
-usrp_basic::start ()
-{
- 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_adc, int offset)
-{
- if (which_adc < 0 || which_adc > 3)
- return false;
-
- return _write_fpga_reg (FR_ADC_OFFSET_0 + which_adc, offset);
-}
-
-bool
-usrp_basic::set_dac_offset (int which_dac, int offset, int offset_pin)
-{
- if (which_dac < 0 || which_dac > 3)
- return false;
-
- int which_codec = which_dac >> 1;
- int tx_a = (which_dac & 0x1) == 0;
- int lo = ((offset & 0x3) << 6) | (offset_pin & 0x1);
- int hi = (offset >> 2);
- bool ok;
-
- 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_adc, bool bypass)
-{
- if (which_adc < 0 || which_adc > 3)
- return false;
-
- int codec = which_adc >> 1;
- int reg = (which_adc & 1) == 0 ? REG_RX_A : REG_RX_B;
-
- unsigned char cur_rx;
- unsigned char cur_pwr_dn;
-
- // 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_adc & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B;
- }
- else {
- cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER;
- cur_pwr_dn &= ~(((which_adc & 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::set_dc_offset_cl_enable(int bits, int mask)
-{
- return _write_fpga_reg(FR_DC_OFFSET_CL_EN,
- (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & mask));
-}
-
-// ----------------------------------------------------------------
-
-bool
-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_led, bool on)
-{
- return usrp_set_led (d_udh, which_led, on);
-}
-
-bool
-usrp_basic::write_atr_tx_delay(int value)
-{
- return _write_fpga_reg(FR_ATR_TX_DELAY, value);
-}
-
-bool
-usrp_basic::write_atr_rx_delay(int value)
-{
- return _write_fpga_reg(FR_ATR_RX_DELAY, value);
-}
-
-/*
- * ----------------------------------------------------------------
- * Routines to access and control daughterboard specific i/o
- * ----------------------------------------------------------------
- */
-static int
-slot_id_to_oe_reg (int slot_id)
-{
- static int reg[4] = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 };
- assert (0 <= slot_id && slot_id < 4);
- return reg[slot_id];
-}
-
-static int
-slot_id_to_io_reg (int slot_id)
-{
- static int reg[4] = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 };
- assert (0 <= slot_id && slot_id < 4);
- return reg[slot_id];
-}
-
-static int
-slot_id_to_refclk_reg(int slot_id)
-{
- static int reg[4] = { FR_TX_A_REFCLK, FR_RX_A_REFCLK, FR_TX_B_REFCLK, FR_RX_B_REFCLK };
- assert (0 <= slot_id && slot_id < 4);
- return reg[slot_id];
-}
-
-static int
-slot_id_to_atr_mask_reg(int slot_id)
-{
- static int reg[4] = { FR_ATR_MASK_0, FR_ATR_MASK_1, FR_ATR_MASK_2, FR_ATR_MASK_3 };
- assert (0 <= slot_id && slot_id < 4);
- return reg[slot_id];
-}
-
-static int
-slot_id_to_atr_txval_reg(int slot_id)
-{
- static int reg[4] = { FR_ATR_TXVAL_0, FR_ATR_TXVAL_1, FR_ATR_TXVAL_2, FR_ATR_TXVAL_3 };
- assert (0 <= slot_id && slot_id < 4);
- return reg[slot_id];
-}
-
-static int
-slot_id_to_atr_rxval_reg(int slot_id)
-{
- static int reg[4] = { FR_ATR_RXVAL_0, FR_ATR_RXVAL_1, FR_ATR_RXVAL_2, FR_ATR_RXVAL_3 };
- assert (0 <= slot_id && slot_id < 4);
- return reg[slot_id];
-}
-
-static int
-to_slot(txrx_t txrx, int which_side)
-{
- // TX_A = 0
- // RX_A = 1
- // TX_B = 2
- // RX_B = 3
- return ((which_side & 0x1) << 1) | ((txrx & 0x1) == C_RX);
-}
-
-bool
-usrp_basic::common_set_pga(txrx_t txrx, int which_amp, double gain)
-{
- if (which_amp < 0 || which_amp > 3)
- return false;
-
- gain = std::min(common_pga_max(txrx),
- std::max(common_pga_min(txrx), gain));
-
- int codec = which_amp >> 1;
- int int_gain = (int) rint((gain - common_pga_min(txrx)) / common_pga_db_per_step(txrx));
-
- if (txrx == C_TX){ // 0 and 1 are same, as are 2 and 3
- return _write_9862(codec, REG_TX_PGA, int_gain);
- }
- else {
- int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B;
-
- // read current value to get input buffer bypass flag.
- unsigned char cur_rx;
- if (!_read_9862(codec, reg, &cur_rx))
- return false;
-
- cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
- return _write_9862(codec, reg, cur_rx);
- }
-}
-
-double
-usrp_basic::common_pga(txrx_t txrx, int which_amp) const
-{
- if (which_amp < 0 || which_amp > 3)
- return READ_FAILED;
-
- if (txrx == C_TX){
- int codec = which_amp >> 1;
- unsigned char v;
- bool ok = _read_9862 (codec, REG_TX_PGA, &v);
- if (!ok)
- return READ_FAILED;
-
- return (pga_db_per_step() * v) + pga_min();
- }
- else {
- int codec = which_amp >> 1;
- int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B;
- unsigned char v;
- bool ok = _read_9862 (codec, reg, &v);
- if (!ok)
- return READ_FAILED;
-
- return (pga_db_per_step() * (v & 0x1f)) + pga_min();
- }
-}
-
-double
-usrp_basic::common_pga_min(txrx_t txrx) const
-{
- if (txrx == C_TX)
- return -20.0;
- else
- return 0.0;
-}
-
-double
-usrp_basic::common_pga_max(txrx_t txrx) const
-{
- if (txrx == C_TX)
- return 0.0;
- else
- return 20.0;
-}
-
-double
-usrp_basic::common_pga_db_per_step(txrx_t txrx) const
-{
- if (txrx == C_TX)
- return 20.0 / 255;
- else
- return 20.0 / 20;
-}
-
-bool
-usrp_basic::_common_write_oe(txrx_t txrx, int which_side, int value, int mask)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- return _write_fpga_reg(slot_id_to_oe_reg(to_slot(txrx, which_side)),
- (mask << 16) | (value & 0xffff));
-}
-
-bool
-usrp_basic::common_write_io(txrx_t txrx, int which_side, int value, int mask)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- return _write_fpga_reg(slot_id_to_io_reg(to_slot(txrx, which_side)),
- (mask << 16) | (value & 0xffff));
-}
-
-bool
-usrp_basic::common_read_io(txrx_t txrx, int which_side, int *value)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- int t;
- int reg = which_side + 1; // FIXME, *very* magic number (fix in serial_io.v)
- bool ok = _read_fpga_reg(reg, &t);
- if (!ok)
- return false;
-
- if (txrx == C_TX){
- *value = t & 0xffff; // FIXME, more magic
- return true;
- }
- else {
- *value = (t >> 16) & 0xffff; // FIXME, more magic
- return true;
- }
-}
-
-int
-usrp_basic::common_read_io(txrx_t txrx, int which_side)
-{
- int value;
- if (!common_read_io(txrx, which_side, &value))
- return READ_FAILED;
- return value;
-}
-
-bool
-usrp_basic::common_write_refclk(txrx_t txrx, int which_side, int value)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- return _write_fpga_reg(slot_id_to_refclk_reg(to_slot(txrx, which_side)),
- value);
-}
-
-bool
-usrp_basic::common_write_atr_mask(txrx_t txrx, int which_side, int value)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- return _write_fpga_reg(slot_id_to_atr_mask_reg(to_slot(txrx, which_side)),
- value);
-}
-
-bool
-usrp_basic::common_write_atr_txval(txrx_t txrx, int which_side, int value)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- return _write_fpga_reg(slot_id_to_atr_txval_reg(to_slot(txrx, which_side)),
- value);
-}
-
-bool
-usrp_basic::common_write_atr_rxval(txrx_t txrx, int which_side, int value)
-{
- if (! (0 <= which_side && which_side <= 1))
- return false;
-
- return _write_fpga_reg(slot_id_to_atr_rxval_reg(to_slot(txrx, which_side)),
- value);
-}
-
-bool
-usrp_basic::common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value)
-{
- return _write_aux_dac(to_slot(txrx, which_side), which_dac, value);
-}
-
-bool
-usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value)
-{
- return _read_aux_adc(to_slot(txrx, which_side), which_adc, value);
-}
-
-int
-usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc)
-{
- return _read_aux_adc(to_slot(txrx, which_side), which_adc);
-}
-
-
-////////////////////////////////////////////////////////////////
-//
-// usrp_basic_rx
-//
-////////////////////////////////////////////////////////////////
-
-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);
-
- //d_db[0] = instantiate_dbs(d_dbid[0], this, 0);
- //d_db[1] = instantiate_dbs(d_dbid[1], this, 1);
-
- // check fusb buffering parameters
-
- if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
- 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_sysconfig::default_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_atr_mask(0, 0); // zero Rx A Auto Transmit/Receive regs
- write_atr_txval(0, 0);
- write_atr_rxval(0, 0);
- write_atr_mask(1, 0); // zero Rx B Auto Transmit/Receive regs
- write_atr_txval(1, 0);
- write_atr_rxval(1, 0);
-}
-
-static unsigned char rx_fini_regs[] = {
- 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");
- }
-
- shutdown_daughterboards();
-}
-
-
-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 (!set_rx_enable(false)){
- fprintf (stderr, "usrp_basic_rx: set_rx_enable(false) failed\n");
- usb_strerror ();
- ok = false;
- }
-
- if (!d_ephandle->stop()){
- fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming");
- usb_strerror ();
- ok = false;
- }
-
- return ok;
-}
-
-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);
-}
-
-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::set_pga (int which_amp, double gain)
-{
- return common_set_pga(C_RX, which_amp, gain);
-}
-
-double
-usrp_basic_rx::pga(int which_amp) const
-{
- return common_pga(C_RX, which_amp);
-}
-
-double
-usrp_basic_rx::pga_min() const
-{
- return common_pga_min(C_RX);
-}
-
-double
-usrp_basic_rx::pga_max() const
-{
- return common_pga_max(C_RX);
-}
-
-double
-usrp_basic_rx::pga_db_per_step() const
-{
- return common_pga_db_per_step(C_RX);
-}
-
-bool
-usrp_basic_rx::_write_oe (int which_side, int value, int mask)
-{
- return _common_write_oe(C_RX, which_side, value, mask);
-}
-
-bool
-usrp_basic_rx::write_io (int which_side, int value, int mask)
-{
- return common_write_io(C_RX, which_side, value, mask);
-}
-
-bool
-usrp_basic_rx::read_io (int which_side, int *value)
-{
- return common_read_io(C_RX, which_side, value);
-}
-
-int
-usrp_basic_rx::read_io (int which_side)
-{
- return common_read_io(C_RX, which_side);
-}
-
-bool
-usrp_basic_rx::write_refclk(int which_side, int value)
-{
- return common_write_refclk(C_RX, which_side, value);
-}
-
-bool
-usrp_basic_rx::write_atr_mask(int which_side, int value)
-{
- return common_write_atr_mask(C_RX, which_side, value);
-}
-
-bool
-usrp_basic_rx::write_atr_txval(int which_side, int value)
-{
- return common_write_atr_txval(C_RX, which_side, value);
-}
-
-bool
-usrp_basic_rx::write_atr_rxval(int which_side, int value)
-{
- return common_write_atr_rxval(C_RX, which_side, value);
-}
-
-bool
-usrp_basic_rx::write_aux_dac (int which_side, int which_dac, int value)
-{
- return common_write_aux_dac(C_RX, which_side, which_dac, value);
-}
-
-bool
-usrp_basic_rx::read_aux_adc (int which_side, int which_adc, int *value)
-{
- return common_read_aux_adc(C_RX, which_side, which_adc, value);
-}
-
-int
-usrp_basic_rx::read_aux_adc (int which_side, int which_adc)
-{
- return common_read_aux_adc(C_RX, which_side, which_adc);
-}
-
-int
-usrp_basic_rx::block_size () const { return d_ephandle->block_size(); }
-
-////////////////////////////////////////////////////////////////
-//
-// usrp_basic_tx
-//
-////////////////////////////////////////////////////////////////
-
-
-//
-// 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);
-
- //d_db[0] = instantiate_dbs(d_dbid[0], this, 0);
- //d_db[1] = instantiate_dbs(d_dbid[1], this, 1);
-
- // check fusb buffering parameters
-
- if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
- 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_atr_mask(0, 0); // zero Tx A Auto Transmit/Receive regs
- write_atr_txval(0, 0);
- write_atr_rxval(0, 0);
- write_atr_mask(1, 0); // zero Tx B Auto Transmit/Receive regs
- write_atr_txval(1, 0);
- write_atr_rxval(1, 0);
-}
-
-
-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");
- }
-
- shutdown_daughterboards();
-}
-
-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 (!d_ephandle->stop ()){
- fprintf (stderr, "usrp_basic_tx: failed to stop end point streaming");
- usb_strerror ();
- ok = false;
- }
-
- if (!set_tx_enable (false)){
- fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n");
- 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);
-}
-
-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::set_pga (int which_amp, double gain)
-{
- return common_set_pga(C_TX, which_amp, gain);
-}
-
-double
-usrp_basic_tx::pga (int which_amp) const
-{
- return common_pga(C_TX, which_amp);
-}
-
-double
-usrp_basic_tx::pga_min() const
-{
- return common_pga_min(C_TX);
-}
-
-double
-usrp_basic_tx::pga_max() const
-{
- return common_pga_max(C_TX);
-}
-
-double
-usrp_basic_tx::pga_db_per_step() const
-{
- return common_pga_db_per_step(C_TX);
-}
-
-bool
-usrp_basic_tx::_write_oe (int which_side, int value, int mask)
-{
- return _common_write_oe(C_TX, which_side, value, mask);
-}
-
-bool
-usrp_basic_tx::write_io (int which_side, int value, int mask)
-{
- return common_write_io(C_TX, which_side, value, mask);
-}
-
-bool
-usrp_basic_tx::read_io (int which_side, int *value)
-{
- return common_read_io(C_TX, which_side, value);
-}
-
-int
-usrp_basic_tx::read_io (int which_side)
-{
- return common_read_io(C_TX, which_side);
-}
-
-bool
-usrp_basic_tx::write_refclk(int which_side, int value)
-{
- return common_write_refclk(C_TX, which_side, value);
-}
-
-bool
-usrp_basic_tx::write_atr_mask(int which_side, int value)
-{
- return common_write_atr_mask(C_TX, which_side, value);
-}
-
-bool
-usrp_basic_tx::write_atr_txval(int which_side, int value)
-{
- return common_write_atr_txval(C_TX, which_side, value);
-}
-
-bool
-usrp_basic_tx::write_atr_rxval(int which_side, int value)
-{
- return common_write_atr_rxval(C_TX, which_side, value);
-}
-
-bool
-usrp_basic_tx::write_aux_dac (int which_side, int which_dac, int value)
-{
- return common_write_aux_dac(C_TX, which_side, which_dac, value);
-}
-
-bool
-usrp_basic_tx::read_aux_adc (int which_side, int which_adc, int *value)
-{
- return common_read_aux_adc(C_TX, which_side, which_adc, value);
-}
-
-int
-usrp_basic_tx::read_aux_adc (int which_side, int which_adc)
-{
- return common_read_aux_adc(C_TX, which_side, which_adc);
-}
-
-int
-usrp_basic_tx::block_size () const { return d_ephandle->block_size(); }
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2004,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-/*
- * ----------------------------------------------------------------------
- * 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 <db_base.h>
-#include <usrp_slots.h>
-#include <string>
-#include <vector>
-#include <boost/utility.hpp>
-#include <usrp_subdev_spec.h>
-
-struct usb_dev_handle;
-class fusb_devhandle;
-class fusb_ephandle;
-
-enum txrx_t {
- C_RX = 0,
- C_TX = 1
-};
-
-/*!
- * \brief abstract base class for usrp operations
- * \ingroup usrp
- */
-class usrp_basic : boost::noncopyable
-{
-protected:
- void shutdown_daughterboards();
-
-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;
- long d_fpga_master_clock_freq;
-
- static const int MAX_REGS = 128;
- unsigned int d_fpga_shadows[MAX_REGS];
-
- int d_dbid[2]; // daughterboard ID's (side A, side B)
-
- /*!
- * Shared pointers to subclasses of db_base.
- *
- * The outer vector is of length 2 (0 = side A, 1 = side B). The
- * inner vectors are of length 1, 2 or 3 depending on the number of
- * subdevices implemented by the daugherboard. At this time, only
- * the Basic Rx and LF Rx implement more than 1 subdevice.
- */
- std::vector< std::vector<db_base_sptr> > d_db;
-
- //! One time call, made only only from usrp_standard_*::make after shared_ptr is created.
- void init_db(usrp_basic_sptr u);
-
-
- usrp_basic (int which_board,
- struct usb_dev_handle *open_interface (struct usb_device *dev),
- const std::string fpga_filename = "",
- 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 ();
-
-
- /*!
- * Return a vector of vectors that contain shared pointers
- * to the daughterboard instance(s) associated with the specified side.
- *
- * It is an error to use the returned objects after the usrp_basic
- * object has been destroyed.
- */
- std::vector<std::vector<db_base_sptr> > db() const { return d_db; }
-
- /*!
- * Return a vector of size >= 1 that contains shared pointers
- * to the daughterboard instance(s) associated with the specified side.
- *
- * \param which_side [0,1] which daughterboard
- *
- * It is an error to use the returned objects after the usrp_basic
- * object has been destroyed.
- */
- std::vector<db_base_sptr> db(int which_side);
-
- /*!
- * \brief is the subdev_spec valid?
- */
- bool is_valid(const usrp_subdev_spec &ss);
-
- /*!
- * \brief given a subdev_spec, return the corresponding daughterboard object.
- * \throws std::invalid_ argument if ss is invalid.
- *
- * \param ss specifies the side and subdevice
- */
- db_base_sptr selected_subdev(const usrp_subdev_spec &ss);
-
- /*!
- * \brief return frequency of master oscillator on USRP
- */
- long fpga_master_clock_freq () const { return d_fpga_master_clock_freq; }
-
- /*!
- * Tell API that the master oscillator on the USRP is operating at a non-standard
- * fixed frequency. This is only needed for custom USRP hardware modified to
- * operate at a different frequency from the default factory configuration. This
- * function must be called prior to any other API function.
- * \param master_clock USRP2 FPGA master clock frequency in Hz (10..64 MHz)
- */
- void set_fpga_master_clock_freq (long master_clock) { d_fpga_master_clock_freq = master_clock; }
-
- /*!
- * \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_adc 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_adc, int offset);
-
- /*!
- * \brief Set DAC offset correction
- * \param which_dac 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_dac, int offset, int offset_pin);
-
- /*!
- * \brief Control ADC input buffer
- * \param which_adc which ADC[0,3]
- * \param bypass if non-zero, bypass input buffer and connect input
- * directly to switched cap SHA input of RxPGA.
- */
- bool set_adc_buffer_bypass (int which_adc, bool bypass);
-
- /*!
- * \brief Enable/disable automatic DC offset removal control loop in FPGA
- *
- * \param bits which control loops to enable
- * \param mask which \p bits to pay attention to
- *
- * If the corresponding bit is set, enable the automatic DC
- * offset correction control loop.
- *
- * <pre>
- * The 4 low bits are significant:
- *
- * ADC0 = (1 << 0)
- * ADC1 = (1 << 1)
- * ADC2 = (1 << 2)
- * ADC3 = (1 << 3)
- * </pre>
- *
- * By default the control loop is enabled on all ADC's.
- */
- bool set_dc_offset_cl_enable(int bits, int mask);
-
- /*!
- * \brief return the usrp's serial number.
- *
- * \returns non-zero length string iff successful.
- */
- std::string serial_number();
-
- /*!
- * \brief Return daughterboard ID for given side [0,1].
- *
- * \param which_side [0,1] which daughterboard
- *
- * \return daughterboard id >= 0 if successful
- * \return -1 if no daugherboard
- * \return -2 if invalid EEPROM on daughterboard
- */
- virtual int daughterboard_id (int which_side) const = 0;
-
- /*!
- * \brief Clock ticks to delay rising of T/R signal
- * \sa write_atr_mask, write_atr_txval, write_atr_rxval
- */
- bool write_atr_tx_delay(int value);
-
- /*!
- * \brief Clock ticks to delay falling edge of T/R signal
- * \sa write_atr_mask, write_atr_txval, write_atr_rxval
- */
- bool write_atr_rx_delay(int value);
-
-
-\f // ================================================================
- // Routines to access and control daughterboard specific i/o
- //
- // Those with a common_ prefix access either the Tx or Rx side depending
- // on the txrx parameter. Those without the common_ prefix are virtual
- // and are overriden in usrp_basic_rx and usrp_basic_tx to access the
- // the Rx or Tx sides automatically. We provide the common_ versions
- // for those daughterboards such as the WBX and XCVR2450 that share
- // h/w resources (such as the LO) between the Tx and Rx sides.
-
- // ----------------------------------------------------------------
- // BEGIN common_ daughterboard control functions
-
- /*!
- * \brief Set Programmable Gain Amplifier(PGA)
- *
- * \param txrx Tx or Rx?
- * \param which_amp which amp [0,3]
- * \param gain_in_db gain value(linear in dB)
- *
- * gain is rounded to closest setting supported by hardware.
- *
- * \returns true iff sucessful.
- *
- * \sa pga_min(), pga_max(), pga_db_per_step()
- */
- bool common_set_pga(txrx_t txrx, int which_amp, double gain_in_db);
-
- /*!
- * \brief Return programmable gain amplifier gain setting in dB.
- *
- * \param txrx Tx or Rx?
- * \param which_amp which amp [0,3]
- */
- double common_pga(txrx_t txrx, int which_amp) const;
-
- /*!
- * \brief Return minimum legal PGA gain in dB.
- * \param txrx Tx or Rx?
- */
- double common_pga_min(txrx_t txrx) const;
-
- /*!
- * \brief Return maximum legal PGA gain in dB.
- * \param txrx Tx or Rx?
- */
- double common_pga_max(txrx_t txrx) const;
-
- /*!
- * \brief Return hardware step size of PGA(linear in dB).
- * \param txrx Tx or Rx?
- */
- double common_pga_db_per_step(txrx_t txrx) const;
-
- /*!
- * \brief Write direction register(output enables) for pins that go to daughterboard.
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which size
- * \param value value to write into register
- * \param mask which bits of value to write into reg
- *
- * Each d'board has 16-bits of general purpose i/o.
- * Setting the bit makes it an output from the FPGA to the d'board.
- *
- * This register is initialized based on a value stored in the
- * d'board EEPROM. In general, you shouldn't be using this routine
- * without a very good reason. Using this method incorrectly will
- * kill your USRP motherboard and/or daughterboard.
- */
- bool _common_write_oe(txrx_t txrx, int which_side, int value, int mask);
-
- /*!
- * \brief Write daughterboard i/o pin value
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * \param value value to write into register
- * \param mask which bits of value to write into reg
- */
- bool common_write_io(txrx_t txrx, int which_side, int value, int mask);
-
- /*!
- * \brief Read daughterboard i/o pin value
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * \param value output
- */
- bool common_read_io(txrx_t txrx, int which_side, int *value);
-
- /*!
- * \brief Read daughterboard i/o pin value
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * \returns register value if successful, else READ_FAILED
- */
- int common_read_io(txrx_t txrx, int which_side);
-
- /*!
- * \brief Write daughterboard refclk config register
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * \param value value to write into register, see below
- *
- * <pre>
- * Control whether a reference clock is sent to the daughterboards,
- * and what frequency. The refclk is sent on d'board i/o pin 0.
- *
- * 3 2 1
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------------------------------+-+------------+
- * | Reserved (Must be zero) |E| DIVISOR |
- * +-----------------------------------------------+-+------------+
- *
- * Bit 7 -- 1 turns on refclk, 0 allows IO use
- * Bits 6:0 Divider value
- * </pre>
- */
- bool common_write_refclk(txrx_t txrx, int which_side, int value);
-
- /*!
- * \brief Automatic Transmit/Receive switching
- * <pre>
- *
- * If automatic transmit/receive (ATR) switching is enabled in the
- * FR_ATR_CTL register, the presence or absence of data in the FPGA
- * transmit fifo selects between two sets of values for each of the 4
- * banks of daughterboard i/o pins.
- *
- * Each daughterboard slot has 3 16-bit registers associated with it:
- * FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_*
- *
- * FR_ATR_MASK_{0,1,2,3}:
- *
- * These registers determine which of the daugherboard i/o pins are
- * affected by ATR switching. If a bit in the mask is set, the
- * corresponding i/o bit is controlled by ATR, else it's output
- * value comes from the normal i/o pin output register:
- * FR_IO_{0,1,2,3}.
- *
- * FR_ATR_TXVAL_{0,1,2,3}:
- * FR_ATR_RXVAL_{0,1,2,3}:
- *
- * If the Tx fifo contains data, then the bits from TXVAL that are
- * selected by MASK are output. Otherwise, the bits from RXVAL that
- * are selected by MASK are output.
- * </pre>
- */
- bool common_write_atr_mask(txrx_t txrx, int which_side, int value);
- bool common_write_atr_txval(txrx_t txrx, int which_side, int value);
- bool common_write_atr_rxval(txrx_t txrx, int which_side, int value);
-
- /*!
- * \brief Write auxiliary digital to analog converter.
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
- * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
- * \param which_dac [2,3] TX slots must use only 2 and 3.
- * \param value [0,4095]
- * \returns true iff successful
- */
- bool common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value);
-
- /*!
- * \brief Read auxiliary analog to digital converter.
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * \param which_adc [0,1]
- * \param value return 12-bit value [0,4095]
- * \returns true iff successful
- */
- bool common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value);
-
- /*!
- * \brief Read auxiliary analog to digital converter.
- *
- * \param txrx Tx or Rx?
- * \param which_side [0,1] which d'board
- * \param which_adc [0,1]
- * \returns value in the range [0,4095] if successful, else READ_FAILED.
- */
- int common_read_aux_adc(txrx_t txrx, int which_side, int which_adc);
-
- // END common_ daughterboard control functions\f
- // ----------------------------------------------------------------
- // BEGIN virtual daughterboard control functions
-
- /*!
- * \brief Set Programmable Gain Amplifier (PGA)
- *
- * \param which_amp which amp [0,3]
- * \param gain_in_db gain value (linear in dB)
- *
- * gain is rounded to closest setting supported by hardware.
- *
- * \returns true iff sucessful.
- *
- * \sa pga_min(), pga_max(), pga_db_per_step()
- */
- virtual bool set_pga (int which_amp, double gain_in_db) = 0;
-
- /*!
- * \brief Return programmable gain amplifier gain setting in dB.
- *
- * \param which_amp which amp [0,3]
- */
- virtual double pga (int which_amp) const = 0;
-
- /*!
- * \brief Return minimum legal PGA gain in dB.
- */
- virtual double pga_min () const = 0;
-
- /*!
- * \brief Return maximum legal PGA gain in dB.
- */
- virtual double pga_max () const = 0;
-
- /*!
- * \brief Return hardware step size of PGA (linear in dB).
- */
- virtual double pga_db_per_step () const = 0;
-
- /*!
- * \brief Write direction register (output enables) for pins that go to daughterboard.
- *
- * \param which_side [0,1] which size
- * \param value value to write into register
- * \param mask which bits of value to write into reg
- *
- * Each d'board has 16-bits of general purpose i/o.
- * Setting the bit makes it an output from the FPGA to the d'board.
- *
- * This register is initialized based on a value stored in the
- * d'board EEPROM. In general, you shouldn't be using this routine
- * without a very good reason. Using this method incorrectly will
- * kill your USRP motherboard and/or daughterboard.
- */
- virtual bool _write_oe (int which_side, int value, int mask) = 0;
-
- /*!
- * \brief Write daughterboard i/o pin value
- *
- * \param which_side [0,1] which d'board
- * \param value value to write into register
- * \param mask which bits of value to write into reg
- */
- virtual bool write_io (int which_side, int value, int mask) = 0;
-
- /*!
- * \brief Read daughterboard i/o pin value
- *
- * \param which_side [0,1] which d'board
- * \param value output
- */
- virtual bool read_io (int which_side, int *value) = 0;
-
- /*!
- * \brief Read daughterboard i/o pin value
- *
- * \param which_side [0,1] which d'board
- * \returns register value if successful, else READ_FAILED
- */
- virtual int read_io (int which_side) = 0;
-
- /*!
- * \brief Write daughterboard refclk config register
- *
- * \param which_side [0,1] which d'board
- * \param value value to write into register, see below
- *
- * <pre>
- * Control whether a reference clock is sent to the daughterboards,
- * and what frequency. The refclk is sent on d'board i/o pin 0.
- *
- * 3 2 1
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------------------------------+-+------------+
- * | Reserved (Must be zero) |E| DIVISOR |
- * +-----------------------------------------------+-+------------+
- *
- * Bit 7 -- 1 turns on refclk, 0 allows IO use
- * Bits 6:0 Divider value
- * </pre>
- */
- virtual bool write_refclk(int which_side, int value) = 0;
-
- virtual bool write_atr_mask(int which_side, int value) = 0;
- virtual bool write_atr_txval(int which_side, int value) = 0;
- virtual bool write_atr_rxval(int which_side, int value) = 0;
-
- /*!
- * \brief Write auxiliary digital to analog converter.
- *
- * \param which_side [0,1] which d'board
- * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's.
- * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's.
- * \param which_dac [2,3] TX slots must use only 2 and 3.
- * \param value [0,4095]
- * \returns true iff successful
- */
- virtual bool write_aux_dac (int which_side, int which_dac, int value) = 0;
-
- /*!
- * \brief Read auxiliary analog to digital converter.
- *
- * \param which_side [0,1] which d'board
- * \param which_adc [0,1]
- * \param value return 12-bit value [0,4095]
- * \returns true iff successful
- */
- virtual bool read_aux_adc (int which_side, int which_adc, int *value) = 0;
-
- /*!
- * \brief Read auxiliary analog to digital converter.
- *
- * \param which_side [0,1] which d'board
- * \param which_adc [0,1]
- * \returns value in the range [0,4095] if successful, else READ_FAILED.
- */
- virtual int read_aux_adc (int which_side, int which_adc) = 0;
-
- /*!
- * \brief returns current fusb block size
- */
- virtual int block_size() const = 0;
-
- /*!
- * \brief returns A/D or D/A converter rate in Hz
- */
- virtual long converter_rate() const = 0;
-
- // END virtual daughterboard control functions\f
-
- // ----------------------------------------------------------------
- // Low level implementation routines.
- // You probably shouldn't be using these...
- //
-
- bool _set_led (int which_led, 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 ();
-};
-
-\f/*!
- * \brief class for accessing the receive side of the USRP
- * \ingroup 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:
- /*!
- * \param which_board Which USRP board on usb (not particularly useful; use 0)
- * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
- * Use zero for a reasonable default.
- * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
- * \param fpga_filename name of the rbf file to load
- * \param firmware_filename name of ihx file to load
- */
- 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);
-
-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.
- * \param fpga_filename name of file that contains image to load into FPGA
- * \param firmware_filename name of file that contains image to load into FX2
- */
- static usrp_basic_rx *make (int which_board,
- int fusb_block_size=0,
- int fusb_nblocks=0,
- const std::string fpga_filename = "",
- const std::string firmware_filename = ""
- );
-
- /*!
- * \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);
-
-
- //! sampling rate of A/D converter
- virtual long converter_rate() const { return fpga_master_clock_freq(); } // 64M
- long adc_rate() const { return converter_rate(); }
- int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; }
-
- bool set_pga (int which_amp, double gain_in_db);
- double pga (int which_amp) const;
- double pga_min () const;
- double pga_max () const;
- double pga_db_per_step () const;
-
- bool _write_oe (int which_side, int value, int mask);
- bool write_io (int which_side, int value, int mask);
- bool read_io (int which_side, int *value);
- int read_io (int which_side);
- bool write_refclk(int which_side, int value);
- bool write_atr_mask(int which_side, int value);
- bool write_atr_txval(int which_side, int value);
- bool write_atr_rxval(int which_side, int value);
-
- bool write_aux_dac (int which_side, int which_dac, int value);
- bool read_aux_adc (int which_side, int which_adc, int *value);
- int read_aux_adc (int which_side, int which_adc);
-
- int block_size() const;
-
- // called in base class to derived class order
- bool start ();
- bool stop ();
-};
-
-\f/*!
- * \brief class for accessing the transmit side of the USRP
- * \ingroup 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:
- /*!
- * \param which_board Which USRP board on usb (not particularly useful; use 0)
- * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
- * Use zero for a reasonable default.
- * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
- * \param fpga_filename name of file that contains image to load into FPGA
- * \param firmware_filename name of file that contains image to load into FX2
- */
- usrp_basic_tx (int which_board,
- int fusb_block_size=0,
- 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);
-
-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.
- * \param fpga_filename name of file that contains image to load into FPGA
- * \param firmware_filename name of file that contains image to load into FX2
- */
- static usrp_basic_tx *make (int which_board, int fusb_block_size=0, int fusb_nblocks=0,
- const std::string fpga_filename = "",
- const std::string firmware_filename = ""
- );
-
- /*!
- * \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 ();
-
- //! 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(); }
- int daughterboard_id (int which_side) const { return d_dbid[which_side & 0x1]; }
-
- bool set_pga (int which_amp, double gain_in_db);
- double pga (int which_amp) const;
- double pga_min () const;
- double pga_max () const;
- double pga_db_per_step () const;
-
- bool _write_oe (int which_side, int value, int mask);
- bool write_io (int which_side, int value, int mask);
- bool read_io (int which_side, int *value);
- int read_io (int which_side);
- bool write_refclk(int which_side, int value);
- bool write_atr_mask(int which_side, int value);
- bool write_atr_txval(int which_side, int value);
- bool write_atr_rxval(int which_side, int value);
-
- bool write_aux_dac (int which_side, int which_dac, int value);
- bool read_aux_adc (int which_side, int which_adc, int *value);
- int read_aux_adc (int which_side, int which_adc);
-
- int block_size() const;
-
- // called in base class to derived class order
- bool start ();
- bool stop ();
-};
-
-#endif
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-#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
-
-#warning Using non-portable code (likely wrong other than ILP32).
-
-static inline unsigned short int
-bswap_16 (unsigned short int x)
-{
- return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
-}
-
-static inline unsigned int
-bswap_32 (unsigned int x)
-{
- return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
- | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
-}
-#endif
-
-
-#ifdef WORDS_BIGENDIAN
-
-static inline unsigned int
-host_to_usrp_u32 (unsigned int x)
-{
- return bswap_32(x);
-}
-
-static inline unsigned int
-usrp_to_host_u32 (unsigned int x)
-{
- return bswap_32(x);
-}
-
-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 unsigned int
-host_to_usrp_u32 (unsigned int x)
-{
- return x;
-}
-
-static inline unsigned int
-usrp_to_host_u32 (unsigned int x)
-{
- return x;
-}
-
-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 */
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "usrp_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;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef _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_ */
+++ /dev/null
-#
-# Copyright 2005,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-
-# 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 ClkMod" 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
-"DTT754" 0x0041
-"DTT768" 0x0042
-
-"WBX LO TX" 0x0050
-"WBX LO RX" 0x0051
-
-"XCVR2450 Tx" 0x0060
-"XCVR2450 Rx" 0x0061
-
-"Experimental Tx" 0xfffe
-"Experimental Rx" 0xffff
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-/*
- * 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>
-#include <string.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
- }
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#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 */
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "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 const char *default_firmware_filename = "std.ihx";
-static const char *default_fpga_filename = "std_2rxhb_2tx.rbf";
-
-#include "std_paths.h"
-#include <stdio.h>
-
-static char *
-find_file (const char *filename, int hw_rev)
-{
- const 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) || defined(__WIN32__) || defined(__CYGWIN__)
- // 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...
-
- // Appears to be required for libusb-win32 and Cygwin -- dew 09/20/06
- 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)
-{
- unsigned char 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;
-}
+++ /dev/null
-/* -*- 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 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-/*
- * 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_ */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#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 */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#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>
-#include <cstdio>
-
-
-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]))
-
-
-void
-usrp_standard_common::calc_dxc_freq(double target_freq, double baseband_freq, double fs,
- double *dxc_freq, bool *inverted)
-{
- /*
- Calculate the frequency to use for setting the digital up or down converter.
-
- @param target_freq: desired RF frequency (Hz)
- @param baseband_freq: the RF frequency that corresponds to DC in the IF.
- @param fs: converter sample rate
-
- @returns: 2-tuple (ddc_freq, inverted) where ddc_freq is the value
- for the ddc and inverted is True if we're operating in an inverted
- Nyquist zone.
- */
-
-#if 0
- printf("calc_dxc_freq:\n");
- printf(" target = %f\n", target_freq);
- printf(" baseband = %f\n", baseband_freq);
- printf(" fs = %f\n", fs);
-#endif
-
- double delta = target_freq - baseband_freq;
-
- if(delta >= 0) {
- while(delta > fs) {
- delta -= fs;
- }
- if(delta <= fs/2) { // non-inverted region
- *dxc_freq = -delta;
- *inverted = false;
- }
- else { // inverted region
- *dxc_freq = delta - fs;
- *inverted = true;
- }
- }
- else {
- while(delta < -fs) {
- delta += fs;
- }
- if(delta >= -fs/2) {
- *dxc_freq = -delta; // non-inverted region
- *inverted = false;
- }
- else { // inverted region
- *dxc_freq = delta + fs;
- *inverted = true;
- }
- }
-
-#if 0
- printf(" dxc_freq = %f\n", *dxc_freq);
- printf(" inverted = %s\n", *inverted ? "true" : "false");
-#endif
-}
-
-
-/*
- * Real lambda expressions would be _so_ much easier...
- */
-class dxc_control {
-public:
- virtual bool is_tx() = 0;
- virtual bool set_dxc_freq(double dxc_freq) = 0;
- virtual double dxc_freq() = 0;
-};
-
-class ddc_control : public dxc_control {
- usrp_standard_rx *d_u;
- int d_chan;
-
-public:
- ddc_control(usrp_standard_rx *u, int chan)
- : d_u(u), d_chan(chan) {}
-
- bool is_tx(){ return false; }
- bool set_dxc_freq(double dxc_freq){ return d_u->set_rx_freq(d_chan, dxc_freq); }
- double dxc_freq(){ return d_u->rx_freq(d_chan); }
-};
-
-class duc_control : public dxc_control {
- usrp_standard_tx *d_u;
- int d_chan;
-
-public:
- duc_control(usrp_standard_tx *u, int chan)
- : d_u(u), d_chan(chan) {}
-
- bool is_tx(){ return true; }
- bool set_dxc_freq(double dxc_freq){ return d_u->set_tx_freq(d_chan, dxc_freq); }
- double dxc_freq() { return d_u->tx_freq(d_chan); }
-};
-
-
-/*!
- * \brief Tune such that target_frequency ends up at DC in the complex baseband
- *
- * \param db the daughterboard to use
- * \param target_freq the center frequency we want at baseband (DC)
- * \param fs the sample rate
- * \param dxc DDC or DUC access and control object
- * \param[out] result details of what we did
- *
- * \returns true iff operation was successful
- *
- * Tuning is a two step process. First we ask the front-end to
- * tune as close to the desired frequency as it can. Then we use
- * the result of that operation and our target_frequency to
- * determine the value for the digital down converter.
- */
-static bool
-tune_a_helper(db_base_sptr db, double target_freq, double fs,
- dxc_control &dxc, usrp_tune_result *result)
-{
- bool inverted = false;
- double dxc_freq;
- double actual_dxc_freq;
-
- // Ask the d'board to tune as closely as it can to target_freq
-#if 0
- bool ok = db->set_freq(target_freq, &result->baseband_freq);
-#else
- bool ok;
- {
- freq_result_t fr = db->set_freq(target_freq);
- ok = fr.ok;
- result->baseband_freq = fr.baseband_freq;
- }
-#endif
-
- // Calculate the DDC setting that will downconvert the baseband from the
- // daughterboard to our target frequency.
- usrp_standard_common::calc_dxc_freq(target_freq, result->baseband_freq, fs,
- &dxc_freq, &inverted);
-
- // If the spectrum is inverted, and the daughterboard doesn't do
- // quadrature downconversion, we can fix the inversion by flipping the
- // sign of the dxc_freq... (This only happens using the basic_rx board)
-
- if(db->spectrum_inverted())
- inverted = !inverted;
-
- if(inverted && !db->is_quadrature()){
- dxc_freq = -dxc_freq;
- inverted = !inverted;
- }
-
- if (dxc.is_tx() && !db->i_and_q_swapped()) // down conversion versus up conversion
- dxc_freq = -dxc_freq;
-
- ok &= dxc.set_dxc_freq(dxc_freq);
- actual_dxc_freq = dxc.dxc_freq();
-
- result->dxc_freq = dxc_freq;
- result->residual_freq = dxc_freq - actual_dxc_freq;
- result->inverted = inverted;
- return ok;
-}
-
-
-static unsigned int
-compute_freq_control_word_fpga (double master_freq, double target_freq,
- double *actual_freq, bool verbose)
-{
- 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_sptr
-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
- )
-{
- try {
- usrp_standard_rx_sptr u =
- usrp_standard_rx_sptr(new usrp_standard_rx(which_board, decim_rate,
- nchan, mux, mode,
- fusb_block_size, fusb_nblocks,
- fpga_filename, firmware_filename));
- u->init_db(u);
- return u;
- }
- catch (...){
- return usrp_standard_rx_sptr();
- }
-}
-
-bool
-usrp_standard_rx::set_decim_rate(unsigned int rate)
-{
- if (has_rx_halfband()){
- 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;
- }
- }
- else {
- if (rate < 4 || rate > 128){
- fprintf (stderr, "usrp_standard_rx::set_decim_rate: rate must be in [4, 128]\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;
-}
-
-int
-usrp_standard_rx::determine_rx_mux_value(const usrp_subdev_spec &ss)
-{
- /*
- Determine appropriate Rx mux value as a function of the subdevice choosen and the
- characteristics of the respective daughterboard.
-
- @param u: instance of USRP source
- @param subdev_spec: return value from subdev option parser.
- @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 or 1
- @returns: the Rx mux value
-
- Figure out which A/D's to connect to the DDC.
-
- Each daughterboard consists of 1 or 2 subdevices. (At this time,
- all but the Basic Rx have a single subdevice. The Basic Rx
- has two independent channels, treated as separate subdevices).
- subdevice 0 of a daughterboard may use 1 or 2 A/D's. We determine this
- by checking the is_quadrature() method. If subdevice 0 uses only a single
- A/D, it's possible that the daughterboard has a second subdevice, subdevice 1,
- and it uses the second A/D.
-
- If the card uses only a single A/D, we wire a zero into the DDC Q input.
-
- (side, 0) says connect only the A/D's used by subdevice 0 to the DDC.
- (side, 1) says connect only the A/D's used by subdevice 1 to the DDC.
- */
-
- struct truth_table_element
- {
- int d_side;
- int d_uses;
- bool d_swap_iq;
- unsigned int d_mux_val;
-
- truth_table_element(int side, unsigned int uses, bool swap_iq, unsigned int mux_val=0)
- : d_side(side), d_uses(uses), d_swap_iq(swap_iq), d_mux_val(mux_val){}
-
- bool operator==(const truth_table_element &in)
- {
- return (d_side == in.d_side && d_uses == in.d_uses && d_swap_iq == in.d_swap_iq);
- }
-
- unsigned int mux_val() { return d_mux_val; }
- };
-
-
- if (!is_valid(ss))
- throw std::invalid_argument("subdev_spec");
-
-
- // This is a tuple of length 1 or 2 containing the subdevice
- // classes for the selected side.
- std::vector<db_base_sptr> db = this->db(ss.side);
-
- unsigned int uses;
-
- // compute bitmasks of used A/D's
-
- if(db[ss.subdev]->is_quadrature())
- uses = 0x3; // uses A/D 0 and 1
- else if (ss.subdev == 0)
- uses = 0x1; // uses A/D 0 only
- else if(ss.subdev == 1)
- uses = 0x2; // uses A/D 1 only
- else
- uses = 0x0; // uses no A/D (doesn't exist)
-
- if(uses == 0){
- throw std::runtime_error("Determine RX Mux Error");
- }
-
- bool swap_iq = db[ss.subdev]->i_and_q_swapped();
-
- truth_table_element truth_table[8] = {
- // (side, uses, swap_iq) : mux_val
- truth_table_element(0, 0x1, false, 0xf0f0f0f0),
- truth_table_element(0, 0x2, false, 0xf0f0f0f1),
- truth_table_element(0, 0x3, false, 0x00000010),
- truth_table_element(0, 0x3, true, 0x00000001),
- truth_table_element(1, 0x1, false, 0xf0f0f0f2),
- truth_table_element(1, 0x2, false, 0xf0f0f0f3),
- truth_table_element(1, 0x3, false, 0x00000032),
- truth_table_element(1, 0x3, true, 0x00000023)
- };
- size_t nelements = sizeof(truth_table)/sizeof(truth_table[0]);
-
- truth_table_element target(ss.side, uses, swap_iq, 0);
-
- size_t i;
- for(i = 0; i < nelements; i++){
- if (truth_table[i] == target)
- return truth_table[i].mux_val();
- }
- throw std::runtime_error("internal error");
-}
-
-int
-usrp_standard_rx::determine_rx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b)
-{
- std::vector<db_base_sptr> db_a = this->db(ss_a.side);
- std::vector<db_base_sptr> db_b = this->db(ss_b.side);
- if (db_a[ss_a.subdev]->is_quadrature() != db_b[ss_b.subdev]->is_quadrature()){
- throw std::runtime_error("Cannot compute dual mux when mixing quadrature and non-quadrature subdevices");
- }
- int mux_a = determine_rx_mux_value(ss_a);
- int mux_b = determine_rx_mux_value(ss_b);
- //move the lower byte of the mux b into the second byte of the mux a
- return ((mux_b & 0xff) << 8) | (mux_a & 0xffff00ff);
-}
-
-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_rate(),
- 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;
-}
-
-bool
-usrp_standard_rx::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result)
-{
- ddc_control dxc(this, chan);
- return tune_a_helper(db, target_freq, converter_rate(), dxc, result);
-}
-
-
-//////////////////////////////////////////////////////////////////
-
-
-// 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_sptr
-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
- )
-{
- try {
- usrp_standard_tx_sptr u =
- usrp_standard_tx_sptr(new usrp_standard_tx(which_board, interp_rate, nchan, mux,
- fusb_block_size, fusb_nblocks,
- fpga_filename, firmware_filename));
- u->init_db(u);
- return u;
- }
- catch (...){
- return usrp_standard_tx_sptr();
- }
-}
-
-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;
-}
-
-int
-usrp_standard_tx::determine_tx_mux_value(const usrp_subdev_spec &ss)
-{
- /*
- Determine appropriate Tx mux value as a function of the subdevice choosen.
-
- @param u: instance of USRP source
- @param subdev_spec: return value from subdev option parser.
- @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0
- @returns: the Rx mux value
-
- This is simpler than the rx case. Either you want to talk
- to side A or side B. If you want to talk to both sides at once,
- determine the value manually.
- */
-
- if (!is_valid(ss))
- throw std::invalid_argument("subdev_spec");
-
- std::vector<db_base_sptr> db = this->db(ss.side);
-
- if(db[ss.subdev]->i_and_q_swapped()) {
- unsigned int mask[2] = {0x0089, 0x8900};
- return mask[ss.side];
- }
- else {
- unsigned int mask[2] = {0x0098, 0x9800};
- return mask[ss.side];
- }
-}
-
-int
-usrp_standard_tx::determine_tx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b)
-{
- if (ss_a.side == ss_b.side && ss_a.subdev == ss_b.subdev){
- throw std::runtime_error("Cannot compute dual mux, repeated subdevice");
- }
- int mux_a = determine_tx_mux_value(ss_a);
- //Get the mux b:
- // DAC0 becomes DAC2
- // DAC1 becomes DAC3
- unsigned int mask[2] = {0x0022, 0x2200};
- int mux_b = determine_tx_mux_value(ss_b) + mask[ss_b.side];
- return mux_b | mux_a;
-}
-
-#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_rate () / 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_rate () == 128000000);
-
- if (freq < -44e6) // too low
- return false;
- else if (freq < -24e6){ // [-44, -24)
- cm = CM_NEG_FDAC_OVER_4;
- coarse = -dac_rate () / 4;
- }
- else if (freq < -8e6){ // [-24, -8)
- cm = CM_NEG_FDAC_OVER_8;
- coarse = -dac_rate () / 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_rate () / 8;
- }
- else if (freq <= 44e6){ // [24, 44]
- cm = CM_POS_FDAC_OVER_4;
- coarse = dac_rate () / 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_rate () / 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];
-}
-
-bool
-usrp_standard_tx::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result)
-{
- duc_control dxc(this, chan);
- return tune_a_helper(db, target_freq, converter_rate(), dxc, result);
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004,2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_USRP_STANDARD_H
-#define INCLUDED_USRP_STANDARD_H
-
-#include <usrp_basic.h>
-#include <boost/shared_ptr.hpp>
-#include <usrp_tune_result.h>
-
-class usrp_standard_tx;
-class usrp_standard_rx;
-
-typedef boost::shared_ptr<usrp_standard_tx> usrp_standard_tx_sptr;
-typedef boost::shared_ptr<usrp_standard_rx> usrp_standard_rx_sptr;
-
-/*!
- * \ingroup usrp
- */
-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 Calculate the frequency to use for setting the digital up or down converter.
- *
- * \param target_freq is the desired RF frequency (Hz).
- * \param baseband_freq is the RF frequency that corresponds to DC in the IF coming from the d'board.
- * \param fs is the sampling frequency.
- * \param[out] dxc_freq the frequency to program into the DDC (or DUC).
- * \param[out] inverted is true if we're operating in an inverted Nyquist zone.
- */
- static void calc_dxc_freq(double target_freq, double baseband_freq, double fs,
- double *dxc_freq, bool *inverted);
-};
-
-/*!
- * \brief The C++ interface the receive side of the USRP
- * \ingroup usrp
- *
- * This is the recommended interface to USRP receive functionality
- * for applications that use the USRP but not GNU Radio.
- */
-class usrp_standard_rx : public usrp_basic_rx, public 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 shared_ptr or shared_ptr equivalent of 0 if trouble
- *
- * \param which_board Which USRP board on usb (not particularly useful; use 0)
- * \param decim_rate decimation factor
- * \param nchan number of channels
- * \param mux Rx mux setting, \sa set_mux
- * \param mode mode
- * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
- * Use zero for a reasonable default.
- * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
- * \param fpga_filename Name of rbf file to load
- * \param firmware_filename Name of ihx file to load
- */
- static usrp_standard_rx_sptr make(int which_board,
- unsigned int decim_rate,
- int nchan = 1,
- int mux = -1,
- int mode = 0,
- int fusb_block_size = 0,
- int fusb_nblocks = 0,
- const std::string fpga_filename = "",
- const std::string firmware_filename = ""
- );
- /*!
- * \brief Set decimator rate. \p rate MUST BE EVEN and in [8, 256].
- *
- * 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);
-
- /*!
- * Determine the appropriate Rx mux value as a function of the subdevice choosen
- * and the characteristics of the respective daughterboard.
- */
- int determine_rx_mux_value(const usrp_subdev_spec &ss);
- int determine_rx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b);
-
- /*!
- * \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);
-
- /*!
- * \brief High-level "tune" method. Works for the single channel case.
- *
- * This method adjusts both the daughterboard LO and the DDC so that
- * target_freq ends up at DC in the complex baseband samples.
- *
- * \param chan which DDC channel we're controlling (almost always 0).
- * \param db the daughterboard we're controlling.
- * \param target_freq the RF frequency we want at DC in the complex baseband.
- * \param[out] result details how the hardware was configured.
- *
- * \returns true iff everything was successful.
- */
- bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result);
-
-
- // ACCESSORS
- unsigned int decim_rate () const;
- double rx_freq (int channel) const;
- int nchannels () const;
- int mux () const;
- unsigned int format () const;
-
- // called in base class to derived class order
- bool start ();
- bool stop ();
-};
-
-// ----------------------------------------------------------------
-
-/*!
- * \brief The C++ interface the transmit side of the USRP
- * \ingroup usrp
- *
- * This is the recommended interface to USRP transmit functionality
- * for applications that use the USRP but not GNU Radio.
- *
- * Uses digital upconverter (coarse & fine modulators) in AD9862...
- */
-class usrp_standard_tx : public usrp_basic_tx, public 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 shared_ptr or shared_ptr equivalent of 0 if trouble
- *
- * \param which_board Which USRP board on usb (not particularly useful; use 0)
- * \param interp_rate interpolation factor
- * \param nchan number of channels
- * \param mux Tx mux setting, \sa set_mux
- * \param fusb_block_size fast usb xfer block size. Must be a multiple of 512.
- * Use zero for a reasonable default.
- * \param fusb_nblocks number of fast usb URBs to allocate. Use zero for a reasonable default.
- * \param fpga_filename Name of rbf file to load
- * \param firmware_filename Name of ihx file to load
- */
- static usrp_standard_tx_sptr make(int which_board,
- unsigned int interp_rate,
- int nchan = 1,
- int mux = -1,
- int fusb_block_size = 0,
- int fusb_nblocks = 0,
- const std::string fpga_filename = "",
- const std::string firmware_filename = ""
- );
-
- /*!
- * \brief Set interpolator rate. \p rate must be in [4, 512] and a multiple of 4.
- *
- * 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);
-
- /*!
- * Determine the appropriate Tx mux value as a function of the subdevice choosen
- * and the characteristics of the respective daughterboard.
- */
- int determine_tx_mux_value(const usrp_subdev_spec &ss);
- int determine_tx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b);
-
- /*!
- * \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;
-
- /*!
- * \brief High-level "tune" method. Works for the single channel case.
- *
- * This method adjusts both the daughterboard LO and the DUC so that
- * DC in the complex baseband samples ends up at RF target_freq.
- *
- * \param chan which DUC channel we're controlling (usually == which_side).
- * \param db the daughterboard we're controlling.
- * \param target_freq the RF frequency we want our baseband translated to.
- * \param[out] result details how the hardware was configured.
- *
- * \returns true iff everything was successful.
- */
- bool tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result);
-
-
- // called in base class to derived class order
- bool start ();
- bool stop ();
-};
-
-#endif /* INCLUDED_USRP_STANDARD_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef INCLUDED_USRP_SUBDEV_SPEC_H
-#define INCLUDED_USRP_SUBDEV_SPEC_H
-
-/*!
- * \brief specify a daughterboard and subdevice on a daughterboard.
- *
- * In the USRP1, there are two sides, A and B.
- *
- * A daughterboard generally implements a single subdevice, but may in
- * general implement any number of subdevices. At this time, all daughterboards
- * with the exception of the Basic Rx and LF Rx implement a single subdevice.
- *
- * The Basic Rx and LF Rx implement 2 subdevices (soon 3). Subdevice
- * 0 routes input RX-A to the DDC I input and routes a constant zero
- * to the DDC Q input. Similarly, subdevice 1 routes input RX-B to
- * the DDC I input and routes a constant zero to the DDC Q
- * input. Subdevice 2 (when implemented) will route RX-A to the DDC I
- * input and RX-B to the DDC Q input.
- */
-
-struct usrp_subdev_spec {
- unsigned int side; // 0 -> A; 1 -> B
- unsigned int subdev; // which subdevice (usually zero)
-
- usrp_subdev_spec(unsigned int _side = 0, unsigned int _subdev = 0)
- : side(_side), subdev(_subdev) {}
-};
-
-#endif /* INCLUDED_USRP_SUBDEV_SPEC_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_USRP_TUNE_RESULT_H
-#define INCLUDED_USRP_TUNE_RESULT_H
-
-class usrp_tune_result
-{
-public:
- // RF frequency that corresponds to DC in the IF
- double baseband_freq;
-
- // frequency programmed into the DDC/DUC
- double dxc_freq;
-
- // residual frequency (typically < 0.01 Hz)
- double residual_freq;
-
- // is the spectrum inverted?
- bool inverted;
-
- usrp_tune_result(double baseband=0, double dxc=0, double residual=0, bool _inverted=false)
- : baseband_freq(baseband), dxc_freq(dxc),
- residual_freq(residual), inverted(_inverted) {}
-};
-
-#endif /* INCLUDED_USRP_TUNE_RESULT_H */
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#include <db_wbx.h>
+#include <fpga_regs_standard.h>
+#include <fpga_regs_common.h>
+#include <usrp_prims.h>
+#include <usrp_spi_defs.h>
+#include <stdexcept>
+#include <cmath>
+
+// d'board i/o pin defs
+
+// TX IO Pins
+#define TX_POWER (1 << 0) // TX Side Power
+#define RX_TXN (1 << 1) // T/R antenna switch for TX/RX port
+#define TX_ENB_MIX (1 << 2) // Enable IQ mixer
+#define TX_ENB_VGA (1 << 3)
+
+// RX IO Pins
+#define RX2_RX1N (1 << 0) // antenna switch between RX2 and TX/RX port
+#define RXENABLE (1 << 1) // enables mixer
+#define PLL_LOCK_DETECT (1 << 2) // Muxout pin from PLL -- MUST BE INPUT
+#define MReset (1 << 3) // NB6L239 Master Reset, asserted low
+#define SELA0 (1 << 4) // NB6L239 SelA0
+#define SELA1 (1 << 5) // NB6L239 SelA1
+#define SELB0 (1 << 6) // NB6L239 SelB0
+#define SELB1 (1 << 7) // NB6L239 SelB1
+#define PLL_ENABLE (1 << 8) // CE Pin on PLL
+#define AUX_SCLK (1 << 9) // ALT SPI SCLK
+#define AUX_SDO (1 << 10) // ALT SPI SDO
+#define AUX_SEN (1 << 11) // ALT SPI SEN
+
+
+wbx_base::wbx_base(usrp_basic_sptr usrp, int which)
+ : db_base(usrp, which)
+{
+ /*
+ * @param usrp: instance of usrp.source_c
+ * @param which: which side: 0 or 1 corresponding to side A or B respectively
+ * @type which: int
+ */
+
+ d_first = true;
+ d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
+
+ // FIXME -- the write reg functions don't work with 0xffff for masks
+ _rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff);
+ _rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE));
+
+ _tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff);
+ _tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); // TX off, TR switch set to RX
+
+ if(d_which == 0) {
+ d_spi_enable = SPI_ENABLE_RX_A;
+ }
+ else {
+ d_spi_enable = SPI_ENABLE_RX_B;
+ }
+
+ set_auto_tr(false);
+
+}
+
+wbx_base::~wbx_base()
+{
+ shutdown();
+}
+
+
+void
+wbx_base::shutdown()
+{
+ if (!d_is_shutdown){
+ d_is_shutdown = true;
+ // do whatever there is to do to shutdown
+
+ write_io(d_which, d_power_off, POWER_UP); // turn off power to board
+ _write_oe(d_which, 0, 0xffff); // turn off all outputs
+ set_auto_tr(false); // disable auto transmit
+ }
+}
+
+bool
+wbx_base::_lock_detect()
+{
+ /*
+ * @returns: the value of the VCO/PLL lock detect bit.
+ * @rtype: 0 or 1
+ */
+
+ if(_rx_read_io() & PLL_LOCK_DETECT) {
+ return true;
+ }
+ else { // Give it a second chance
+ if(_rx_read_io() & PLL_LOCK_DETECT) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+}
+
+bool
+wbx_base::_tx_write_oe(int value, int mask)
+{
+ int reg = (d_which == 0 ? FR_OE_0 : FR_OE_2);
+ return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
+}
+
+bool
+wbx_base::_rx_write_oe(int value, int mask)
+{
+ int reg = (d_which == 0 ? FR_OE_1 : FR_OE_3);
+ return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
+}
+
+bool
+wbx_base::_tx_write_io(int value, int mask)
+{
+ int reg = (d_which == 0 ? FR_IO_0 : FR_IO_2);
+ return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
+}
+
+bool
+wbx_base::_rx_write_io(int value, int mask)
+{
+ int reg = (d_which == 0 ? FR_IO_1 : FR_IO_3);
+ return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff));
+}
+
+bool
+wbx_base::_rx_read_io()
+{
+ int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B);
+ int t = d_usrp->_read_fpga_reg(reg);
+ return (t >> 16) & 0xffff;
+}
+
+bool
+wbx_base::_tx_read_io()
+{
+ int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B);
+ int t = d_usrp->_read_fpga_reg(reg);
+ return (t & 0xffff);
+}
+
+bool
+wbx_base::_compute_regs(double freq)
+{
+ /*
+ * Determine values of registers, along with actual freq.
+ *
+ * @param freq: target frequency in Hz
+ * @type freq: double
+ * @returns: (R, N, func, init, actual_freq)
+ * @rtype: tuple(int, int, int, int, double)
+ *
+ * Override this in derived classes.
+ */
+ throw std::runtime_error("_compute_regs called from base class\n");
+}
+
+double
+wbx_base::_refclk_freq()
+{
+ return (double)(d_usrp->fpga_master_clock_freq())/_refclk_divisor();
+}
+
+int
+wbx_base::_refclk_divisor()
+{
+ /*
+ * Return value to stick in REFCLK_DIVISOR register
+ */
+ return 1;
+}
+
+struct freq_result_t
+wbx_base::set_freq(double freq)
+{
+ /*
+ * @returns (ok, actual_baseband_freq) where:
+ * ok is True or False and indicates success or failure,
+ * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
+ */
+ throw std::runtime_error("set_freq called from base class\n");
+}
+
+float
+wbx_base::gain_min()
+{
+ throw std::runtime_error("gain_min called from base class\n");
+}
+
+float
+wbx_base::gain_max()
+{
+ throw std::runtime_error("gain_max called from base class\n");
+}
+
+float
+wbx_base::gain_db_per_step()
+{
+ throw std::runtime_error("gain_db_per_step called from base class\n");
+}
+
+bool
+wbx_base::set_gain(float gain)
+{
+ /*
+ * Set the gain.
+ *
+ * @param gain: gain in decibels
+ * @returns True/False
+ */
+ throw std::runtime_error("set_gain called from base class\n");
+}
+
+bool
+wbx_base::_set_pga(float pga_gain)
+{
+ bool ok;
+ if(d_which == 0) {
+ ok = d_usrp->set_pga(0, pga_gain);
+ ok |= d_usrp->set_pga(1, pga_gain);
+ }
+ else {
+ ok = d_usrp->set_pga(2, pga_gain);
+ ok |= d_usrp->set_pga(3, pga_gain);
+ }
+ return ok;
+}
+
+bool
+wbx_base::is_quadrature()
+{
+ /*
+ * Return True if this board requires both I & Q analog channels.
+ *
+ * This bit of info is useful when setting up the USRP Rx mux register.
+ */
+ return true;
+}
+
+
+/****************************************************************************/
+
+
+wbx_base_tx::wbx_base_tx(usrp_basic_sptr usrp, int which)
+ : wbx_base(usrp, which)
+{
+ /*
+ * @param usrp: instance of usrp.sink_c
+ * @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
+ */
+
+ // power up the transmit side, NO -- but set antenna to receive
+ d_usrp->write_io(d_which, (TX_POWER), (TX_POWER|RX_TXN));
+ d_lo_offset = 0e6;
+
+ // Gain is not set by the PGA, but the PGA must be set at max gain in the TX
+ _set_pga(d_usrp->pga_max());
+}
+
+wbx_base_tx::~wbx_base_tx()
+{
+ // Power down and leave the T/R switch in the R position
+ d_usrp->write_io(d_which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA));
+}
+
+void
+wbx_base_tx::set_auto_tr(bool on)
+{
+ if(on) {
+ set_atr_mask (RX_TXN);
+ set_atr_txval(0);
+ set_atr_rxval(RX_TXN);
+ }
+ else {
+ set_atr_mask (0);
+ set_atr_txval(0);
+ set_atr_rxval(0);
+ }
+}
+
+void
+wbx_base_tx::set_enable(bool on)
+{
+ /*
+ * Enable transmitter if on is True
+ */
+
+ int mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA;
+ //printf("HERE!!!!\n");
+ if(on) {
+ d_usrp->write_io(d_which, TX_ENB_MIX|TX_ENB_VGA, mask);
+ }
+ else {
+ d_usrp->write_io(d_which, RX_TXN, mask);
+ }
+}
+
+void
+wbx_base_tx::set_lo_offset(double offset)
+{
+ /*
+ * Set amount by which LO is offset from requested tuning frequency.
+ *
+ * @param offset: offset in Hz
+ */
+
+ d_lo_offset = offset;
+}
+
+double
+wbx_base_tx::lo_offset()
+{
+ /*
+ * Get amount by which LO is offset from requested tuning frequency.
+ *
+ * @returns Offset in Hz
+ */
+
+ return d_lo_offset;
+}
+
+
+/****************************************************************************/
+
+
+wbx_base_rx::wbx_base_rx(usrp_basic_sptr usrp, int which)
+ : wbx_base(usrp, which)
+{
+ /*
+ * @param usrp: instance of usrp.source_c
+ * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
+ */
+
+ // set up for RX on TX/RX port
+ select_rx_antenna("TX/RX");
+
+ bypass_adc_buffers(true);
+
+ d_lo_offset = 0.0;
+}
+
+wbx_base_rx::~wbx_base_rx()
+{
+ // Power down
+ d_usrp->write_io(d_which, 0, (RXENABLE));
+}
+
+void
+wbx_base_rx::set_auto_tr(bool on)
+{
+ if(on) {
+ // FIXME: where does ENABLE come from?
+ //set_atr_mask (ENABLE);
+ set_atr_txval( 0);
+ //set_atr_rxval(ENABLE);
+ }
+ else {
+ set_atr_mask (0);
+ set_atr_txval(0);
+ set_atr_rxval(0);
+ }
+}
+
+void
+wbx_base_rx::select_rx_antenna(int which_antenna)
+{
+ /*
+ * Specify which antenna port to use for reception.
+ * @param which_antenna: either 'TX/RX' or 'RX2'
+ */
+
+ if(which_antenna == 0) {
+ d_usrp->write_io(d_which, 0, RX2_RX1N);
+ }
+ else if(which_antenna == 1) {
+ d_usrp->write_io(d_which, RX2_RX1N, RX2_RX1N);
+ }
+ else {
+ throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
+ }
+}
+
+void
+wbx_base_rx::select_rx_antenna(const std::string &which_antenna)
+{
+ if(which_antenna == "TX/RX") {
+ select_rx_antenna(0);
+ }
+ else if(which_antenna == "RX2") {
+ select_rx_antenna(1);
+ }
+ else {
+ throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
+ }
+}
+
+bool
+wbx_base_rx::set_gain(float gain)
+{
+ /*
+ * Set the gain.
+ *
+ * @param gain: gain in decibels
+ * @returns True/False
+ */
+
+ float pga_gain, agc_gain;
+ float maxgain = gain_max() - d_usrp->pga_max();
+ float mingain = gain_min();
+ if(gain > maxgain) {
+ pga_gain = gain-maxgain;
+ assert(pga_gain <= d_usrp->pga_max());
+ agc_gain = maxgain;
+ }
+ else {
+ pga_gain = 0;
+ agc_gain = gain;
+ }
+
+ float V_maxgain = .2;
+ float V_mingain = 1.2;
+ float V_fullscale = 3.3;
+ float dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
+
+ assert(dac_value>=0 && dac_value<4096);
+
+ return d_usrp->write_aux_dac(d_which, 0, (int)(dac_value)) && _set_pga((int)(pga_gain));
+}
+
+void
+wbx_base_rx::set_lo_offset(double offset)
+{
+ /*
+ * Set amount by which LO is offset from requested tuning frequency.
+ *
+ * @param offset: offset in Hz
+ */
+ d_lo_offset = offset;
+}
+
+double
+wbx_base_rx::lo_offset()
+{
+ /*
+ * Get amount by which LO is offset from requested tuning frequency.
+ *
+ * @returns Offset in Hz
+ */
+ return d_lo_offset;
+}
+
+bool
+wbx_base_rx::i_and_q_swapped()
+{
+ /*
+ * Return True if this is a quadrature device and ADC 0 is Q.
+ */
+ return false;
+}
+
+
+/****************************************************************************/
+
+_ADF410X_common::_ADF410X_common()
+{
+ // R-Register Common Values
+ d_R_RSV = 0; // bits 23,22,21
+ d_LDP = 1; // bit 20 Lock detect in 5 cycles
+ d_TEST = 0; // bit 19,18 Normal
+ d_ABP = 0; // bit 17,16 2.9ns
+
+ // N-Register Common Values
+ d_N_RSV = 0; // 23,22
+ d_CP_GAIN = 0; // 21
+
+ // Function Register Common Values
+ d_P = 0; // bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65
+ d_PD2 = 0; // bit 21 Normal operation
+ d_CP2 = 4; // bits 20,19,18 CP Gain = 5mA
+ d_CP1 = 4; // bits 17,16,15 CP Gain = 5mA
+ d_TC = 0; // bits 14-11 PFD Timeout
+ d_FL = 0; // bit 10,9 Fastlock Disabled
+ d_CP3S = 0; // bit 8 CP Enabled
+ d_PDP = 0; // bit 7 Phase detector polarity, Positive=1
+ d_MUXOUT = 1; // bits 6:4 Digital Lock Detect
+ d_PD1 = 0; // bit 3 Normal operation
+ d_CR = 0; // bit 2 Normal operation
+}
+
+_ADF410X_common::~_ADF410X_common()
+{
+}
+
+bool
+_ADF410X_common::_compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq)
+{
+ /*
+ * Determine values of R, control, and N registers, along with actual freq.
+ *
+ * @param freq: target frequency in Hz
+ * @type freq: double
+ * @returns: (R, N, control, actual_freq)
+ * @rtype: tuple(int, int, int, double)
+ */
+
+ // Band-specific N-Register Values
+ double phdet_freq = _refclk_freq()/d_R_DIV;
+ printf("phdet_freq = %f\n", phdet_freq);
+
+ double desired_n = round(freq*d_freq_mult/phdet_freq);
+ printf("desired_n %f\n", desired_n);
+
+ double actual_freq = desired_n * phdet_freq;
+ printf("actual freq %f\n", actual_freq);
+
+ double B = floor(desired_n/_prescaler());
+ double A = desired_n - _prescaler()*B;
+ printf("A %f B %f\n", A, B);
+
+ d_B_DIV = int(B); // bits 20:8;
+ d_A_DIV = int(A); // bit 6:2;
+
+ if(d_B_DIV < d_A_DIV) {
+ retR = 0;
+ retN = 0;
+ retcontrol = 0;
+ retfreq = 0;
+ return false;
+ }
+
+ retR = (d_R_RSV<<21) | (d_LDP<<20) | (d_TEST<<18) |
+ (d_ABP<<16) | (d_R_DIV<<2);
+
+ retN = (d_N_RSV<<22) | (d_CP_GAIN<<21) | (d_B_DIV<<8) | (d_A_DIV<<2);
+
+ retcontrol = (d_P<<22) | (d_PD2<<21) | (d_CP2<<18) | (d_CP1<<15) |
+ (d_TC<<11) | (d_FL<<9) | (d_CP3S<<8) | (d_PDP<<7) |
+ (d_MUXOUT<<4) | (d_PD1<<3) | (d_CR<<2);
+
+ retfreq = actual_freq/d_freq_mult;
+
+ return true;
+}
+
+void
+_ADF410X_common::_write_all(int R, int N, int control)
+{
+ /*
+ * Write all PLL registers:
+ * R counter latch,
+ * N counter latch,
+ * Function latch,
+ * Initialization latch
+ *
+ * Adds 10ms delay between writing control and N if this is first call.
+ * This is the required power-up sequence.
+ *
+ * @param R: 24-bit R counter latch
+ * @type R: int
+ * @param N: 24-bit N counter latch
+ * @type N: int
+ * @param control: 24-bit control latch
+ * @type control: int
+ */
+ static bool first = true;
+
+ timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 10000000;
+
+ _write_R(R);
+ _write_func(control);
+ _write_init(control);
+ if(first) {
+ //time.sleep(0.010);
+ nanosleep(&t, NULL);
+ first = false;
+ }
+ _write_N(N);
+}
+
+void
+_ADF410X_common::_write_R(int R)
+{
+ _write_it((R & ~0x3) | 0);
+}
+
+void
+_ADF410X_common::_write_N(int N)
+{
+ _write_it((N & ~0x3) | 1);
+}
+
+void
+_ADF410X_common::_write_func(int func)
+{
+ _write_it((func & ~0x3) | 2);
+}
+
+void
+_ADF410X_common::_write_init(int init)
+{
+ _write_it((init & ~0x3) | 3);
+}
+
+void
+_ADF410X_common::_write_it(int v)
+{
+ char c[3];
+ c[0] = (char)((v >> 16) & 0xff);
+ c[1] = (char)((v >> 8) & 0xff);
+ c[2] = (char)((v & 0xff));
+ std::string s(c, 3);
+ //d_usrp->_write_spi(0, d_spi_enable, d_spi_format, s);
+ usrp()->_write_spi(0, d_spi_enable, d_spi_format, s);
+}
+
+int
+_ADF410X_common::_prescaler()
+{
+ if(d_P == 0) {
+ return 8;
+ }
+ else if(d_P == 1) {
+ return 16;
+ }
+ else if(d_P == 2) {
+ return 32;
+ }
+ else if(d_P == 3) {
+ return 64;
+ }
+ else {
+ throw std::invalid_argument("Prescaler out of range\n");
+ }
+}
+
+double
+_ADF410X_common::_refclk_freq()
+{
+ throw std::runtime_error("_refclk_freq called from base class.");
+}
+
+bool
+_ADF410X_common::_rx_write_io(int value, int mask)
+{
+ throw std::runtime_error("_rx_write_io called from base class.");
+}
+
+bool
+_ADF410X_common::_lock_detect()
+{
+ throw std::runtime_error("_lock_detect called from base class.");
+}
+
+usrp_basic*
+_ADF410X_common::usrp()
+{
+ throw std::runtime_error("usrp() called from base class.");
+}
+
+
+/****************************************************************************/
+
+
+_lo_common::_lo_common()
+ : _ADF410X_common()
+{
+ // Band-specific R-Register Values
+ d_R_DIV = 4; // bits 15:2
+
+ // Band-specific C-Register values
+ d_P = 0; // bits 23,22 0 = Div by 8/9
+ d_CP2 = 4; // bits 19:17
+ d_CP1 = 4; // bits 16:14
+
+ // Band specifc N-Register Values
+ d_DIVSEL = 0; // bit 23
+ d_DIV2 = 0; // bit 22
+ d_CPGAIN = 0; // bit 21
+ d_freq_mult = 1;
+
+ d_div = 1;
+ d_aux_div = 2;
+ d_main_div = 0;
+}
+
+_lo_common::~_lo_common()
+{
+}
+
+double
+_lo_common::freq_min()
+{
+ return 50e6;
+}
+
+double
+_lo_common::freq_max()
+{
+ return 1000e6;
+}
+
+void
+_lo_common::set_divider(int main_or_aux, int divisor)
+{
+ if(main_or_aux == 0) {
+ if((divisor != 1) || (divisor != 2) || (divisor != 4) || (divisor != 8)) {
+ throw std::invalid_argument("Main Divider Must be 1, 2, 4, or 8\n");
+ }
+ d_main_div = (int)(log10(divisor)/log10(2.0));
+ }
+ else if(main_or_aux == 1) {
+ if((divisor != 2) || (divisor != 4) || (divisor != 8) || (divisor != 16)) {
+ throw std::invalid_argument("Aux Divider Must be 2, 4, 8 or 16\n");
+ }
+ d_main_div = (int)(log10(divisor/2.0)/log10(2.0));
+ }
+ else {
+ throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n");
+ }
+
+ int vala = d_main_div*SELA0;
+ int valb = d_aux_div*SELB0;
+ int mask = SELA0|SELA1|SELB0|SELB1;
+
+ _rx_write_io((vala | valb), mask);
+}
+
+void
+_lo_common::set_divider(const std::string &main_or_aux, int divisor)
+{
+ if(main_or_aux == "main") {
+ set_divider(0, divisor);
+ }
+ else if(main_or_aux == "aux") {
+ set_divider(1, divisor);
+ }
+ else {
+ throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n");
+ }
+}
+
+struct freq_result_t
+_lo_common::set_freq(double freq)
+{
+ struct freq_result_t ret;
+
+ if(freq < 20e6 or freq > 1200e6) {
+ throw std::invalid_argument("Requested frequency out of range\n");
+ }
+
+ int div = 1;
+ double lo_freq = freq * 2;
+ while((lo_freq < 1e9) && (div < 8)) {
+ div = div * 2;
+ lo_freq = lo_freq * 2;
+ }
+
+ printf("For RF freq of %f, we set DIV=%d and LO Freq=%f\n", freq, div, lo_freq);
+
+ set_divider("main", div);
+ set_divider("aux", div*2);
+
+ int R, N, control;
+ double actual_freq;
+ _compute_regs(lo_freq, R, N, control, actual_freq);
+
+ printf("R %d N %d control %d actual freq %f\n", R, N, control, actual_freq);
+ if(R==0) {
+ ret.ok = false;
+ ret.baseband_freq = 0.0;
+ return ret;
+ }
+ _write_all(R, N, control);
+
+ ret.ok = _lock_detect();
+ ret.baseband_freq = actual_freq/div/2;
+ return ret;
+}
+
+
+/****************************************************************************/
+
+
+db_wbx_lo_tx::db_wbx_lo_tx(usrp_basic_sptr usrp, int which)
+ : _lo_common(),
+ wbx_base_tx(usrp, which)
+{
+}
+
+db_wbx_lo_tx::~db_wbx_lo_tx()
+{
+}
+
+float
+db_wbx_lo_tx::gain_min()
+{
+ return -56.0;
+}
+
+float
+db_wbx_lo_tx::gain_max()
+{
+ return 0.0;
+}
+
+float
+db_wbx_lo_tx::gain_db_per_step()
+{
+ return 0.1;
+}
+
+bool
+db_wbx_lo_tx::set_gain(float gain)
+{
+ /*
+ * Set the gain.
+ *
+ * @param gain: gain in decibels
+ * @returns True/False
+ */
+
+ float txvga_gain;
+ float maxgain = gain_max();
+ float mingain = gain_min();
+ if(gain > maxgain) {
+ txvga_gain = maxgain;
+ }
+ else if(gain < mingain) {
+ txvga_gain = mingain;
+ }
+ else {
+ txvga_gain = gain;
+ }
+
+ float V_maxgain = 1.4;
+ float V_mingain = 0.1;
+ float V_fullscale = 3.3;
+ float dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/
+ (maxgain-mingain) + V_mingain)*4096/V_fullscale;
+
+ assert(dac_value>=0 && dac_value<4096);
+ printf("DAC value %f\n", dac_value);
+
+ return d_usrp->write_aux_dac(d_which, 1, (int)(dac_value));
+}
+
+double
+db_wbx_lo_tx::_refclk_freq()
+{
+ return wbx_base::_refclk_freq();
+}
+
+bool
+db_wbx_lo_tx::_rx_write_io(int value, int mask)
+{
+ return wbx_base::_rx_write_io(value, mask);
+}
+
+bool
+db_wbx_lo_tx::_lock_detect()
+{
+ return wbx_base::_lock_detect();
+}
+
+usrp_basic*
+db_wbx_lo_tx::usrp()
+{
+ return d_usrp;
+}
+
+
+/****************************************************************************/
+
+
+db_wbx_lo_rx::db_wbx_lo_rx(usrp_basic_sptr usrp, int which)
+ : _lo_common(),
+ wbx_base_rx(usrp, which)
+{
+}
+
+db_wbx_lo_rx::~db_wbx_lo_rx()
+{
+}
+
+float
+db_wbx_lo_rx::gain_min()
+{
+ return d_usrp->pga_min();
+}
+
+float
+db_wbx_lo_rx::gain_max()
+{
+ return d_usrp->pga_max() + 45;
+}
+
+float
+db_wbx_lo_rx::gain_db_per_step()
+{
+ return 0.05;
+}
+
+double
+db_wbx_lo_rx::_refclk_freq()
+{
+ return wbx_base::_refclk_freq();
+}
+
+bool
+db_wbx_lo_rx::_rx_write_io(int value, int mask)
+{
+ return wbx_base::_rx_write_io(value, mask);
+}
+
+bool
+db_wbx_lo_rx::_lock_detect()
+{
+ return wbx_base::_lock_detect();
+}
+
+usrp_basic*
+db_wbx_lo_rx::usrp()
+{
+ return d_usrp;
+}
--- /dev/null
+/* -*- c++ -*- */
+//
+// Copyright 2008 Free Software Foundation, Inc.
+//
+// This file is part of GNU Radio
+//
+// GNU Radio is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either asversion 3, or (at your option)
+// any later version.
+//
+// GNU Radio is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GNU Radio; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 51 Franklin Street,
+// Boston, MA 02110-1301, USA.
+
+#ifndef DB_WBX_H
+#define DB_WBX_H
+
+#include <db_base.h>
+#include <boost/shared_ptr.hpp>
+
+
+/*
+ A few comments about the WBX boards:
+ They are half-duplex. I.e., transmit and receive are mutually exclusive.
+ There is a single LO for both the Tx and Rx sides.
+ The the shared control signals are hung off of the Rx side.
+ The shared io controls are duplexed onto the Rx side pins.
+ The wbx_high d'board always needs to be in 'auto_tr_mode'
+*/
+
+
+class wbx_base : public db_base
+{
+protected:
+ void shutdown();
+
+ /*
+ * Abstract base class for all wbx boards.
+ *
+ * Derive board specific subclasses from db_wbx_base_{tx,rx}
+ */
+
+public:
+ wbx_base(usrp_basic_sptr usrp, int which);
+ ~wbx_base();
+
+ struct freq_result_t set_freq(double freq);
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool set_gain(float gain);
+ bool is_quadrature();
+
+
+protected:
+ virtual bool _lock_detect();
+
+ // FIXME: After testing, replace these with usrp_basic::common_write_io/oe
+ bool _tx_write_oe(int value, int mask);
+ bool _rx_write_oe(int value, int mask);
+ bool _tx_write_io(int value, int mask);
+ bool _rx_write_io(int value, int mask);
+ virtual bool _rx_read_io();
+ bool _tx_read_io();
+ bool _compute_regs(double freq);
+ virtual double _refclk_freq();
+ int _refclk_divisor();
+
+ bool _set_pga(float pga_gain);
+
+ bool d_first;
+ int d_spi_format;
+ int d_spi_enable;
+ double d_lo_offset;
+};
+
+
+/****************************************************************************/
+
+
+class wbx_base_tx : public wbx_base
+{
+public:
+ wbx_base_tx(usrp_basic_sptr usrp, int which);
+ ~wbx_base_tx();
+
+ bool set_auto_tr(bool on);
+ bool set_enable(bool on);
+};
+
+
+/****************************************************************************/
+
+
+class wbx_base_rx : public wbx_base
+{
+public:
+ wbx_base_rx(usrp_basic_sptr usrp, int which);
+ ~wbx_base_rx();
+
+ bool set_auto_tr(bool on);
+ bool select_rx_antenna(int which_antenna);
+ bool select_rx_antenna(const std::string &which_antenna);
+ bool set_gain(float gain);
+ bool i_and_q_swapped();
+};
+
+
+/****************************************************************************/
+
+
+class _ADF410X_common
+{
+public:
+ _ADF410X_common();
+ virtual ~_ADF410X_common();
+
+ bool _compute_regs(double freq, int &retR, int &retcontrol,
+ int &retN, double &retfreq);
+ void _write_all(int R, int N, int control);
+ void _write_R(int R);
+ void _write_N(int N);
+ void _write_func(int func);
+ void _write_init(int init);
+ int _prescaler();
+ virtual void _write_it(int v);
+ virtual double _refclk_freq();
+ virtual bool _rx_write_io(int value, int mask);
+ virtual bool _lock_detect();
+
+protected:
+ virtual usrp_basic* usrp();
+
+ int d_R_RSV, d_LDP, d_TEST, d_ABP;
+ int d_N_RSV, d_CP_GAIN;
+ int d_P, d_PD2, d_CP2, d_CP1, d_TC, d_FL;
+ int d_CP3S, d_PDP, d_MUXOUT, d_PD1, d_CR;
+ int d_R_DIV, d_A_DIV, d_B_DIV;
+ int d_freq_mult;
+
+ int d_spi_format;
+ int d_spi_enable;
+};
+
+
+/****************************************************************************/
+
+
+class _lo_common : public _ADF410X_common
+{
+public:
+ _lo_common();
+ ~_lo_common();
+
+ double freq_min();
+ double freq_max();
+
+ void set_divider(int main_or_aux, int divisor);
+ void set_divider(const std::string &main_or_aux, int divisor);
+
+ struct freq_result_t set_freq(double freq);
+
+protected:
+ int d_R_DIV, d_P, d_CP2, d_CP1;
+ int d_DIVSEL, d_DIV2, d_CPGAIN;
+ int d_div, d_aux_div, d_main_div;
+};
+
+
+/****************************************************************************/
+
+
+class db_wbx_lo_tx : public _lo_common, public wbx_base_tx
+{
+public:
+ db_wbx_lo_tx(usrp_basic_sptr usrp, int which);
+ ~db_wbx_lo_tx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+ bool set_gain(float gain);
+
+ double _refclk_freq();
+ bool _rx_write_io(int value, int mask);
+ bool _lock_detect();
+
+protected:
+ usrp_basic* usrp();
+};
+
+
+/****************************************************************************/
+
+
+class db_wbx_lo_rx : public _lo_common, public wbx_base_rx
+{
+public:
+ db_wbx_lo_rx(usrp_basic_sptr usrp, int which);
+ ~db_wbx_lo_rx();
+
+ float gain_min();
+ float gain_max();
+ float gain_db_per_step();
+
+ double _refclk_freq();
+ bool _rx_write_io(int value, int mask);
+ bool _lock_detect();
+
+protected:
+ usrp_basic* usrp();
+};
+
+#endif
--- /dev/null
+/* 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 3, 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., 51 Franklin Street, Boston, MA 02110-1301, 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;
+}
--- /dev/null
+/* 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 3, 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., 51 Franklin Street, Boston, MA 02110-1301, 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
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _INCLUDED_MLD_THREADS_H_
+#define _INCLUDED_MLD_THREADS_H_
+
+/* classes which allow for either pthreads or omni_threads */
+
+#define __macos__
+#ifdef _USE_OMNI_THREADS_
+#include <gnuradio/omnithread.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <stdexcept>
+
+#define __INLINE__ inline
+
+#ifndef DO_DEBUG
+#define DO_DEBUG 0
+#endif
+
+#if DO_DEBUG
+#define DEBUG(X) do{X} while(0);
+#else
+#define DEBUG(X) do{} while(0);
+#endif
+
+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_i_own_mutex;
+
+public:
+ __INLINE__ mld_condition_t (mld_mutex_ptr mutex = NULL) {
+ if (mutex) {
+ d_i_own_mutex = false;
+ d_mutex = mutex;
+ } else {
+ d_i_own_mutex = true;
+ 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;
+ if (d_i_own_mutex)
+ delete d_mutex;
+ d_mutex = NULL;
+ };
+
+ __INLINE__ mld_mutex_ptr mutex () {return (d_mutex);};
+
+ __INLINE__ void signal () {
+ DEBUG (fprintf (stderr, "a "););
+
+#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
+ DEBUG (fprintf (stderr, "b "););
+ };
+
+ __INLINE__ void wait () {
+ DEBUG (fprintf (stderr, "c "););
+#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
+ DEBUG (fprintf (stderr, "d "););
+ };
+};
+
+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_ */
--- /dev/null
+ { 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 }
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+static const char *std_paths[] = {
+ "@prefix@/share/usrp",
+ "/usr/local/share/usrp",
+ 0
+};
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <usrp/usrp_basic.h>
+#include "usrp/usrp_prims.h"
+#include "usrp_interfaces.h"
+#include "fpga_regs_common.h"
+#include "fpga_regs_standard.h"
+#include "fusb.h"
+#include "db_boards.h"
+#include <usb.h>
+#include <stdexcept>
+#include <assert.h>
+#include <math.h>
+#include <ad9862.h>
+#include <string.h>
+#include <cstdio>
+
+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 = fusb_sysconfig::default_buffer_size();
+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), d_fpga_master_clock_freq(64000000), d_db(2)
+{
+ /*
+ * 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
+}
+
+void
+usrp_basic::shutdown_daughterboards()
+{
+ // nuke d'boards before we close down USB in ~usrp_basic
+ // shutdown() will do any board shutdown while the USRP can still
+ // be talked to
+ for(size_t i = 0; i < d_db.size(); i++)
+ for(size_t j = 0; j < d_db[i].size(); j++)
+ d_db[i][j]->shutdown();
+}
+
+usrp_basic::~usrp_basic ()
+{
+ // shutdown_daughterboards(); // call from ~usrp_basic_{tx,rx}
+
+ d_db.resize(0); // forget db shared ptrs
+
+ if (d_udh)
+ usb_close (d_udh);
+}
+
+void
+usrp_basic::init_db(usrp_basic_sptr u)
+{
+ if (u.get() != this)
+ throw std::invalid_argument("u is not this");
+
+ d_db[0] = instantiate_dbs(d_dbid[0], u, 0);
+ d_db[1] = instantiate_dbs(d_dbid[1], u, 1);
+}
+
+std::vector<db_base_sptr>
+usrp_basic::db(int which_side)
+{
+ which_side &= 0x1; // clamp it to avoid any reporting any errors
+ return d_db[which_side];
+}
+
+bool
+usrp_basic::is_valid(const usrp_subdev_spec &ss)
+{
+ if (ss.side < 0 || ss.side > 1)
+ return false;
+
+ if (ss.subdev < 0 || ss.subdev >= d_db[ss.side].size())
+ return false;
+
+ return true;
+}
+
+db_base_sptr
+usrp_basic::selected_subdev(const usrp_subdev_spec &ss)
+{
+ if (!is_valid(ss))
+ throw std::invalid_argument("invalid subdev_spec");
+
+ return d_db[ss.side][ss.subdev];
+}
+
+bool
+usrp_basic::start ()
+{
+ 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_adc, int offset)
+{
+ if (which_adc < 0 || which_adc > 3)
+ return false;
+
+ return _write_fpga_reg (FR_ADC_OFFSET_0 + which_adc, offset);
+}
+
+bool
+usrp_basic::set_dac_offset (int which_dac, int offset, int offset_pin)
+{
+ if (which_dac < 0 || which_dac > 3)
+ return false;
+
+ int which_codec = which_dac >> 1;
+ int tx_a = (which_dac & 0x1) == 0;
+ int lo = ((offset & 0x3) << 6) | (offset_pin & 0x1);
+ int hi = (offset >> 2);
+ bool ok;
+
+ 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_adc, bool bypass)
+{
+ if (which_adc < 0 || which_adc > 3)
+ return false;
+
+ int codec = which_adc >> 1;
+ int reg = (which_adc & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+ unsigned char cur_rx;
+ unsigned char cur_pwr_dn;
+
+ // 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_adc & 1) == 0) ? RX_PWR_DN_BUF_A : RX_PWR_DN_BUF_B;
+ }
+ else {
+ cur_rx &= ~RX_X_BYPASS_INPUT_BUFFER;
+ cur_pwr_dn &= ~(((which_adc & 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::set_dc_offset_cl_enable(int bits, int mask)
+{
+ return _write_fpga_reg(FR_DC_OFFSET_CL_EN,
+ (d_fpga_shadows[FR_DC_OFFSET_CL_EN] & ~mask) | (bits & mask));
+}
+
+// ----------------------------------------------------------------
+
+bool
+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_led, bool on)
+{
+ return usrp_set_led (d_udh, which_led, on);
+}
+
+bool
+usrp_basic::write_atr_tx_delay(int value)
+{
+ return _write_fpga_reg(FR_ATR_TX_DELAY, value);
+}
+
+bool
+usrp_basic::write_atr_rx_delay(int value)
+{
+ return _write_fpga_reg(FR_ATR_RX_DELAY, value);
+}
+
+/*
+ * ----------------------------------------------------------------
+ * Routines to access and control daughterboard specific i/o
+ * ----------------------------------------------------------------
+ */
+static int
+slot_id_to_oe_reg (int slot_id)
+{
+ static int reg[4] = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_io_reg (int slot_id)
+{
+ static int reg[4] = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_refclk_reg(int slot_id)
+{
+ static int reg[4] = { FR_TX_A_REFCLK, FR_RX_A_REFCLK, FR_TX_B_REFCLK, FR_RX_B_REFCLK };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_atr_mask_reg(int slot_id)
+{
+ static int reg[4] = { FR_ATR_MASK_0, FR_ATR_MASK_1, FR_ATR_MASK_2, FR_ATR_MASK_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_atr_txval_reg(int slot_id)
+{
+ static int reg[4] = { FR_ATR_TXVAL_0, FR_ATR_TXVAL_1, FR_ATR_TXVAL_2, FR_ATR_TXVAL_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_atr_rxval_reg(int slot_id)
+{
+ static int reg[4] = { FR_ATR_RXVAL_0, FR_ATR_RXVAL_1, FR_ATR_RXVAL_2, FR_ATR_RXVAL_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+to_slot(txrx_t txrx, int which_side)
+{
+ // TX_A = 0
+ // RX_A = 1
+ // TX_B = 2
+ // RX_B = 3
+ return ((which_side & 0x1) << 1) | ((txrx & 0x1) == C_RX);
+}
+
+bool
+usrp_basic::common_set_pga(txrx_t txrx, int which_amp, double gain)
+{
+ if (which_amp < 0 || which_amp > 3)
+ return false;
+
+ gain = std::min(common_pga_max(txrx),
+ std::max(common_pga_min(txrx), gain));
+
+ int codec = which_amp >> 1;
+ int int_gain = (int) rint((gain - common_pga_min(txrx)) / common_pga_db_per_step(txrx));
+
+ if (txrx == C_TX){ // 0 and 1 are same, as are 2 and 3
+ return _write_9862(codec, REG_TX_PGA, int_gain);
+ }
+ else {
+ int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+ // read current value to get input buffer bypass flag.
+ unsigned char cur_rx;
+ if (!_read_9862(codec, reg, &cur_rx))
+ return false;
+
+ cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
+ return _write_9862(codec, reg, cur_rx);
+ }
+}
+
+double
+usrp_basic::common_pga(txrx_t txrx, int which_amp) const
+{
+ if (which_amp < 0 || which_amp > 3)
+ return READ_FAILED;
+
+ if (txrx == C_TX){
+ int codec = which_amp >> 1;
+ unsigned char v;
+ bool ok = _read_9862 (codec, REG_TX_PGA, &v);
+ if (!ok)
+ return READ_FAILED;
+
+ return (pga_db_per_step() * v) + pga_min();
+ }
+ else {
+ int codec = which_amp >> 1;
+ int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B;
+ unsigned char v;
+ bool ok = _read_9862 (codec, reg, &v);
+ if (!ok)
+ return READ_FAILED;
+
+ return (pga_db_per_step() * (v & 0x1f)) + pga_min();
+ }
+}
+
+double
+usrp_basic::common_pga_min(txrx_t txrx) const
+{
+ if (txrx == C_TX)
+ return -20.0;
+ else
+ return 0.0;
+}
+
+double
+usrp_basic::common_pga_max(txrx_t txrx) const
+{
+ if (txrx == C_TX)
+ return 0.0;
+ else
+ return 20.0;
+}
+
+double
+usrp_basic::common_pga_db_per_step(txrx_t txrx) const
+{
+ if (txrx == C_TX)
+ return 20.0 / 255;
+ else
+ return 20.0 / 20;
+}
+
+bool
+usrp_basic::_common_write_oe(txrx_t txrx, int which_side, int value, int mask)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_oe_reg(to_slot(txrx, which_side)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic::common_write_io(txrx_t txrx, int which_side, int value, int mask)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_io_reg(to_slot(txrx, which_side)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic::common_read_io(txrx_t txrx, int which_side, int *value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ int t;
+ int reg = which_side + 1; // FIXME, *very* magic number (fix in serial_io.v)
+ bool ok = _read_fpga_reg(reg, &t);
+ if (!ok)
+ return false;
+
+ if (txrx == C_TX){
+ *value = t & 0xffff; // FIXME, more magic
+ return true;
+ }
+ else {
+ *value = (t >> 16) & 0xffff; // FIXME, more magic
+ return true;
+ }
+}
+
+int
+usrp_basic::common_read_io(txrx_t txrx, int which_side)
+{
+ int value;
+ if (!common_read_io(txrx, which_side, &value))
+ return READ_FAILED;
+ return value;
+}
+
+bool
+usrp_basic::common_write_refclk(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_refclk_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_atr_mask(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_atr_mask_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_atr_txval(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_atr_txval_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_atr_rxval(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_atr_rxval_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value)
+{
+ return _write_aux_dac(to_slot(txrx, which_side), which_dac, value);
+}
+
+bool
+usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value)
+{
+ return _read_aux_adc(to_slot(txrx, which_side), which_adc, value);
+}
+
+int
+usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc)
+{
+ return _read_aux_adc(to_slot(txrx, which_side), which_adc);
+}
+
+
+////////////////////////////////////////////////////////////////
+//
+// usrp_basic_rx
+//
+////////////////////////////////////////////////////////////////
+
+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);
+
+ //d_db[0] = instantiate_dbs(d_dbid[0], this, 0);
+ //d_db[1] = instantiate_dbs(d_dbid[1], this, 1);
+
+ // check fusb buffering parameters
+
+ if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+ 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_sysconfig::default_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_atr_mask(0, 0); // zero Rx A Auto Transmit/Receive regs
+ write_atr_txval(0, 0);
+ write_atr_rxval(0, 0);
+ write_atr_mask(1, 0); // zero Rx B Auto Transmit/Receive regs
+ write_atr_txval(1, 0);
+ write_atr_rxval(1, 0);
+}
+
+static unsigned char rx_fini_regs[] = {
+ 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");
+ }
+
+ shutdown_daughterboards();
+}
+
+
+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 (!set_rx_enable(false)){
+ fprintf (stderr, "usrp_basic_rx: set_rx_enable(false) failed\n");
+ usb_strerror ();
+ ok = false;
+ }
+
+ if (!d_ephandle->stop()){
+ fprintf (stderr, "usrp_basic_rx: failed to stop end point streaming");
+ usb_strerror ();
+ ok = false;
+ }
+
+ return ok;
+}
+
+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);
+}
+
+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::set_pga (int which_amp, double gain)
+{
+ return common_set_pga(C_RX, which_amp, gain);
+}
+
+double
+usrp_basic_rx::pga(int which_amp) const
+{
+ return common_pga(C_RX, which_amp);
+}
+
+double
+usrp_basic_rx::pga_min() const
+{
+ return common_pga_min(C_RX);
+}
+
+double
+usrp_basic_rx::pga_max() const
+{
+ return common_pga_max(C_RX);
+}
+
+double
+usrp_basic_rx::pga_db_per_step() const
+{
+ return common_pga_db_per_step(C_RX);
+}
+
+bool
+usrp_basic_rx::_write_oe (int which_side, int value, int mask)
+{
+ return _common_write_oe(C_RX, which_side, value, mask);
+}
+
+bool
+usrp_basic_rx::write_io (int which_side, int value, int mask)
+{
+ return common_write_io(C_RX, which_side, value, mask);
+}
+
+bool
+usrp_basic_rx::read_io (int which_side, int *value)
+{
+ return common_read_io(C_RX, which_side, value);
+}
+
+int
+usrp_basic_rx::read_io (int which_side)
+{
+ return common_read_io(C_RX, which_side);
+}
+
+bool
+usrp_basic_rx::write_refclk(int which_side, int value)
+{
+ return common_write_refclk(C_RX, which_side, value);
+}
+
+bool
+usrp_basic_rx::write_atr_mask(int which_side, int value)
+{
+ return common_write_atr_mask(C_RX, which_side, value);
+}
+
+bool
+usrp_basic_rx::write_atr_txval(int which_side, int value)
+{
+ return common_write_atr_txval(C_RX, which_side, value);
+}
+
+bool
+usrp_basic_rx::write_atr_rxval(int which_side, int value)
+{
+ return common_write_atr_rxval(C_RX, which_side, value);
+}
+
+bool
+usrp_basic_rx::write_aux_dac (int which_side, int which_dac, int value)
+{
+ return common_write_aux_dac(C_RX, which_side, which_dac, value);
+}
+
+bool
+usrp_basic_rx::read_aux_adc (int which_side, int which_adc, int *value)
+{
+ return common_read_aux_adc(C_RX, which_side, which_adc, value);
+}
+
+int
+usrp_basic_rx::read_aux_adc (int which_side, int which_adc)
+{
+ return common_read_aux_adc(C_RX, which_side, which_adc);
+}
+
+int
+usrp_basic_rx::block_size () const { return d_ephandle->block_size(); }
+
+////////////////////////////////////////////////////////////////
+//
+// usrp_basic_tx
+//
+////////////////////////////////////////////////////////////////
+
+
+//
+// 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);
+
+ //d_db[0] = instantiate_dbs(d_dbid[0], this, 0);
+ //d_db[1] = instantiate_dbs(d_dbid[1], this, 1);
+
+ // check fusb buffering parameters
+
+ if (fusb_block_size < 0 || fusb_block_size > FUSB_BLOCK_SIZE)
+ 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_atr_mask(0, 0); // zero Tx A Auto Transmit/Receive regs
+ write_atr_txval(0, 0);
+ write_atr_rxval(0, 0);
+ write_atr_mask(1, 0); // zero Tx B Auto Transmit/Receive regs
+ write_atr_txval(1, 0);
+ write_atr_rxval(1, 0);
+}
+
+
+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");
+ }
+
+ shutdown_daughterboards();
+}
+
+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 (!d_ephandle->stop ()){
+ fprintf (stderr, "usrp_basic_tx: failed to stop end point streaming");
+ usb_strerror ();
+ ok = false;
+ }
+
+ if (!set_tx_enable (false)){
+ fprintf (stderr, "usrp_basic_tx: set_tx_enable(false) failed\n");
+ 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);
+}
+
+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::set_pga (int which_amp, double gain)
+{
+ return common_set_pga(C_TX, which_amp, gain);
+}
+
+double
+usrp_basic_tx::pga (int which_amp) const
+{
+ return common_pga(C_TX, which_amp);
+}
+
+double
+usrp_basic_tx::pga_min() const
+{
+ return common_pga_min(C_TX);
+}
+
+double
+usrp_basic_tx::pga_max() const
+{
+ return common_pga_max(C_TX);
+}
+
+double
+usrp_basic_tx::pga_db_per_step() const
+{
+ return common_pga_db_per_step(C_TX);
+}
+
+bool
+usrp_basic_tx::_write_oe (int which_side, int value, int mask)
+{
+ return _common_write_oe(C_TX, which_side, value, mask);
+}
+
+bool
+usrp_basic_tx::write_io (int which_side, int value, int mask)
+{
+ return common_write_io(C_TX, which_side, value, mask);
+}
+
+bool
+usrp_basic_tx::read_io (int which_side, int *value)
+{
+ return common_read_io(C_TX, which_side, value);
+}
+
+int
+usrp_basic_tx::read_io (int which_side)
+{
+ return common_read_io(C_TX, which_side);
+}
+
+bool
+usrp_basic_tx::write_refclk(int which_side, int value)
+{
+ return common_write_refclk(C_TX, which_side, value);
+}
+
+bool
+usrp_basic_tx::write_atr_mask(int which_side, int value)
+{
+ return common_write_atr_mask(C_TX, which_side, value);
+}
+
+bool
+usrp_basic_tx::write_atr_txval(int which_side, int value)
+{
+ return common_write_atr_txval(C_TX, which_side, value);
+}
+
+bool
+usrp_basic_tx::write_atr_rxval(int which_side, int value)
+{
+ return common_write_atr_rxval(C_TX, which_side, value);
+}
+
+bool
+usrp_basic_tx::write_aux_dac (int which_side, int which_dac, int value)
+{
+ return common_write_aux_dac(C_TX, which_side, which_dac, value);
+}
+
+bool
+usrp_basic_tx::read_aux_adc (int which_side, int which_adc, int *value)
+{
+ return common_read_aux_adc(C_TX, which_side, which_adc, value);
+}
+
+int
+usrp_basic_tx::read_aux_adc (int which_side, int which_adc)
+{
+ return common_read_aux_adc(C_TX, which_side, which_adc);
+}
+
+int
+usrp_basic_tx::block_size () const { return d_ephandle->block_size(); }
+
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "usrp_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;
+}
--- /dev/null
+/* -*- 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 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _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_ */
--- /dev/null
+#
+# Copyright 2005,2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+# 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 ClkMod" 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
+"DTT754" 0x0041
+"DTT768" 0x0042
+
+"WBX LO TX" 0x0050
+"WBX LO RX" 0x0051
+
+"XCVR2450 Tx" 0x0060
+"XCVR2450 Rx" 0x0061
+
+"Experimental Tx" 0xfffe
+"Experimental Rx" 0xffff
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * 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/usrp_local_sighandler.h>
+#include <stdexcept>
+#include <stdio.h>
+#include <string.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
+ }
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2004,2006,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "usrp/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 const char *default_firmware_filename = "std.ihx";
+static const char *default_fpga_filename = "std_2rxhb_2tx.rbf";
+
+#include "std_paths.h"
+#include <stdio.h>
+
+static char *
+find_file (const char *filename, int hw_rev)
+{
+ const 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) || defined(__WIN32__) || defined(__CYGWIN__)
+ // 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...
+
+ // Appears to be required for libusb-win32 and Cygwin -- dew 09/20/06
+ 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)
+{
+ unsigned char 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;
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <usrp/usrp_standard.h>
+
+#include "usrp/usrp_prims.h"
+#include "fpga_regs_common.h"
+#include "fpga_regs_standard.h"
+#include <stdexcept>
+#include <assert.h>
+#include <math.h>
+#include <ad9862.h>
+#include <cstdio>
+
+
+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]))
+
+
+void
+usrp_standard_common::calc_dxc_freq(double target_freq, double baseband_freq, double fs,
+ double *dxc_freq, bool *inverted)
+{
+ /*
+ Calculate the frequency to use for setting the digital up or down converter.
+
+ @param target_freq: desired RF frequency (Hz)
+ @param baseband_freq: the RF frequency that corresponds to DC in the IF.
+ @param fs: converter sample rate
+
+ @returns: 2-tuple (ddc_freq, inverted) where ddc_freq is the value
+ for the ddc and inverted is True if we're operating in an inverted
+ Nyquist zone.
+ */
+
+#if 0
+ printf("calc_dxc_freq:\n");
+ printf(" target = %f\n", target_freq);
+ printf(" baseband = %f\n", baseband_freq);
+ printf(" fs = %f\n", fs);
+#endif
+
+ double delta = target_freq - baseband_freq;
+
+ if(delta >= 0) {
+ while(delta > fs) {
+ delta -= fs;
+ }
+ if(delta <= fs/2) { // non-inverted region
+ *dxc_freq = -delta;
+ *inverted = false;
+ }
+ else { // inverted region
+ *dxc_freq = delta - fs;
+ *inverted = true;
+ }
+ }
+ else {
+ while(delta < -fs) {
+ delta += fs;
+ }
+ if(delta >= -fs/2) {
+ *dxc_freq = -delta; // non-inverted region
+ *inverted = false;
+ }
+ else { // inverted region
+ *dxc_freq = delta + fs;
+ *inverted = true;
+ }
+ }
+
+#if 0
+ printf(" dxc_freq = %f\n", *dxc_freq);
+ printf(" inverted = %s\n", *inverted ? "true" : "false");
+#endif
+}
+
+
+/*
+ * Real lambda expressions would be _so_ much easier...
+ */
+class dxc_control {
+public:
+ virtual bool is_tx() = 0;
+ virtual bool set_dxc_freq(double dxc_freq) = 0;
+ virtual double dxc_freq() = 0;
+};
+
+class ddc_control : public dxc_control {
+ usrp_standard_rx *d_u;
+ int d_chan;
+
+public:
+ ddc_control(usrp_standard_rx *u, int chan)
+ : d_u(u), d_chan(chan) {}
+
+ bool is_tx(){ return false; }
+ bool set_dxc_freq(double dxc_freq){ return d_u->set_rx_freq(d_chan, dxc_freq); }
+ double dxc_freq(){ return d_u->rx_freq(d_chan); }
+};
+
+class duc_control : public dxc_control {
+ usrp_standard_tx *d_u;
+ int d_chan;
+
+public:
+ duc_control(usrp_standard_tx *u, int chan)
+ : d_u(u), d_chan(chan) {}
+
+ bool is_tx(){ return true; }
+ bool set_dxc_freq(double dxc_freq){ return d_u->set_tx_freq(d_chan, dxc_freq); }
+ double dxc_freq() { return d_u->tx_freq(d_chan); }
+};
+
+
+/*!
+ * \brief Tune such that target_frequency ends up at DC in the complex baseband
+ *
+ * \param db the daughterboard to use
+ * \param target_freq the center frequency we want at baseband (DC)
+ * \param fs the sample rate
+ * \param dxc DDC or DUC access and control object
+ * \param[out] result details of what we did
+ *
+ * \returns true iff operation was successful
+ *
+ * Tuning is a two step process. First we ask the front-end to
+ * tune as close to the desired frequency as it can. Then we use
+ * the result of that operation and our target_frequency to
+ * determine the value for the digital down converter.
+ */
+static bool
+tune_a_helper(db_base_sptr db, double target_freq, double fs,
+ dxc_control &dxc, usrp_tune_result *result)
+{
+ bool inverted = false;
+ double dxc_freq;
+ double actual_dxc_freq;
+
+ // Ask the d'board to tune as closely as it can to target_freq
+#if 0
+ bool ok = db->set_freq(target_freq, &result->baseband_freq);
+#else
+ bool ok;
+ {
+ freq_result_t fr = db->set_freq(target_freq);
+ ok = fr.ok;
+ result->baseband_freq = fr.baseband_freq;
+ }
+#endif
+
+ // Calculate the DDC setting that will downconvert the baseband from the
+ // daughterboard to our target frequency.
+ usrp_standard_common::calc_dxc_freq(target_freq, result->baseband_freq, fs,
+ &dxc_freq, &inverted);
+
+ // If the spectrum is inverted, and the daughterboard doesn't do
+ // quadrature downconversion, we can fix the inversion by flipping the
+ // sign of the dxc_freq... (This only happens using the basic_rx board)
+
+ if(db->spectrum_inverted())
+ inverted = !inverted;
+
+ if(inverted && !db->is_quadrature()){
+ dxc_freq = -dxc_freq;
+ inverted = !inverted;
+ }
+
+ if (dxc.is_tx() && !db->i_and_q_swapped()) // down conversion versus up conversion
+ dxc_freq = -dxc_freq;
+
+ ok &= dxc.set_dxc_freq(dxc_freq);
+ actual_dxc_freq = dxc.dxc_freq();
+
+ result->dxc_freq = dxc_freq;
+ result->residual_freq = dxc_freq - actual_dxc_freq;
+ result->inverted = inverted;
+ return ok;
+}
+
+
+static unsigned int
+compute_freq_control_word_fpga (double master_freq, double target_freq,
+ double *actual_freq, bool verbose)
+{
+ 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_sptr
+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
+ )
+{
+ try {
+ usrp_standard_rx_sptr u =
+ usrp_standard_rx_sptr(new usrp_standard_rx(which_board, decim_rate,
+ nchan, mux, mode,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename));
+ u->init_db(u);
+ return u;
+ }
+ catch (...){
+ return usrp_standard_rx_sptr();
+ }
+}
+
+bool
+usrp_standard_rx::set_decim_rate(unsigned int rate)
+{
+ if (has_rx_halfband()){
+ 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;
+ }
+ }
+ else {
+ if (rate < 4 || rate > 128){
+ fprintf (stderr, "usrp_standard_rx::set_decim_rate: rate must be in [4, 128]\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;
+}
+
+int
+usrp_standard_rx::determine_rx_mux_value(const usrp_subdev_spec &ss)
+{
+ /*
+ Determine appropriate Rx mux value as a function of the subdevice choosen and the
+ characteristics of the respective daughterboard.
+
+ @param u: instance of USRP source
+ @param subdev_spec: return value from subdev option parser.
+ @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0 or 1
+ @returns: the Rx mux value
+
+ Figure out which A/D's to connect to the DDC.
+
+ Each daughterboard consists of 1 or 2 subdevices. (At this time,
+ all but the Basic Rx have a single subdevice. The Basic Rx
+ has two independent channels, treated as separate subdevices).
+ subdevice 0 of a daughterboard may use 1 or 2 A/D's. We determine this
+ by checking the is_quadrature() method. If subdevice 0 uses only a single
+ A/D, it's possible that the daughterboard has a second subdevice, subdevice 1,
+ and it uses the second A/D.
+
+ If the card uses only a single A/D, we wire a zero into the DDC Q input.
+
+ (side, 0) says connect only the A/D's used by subdevice 0 to the DDC.
+ (side, 1) says connect only the A/D's used by subdevice 1 to the DDC.
+ */
+
+ struct truth_table_element
+ {
+ int d_side;
+ int d_uses;
+ bool d_swap_iq;
+ unsigned int d_mux_val;
+
+ truth_table_element(int side, unsigned int uses, bool swap_iq, unsigned int mux_val=0)
+ : d_side(side), d_uses(uses), d_swap_iq(swap_iq), d_mux_val(mux_val){}
+
+ bool operator==(const truth_table_element &in)
+ {
+ return (d_side == in.d_side && d_uses == in.d_uses && d_swap_iq == in.d_swap_iq);
+ }
+
+ unsigned int mux_val() { return d_mux_val; }
+ };
+
+
+ if (!is_valid(ss))
+ throw std::invalid_argument("subdev_spec");
+
+
+ // This is a tuple of length 1 or 2 containing the subdevice
+ // classes for the selected side.
+ std::vector<db_base_sptr> db = this->db(ss.side);
+
+ unsigned int uses;
+
+ // compute bitmasks of used A/D's
+
+ if(db[ss.subdev]->is_quadrature())
+ uses = 0x3; // uses A/D 0 and 1
+ else if (ss.subdev == 0)
+ uses = 0x1; // uses A/D 0 only
+ else if(ss.subdev == 1)
+ uses = 0x2; // uses A/D 1 only
+ else
+ uses = 0x0; // uses no A/D (doesn't exist)
+
+ if(uses == 0){
+ throw std::runtime_error("Determine RX Mux Error");
+ }
+
+ bool swap_iq = db[ss.subdev]->i_and_q_swapped();
+
+ truth_table_element truth_table[8] = {
+ // (side, uses, swap_iq) : mux_val
+ truth_table_element(0, 0x1, false, 0xf0f0f0f0),
+ truth_table_element(0, 0x2, false, 0xf0f0f0f1),
+ truth_table_element(0, 0x3, false, 0x00000010),
+ truth_table_element(0, 0x3, true, 0x00000001),
+ truth_table_element(1, 0x1, false, 0xf0f0f0f2),
+ truth_table_element(1, 0x2, false, 0xf0f0f0f3),
+ truth_table_element(1, 0x3, false, 0x00000032),
+ truth_table_element(1, 0x3, true, 0x00000023)
+ };
+ size_t nelements = sizeof(truth_table)/sizeof(truth_table[0]);
+
+ truth_table_element target(ss.side, uses, swap_iq, 0);
+
+ size_t i;
+ for(i = 0; i < nelements; i++){
+ if (truth_table[i] == target)
+ return truth_table[i].mux_val();
+ }
+ throw std::runtime_error("internal error");
+}
+
+int
+usrp_standard_rx::determine_rx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b)
+{
+ std::vector<db_base_sptr> db_a = this->db(ss_a.side);
+ std::vector<db_base_sptr> db_b = this->db(ss_b.side);
+ if (db_a[ss_a.subdev]->is_quadrature() != db_b[ss_b.subdev]->is_quadrature()){
+ throw std::runtime_error("Cannot compute dual mux when mixing quadrature and non-quadrature subdevices");
+ }
+ int mux_a = determine_rx_mux_value(ss_a);
+ int mux_b = determine_rx_mux_value(ss_b);
+ //move the lower byte of the mux b into the second byte of the mux a
+ return ((mux_b & 0xff) << 8) | (mux_a & 0xffff00ff);
+}
+
+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_rate(),
+ 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;
+}
+
+bool
+usrp_standard_rx::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result)
+{
+ ddc_control dxc(this, chan);
+ return tune_a_helper(db, target_freq, converter_rate(), dxc, result);
+}
+
+
+//////////////////////////////////////////////////////////////////
+
+
+// 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_sptr
+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
+ )
+{
+ try {
+ usrp_standard_tx_sptr u =
+ usrp_standard_tx_sptr(new usrp_standard_tx(which_board, interp_rate, nchan, mux,
+ fusb_block_size, fusb_nblocks,
+ fpga_filename, firmware_filename));
+ u->init_db(u);
+ return u;
+ }
+ catch (...){
+ return usrp_standard_tx_sptr();
+ }
+}
+
+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;
+}
+
+int
+usrp_standard_tx::determine_tx_mux_value(const usrp_subdev_spec &ss)
+{
+ /*
+ Determine appropriate Tx mux value as a function of the subdevice choosen.
+
+ @param u: instance of USRP source
+ @param subdev_spec: return value from subdev option parser.
+ @type subdev_spec: (side, subdev), where side is 0 or 1 and subdev is 0
+ @returns: the Rx mux value
+
+ This is simpler than the rx case. Either you want to talk
+ to side A or side B. If you want to talk to both sides at once,
+ determine the value manually.
+ */
+
+ if (!is_valid(ss))
+ throw std::invalid_argument("subdev_spec");
+
+ std::vector<db_base_sptr> db = this->db(ss.side);
+
+ if(db[ss.subdev]->i_and_q_swapped()) {
+ unsigned int mask[2] = {0x0089, 0x8900};
+ return mask[ss.side];
+ }
+ else {
+ unsigned int mask[2] = {0x0098, 0x9800};
+ return mask[ss.side];
+ }
+}
+
+int
+usrp_standard_tx::determine_tx_mux_value(const usrp_subdev_spec &ss_a, const usrp_subdev_spec &ss_b)
+{
+ if (ss_a.side == ss_b.side && ss_a.subdev == ss_b.subdev){
+ throw std::runtime_error("Cannot compute dual mux, repeated subdevice");
+ }
+ int mux_a = determine_tx_mux_value(ss_a);
+ //Get the mux b:
+ // DAC0 becomes DAC2
+ // DAC1 becomes DAC3
+ unsigned int mask[2] = {0x0022, 0x2200};
+ int mux_b = determine_tx_mux_value(ss_b) + mask[ss_b.side];
+ return mux_b | mux_a;
+}
+
+#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_rate () / 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_rate () == 128000000);
+
+ if (freq < -44e6) // too low
+ return false;
+ else if (freq < -24e6){ // [-44, -24)
+ cm = CM_NEG_FDAC_OVER_4;
+ coarse = -dac_rate () / 4;
+ }
+ else if (freq < -8e6){ // [-24, -8)
+ cm = CM_NEG_FDAC_OVER_8;
+ coarse = -dac_rate () / 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_rate () / 8;
+ }
+ else if (freq <= 44e6){ // [24, 44]
+ cm = CM_POS_FDAC_OVER_4;
+ coarse = dac_rate () / 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_rate () / 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];
+}
+
+bool
+usrp_standard_tx::tune(int chan, db_base_sptr db, double target_freq, usrp_tune_result *result)
+{
+ duc_control dxc(this, chan);
+ return tune_a_helper(db, target_freq, converter_rate(), dxc, result);
+}
/* -*- c++ -*- */
/*
- * Copyright 2003,2004 Free Software Foundation, Inc.
+ * Copyright 2003,2004,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
%{
-#include <usrp_prims.h>
+#include <usrp/usrp_prims.h>
%}
--- /dev/null
+#
+# Copyright 2003,2006,2008 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = \
+ $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \
+ $(USRP_INCLUDES) $(USRP_INBAND_INCLUDES) $(BOOST_CPPFLAGS) \
+ $(CPPUNIT_INCLUDES) $(WITH_INCLUDES) -I$(top_srcdir)/mblock/src/lib
+
+
+bin_PROGRAMS =
+
+noinst_PROGRAMS = \
+ test_usrp_inband_ping \
+ test_usrp_inband_registers \
+ test_usrp_inband_rx \
+ test_usrp_inband_2rx \
+ test_usrp_inband_tx \
+ test_usrp_inband_2tx \
+ test_usrp_inband_timestamps \
+ test_usrp_inband_overrun \
+ test_usrp_inband_underrun \
+ read_packets
+
+noinst_HEADERS = \
+ ui_nco.h \
+ ui_sincos.h
+
+
+test_usrp_inband_ping_SOURCES = test_usrp_inband_ping.cc
+test_usrp_inband_ping_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_tx_SOURCES = test_usrp_inband_tx.cc ui_sincos.c
+test_usrp_inband_tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_2tx_SOURCES = test_usrp_inband_2tx.cc ui_sincos.c
+test_usrp_inband_2tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_timestamps_SOURCES = test_usrp_inband_timestamps.cc ui_sincos.c
+test_usrp_inband_timestamps_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_registers_SOURCES = test_usrp_inband_registers.cc ui_sincos.c
+test_usrp_inband_registers_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_overrun_SOURCES = test_usrp_inband_overrun.cc
+test_usrp_inband_overrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_underrun_SOURCES = test_usrp_inband_underrun.cc
+test_usrp_inband_underrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_rx_SOURCES = test_usrp_inband_rx.cc ui_sincos.c
+test_usrp_inband_rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+test_usrp_inband_2rx_SOURCES = test_usrp_inband_2rx.cc ui_sincos.c
+test_usrp_inband_2rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
+
+read_packets_SOURCES = read_packets.cc
+read_packets_LDADD = $(USRP_LA) $(USRP_INBAND_LA)
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <usrp_inband_usb_packet.h>
+#include <mblock/class_registry.h>
+#include <vector>
+#include <usrp_usb_interface.h>
+#include <fstream>
+
+typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
+
+int main(int argc, char *argv[]) {
+
+ if(argc !=2) {
+ std::cout << "Usage: ./read_packets <data_file>\n";
+ return -1;
+ }
+
+ std::ifstream infile;
+ std::ofstream outfile;
+
+ unsigned int pkt_size = transport_pkt::max_pkt_size();
+ unsigned int pkt_num=0;
+
+ transport_pkt *pkt;
+ char pkt_data[pkt_size]; // allocate the number of bytes for a single packet
+
+ pkt = (transport_pkt *)pkt_data; // makes operations cleaner to read
+
+ // Open the file and read the packets, dumping information
+ infile.open(argv[1], std::ios::binary|std::ios::in);
+ if(!infile.is_open())
+ exit(-1);
+
+ //outfile.open("dump.dat",std::ios::out|std::ios::binary);
+
+ // read 1 packet in to the memory
+ infile.read(pkt_data, pkt_size);
+
+ while(!infile.eof()) {
+
+ printf("Packet %u\n", pkt_num);
+
+ if(pkt->start_of_burst())
+ printf("\tstart of burst\n");
+
+ if(pkt->end_of_burst())
+ printf("\tend of burst\n");
+
+// if(pkt->carrier_sense())
+// printf("\tcarrier sense\n");
+
+ if(pkt->underrun())
+ printf("\tunderrun\n");
+
+ if(pkt->overrun())
+ printf("\toverrun\n");
+
+ printf("\tchannel: \t0x%x\n", pkt->chan());
+ printf("\ttimestamp: \t0x%x\n", pkt->timestamp());
+ //printf("\ttimestamp: \t%u\n", pkt->timestamp());
+ printf("\tlength: \t%u\n", pkt->payload_len());
+ printf("\trssi: \t%u\n", pkt->rssi());
+
+ printf("\tpayload: \n");
+ for(int i=0; i < pkt->payload_len(); i++)
+ //for(int i=0; i < pkt->max_payload(); i++)
+ {
+ printf("\t%d\t0x%x\n", i, *(pkt->payload()+i));
+ //outfile.write((const char*)(pkt->payload()+i),1);
+ //printf("\t\t0x%x\n", pkt->payload()+i);
+
+ }
+ printf("\n\n");
+
+ pkt_num++;
+
+ // read 1 packet in to the memory
+ infile.read(pkt_data, pkt_size);
+
+ }
+
+ infile.close();
+ //outfile.close();
+
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mb_runtime_nop.h> // QA only
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mb_mblock_impl.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+// Include the symbols needed for communication with USRP server
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_rx.h>
+
+static bool verbose = true;
+
+class test_usrp_rx : public mb_mblock
+{
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+ pmt_t d_rx_chan0, d_rx_chan1;
+
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNEL,
+ RECEIVING,
+ CLOSING_CHANNEL,
+ CLOSING_USRP,
+ };
+
+ state_t d_state;
+
+ std::ofstream d_ofile;
+
+ long d_samples_recvd;
+ long d_samples_to_recv;
+
+ public:
+ test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_rx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void open_usrp();
+ void close_usrp();
+ void allocate_channel();
+ void send_packets();
+ void enter_receiving();
+ void build_and_send_next_frame();
+ void handle_response_recv_raw_samples(pmt_t invocation_handle);
+ void enter_closing_channel();
+};
+
+test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_rx_chan0(PMT_NIL), d_rx_chan1(PMT_NIL),
+ d_samples_recvd(0),
+ d_samples_to_recv(20e6)
+{
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
+ pmt_t usrp_dict = pmt_make_dict();
+
+ // To test the application without a USRP
+ bool fake_usrp_p = false;
+ if(fake_usrp_p) {
+ pmt_dict_set(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_T);
+ }
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_2rxhb_2tx.rbf"));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(64));
+
+ define_component("server", "usrp_server", usrp_dict);
+
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+test_usrp_rx::~test_usrp_rx()
+{
+}
+
+void
+test_usrp_rx::initial_transition()
+{
+ open_usrp();
+}
+
+void
+test_usrp_rx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ switch(d_state){
+
+ //----------------------------- OPENING_USRP ----------------------------//
+ // We only expect a response from opening the USRP which should be succesful
+ // or failed.
+ case OPENING_USRP:
+ if (pmt_eq(event, s_response_open)){
+ status = pmt_nth(1, data);
+ if (pmt_eq(status, PMT_T)){
+ allocate_channel();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //----------------------- ALLOCATING CHANNELS --------------------//
+ // Allocate an RX channel to perform the overrun test.
+ case ALLOCATING_CHANNEL:
+ if (pmt_eq(event, s_response_allocate_channel)){
+ status = pmt_nth(1, data);
+ if(pmt_eqv(d_rx_chan0, PMT_NIL))
+ d_rx_chan0 = pmt_nth(2, data);
+ else
+ d_rx_chan1 = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T) && !pmt_eqv(d_rx_chan1, PMT_NIL)){
+ enter_receiving();
+ return;
+ }
+ else if(pmt_eq(status, PMT_F)){
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ return;
+ }
+ goto unhandled;
+
+ //--------------------------- RECEIVING ------------------------------//
+ // In the receiving state, we receive samples until the specified amount
+ // while counting the number of overruns.
+ case RECEIVING:
+ if (pmt_eq(event, s_response_recv_raw_samples)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_response_recv_raw_samples(data);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //------------------------- CLOSING CHANNEL ----------------------------//
+ // Check deallocation response for the RX channel
+ case CLOSING_CHANNEL:
+ if (pmt_eq(event, s_response_deallocate_channel)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ close_usrp();
+ return;
+ }
+ else {
+ error_msg = "failed to deallocate channel:";
+ goto bail;
+ }
+ }
+
+ // Alternately, we ignore all response recv samples while waiting for the
+ // channel to actually close
+ if (pmt_eq(event, s_response_recv_raw_samples))
+ return;
+
+ goto unhandled;
+
+ //--------------------------- CLOSING USRP ------------------------------//
+ // Once we have received a successful USRP close response, we shutdown all
+ // mblocks and exit.
+ case CLOSING_USRP:
+ if (pmt_eq(event, s_response_close)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ fflush(stdout);
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ default:
+ goto unhandled;
+ }
+ return;
+
+ // An error occured, print it, and shutdown all m-blocks
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ // Received an unhandled message for a specific state
+ unhandled:
+ if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+}
+
+
+void
+test_usrp_rx::open_usrp()
+{
+ pmt_t which_usrp = pmt_from_long(0);
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
+ d_state = OPENING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n";
+}
+
+void
+test_usrp_rx::close_usrp()
+{
+
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+ d_state = CLOSING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n";
+}
+
+void
+test_usrp_rx::allocate_channel()
+{
+ long capacity = (long) 16e6;
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_state = ALLOCATING_CHANNEL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n";
+}
+
+void
+test_usrp_rx::enter_receiving()
+{
+ d_state = RECEIVING;
+
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan0));
+
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan1));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n";
+}
+
+void
+test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t v_samples = pmt_nth(2, data);
+ pmt_t timestamp = pmt_nth(3, data);
+ pmt_t channel = pmt_nth(4, data);
+ pmt_t properties = pmt_nth(5, data);
+
+ d_samples_recvd += pmt_length(v_samples) / 4;
+
+ // Check for overrun
+ if(!pmt_is_dict(properties)) {
+ std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n";
+ return;
+ }
+
+ // Check if the number samples we have received meets the test
+ if(d_samples_recvd >= d_samples_to_recv) {
+ d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan0));
+ d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan1));
+ enter_closing_channel();
+ return;
+ }
+
+}
+
+void
+test_usrp_rx::enter_closing_channel()
+{
+ d_state = CLOSING_CHANNEL;
+
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan0));
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan1));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n";
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_rx);
+
+
+// ----------------------------------------------------------------
+
+int
+main (int argc, char **argv)
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_rx", PMT_F, &result);
+
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mb_runtime_nop.h> // QA only
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mb_mblock_impl.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+
+#include <ui_nco.h>
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_tx.h>
+
+static bool verbose = true;
+
+class test_usrp_tx : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_cs;
+ pmt_t d_tx_chan0, d_tx_chan1;
+
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNEL,
+ TRANSMITTING,
+ CLOSING_CHANNEL,
+ CLOSING_USRP,
+ };
+
+ state_t d_state;
+ long d_nsamples_to_send;
+ long d_nsamples_xmitted;
+ long d_nframes_xmitted;
+ long d_samples_per_frame;
+ bool d_done_sending;
+
+ // for generating sine wave output
+ ui_nco<float,float> d_nco;
+ double d_amplitude;
+
+ public:
+ test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_tx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void open_usrp();
+ void close_usrp();
+ void allocate_channel();
+ void send_packets();
+ void enter_transmitting();
+ void build_and_send_next_frame();
+ void handle_xmit_response(pmt_t invocation_handle);
+ void enter_closing_channel();
+};
+
+test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_tx_chan0(PMT_NIL), d_tx_chan1(PMT_NIL),
+ d_state(INIT), d_nsamples_to_send((long) 80e6),
+ d_nsamples_xmitted(0),
+ d_nframes_xmitted(0),
+ d_samples_per_frame((long)(126 * 4)), // full packet
+ d_done_sending(false),
+ d_amplitude(16384)
+{
+ // std::cout << "[TEST_USRP_TX] Initializing...\n";
+
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ //bool fake_usrp_p = true;
+ bool fake_usrp_p = false;
+
+ // Test the TX side
+
+ pmt_t usrp_dict = pmt_make_dict();
+
+ if(fake_usrp_p) {
+ pmt_dict_set(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_T);
+ }
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_2rxhb_2tx.rbf"));
+
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("interp-tx"),
+ pmt_from_long(128));
+
+// pmt_dict_set(usrp_dict,
+// pmt_intern("rf-freq"),
+// pmt_from_long(10e6));
+
+ define_component("server", "usrp_server", usrp_dict);
+
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "cs", "server", "cs");
+
+ // initialize NCO
+ double freq = 100e3;
+ int interp = 32; // 32 -> 4MS/s
+ double sample_rate = 128e6 / interp;
+ d_nco.set_freq(2*M_PI * freq/sample_rate);
+
+ // FIXME need to somehow set the interp rate in the USRP.
+ // for now, we'll have the low-level code hardwire it.
+}
+
+test_usrp_tx::~test_usrp_tx()
+{
+}
+
+void
+test_usrp_tx::initial_transition()
+{
+ open_usrp();
+}
+
+void
+test_usrp_tx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ //std::cout << msg << std::endl;
+
+ switch(d_state){
+ case OPENING_USRP:
+ if (pmt_eq(event, s_response_open)){
+ status = pmt_nth(1, data);
+ if (pmt_eq(status, PMT_T)){
+ allocate_channel();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case ALLOCATING_CHANNEL:
+ if (pmt_eq(event, s_response_allocate_channel)){
+ status = pmt_nth(1, data);
+ if(pmt_eqv(d_tx_chan0, PMT_NIL))
+ d_tx_chan0 = pmt_nth(2, data);
+ else
+ d_tx_chan1 = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T) && !pmt_eqv(d_tx_chan1, PMT_NIL)){
+ enter_transmitting();
+ return;
+ }
+ else if(pmt_eq(status, PMT_F)){
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ return;
+ }
+ goto unhandled;
+
+ case TRANSMITTING:
+ if (pmt_eq(event, s_response_xmit_raw_frame)){
+ handle = pmt_nth(0, data);
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_xmit_response(handle);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case CLOSING_CHANNEL:
+ if (pmt_eq(event, s_response_deallocate_channel)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ close_usrp();
+ return;
+ }
+ else {
+ error_msg = "failed to deallocate channel:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case CLOSING_USRP:
+ if (pmt_eq(event, s_response_close)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ default:
+ goto unhandled;
+ }
+ return;
+
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ unhandled:
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+}
+
+
+void
+test_usrp_tx::open_usrp()
+{
+ pmt_t which_usrp = pmt_from_long(0);
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
+ d_state = OPENING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n";
+}
+
+void
+test_usrp_tx::close_usrp()
+{
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+ d_state = CLOSING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n";
+}
+
+void
+test_usrp_tx::allocate_channel()
+{
+ long capacity = (long) 16e6;
+
+ // Send two capacity requests, which will allocate us two channels
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_state = ALLOCATING_CHANNEL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n";
+}
+
+void
+test_usrp_tx::enter_transmitting()
+{
+ d_state = TRANSMITTING;
+ d_nsamples_xmitted = 0;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n";
+
+ build_and_send_next_frame(); // fire off 4 to start pipeline
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+}
+
+void
+test_usrp_tx::build_and_send_next_frame()
+{
+ // allocate the uniform vector for the samples
+ // FIXME perhaps hold on to this between calls
+
+#if 1
+ long nsamples_this_frame =
+ std::min(d_nsamples_to_send - d_nsamples_xmitted,
+ d_samples_per_frame);
+#else
+ long nsamples_this_frame = d_samples_per_frame;
+#endif
+
+ if (nsamples_this_frame == 0){
+ d_done_sending = true;
+ return;
+ }
+
+
+ size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
+ pmt_t uvec = pmt_make_s16vector(nshorts, 0);
+ size_t ignore;
+ int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
+
+ // fill in the complex sinusoid
+
+ for (int i = 0; i < nsamples_this_frame; i++){
+
+ if (1){
+ gr_complex s;
+ d_nco.sincos(&s, 1, d_amplitude);
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ else {
+ gr_complex s(d_amplitude, d_amplitude);
+
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ }
+
+ pmt_t tx_properties = pmt_make_dict();
+
+ pmt_t timestamp = pmt_from_long(0xffffffff); // NOW
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle
+ d_tx_chan0, // channel
+ uvec, // the samples
+ timestamp,
+ tx_properties));
+
+ // Resend on channel 1
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle
+ d_tx_chan1, // channel
+ uvec, // the samples
+ timestamp,
+ tx_properties));
+
+ d_nsamples_xmitted += nsamples_this_frame;
+ d_nframes_xmitted++;
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n";
+}
+
+
+void
+test_usrp_tx::handle_xmit_response(pmt_t handle)
+{
+ if (d_done_sending &&
+ pmt_to_long(handle) == (d_nframes_xmitted - 1)){
+ // We're done sending and have received all responses
+ enter_closing_channel();
+ }
+
+ build_and_send_next_frame();
+}
+
+void
+test_usrp_tx::enter_closing_channel()
+{
+ d_state = CLOSING_CHANNEL;
+
+ // Deallocate both channels
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan0));
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan1));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n";
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_tx);
+
+
+// ----------------------------------------------------------------
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_tx", PMT_F, &result);
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+// Include the symbols needed for communication with USRP server
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_rx.h>
+
+static bool verbose = true;
+
+class test_usrp_rx : public mb_mblock
+{
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+ pmt_t d_rx_chan; // returned tx channel handle
+
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNEL,
+ RECEIVING,
+ CLOSING_CHANNEL,
+ CLOSING_USRP,
+ };
+
+ state_t d_state;
+
+ std::ofstream d_ofile;
+
+ long d_n_overruns;
+
+ long d_samples_recvd;
+ long d_samples_to_recv;
+
+ public:
+ test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_rx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void open_usrp();
+ void close_usrp();
+ void allocate_channel();
+ void send_packets();
+ void enter_receiving();
+ void build_and_send_next_frame();
+ void handle_response_recv_raw_samples(pmt_t invocation_handle);
+ void enter_closing_channel();
+};
+
+test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_n_overruns(0),
+ d_samples_recvd(0),
+ d_samples_to_recv(10e6)
+{
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
+ pmt_t usrp_dict = pmt_make_dict();
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_1rxhb_1tx.rbf"));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(128));
+
+ define_component("server", "usrp_server", usrp_dict);
+
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+test_usrp_rx::~test_usrp_rx()
+{
+}
+
+void
+test_usrp_rx::initial_transition()
+{
+ open_usrp();
+}
+
+void
+test_usrp_rx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ switch(d_state){
+
+ //----------------------------- OPENING_USRP ----------------------------//
+ // We only expect a response from opening the USRP which should be succesful
+ // or failed.
+ case OPENING_USRP:
+ if (pmt_eq(event, s_response_open)){
+ status = pmt_nth(1, data);
+ if (pmt_eq(status, PMT_T)){
+ allocate_channel();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //----------------------- ALLOCATING CHANNELS --------------------//
+ // Allocate an RX channel to perform the overrun test.
+ case ALLOCATING_CHANNEL:
+ if (pmt_eq(event, s_response_allocate_channel)){
+ status = pmt_nth(1, data);
+ d_rx_chan = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T)){
+ enter_receiving();
+ return;
+ }
+ else {
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //--------------------------- RECEIVING ------------------------------//
+ // In the receiving state, we receive samples until the specified amount
+ // while counting the number of overruns.
+ case RECEIVING:
+ if (pmt_eq(event, s_response_recv_raw_samples)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_response_recv_raw_samples(data);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //------------------------- CLOSING CHANNEL ----------------------------//
+ // Check deallocation response for the RX channel
+ case CLOSING_CHANNEL:
+ if (pmt_eq(event, s_response_deallocate_channel)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ close_usrp();
+ return;
+ }
+ else {
+ error_msg = "failed to deallocate channel:";
+ goto bail;
+ }
+ }
+
+ // Alternately, we ignore all response recv samples while waiting for the
+ // channel to actually close
+ if (pmt_eq(event, s_response_recv_raw_samples))
+ return;
+
+ goto unhandled;
+
+ //--------------------------- CLOSING USRP ------------------------------//
+ // Once we have received a successful USRP close response, we shutdown all
+ // mblocks and exit.
+ case CLOSING_USRP:
+ if (pmt_eq(event, s_response_close)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ std::cout << "\nOverruns: " << d_n_overruns << std::endl;
+ fflush(stdout);
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ default:
+ goto unhandled;
+ }
+ return;
+
+ // An error occured, print it, and shutdown all m-blocks
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ // Received an unhandled message for a specific state
+ unhandled:
+ if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+}
+
+
+void
+test_usrp_rx::open_usrp()
+{
+ pmt_t which_usrp = pmt_from_long(0);
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
+ d_state = OPENING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Opening the USRP\n";
+}
+
+void
+test_usrp_rx::close_usrp()
+{
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+ d_state = CLOSING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Closing the USRP\n";
+}
+
+void
+test_usrp_rx::allocate_channel()
+{
+ long capacity = (long) 16e6;
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_state = ALLOCATING_CHANNEL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Requesting RX channel allocation\n";
+}
+
+void
+test_usrp_rx::enter_receiving()
+{
+ d_state = RECEIVING;
+
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Receiving...\n";
+}
+
+void
+test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t v_samples = pmt_nth(2, data);
+ pmt_t timestamp = pmt_nth(3, data);
+ pmt_t channel = pmt_nth(4, data);
+ pmt_t properties = pmt_nth(5, data);
+
+ d_samples_recvd += pmt_length(v_samples) / 4;
+
+ // Check for overrun
+ if(!pmt_is_dict(properties)) {
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Recv samples dictionary is improper\n";
+ return;
+ }
+
+ if(pmt_t overrun = pmt_dict_ref(properties,
+ pmt_intern("overrun"),
+ PMT_NIL)) {
+ if(pmt_eqv(overrun, PMT_T)) {
+ d_n_overruns++;
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Underrun\n";
+ }
+ else {
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n" << overrun <<std::endl;
+ }
+ } else {
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n";
+ }
+
+ // Check if the number samples we have received meets the test
+ if(d_samples_recvd >= d_samples_to_recv) {
+ d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan));
+ enter_closing_channel();
+ return;
+ }
+
+}
+
+void
+test_usrp_rx::enter_closing_channel()
+{
+ d_state = CLOSING_CHANNEL;
+
+ sleep(2);
+
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_OVERRUN] Deallocating RX channel\n";
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_rx);
+
+
+// ----------------------------------------------------------------
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_rx", PMT_F, &result);
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <iostream>
+
+// Include the symbols needed for communication with USRP server
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_tx.h>
+#include <symbols_usrp_rx.h>
+
+static bool verbose = false;
+
+class test_usrp_inband_ping : public mb_mblock
+{
+
+ mb_port_sptr d_tx; // Ports connected to the USRP server
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ pmt_t d_tx_chan; // Returned channel from TX allocation
+ pmt_t d_rx_chan; // Returned channel from RX allocation
+
+ pmt_t d_which_usrp; // The USRP to use for the test
+
+ long d_warm_msgs; // The number of messages to 'warm' the USRP
+ long d_warm_recvd; // The number of msgs received in the 'warm' state
+
+ // Keep track of current state
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNELS,
+ WARMING_USRP,
+ PINGING,
+ CLOSING_CHANNELS,
+ CLOSING_USRP,
+ };
+ state_t d_state;
+
+ public:
+ test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_inband_ping();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void opening_usrp();
+ void allocating_channels();
+ void enter_warming_usrp();
+ void enter_pinging();
+ void build_and_send_ping();
+ void closing_channels();
+ void closing_usrp();
+};
+
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_inband_ping", PMT_F, &result);
+}
+
+
+test_usrp_inband_ping::test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_tx_chan(PMT_NIL),
+ d_rx_chan(PMT_NIL),
+ d_which_usrp(pmt_from_long(0)),
+ d_state(INIT)
+{
+
+ // A dictionary is used to pass parameters to the USRP
+ pmt_t usrp_dict = pmt_make_dict();
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("fixed1.rbf"));
+
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("interp-tx"),
+ pmt_from_long(128));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(16));
+
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Create an instance of USRP server and connect ports
+ define_component("server", "usrp_server", usrp_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+test_usrp_inband_ping::~test_usrp_inband_ping()
+{
+}
+
+void
+test_usrp_inband_ping::initial_transition()
+{
+ opening_usrp();
+}
+
+// Handle message reads all incoming messages from USRP server which will be
+// initialization and ping responses. We perform actions based on the current
+// state and the event (ie, ping response)
+void
+test_usrp_inband_ping::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+ pmt_t port_id = msg->port_id();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ // Dispatch based on state
+ switch(d_state) {
+
+ //----------------------------- OPENING_USRP ----------------------------//
+ // We only expect a response from opening the USRP which should be succesful
+ // or failed.
+ case OPENING_USRP:
+
+ if(pmt_eq(event, s_response_open)) {
+
+ status = pmt_nth(1, data); // failed/succes
+
+ if(pmt_eq(status, PMT_T)) {
+ allocating_channels();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+
+ }
+
+ goto unhandled; // all other messages not handled in this state
+
+
+ //----------------------- ALLOCATING CHANNELS --------------------//
+ // When allocating channels, we need to wait for 2 responses from
+ // USRP server: one for TX and one for RX. Both are initialized to
+ // NIL so we know to continue to the next state once both are set.
+ case ALLOCATING_CHANNELS:
+
+ // A TX allocation response
+ if(pmt_eq(event, s_response_allocate_channel)
+ && pmt_eq(d_tx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful response, extract the channel
+ if(pmt_eq(status, PMT_T)) {
+
+ d_tx_chan = pmt_nth(2, data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation"
+ << " on channel " << d_tx_chan << std::endl;
+
+ // If the RX has also been allocated already, we can continue
+ if(!pmt_eqv(d_rx_chan, PMT_NIL))
+ enter_warming_usrp();
+
+ return;
+ }
+ else { // TX allocation failed
+ error_msg = "failed to allocate TX channel:";
+ goto bail;
+ }
+ }
+
+ // A RX allocation response
+ if(pmt_eq(event, s_response_allocate_channel)
+ && pmt_eq(d_rx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful response, extract the channel
+ if(pmt_eq(status, PMT_T)) {
+
+ d_rx_chan = pmt_nth(2, data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation"
+ << " on channel " << d_rx_chan << std::endl;
+
+ // If the TX has also been allocated already, we can continue
+ if(!pmt_eqv(d_tx_chan, PMT_NIL))
+ enter_warming_usrp();
+
+ return;
+ }
+ else { // RX allocation failed
+ error_msg = "failed to allocate RX channel:";
+ goto bail;
+ }
+ }
+
+ goto unhandled;
+
+ //----------------------- WARMING USRP --------------------//
+ // The FX2 seems to need some amount of data to be buffered
+ // before it begins reading. We use this state to simply
+ // warm up the USRP before benchmarking pings.
+ case WARMING_USRP:
+
+ // We really don't care about the responses from the
+ // control channel in the warming stage, but once we receive
+ // the proper number of responses we switch states.
+ if(pmt_eq(event, s_response_from_control_channel)
+ && pmt_eq(d_rx->port_symbol(), port_id))
+ {
+ d_warm_recvd++;
+
+ if(d_warm_recvd > d_warm_msgs)
+ enter_pinging();
+
+ return;
+ }
+
+ goto unhandled;
+
+ case PINGING:
+ goto unhandled;
+
+ case CLOSING_CHANNELS:
+ goto unhandled;
+
+ case CLOSING_USRP:
+ goto unhandled;
+
+ case INIT:
+ goto unhandled;
+
+ }
+
+ // An error occured, print it, and shutdown all m-blocks
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ // Received an unhandled message for a specific state
+ unhandled:
+ if(verbose)
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+
+}
+
+
+// Sends a command to USRP server to open up a connection to the
+// specified USRP, which is defaulted to USRP 0 on the system
+void
+test_usrp_inband_ping::opening_usrp()
+{
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Opening USRP "
+ << d_which_usrp << std::endl;
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp));
+ d_state = OPENING_USRP;
+}
+
+// RX and TX channels must be allocated so that the USRP server can
+// properly share bandwidth across multiple USRPs. No commands will be
+// successful to the USRP through the USRP server on the TX or RX channels until
+// a bandwidth allocation has been received.
+void
+test_usrp_inband_ping::allocating_channels()
+{
+ d_state = ALLOCATING_CHANNELS;
+
+ long capacity = (long) 16e6;
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+}
+
+// The USRP needs some amount of initial data to pass a buffering point such
+// that it begins to pull and read data from the FX2. We send an arbitrary
+// amount of data to start the pipeline, which are just pings.
+void
+test_usrp_inband_ping::enter_warming_usrp()
+{
+ d_state = WARMING_USRP;
+
+ for(int i=0; i < d_warm_msgs; i++)
+ build_and_send_ping();
+}
+
+void
+test_usrp_inband_ping::enter_pinging()
+{
+ d_state = PINGING;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Running ping tests\n";
+
+}
+
+// Pings are sent over the TX channel using the signal 'cmd-to-control-channel'
+// to the USRP server. Within this message there can be infinite subpackets
+// stored as a list (the second parameter) and sent. The only subpacket we send
+// is a ping, interpreted by the 'op-ping-fixed' signal.
+void
+test_usrp_inband_ping::build_and_send_ping()
+{
+
+ d_tx->send(s_cmd_to_control_channel, // USRP server signal
+ pmt_list2(PMT_NIL, // invocation handle
+ pmt_list1(pmt_list3(s_op_ping_fixed,
+ pmt_from_long(0),
+ pmt_from_long(0)))));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Ping!!" << std::endl;
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_inband_ping);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+//#include <mb_mblock_impl.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <iostream>
+
+// Include the symbols needed for communication with USRP server
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_tx.h>
+#include <symbols_usrp_rx.h>
+
+static bool verbose = true;
+
+class test_usrp_inband_registers : public mb_mblock
+{
+
+ mb_port_sptr d_tx; // Ports connected to the USRP server
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ pmt_t d_tx_chan; // Returned channel from TX allocation
+ pmt_t d_rx_chan; // Returned channel from RX allocation
+
+ pmt_t d_which_usrp; // The USRP to use for the test
+
+ long d_warm_msgs; // The number of messages to 'warm' the USRP
+ long d_warm_recvd; // The number of msgs received in the 'warm' state
+
+ // Keep track of current state
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNELS,
+ WRITE_REGISTER,
+ READ_REGISTER,
+ CLOSING_CHANNELS,
+ CLOSING_USRP,
+ };
+ state_t d_state;
+
+ public:
+ test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_inband_registers();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void opening_usrp();
+ void allocating_channels();
+ void write_register();
+ void read_register();
+ void closing_channels();
+ void closing_usrp();
+ void enter_receiving();
+ void build_and_send_ping();
+};
+
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_inband_registers", PMT_F, &result);
+}
+
+
+test_usrp_inband_registers::test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_tx_chan(PMT_NIL),
+ d_rx_chan(PMT_NIL),
+ d_which_usrp(pmt_from_long(0)),
+ d_state(INIT)
+{
+
+ // A dictionary is used to pass parameters to the USRP
+ pmt_t usrp_dict = pmt_make_dict();
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_1rxhb_1tx.rbf"));
+
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("interp-tx"),
+ pmt_from_long(128));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(16));
+
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Create an instance of USRP server and connect ports
+ define_component("server", "usrp_server", usrp_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+test_usrp_inband_registers::~test_usrp_inband_registers()
+{
+}
+
+void
+test_usrp_inband_registers::initial_transition()
+{
+ opening_usrp();
+}
+
+// Handle message reads all incoming messages from USRP server which will be
+// initialization and ping responses. We perform actions based on the current
+// state and the event (ie, ping response)
+void
+test_usrp_inband_registers::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+ pmt_t port_id = msg->port_id();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ // Dispatch based on state
+ switch(d_state) {
+
+ //----------------------------- OPENING_USRP ----------------------------//
+ // We only expect a response from opening the USRP which should be succesful
+ // or failed.
+ case OPENING_USRP:
+
+ if(pmt_eq(event, s_response_open)) {
+
+ status = pmt_nth(1, data); // failed/succes
+
+ if(pmt_eq(status, PMT_T)) {
+ allocating_channels();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+
+ }
+
+ goto unhandled; // all other messages not handled in this state
+
+
+ //----------------------- ALLOCATING CHANNELS --------------------//
+ // When allocating channels, we need to wait for 2 responses from
+ // USRP server: one for TX and one for RX. Both are initialized to
+ // NIL so we know to continue to the next state once both are set.
+ case ALLOCATING_CHANNELS:
+
+ // A TX allocation response
+ if(pmt_eq(event, s_response_allocate_channel)
+ && pmt_eq(d_tx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful response, extract the channel
+ if(pmt_eq(status, PMT_T)) {
+
+ d_tx_chan = pmt_nth(2, data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation"
+ << " on channel " << d_tx_chan << std::endl;
+
+ // If the RX has also been allocated already, we can continue
+ if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
+ enter_receiving();
+ write_register();
+ }
+
+ return;
+ }
+ else { // TX allocation failed
+ error_msg = "failed to allocate TX channel:";
+ goto bail;
+ }
+ }
+
+ // A RX allocation response
+ if(pmt_eq(event, s_response_allocate_channel)
+ && pmt_eq(d_rx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful response, extract the channel
+ if(pmt_eq(status, PMT_T)) {
+
+ d_rx_chan = pmt_nth(2, data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation"
+ << " on channel " << d_rx_chan << std::endl;
+
+ // If the TX has also been allocated already, we can continue
+ if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
+ enter_receiving();
+ write_register();
+ }
+
+ return;
+ }
+ else { // RX allocation failed
+ error_msg = "failed to allocate RX channel:";
+ goto bail;
+ }
+ }
+
+ goto unhandled;
+
+ //-------------------------- WRITE REGISTER ----------------------------//
+ // In the write register state, we do not expect to receive any messages
+ // since the write does not directly generate a response until the USRP
+ // responds.
+ case WRITE_REGISTER:
+ goto unhandled;
+
+ //-------------------------- READ REGISTER ----------------------------//
+ // In the read register state, we only expect a read register response back
+ // that has the value we expect to have in it. We read the response, ensure
+ // that the read was successful and display the register value.
+ case READ_REGISTER:
+
+ if(pmt_eq(event, s_response_from_control_channel)
+ && pmt_eq(d_tx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If the read was successful, we extract the subpacket information
+ if(pmt_eq(status, PMT_T)) {
+
+ pmt_t subp = pmt_nth(2, data); // subpacket should be the read reg reply
+
+ pmt_t subp_sig = pmt_nth(0, subp);
+ pmt_t subp_data = pmt_nth(1, subp);
+
+ if(!pmt_eqv(subp_sig, s_op_read_reg_reply)) {
+ error_msg = "received improper subpacket when expecting reg reply.";
+ goto bail;
+ }
+
+ pmt_t rid = pmt_nth(0, subp_data);
+ pmt_t reg_num = pmt_nth(1, subp_data);
+ pmt_t reg_val = pmt_nth(2, subp_data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_REGISTERS] Received read reg reply "
+ << "("
+ << "RID: " << rid << ", "
+ << "Reg: " << reg_num << ", "
+ << "Val: " << reg_val
+ << ")\n";
+
+ // read_register(); FIX ME STATE TRANSITION
+ return;
+
+ } else { // bail on unsuccessful write
+ error_msg = "failed to write to register.";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case CLOSING_CHANNELS:
+ goto unhandled;
+
+ case CLOSING_USRP:
+ goto unhandled;
+
+ case INIT:
+ goto unhandled;
+
+ }
+
+ // An error occured, print it, and shutdown all m-blocks
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ // Received an unhandled message for a specific state
+ unhandled:
+ if(verbose && !pmt_eq(event, s_response_recv_raw_samples))
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+
+}
+
+
+// Sends a command to USRP server to open up a connection to the
+// specified USRP, which is defaulted to USRP 0 on the system
+void
+test_usrp_inband_registers::opening_usrp()
+{
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_PING] Opening USRP "
+ << d_which_usrp << std::endl;
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp));
+ d_state = OPENING_USRP;
+}
+
+// RX and TX channels must be allocated so that the USRP server can
+// properly share bandwidth across multiple USRPs. No commands will be
+// successful to the USRP through the USRP server on the TX or RX channels until
+// a bandwidth allocation has been received.
+void
+test_usrp_inband_registers::allocating_channels()
+{
+ d_state = ALLOCATING_CHANNELS;
+
+ long capacity = (long) 16e6;
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+}
+
+// After allocating the channels, a write register command will be sent to the
+// USRP.
+void
+test_usrp_inband_registers::write_register()
+{
+ d_state = WRITE_REGISTER;
+
+ long reg = 0;
+
+ d_tx->send(s_cmd_to_control_channel, // C/S packet
+ pmt_list2(PMT_NIL, // invoc handle
+ pmt_list1(
+ pmt_list2(s_op_write_reg,
+ pmt_list2(
+ pmt_from_long(reg),
+ pmt_from_long(0xbeef))))));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to "
+ << reg << std::endl;
+
+ read_register(); // immediately transition to read the register
+}
+
+// Temporary: for testing pings
+void
+test_usrp_inband_registers::build_and_send_ping()
+{
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
+ pmt_list2(pmt_from_long(0),
+ pmt_from_long(0))))));
+
+ std::cout << "[TEST_USRP_INBAND_CS] Ping sent" << std::endl;
+}
+
+// After writing to the register, we want to read the value back and ensure that
+// it is the same value that we wrote.
+void
+test_usrp_inband_registers::read_register()
+{
+ d_state = READ_REGISTER;
+
+ long reg = 9;
+
+ d_tx->send(s_cmd_to_control_channel, // C/S packet
+ pmt_list2(PMT_NIL, // invoc handle
+ pmt_list1(
+ pmt_list2(s_op_read_reg,
+ pmt_list2(
+ pmt_from_long(0), // rid
+ pmt_from_long(reg))))));
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_REGISTERS] Reading from register "
+ << reg << std::endl;
+}
+
+// Used to enter the receiving state
+void
+test_usrp_inband_registers::enter_receiving()
+{
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan));
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_inband_registers);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+
+// Include the symbols needed for communication with USRP server
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_rx.h>
+
+static bool verbose = true;
+
+class test_usrp_rx : public mb_mblock
+{
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+ pmt_t d_rx_chan; // returned tx channel handle
+
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNEL,
+ RECEIVING,
+ CLOSING_CHANNEL,
+ CLOSING_USRP,
+ };
+
+ state_t d_state;
+
+ std::ofstream d_ofile;
+
+ long d_samples_recvd;
+ long d_samples_to_recv;
+
+ public:
+ test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_rx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void open_usrp();
+ void close_usrp();
+ void allocate_channel();
+ void send_packets();
+ void enter_receiving();
+ void build_and_send_next_frame();
+ void handle_response_recv_raw_samples(pmt_t invocation_handle);
+ void enter_closing_channel();
+};
+
+test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_samples_recvd(0),
+ d_samples_to_recv(20e6)
+{
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
+ pmt_t usrp_dict = pmt_make_dict();
+
+ // To test the application without a USRP
+ bool fake_usrp_p = false;
+ if(fake_usrp_p) {
+ pmt_dict_set(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_T);
+ }
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_1rxhb_1tx.rbf"));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(64));
+
+// If unspecified, chooses center frequency from range
+// pmt_dict_set(usrp_dict,
+// pmt_intern("rf-freq"),
+// pmt_from_long(10e6));
+
+ define_component("server", "usrp_server", usrp_dict);
+
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+test_usrp_rx::~test_usrp_rx()
+{
+}
+
+void
+test_usrp_rx::initial_transition()
+{
+ open_usrp();
+}
+
+void
+test_usrp_rx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ switch(d_state){
+
+ //----------------------------- OPENING_USRP ----------------------------//
+ // We only expect a response from opening the USRP which should be succesful
+ // or failed.
+ case OPENING_USRP:
+ if (pmt_eq(event, s_response_open)){
+ status = pmt_nth(1, data);
+ if (pmt_eq(status, PMT_T)){
+ allocate_channel();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //----------------------- ALLOCATING CHANNELS --------------------//
+ // Allocate an RX channel to perform the overrun test.
+ case ALLOCATING_CHANNEL:
+ if (pmt_eq(event, s_response_allocate_channel)){
+ status = pmt_nth(1, data);
+ d_rx_chan = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T)){
+ enter_receiving();
+ return;
+ }
+ else {
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //--------------------------- RECEIVING ------------------------------//
+ // In the receiving state, we receive samples until the specified amount
+ // while counting the number of overruns.
+ case RECEIVING:
+ if (pmt_eq(event, s_response_recv_raw_samples)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_response_recv_raw_samples(data);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ //------------------------- CLOSING CHANNEL ----------------------------//
+ // Check deallocation response for the RX channel
+ case CLOSING_CHANNEL:
+ if (pmt_eq(event, s_response_deallocate_channel)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ close_usrp();
+ return;
+ }
+ else {
+ error_msg = "failed to deallocate channel:";
+ goto bail;
+ }
+ }
+
+ // Alternately, we ignore all response recv samples while waiting for the
+ // channel to actually close
+ if (pmt_eq(event, s_response_recv_raw_samples))
+ return;
+
+ goto unhandled;
+
+ //--------------------------- CLOSING USRP ------------------------------//
+ // Once we have received a successful USRP close response, we shutdown all
+ // mblocks and exit.
+ case CLOSING_USRP:
+ if (pmt_eq(event, s_response_close)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ fflush(stdout);
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ default:
+ goto unhandled;
+ }
+ return;
+
+ // An error occured, print it, and shutdown all m-blocks
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ // Received an unhandled message for a specific state
+ unhandled:
+ if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+}
+
+
+void
+test_usrp_rx::open_usrp()
+{
+ pmt_t which_usrp = pmt_from_long(0);
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
+ d_state = OPENING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n";
+}
+
+void
+test_usrp_rx::close_usrp()
+{
+
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+ d_state = CLOSING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n";
+}
+
+void
+test_usrp_rx::allocate_channel()
+{
+ long capacity = (long) 16e6;
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_state = ALLOCATING_CHANNEL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n";
+}
+
+void
+test_usrp_rx::enter_receiving()
+{
+ d_state = RECEIVING;
+
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n";
+}
+
+void
+test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t v_samples = pmt_nth(2, data);
+ pmt_t timestamp = pmt_nth(3, data);
+ pmt_t channel = pmt_nth(4, data);
+ pmt_t properties = pmt_nth(5, data);
+
+ d_samples_recvd += pmt_length(v_samples) / 4;
+
+ // Check for overrun
+ if(!pmt_is_dict(properties)) {
+ std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n";
+ return;
+ }
+
+ // Check if the number samples we have received meets the test
+ if(d_samples_recvd >= d_samples_to_recv) {
+ d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan));
+ enter_closing_channel();
+ return;
+ }
+
+}
+
+void
+test_usrp_rx::enter_closing_channel()
+{
+ d_state = CLOSING_CHANNEL;
+
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n";
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_rx);
+
+
+// ----------------------------------------------------------------
+
+int
+main (int argc, char **argv)
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_rx", PMT_F, &result);
+
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <iostream>
+
+#include <ui_nco.h>
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_tx.h>
+#include <symbols_usrp_rx.h>
+
+#define NBPING 10
+
+static bool verbose = true;
+bool bskip = false;
+long bstep = 10000;
+long bcurr = 0;
+long incr = 0x500;
+long ptime = 0x000;
+
+class test_usrp_inband_timestamps : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+ pmt_t d_tx_chan; // returned tx channel handle
+ pmt_t d_rx_chan; // returned tx channel handle
+
+ struct timeval times[NBPING];
+
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNEL,
+ TRANSMITTING,
+ CLOSING_CHANNEL,
+ CLOSING_USRP,
+ };
+
+ state_t d_state;
+ long d_nsamples_to_send;
+ long d_nsamples_xmitted;
+ long d_nframes_xmitted;
+ long d_samples_per_frame;
+ bool d_done_sending;
+
+ // for generating sine wave output
+ ui_nco<float,float> d_nco;
+ double d_amplitude;
+
+ public:
+ test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_inband_timestamps();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void open_usrp();
+ void close_usrp();
+ void allocate_channel();
+ void send_packets();
+ void enter_receiving();
+ void enter_transmitting();
+ void build_and_send_ping();
+ void build_and_send_next_frame();
+ void handle_xmit_response(pmt_t invocation_handle);
+ void enter_closing_channel();
+};
+
+test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_tx_chan(PMT_NIL),
+ d_rx_chan(PMT_NIL),
+ d_state(INIT), d_nsamples_to_send((long) 40e6),
+ d_nsamples_xmitted(0),
+ d_nframes_xmitted(0),
+ //d_samples_per_frame((long)(126)),
+ d_samples_per_frame((long)(126 * 2)), // non-full packet
+ //d_samples_per_frame((long)(126 * 3.5)), // non-full packet
+ //d_samples_per_frame((long)(126 * 4)), // full packet
+ d_done_sending(false),
+ d_amplitude(16384)
+{
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Initializing...\n";
+
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ bool fake_usrp_p = false;
+
+ // Test the TX side
+
+ pmt_t usrp_dict = pmt_make_dict();
+
+ if(fake_usrp_p) {
+ pmt_dict_set(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_T);
+ }
+
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("interp-tx"),
+ pmt_from_long(128));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(16));
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_1rxhb_1tx.rbf"));
+
+ define_component("server", "usrp_server", usrp_dict);
+
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+ // initialize NCO
+ double freq = 100e3;
+ int interp = 32; // 32 -> 4MS/s
+ double sample_rate = 128e6 / interp;
+ d_nco.set_freq(2*M_PI * freq/sample_rate);
+
+}
+
+test_usrp_inband_timestamps::~test_usrp_inband_timestamps()
+{
+}
+
+void
+test_usrp_inband_timestamps::initial_transition()
+{
+ open_usrp();
+}
+
+void
+test_usrp_inband_timestamps::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+ pmt_t port_id = msg->port_id();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ //std::cout << msg << std::endl;
+
+ switch(d_state){
+ case OPENING_USRP:
+ if (pmt_eq(event, s_response_open)){
+ status = pmt_nth(1, data);
+ if (pmt_eq(status, PMT_T)){
+ allocate_channel();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case ALLOCATING_CHANNEL:
+ if (pmt_eq(event, s_response_allocate_channel)){
+
+ if(pmt_eq(d_tx->port_symbol(), port_id)) {
+ status = pmt_nth(1, data);
+ d_tx_chan = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T)){
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n";
+
+ if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
+ enter_receiving();
+ enter_transmitting();
+ }
+ return;
+ }
+ else {
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ }
+
+ if(pmt_eq(d_rx->port_symbol(), port_id)) {
+ status = pmt_nth(1, data);
+ d_rx_chan = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T)){
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n";
+
+ if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
+ enter_receiving();
+ enter_transmitting();
+ }
+ return;
+ }
+ else {
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ }
+ }
+ goto unhandled;
+
+ case TRANSMITTING:
+ if (pmt_eq(event, s_response_xmit_raw_frame)){
+ handle = pmt_nth(0, data);
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_xmit_response(handle);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+
+ if (pmt_eq(event, s_response_from_control_channel)) {
+ std::cout << "ping response!\n";
+ }
+ goto unhandled;
+
+ case CLOSING_CHANNEL:
+ if (pmt_eq(event, s_response_deallocate_channel)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ close_usrp();
+ return;
+ }
+ else {
+ error_msg = "failed to deallocate channel:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case CLOSING_USRP:
+ if (pmt_eq(event, s_response_close)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ default:
+ goto unhandled;
+ }
+ return;
+
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ unhandled:
+ if(verbose && 0)
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+}
+
+
+void
+test_usrp_inband_timestamps::open_usrp()
+{
+ pmt_t which_usrp = pmt_from_long(0);
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
+ d_state = OPENING_USRP;
+}
+
+void
+test_usrp_inband_timestamps::close_usrp()
+{
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+ d_state = CLOSING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing USRP\n";
+}
+
+void
+test_usrp_inband_timestamps::allocate_channel()
+{
+ long capacity = (long) 16e6;
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_state = ALLOCATING_CHANNEL;
+}
+
+void
+test_usrp_inband_timestamps::enter_receiving()
+{
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan));
+}
+
+void
+test_usrp_inband_timestamps::enter_transmitting()
+{
+ d_state = TRANSMITTING;
+ d_nsamples_xmitted = 0;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Beginning transmission\n";
+
+ sleep(1);
+
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+
+}
+
+void
+test_usrp_inband_timestamps::build_and_send_ping()
+{
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
+ pmt_list2(pmt_from_long(0),
+ pmt_from_long(0))))));
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Ping sent" << std::endl;
+}
+
+void
+test_usrp_inband_timestamps::build_and_send_next_frame()
+{
+ // allocate the uniform vector for the samples
+ // FIXME perhaps hold on to this between calls
+
+#if 0
+ long nsamples_this_frame =
+ std::min(d_nsamples_to_send - d_nsamples_xmitted,
+ d_samples_per_frame);
+#else
+ long nsamples_this_frame = d_samples_per_frame;
+#endif
+
+ if (nsamples_this_frame == 0){
+ d_done_sending = true;
+ return;
+ }
+
+
+ size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
+ pmt_t uvec = pmt_make_s16vector(nshorts, 0);
+ size_t ignore;
+ int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
+
+ // fill in the complex sinusoid
+
+ for (int i = 0; i < nsamples_this_frame; i++){
+
+ if (1){
+ gr_complex s;
+ d_nco.sincos(&s, 1, d_amplitude);
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ else {
+ gr_complex s(d_amplitude, d_amplitude);
+
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ }
+
+ pmt_t timestamp;
+
+ if(bskip) {
+ timestamp = pmt_from_long(0x0); // throw away
+ bcurr++;
+ if(bcurr == bstep) {
+ bskip = false;
+ bcurr = 0;
+ }
+ } else {
+ timestamp = pmt_from_long(0xffffffff); // NOW
+ timestamp = pmt_from_long(ptime);
+ ptime += incr;
+ bcurr++;
+ if(bcurr == bstep) {
+ //bskip = true;
+ bcurr = 0;
+ }
+ }
+
+ std::cout << bskip << " -- " << bcurr << std::endl;
+
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle
+ d_tx_chan, // channel
+ uvec, // the samples
+ timestamp));
+
+ d_nsamples_xmitted += nsamples_this_frame;
+ d_nframes_xmitted++;
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Transmitted frame\n";
+
+ //build_and_send_next_frame();
+}
+
+
+void
+test_usrp_inband_timestamps::handle_xmit_response(pmt_t handle)
+{
+ if (d_done_sending &&
+ pmt_to_long(handle) == (d_nframes_xmitted - 1)){
+ // We're done sending and have received all responses
+ enter_closing_channel();
+ }
+
+ build_and_send_next_frame();
+ //build_and_send_ping();
+}
+
+void
+test_usrp_inband_timestamps::enter_closing_channel()
+{
+ d_state = CLOSING_CHANNEL;
+
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing channel\n";
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_inband_timestamps);
+
+
+// ----------------------------------------------------------------
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_inband_timestamps", PMT_F, &result);
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+
+#include <ui_nco.h>
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_tx.h>
+
+static bool verbose = true;
+
+class test_usrp_tx : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_cs;
+ pmt_t d_tx_chan; // returned tx channel handle
+
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNEL,
+ TRANSMITTING,
+ CLOSING_CHANNEL,
+ CLOSING_USRP,
+ };
+
+ state_t d_state;
+ long d_nsamples_to_send;
+ long d_nsamples_xmitted;
+ long d_nframes_xmitted;
+ long d_samples_per_frame;
+ bool d_done_sending;
+
+ // for generating sine wave output
+ ui_nco<float,float> d_nco;
+ double d_amplitude;
+
+ public:
+ test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_tx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void open_usrp();
+ void close_usrp();
+ void allocate_channel();
+ void send_packets();
+ void enter_transmitting();
+ void build_and_send_next_frame();
+ void handle_xmit_response(pmt_t invocation_handle);
+ void enter_closing_channel();
+};
+
+test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_state(INIT), d_nsamples_to_send((long) 80e6),
+ d_nsamples_xmitted(0),
+ d_nframes_xmitted(0),
+ d_samples_per_frame((long)(126 * 4)), // full packet
+ d_done_sending(false),
+ d_amplitude(16384)
+{
+ // std::cout << "[TEST_USRP_TX] Initializing...\n";
+
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ //bool fake_usrp_p = true;
+ bool fake_usrp_p = false;
+
+ // Test the TX side
+
+ pmt_t usrp_dict = pmt_make_dict();
+
+ if(fake_usrp_p) {
+ pmt_dict_set(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_T);
+ }
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_1rxhb_1tx.rbf"));
+
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("interp-tx"),
+ pmt_from_long(64));
+
+// If unspecified, chooses center frequency from range
+// pmt_dict_set(usrp_dict,
+// pmt_intern("rf-freq"),
+// pmt_from_long(10e6));
+
+ define_component("server", "usrp_server", usrp_dict);
+
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "cs", "server", "cs");
+
+ // initialize NCO
+ double freq = 100e3;
+ int interp = 32; // 32 -> 4MS/s
+ double sample_rate = 128e6 / interp;
+ d_nco.set_freq(2*M_PI * freq/sample_rate);
+
+ // FIXME need to somehow set the interp rate in the USRP.
+ // for now, we'll have the low-level code hardwire it.
+}
+
+test_usrp_tx::~test_usrp_tx()
+{
+}
+
+void
+test_usrp_tx::initial_transition()
+{
+ open_usrp();
+}
+
+void
+test_usrp_tx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ std::string error_msg;
+
+ //std::cout << msg << std::endl;
+
+ switch(d_state){
+ case OPENING_USRP:
+ if (pmt_eq(event, s_response_open)){
+ status = pmt_nth(1, data);
+ if (pmt_eq(status, PMT_T)){
+ allocate_channel();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case ALLOCATING_CHANNEL:
+ if (pmt_eq(event, s_response_allocate_channel)){
+ status = pmt_nth(1, data);
+ d_tx_chan = pmt_nth(2, data);
+
+ if (pmt_eq(status, PMT_T)){
+ enter_transmitting();
+ return;
+ }
+ else {
+ error_msg = "failed to allocate channel:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case TRANSMITTING:
+ if (pmt_eq(event, s_response_xmit_raw_frame)){
+ handle = pmt_nth(0, data);
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_xmit_response(handle);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case CLOSING_CHANNEL:
+ if (pmt_eq(event, s_response_deallocate_channel)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ close_usrp();
+ return;
+ }
+ else {
+ error_msg = "failed to deallocate channel:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ case CLOSING_USRP:
+ if (pmt_eq(event, s_response_close)){
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+ goto unhandled;
+
+ default:
+ goto unhandled;
+ }
+ return;
+
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ unhandled:
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+}
+
+
+void
+test_usrp_tx::open_usrp()
+{
+ pmt_t which_usrp = pmt_from_long(0);
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
+ d_state = OPENING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n";
+}
+
+void
+test_usrp_tx::close_usrp()
+{
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+ d_state = CLOSING_USRP;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n";
+}
+
+void
+test_usrp_tx::allocate_channel()
+{
+ long capacity = (long) 16e6;
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_state = ALLOCATING_CHANNEL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n";
+}
+
+void
+test_usrp_tx::enter_transmitting()
+{
+ d_state = TRANSMITTING;
+ d_nsamples_xmitted = 0;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n";
+
+ build_and_send_next_frame(); // fire off 4 to start pipeline
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+}
+
+void
+test_usrp_tx::build_and_send_next_frame()
+{
+ // allocate the uniform vector for the samples
+ // FIXME perhaps hold on to this between calls
+
+#if 1
+ long nsamples_this_frame =
+ std::min(d_nsamples_to_send - d_nsamples_xmitted,
+ d_samples_per_frame);
+#else
+ long nsamples_this_frame = d_samples_per_frame;
+#endif
+
+ if (nsamples_this_frame == 0){
+ d_done_sending = true;
+ return;
+ }
+
+
+ size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
+ pmt_t uvec = pmt_make_s16vector(nshorts, 0);
+ size_t ignore;
+ int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
+
+ // fill in the complex sinusoid
+
+ for (int i = 0; i < nsamples_this_frame; i++){
+
+ if (1){
+ gr_complex s;
+ d_nco.sincos(&s, 1, d_amplitude);
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ else {
+ gr_complex s(d_amplitude, d_amplitude);
+
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ }
+
+ pmt_t tx_properties = pmt_make_dict();
+
+ pmt_t timestamp = pmt_from_long(0xffffffff); // NOW
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle
+ d_tx_chan, // channel
+ uvec, // the samples
+ timestamp,
+ tx_properties));
+
+ d_nsamples_xmitted += nsamples_this_frame;
+ d_nframes_xmitted++;
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n";
+}
+
+
+void
+test_usrp_tx::handle_xmit_response(pmt_t handle)
+{
+ if (d_done_sending &&
+ pmt_to_long(handle) == (d_nframes_xmitted - 1)){
+ // We're done sending and have received all responses
+ enter_closing_channel();
+ }
+
+ build_and_send_next_frame();
+}
+
+void
+test_usrp_tx::enter_closing_channel()
+{
+ d_state = CLOSING_CHANNEL;
+
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n";
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_tx);
+
+
+// ----------------------------------------------------------------
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_tx", PMT_F, &result);
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/exception.h>
+#include <mblock/msg_queue.h>
+#include <mblock/message.h>
+#include <mblock/msg_accepter.h>
+#include <mblock/class_registry.h>
+#include <pmt.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <iostream>
+#include <ui_nco.h>
+
+// Include the symbols needed for communication with USRP server
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_tx.h>
+#include <symbols_usrp_rx.h>
+
+static bool verbose = true;
+
+class test_usrp_inband_underrun : public mb_mblock
+{
+
+ mb_port_sptr d_tx; // Ports connected to the USRP server
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ pmt_t d_tx_chan; // Returned channel from TX allocation
+ pmt_t d_rx_chan; // Returned channel from RX allocation
+
+ pmt_t d_which_usrp; // The USRP to use for the test
+
+ long d_warm_msgs; // The number of messages to 'warm' the USRP
+ long d_warm_recvd; // The number of msgs received in the 'warm' state
+
+ // Keep track of current state
+ enum state_t {
+ INIT,
+ OPENING_USRP,
+ ALLOCATING_CHANNELS,
+ WRITE_REGISTER,
+ READ_REGISTER,
+ TRANSMITTING,
+ CLOSING_CHANNELS,
+ CLOSING_USRP,
+ };
+ state_t d_state;
+
+ long d_nsamples_to_send;
+ long d_nsamples_xmitted;
+ long d_nframes_xmitted;
+ long d_samples_per_frame;
+ bool d_done_sending;
+
+ // for generating sine wave output
+ ui_nco<float,float> d_nco;
+ double d_amplitude;
+
+ long d_n_underruns;
+
+ public:
+ test_usrp_inband_underrun(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~test_usrp_inband_underrun();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void opening_usrp();
+ void allocating_channels();
+ void write_register();
+ void read_register();
+ void closing_channels();
+ void closing_usrp();
+ void enter_receiving();
+ void enter_transmitting();
+ void build_and_send_ping();
+ void build_and_send_next_frame();
+ void handle_xmit_response(pmt_t handle);
+ void handle_recv_response(pmt_t dict);
+};
+
+
+int
+main (int argc, char **argv)
+{
+ // handle any command line args here
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "test_usrp_inband_underrun", PMT_F, &result);
+}
+
+
+test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_tx_chan(PMT_NIL),
+ d_rx_chan(PMT_NIL),
+ d_which_usrp(pmt_from_long(0)),
+ d_state(INIT),
+ d_nsamples_to_send((long) 27e6),
+ d_nsamples_xmitted(0),
+ d_nframes_xmitted(0),
+ d_samples_per_frame(d_nsamples_to_send), // full packet
+
+ d_done_sending(false),
+ d_amplitude(16384),
+ d_n_underruns(0)
+{
+
+ // A dictionary is used to pass parameters to the USRP
+ pmt_t usrp_dict = pmt_make_dict();
+
+ // Specify the RBF to use
+ pmt_dict_set(usrp_dict,
+ pmt_intern("rbf"),
+ pmt_intern("inband_1rxhb_1tx.rbf"));
+
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("interp-tx"),
+ pmt_from_long(64));
+
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(128));
+
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Create an instance of USRP server and connect ports
+ define_component("server", "usrp_server", usrp_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+ // initialize NCO
+ double freq = 100e3;
+ int interp = 32; // 32 -> 4MS/s
+ double sample_rate = 128e6 / interp;
+ d_nco.set_freq(2*M_PI * freq/sample_rate);
+}
+
+test_usrp_inband_underrun::~test_usrp_inband_underrun()
+{
+}
+
+void
+test_usrp_inband_underrun::initial_transition()
+{
+ opening_usrp();
+}
+
+// Handle message reads all incoming messages from USRP server which will be
+// initialization and ping responses. We perform actions based on the current
+// state and the event (ie, ping response)
+void
+test_usrp_inband_underrun::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t data = msg->data();
+ pmt_t port_id = msg->port_id();
+
+ pmt_t handle = PMT_F;
+ pmt_t status = PMT_F;
+ pmt_t dict = PMT_NIL;
+ std::string error_msg;
+
+ // Check the recv sample responses for underruns and count
+ if(pmt_eq(event, s_response_recv_raw_samples)) {
+ handle = pmt_nth(0, data);
+ status = pmt_nth(1, data);
+ dict = pmt_nth(4, data);
+
+ if(pmt_eq(status, PMT_T)) {
+ handle_recv_response(dict);
+ return;
+ }
+ else {
+ error_msg = "error while receiving samples:";
+ goto bail;
+ }
+ }
+
+
+ // Dispatch based on state
+ switch(d_state) {
+
+ //----------------------------- OPENING_USRP ----------------------------//
+ // We only expect a response from opening the USRP which should be succesful
+ // or failed.
+ case OPENING_USRP:
+
+ if(pmt_eq(event, s_response_open)) {
+
+ status = pmt_nth(1, data); // failed/succes
+
+ if(pmt_eq(status, PMT_T)) {
+ allocating_channels();
+ return;
+ }
+ else {
+ error_msg = "failed to open usrp:";
+ goto bail;
+ }
+
+ }
+
+ goto unhandled; // all other messages not handled in this state
+
+
+ //----------------------- ALLOCATING CHANNELS --------------------//
+ // When allocating channels, we need to wait for 2 responses from
+ // USRP server: one for TX and one for RX. Both are initialized to
+ // NIL so we know to continue to the next state once both are set.
+ case ALLOCATING_CHANNELS:
+
+ // A TX allocation response
+ if(pmt_eq(event, s_response_allocate_channel)
+ && pmt_eq(d_tx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful response, extract the channel
+ if(pmt_eq(status, PMT_T)) {
+
+ d_tx_chan = pmt_nth(2, data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received TX allocation"
+ << " on channel " << d_tx_chan << std::endl;
+
+ // If the RX has also been allocated already, we can continue
+ if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
+ enter_receiving();
+ enter_transmitting();
+ }
+
+ return;
+ }
+ else { // TX allocation failed
+ error_msg = "failed to allocate TX channel:";
+ goto bail;
+ }
+ }
+
+ // A RX allocation response
+ if(pmt_eq(event, s_response_allocate_channel)
+ && pmt_eq(d_rx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful response, extract the channel
+ if(pmt_eq(status, PMT_T)) {
+
+ d_rx_chan = pmt_nth(2, data);
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received RX allocation"
+ << " on channel " << d_rx_chan << std::endl;
+
+ // If the TX has also been allocated already, we can continue
+ if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
+ enter_receiving();
+ enter_transmitting();
+ }
+
+ return;
+ }
+ else { // RX allocation failed
+ error_msg = "failed to allocate RX channel:";
+ goto bail;
+ }
+ }
+
+ goto unhandled;
+
+ case WRITE_REGISTER:
+ goto unhandled;
+
+ case READ_REGISTER:
+ goto unhandled;
+
+ //-------------------------- TRANSMITTING ----------------------------//
+ // In the transmit state we count the number of underruns received and
+ // ballpark the number with an expected count (something >1 for starters)
+ case TRANSMITTING:
+
+ // Check that the transmits are OK
+ if (pmt_eq(event, s_response_xmit_raw_frame)){
+ handle = pmt_nth(0, data);
+ status = pmt_nth(1, data);
+
+ if (pmt_eq(status, PMT_T)){
+ handle_xmit_response(handle);
+ return;
+ }
+ else {
+ error_msg = "bad response-xmit-raw-frame:";
+ goto bail;
+ }
+ }
+
+ goto unhandled;
+
+ //------------------------- CLOSING CHANNELS ----------------------------//
+ // Check deallocation responses, once the TX and RX channels are both
+ // deallocated then we close the USRP.
+ case CLOSING_CHANNELS:
+
+ if (pmt_eq(event, s_response_deallocate_channel)
+ && pmt_eq(d_tx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful, set the port to NIL
+ if(pmt_eq(status, PMT_T)) {
+ d_tx_chan = PMT_NIL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received TX deallocation\n";
+
+ // If the RX is also deallocated, we can close the USRP
+ if(pmt_eq(d_rx_chan, PMT_NIL))
+ closing_usrp();
+
+ return;
+
+ } else {
+
+ error_msg = "failed to deallocate TX channel:";
+ goto bail;
+
+ }
+ }
+
+ if (pmt_eq(event, s_response_deallocate_channel)
+ && pmt_eq(d_rx->port_symbol(), port_id))
+ {
+ status = pmt_nth(1, data);
+
+ // If successful, set the port to NIL
+ if(pmt_eq(status, PMT_T)) {
+ d_rx_chan = PMT_NIL;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received RX deallocation\n";
+
+ // If the TX is also deallocated, we can close the USRP
+ if(pmt_eq(d_tx_chan, PMT_NIL))
+ closing_usrp();
+
+ return;
+
+ } else {
+
+ error_msg = "failed to deallocate RX channel:";
+ goto bail;
+
+ }
+ }
+
+ goto unhandled;
+
+ //--------------------------- CLOSING USRP ------------------------------//
+ // Once we have received a successful USRP close response, we shutdown all
+ // mblocks and exit.
+ case CLOSING_USRP:
+
+ if (pmt_eq(event, s_response_close)) {
+
+ status = pmt_nth(1, data);
+
+ if(pmt_eq(status, PMT_T)) {
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Successfully closed USRP\n";
+
+ std::cout << "\nUnderruns: " << d_n_underruns << std::endl;
+ fflush(stdout);
+
+ shutdown_all(PMT_T);
+ return;
+
+ } else {
+
+ error_msg = "failed to close USRP:";
+ goto bail;
+ }
+ }
+
+ goto unhandled;
+
+ case INIT:
+ goto unhandled;
+
+ }
+
+ // An error occured, print it, and shutdown all m-blocks
+ bail:
+ std::cerr << error_msg << data
+ << "status = " << status << std::endl;
+ shutdown_all(PMT_F);
+ return;
+
+ // Received an unhandled message for a specific state
+ unhandled:
+ if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
+ std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
+ << "in state "<< d_state << std::endl;
+
+}
+
+
+// Sends a command to USRP server to open up a connection to the
+// specified USRP, which is defaulted to USRP 0 on the system
+void
+test_usrp_inband_underrun::opening_usrp()
+{
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Opening USRP "
+ << d_which_usrp << std::endl;
+
+ d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp));
+ d_state = OPENING_USRP;
+}
+
+// RX and TX channels must be allocated so that the USRP server can
+// properly share bandwidth across multiple USRPs. No commands will be
+// successful to the USRP through the USRP server on the TX or RX channels until
+// a bandwidth allocation has been received.
+void
+test_usrp_inband_underrun::allocating_channels()
+{
+ d_state = ALLOCATING_CHANNELS;
+
+ long capacity = (long) 16e6;
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
+}
+
+// After allocating the channels, a write register command will be sent to the
+// USRP.
+void
+test_usrp_inband_underrun::write_register()
+{
+ d_state = WRITE_REGISTER;
+
+ long reg = 0;
+
+ d_tx->send(s_cmd_to_control_channel, // C/S packet
+ pmt_list2(PMT_NIL, // invoc handle
+ pmt_list1(
+ pmt_list2(s_op_write_reg,
+ pmt_list2(
+ pmt_from_long(reg),
+ pmt_from_long(0xbeef))))));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to "
+ << reg << std::endl;
+
+ read_register(); // immediately transition to read the register
+}
+
+// Temporary: for testing pings
+void
+test_usrp_inband_underrun::build_and_send_ping()
+{
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
+ pmt_list2(pmt_from_long(0),
+ pmt_from_long(0))))));
+
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Ping sent" << std::endl;
+}
+
+// After writing to the register, we want to read the value back and ensure that
+// it is the same value that we wrote.
+void
+test_usrp_inband_underrun::read_register()
+{
+ d_state = READ_REGISTER;
+
+ long reg = 9;
+
+ d_tx->send(s_cmd_to_control_channel, // C/S packet
+ pmt_list2(PMT_NIL, // invoc handle
+ pmt_list1(
+ pmt_list2(s_op_read_reg,
+ pmt_list2(
+ pmt_from_long(0), // rid
+ pmt_from_long(reg))))));
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Reading from register "
+ << reg << std::endl;
+}
+
+// Used to enter the receiving state
+void
+test_usrp_inband_underrun::enter_receiving()
+{
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_F,
+ d_rx_chan));
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Started RX sample stream\n";
+}
+
+void
+test_usrp_inband_underrun::enter_transmitting()
+{
+ d_state = TRANSMITTING;
+ d_nsamples_xmitted = 0;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Entering transmit state...\n";
+
+ build_and_send_next_frame(); // fire off 4 to start pipeline
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+ build_and_send_next_frame();
+}
+
+void
+test_usrp_inband_underrun::build_and_send_next_frame()
+{
+
+ long nsamples_this_frame =
+ std::min(d_nsamples_to_send - d_nsamples_xmitted,
+ d_samples_per_frame);
+
+ if (nsamples_this_frame == 0){
+ d_done_sending = true;
+ return;
+ }
+
+ size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
+ pmt_t uvec = pmt_make_s16vector(nshorts, 0);
+ size_t ignore;
+ int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
+
+ // fill in the complex sinusoid
+
+ for (int i = 0; i < nsamples_this_frame; i++){
+
+ if (1){
+ gr_complex s;
+ d_nco.sincos(&s, 1, d_amplitude);
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ else {
+ gr_complex s(d_amplitude, d_amplitude);
+
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ }
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Transmitting frame...\n";
+
+ pmt_t timestamp = pmt_from_long(0xffffffff); // NOW
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle
+ d_tx_chan, // channel
+ uvec, // the samples
+ timestamp));
+
+ d_nsamples_xmitted += nsamples_this_frame;
+ d_nframes_xmitted++;
+
+ if(verbose)
+ std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n";
+
+}
+
+void
+test_usrp_inband_underrun::handle_xmit_response(pmt_t handle)
+{
+ if (d_done_sending &&
+ pmt_to_long(handle) == (d_nframes_xmitted - 1)){
+ // We're done sending and have received all responses
+ closing_channels();
+ return;
+ }
+
+ build_and_send_next_frame();
+}
+
+void
+test_usrp_inband_underrun::handle_recv_response(pmt_t dict)
+{
+ if(!pmt_is_dict(dict)) {
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Recv samples dictionary is improper\n";
+ return;
+ }
+
+ // Read the TX interpolations
+ if(pmt_t underrun = pmt_dict_ref(dict,
+ pmt_intern("underrun"),
+ PMT_NIL)) {
+ if(pmt_eqv(underrun, PMT_T)) {
+ d_n_underruns++;
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] Underrun\n";
+ }
+ else {
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] No underrun\n" << underrun <<std::endl;
+ }
+ } else {
+
+ if(verbose && 0)
+ std::cout << "[TEST_USRP_INBAND_UNDERRUN] No underrun\n";
+ }
+
+}
+
+void
+test_usrp_inband_underrun::closing_channels()
+{
+ d_state = CLOSING_CHANNELS;
+
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
+}
+
+void
+test_usrp_inband_underrun::closing_usrp()
+{
+ d_state = CLOSING_USRP;
+
+ d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
+}
+
+REGISTER_MBLOCK_CLASS(test_usrp_inband_underrun);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDED_UI_NCO_H
+#define INCLUDED_UI_NCO_H
+
+
+#include <vector>
+#include <ui_sincos.h>
+#include <cmath>
+
+#include <complex>
+typedef std::complex<float> gr_complex;
+
+
+/*!
+ * \brief base class template for Numerically Controlled Oscillator (NCO)
+ */
+
+
+//FIXME Eventually generalize this to fixed point
+
+template<class o_type, class i_type>
+class ui_nco {
+public:
+ ui_nco () : phase (0), phase_inc(0) {}
+
+ virtual ~ui_nco () {}
+
+ // radians
+ void set_phase (double angle) {
+ phase = angle;
+ }
+
+ void adjust_phase (double delta_phase) {
+ phase += delta_phase;
+ }
+
+
+ // angle_rate is in radians / step
+ void set_freq (double angle_rate){
+ phase_inc = angle_rate;
+ }
+
+ // angle_rate is a delta in radians / step
+ void adjust_freq (double delta_angle_rate)
+ {
+ phase_inc += delta_angle_rate;
+ }
+
+ // increment current phase angle
+
+ void step ()
+ {
+ phase += phase_inc;
+ if (fabs (phase) > M_PI){
+
+ while (phase > M_PI)
+ phase -= 2*M_PI;
+
+ while (phase < -M_PI)
+ phase += 2*M_PI;
+ }
+ }
+
+ void step (int n)
+ {
+ phase += phase_inc * n;
+ if (fabs (phase) > M_PI){
+
+ while (phase > M_PI)
+ phase -= 2*M_PI;
+
+ while (phase < -M_PI)
+ phase += 2*M_PI;
+ }
+ }
+
+ // units are radians / step
+ double get_phase () const { return phase; }
+ double get_freq () const { return phase_inc; }
+
+ // compute sin and cos for current phase angle
+ void sincos (float *sinx, float *cosx) const;
+
+ // compute cos or sin for current phase angle
+ float cos () const { return std::cos (phase); }
+ float sin () const { return std::sin (phase); }
+
+ // compute a block at a time
+ void sin (float *output, int noutput_items, double ampl = 1.0);
+ void cos (float *output, int noutput_items, double ampl = 1.0);
+ void sincos (gr_complex *output, int noutput_items, double ampl = 1.0);
+ void sin (short *output, int noutput_items, double ampl = 1.0);
+ void cos (short *output, int noutput_items, double ampl = 1.0);
+ void sin (int *output, int noutput_items, double ampl = 1.0);
+ void cos (int *output, int noutput_items, double ampl = 1.0);
+
+protected:
+ double phase;
+ double phase_inc;
+};
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::sincos (float *sinx, float *cosx) const
+{
+ ui_sincosf (phase, sinx, cosx);
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::sin (float *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ output[i] = (float)(sin () * ampl);
+ step ();
+ }
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::cos (float *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ output[i] = (float)(cos () * ampl);
+ step ();
+ }
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::sin (short *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ output[i] = (short)(sin() * ampl);
+ step ();
+ }
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::cos (short *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ output[i] = (short)(cos () * ampl);
+ step ();
+ }
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::sin (int *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ output[i] = (int)(sin () * ampl);
+ step ();
+ }
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::cos (int *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ output[i] = (int)(cos () * ampl);
+ step ();
+ }
+}
+
+template<class o_type, class i_type>
+void
+ui_nco<o_type,i_type>::sincos (gr_complex *output, int noutput_items, double ampl)
+{
+ for (int i = 0; i < noutput_items; i++){
+ float cosx, sinx;
+ sincos (&sinx, &cosx);
+ output[i] = gr_complex(cosx * ampl, sinx * ampl);
+ step ();
+ }
+}
+
+#endif /* INCLUDED_UI_NCO_H */
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define _GNU_SOURCE // ask for GNU extensions if available
+
+#include "ui_sincos.h"
+#include <math.h>
+
+// ----------------------------------------------------------------
+
+#if defined (HAVE_SINCOS)
+
+void
+ui_sincos (double x, double *sinx, double *cosx)
+{
+ sincos (x, sinx, cosx);
+}
+
+#else
+
+void
+ui_sincos (double x, double *sinx, double *cosx)
+{
+ *sinx = sin (x);
+ *cosx = cos (x);
+}
+
+#endif
+
+// ----------------------------------------------------------------
+
+#if defined (HAVE_SINCOSF)
+
+void
+ui_sincosf (float x, float *sinx, float *cosx)
+{
+ sincosf (x, sinx, cosx);
+}
+
+#elif defined (HAVE_SINF) && defined (HAVE_COSF)
+
+void
+ui_sincosf (float x, float *sinx, float *cosx)
+{
+ *sinx = sinf (x);
+ *cosx = cosf (x);
+}
+
+#else
+
+void
+ui_sincosf (float x, float *sinx, float *cosx)
+{
+ *sinx = sin (x);
+ *cosx = cos (x);
+}
+
+#endif
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_UI_SINCOS_H
+#define INCLUDED_UI_SINCOS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// compute sine and cosine at the same time
+
+void ui_sincos (double x, double *sin, double *cos);
+void ui_sincosf (float x, float *sin, float *cos);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* INCLUDED_UI_SINCOS_H */
--- /dev/null
+#
+# Copyright 2007,2008 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = \
+ $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \
+ $(USRP_INCLUDES) $(BOOST_CPPFLAGS) $(CPPUNIT_INCLUDES) \
+ -I$(srcdir)/../../apps-inband $(WITH_INCLUDES)
+
+TESTS = test_inband
+
+EXTRA_DIST = \
+ usrp_server.mbh \
+ usrp_interface.mbh
+
+lib_LTLIBRARIES = \
+ libusrp-inband.la \
+ libusrp-inband-qa.la
+
+# ------------------------------------------------------------------------
+# Build the inband library
+
+BUILT_SOURCES = \
+ usrp_server_mbh.cc \
+ usrp_interface_mbh.cc
+
+usrp_server_mbh.cc : usrp_server.mbh
+ $(COMPILE_MBH) $(srcdir)/usrp_server.mbh usrp_server_mbh.cc
+
+usrp_interface_mbh.cc : usrp_interface.mbh
+ $(COMPILE_MBH) $(srcdir)/usrp_interface.mbh usrp_interface_mbh.cc
+
+libusrp_inband_la_SOURCES = \
+ $(BUILT_SOURCES) \
+ $(srcdir)/../../apps-inband/ui_sincos.c \
+ usrp_inband_usb_packet.cc \
+ usrp_rx.cc \
+ usrp_rx_stub.cc \
+ usrp_server.cc \
+ usrp_tx.cc \
+ usrp_tx_stub.cc \
+ usrp_usb_interface.cc
+
+libusrp_inband_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
+
+libusrp_inband_la_LIBADD = \
+ $(MBLOCK_LA) \
+ $(USRP_LA) \
+ -lstdc++
+
+include_HEADERS = \
+ usrp_inband_usb_packet.h \
+ usrp_rx.h \
+ usrp_rx_stub.h \
+ usrp_server.h \
+ usrp_tx.h \
+ usrp_tx_stub.h \
+ usrp_usb_interface.h
+
+noinst_HEADERS = \
+ qa_inband.h \
+ qa_inband_packet_prims.h \
+ qa_inband_usrp_server.h \
+ symbols_usrp_channel.h \
+ symbols_usrp_interface_cs.h \
+ symbols_usrp_low_level_cs.h \
+ symbols_usrp_rx.h \
+ symbols_usrp_rx_cs.h \
+ symbols_usrp_server_cs.h \
+ symbols_usrp_tx.h \
+ symbols_usrp_tx_cs.h
+
+# ------------------------------------------------------------------------
+# Build the qa code in its own library
+
+libusrp_inband_qa_la_SOURCES = \
+ qa_inband.cc \
+ qa_inband_packet_prims.cc \
+ qa_inband_usrp_server.cc
+
+# magic flags
+libusrp_inband_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version
+
+libusrp_inband_qa_la_LIBADD = \
+ libusrp-inband.la \
+ $(PMT_LA) \
+ $(CPPUNIT_LIBS) \
+ -lstdc++
+
+# ------------------------------------------------------------------------
+
+noinst_PROGRAMS = \
+ test_inband
+
+test_inband_SOURCES = test_inband.cc
+test_inband_LDADD = libusrp-inband-qa.la
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+import sys
+import struct
+from optparse import OptionParser
+
+from usb_packet import *
+
+def dump_packet(raw_pkt, outfile, dump_payload):
+ pkt = usb_packet(raw_pkt)
+ outfile.write(pkt.decoded_flags())
+ outfile.write(' chan= %2d len= %3d timestamp= 0x%08x rssi= % 2d tag= %2d\n' % (
+ pkt.chan(), pkt.payload_len(), pkt.timestamp(), pkt.rssi(), pkt.tag()))
+ if dump_payload:
+ assert pkt.payload_len() % 4 == 0
+ shorts = struct.unpack('<%dh' % (pkt.payload_len() // 2), pkt.payload())
+ for i in range(0, len(shorts), 2):
+ outfile.write(' %6d, %6d\n' % (shorts[i], shorts[i+1]))
+
+
+def dump_packets(infile, outfile, dump_payload):
+ raw_pkt = infile.read(512)
+ while raw_pkt:
+ if len(raw_pkt) != 512:
+ sys.stderr.write("File length is not a multiple of 512 bytes")
+ raise SystemExit, 1
+
+ dump_packet(raw_pkt, outfile, dump_payload)
+ raw_pkt = infile.read(512)
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option('-p', '--dump-payload', action='store_true', default=False,
+ help='dump payload in decimal and hex')
+
+ (options, files) = parser.parse_args()
+ if len(files) == 0:
+ dump_packets(sys.stdin, sys.stdout, options.dump_payload)
+ else:
+ for f in files:
+ dump_packets(open(f, "r"), sys.stdout, options.dump_payload)
+
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/usr/bin/env python
+
+import random
+import struct
+from pprint import pprint
+from usb_packet import *
+
+MAX_PAYLOAD = 504
+TIME_NOW = 0xffffffff
+
+
+class sequence_generator(object):
+ def __init__(self):
+ self.i = 0
+
+ def __call__(self):
+ t = self.i
+ self.i += 1
+ return t
+
+def gen_shuffled_lengths():
+ valid_lengths = range(0, MAX_PAYLOAD+1, 4) # [0, 4, 8, ... 504]
+ random.shuffle(valid_lengths)
+ return valid_lengths
+
+
+class packet_sequence_generator(object):
+ def __init__(self, channel, lengths):
+ self.next = sequence_generator()
+ self.channel = channel
+ self.lengths = lengths
+
+ def __call__(self, output_file):
+ gen_packet(output_file, self.channel, self.next, self.lengths[0])
+ del self.lengths[0]
+
+
+def gen_packet(output_file, channel, content_generator, payload_len):
+ assert (payload_len % 4) == 0
+ payload = []
+ n_iq = payload_len // 4
+ for n in range(n_iq):
+ payload.append(content_generator()) # I
+ payload.append(content_generator()) # Q
+ for n in range(MAX_PAYLOAD // 4 - n_iq):
+ payload.append(0x0000)
+ payload.append(0xffff)
+
+ assert (len(payload) == MAX_PAYLOAD // 2)
+
+ #print "\npayload_len =", payload_len
+ #pprint(payload)
+
+ output_file.write(make_header(FL_START_OF_BURST|FL_END_OF_BURST,
+ channel, payload_len, TIME_NOW))
+ output_file.write(struct.pack('<252h', *payload))
+
+
+def gen_all_valid_packet_lengths_1_channel(output_file):
+ lengths = gen_shuffled_lengths()
+ npkts = len(lengths) # number of packets we'll generator on each stream
+ pkt_gen_0 = packet_sequence_generator(0, lengths)
+ for i in range(npkts):
+ pkt_gen_0(output_file)
+
+ assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+
+
+def gen_all_valid_packet_lengths_2_channels(output_file):
+ lengths = gen_shuffled_lengths()
+ npkts = len(lengths) # number of packets we'll generator on each stream
+ pkt_gen_0 = packet_sequence_generator(0, lengths)
+ pkt_gen_1 = packet_sequence_generator(0x1f, gen_shuffled_lengths())
+ pkt_gen = (pkt_gen_0, pkt_gen_1)
+
+ which_gen = (npkts * [0]) + (npkts * [1])
+ random.shuffle(which_gen)
+
+ for i in which_gen:
+ pkt_gen[i](output_file)
+
+ assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+ assert pkt_gen_1.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+
+if __name__ == '__main__':
+ random.seed(0)
+ gen_all_valid_packet_lengths_1_channel(open("all_valid_packet_lengths_1_channel.dat", "w"))
+ gen_all_valid_packet_lengths_2_channels(open("all_valid_packet_lengths_2_channels.dat", "w"))
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <qa_inband.h>
+#include <qa_inband_packet_prims.h>
+#include <qa_inband_usrp_server.h>
+
+CppUnit::TestSuite *
+qa_inband::suite()
+{
+ CppUnit::TestSuite *s = new CppUnit::TestSuite("inband");
+
+ s->addTest (qa_inband_packet_prims::suite());
+ s->addTest (qa_inband_usrp_server::suite());
+
+ return s;
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_QA_INBAND_H
+#define INCLUDED_QA_INBAND_H
+
+#include <cppunit/TestSuite.h>
+
+//! collect all the tests for the user server
+
+class qa_inband {
+ public:
+ //! return suite of tests for all of usrp server
+ static CppUnit::TestSuite *suite();
+};
+
+#endif /* INCLUDED_QA_INBAND_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_inband_packet_prims.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+#include <string.h>
+#include <usrp_inband_usb_packet.h> // will change on gigabit crossover
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+void
+qa_inband_packet_prims::test_flags()
+{
+ transport_pkt pkt;
+
+ // Test each one of the flags while ensuring no other fields become set in the process
+ pkt.set_header(pkt.FL_START_OF_BURST,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_END_OF_BURST,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_OVERRUN,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_UNDERRUN,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_DROPPED,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ // test of all fields set
+ pkt.set_header(
+ pkt.FL_START_OF_BURST |
+ pkt.FL_END_OF_BURST |
+ pkt.FL_UNDERRUN |
+ pkt.FL_OVERRUN |
+ pkt.FL_DROPPED
+ ,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+
+}
+//////////////////////////////////////////////////////////////////////
+
+void
+qa_inband_packet_prims::test_fields()
+{
+ transport_pkt pkt;
+ void * payload;
+
+ // test word0 field exclusiveness
+ //
+ // I want to test max values of each field to ensure field boundaries
+ // but these max values could change based on technology? The
+ // max payload is returned by a private method so the code is not
+ // technology dependent
+ pkt.set_header(0,16,0,0);
+ CPPUNIT_ASSERT_EQUAL(16, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(0,0,8,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(8, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0,pkt.payload_len());
+
+ pkt.set_header(0,0,0,pkt.max_payload());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(pkt.max_payload(), pkt.payload_len());
+
+ // test timestamp, shouldn't have to test other fields since
+ // setting the timestamp only has the ability to affect one word
+ pkt.set_timestamp(54);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(54), pkt.timestamp());
+
+ // test the payload, ensure no other fields overwritten
+ //
+ // is there a better test for this?
+ pkt.set_header(0,0,0,0);
+ payload = malloc(pkt.payload_len());
+ memset(payload, 'f', pkt.payload_len());
+ memcpy(pkt.payload(), payload, pkt.payload_len());
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(pkt.payload(), payload, pkt.payload_len()));
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+ free(payload);
+
+}
+//////////////////////////////////////////////////////////////////////
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef QA_INBAND_PACKET_PRIMS_H
+#define QA_INBAND_PACKET_PRIMS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_inband_packet_prims : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_inband_packet_prims);
+ CPPUNIT_TEST(test_flags);
+ CPPUNIT_TEST(test_fields);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_flags();
+ void test_fields();
+
+};
+
+#endif /* INCLUDED_QA_INBAND_PACKET_PRIMS_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp_inband_usb_packet.h>
+#include <qa_inband_usrp_server.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+#include <usrp_server.h>
+#include <mblock/mblock.h>
+#include <mblock/runtime.h>
+#include <mblock/protocol_class.h>
+#include <mblock/class_registry.h>
+#include <vector>
+#include <iostream>
+#include <pmt.h>
+
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_tx.h>
+#include <symbols_usrp_rx.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_low_level_cs.h>
+
+typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
+
+static bool verbose = false;
+
+static pmt_t s_timeout = pmt_intern("%timeout");
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_alloc_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_nmsgs_to_recv;
+ long d_nrecvd;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ public:
+ qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_alloc_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_message(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_alloc_top::qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_nrecvd=0;
+ d_nmsgs_to_recv = 6;
+ d_nstatus=0;
+ d_nstatus_to_recv = 50;
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_server_dict = pmt_make_dict();
+ pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_server_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+qa_alloc_top::~qa_alloc_top(){}
+
+void
+qa_alloc_top::initial_transition()
+{
+ // Allocations should fail before open
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel,
+ s_err_usrp_not_opened),
+ pmt_from_long(1)));
+
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel,
+ s_err_usrp_not_opened),
+ pmt_from_long(1)));
+
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open, PMT_T),
+ pmt_from_long(0)));
+
+ d_cs->send(s_cmd_max_capacity,
+ pmt_list1(pmt_list2(s_response_max_capacity, PMT_T)));
+
+ d_cs->send(s_cmd_ntx_chan,
+ pmt_list1(pmt_list2(s_response_ntx_chan, PMT_T)));
+
+ d_cs->send(s_cmd_nrx_chan,
+ pmt_list1(pmt_list2(s_response_nrx_chan,PMT_T)));
+}
+
+void
+qa_alloc_top::run_tests()
+{
+ if(verbose)
+ std::cout << "[qa_alloc_top] Starting tests...\n";
+
+ // should be able to allocate 1 byte
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(PMT_T, pmt_from_long(1)));
+
+ // should not be able to allocate max capacity after 100 bytes were allocated
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(s_err_requested_capacity_unavailable,
+ pmt_from_long(d_max_capacity)));
+
+ // keep allocating a little more until all of the channels are used and test
+ // the error response we start at 1 since we've already allocated 1 channel
+ for(int i=1; i < d_ntx_chan; i++) {
+
+ if(verbose)
+ std::cout << "[qa_alloc_top] Sent allocation request...\n";
+
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+
+ d_nmsgs_to_recv++;
+ }
+
+ // No more channels after allocating all of them is expected
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(s_err_channel_unavailable,
+ pmt_from_long(1)));
+
+ // test out the same on the RX side
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(s_err_requested_capacity_unavailable,
+ pmt_from_long(d_max_capacity)));
+
+ for(int i=1; i < d_nrx_chan; i++) {
+
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+
+ d_nmsgs_to_recv++;
+ }
+
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(s_err_channel_unavailable,
+ pmt_from_long(1)));
+
+ // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes
+ // allocated
+ d_cs->send(s_cmd_current_capacity_allocation,
+ pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan)));
+}
+
+void
+qa_alloc_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ && pmt_eq(msg->signal(), s_response_allocate_channel))
+ check_message(msg);
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(2, data));
+ if(verbose)
+ std::cout << "[qa_alloc_top] USRP has max capacity of "
+ << d_max_capacity << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(2, data));
+ if(verbose)
+ std::cout << "[qa_alloc_top] USRP tx channels: "
+ << d_ntx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(2, data));
+ if(verbose)
+ std::cout << "[qa_alloc_top] USRP rx channels: "
+ << d_nrx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ check_message(msg);
+ }
+
+ d_nstatus++;
+
+ check_message(msg);
+
+ if(d_nstatus==d_nstatus_to_recv)
+ run_tests();
+ }
+}
+
+void
+qa_alloc_top::check_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+
+ pmt_t e_event = pmt_nth(0, expected);
+ pmt_t e_status = pmt_nth(1, expected);
+
+ d_nrecvd++;
+
+
+ if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
+ if(verbose)
+ std::cout << "Got: " << status << " Expected: " << e_status << "\n";
+ shutdown_all(PMT_F);
+ return;
+ } else {
+ if(verbose)
+ std::cout << "[qa_alloc_top] Received expected response for message "
+ << d_nrecvd << " (" << event << ")\n";
+ }
+
+ if(d_nrecvd == d_nmsgs_to_recv)
+ shutdown_all(PMT_T);
+}
+
+REGISTER_MBLOCK_CLASS(qa_alloc_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_dealloc_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ long d_nalloc_to_recv;
+ long d_nalloc_recvd;
+
+ long d_ndealloc_to_recv;
+ long d_ndealloc_recvd;
+
+ std::vector<long> d_tx_chans;
+ std::vector<long> d_rx_chans;
+
+ public:
+ qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_dealloc_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_allocation(mb_message_sptr msg);
+ void check_deallocation(mb_message_sptr msg);
+ void allocate_max();
+ void deallocate_all();
+};
+
+qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_ndealloc_recvd=0;
+ d_ndealloc_to_recv = 0;
+ d_nalloc_recvd=0;
+ d_nalloc_to_recv = 0; // auto-set
+ d_nstatus=0;
+ d_nstatus_to_recv = 4;
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_server_dict = pmt_make_dict();
+ pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_server_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+}
+
+qa_dealloc_top::~qa_dealloc_top(){}
+
+void
+qa_dealloc_top::initial_transition()
+{
+
+ if(verbose)
+ std::cout << "[qa_dealloc_top] Initializing...\n";
+
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open,PMT_T),
+ pmt_from_long(0)));
+
+ d_cs->send(s_cmd_max_capacity,
+ pmt_list1(pmt_list2(s_response_max_capacity,PMT_T)));
+
+ d_cs->send(s_cmd_ntx_chan,
+ pmt_list1(pmt_list2(s_response_ntx_chan,PMT_T)));
+
+ d_cs->send(s_cmd_nrx_chan,
+ pmt_list1(pmt_list2(s_response_nrx_chan,PMT_T)));
+}
+
+void
+qa_dealloc_top::allocate_max()
+{
+
+ // Keep allocating until we hit the maximum number of channels
+ for(int i=0; i < d_ntx_chan; i++) {
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T),
+ pmt_from_long(1))); // 1 byte is good enough
+
+ d_nalloc_to_recv++;
+ }
+
+ for(int i=0; i < d_nrx_chan; i++) {
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T),
+ pmt_from_long(1)));
+
+ d_nalloc_to_recv++;
+ }
+
+}
+
+void
+qa_dealloc_top::deallocate_all() {
+
+ // Deallocate all of the channels that were allocated from allocate_max()
+ for(int i=0; i < (int)d_tx_chans.size(); i++) {
+
+ if(verbose)
+ std::cout << "[qa_dealloc_top] Trying to dealloc TX "
+ << d_tx_chans[i] << std::endl;
+
+ d_tx->send(s_cmd_deallocate_channel,
+ pmt_list2(pmt_list2(s_response_deallocate_channel,PMT_T),
+ pmt_from_long(d_tx_chans[i])));
+
+ d_ndealloc_to_recv++;
+ }
+
+ // Deallocate the RX side now
+ for(int i=0; i < (int)d_rx_chans.size(); i++) {
+
+ if(verbose)
+ std::cout << "[qa_dealloc_top] Trying to dealloc RX "
+ << d_tx_chans[i] << std::endl;
+
+ d_rx->send(s_cmd_deallocate_channel,
+ pmt_list2(pmt_list2(s_response_deallocate_channel,PMT_T),
+ pmt_from_long(d_rx_chans[i])));
+
+ d_ndealloc_to_recv++;
+ }
+
+ // Should get permission denied errors trying to re-dealloc the channels, as
+ // we no longer have permission to them after deallocating
+ for(int i=0; i < (int)d_tx_chans.size(); i++) {
+
+ d_tx->send(s_cmd_deallocate_channel,
+ pmt_list2(pmt_list2(s_response_deallocate_channel,
+ s_err_channel_permission_denied),
+ pmt_from_long(d_tx_chans[i])));
+
+ d_ndealloc_to_recv++;
+ }
+
+ // Same for RX
+ for(int i=0; i < (int)d_rx_chans.size(); i++) {
+
+ d_rx->send(s_cmd_deallocate_channel,
+ pmt_list2(pmt_list2(s_response_deallocate_channel,
+ s_err_channel_permission_denied),
+ pmt_from_long(d_rx_chans[i])));
+
+ d_ndealloc_to_recv++;
+ }
+
+ // Try to deallocate a channel that doesn't exist on both sides, the last
+ // element in the vectors is the highest channel number, so we take that plus
+ // 1
+ d_ndealloc_to_recv+=2;
+ d_tx->send(s_cmd_deallocate_channel,
+ pmt_list2(pmt_list2(s_response_deallocate_channel,
+ s_err_channel_invalid),
+ pmt_from_long(d_rx_chans.back()+1)));
+
+ d_rx->send(s_cmd_deallocate_channel,
+ pmt_list2(pmt_list2(s_response_deallocate_channel,
+ s_err_channel_invalid),
+ pmt_from_long(d_rx_chans.back()+1)));
+
+
+ // The used capacity should be back to 0 now that we've deallocated everything
+ d_cs->send(s_cmd_current_capacity_allocation,
+ pmt_list1(pmt_list2(s_response_current_capacity_allocation,
+ PMT_T)));
+}
+
+void
+qa_dealloc_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ if(pmt_eq(event, pmt_intern("%shutdown")))
+ return;
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+
+ pmt_t e_event = pmt_nth(0, expected);
+ pmt_t e_status = pmt_nth(1, expected);
+
+ if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
+ if(verbose)
+ std::cout << "Got: " << status << " Expected: " << e_status << "\n";
+ shutdown_all(PMT_F);
+ return;
+ } else {
+ if(verbose)
+ std::cout << "[qa_alloc_top] Received expected response for message "
+ << d_ndealloc_recvd
+ << " (" << event << ")\n";
+ }
+
+ if (pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_allocate_channel)) {
+ check_allocation(msg);
+ }
+
+ }
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(2, data));
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(2, data));
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(2, data));
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ // the final command is a capacity check which should be 0, then we
+ // shutdown
+ pmt_t expected_result = pmt_from_long(0);
+ pmt_t result = pmt_nth(2, data);
+
+ if(pmt_eqv(expected_result, result)) {
+ shutdown_all(PMT_T);
+ return;
+ } else {
+ shutdown_all(PMT_F);
+ return;
+ }
+ }
+
+ d_nstatus++;
+
+ if(d_nstatus==d_nstatus_to_recv)
+ allocate_max();
+ }
+}
+
+
+void
+qa_dealloc_top::check_allocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ d_nalloc_recvd++;
+
+ if(!pmt_eqv(status, PMT_T)) {
+ shutdown_all(PMT_F);
+ return;
+ } else {
+ // store all of the allocate channel numbers
+ if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
+ d_tx_chans.push_back(pmt_to_long(channel));
+ if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ d_rx_chans.push_back(pmt_to_long(channel));
+ }
+
+ if(d_nalloc_recvd == d_nalloc_to_recv) {
+
+ if(verbose) {
+ std::cout << "[qa_dealloc_top] Allocated TX channels: ";
+ for(int i=0; i < (int)d_tx_chans.size(); i++)
+ std::cout << d_tx_chans[i] << " ";
+
+ std::cout << "\n[qa_dealloc_top] Allocated RX channels: ";
+ for(int i=0; i < (int)d_rx_chans.size(); i++)
+ std::cout << d_rx_chans[i] << " ";
+ std::cout << "\n";
+ }
+
+ deallocate_all(); // once we've allocated all of our channels, try to
+ // dealloc them
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_dealloc_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_open_close_top : public mb_mblock
+{
+ mb_port_sptr d_cs;
+
+ long d_max_capacity;
+
+ long d_nmsg_to_recv;
+ long d_nmsg_recvd;
+
+ public:
+ qa_open_close_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_open_close_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_cs(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_open_close_top::qa_open_close_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+
+ d_nmsg_to_recv=7;
+ d_nmsg_recvd=0;
+
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_server_dict = pmt_make_dict();
+ pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_server_dict);
+ connect("self", "cs", "server", "cs");
+}
+
+qa_open_close_top::~qa_open_close_top(){}
+
+void
+qa_open_close_top::initial_transition()
+{
+ run_tests();
+}
+
+void
+qa_open_close_top::run_tests()
+{
+ // std::cout << "[qa_open_close_top] Starting tests\n";
+
+ // A close before an open should fail
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,
+ s_err_usrp_already_closed)));
+
+ // Perform an open, and a second open which should fail
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open,PMT_T),
+ pmt_from_long(0)));
+
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open,
+ s_err_usrp_already_opened),
+ pmt_from_long(0)));
+
+ // A close should now be successful since the interface is open
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
+
+ // But, a second close should fail
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,
+ s_err_usrp_already_closed)));
+
+ // Just to be thorough, try an open and close again
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open,PMT_T),
+ pmt_from_long(0)));
+
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
+
+}
+
+
+void
+qa_open_close_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+ check_cs(msg);
+ }
+
+ d_nmsg_recvd++;
+
+ if(d_nmsg_to_recv == d_nmsg_recvd)
+ shutdown_all(PMT_T);
+}
+
+void
+qa_open_close_top::check_cs(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+
+ pmt_t e_event = pmt_nth(0, expected);
+ pmt_t e_status = pmt_nth(1, expected);
+
+ if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
+
+ if(verbose)
+ std::cout << "[qa_open_close_top] FAILED check_cs... Got: " << status
+ << " Expected: " << e_status
+ << " for event " << event << "\n";
+
+ shutdown_all(PMT_F);
+ } else {
+ if(verbose)
+ std::cout << "[qa_open_close_top] Received expected CS response ("
+ << event << ")\n";
+ }
+
+}
+
+REGISTER_MBLOCK_CLASS(qa_open_close_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_tx_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_tx_chan;
+ long d_rx_chan;
+
+ long d_nmsg_to_recv;
+ long d_nmsg_recvd;
+
+ public:
+ qa_tx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_tx_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_allocation(mb_message_sptr msg);
+ void check_deallocation(mb_message_sptr msg);
+ void check_xmit(mb_message_sptr msg);
+ void check_cs(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_tx_top::qa_tx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+
+ d_nmsg_to_recv=10;
+ d_nmsg_recvd=0;
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_server_dict = pmt_make_dict();
+ pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_server_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+}
+
+qa_tx_top::~qa_tx_top(){}
+
+void
+qa_tx_top::initial_transition()
+{
+ run_tests();
+}
+
+void
+qa_tx_top::run_tests()
+{
+ if(verbose)
+ std::cout << "[qa_tx_top] Starting tests\n";
+
+ // A transmit before an open should fail
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_list2(s_response_xmit_raw_frame,
+ s_err_usrp_not_opened),
+ pmt_from_long(0),
+ pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
+ pmt_from_long(0)));
+
+ // Now open
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open,PMT_T),
+ pmt_from_long(0)));
+
+ // Try to transmit on a channel that we have no allocation for
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_list2(s_response_xmit_raw_frame,
+ s_err_channel_permission_denied),
+ pmt_from_long(0),
+ pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
+ pmt_from_long(0)));
+
+ // Get a channel allocation and send on it, we assume 0 (FIXME) until 'defer'
+ // is implemented for simplicity
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
+ pmt_from_long(1)));
+
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_list2(s_response_xmit_raw_frame, PMT_T),
+ pmt_from_long(0),
+ pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
+ pmt_from_long(0)));
+
+ // Close should be successful
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
+
+ // After closing, a new transmit raw frame should fail again
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_list2(s_response_xmit_raw_frame,
+ s_err_usrp_not_opened),
+ pmt_from_long(0),
+ pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
+ pmt_from_long(0)));
+
+ // Reopen and retry before getting an allocation, the first xmit should fail,
+ // after we allocate it should work again
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open, PMT_T),
+ pmt_from_long(0)));
+
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_list2(s_response_xmit_raw_frame,
+ s_err_channel_permission_denied),
+ pmt_from_long(0),
+ pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
+ pmt_from_long(0)));
+
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
+ pmt_from_long(1)));
+
+ d_tx->send(s_cmd_xmit_raw_frame,
+ pmt_list4(pmt_list2(s_response_xmit_raw_frame,PMT_T),
+ pmt_from_long(0),
+ pmt_make_u32vector(transport_pkt::max_payload()/4, 0),
+ pmt_from_long(0)));
+
+ // A final close which should be successful
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
+
+}
+
+
+void
+qa_tx_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ if(pmt_eq(event, pmt_intern("%shutdown")))
+ return;
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+
+ pmt_t e_event = pmt_nth(0, expected);
+ pmt_t e_status = pmt_nth(1, expected);
+
+ if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
+ if(verbose)
+ std::cout << "[qa_xmit_top] Got: " << status
+ << " Expected: " << e_status
+ << "For signal: " << event << "\n";
+ shutdown_all(PMT_F);
+ return;
+ } else {
+ if(verbose)
+ std::cout << "[qa_xmit_top] Received expected response for message "
+ << d_nmsg_recvd
+ << " (" << event << ")\n";
+ }
+
+ if (pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_allocate_channel))
+ check_allocation(msg);
+
+ }
+
+ d_nmsg_recvd++;
+
+ if(d_nmsg_to_recv == d_nmsg_recvd){
+ shutdown_all(PMT_T);
+ return;
+ }
+}
+
+void
+qa_tx_top::check_allocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ if(pmt_eqv(status, PMT_T)) {
+ // store all of the allocate channel numbers
+ if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
+ d_tx_chan = pmt_to_long(channel);
+ if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ d_rx_chan = pmt_to_long(channel);
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_tx_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_rx_top : public mb_mblock
+{
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_rx_chan;
+
+ bool d_got_response_recv;
+
+ mb_time d_t0;
+ double d_delta_t;
+
+ public:
+ qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_rx_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_allocation(mb_message_sptr msg);
+ void check_deallocation(mb_message_sptr msg);
+ void check_xmit(mb_message_sptr msg);
+ void check_cs(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_rx_top::qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_got_response_recv(false)
+{
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_dict = pmt_make_dict();
+ // Set TX and RX interpolations
+ pmt_dict_set(usrp_dict,
+ pmt_intern("decim-rx"),
+ pmt_from_long(128));
+ pmt_dict_set(usrp_dict, pmt_intern("fake-usrp"), PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_dict);
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+}
+
+qa_rx_top::~qa_rx_top(){}
+
+void
+qa_rx_top::initial_transition()
+{
+ run_tests();
+}
+
+void
+qa_rx_top::run_tests()
+{
+ if(verbose)
+ std::cout << "[qa_rx_top] Starting tests\n";
+
+ d_cs->send(s_cmd_open, pmt_list2(pmt_list2(s_response_open,PMT_T), pmt_from_long(0)));
+
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T),
+ pmt_from_long(1)));
+
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_NIL,
+ pmt_from_long(0)));
+
+ // Schedule a small timeout in which we expect to have received at least one
+ // packet worth of samples from the stub
+ d_t0 = mb_time::time();
+ schedule_one_shot_timeout(d_t0 + 0.01, PMT_NIL);
+}
+
+
+void
+qa_rx_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ if(pmt_eq(event, pmt_intern("%shutdown")))
+ return;
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+
+ // If we get a timeout we shutdown
+ if(pmt_eq(event, s_timeout)) {
+ if(verbose)
+ std::cout << "[qa_rx_top] Got timeout\n";
+ d_rx->send(s_cmd_stop_recv_raw_samples,
+ pmt_list2(PMT_NIL,
+ pmt_from_long(0)));
+
+ d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T)));
+ return;
+ }
+
+ // For testing RX, an invocation handle is not generated by the stub,
+ // therefore the same approach for testing is not used. We simply
+ // expect all responses to be true.
+ if(pmt_eq(event, s_response_recv_raw_samples)) {
+ if(pmt_eqv(status, PMT_T)) {
+
+ if(verbose)
+ std::cout << "[qa_rx_top] Received expected response for message "
+ << " (" << event << ")\n";
+
+ // All we want is 1 response receive! Can't guarantee exact numbers
+ d_got_response_recv = true;
+ }
+ else {
+ if(verbose)
+ std::cout << "Got: " << status << " Expected: " << PMT_T << "\n";
+ shutdown_all(PMT_F);
+ }
+ return;
+ }
+
+ pmt_t e_event = pmt_nth(0, expected);
+ pmt_t e_status = pmt_nth(1, expected);
+
+ if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
+ if(verbose)
+ std::cout << "Got: " << status << " Expected: " << e_status << "\n";
+ shutdown_all(PMT_F);
+ return;
+ } else {
+ if(verbose)
+ std::cout << "[qa_rx_top] Received expected response for message "
+ << " (" << event << ")\n";
+ }
+
+ if (pmt_eq(msg->port_id(), d_rx->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_allocate_channel))
+ check_allocation(msg);
+
+ }
+
+ // We stop when we get a close, we are successful if we
+ // got a response from recv, fail if we never got a recv response
+ if(pmt_eq(msg->signal(), s_response_close)) {
+
+ if(d_got_response_recv) {
+ shutdown_all(PMT_T);
+ return;
+ }
+ else {
+ shutdown_all(PMT_F);
+ if(verbose)
+ std::cout << "[qa_rx_top] No response message before close\n";
+ return;
+ }
+ }
+}
+
+
+void
+qa_rx_top::check_allocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ if(pmt_eqv(status, PMT_T)) {
+ // store all of the allocate channel numbers
+ if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ d_rx_chan = pmt_to_long(channel);
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_rx_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_rid_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_npongs;
+ long d_tcycles;
+ long d_cycles;
+ long d_max_rid;
+
+ mb_time d_t0;
+ double d_delta_t;
+
+ public:
+ qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_rid_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void run_tests();
+ void send_max_pings();
+};
+
+qa_rid_top::qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_npongs = 0;
+ d_tcycles = 3;
+ d_cycles = d_tcycles;
+ d_max_rid = usrp_server::D_MAX_RID;
+ d_delta_t = 0.1;
+
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_server_dict = pmt_make_dict();
+ pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_server_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+qa_rid_top::~qa_rid_top(){}
+
+void
+qa_rid_top::initial_transition()
+{
+ run_tests();
+}
+
+void
+qa_rid_top::run_tests()
+{
+ if(verbose)
+ std::cout << "[qa_rid_top] Starting tests...\n";
+
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open, PMT_T),
+ pmt_from_long(0)));
+
+ // should be able to allocate 1 byte
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
+ pmt_from_long(1)));
+
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
+ pmt_from_long(1)));
+
+ // Need to start receiving to read from the USRP to get C/S responses
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_NIL,
+ pmt_from_long(0)));
+
+ // Build a subpacket of MAX_RID pings and wait a small amount for all of the
+ // responses and fire off another MAX_RID. If MAX_RID*2 responses are
+ // received, the RID recycling is working correctly.
+ // Schedule a timer in which we expect to have received all of the responses,
+ // which will send off another MAX_RID worth.
+ send_max_pings();
+ d_t0 = mb_time::time();
+ schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL);
+}
+
+void
+qa_rid_top::send_max_pings()
+{
+ pmt_t ping = pmt_list2(s_op_ping_fixed,
+ pmt_list2(pmt_from_long(0),
+ pmt_from_long(0)));
+
+ pmt_t sub_packets = PMT_NIL;
+
+ for(int i=0; i<d_max_rid; i++)
+ sub_packets = pmt_list_add(sub_packets, ping);
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ sub_packets));
+}
+
+void
+qa_rid_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ // If we get a timeout we ensure we got a maximum RID number of responses.
+ if(pmt_eq(event, s_timeout)) {
+ if(verbose)
+ std::cout << "[qa_rid_top] Got timeout, received so far: "
+ << d_npongs << "\n";
+
+ d_cycles--;
+
+ if(d_cycles==0 && d_npongs == d_max_rid*d_tcycles) {
+ shutdown_all(PMT_T);
+ }
+ else if(d_cycles==0) {
+
+ std::cout << "[qa_rid_top] d_npongs: " << d_npongs
+ << " expected: " << d_max_rid*d_tcycles
+ << std::endl;
+
+ shutdown_all(PMT_F);
+ }
+ else {
+ send_max_pings();
+ d_t0 = mb_time::time();
+ schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL);
+ }
+
+ }
+ else if(pmt_eq(event, s_response_from_control_channel))
+ {
+ d_npongs++;
+ }
+
+}
+
+REGISTER_MBLOCK_CLASS(qa_rid_top);
+
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_cs_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_nmsgs_to_recv;
+ long d_nrecvd;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ public:
+ qa_cs_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_cs_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_message(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_cs_top::qa_cs_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_nrecvd=0;
+ d_nmsgs_to_recv = 8;
+ d_nstatus=0;
+ d_nstatus_to_recv = 50;
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Use the stub with the usrp_server
+ pmt_t usrp_server_dict = pmt_make_dict();
+ pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T);
+
+ // Test the TX side
+ define_component("server", "usrp_server", usrp_server_dict);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+qa_cs_top::~qa_cs_top(){}
+
+void
+qa_cs_top::initial_transition()
+{
+ run_tests();
+}
+
+void
+qa_cs_top::run_tests()
+{
+ if(verbose)
+ std::cout << "[qa_cs_top] Starting tests...\n";
+
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_open,
+ pmt_list2(pmt_list2(s_response_open, PMT_T),
+ pmt_from_long(0)));
+
+ // should be able to allocate 1 byte
+ d_tx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
+ pmt_from_long(1)));
+
+ d_rx->send(s_cmd_allocate_channel,
+ pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T),
+ pmt_from_long(1)));
+
+ // Need to start receiving to read from the USRP to get C/S responses
+ d_rx->send(s_cmd_start_recv_raw_samples,
+ pmt_list2(PMT_NIL,
+ pmt_from_long(0)));
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ pmt_list1(
+ pmt_list2(s_op_ping_fixed,
+ pmt_list2(pmt_from_long(3),
+ pmt_from_long(0))))));
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ pmt_list1(
+ pmt_list2(s_op_write_reg,
+ pmt_list2(
+ pmt_from_long(0x3),
+ pmt_from_long(0x4))))));
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ pmt_list1(
+ pmt_list2(s_op_write_reg_masked,
+ pmt_list3(
+ pmt_from_long(0x3),
+ pmt_from_long(0x4),
+ pmt_from_long(0x5))))));
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ pmt_list1(
+ pmt_list2(s_op_read_reg,
+ pmt_list2(pmt_from_long(0),
+ pmt_from_long(0x6))))));
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ pmt_list1(
+ pmt_list2(s_op_delay,
+ pmt_list1(pmt_from_long(0x7))))));
+
+ pmt_t subpackets = pmt_list5(
+ pmt_list2(s_op_ping_fixed, pmt_list2(pmt_from_long(0), pmt_from_long(0))),
+ pmt_list2(s_op_delay, pmt_list1(pmt_from_long(0x7))),
+ pmt_list2(s_op_write_reg_masked, pmt_list3(pmt_from_long(3),
+ pmt_from_long(4),
+ pmt_from_long(5))),
+ pmt_list2(s_op_write_reg, pmt_list2(pmt_from_long(3),
+ pmt_from_long(4))),
+ pmt_list2(s_op_read_reg, pmt_list2(pmt_from_long(0),
+ pmt_from_long(6)))
+ );
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ subpackets));
+
+ pmt_t i2c_data = pmt_make_u8vector(8, 0xff);
+
+ subpackets = pmt_list2(
+ pmt_list2(s_op_i2c_write,
+ pmt_list2(pmt_from_long(8), i2c_data)),
+ pmt_list2(s_op_i2c_read,
+ pmt_list3(pmt_from_long(0), pmt_from_long(9), pmt_from_long(1)))
+
+ );
+
+ d_tx->send(s_cmd_to_control_channel,
+ pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T),
+ subpackets));
+
+}
+
+void
+qa_cs_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ && pmt_eq(msg->signal(), s_response_allocate_channel))
+ check_message(msg);
+
+ if (pmt_eq(msg->port_id(), d_tx->port_symbol())
+ && pmt_eq(msg->signal(), s_response_from_control_channel))
+ check_message(msg);
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(2, data));
+ if(verbose)
+ std::cout << "[qa_cs_top] USRP has max capacity of "
+ << d_max_capacity << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(2, data));
+ if(verbose)
+ std::cout << "[qa_cs_top] USRP tx channels: "
+ << d_ntx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(2, data));
+ if(verbose)
+ std::cout << "[qa_cs_top] USRP rx channels: "
+ << d_nrx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ check_message(msg);
+ }
+
+ d_nstatus++;
+
+ check_message(msg);
+
+ if(d_nstatus==d_nstatus_to_recv)
+ run_tests();
+ }
+}
+
+void
+qa_cs_top::check_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ pmt_t event = msg->signal();
+
+ pmt_t expected = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+
+ pmt_t e_event = pmt_nth(0, expected);
+ pmt_t e_status = pmt_nth(1, expected);
+
+ d_nrecvd++;
+
+
+ if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) {
+ if(verbose)
+ std::cout << "[qa_cs_top] Got: " << status << " Expected: " << e_status << "\n";
+ shutdown_all(PMT_F);
+ return;
+ } else {
+ if(verbose)
+ std::cout << "[qa_cs_top] Received expected response for message "
+ << d_nrecvd << " (" << event << ")\n";
+ }
+
+ if(d_nrecvd == d_nmsgs_to_recv)
+ shutdown_all(PMT_T);
+}
+
+REGISTER_MBLOCK_CLASS(qa_cs_top);
+
+// ----------------------------------------------------------------------------------------------
+
+void
+qa_inband_usrp_server::test_open_close()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n----------------------------\n";
+ // std::cout << " RUNNING OPEN/CLOSE TESTS \n";
+
+ rt->run("top", "qa_open_close_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_chan_allocation()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n----------------------------\n";
+ // std::cout << " RUNNING ALLOCATION TESTS \n";
+
+ rt->run("qa_alloc_top", "qa_alloc_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_chan_deallocation()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n----------------------------\n";
+ // std::cout << " RUNNING DEALLOCATION TESTS \n";
+
+ rt->run("qa_dealloc_top", "qa_dealloc_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_tx()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n-----------------\n";
+ // std::cout << " RUNNING TX TESTS \n";
+
+ rt->run("top", "qa_tx_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_rx()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n-----------------\n";
+ // std::cout << " RUNNING RX TESTS \n";
+
+ rt->run("top", "qa_rx_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_cs()
+{
+ // FIXME This test is disabled because it hangs with the change to use usrp_standard_*_sptr's
+ return;
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n-----------------\n";
+ // std::cout << " RUNNING CS TESTS \n";
+
+ rt->run("top", "qa_cs_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_rid()
+{
+ // FIXME This test is disabled because it hangs with the change to use usrp_standard_*_sptr's
+ return;
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ // std::cout << "\n\n-----------------\n";
+ // std::cout << " RUNNING RID TESTS \n";
+
+ rt->run("top", "qa_rid_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef QA_INBAND_USRP_SERVER_H
+#define QA_INBAND_USRP_SERVER_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_inband_usrp_server : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_inband_usrp_server);
+ CPPUNIT_TEST(test_open_close);
+ CPPUNIT_TEST(test_chan_allocation);
+ CPPUNIT_TEST(test_chan_deallocation);
+ CPPUNIT_TEST(test_tx);
+ CPPUNIT_TEST(test_rx);
+ CPPUNIT_TEST(test_cs);
+ CPPUNIT_TEST(test_rid);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_chan_allocation();
+ void test_chan_deallocation();
+ void test_open_close();
+ void test_tx();
+ void test_rx();
+ void test_cs();
+ void test_rid();
+};
+
+#endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_CHANNEL_H
+#define INCLUDED_SYMBOLS_USRP_CHANNEL_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel");
+static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel");
+
+// Incoming
+static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel");
+static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel");
+
+// Errors
+static pmt_t s_err_requested_capacity_unavailable = pmt_intern("err-requested-capacity-unavailable");
+static pmt_t s_err_channel_unavailable = pmt_intern("err-channel-unavailable");
+static pmt_t s_err_channel_invalid = pmt_intern("err-channel-invalid");
+static pmt_t s_err_channel_permission_denied = pmt_intern("err-channel-permission-denied");
+
+#endif /* INCLUDED_SYMBOLS_USRP_CHANNEL_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H
+#define INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_usrp_open = pmt_intern("cmd-usrp-open");
+static pmt_t s_cmd_usrp_close = pmt_intern("cmd-usrp-close");
+static pmt_t s_cmd_usrp_ntx_chan = pmt_intern("cmd-usrp-ntx-chan");
+static pmt_t s_cmd_usrp_nrx_chan = pmt_intern("cmd-usrp-nrx-chan");
+static pmt_t s_cmd_usrp_write = pmt_intern("cmd-usrp-write");
+static pmt_t s_cmd_usrp_start_reading = pmt_intern("cmd-usrp-start-reading");
+static pmt_t s_cmd_usrp_stop_reading = pmt_intern("cmd-usrp-stop-reading");
+
+// Incoming
+static pmt_t s_response_usrp_open = pmt_intern("response-usrp-open");
+static pmt_t s_response_usrp_close = pmt_intern("response-usrp-close");
+static pmt_t s_response_usrp_ntx_chan = pmt_intern("response-usrp-ntx-chan");
+static pmt_t s_response_usrp_nrx_chan = pmt_intern("response-usrp-nrx-chan");
+static pmt_t s_response_usrp_write = pmt_intern("response-usrp-write");
+static pmt_t s_response_usrp_read = pmt_intern("response-usrp-read");
+
+#endif /* INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H
+#define INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel");
+
+// Incoming
+static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel");
+
+// Subpackets
+static pmt_t s_op_ping_fixed = pmt_intern("op-ping-fixed");
+static pmt_t s_op_ping_fixed_reply = pmt_intern("op-ping-fixed-reply");
+static pmt_t s_op_write_reg = pmt_intern("op-write-reg");
+static pmt_t s_op_write_reg_masked = pmt_intern("op-write-reg-masked");
+static pmt_t s_op_read_reg = pmt_intern("op-read-reg");
+static pmt_t s_op_read_reg_reply = pmt_intern("op-read-reg-reply");
+static pmt_t s_op_i2c_write = pmt_intern("op-i2c-write");
+static pmt_t s_op_i2c_read = pmt_intern("op-i2c-read");
+static pmt_t s_op_i2c_read_reply = pmt_intern("op-i2c-read-reply");
+static pmt_t s_op_spi_write = pmt_intern("op-spi-write");
+static pmt_t s_op_spi_read = pmt_intern("op-spi-read");
+static pmt_t s_op_spi_read_reply = pmt_intern("op-spi-read-reply");
+static pmt_t s_op_delay = pmt_intern("op-delay");
+
+#endif /* INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_RX_H
+#define INCLUDED_SYMBOLS_USRP_RX_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples");
+static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples");
+
+// Incoming
+static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples");
+
+// Errors
+static pmt_t s_err_already_receiving = pmt_intern("err-already-receiving");
+
+#endif /* INCLUDED_SYMBOLS_USRP_RX_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_RX_CS_H
+#define INCLUDED_SYMBOLS_USRP_RX_CS_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_usrp_rx_start_reading = pmt_intern("cmd-usrp-rx-start-reading");
+
+// Incoming
+static pmt_t s_response_usrp_rx_read = pmt_intern("response-usrp-rx-read");
+
+#endif /* INCLUDED_SYMBOLS_USRP_RX_CS_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_SERVER_CS_H
+#define INCLUDED_SYMBOLS_USRP_SERVER_CS_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_open = pmt_intern("cmd-open");
+static pmt_t s_cmd_close = pmt_intern("cmd-close");
+static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity");
+static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan");
+static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan");
+static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation");
+
+// Incoming
+static pmt_t s_response_open = pmt_intern("response-open");
+static pmt_t s_response_close = pmt_intern("response-close");
+static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity");
+static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan");
+static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan");
+static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation");
+
+// Errors
+static pmt_t s_err_usrp_not_opened = pmt_intern("err-usrp-not-opened");
+static pmt_t s_err_usrp_already_opened = pmt_intern("err-usrp-already-opened");
+static pmt_t s_err_usrp_already_closed = pmt_intern("err-usrp-already-closed");
+
+#endif /* INCLUDED_SYMBOLS_USRP_SERVER_CS_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_TX_H
+#define INCLUDED_SYMBOLS_USRP_TX_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame");
+
+// Incoming
+static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame");
+
+#endif /* INCLUDED_SYMBOLS_USRP_TX_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_SYMBOLS_USRP_TX_CS_H
+#define INCLUDED_SYMBOLS_USRP_TX_CS_H
+
+#include <pmt.h>
+
+// Outgoing
+static pmt_t s_cmd_usrp_tx_write = pmt_intern("cmd-usrp-tx-write");
+
+// Incoming
+static pmt_t s_response_usrp_tx_write = pmt_intern("response-usrp-tx-write");
+
+#endif /* INCLUDED_SYMBOLS_USRP_TX_CS_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <cppunit/TextTestRunner.h>
+#include <qa_inband.h>
+
+int
+main(int argc, char **argv)
+{
+
+ CppUnit::TextTestRunner runner;
+
+ runner.addTest(qa_inband::suite ());
+
+ bool was_successful = runner.run("", false);
+
+ return was_successful ? 0 : 1;
+}
--- /dev/null
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+import struct
+
+
+FL_OVERRUN = 0x80000000
+FL_UNDERRUN = 0x40000000
+FL_DROPPED = 0x20000000
+FL_END_OF_BURST = 0x10000000
+FL_START_OF_BURST = 0x08000000
+
+FL_ALL_FLAGS = 0xf8000000
+
+FL_OVERRUN_SHIFT = 31
+FL_UNDERRUN_SHIFT = 30
+FL_DROPPED_SHIFT = 29
+FL_END_OF_BURST_SHIFT = 28
+FL_START_OF_BURST_SHIFT = 27
+
+RSSI_MASK = 0x3f
+RSSI_SHIFT = 21
+
+CHAN_MASK = 0x1f
+CHAN_SHIFT = 16
+
+TAG_MASK = 0xf
+TAG_SHIFT = 9
+
+PAYLOAD_LEN_MASK = 0x1ff
+PAYLOAD_LEN_SHIFT = 0
+
+def make_header(flags, chan, payload_len, timestamp, rssi=0, tag=0):
+ word0 = ((flags & FL_ALL_FLAGS)
+ | ((rssi & RSSI_MASK) << RSSI_SHIFT)
+ | ((chan & CHAN_MASK) << CHAN_SHIFT)
+ | ((tag & TAG_MASK) << TAG_SHIFT)
+ | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT))
+ word1 = timestamp
+ return struct.pack('<2I', word0, word1)
+
+
+def _decode(pred, indicator):
+ if pred:
+ return indicator
+ else:
+ return '-'
+
+
+class usb_packet(object):
+ def __init__(self, raw_pkt):
+ assert isinstance(raw_pkt, str) and len(raw_pkt) == 512
+ self._raw_pkt = raw_pkt;
+ (self._word0, self._word1) = struct.unpack('<2I', self._raw_pkt[0:8])
+
+ def timestamp(self):
+ return self._word1
+
+ def rssi(self):
+ return (self._word0 >> RSSI_SHIFT) & RSSI_MASK
+
+ def chan(self):
+ return (self._word0 >> CHAN_SHIFT) & CHAN_MASK
+
+ def tag(self):
+ return (self._word0 >> TAG_SHIFT) & TAG_MASK
+
+ def payload_len(self):
+ return (self._word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK
+
+ def flags(self):
+ return self._word0 & FL_ALL_FLAGS
+
+ def overrun(self):
+ return (self._word0 >> FL_OVERRUN_SHIFT) & 0x1
+
+ def underrun(self):
+ return (self._word0 >> FL_UNDERRUN_SHIFT) & 0x1
+
+ def start_of_burst(self):
+ return (self._word0 >> FL_START_OF_BURST_SHIFT) & 0x1
+
+ def end_of_burst(self):
+ return (self._word0 >> FL_END_OF_BURST_SHIFT) & 0x1
+
+ def dropped(self):
+ return (self._word0 >> FL_DROPPED_SHIFT) & 0x1
+
+ def payload(self):
+ return self._raw_pkt[8:8+self.payload_len()]
+
+ def decoded_flags(self):
+ s = (_decode(self.overrun(), 'O')
+ + _decode(self.underrun(), 'U')
+ + _decode(self.dropped(), 'D')
+ + _decode(self.end_of_burst(), 'E')
+ + _decode(self.start_of_burst(), 'S'))
+ return s
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp_inband_usb_packet.h>
+
+#include <usrp_bytesex.h>
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+
+/*!
+ * \brief Aligns the packet payload on a 32 bit boundary. This is essential to
+ * all control/status packets so that the inband FPGA code can parse them
+ * easily.
+ *
+ * \returns true if successful or if the packet was already aligned; false if it
+ * cannot be aligned.
+ */
+bool usrp_inband_usb_packet::align32()
+{
+ int p_len = payload_len();
+
+ int bytes_needed = 4 - (p_len % 4);
+
+ if(bytes_needed == 4)
+ return true;
+
+ // If the room left in the packet is less than the number of bytes
+ // needed, return false to indicate no room to align
+ if((MAX_PAYLOAD - p_len) < bytes_needed)
+ return false;
+
+ incr_header_len(bytes_needed);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a ping command to the current control packet.
+ *
+ * The \p rid is the rid to be associated with the ping response and \p ping_val
+ * is currently unused.
+ *
+ * \returns true if adding the ping command was successful, false otherwise
+ * (i.e. no space in the current packet).
+ */
+bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_PING_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t ping = (
+ ((OP_PING_FIXED & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_PING_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ | (ping_val & CS_PINGVAL_MASK)
+
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(ping);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_PING_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a ping response to the packet. This is used by the fake USRP
+ * code to generate fake responses for pings.
+ *
+ * The \p rid is the RID to be associated with the response and \p ping_val is
+ * currently unused.
+ *
+ * \returns true if the ping reply was added successfully, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_PING_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t ping = (
+ ((OP_PING_FIXED_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_PING_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ | ((ping_val & CS_PINGVAL_MASK) << CS_PINGVAL_SHIFT)
+
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(ping);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_PING_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a write register command to the packet.
+ *
+ * The \p reg_num is the register number for which the value \p val will be
+ * written to.
+ *
+ * \returns true if the command was added to the packet successfully, false
+ * otherwise.
+ */
+bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_WRITEREG_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word0 = 0;
+
+ // Build the first word which includes the register number
+ word0 = (
+ ((OP_WRITE_REG & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_WRITEREG_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word0);
+
+ // The second word is solely the register value to be written
+ // FIXME: should this be unsigned?
+ payload += 1;
+ *payload = host_to_usrp_u32((uint32_t) val);
+
+ // Rebuild the header to update the payload length
+ incr_header_len(CS_FIXED_LEN + CS_WRITEREG_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a write register masked command to the packet.
+ *
+ * The \p reg_num is the register number for which the value \p val will be
+ * written, masked by \p mask
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long mask)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_WRITEREGMASKED_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word0 = 0;
+
+ // Build the first word which includes the register number
+ word0 = (
+ ((OP_WRITE_REG_MASKED & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_WRITEREGMASKED_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word0);
+
+ // Skip over the first word and write the register value
+ payload += 1;
+ *payload = host_to_usrp_u32((uint32_t) val);
+
+ // Skip over the register value and write the mask
+ payload += 1;
+ *payload = host_to_usrp_u32((uint32_t) mask);
+
+ // Rebuild the header to update the payload length
+ incr_header_len(CS_FIXED_LEN + CS_WRITEREGMASKED_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a read register message to the packet.
+ *
+ * The \p rid will be the associated RID returned with the response, and \p
+ * reg_num is the register to be read.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_READREG_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t read_reg = (
+ ((OP_READ_REG & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_READREG_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
+
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(read_reg);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_READREG_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a read register reply response to the current packet. This is
+ * used by the fake USRP code to generate fake register read responses for
+ * testing.
+ *
+ * The \p rid is the associated RID to be included in the response, \p reg_num
+ * is the register the read is coming from, and \p reg_val is the value of the
+ * read.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_val)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_READREGREPLY_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word0 = (
+ ((OP_READ_REG_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_READREGREPLY_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT)
+
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word0);
+
+ // Hop to the next word and write the reg value
+ payload += 1;
+ *payload = host_to_usrp_u32((uint32_t) reg_val);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_READREGREPLY_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a delay command to the current packet.
+ *
+ * The \p ticks parameter is the number of clock ticks the FPGA should delay
+ * parsing for, which is added to the packet.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_delay(long ticks)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_DELAY_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t delay = (
+ ((OP_DELAY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_DELAY_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((ticks & CS_DELAY_MASK) << CS_DELAY_SHIFT)
+
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(delay);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_DELAY_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ int i2c_len = data_len + 2; // 2 bytes between mbz and addr
+
+ if((MAX_PAYLOAD - p_len) < (i2c_len + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word0 = 0;
+
+ word0 = (
+ ((OP_I2C_WRITE & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((i2c_len & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT)
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word0);
+
+ // Jump over the first word and write the data
+ // FIXME: Should the data be changed to usrp byte order?
+ payload += 1;
+ memcpy(payload, i2c_data, data_len);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + i2c_len);
+
+ return true;
+}
+
+/*!
+ * \brief Adds an I2C read command to the current packet.
+ *
+ * The \p rid is the associated RID to return with the read response, \p
+ * i2c_addr is the address to read from on the I2C bus, and \p n_bytes is the
+ * number of bytes to be read from the bus.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_I2CREAD_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word0 = 0;
+
+ word0 = (
+ ((OP_I2C_READ & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_I2CREAD_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT)
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word0);
+
+ // Jump a word and write the number of bytes to read
+ payload += 1;
+ uint32_t word1 =
+ (n_bytes & CS_I2CREADBYTES_MASK) << CS_I2CREADBYTES_SHIFT;
+ *payload = host_to_usrp_u32(word1);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_I2CREAD_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds an I2C read reply response to the current packet. This is used
+ * by the fake USRP code to generate fake I2C responses.
+ *
+ * The \p rid is the RID to be associated with the response, \p i2c_addr is the
+ * address on the I2C bus that the \p i2c_data of \p i2c_data_len was read from.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ int i2c_len = i2c_data_len + 2;
+
+ if((MAX_PAYLOAD - p_len) < (i2c_len + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word0 = 0;
+
+ word0 = (
+ ((OP_I2C_READ_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((i2c_len & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT)
+ );
+
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word0);
+
+ // Jump a word and write the actual data
+ payload += 1;
+ memcpy(payload, i2c_data, i2c_data_len);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + i2c_len);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a SPI write command to the current packet.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ int spi_len = spi_data_len + 6;
+
+ if((MAX_PAYLOAD - p_len) < (spi_len + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word = 0;
+
+ // First word contains the opcode and length, then mbz
+ word = (
+ ((OP_SPI_WRITE & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((spi_len & CS_LEN_MASK) << CS_LEN_SHIFT)
+ );
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word);
+
+ payload += 1;
+
+ // Second word contains the enables, format, and optional tx bytes
+ word = 0;
+ word = (
+ ((enables & CS_SPIENABLES_MASK) << CS_SPIENABLES_SHIFT)
+ | ((format & CS_SPIFORMAT_MASK) << CS_SPIFORMAT_SHIFT)
+ | ((opt_header_bytes & CS_SPIOPT_MASK) << CS_SPIOPT_SHIFT)
+ );
+ payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word);
+
+ payload += 1;
+ memcpy(payload, spi_data, spi_data_len);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + spi_len);
+
+ return true;
+}
+
+/*!
+ * \brief Adds a SPI bus read command to the packet.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ if((MAX_PAYLOAD - p_len) < (CS_SPIREAD_LEN + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word = 0;
+
+ // First word contains the opcode, length, and RID
+ word = (
+ ((OP_SPI_READ & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((CS_SPIREAD_LEN & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ );
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word);
+
+ payload += 1;
+
+ // Second word contains the enables, format, and optional tx bytes
+ word = 0;
+ word = (
+ ((enables & CS_SPIENABLES_MASK) << CS_SPIENABLES_SHIFT)
+ | ((format & CS_SPIFORMAT_MASK) << CS_SPIFORMAT_SHIFT)
+ | ((opt_header_bytes & CS_SPIOPT_MASK) << CS_SPIOPT_SHIFT)
+ );
+ payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word);
+
+ payload += 1;
+
+ // The third word contains the number of bytes
+ word = 0;
+ word = (
+ ((n_bytes & CS_SPINBYTES_MASK) << CS_SPINBYTES_SHIFT)
+ );
+ payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + CS_SPIREAD_LEN);
+
+ return true;
+}
+
+/*!
+ * \brief Adds an SPI read reply to the current packet. This is used by the
+ * fake USRP code to generate fake responses for SPI reads.
+ *
+ * \returns true if the command was added to the packet, false otherwise.
+ */
+bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len)
+{
+ if(!align32())
+ return false;
+
+ int p_len = payload_len();
+
+ int spi_len = spi_data_len + 2;
+
+ if((MAX_PAYLOAD - p_len) < (spi_len + CS_FIXED_LEN))
+ return false;
+
+ uint32_t word = 0;
+
+ // First word contains the opcode, length, and RID
+ word = (
+ ((OP_SPI_READ_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT)
+ | ((spi_len & CS_LEN_MASK) << CS_LEN_SHIFT)
+ | ((rid & CS_RID_MASK) << CS_RID_SHIFT)
+ );
+ uint32_t *payload = (uint32_t *) (d_payload + p_len);
+ *payload = host_to_usrp_u32(word);
+
+ // Jump a word and write the actual data
+ payload += 1;
+ memcpy(payload, spi_data, spi_data_len);
+
+ // Update payload length
+ incr_header_len(CS_FIXED_LEN + spi_len);
+
+ return true;
+}
+
+/*!
+ * \brief Since all control packets contain subpackets which have the length of
+ * the subpacket at a uniform location in the subpacket, this will return the
+ * subpacket length given a byte offset of the start of the subpacket from the beginning of the packet.
+ *
+ * \returns the length of the subpacket
+ */
+int usrp_inband_usb_packet::cs_len(int payload_offset) {
+ uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset)));
+ return (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK;
+}
+
+/*!
+ * \brief The following method takes an offset within the packet payload to
+ * extract a control/status subpacket and constructs a pmt response which
+ * includes the proper signal and arguments specified by usrp-low-level-cs. The
+ * USRP server could therefore use this to read subpackets and pass them
+ * responses back up to the application. It's arguable that only reply packets
+ * should be parsed here, however we parse others for use in debugging or
+ * failure reporting on the transmit side of packets.
+ */
+pmt_t usrp_inband_usb_packet::read_subpacket(int payload_offset) {
+
+ uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset)));
+ uint32_t opcode = (subpkt >> CS_OPCODE_SHIFT) & CS_OPCODE_MASK;
+ uint32_t len = (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK;
+
+ switch(opcode) {
+
+ case OP_PING_FIXED_REPLY:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+ pmt_t pingval = pmt_from_long((subpkt >> CS_PINGVAL_SHIFT) & CS_PINGVAL_MASK);
+ return pmt_list3(s_op_ping_fixed_reply, rid, pingval);
+ }
+
+ case OP_READ_REG_REPLY:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+ pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
+
+ // To get the register value we just read the next 32 bits
+ uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
+ pmt_t reg_val = pmt_from_long(val);
+
+ return pmt_list4(s_op_read_reg_reply, rid, reg_num, reg_val);
+ }
+
+ case OP_I2C_READ_REPLY:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+ pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK);
+
+ // Make a u8 vector to dump the data from the packet into
+ size_t i2c_data_len;
+ pmt_t i2c_data = pmt_make_u8vector(len - 2, 0); // skip rid+mbz+addr = 2 bytes
+ uint8_t *w_data =
+ (uint8_t *) pmt_u8vector_writable_elements(i2c_data, i2c_data_len);
+
+ memcpy(w_data, d_payload + payload_offset + 4, i2c_data_len); // skip first word
+
+ return pmt_list4(s_op_i2c_read_reply, rid, i2c_addr, i2c_data);
+ }
+
+ case OP_SPI_READ_REPLY:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+
+ // Make a u8 vector to dump the data from the packet into
+ size_t spi_data_len;
+ pmt_t spi_data = pmt_make_u8vector(len - 2, 0); // skip rid+mbz+addr = 2 bytes
+ uint8_t *w_data =
+ (uint8_t *) pmt_u8vector_writable_elements(spi_data, spi_data_len);
+
+ memcpy(w_data, d_payload + payload_offset + 4, spi_data_len); // skip first word
+
+ return pmt_list3(s_op_spi_read_reply, rid, spi_data);
+ }
+
+ case OP_PING_FIXED:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+ pmt_t pingval = pmt_from_long((subpkt >> CS_PINGVAL_SHIFT) & CS_PINGVAL_MASK);
+ return pmt_list3(s_op_ping_fixed, rid, pingval);
+ }
+
+ case OP_WRITE_REG:
+ {
+ pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
+
+ // To get the register value we just read the next 32 bits
+ uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
+ pmt_t reg_val = pmt_from_long(val);
+
+ return pmt_list3(s_op_write_reg, reg_num, reg_val);
+ }
+
+ case OP_WRITE_REG_MASKED:
+ {
+ pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
+
+ // To get the register value we just read the next 32 bits
+ uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
+ pmt_t reg_val = pmt_from_long(val);
+
+ // The mask is the next 32 bits
+ uint32_t mask = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 8)));
+ pmt_t reg_mask = pmt_from_long(mask);
+
+ return pmt_list4(s_op_write_reg_masked, reg_num, reg_val, reg_mask);
+ }
+
+ case OP_READ_REG:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+ pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK);
+
+ return pmt_list3(s_op_read_reg, rid, reg_num);
+ }
+
+ case OP_I2C_WRITE:
+ {
+ pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK);
+
+ // The length includes an extra 2 bytes for storing the mbz and addr
+ pmt_t i2c_data = pmt_make_u8vector(len-2, 0);
+
+ // Get a writable address to copy the data from the packet
+ size_t ignore;
+ uint8_t *w_data = (uint8_t *) pmt_u8vector_writable_elements(i2c_data, ignore);
+ memcpy(w_data, d_payload + payload_offset + 4, len-2);
+
+
+ return pmt_list3(s_op_i2c_write, i2c_addr, i2c_data);
+ }
+
+ case OP_I2C_READ:
+ {
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+ pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK);
+
+ // The number of bytes is in the next word
+ uint32_t bytes = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
+ bytes = (bytes >> CS_I2CREADBYTES_SHIFT) & CS_I2CREADBYTES_MASK;
+ pmt_t i2c_bytes = pmt_from_long(bytes);
+
+ return pmt_list4(s_op_i2c_read, rid, i2c_addr, i2c_bytes);
+ }
+
+ case OP_SPI_WRITE:
+ {
+ // Nothing interesting in the first word, skip to the next
+ uint32_t word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
+ pmt_t enables = pmt_from_long((word >> CS_SPIENABLES_SHIFT) & CS_SPIENABLES_MASK);
+ pmt_t format = pmt_from_long((word >> CS_SPIFORMAT_SHIFT) & CS_SPIFORMAT_MASK);
+ pmt_t opt = pmt_from_long((word >> CS_SPIOPT_SHIFT) & CS_SPIOPT_MASK);
+
+ // From the next word and on is data
+ size_t spi_data_len;
+ pmt_t spi_data = pmt_make_u8vector(len - 6, 0); // skip rid+mbz+addr = 2 bytes
+ uint8_t *w_data =
+ (uint8_t *) pmt_u8vector_writable_elements(spi_data, spi_data_len);
+
+ memcpy(w_data, d_payload + payload_offset + 8, spi_data_len); // skip first 2 words
+
+ return pmt_list5(s_op_spi_write, enables, format, opt, spi_data);
+ }
+
+ case OP_SPI_READ:
+ {
+ // Read the RID from the first word, the rest is mbz
+ pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK);
+
+ // Continue at the next word...
+ uint32_t word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4)));
+ pmt_t enables = pmt_from_long((word >> CS_SPIENABLES_SHIFT) & CS_SPIENABLES_MASK);
+ pmt_t format = pmt_from_long((word >> CS_SPIFORMAT_SHIFT) & CS_SPIFORMAT_MASK);
+ pmt_t opt = pmt_from_long((word >> CS_SPIOPT_SHIFT) & CS_SPIOPT_MASK);
+
+ // The number of bytes is the only thing to read in the next word
+ word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 8)));
+ pmt_t n_bytes = pmt_from_long((word >> CS_SPINBYTES_SHIFT) & CS_SPINBYTES_MASK);
+
+ return pmt_list6(s_op_spi_read, rid, enables, format, opt, n_bytes);
+ }
+
+ case OP_DELAY:
+ {
+ pmt_t ticks = pmt_from_long((subpkt >> CS_DELAY_SHIFT) & CS_DELAY_MASK);
+
+ return pmt_list2(s_op_delay, ticks);
+ }
+
+ default:
+ return PMT_NIL;
+
+ }
+}
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_USRP_INBAND_USB_PACKET_H_
+#define INCLUDED_USRP_INBAND_USB_PACKET_H_
+
+#include <usrp_bytesex.h>
+#include <mblock/mblock.h>
+#include <pmt.h>
+#include <iostream>
+
+#include <symbols_usrp_low_level_cs.h>
+
+static const int USB_PKT_SIZE = 512; // bytes
+static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t);
+static const int CONTROL_CHAN = 0x1f;
+
+class usrp_inband_usb_packet {
+ //
+ // keep raw packet in USRP-endian order
+ //
+ uint32_t d_word0;
+ uint32_t d_timestamp;
+ unsigned char d_payload[MAX_PAYLOAD];
+
+public:
+
+ enum opcodes {
+ OP_PING_FIXED = 0x00,
+ OP_PING_FIXED_REPLY = 0x01,
+ OP_WRITE_REG = 0x02,
+ OP_WRITE_REG_MASKED = 0x03,
+ OP_READ_REG = 0x04,
+ OP_READ_REG_REPLY = 0x05,
+ OP_I2C_WRITE = 0x06,
+ OP_I2C_READ = 0x07,
+ OP_I2C_READ_REPLY = 0x08,
+ OP_SPI_WRITE = 0x09,
+ OP_SPI_READ = 0x0a,
+ OP_SPI_READ_REPLY = 0x0b,
+ OP_DELAY = 0x0c
+ };
+
+ enum flags {
+ FL_OVERRUN = 0x80000000,
+ FL_UNDERRUN = 0x40000000,
+ FL_DROPPED = 0x20000000,
+ FL_START_OF_BURST = 0x10000000,
+ FL_END_OF_BURST = 0x08000000,
+ FL_CARRIER_SENSE = 0x04000000,
+
+ FL_ALL_FLAGS = 0xfc000000
+ };
+
+ static const int FL_OVERRUN_SHIFT = 31;
+ static const int FL_UNDERRUN_SHIFT = 30;
+ static const int FL_DROPPED_SHIFT = 29;
+ static const int FL_END_OF_BURST_SHIFT = 27;
+ static const int FL_START_OF_BURST_SHIFT = 28;
+
+ static const int RSSI_MASK = 0x3f;
+ static const int RSSI_SHIFT = 21;
+
+ static const int CHAN_MASK = 0x1f;
+ static const int CHAN_SHIFT = 16;
+
+ static const int TAG_MASK = 0xf;
+ static const int TAG_SHIFT = 9;
+
+ static const int PAYLOAD_LEN_MASK = 0x1ff;
+ static const int PAYLOAD_LEN_SHIFT = 0;
+
+ // Fixed size for opcode and length fields
+ static const int CS_FIXED_LEN = 2;
+
+ static const int CS_OPCODE_MASK = 0xff;
+ static const int CS_OPCODE_SHIFT = 24;
+
+ static const int CS_LEN_MASK = 0xff;
+ static const int CS_LEN_SHIFT = 16;
+
+ static const int CS_RID_MASK = 0x3f;
+ static const int CS_RID_SHIFT = 10;
+
+ static const int CS_PING_LEN = 2;
+ static const int CS_PINGVAL_MASK = 0x3ff;
+ static const int CS_PINGVAL_SHIFT = 0;
+
+ static const int CS_WRITEREG_LEN = 6;
+ static const int CS_WRITEREGMASKED_LEN = 10;
+ static const int CS_READREG_LEN = 2;
+ static const int CS_READREGREPLY_LEN = 6;
+ static const int CS_REGNUM_MASK = 0x3ff;
+ static const int CS_REGNUM_SHIFT = 0;
+
+ static const int CS_DELAY_LEN = 2;
+ static const int CS_DELAY_MASK = 0xffff;
+ static const int CS_DELAY_SHIFT = 0;
+
+ static const int CS_I2CADDR_MASK = 0x7f;
+ static const int CS_I2CADDR_SHIFT = 0;
+
+ static const int CS_I2CREAD_LEN = 3;
+ static const int CS_I2CREADBYTES_MASK = 0x7f;
+ static const int CS_I2CREADBYTES_SHIFT = 24;
+
+ static const int CS_SPIOPT_MASK = 0xffff;
+ static const int CS_SPIOPT_SHIFT = 0;
+ static const int CS_SPIFORMAT_MASK = 0xff;
+ static const int CS_SPIFORMAT_SHIFT = 16;
+ static const int CS_SPIENABLES_MASK = 0xff;
+ static const int CS_SPIENABLES_SHIFT = 24;
+ static const int CS_SPIREAD_LEN = 7;
+ static const int CS_SPINBYTES_MASK = 0xff;
+ static const int CS_SPINBYTES_SHIFT = 24;
+
+public:
+
+ void set_timestamp(uint32_t timestamp){
+ d_timestamp = host_to_usrp_u32(timestamp);
+ }
+
+ void set_end_of_burst() {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ word0 |= 1<<FL_END_OF_BURST_SHIFT;
+ d_word0 = host_to_usrp_u32(word0);
+ }
+
+ void set_header(int flags, int chan, int tag, int payload_len){
+ uint32_t word0 = ((flags & FL_ALL_FLAGS)
+ | ((chan & CHAN_MASK) << CHAN_SHIFT)
+ | ((tag & TAG_MASK) << TAG_SHIFT)
+ | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT));
+ d_word0 = host_to_usrp_u32(word0);
+ }
+
+ void incr_header_len(int val) {
+ set_header(flags(), chan(), tag(), payload_len() + val);
+ }
+
+ uint32_t timestamp() const {
+ return usrp_to_host_u32(d_timestamp);
+ }
+
+ int rssi() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> RSSI_SHIFT) & RSSI_MASK;
+ }
+
+ int chan() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> CHAN_SHIFT) & CHAN_MASK;
+ }
+
+ int tag() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> TAG_SHIFT) & TAG_MASK;
+ }
+
+ int payload_len() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK;
+ }
+
+ int flags() const {
+ return usrp_to_host_u32(d_word0) & FL_ALL_FLAGS;
+ }
+
+ int overrun() const {
+ return (usrp_to_host_u32(d_word0) & FL_OVERRUN) >> FL_OVERRUN_SHIFT;
+ }
+
+
+ int underrun() const {
+ return (usrp_to_host_u32(d_word0) & FL_UNDERRUN) >> FL_UNDERRUN_SHIFT;
+ }
+
+
+ int start_of_burst() const {
+ return (usrp_to_host_u32(d_word0) & FL_START_OF_BURST) >> FL_START_OF_BURST_SHIFT;
+ }
+
+ int end_of_burst() const {
+ return (usrp_to_host_u32(d_word0) & FL_END_OF_BURST) >> FL_END_OF_BURST_SHIFT;
+ }
+
+ int dropped() const {
+ return (usrp_to_host_u32(d_word0) & FL_DROPPED) >> FL_DROPPED_SHIFT;
+ }
+
+ unsigned char *payload() {
+ return d_payload;
+ }
+
+ static int max_payload() {
+ return MAX_PAYLOAD;
+ }
+
+ static int max_pkt_size() {
+ return USB_PKT_SIZE;
+ }
+
+ // C/S methods
+ bool align32();
+ bool cs_ping(long rid, long ping_val);
+ bool cs_ping_reply(long rid, long ping_val);
+ bool cs_write_reg(long reg_num, long val);
+ bool cs_write_reg_masked(long reg_num, long val, long mask);
+ bool cs_read_reg(long rid, long reg_num);
+ bool cs_read_reg_reply(long rid, long reg_num, long reg_val);
+ bool cs_delay(long ticks);
+ bool cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len);
+ bool cs_i2c_read(long rid, long i2c_addr, long n_bytes);
+ bool cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len);
+ bool cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len);
+ bool cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes);
+ bool cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len);
+ int cs_len(int payload_offset);
+ pmt_t read_subpacket(int payload_offset);
+};
+
+#endif
--- /dev/null
+;; -*- scheme -*- ; not really, but tells emacs how to format this
+;;
+;; Copyright 2007 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Radio
+;;
+;; GNU Radio is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; GNU Radio is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program; if not, write to the Free Software Foundation, Inc.,
+;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+;;
+
+;; ----------------------------------------------------------------
+;; This is an mblock header file
+;;
+;; The format is very much a work-in-progress.
+;; It'll be compiled to C++.
+;; ----------------------------------------------------------------
+
+;; ----------------------------------------------------------------
+;; usrp-interface-cs
+;;
+;; Handles interaction between the usrp_sever and the USB interface
+
+(define-protocol-class usrp-interface-cs
+
+ (:outgoing
+ (cmd-usrp-open invocation-handle which-usrp)
+ (cmd-usrp-close invocation-handle)
+ (cmd-usrp-ntx-chan invocation-handle)
+ (cmd-usrp-nrx-chan invocation-handle)
+ (cmd-usrp-write invocation-handle channel data)
+ (cmd-usrp-start-reading invocation-handle channel)
+ )
+
+ (:incoming
+ (response-usrp-open invocation-handle status)
+ (response-usrp-close invocation-handle status)
+ (response-usrp-ntx-chan invocation-handle ntx-chan)
+ (response-usrp-nrx-chan invocation-handle nrx-chan)
+ (response-usrp-write invocation-handle status channel)
+ (response-usrp-read invocation-handle status data)
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-tx-cs
+;;
+;; Handles interaction between the USB interface and TX interface
+
+(define-protocol-class usrp-tx-cs
+
+ (:outgoing
+ (cmd-usrp-tx-write invocation-handle channel data tx-handle)
+ )
+
+ (:incoming
+ (response-usrp-tx-write invocation-handle status channel)
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-rx-cs
+;;
+;; Handles interaction between the USB interface and RX interface
+
+(define-protocol-class usrp-rx-cs
+
+ (:outgoing
+ (cmd-usrp-rx-start-reading invocation-handle rx-handle)
+ (cmd-usrp-rx-stop-reading invocation-handle)
+ )
+
+ (:incoming
+ (response-usrp-rx-read invocation-handle status data)
+
+ ;; There is currently no response to a stop reading
+ )
+ )
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp_rx.h>
+
+#include <usrp_standard.h>
+#include <iostream>
+#include <vector>
+#include <usb.h>
+#include <mblock/class_registry.h>
+#include <usrp_inband_usb_packet.h>
+#include <fpga_regs_common.h>
+#include <stdio.h>
+
+#include <symbols_usrp_rx_cs.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+static const bool verbose = false;
+
+bool usrp_rx_stop;
+
+usrp_rx::usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_disk_write(false),
+ d_disk_write_pkt(false) // if true, writes full packet, else just the payload
+{
+ d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL);
+
+ if(d_disk_write) {
+ d_ofile0.open("rx_data_chan0.dat",std::ios::binary|std::ios::out);
+ d_ofile1.open("rx_data_chan1.dat",std::ios::binary|std::ios::out);
+ d_cs_ofile.open("rx_cs.dat",std::ios::binary|std::ios::out);
+ }
+
+ usrp_rx_stop = false;
+
+}
+
+usrp_rx::~usrp_rx()
+{
+ if(d_disk_write) {
+ d_ofile0.close();
+ d_ofile1.close();
+ d_cs_ofile.close();
+ }
+}
+
+void
+usrp_rx::initial_transition()
+{
+
+}
+
+/*!
+ * \brief Handles incoming signals to to the m-block, wihch should only ever be
+ * a single message: cmd-usrrp-rx-start-reading. There is no signal to stop
+ * reading as the m-block goes in to a forever loop to read inband packets from
+ * the bus.
+ */
+void
+usrp_rx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t port_id = msg->port_id();
+ pmt_t data = msg->data();
+
+ // Theoretically only have 1 message to ever expect, but
+ // want to make sure its at least what we want
+ if(pmt_eq(port_id, d_cs->port_symbol())) {
+
+ if(pmt_eqv(event, s_cmd_usrp_rx_start_reading))
+ read_and_respond(data);
+ }
+}
+
+/*!
+ * \brief Performs the actual reading of data from the USB bus, called by
+ * handle_message() when a cmd-usrp-rx-start-reading signal is received.
+ *
+ * The method enters a forever loop where it continues to read data from the bus
+ * and generate read responses to the higher layer. Currently, shared memory is
+ * used to exit this loop.
+ *
+ * The \p data parameter is a PMT list which contains only a single element, an
+ * invocation handle which will be returned with all read respones.
+ */
+void
+usrp_rx::read_and_respond(pmt_t data)
+{
+ size_t ignore;
+ bool underrun;
+ unsigned int n_read;
+ unsigned int pkt_size = sizeof(transport_pkt);
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ // Need the handle to the RX port to send responses, this is passed
+ // by the USRP interface m-block
+ pmt_t handle = pmt_nth(1, data);
+ d_urx =
+ boost::any_cast<usrp_standard_rx_sptr>(pmt_any_ref(handle));
+
+ if(verbose)
+ std::cout << "[usrp_rx] Waiting for packets..\n";
+
+ // Read by 512 which is packet size and send them back up
+ while(!usrp_rx_stop) {
+
+ pmt_t v_pkt = pmt_make_u8vector(pkt_size, 0);
+ transport_pkt *pkt =
+ (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, ignore);
+
+ n_read = d_urx->read(pkt, pkt_size, &underrun);
+
+ if(n_read != pkt_size) {
+ std::cerr << "[usrp_rx] Error reading packet, shutting down\n";
+ d_cs->send(s_response_usrp_rx_read,
+ pmt_list3(PMT_NIL, PMT_F, PMT_NIL));
+ return;
+ }
+
+ if(underrun && verbose && 0)
+ std::cout << "[usrp_rx] Underrun\n";
+
+ d_cs->send(s_response_usrp_rx_read,
+ pmt_list3(PMT_NIL, PMT_T, v_pkt));
+ if(verbose && 0)
+ std::cout << "[usrp_rx] Read 1 packet\n";
+
+ if(d_disk_write) {
+ if(pkt->chan() == CONTROL_CHAN)
+ d_cs_ofile.write((const char *)pkt, transport_pkt::max_pkt_size());
+ else {
+ if(d_disk_write_pkt) {
+ if(pkt->chan() == 0)
+ d_ofile0.write((const char *)pkt, transport_pkt::max_pkt_size());
+ else if(pkt->chan() == 1)
+ d_ofile1.write((const char *)pkt, transport_pkt::max_pkt_size());
+ } else {
+ if(pkt->chan() == 0)
+ d_ofile0.write((const char *)pkt->payload(), transport_pkt::max_payload());
+ else if(pkt->chan() == 1)
+ d_ofile1.write((const char *)pkt->payload(), transport_pkt::max_payload());
+ }
+ }
+
+ d_cs_ofile.flush();
+ d_ofile0.flush();
+ d_ofile1.flush();
+ }
+ }
+
+ usrp_rx_stop = false;
+
+ if(verbose) {
+ std::cout << "[USRP_RX] Stopping...\n";
+ fflush(stdout);
+ }
+}
+
+REGISTER_MBLOCK_CLASS(usrp_rx);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_RX_H
+#define INCLUDED_USRP_RX_H
+
+#include <mblock/mblock.h>
+#include <fstream>
+#include "usrp_standard.h"
+
+extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub
+
+/*!
+ * \brief Implements the low level usb interface to the USRP
+ */
+class usrp_rx : public mb_mblock
+{
+ mb_port_sptr d_cs;
+ usrp_standard_rx_sptr d_urx;
+
+ bool d_disk_write;
+ bool d_disk_write_pkt;
+ std::ofstream d_ofile0;
+ std::ofstream d_ofile1;
+ std::ofstream d_cs_ofile;
+
+ public:
+ usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_rx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ private:
+ void read_and_respond(pmt_t data);
+ void read_data();
+
+};
+
+
+#endif /* INCLUDED_USRP_RX_H */
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp_rx_stub.h>
+
+#include <iostream>
+#include <vector>
+#include <usb.h>
+#include <mblock/class_registry.h>
+#include <usrp_inband_usb_packet.h>
+#include <fpga_regs_common.h>
+#include "usrp_standard.h"
+#include <stdio.h>
+#include <string.h>
+#include <ui_nco.h>
+#include <fstream>
+
+#include <symbols_usrp_rx_cs.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+static const bool verbose = false;
+
+bool usrp_rx_stop_stub;
+
+// Used for the fake control packet response code to send the responses back up
+// the RX. The TX stub dumps responses in to this queue.
+std::queue<pmt_t> d_cs_queue;
+
+usrp_rx_stub::usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_samples_per_frame((long)(126)),
+ d_decim_rx(128),
+ d_amplitude(16384),
+ d_disk_write(false)
+{
+
+ // Information about the rates are passed all the way from the app in the form
+ // of a dictionary. We use this to read the RX decimation rate and compute
+ // the approximate number of MS/s as a form of flow control for the stub.
+ pmt_t usrp_dict = user_arg;
+
+ if (pmt_is_dict(usrp_dict)) {
+ // Read the RX decimation rate
+ if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
+ pmt_intern("decim-rx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(decim_rx, PMT_NIL))
+ d_decim_rx = pmt_to_long(decim_rx);
+ }
+ }
+
+ d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL);
+
+ // initialize NCO
+ double freq = 100e3;
+ int interp = 32; // 32 -> 4MS/s
+ double sample_rate = 64e6 / interp;
+ d_nco.set_freq(2*M_PI * freq/sample_rate);
+
+ //d_disk_write = true;
+
+ if(d_disk_write)
+ d_ofile.open("raw_rx.dat",std::ios::binary|std::ios::out);
+
+ usrp_rx_stop_stub = false;
+}
+
+usrp_rx_stub::~usrp_rx_stub()
+{
+ if(d_disk_write)
+ d_ofile.close();
+}
+
+void
+usrp_rx_stub::initial_transition()
+{
+}
+
+void
+usrp_rx_stub::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t port_id = msg->port_id();
+ pmt_t data = msg->data();
+
+ if (pmt_eq(msg->signal(), s_timeout)
+ && !pmt_eq(msg->data(), s_done)) {
+
+ if(!usrp_rx_stop_stub)
+ read_and_respond();
+ else { // requested to stop
+ cancel_timeout(msg->metadata());
+ usrp_rx_stop_stub=false;
+ if(verbose)
+ std::cout << "[USRP_RX_STUB] Stopping RX stub\n";
+ }
+
+ }
+
+ // Theoretically only have 1 message to ever expect, but
+ // want to make sure its at least what we want
+ if(pmt_eq(port_id, d_cs->port_symbol())
+ && pmt_eqv(event, s_cmd_usrp_rx_start_reading)) {
+
+ if(verbose)
+ std::cout << "[USRP_RX_STUB] Starting with decim @ "
+ << d_decim_rx << std::endl;
+
+ start_packet_timer();
+ }
+}
+
+// Setup a periodic timer which will drive packet generation
+void
+usrp_rx_stub::start_packet_timer()
+{
+ d_t0 = mb_time::time(); // current time
+
+ // Calculate the inter-packet arrival time.
+ double samples_per_sec = (64.0/(double)d_decim_rx)*1000000.0;
+ double frames_per_sec = samples_per_sec / (double)d_samples_per_frame;
+ double frame_rate = 1.0 / frames_per_sec;
+
+ if(verbose) {
+ std::cout << "[USRP_RX_STUB] Scheduling periodic packet generator\n";
+ std::cout << "\tsamples_per_sec: " << samples_per_sec << std::endl;
+ std::cout << "\tframes_per_sec: " << frames_per_sec << std::endl;
+ std::cout << "\tframe_rate: " << frame_rate << std::endl;
+ }
+
+ schedule_periodic_timeout(d_t0 + frame_rate, mb_time(frame_rate), PMT_T);
+}
+
+void
+usrp_rx_stub::read_and_respond()
+{
+
+ long nsamples_this_frame = d_samples_per_frame;
+
+ size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q
+ long channel = 0;
+ long n_bytes = nshorts*2;
+ pmt_t uvec = pmt_make_s16vector(nshorts, 0);
+ size_t ignore;
+ int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore);
+
+ // fill in the complex sinusoid
+
+ for (int i = 0; i < nsamples_this_frame; i++){
+
+ if (1){
+ gr_complex s;
+ d_nco.sincos(&s, 1, d_amplitude);
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ else {
+ gr_complex s(d_amplitude, d_amplitude);
+
+ // write 16-bit i & q
+ samples[2*i] = (int16_t) s.real();
+ samples[2*i+1] = (int16_t) s.imag();
+ }
+ }
+
+ if(d_disk_write)
+ d_ofile.write((const char *)samples, n_bytes);
+
+ pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0);
+ transport_pkt *pkt =
+ (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, ignore);
+
+ pkt->set_header(0, channel, 0, n_bytes);
+ pkt->set_timestamp(0xffffffff);
+ memcpy(pkt->payload(), samples, n_bytes);
+
+ d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt));
+
+ // Now lets check the shared CS queue between the TX and RX stub. Each
+ // element in a queue is a list where the first element is an invocation
+ // handle and the second element is a PMT u8 vect representation of the
+ // CS packet response which can just be passed transparently.
+ while(!d_cs_queue.empty()) {
+
+ pmt_t cs_pkt = d_cs_queue.front();
+ d_cs_queue.pop();
+
+ pmt_t invocation_handle = pmt_nth(0, cs_pkt);
+ pmt_t v_pkt = pmt_nth(1, cs_pkt);
+
+ d_cs->send(s_response_usrp_rx_read,
+ pmt_list3(invocation_handle,
+ PMT_T,
+ v_pkt)); // Take the front CS pkt
+
+
+ if(verbose)
+ std::cout << "[USRP_RX_STUB] Received CS response from TX stub\n";
+ }
+
+}
+
+REGISTER_MBLOCK_CLASS(usrp_rx_stub);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_RX_STUB_H
+#define INCLUDED_USRP_RX_STUB_H
+
+#include <mblock/mblock.h>
+#include <vector>
+#include "usrp_standard.h"
+#include <ui_nco.h>
+#include <fstream>
+#include <queue>
+#include <usrp_inband_usb_packet.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+extern bool usrp_rx_stop_stub; // used to communicate a 'stop' to the RX stub
+extern std::queue<pmt_t> d_cs_queue;
+
+static pmt_t s_timeout = pmt_intern("%timeout");
+static pmt_t s_done = pmt_intern("done");
+
+/*!
+ * \brief Implements the low level usb interface to the USRP
+ */
+class usrp_rx_stub : public mb_mblock
+{
+ public:
+
+ mb_port_sptr d_cs;
+ usrp_standard_rx* d_urx;
+
+ long d_samples_per_frame;
+ long d_decim_rx;
+
+ mb_time d_t0;
+ double d_delta_t;
+
+ // for generating sine wave output
+ ui_nco<float,float> d_nco;
+ double d_amplitude;
+
+ bool d_disk_write;
+
+ std::ofstream d_ofile;
+
+ public:
+ usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_rx_stub();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ private:
+ void read_and_respond();
+ void read_data();
+ void start_packet_timer();
+
+};
+
+
+#endif /* INCLUDED_USRP_RX_H */
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <usrp_server.h>
+#include <iostream>
+#include <usrp_inband_usb_packet.h>
+#include <mblock/class_registry.h>
+#include <vector>
+#include <usrp_usb_interface.h>
+#include <string.h>
+#include <fpga_regs_common.h>
+#include <fpga_regs_standard.h>
+
+#include <symbols_usrp_server_cs.h>
+#include <symbols_usrp_channel.h>
+#include <symbols_usrp_tx.h>
+#include <symbols_usrp_rx.h>
+#include <symbols_usrp_low_level_cs.h>
+#include <symbols_usrp_interface_cs.h>
+
+static pmt_t s_shutdown = pmt_intern("%shutdown");
+
+typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
+
+const static bool verbose = false;
+
+static std::string
+str(long x)
+{
+ std::ostringstream s;
+ s << x;
+ return s.str();
+}
+
+usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_fpga_debug(false),
+ d_interp_tx(128), // these should match the lower level defaults (rx also)
+ d_decim_rx(128),
+ d_fake_rx(false)
+{
+ if(verbose)
+ std::cout << "[USRP_SERVER] Initializing...\n";
+
+ // Dictionary for arguments to all of the components
+ d_usrp_dict = user_arg;
+
+ if (pmt_is_dict(d_usrp_dict)) {
+
+ if(pmt_t fpga_debug = pmt_dict_ref(d_usrp_dict,
+ pmt_intern("fpga-debug"),
+ PMT_NIL)) {
+ if(pmt_eqv(fpga_debug, PMT_T))
+ d_fpga_debug=true;
+ }
+
+ // Read the TX interpolations
+ if(pmt_t interp_tx = pmt_dict_ref(d_usrp_dict,
+ pmt_intern("interp-tx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(interp_tx, PMT_NIL))
+ d_interp_tx = pmt_to_long(interp_tx);
+ }
+
+ // Read the RX decimation rate
+ if(pmt_t decim_rx = pmt_dict_ref(d_usrp_dict,
+ pmt_intern("decim-rx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(decim_rx, PMT_NIL))
+ d_decim_rx = pmt_to_long(decim_rx);
+ }
+ }
+
+ // control & status port
+ d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL);
+ d_cs_usrp = define_port("cs_usrp", "usrp-interface-cs", false, mb_port::INTERNAL);
+
+ // ports
+ //
+ // (if/when we do replicated ports, these will be replaced by a
+ // single replicated port)
+ for(int port=0; port < N_PORTS; port++) {
+
+ d_tx.push_back(define_port("tx"+str(port),
+ "usrp-tx",
+ true,
+ mb_port::EXTERNAL));
+
+ d_rx.push_back(define_port("rx"+str(port),
+ "usrp-rx",
+ true,
+ mb_port::EXTERNAL));
+ }
+
+ define_component("usrp", "usrp_usb_interface", d_usrp_dict);
+ connect("self", "cs_usrp", "usrp", "cs");
+
+ d_defer=false;
+ d_opened=false;
+
+ // FIXME: needs to be returned from open, if we want to use this
+ d_nrx_chan = 2;
+ d_ntx_chan = 2;
+
+ // Initialize capacity on each channel to 0 and to no owner
+ // Also initialize the USRP standard tx/rx pointers to NULL
+ for(int chan=0; chan < d_ntx_chan; chan++)
+ d_chaninfo_tx.push_back(channel_info());
+
+ for(int chan=0; chan < d_nrx_chan; chan++)
+ d_chaninfo_rx.push_back(channel_info());
+
+ d_rx_chan_mask = 0;
+
+ for(int i=0; i < D_MAX_RID; i++)
+ d_rids.push_back(rid_info());
+
+ //d_fake_rx=true;
+}
+
+/*!
+ * \brief resets the assigned capacity and owners of each RX and TX channel from
+ * allocations.
+ */
+void
+usrp_server::reset_channels()
+{
+
+ for(int chan=0; chan < d_ntx_chan; chan++) {
+ d_chaninfo_tx[chan].assigned_capacity = 0;
+ d_chaninfo_tx[chan].owner = PMT_NIL;
+ }
+
+ for(int chan=0; chan < d_nrx_chan; chan++) {
+ d_chaninfo_rx[chan].assigned_capacity = 0;
+ d_chaninfo_rx[chan].owner = PMT_NIL;
+ }
+
+ d_rx_chan_mask = 0;
+}
+
+usrp_server::~usrp_server()
+{
+}
+
+
+void
+usrp_server::initial_transition()
+{
+ // the initial transition
+}
+
+/*!
+ * \brief Reads all incoming messages to USRP server from the TX, RX, and the CS
+ * ports. This drives the state of USRP server and dispatches based on the
+ * message.
+ */
+void
+usrp_server::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal(); // the "name" of the message
+ pmt_t port_id = msg->port_id(); // which port it came in on
+ pmt_t data = msg->data();
+ pmt_t invocation_handle;
+ pmt_t metadata = msg->metadata();
+ pmt_t status;
+
+ long port;
+
+ if (pmt_eq(event, s_shutdown)) // ignore (for now)
+ return;
+
+ invocation_handle = pmt_nth(0, data);
+
+ if (0){
+ std::cout << "[USRP_SERVER] event: " << event << std::endl;
+ std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl;
+ }
+
+ // It would be nice if this were all table driven, and we could compute our
+ // state transition as f(current_state, port_id, signal)
+
+ // A message from the USRP CS, which should *only* be responses
+ //
+ // It is important that this set come before checking messages of any other
+ // components. This is since we always want to listen to the low level USRP
+ // server, even if we aren't initialized we are waiting for responses to
+ // become initialized. Likewise, after the usrp_server is "closed", we still
+ // want to pass responses back from the low level.
+
+ //---------------- USRP RESPONSE ---------------//
+ if (pmt_eq(port_id, d_cs_usrp->port_symbol())) {
+
+ //-------------- USRP OPEN ------------------//
+ if(pmt_eq(event, s_response_usrp_open)) {
+ // pass the response back over the regular CS port
+ pmt_t status = pmt_nth(1, data);
+ d_cs->send(s_response_open, pmt_list2(invocation_handle, status));
+
+ //reset_all_registers();
+ //initialize_registers();
+
+ if(pmt_eqv(status,PMT_T)) {
+ d_opened = true;
+ d_defer = false;
+ recall_defer_queue();
+ }
+
+ return;
+ }
+ //------------- USRP CLOSE -------------------//
+ else if (pmt_eq(event, s_response_usrp_close)) {
+ pmt_t status = pmt_nth(1, data);
+ d_cs->send(s_response_close, pmt_list2(invocation_handle, status));
+
+ if(pmt_eqv(status,PMT_T)) {
+ d_opened = false;
+ d_defer = false;
+ reset_channels();
+ recall_defer_queue();
+ }
+
+ return;
+ }
+ //--------------- USRP WRITE --------------//
+ else if (pmt_eq(event, s_response_usrp_write)) {
+
+ pmt_t status = pmt_nth(1, data);
+ long channel = pmt_to_long(pmt_nth(2, data));
+ long port;
+
+ // Do not report back responses if they were generated from a
+ // command packet
+ if(channel == CONTROL_CHAN)
+ return;
+
+ // Find the port through the owner of the channel
+ if((port = tx_port_index(d_chaninfo_tx[channel].owner)) !=-1 )
+ d_tx[port]->send(s_response_xmit_raw_frame,
+ pmt_list2(invocation_handle, status));
+ return;
+ }
+ //--------------- USRP READ ---------------//
+ else if (pmt_eq(event, s_response_usrp_read)) {
+
+ pmt_t status = pmt_nth(1, data);
+
+ if(!pmt_eqv(status, PMT_T)) {
+ std::cerr << "[USRP_SERVER] Error receiving packet\n";
+ return;
+ }
+ else {
+ handle_response_usrp_read(data);
+ return;
+ }
+ }
+
+ goto unhandled;
+ }
+
+ // Checking for defer on all other messages
+ if(d_defer) {
+ if (verbose)
+ std::cout << "[USRP_SERVER] Received msg while deferring ("
+ << msg->signal() << ")\n";
+ d_defer_queue.push(msg);
+ return;
+ }
+
+ //--------- CONTROL / STATUS ------------//
+ if (pmt_eq(port_id, d_cs->port_symbol())){
+
+ //----------- OPEN -----------//
+ if (pmt_eq(event, s_cmd_open)){
+
+ // Reject if already open
+ if(d_opened) {
+ d_cs->send(s_response_open, pmt_list2(invocation_handle, s_err_usrp_already_opened));
+ return;
+ }
+
+ // the parameters are the same to the low level interface, so we just pass 'data' along
+ d_cs_usrp->send(s_cmd_usrp_open, data);
+
+ d_defer = true;
+
+ return;
+ }
+ //---------- CLOSE -----------//
+ else if (pmt_eq(event, s_cmd_close)){
+
+ if(!d_opened) {
+ d_cs->send(s_response_close, pmt_list2(invocation_handle, s_err_usrp_already_closed));
+ return;
+ }
+
+ d_defer = true;
+ d_cs_usrp->send(s_cmd_usrp_close, pmt_list1(invocation_handle));
+
+ return;
+ }
+ //---------- MAX CAPACITY ----------//
+ else if (pmt_eq(event, s_cmd_max_capacity)) {
+
+ if(!d_opened) {
+ d_cs->send(s_response_max_capacity,
+ pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
+ return;
+ }
+
+ d_cs->send(s_response_max_capacity,
+ pmt_list3(invocation_handle,
+ PMT_T,
+ pmt_from_long(max_capacity())));
+ return;
+ }
+ //---------- NTX CHAN --------------//
+ else if (pmt_eq(event, s_cmd_ntx_chan)) {
+
+ if(!d_opened) {
+ d_cs->send(s_response_ntx_chan,
+ pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
+ return;
+ }
+
+ d_cs->send(s_response_ntx_chan,
+ pmt_list3(invocation_handle,
+ PMT_T,
+ pmt_from_long(d_ntx_chan)));
+ return;
+ }
+ //---------- NRX CHAN -----------//
+ else if (pmt_eq(event, s_cmd_nrx_chan)) {
+
+ if(!d_opened) {
+ d_cs->send(s_response_nrx_chan,
+ pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
+ return;
+ }
+
+ d_cs->send(s_response_nrx_chan,
+ pmt_list3(invocation_handle,
+ PMT_T,
+ pmt_from_long(d_nrx_chan)));
+ return;
+ }
+ //--------- ALLOCATION? -----------//
+ else if (pmt_eq(event, s_cmd_current_capacity_allocation)) {
+
+ if(!d_opened) {
+ d_cs->send(s_response_current_capacity_allocation,
+ pmt_list3(invocation_handle,
+ s_err_usrp_not_opened,
+ pmt_from_long(0)));
+ return;
+ }
+
+ d_cs->send(s_response_current_capacity_allocation,
+ pmt_list3(invocation_handle,
+ PMT_T,
+ pmt_from_long(current_capacity_allocation())));
+ return;
+ }
+ goto unhandled;
+ }
+
+ //-------------- TX ---------------//
+ if ((port = tx_port_index(port_id)) != -1) {
+
+ //------------ ALLOCATE (TX) ----------------//
+ if (pmt_eq(event, s_cmd_allocate_channel)){
+
+ if(!d_opened) {
+ d_tx[port]->send(s_response_allocate_channel,
+ pmt_list3(invocation_handle,
+ s_err_usrp_not_opened,
+ pmt_from_long(0)));
+ return;
+ }
+
+ handle_cmd_allocate_channel(d_tx[port], d_chaninfo_tx, data);
+ return;
+ }
+
+ //----------- DEALLOCATE (TX) ---------------//
+ if (pmt_eq(event, s_cmd_deallocate_channel)) {
+
+ if(!d_opened) {
+ d_tx[port]->send(s_response_deallocate_channel,
+ pmt_list3(invocation_handle,
+ s_err_usrp_not_opened,
+ pmt_from_long(0)));
+ return;
+ }
+
+ handle_cmd_deallocate_channel(d_tx[port], d_chaninfo_tx, data);
+ return;
+ }
+
+ //-------------- XMIT RAW FRAME -----------------/
+ if (pmt_eq(event, s_cmd_xmit_raw_frame)){
+
+ if(!d_opened) {
+ d_tx[port]->send(s_response_xmit_raw_frame,
+ pmt_list2(invocation_handle, s_err_usrp_not_opened));
+ return;
+ }
+
+ handle_cmd_xmit_raw_frame(d_tx[port], d_chaninfo_tx, data);
+ return;
+ }
+
+ //-------------- CONTROL PACKET -----------------/
+ if (pmt_eq(event, s_cmd_to_control_channel)) {
+
+ if(!d_opened) {
+ d_tx[port]->send(s_response_xmit_raw_frame,
+ pmt_list2(invocation_handle, s_err_usrp_not_opened));
+ return;
+ }
+
+ handle_cmd_to_control_channel(d_tx[port], d_chaninfo_tx, data);
+ return;
+
+ }
+
+ goto unhandled;
+ }
+
+ //-------------- RX ---------------//
+ if ((port = rx_port_index(port_id)) != -1) {
+
+ //------------ ALLOCATE (RX) ----------------//
+ if (pmt_eq(event, s_cmd_allocate_channel)) {
+
+ if(!d_opened) {
+ d_rx[port]->send(s_response_allocate_channel,
+ pmt_list3(invocation_handle,
+ s_err_usrp_not_opened,
+ pmt_from_long(0)));
+ return;
+ }
+
+ handle_cmd_allocate_channel(d_rx[port], d_chaninfo_rx, data);
+ return;
+ }
+
+ //----------- DEALLOCATE (RX) ---------------//
+ if (pmt_eq(event, s_cmd_deallocate_channel)) {
+
+ if(!d_opened) {
+ d_rx[port]->send(s_response_deallocate_channel,
+ pmt_list3(invocation_handle,
+ s_err_usrp_not_opened,
+ pmt_from_long(0)));
+ return;
+ }
+
+ handle_cmd_deallocate_channel(d_rx[port], d_chaninfo_rx, data);
+ return;
+ }
+
+ //-------------- START RECV ----------------//
+ if (pmt_eq(event, s_cmd_start_recv_raw_samples)) {
+
+ if(!d_opened) {
+ d_rx[port]->send(s_response_recv_raw_samples,
+ pmt_list2(invocation_handle, s_err_usrp_not_opened));
+ return;
+ }
+
+ handle_cmd_start_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
+ return;
+ }
+
+ //-------------- STOP RECV ----------------//
+ if (pmt_eq(event, s_cmd_stop_recv_raw_samples)) {
+
+ if(!d_opened)
+ return;
+
+ // FIX ME : no response for stopping? even if error? (permissions)
+ handle_cmd_stop_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
+
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ unhandled:
+ std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl;
+}
+
+/*!
+ * \brief Takes a port_symbol() as parameter \p port_id and is used to determine
+ * if the port is a TX port, or to find an index in the d_tx vector which stores
+ * the port.
+ *
+ * \returns -1 if \p port_id is not in the d_tx vector (i.e., it's not a TX
+ * port), otherwise returns an index in the d_tx vector which stores the port.
+ */
+int usrp_server::tx_port_index(pmt_t port_id) {
+
+ for(int i=0; i < (int) d_tx.size(); i++)
+ if(pmt_eq(d_tx[i]->port_symbol(), port_id))
+ return i;
+
+ return -1;
+}
+
+/*!
+ * \brief Takes a port_symbol() as parameter \p port_id and is used to determine
+ * if the port is an RX port, or to find an index in the d_rx vector which
+ * stores the port.
+ *
+ * \returns -1 if \p port_id is not in the d_rx vector (i.e., it's not an RX
+ * port), otherwise returns an index in the d_rx vector which stores the port.
+ */
+int usrp_server::rx_port_index(pmt_t port_id) {
+
+ for(int i=0; i < (int) d_rx.size(); i++)
+ if(pmt_eq(d_rx[i]->port_symbol(), port_id))
+ return i;
+
+ return -1;
+}
+
+/*!
+ * \brief Determines the current total capacity allocated by all RX and TX
+ * channels.
+ *
+ * \returns the total allocated capacity
+ */
+long usrp_server::current_capacity_allocation() {
+ long capacity = 0;
+
+ for(int chan=0; chan < d_ntx_chan; chan++)
+ capacity += d_chaninfo_tx[chan].assigned_capacity;
+
+ for(int chan=0; chan < d_nrx_chan; chan++)
+ capacity += d_chaninfo_rx[chan].assigned_capacity;
+
+ return capacity;
+}
+
+
+/*!
+ * \brief Called by the handle_message() method if the incoming message to
+ * usrp_server is to allocate a channel (cmd-allocate-channel). The method
+ * checks if the requested capacity exists and if so it will reserve it for the
+ * caller on the channel that is returned via a response-allocate-channel
+ * signal.
+ */
+void
+usrp_server::handle_cmd_allocate_channel(
+ mb_port_sptr port,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long rqstd_capacity = pmt_to_long(pmt_nth(1, data));
+ long chan;
+
+ // Check capacity exists
+ if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
+
+ // no capacity available
+ port->send(s_response_allocate_channel,
+ pmt_list3(invocation_handle,
+ s_err_requested_capacity_unavailable,
+ PMT_NIL));
+ return;
+ }
+
+ // Find a free channel, assign the capacity and respond
+ for(chan=0; chan < (long)chan_info.size(); chan++) {
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Checking chan: " << chan
+ << " owner " << chan_info[chan].owner
+ << " size " << chan_info.size()
+ << std::endl;
+
+ if(chan_info[chan].owner == PMT_NIL) {
+
+ chan_info[chan].owner = port->port_symbol();
+ chan_info[chan].assigned_capacity = rqstd_capacity;
+
+ port->send(s_response_allocate_channel,
+ pmt_list3(invocation_handle,
+ PMT_T,
+ pmt_from_long(chan)));
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Assigning channel: " << chan
+ << " to " << chan_info[chan].owner
+ << std::endl;
+ return;
+ }
+
+ }
+
+ if (verbose)
+ std::cout << "[USRP_SERVER] Couldnt find a TX chan\n";
+
+ // no free TX chan found
+ port->send(s_response_allocate_channel,
+ pmt_list3(invocation_handle,
+ s_err_channel_unavailable,
+ PMT_NIL));
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method if the incoming message to
+ * usrp_server is to deallocate a channel (cmd-deallocate-channel). The method
+ * ensures that the sender of the signal owns the channel and that the channel
+ * number is valid. A response-deallocate-channel signal is sent back with the
+ * result of the deallocation.
+ */
+void
+usrp_server::handle_cmd_deallocate_channel(
+ mb_port_sptr port,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t data)
+{
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+
+ // Ensure the channel is valid and the caller owns the port
+ if(!check_valid(port, channel, chan_info,
+ pmt_list2(s_response_deallocate_channel, invocation_handle)))
+ return;
+
+ chan_info[channel].assigned_capacity = 0;
+ chan_info[channel].owner = PMT_NIL;
+
+ port->send(s_response_deallocate_channel,
+ pmt_list2(invocation_handle,
+ PMT_T));
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method if the incoming message to
+ * usrp_server is to transmit a frame (cmd-xmit-raw-frame). The method
+ * allocates enough memory to support a burst of packets which contain the frame
+ * over the bus of the frame, sets the packet headers, and sends a signal to the
+ * lower block for the data (packets) to be written to the bus.
+ *
+ * The \p port the command was sent on and the channel info (\p chan_info) of
+ * the channel the frame is to be transmitted on are passed to ensure that the
+ * caller owns the channel.
+ *
+ * The \p data parameter is in the format of a cmd-xmit-raw-frame signal.
+ *
+ * The properties
+ */
+void usrp_server::handle_cmd_xmit_raw_frame(
+ mb_port_sptr port,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t data)
+{
+ size_t n_bytes, psize;
+ long max_payload_len = transport_pkt::max_payload();
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+ const void *samples = pmt_uniform_vector_elements(pmt_nth(2, data), n_bytes);
+ long timestamp = pmt_to_long(pmt_nth(3, data));
+ pmt_t properties = pmt_nth(4, data);
+
+ // Ensure the channel is valid and the caller owns the port
+ if(!check_valid(port, channel, chan_info,
+ pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
+ return;
+
+ // Read information from the properties of the packet
+ bool carrier_sense = false;
+ if(pmt_is_dict(properties)) {
+
+ // Check if carrier sense is enabled for the frame
+ if(pmt_t p_carrier_sense = pmt_dict_ref(properties,
+ pmt_intern("carrier-sense"),
+ PMT_NIL)) {
+ if(pmt_eqv(p_carrier_sense, PMT_T))
+ carrier_sense = true;
+ }
+ }
+
+
+ // Determine the number of packets to allocate contiguous memory for
+ // bursting over the USB and get a pointer to the memory to be used in
+ // building the packets
+ long n_packets =
+ static_cast<long>(std::ceil(n_bytes / (double)max_payload_len));
+
+ pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
+
+ transport_pkt *pkts =
+ (transport_pkt *) pmt_u8vector_writable_elements(v_packets, psize);
+
+ for(int n=0; n < n_packets; n++) {
+
+ long payload_len =
+ std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len);
+
+ if(n == 0) { // first packet gets start of burst flag and timestamp
+
+ if(carrier_sense)
+ pkts[n].set_header(pkts[n].FL_START_OF_BURST
+ | pkts[n].FL_CARRIER_SENSE,
+ channel, 0, payload_len);
+ else
+ pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len);
+
+ pkts[n].set_timestamp(timestamp);
+
+ } else {
+ pkts[n].set_header(0, channel, 0, payload_len);
+ pkts[n].set_timestamp(0xffffffff);
+ }
+
+ memcpy(pkts[n].payload(),
+ (uint8_t *)samples+(max_payload_len * n),
+ payload_len);
+
+ }
+
+
+ pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst
+
+ if (verbose && 0)
+ std::cout << "[USRP_SERVER] Received raw frame invocation: "
+ << invocation_handle << std::endl;
+
+ // The actual response to the write will be generated by a
+ // s_response_usrp_write since we cannot determine whether to transmit was
+ // successful until we hear from the lower layers.
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packets));
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method to parse incoming control/status
+ * signals (cmd-to-control-channel).
+ *
+ * The \p port the command was sent on and the channel info (\p chan_info) of
+ * the channel are passed to ensure that the caller owns the channel.
+ *
+ * The \p data parameter is in the format of a PMT list, where each element
+ * follows the format of a control/status signal (i.e. op-ping-fixed).
+ *
+ * The method will parse all of the C/S commands included in \p data and place
+ * the commands in to a lower level packet sent to the control channel. The
+ * method will pack as many commands as possible in t oa single packet, and once
+ * it is fill generate as many lower level packets as needed.
+ *
+ * Anything that needs to be returned to the sender of the signal (i.e. the
+ * value of a register) will be generated by the parse_control_pkt() method as
+ * the responses to the commands are read back from the USRP.
+ */
+void usrp_server::handle_cmd_to_control_channel(
+ mb_port_sptr port,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t data)
+{
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t subpackets = pmt_nth(1, data);
+
+ long n_subpkts = pmt_length(subpackets);
+ long curr_subpkt = 0;
+
+ size_t psize;
+ long payload_len = 0;
+ long channel = CONTROL_CHAN;
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Handling " << n_subpkts << " commands\n";
+
+ // The design of the following code is optimized for simplicity, not
+ // performance. To performance optimize this code, the total size in bytes
+ // needed for all of the CS packets is needed to allocate contiguous memory
+ // which contains the USB packets for bursting over the bus. However to do
+ // this the packets subpackets would need to be parsed twice and their sizes
+ // would need to be determined.
+ //
+ // The approach taken is to keep parsing the subpackets and putting them in to
+ // USB packets. Once the USB packet is full, a write is sent for it and
+ // another packet is created.
+ //
+ // The subpacket creation methods will return false if the subpacket will not
+ // fit in to the current USB packet. In these cases a new USB packet is
+ // created and the old is sent.
+
+ new_packet:
+ // This code needs to become "smart" and only make a new packet when full
+ pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
+ transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_packet, psize);
+ payload_len = 0;
+
+ pkt->set_header(0, channel, 0, payload_len);
+ pkt->set_timestamp(0xffffffff);
+
+ while(curr_subpkt < n_subpkts) {
+
+ pmt_t subp = pmt_nth(curr_subpkt, subpackets);
+ pmt_t subp_cmd = pmt_nth(0, subp);
+ pmt_t subp_data = pmt_nth(1, subp);
+
+ //--------- PING FIXED --------------//
+ if(pmt_eq(subp_cmd, s_op_ping_fixed)) {
+
+ long urid = pmt_to_long(pmt_nth(0, subp_data));
+ long pingval = pmt_to_long(pmt_nth(1, subp_data));
+
+ // USRP server sets request ID's to keep track of which application gets
+ // what response back. To allow a full 6-bits for an RID to the user, we
+ // keep a mapping and replace the RID's as the packets go in and out. If
+ // there are no RID's available, the command is thrown away silently.
+ long srid;
+ if((srid = next_rid()) == -1)
+ goto subpkt_bail;
+
+ // We use a vector to store the owner of the ping request and will use it
+ // to send the request on any RX port they own.
+ d_rids[srid].owner = port->port_symbol();
+ d_rids[srid].user_rid = urid;
+
+ // Adds a ping after the previous command in the pkt
+ if(!pkt->cs_ping(srid, pingval))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ // Return the RID
+ d_rids[srid].owner = PMT_NIL;
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received ping command request"
+ << " assigning RID " << srid << std::endl;
+
+ }
+
+ //----------- WRITE REG ---------------//
+ if(pmt_eq(subp_cmd, s_op_write_reg)) {
+
+ long reg_num = pmt_to_long(pmt_nth(0, subp_data));
+ long val = pmt_to_long(pmt_nth(1, subp_data));
+
+ if(!pkt->cs_write_reg(reg_num, val))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received write register request "
+ << "("
+ << "Reg: " << reg_num << ", "
+ << "Val: " << val
+ << ")\n";
+ }
+
+ //------- WRITE REG MASKED ----------//
+ if(pmt_eq(subp_cmd, s_op_write_reg_masked)) {
+
+ long reg_num = pmt_to_long(pmt_nth(0, subp_data));
+ long val = pmt_to_long(pmt_nth(1, subp_data));
+ long mask = pmt_to_long(pmt_nth(2, subp_data));
+
+ if(!pkt->cs_write_reg_masked(reg_num, val, mask))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received write register masked request\n";
+ }
+
+ //------------ READ REG --------------//
+ if(pmt_eq(subp_cmd, s_op_read_reg)) {
+
+ long urid = pmt_to_long(pmt_nth(0, subp_data));
+ long reg_num = pmt_to_long(pmt_nth(1, subp_data));
+
+ long srid;
+ if((srid = next_rid()) == -1)
+ goto subpkt_bail;
+
+ d_rids[srid].owner = port->port_symbol();
+ d_rids[srid].user_rid = urid;
+
+ if(!pkt->cs_read_reg(srid, reg_num))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ // Return the rid
+ d_rids[srid].owner = PMT_NIL;
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received read register request"
+ << " assigning RID " << srid << std::endl;
+ }
+
+ //------------ DELAY --------------//
+ if(pmt_eq(subp_cmd, s_op_delay)) {
+
+ long ticks = pmt_to_long(pmt_nth(0, subp_data));
+
+ if(!pkt->cs_delay(ticks))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received delay request of "
+ << ticks << " ticks\n";
+ }
+
+ //--------- I2C WRITE -----------//
+ // FIXME: could check that byte count does not exceed 2^8 which
+ // is the max length in the subpacket for # of bytes to read.
+ if(pmt_eq(subp_cmd, s_op_i2c_write)) {
+
+ long i2c_addr = pmt_to_long(pmt_nth(0, subp_data));
+ pmt_t data = pmt_nth(1, subp_data);
+
+ // Get a readable address to the data which also gives us the length
+ size_t data_len;
+ uint8_t *i2c_data = (uint8_t *) pmt_u8vector_writable_elements(data, data_len);
+
+ // Make the USB packet
+ if(!pkt->cs_i2c_write(i2c_addr, i2c_data, data_len))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received I2C write\n";
+ }
+
+ //----------- I2C Read -------------//
+ if(pmt_eq(subp_cmd, s_op_i2c_read)) {
+
+ long urid = pmt_to_long(pmt_nth(0, subp_data));
+ long i2c_addr = pmt_to_long(pmt_nth(1, subp_data));
+ long i2c_bytes = pmt_to_long(pmt_nth(2, subp_data));
+
+ long srid;
+ if((srid = next_rid()) == -1)
+ goto subpkt_bail;
+
+ d_rids[srid].owner = port->port_symbol();
+ d_rids[srid].user_rid = urid;
+
+ if(!pkt->cs_i2c_read(srid, i2c_addr, i2c_bytes))
+ {
+
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ d_rids[srid].owner = PMT_NIL;
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received I2C read\n";
+ }
+
+ //--------- SPI WRITE -----------//
+ if(pmt_eq(subp_cmd, s_op_spi_write)) {
+
+ long enables = pmt_to_long(pmt_nth(0, subp_data));
+ long format = pmt_to_long(pmt_nth(1, subp_data));
+ long opt = pmt_to_long(pmt_nth(2, subp_data));
+ pmt_t data = pmt_nth(3, subp_data);
+
+ // Get a readable address to the data which also gives us the length
+ size_t data_len;
+ uint8_t *spi_data = (uint8_t *) pmt_u8vector_writable_elements(data, data_len);
+
+ // Make the USB packet
+ if(!pkt->cs_spi_write(enables, format, opt, spi_data, data_len))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received SPI write\n";
+ }
+
+ //--------- SPI READ -----------//
+ if(pmt_eq(subp_cmd, s_op_spi_read)) {
+
+ long urid = pmt_to_long(pmt_nth(0, subp_data));
+ long enables = pmt_to_long(pmt_nth(1, subp_data));
+ long format = pmt_to_long(pmt_nth(2, subp_data));
+ long opt = pmt_to_long(pmt_nth(3, subp_data));
+ long n_bytes = pmt_to_long(pmt_nth(4, subp_data));
+
+ long srid;
+ if((srid = next_rid()) == -1)
+ goto subpkt_bail;
+
+ d_rids[srid].owner = port->port_symbol();
+ d_rids[srid].user_rid = urid;
+
+ // Make the USB packet
+ if(!pkt->cs_spi_read(srid, enables, format, opt, n_bytes))
+ {
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ // Return the rid
+ d_rids[srid].owner = PMT_NIL;
+
+ goto new_packet;
+ }
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Received SPI read\n";
+ }
+
+ subpkt_bail:
+ curr_subpkt++;
+
+ }
+
+
+ // If the current packets length is > 0, we know there are subpackets that
+ // need to be sent out still.
+ if(pkt->payload_len() > 0)
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(invocation_handle,
+ pmt_from_long(channel),
+ v_packet));
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is a
+ * command to start reading samples from the USRP (cmd-start-recv-raw-samples).
+ *
+ * The \p port the command was sent on and the channel info (\p chan_info) of
+ * the channel are passed to ensure that the caller owns the channel.
+ *
+ * The \p data parameter should be in the format of a cmd-start-recv-raw-samples
+ * command where the first element in the list is an invocation handle, and the
+ * second is the channel the signal generator wants to receive the samples on.
+ */
+void
+usrp_server::handle_cmd_start_recv_raw_samples(
+ mb_port_sptr port,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+
+ // Ensure the channel is valid and the caller owns the port
+ if(!check_valid(port, channel, chan_info,
+ pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
+ return;
+
+ // Already started receiving samples? (another start before a stop)
+ // Check the RX channel bitmask.
+ if(d_rx_chan_mask & (1 << channel)) {
+ port->send(s_response_recv_raw_samples,
+ pmt_list5(invocation_handle,
+ s_err_already_receiving,
+ PMT_NIL,
+ PMT_NIL,
+ PMT_NIL));
+ return;
+ }
+
+ // We only need to generate a 'start reading' command down to the
+ // low level interface if no other channel is already reading
+ //
+ // We carry this over the CS interface because the lower level
+ // interface does not care about the channel, we only demux it
+ // at the usrp_server on responses.
+ if(d_rx_chan_mask == 0) {
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Sending read request down to start recv\n";
+
+ d_cs_usrp->send(s_cmd_usrp_start_reading, pmt_list1(invocation_handle));
+ }
+
+ d_rx_chan_mask |= 1<<channel;
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * stop receiving samples from the USRP (cmd-stop-recv-raw-samples).
+ *
+ * The \p port the command was sent on and the channel info (\p chan_info) of
+ * the channel are passed to ensure that the caller owns the channel.
+ *
+ * The \p data parameter should be in the format of a cmd-stop-recv-raw-samples
+ * command where the first element in the list is an invocation handle, and the
+ * second is the channel the signal generator wants to stop receiving the
+ * samples from.
+ */
+void
+usrp_server::handle_cmd_stop_recv_raw_samples(
+ mb_port_sptr port,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+
+ // FIX ME : we have no responses to send an error...
+ // Ensure the channel is valid and the caller owns the port
+ //if(!check_valid(port, channel, chan_info,
+ // pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
+ // return;
+
+ // Remove this hosts bit from the receiver mask
+ d_rx_chan_mask &= ~(1<<channel);
+
+ // We only need to generate a 'start reading' command down to the
+ // low level interface if no other channel is already reading
+ //
+ // We carry this over the CS interface because the lower level
+ // interface does not care about the channel, we only demux it
+ // at the usrp_server on responses.
+ if(d_rx_chan_mask == 0) {
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Sending stop reading request down\n";
+
+ d_cs_usrp->send(s_cmd_usrp_stop_reading, pmt_list1(invocation_handle));
+ }
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when an incoming signal is
+ * generated to USRP server that contains raw samples from the USRP. This
+ * method generates the response-recv-raw-samples signals that are the result of
+ * a cmd-start-recv-raw-samples signal.
+ *
+ * The raw lower-level packet is extracted from \p data, where the format for \p
+ * data is a PMT list. The PMT \p data list should contain an invocation handle
+ * as the first element, the status of the lower-level read as the second
+ * element, and a uniform vector representation of the packets as the third
+ * element.
+ *
+ * The packet contains a channel field that the samples are destined to, and the
+ * method determines where to send the samples based on this channel since each
+ * channel has an associated port which allocated it.
+ */
+void
+usrp_server::handle_response_usrp_read(pmt_t data)
+{
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t v_pkt = pmt_nth(2, data);
+
+ size_t n_bytes;
+ size_t ignore;
+
+ if (d_fake_rx) {
+
+ pmt_t pkt = pmt_nth(2, data);
+
+ d_rx[0]->send(s_response_recv_raw_samples,
+ pmt_list5(PMT_F,
+ PMT_T,
+ pkt,
+ pmt_from_long(0xffff),
+ PMT_NIL));
+
+ return;
+ }
+
+ // Extract the packet and return appropriately
+ transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, n_bytes);
+
+ // The channel is used to find the port to pass the samples on
+ long channel = pkt->chan();
+ long payload_len = pkt->payload_len();
+ long port;
+
+ // Ignore packets which seem to have incorrect size or size 0
+ if(payload_len > pkt->max_payload() || payload_len == 0)
+ return;
+
+ // If the packet is a C/S packet, parse it separately
+ if(channel == CONTROL_CHAN) {
+ parse_control_pkt(invocation_handle, pkt);
+ return;
+ }
+
+ if((port = rx_port_index(d_chaninfo_rx[channel].owner)) == -1)
+ return; // Don't know where to send the sample... possibility on abrupt close
+
+ pmt_t v_samples = pmt_make_u8vector(payload_len, 0);
+ uint8_t *samples = pmt_u8vector_writable_elements(v_samples, ignore);
+
+ memcpy(samples, pkt->payload(), payload_len);
+
+ // Build a properties dictionary to store things such as the RSSI
+ pmt_t properties = pmt_make_dict();
+
+ pmt_dict_set(properties,
+ pmt_intern("rssi"),
+ pmt_from_long(pkt->rssi()));
+
+ if(pkt->overrun())
+ pmt_dict_set(properties,
+ pmt_intern("overrun"),
+ PMT_T);
+
+ if(pkt->underrun())
+ pmt_dict_set(properties,
+ pmt_intern("underrun"),
+ PMT_T);
+
+ d_rx[port]->send(s_response_recv_raw_samples,
+ pmt_list6(invocation_handle,
+ status,
+ v_samples,
+ pmt_from_long(pkt->timestamp()),
+ pmt_from_long(channel),
+ properties));
+ return;
+}
+
+/*!
+ * \brief Called by handle_response_usrp_read() when the incoming packet has a
+ * channel of CONTROL_CHAN. This means that the incoming packet contains a
+ * response for a command sent to the control channel, which this method will
+ * parse.
+ *
+ * The \p pkt parameter is a pointer to the full packet (transport_pkt) in
+ * memory.
+ *
+ * Given that all commands sent to the control channel that require responses
+ * will carry an RID (request ID), the method will use the RID passed back with
+ * the response to determine which port the response should be sent on.
+ */
+void
+usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt)
+{
+
+ long payload_len = pkt->payload_len();
+ long curr_payload = 0;
+ long port;
+
+ // We dispatch based on the control packet type, however we can extract the
+ // opcode and the length immediately which is consistent in all responses.
+ //
+ // Since each control packet can have multiple responses, we keep reading the
+ // lengths of each subpacket until we reach the payload length.
+ while(curr_payload < payload_len) {
+
+ pmt_t sub_packet = pkt->read_subpacket(curr_payload);
+ pmt_t op_symbol = pmt_nth(0, sub_packet);
+
+ int len = pkt->cs_len(curr_payload);
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Parsing subpacket "
+ << op_symbol << " ... length " << len << std::endl;
+
+ //----------------- PING RESPONSE ------------------//
+ if(pmt_eq(op_symbol, s_op_ping_fixed_reply)) {
+
+ long srid = pmt_to_long(pmt_nth(1, sub_packet));
+ pmt_t pingval = pmt_nth(2, sub_packet);
+
+ long urid = d_rids[srid].user_rid;
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Found ping response "
+ << "("
+ << "URID: " << urid << ", "
+ << "SRID: " << srid << ", "
+ << "VAL: " << pingval
+ << ")\n";
+
+ // Do some bounds checking incase of bogus/corrupt responses
+ if(srid > D_MAX_RID)
+ return;
+
+ pmt_t owner = d_rids[srid].owner;
+
+ // Return the RID
+ d_rids[srid].owner = PMT_NIL;
+
+ // FIXME: should be 1 response for all subpackets here ?
+ if((port = tx_port_index(owner)) != -1)
+ d_tx[port]->send(s_response_from_control_channel,
+ pmt_list4(invocation_handle,
+ PMT_T,
+ pmt_list2(s_op_ping_fixed_reply, // subp
+ pmt_list2(pmt_from_long(urid),
+ pingval)),
+ pmt_from_long(pkt->timestamp())));
+ }
+
+ //----------------- READ REG RESPONSE ------------------//
+ else if(pmt_eq(op_symbol, s_op_read_reg_reply)) {
+
+ long srid = pmt_to_long(pmt_nth(1, sub_packet));
+ pmt_t reg_num = pmt_nth(2, sub_packet);
+ pmt_t reg_val = pmt_nth(3, sub_packet);
+
+ long urid = d_rids[srid].user_rid;
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Found read register response "
+ << "("
+ << "URID: " << urid << ", "
+ << "SRID: " << srid << ", "
+ << "REG: " << reg_num << ", "
+ << "VAL: " << reg_val
+ << ")\n";
+
+ // Do some bounds checking to avoid seg faults
+ if(srid > D_MAX_RID)
+ return;
+
+ pmt_t owner = d_rids[srid].owner;
+
+ // Return the RID
+ d_rids[srid].owner = PMT_NIL;
+
+ // FIXME: should be 1 response for all subpackets here ?
+ if((port = tx_port_index(owner)) != -1)
+ d_tx[port]->send(s_response_from_control_channel,
+ pmt_list4(invocation_handle,
+ PMT_T,
+ pmt_list2(s_op_read_reg_reply, // subp
+ pmt_list3(pmt_from_long(urid),
+ reg_num,
+ reg_val)),
+ pmt_from_long(pkt->timestamp())));
+ }
+
+ //------------------ I2C READ REPLY -------------------//
+ else if(pmt_eq(op_symbol, s_op_i2c_read_reply)) {
+
+ long srid = pmt_to_long(pmt_nth(1, sub_packet));
+ pmt_t i2c_addr = pmt_nth(2, sub_packet);
+ pmt_t i2c_data = pmt_nth(3, sub_packet);
+
+ long urid = d_rids[srid].user_rid;
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Found i2c read reply "
+ << "("
+ << "URID: " << urid << ", "
+ << "SRID: " << srid << ", "
+ << "Addr: " << i2c_addr << ", "
+ << "Data: " << i2c_data
+ << ")\n";
+
+ // Do some bounds checking to avoid seg faults
+ if(srid > D_MAX_RID)
+ return;
+
+ pmt_t owner = d_rids[srid].owner;
+
+ // Return the RID
+ d_rids[srid].owner = PMT_NIL;
+
+ if((port = tx_port_index(owner)) != -1)
+ d_tx[port]->send(s_response_from_control_channel,
+ pmt_list4(invocation_handle,
+ PMT_T,
+ pmt_list2(s_op_i2c_read_reply,
+ pmt_list3(pmt_from_long(urid),
+ i2c_addr,
+ i2c_data)),
+ pmt_from_long(pkt->timestamp())));
+ }
+
+ //------------------ SPI READ REPLY -------------------//
+ else if(pmt_eq(op_symbol, s_op_spi_read_reply)) {
+
+ long srid = pmt_to_long(pmt_nth(1, sub_packet));
+ pmt_t spi_data = pmt_nth(2, sub_packet);
+
+ long urid = d_rids[srid].user_rid;
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Found SPI read reply "
+ << "("
+ << "URID: " << urid << ", "
+ << "SRID: " << srid << ", "
+ << "Data: " << spi_data
+ << ")\n";
+
+ // Bounds check the RID
+ if(srid > D_MAX_RID)
+ return;
+
+ pmt_t owner = d_rids[srid].owner;
+
+ // Return the RID
+ d_rids[srid].owner = PMT_NIL;
+
+ if((port = tx_port_index(owner)) != -1)
+ d_tx[port]->send(s_response_from_control_channel,
+ pmt_list4(invocation_handle,
+ PMT_T,
+ pmt_list2(s_op_spi_read_reply,
+ pmt_list2(pmt_from_long(urid),
+ spi_data)),
+ pmt_from_long(pkt->timestamp())));
+ }
+
+ // Each subpacket has an unaccounted for 2 bytes which is the opcode
+ // and the length field
+ curr_payload += len + 2;
+
+ // All subpackets are 32-bit aligned
+ int align_offset = 4 - (curr_payload % 4);
+
+ if(align_offset != 4)
+ curr_payload += align_offset;
+ }
+}
+
+/*!
+ * \brief Used to recall all incoming signals that were deferred when USRP
+ * server was in the initialization state.
+ */
+void
+usrp_server::recall_defer_queue()
+{
+
+ std::vector<mb_message_sptr> recall;
+
+ while(!d_defer_queue.empty()) {
+ recall.push_back(d_defer_queue.front());
+ d_defer_queue.pop();
+ }
+
+ // Parse the messages that were queued while waiting for an open response
+ for(int i=0; i < (int)recall.size(); i++)
+ handle_message(recall[i]);
+
+ return;
+}
+
+/*!
+ * \brief Commonly called by any method which handles outgoing frames or control
+ * packets to the USRP to check if the port on which the signal was sent owns
+ * the channel the outgoing packet will be associated with. This helps ensure
+ * that applications do not send data on other application's ports.
+ *
+ * The \p port parameter is the port symbol that the caller wishes to determine
+ * owns the channel specified by \p chan_info.
+ *
+ * The \p signal_info parameter is a PMT list containing two elements: the
+ * response signal to use if the permissions are invalid, and the invocation
+ * handle that was passed. This allows the method to generate detailed failure
+ * responses to signals without having to return some sort of structured
+ * information which the caller must then parse and interpret to determine the
+ * failure type.
+ *
+ * \returns true if \p port owns the channel specified by \p chan_info, false
+ * otherwise.
+ */
+bool
+usrp_server::check_valid(mb_port_sptr port,
+ long channel,
+ std::vector<struct channel_info> &chan_info,
+ pmt_t signal_info)
+{
+
+ pmt_t response_signal = pmt_nth(0, signal_info);
+ pmt_t invocation_handle = pmt_nth(1, signal_info);
+
+ // not a valid channel number?
+ if(channel >= (long)chan_info.size() && channel != CONTROL_CHAN) {
+ port->send(response_signal,
+ pmt_list2(invocation_handle,
+ s_err_channel_invalid));
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Invalid channel number for event "
+ << response_signal << std::endl;
+ return false;
+ }
+
+ // not the owner of the port?
+ if(chan_info[channel].owner != port->port_symbol()) {
+ port->send(response_signal,
+ pmt_list2(invocation_handle,
+ s_err_channel_permission_denied));
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] Invalid permissions"
+ << " for " << response_signal
+ << " from " << port->port_symbol()
+ << " proper owner is " << chan_info[channel].owner
+ << " on channel " << channel
+ << " invocation " << invocation_handle
+ << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * \brief Finds the next available RID for internal USRP server use with control
+ * and status packets.
+ *
+ * \returns the next valid RID or -1 if no more RIDs are available.
+ */
+long
+usrp_server::next_rid()
+{
+ for(int i = 0; i < D_MAX_RID; i++)
+ if(pmt_eqv(d_rids[i].owner, PMT_NIL))
+ return i;
+
+ if(verbose)
+ std::cout << "[USRP_SERVER] No RIDs left\n";
+ return -1;
+}
+
+/*!
+ * \brief Called by handle_message() when USRP server gets a response that the
+ * USRP was opened successfully to initialize the registers using the new
+ * register read/write control packets.
+ */
+void
+usrp_server::initialize_registers()
+{
+ // We use handle_cmd_to_control_channel() to create the register writes using
+ // PMT_NIL as the response port to tell usrp_server not to pass the response
+ // up to any application.
+ if(verbose)
+ std::cout << "[USRP_SERVER] Initializing registers...\n";
+
+ // RX mode to normal (0)
+ set_register(FR_MODE, 0);
+
+ // FPGA debugging?
+ if(d_fpga_debug) {
+ set_register(FR_DEBUG_EN, 1);
+ // FIXME: need to figure out exact register writes to control daughterboard
+ // pins that need to be written to
+ } else {
+ set_register(FR_DEBUG_EN, 0);
+ }
+
+ // Set the transmit sample rate divisor, which is 4-1
+ set_register(FR_TX_SAMPLE_RATE_DIV, 3);
+
+ // Dboard IO buffer and register settings
+ set_register(FR_OE_0, (0xffff << 16) | 0x0000);
+ set_register(FR_IO_0, (0xffff << 16) | 0x0000);
+ set_register(FR_OE_1, (0xffff << 16) | 0x0000);
+ set_register(FR_IO_1, (0xffff << 16) | 0x0000);
+ set_register(FR_OE_2, (0xffff << 16) | 0x0000);
+ set_register(FR_IO_2, (0xffff << 16) | 0x0000);
+ set_register(FR_OE_3, (0xffff << 16) | 0x0000);
+ set_register(FR_IO_3, (0xffff << 16) | 0x0000);
+
+ // zero Tx side Auto Transmit/Receive regs
+ set_register(FR_ATR_MASK_0, 0);
+ set_register(FR_ATR_TXVAL_0, 0);
+ set_register(FR_ATR_RXVAL_0, 0);
+ set_register(FR_ATR_MASK_1, 0);
+ set_register(FR_ATR_TXVAL_1, 0);
+ set_register(FR_ATR_RXVAL_1, 0);
+ set_register(FR_ATR_MASK_2, 0);
+ set_register(FR_ATR_TXVAL_2, 0);
+ set_register(FR_ATR_RXVAL_2, 0);
+ set_register(FR_ATR_MASK_3, 0);
+ set_register(FR_ATR_TXVAL_3, 0);
+ set_register(FR_ATR_RXVAL_3, 0);
+
+ // Configure TX mux, this is a hacked value
+ set_register(FR_TX_MUX, 0x00000081);
+
+ // Set the interpolation rate, which is the rate divided by 4, minus 1
+ set_register(FR_INTERP_RATE, (d_interp_tx/4)-1);
+
+ // Apparently this register changes again
+ set_register(FR_TX_MUX, 0x00000981);
+
+ // Set the receive sample rate divisor, which is 2-1
+ set_register(FR_RX_SAMPLE_RATE_DIV, 1);
+
+ // DC offset
+ set_register(FR_DC_OFFSET_CL_EN, 0x0000000f);
+
+ // Reset the DC correction offsets
+ set_register(FR_ADC_OFFSET_0, 0);
+ set_register(FR_ADC_OFFSET_1, 0);
+
+ // Some hard-coded RX configuration
+ set_register(FR_RX_FORMAT, 0x00000300);
+ set_register(FR_RX_MUX, 1);
+
+ // RX decimation rate is divided by two, then subtract 1
+ set_register(FR_DECIM_RATE, (d_decim_rx/2)-1);
+
+ // More hard coding
+ set_register(FR_RX_MUX, 0x000e4e41);
+
+ // Resetting RX registers
+ set_register(FR_RX_PHASE_0, 0);
+ set_register(FR_RX_PHASE_1, 0);
+ set_register(FR_RX_PHASE_2, 0);
+ set_register(FR_RX_PHASE_3, 0);
+ set_register(FR_RX_FREQ_0, 0x28000000);
+ set_register(FR_RX_FREQ_1, 0);
+ set_register(FR_RX_FREQ_2, 0);
+ set_register(FR_RX_FREQ_3, 0);
+
+ // Enable debug bus
+ set_register(FR_DEBUG_EN, 0xf);
+ set_register(FR_OE_0, -1);
+ set_register(FR_OE_1, -1);
+ set_register(FR_OE_2, -1);
+ set_register(FR_OE_3, -1);
+
+ // DEBUGGING
+ //check_register_initialization();
+}
+
+// FIXME: used for debugging to determine if all the registers are actually
+// being set correctly
+void
+usrp_server::check_register_initialization()
+{
+ // RX mode to normal (0)
+ read_register(FR_MODE);
+
+ // FPGA debugging?
+ if(d_fpga_debug) {
+ read_register(FR_DEBUG_EN);
+ // FIXME: need to figure out exact register writes to control daughterboard
+ // pins that need to be written to
+ } else {
+ read_register(FR_DEBUG_EN);
+ }
+
+ // Set the transmit sample rate divisor, which is 4-1
+ read_register(FR_TX_SAMPLE_RATE_DIV);
+
+ // Dboard IO buffer and register settings
+ read_register(FR_OE_0);
+ read_register(FR_IO_0);
+ read_register(FR_OE_1);
+ read_register(FR_IO_1);
+ read_register(FR_OE_2);
+ read_register(FR_IO_2);
+ read_register(FR_OE_3);
+ read_register(FR_IO_3);
+
+ // zero Tx side Auto Transmit/Receive regs
+ read_register(FR_ATR_MASK_0);
+ read_register(FR_ATR_TXVAL_0);
+ read_register(FR_ATR_RXVAL_0);
+ read_register(FR_ATR_MASK_1);
+ read_register(FR_ATR_TXVAL_1);
+ read_register(FR_ATR_RXVAL_1);
+ read_register(FR_ATR_MASK_2);
+ read_register(FR_ATR_TXVAL_2);
+ read_register(FR_ATR_RXVAL_2);
+ read_register(FR_ATR_MASK_3);
+ read_register(FR_ATR_TXVAL_3);
+ read_register(FR_ATR_RXVAL_3);
+
+ // Configure TX mux, this is a hacked value
+ read_register(FR_TX_MUX);
+
+ // Set the interpolation rate, which is the rate divided by 4, minus 1
+ read_register(FR_INTERP_RATE);
+
+ // Apparently this register changes again
+ read_register(FR_TX_MUX);
+
+ // Set the receive sample rate divisor, which is 2-1
+ read_register(FR_RX_SAMPLE_RATE_DIV);
+
+ // DC offset
+ read_register(FR_DC_OFFSET_CL_EN);
+
+ // Reset the DC correction offsets
+ read_register(FR_ADC_OFFSET_0);
+ read_register(FR_ADC_OFFSET_1);
+
+ // Some hard-coded RX configuration
+ read_register(FR_RX_FORMAT);
+ read_register(FR_RX_MUX);
+
+ // RX decimation rate is divided by two, then subtract 1
+ read_register(FR_DECIM_RATE);
+
+ // More hard coding
+ read_register(FR_RX_MUX);
+
+ // Resetting RX registers
+ read_register(FR_RX_PHASE_0);
+ read_register(FR_RX_PHASE_1);
+ read_register(FR_RX_PHASE_2);
+ read_register(FR_RX_PHASE_3);
+ read_register(FR_RX_FREQ_0);
+ read_register(FR_RX_FREQ_1);
+ read_register(FR_RX_FREQ_2);
+ read_register(FR_RX_FREQ_3);
+}
+
+/*!
+ * \brief Used to generate FPGA register write commands to reset all of the FPGA
+ * registers to a value of 0.
+ */
+void
+usrp_server::reset_all_registers()
+{
+ for(int i=0; i<64; i++)
+ set_register(i, 0);
+}
+
+/*!
+ * \brief Used internally by USRP server to generate a control/status packet
+ * which contains a register write.
+ *
+ * The \p reg parameter is the register number that the value \p val will be
+ * written to.
+ */
+void
+usrp_server::set_register(long reg, long val)
+{
+ size_t psize;
+ long payload_len = 0;
+
+ pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
+ transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_packet, psize);
+
+ pkt->set_header(0, CONTROL_CHAN, 0, payload_len);
+ pkt->set_timestamp(0xffffffff);
+
+ pkt->cs_write_reg(reg, val);
+
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(PMT_NIL,
+ pmt_from_long(CONTROL_CHAN),
+ v_packet));
+}
+
+/*!
+ * \brief Used internally by USRP server to generate a control/status packet
+ * which contains a register read. This is important to use internally so that
+ * USRP server can bypass the use of RIDs with register reads, as they are not
+ * needed and it would use up the finite number of RIDs available for use for
+ * applications to receive responses.
+ *
+ * The \p reg parameter is the register number that the value should be read
+ * from.
+ */
+void
+usrp_server::read_register(long reg)
+{
+ size_t psize;
+ long payload_len = 0;
+
+ pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
+ transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writable_elements(v_packet, psize);
+
+ pkt->set_header(0, CONTROL_CHAN, 0, payload_len);
+ pkt->set_timestamp(0xffffffff);
+
+ pkt->cs_read_reg(0, reg);
+
+ d_cs_usrp->send(s_cmd_usrp_write,
+ pmt_list3(PMT_NIL,
+ pmt_from_long(CONTROL_CHAN),
+ v_packet));
+}
+
+REGISTER_MBLOCK_CLASS(usrp_server);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_SERVER_H
+#define INCLUDED_USRP_SERVER_H
+
+#include <mblock/mblock.h>
+#include <vector>
+#include <queue>
+#include <fstream>
+#include <usrp_inband_usb_packet.h>
+
+typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
+
+/*!
+ * \brief Implements the lowest-level mblock usb_interface to the USRP
+ */
+class usrp_server : public mb_mblock
+{
+public:
+
+ // our ports
+ enum port_types {
+ RX_PORT = 0,
+ TX_PORT = 1
+ };
+ static const int N_PORTS = 4;
+ std::vector<mb_port_sptr> d_tx, d_rx;
+ mb_port_sptr d_cs;
+ mb_port_sptr d_cs_usrp;
+
+ static const int D_USB_CAPACITY = 32 * 1024 * 1024;
+ static const int D_MAX_CHANNELS = 16;
+ long d_ntx_chan;
+ long d_nrx_chan;
+
+ pmt_t d_usrp_dict;
+
+ bool d_fpga_debug;
+
+ long d_interp_tx;
+ long d_decim_rx;
+
+ // Keep track of the request IDs
+ struct rid_info {
+ pmt_t owner;
+ long user_rid;
+
+ rid_info() {
+ owner = PMT_NIL;
+ user_rid = 0;
+ }
+ };
+
+ static const long D_MAX_RID = 64;
+ std::vector<rid_info> d_rids;
+
+ struct channel_info {
+ long assigned_capacity; // the capacity currently assignedby the channel
+ pmt_t owner; // port ID of the owner of the channel
+
+ channel_info() {
+ assigned_capacity = 0;
+ owner = PMT_NIL;
+ }
+ };
+
+ long d_rx_chan_mask; // A bitmask representing the channels in the
+ // receiving state
+
+ std::vector<struct channel_info> d_chaninfo_tx;
+ std::vector<struct channel_info> d_chaninfo_rx;
+
+ std::queue<mb_message_sptr> d_defer_queue;
+
+ bool d_defer;
+ bool d_opened;
+
+ bool d_fake_rx;
+
+public:
+ usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_server();
+
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+protected:
+ static int max_capacity() { return D_USB_CAPACITY; }
+
+private:
+ void handle_cmd_allocate_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
+ void handle_cmd_deallocate_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
+ void handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
+ void handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
+ void handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
+ void handle_cmd_stop_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data);
+ int rx_port_index(pmt_t port_id);
+ int tx_port_index(pmt_t port_id);
+ long current_capacity_allocation();
+ void recall_defer_queue();
+ void reset_channels();
+ void handle_response_usrp_read(pmt_t data);
+ bool check_valid(mb_port_sptr port, long channel, std::vector<struct channel_info> &chan_info, pmt_t signal_info);
+ void parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt);
+ long next_rid();
+ void initialize_registers();
+ void set_register(long reg, long val);
+ void read_register(long reg);
+ void check_register_initialization();
+ void reset_all_registers();
+};
+
+#endif /* INCLUDED_USRP_SERVER_H */
--- /dev/null
+;; -*- scheme -*- ; not really, but tells emacs how to format this
+;;
+;; Copyright 2007 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Radio
+;;
+;; GNU Radio is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GNU Radio is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program; if not, write to the Free Software Foundation, Inc.,
+;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+;;
+
+;; ----------------------------------------------------------------
+;; This is an mblock header file
+;;
+;; The format is very much a work-in-progress.
+;; It'll be compiled to C++.
+;; ----------------------------------------------------------------
+
+;; In the outgoing messages described below, invocation-handle is an
+;; identifier provided by the client to tag the method invocation.
+;; The identifier will be returned with the response, to provide the
+;; client with a mechanism to match asynchronous responses with the
+;; commands that generate them. The value of the invocation-handle is
+;; opaque the the server, and is not required by the server to be
+;; unique.
+;;
+;; In the incoming messages described below, invocation-handle is the
+;; identifier provided by the client in the prompting invocation. The
+;; identifier is returned with the response, so that the client has a
+;; mechanism to match asynchronous responses with the commands that
+;; generated them.
+;;
+;; status is either #t, indicating success, or a symbol indicating an error.
+;; All symbol's names shall begin with %error-
+
+
+;; ----------------------------------------------------------------
+;; usrp-channel
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-channel
+
+ (:outgoing
+
+ (cmd-allocate-channel invocation-handle capacity-reservation)
+
+ ;; The cmd-allocate-channel message requests that the server
+ ;; allocates a logical channel in the FPGA for use.
+ ;; capacity-reservation specifies the number of bytes/s of
+ ;; interconnect capacity (USB or ethernet) to reserve for this
+ ;; channel. (The reservation is just a sanity check, no OS
+ ;; specific mechanism is used.)
+
+ (cmd-deallocate-channel invocation-handle channel)
+
+ ;; The integer channel specifies the channel to deallocate.
+
+ )
+
+ (:incoming
+
+
+ (response-allocate-channel invocation-handle status channel)
+
+ ;; If successful, a channel the specified capacity was allocated.
+ ;; channel, an integer, indicates which channel was allocated.
+
+ (response-deallocate-channel invocation-handle status)
+
+ ;; If successful, the specified channel and associated interconnect
+ ;; capacity were deallocated.
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-low-level-cs
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+;;
+;; This defines a low level control and status interface to the usrp.
+;; This will probably be replaced (or at least augmented) with a
+;; higher level interface. For now, this will allow us to get on
+;; the air.
+;;
+;; The subpackets are lists containing the relevant parameters. The
+;; server will marshall them appropriately. Below is a list of
+;; subpackets. See inband-signaling-usb for details. The opcodes are
+;; symbols; unless otherwise indicated the remaining parameters are
+;; integers. rid values are limited to 3-bits.
+;;
+;; (op-ping-fixed rid ping-value)
+;; (op-ping-fixed-reply rid ping-value)
+;; (op-write-reg reg-number reg-value)
+;; (op-write-reg-masked reg-number reg-value mask-value)
+;; (op-read-reg rid reg-number)
+;; (op-read-reg-reply rid reg-number reg-value)
+;; (op-i2c-write i2c-addr u8-vec)
+;; (op-i2c-read rid i2c-addr nbytes)
+;; (op-i2c-read-reply rid i2c-addr u8-vec)
+;; (op-spi-write enables format opt-header-bytes u8-vec)
+;; (op-spi-read rid enables format opt-header-bytes nbytes)
+;; (op-spi-read-reply rid u8-vec)
+;; (op-delay ticks)
+
+
+(define-protocol-class usrp-low-level-cs
+
+ (:outgoing
+
+ (cmd-to-control-channel invocation-handle list-of-subpackets)
+
+ )
+
+ (:incoming
+
+ (response-from-control-channel invocation-handle status list-of-subpackets timestamp)
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-tx
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-tx
+ (:include usrp-channel)
+ (:include usrp-low-level-cs)
+
+ (:outgoing
+
+ (cmd-xmit-raw-frame invocation-handle channel samples timestamp properties)
+
+ ;; The argument channel must be an integer. It specifies the
+ ;; channel on which the frame of samples will be be sent.
+ ;;
+ ;; samples must be a uniform numeric vector. The contents of the
+ ;; sample vector is treated as opaque and is passed on to the FPGA
+ ;; unmodified. It is the responsibility of the sender to ensure
+ ;; that the binary format is sensible for the current FPGA
+ ;; configuration.
+ ;;
+ ;; timestamp is a 32-bit integer that specifies the time at which
+ ;; the first sample in samples shall be sent to the D/A converter.
+ ;; The format and interpration of time is specified in the file
+ ;; inband-signaling-usb
+ )
+
+ (:incoming
+
+ (response-xmit-raw-frame invocation-handle status)
+
+ ;; If successful, the samples of the associated frame have been
+ ;; transmitted to the USRP. This message may be used to implement
+ ;; Tx flow control. The client could for example implement a
+ ;; policy of never having more than 4 unacknowledged
+ ;; cmd-xmit-raw-frame's outstanding.
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-rx
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-rx
+ (:include usrp-channel)
+ (:include usrp-low-level-cs)
+
+ (:outgoing
+
+ (cmd-start-recv-raw-samples invocation-handle channel)
+
+ ;; The argument channel must be an integer. It specifies the
+ ;; channel from which frames of samples will be be received. The
+ ;; server will return response-recv-raw-samples messages until a
+ ;; cmd-stop-recv-raw-samples message is received.
+
+ (cmd-stop-recv-raw-samples invocation-handle channel)
+
+ ;; The argument channel must be an integer. There is no reply to
+ ;; this message.
+
+ )
+
+ (:incoming
+
+ (response-recv-raw-samples invocation-handle status samples timestamp channel properties)
+
+ ;; samples is a uniform numeric vector. The contents of the sample
+ ;; vector is treated as opaque and is passed from the FPGA
+ ;; unmodified. It is the responsibility of the receiver to decode
+ ;; the binary format as appropriate for the current FPGA
+ ;; configuration.
+ ;;
+ ;; timestamp is a 32-bit integer that specifies the time at which
+ ;; the first sample in samples was received from the A/D converter.
+ ;; The format and interpretation of time is as specified in the
+ ;; file inband-signaling-usb.
+ ;;
+ ;; properties is a dictionary containing additional (key, value)
+ ;; pairs associated with the reception of these samples. In
+ ;; particular, the map may contain the Received Signal Strength
+ ;; Indication (RSSI) reported by the front end at the time the
+ ;; first sample was received from the A/D.
+
+ )
+ )
+
+
+;; ----------------------------------------------------------------
+;; usrp-server-cs
+;;
+;; Control and status port for usrp-server
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-server-cs
+
+ (:outgoing
+ (cmd-open invocation-handle which-usrp)
+ (cmd-close invocation-handle)
+ (cmd-max-capacity invocation-handle)
+ (cmd-ntx-chan invocation-handle)
+ (cmd-nrx-chan invocation-handle)
+ (cmd-current-capacity-allocation invocation-handle)
+ )
+
+ (:incoming
+ (response-open invocation-handle status)
+ (response-close invocation-handle status)
+ (response-max-capacity invocation-handle status capacity)
+ (response-ntx-chan invocation-handle status ntx-chan)
+ (response-nrx-chan invocation-handle status nrx-chan)
+ (response-current-capacity-allocation invocation-handle status capacity)
+ )
+ )
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp_tx.h>
+#include <iostream>
+#include <usb.h>
+#include <mblock/class_registry.h>
+#include <usrp_inband_usb_packet.h>
+#include <fpga_regs_common.h>
+#include <usrp_standard.h>
+#include <stdio.h>
+
+#include <symbols_usrp_tx_cs.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+static const bool verbose = false;
+
+usrp_tx::usrp_tx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_disk_write(false)
+{
+ d_cs = define_port("cs", "usrp-tx-cs", true, mb_port::EXTERNAL);
+
+ //d_disk_write=true;
+
+ if(d_disk_write) {
+ d_ofile.open("tx_data.dat",std::ios::binary|std::ios::out);
+ d_cs_ofile.open("tx_cs.dat",std::ios::binary|std::ios::out);
+ }
+}
+
+usrp_tx::~usrp_tx()
+{
+ if(d_disk_write) {
+ d_ofile.close();
+ d_cs_ofile.close();
+ }
+}
+
+void
+usrp_tx::initial_transition()
+{
+
+}
+
+/*!
+ * \brief Handles incoming signals to to the m-block, wihch should only ever be
+ * a single message: cmd-usrp-tx-write.
+ */
+void
+usrp_tx::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t port_id = msg->port_id();
+ pmt_t data = msg->data();
+
+ // Theoretically only have 1 message to ever expect, but
+ // want to make sure its at least what we want
+ if(pmt_eq(port_id, d_cs->port_symbol())) {
+
+ if(pmt_eqv(event, s_cmd_usrp_tx_write))
+ write(data);
+ }
+}
+
+/*!
+ * \brief Performs the actual writing of data to the USB bus, called by
+ * handle_message() when a cmd-usrp-tx-write signal is received.
+ *
+ * The \p data parameter is a PMT list which contains three mandatory elements,
+ * in the following order: an invocation handle, a channel, and a uniform vector
+ * of memory which contains the packets to be written to the bus.
+ */
+void
+usrp_tx::write(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t channel = pmt_nth(1, data);
+ pmt_t v_packets = pmt_nth(2, data);
+ d_utx = boost::any_cast<usrp_standard_tx_sptr>(pmt_any_ref(pmt_nth(3, data)));
+
+ size_t n_bytes;
+ bool underrun; // this will need to go, as it is taken care of in the packet headers
+
+ transport_pkt *pkts = (transport_pkt *) pmt_u8vector_writable_elements(v_packets, n_bytes);
+
+ int ret = d_utx->write (pkts, n_bytes, &underrun);
+
+ if (0 && underrun)
+ fprintf(stderr, "uU");
+
+ if (ret == (int) n_bytes) {
+ if (verbose)
+ std::cout << "[usrp_server] Write of " << n_bytes << " successful\n";
+ // need to respond with the channel so the USRP server knows who to forward the result of
+ // the write to by looking up the owner of the channel
+ d_cs->send(s_response_usrp_tx_write,
+ pmt_list3(invocation_handle, PMT_T, channel));
+ }
+ else {
+ if (verbose)
+ std::cout << "[usrp_server] Error writing " << n_bytes << " bytes to USB bus\n";
+ d_cs->send(s_response_usrp_tx_write,
+ pmt_list3(invocation_handle, PMT_F, channel));
+ }
+
+ long n_packets =
+ static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size()));
+
+ for(int i=0; i < n_packets; i++) {
+
+ if(d_disk_write) {
+ if(pkts[i].chan() == CONTROL_CHAN)
+ d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
+ else
+ d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
+
+ d_cs_ofile.flush();
+ d_ofile.flush();
+ }
+ }
+
+
+ return;
+}
+
+REGISTER_MBLOCK_CLASS(usrp_tx);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_TX_H
+#define INCLUDED_USRP_TX_H
+
+#include <mblock/mblock.h>
+#include <fstream>
+#include "usrp_standard.h"
+
+/*!
+ * \brief Implements the low level usb interface to the USRP
+ */
+class usrp_tx : public mb_mblock
+{
+ mb_port_sptr d_cs;
+ usrp_standard_tx_sptr d_utx;
+
+ bool d_disk_write;
+ std::ofstream d_ofile;
+ std::ofstream d_cs_ofile;
+
+ public:
+ usrp_tx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_tx();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ private:
+ void write(pmt_t data);
+};
+
+
+#endif /* INCLUDED_USRP_TX_H */
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <vector>
+#include <usb.h>
+#include <mblock/class_registry.h>
+#include <usrp_tx_stub.h>
+#include <usrp_inband_usb_packet.h>
+#include <fpga_regs_common.h>
+#include "usrp_standard.h"
+#include <stdio.h>
+#include <fstream>
+#include <usrp_rx_stub.h>
+
+#include <symbols_usrp_tx_cs.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+static const bool verbose = false;
+
+usrp_tx_stub::usrp_tx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_disk_write(false)
+{
+ d_cs = define_port("cs", "usrp-tx-cs", true, mb_port::EXTERNAL);
+
+ //d_disk_write=true;
+
+ if(d_disk_write) {
+ d_ofile.open("tx_stub_data.dat",std::ios::binary|std::ios::out);
+ d_cs_ofile.open("tx_stub_cs.dat",std::ios::binary|std::ios::out);
+ }
+}
+
+usrp_tx_stub::~usrp_tx_stub()
+{
+ if(d_disk_write) {
+ d_ofile.close();
+ d_cs_ofile.close();
+ }
+}
+
+void
+usrp_tx_stub::initial_transition()
+{
+
+}
+
+void
+usrp_tx_stub::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal();
+ pmt_t port_id = msg->port_id();
+ pmt_t data = msg->data();
+
+ // Theoretically only have 1 message to ever expect, but
+ // want to make sure its at least what we want
+ if(pmt_eq(port_id, d_cs->port_symbol())) {
+
+ if(pmt_eqv(event, s_cmd_usrp_tx_write))
+ write(data);
+ }
+}
+
+void
+usrp_tx_stub::write(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t channel = pmt_nth(1, data);
+ pmt_t v_packets = pmt_nth(2, data);
+ d_utx = boost::any_cast<usrp_standard_tx *>(pmt_any_ref(pmt_nth(3, data)));
+
+ size_t n_bytes;
+
+ transport_pkt *pkts = (transport_pkt *) pmt_u8vector_writable_elements(v_packets, n_bytes);
+ long n_packets = static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size()));
+
+ // Parse the packets looking for C/S packets and dump them to a disk if
+ // necessary
+ for(long i=0; i<n_packets; i++) {
+
+ if(d_disk_write) {
+ if(pkts[i].chan() == CONTROL_CHAN)
+ d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
+ else
+ d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size());
+
+ d_cs_ofile.flush();
+ d_ofile.flush();
+ }
+
+ if(pkts[i].chan() == CONTROL_CHAN)
+ parse_cs(invocation_handle, pkts[i]);
+ }
+
+ d_cs->send(s_response_usrp_tx_write,
+ pmt_list3(invocation_handle, PMT_T, channel));
+
+ return;
+}
+
+void
+usrp_tx_stub::parse_cs(pmt_t invocation_handle, transport_pkt pkt)
+{
+
+ long payload_len = pkt.payload_len();
+ long curr_payload = 0;
+
+ size_t ignore;
+
+ // There is the possibility that the responses for a single USB packet full of
+ // CS packets will not fit back in a single USB packet, considering some
+ // responses are greater than their commands (read registers).
+ new_packet:
+ pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0);
+
+ transport_pkt *q_pkt =
+ (transport_pkt *) pmt_u8vector_writable_elements(v_pkt, ignore);
+
+ q_pkt->set_header(0, CONTROL_CHAN, 0, 0);
+ q_pkt->set_timestamp(0xffffffff);
+
+ // We dispatch based on the control packet type, however we can extract the
+ // opcode and the length immediately which is consistent in all responses.
+ //
+ // Since each control packet can have multiple responses, we keep reading the
+ // lengths of each subpacket until we reach the payload length.
+ while(curr_payload < payload_len) {
+
+ pmt_t sub_packet = pkt.read_subpacket(curr_payload);
+ pmt_t op_symbol = pmt_nth(0, sub_packet);
+
+ int len = pkt.cs_len(curr_payload);
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Parsing subpacket "
+ << op_symbol << " ... length " << len << std::endl;
+
+ //----------------- PING FIXED ------------------//
+ if(pmt_eq(op_symbol, s_op_ping_fixed)) {
+
+ long rid = pmt_to_long(pmt_nth(1, sub_packet));
+ long pingval = pmt_to_long(pmt_nth(2, sub_packet));
+
+ // Generate a reply and put it in the queue for the RX stub to read
+ if(!q_pkt->cs_ping_reply(rid, pingval))
+ goto new_packet;
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Generated ping response "
+ << "("
+ << "RID: " << rid << ", "
+ << "VAL: " << pingval
+ << ")\n";
+ }
+
+ //----------------- READ REG ------------------//
+ if(pmt_eq(op_symbol, s_op_read_reg)) {
+
+ long rid = pmt_to_long(pmt_nth(1, sub_packet));
+ long reg_num = pmt_to_long(pmt_nth(2, sub_packet));
+ long reg_val = 0xdeef;
+
+ // Generate a reply and put it in the queue for the RX stub to read
+ if(!q_pkt->cs_read_reg_reply(rid, reg_num, reg_val))
+ goto new_packet;
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Generated read register response "
+ << "("
+ << "RID: " << rid << ", "
+ << "REG: " << reg_num << ", "
+ << "VAL: " << reg_val
+ << ")\n";
+ }
+
+ //----------------- DELAY ------------------//
+ if(pmt_eq(op_symbol, s_op_delay)) {
+
+ long ticks = pmt_to_long(pmt_nth(1, sub_packet));
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received delay command "
+ << "("
+ << "Ticks: " << ticks
+ << ")\n";
+ }
+
+ //----------------- WRITE REG ------------------//
+ if(pmt_eq(op_symbol, s_op_write_reg)) {
+
+ pmt_t reg_num = pmt_nth(1, sub_packet);
+ pmt_t reg_val = pmt_nth(2, sub_packet);
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received write register command "
+ << "("
+ << "RegNum: " << reg_num << ", "
+ << "Val: " << reg_val
+ << ")\n";
+ }
+
+ //----------------- WRITE REG MASK ---------------//
+ if(pmt_eq(op_symbol, s_op_write_reg_masked)) {
+
+ pmt_t reg_num = pmt_nth(1, sub_packet);
+ pmt_t reg_val = pmt_nth(2, sub_packet);
+ pmt_t mask = pmt_nth(3, sub_packet);
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received write register command "
+ << "("
+ << "RegNum: " << reg_num << ", "
+ << "Val: " << reg_val << ", "
+ << "Mask: " << mask
+ << ")\n";
+ }
+
+ //---------------- I2C WRITE ------------------//
+ if(pmt_eq(op_symbol, s_op_i2c_write)) {
+ pmt_t i2c_addr = pmt_nth(1, sub_packet);
+ pmt_t i2c_data = pmt_nth(2, sub_packet);
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received i2c write command "
+ << "("
+ << "Addr: " << i2c_addr << ", "
+ << "Data: " << i2c_data
+ << ")\n";
+ }
+
+ //---------------- I2C READ ------------------//
+ if(pmt_eq(op_symbol, s_op_i2c_read)) {
+ long rid = pmt_to_long(pmt_nth(1, sub_packet));
+ long i2c_addr = pmt_to_long(pmt_nth(2, sub_packet));
+ long i2c_bytes = pmt_to_long(pmt_nth(3, sub_packet));
+
+ // Create data to place as a response, filled with 0xff
+ size_t ignore;
+ pmt_t i2c_data = pmt_make_u8vector(i2c_bytes, 0xff);
+ uint8_t *w_data = (uint8_t *) pmt_u8vector_writable_elements(i2c_data, ignore);
+
+ // Generate a reply and put it in the queue for the RX stub to read
+ if(!q_pkt->cs_i2c_read_reply(rid, i2c_addr, w_data, i2c_bytes))
+ goto new_packet;
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received i2c read "
+ << "("
+ << "RID: " << rid << ", "
+ << "Addr: " << i2c_addr << ", "
+ << "Bytes: " << i2c_bytes
+ << ")\n";
+ }
+
+ //---------------- SPI WRITE ------------------//
+ if(pmt_eq(op_symbol, s_op_spi_write)) {
+ long enables = pmt_to_long(pmt_nth(1, sub_packet));
+ long format = pmt_to_long(pmt_nth(2, sub_packet));
+ long opt = pmt_to_long(pmt_nth(3, sub_packet));
+ pmt_t data = pmt_nth(4, sub_packet);
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received spi write command "
+ << "("
+ << "Enables: " << enables << ", "
+ << "Format: " << format << ", "
+ << "Options: " << opt << ", "
+ << "Data: " << data
+ << ")\n";
+ }
+
+ //---------------- SPI READ ------------------//
+ if(pmt_eq(op_symbol, s_op_spi_read)) {
+ long rid = pmt_to_long(pmt_nth(1, sub_packet));
+ long enables = pmt_to_long(pmt_nth(2, sub_packet));
+ long format = pmt_to_long(pmt_nth(3, sub_packet));
+ long opt = pmt_to_long(pmt_nth(4, sub_packet));
+ long n_bytes = pmt_to_long(pmt_nth(5, sub_packet));
+
+ // Create data to place as a fake response
+ size_t ignore;
+ pmt_t spi_data = pmt_make_u8vector(n_bytes, 0xff);
+ uint8_t *w_data = (uint8_t *) pmt_u8vector_writable_elements(spi_data, ignore);
+
+ // Generate a reply and put it in the queue for the RX stub to read
+ if(!q_pkt->cs_spi_read_reply(rid, w_data, n_bytes))
+ goto new_packet;
+
+ if(verbose)
+ std::cout << "[USRP_TX_STUB] Received spi read command "
+ << "("
+ << "RID: " << rid << ", "
+ << "Enables: " << enables << ", "
+ << "Format: " << format << ", "
+ << "Options: " << opt << ", "
+ << "Bytes: " << n_bytes
+ << ")\n";
+
+ }
+
+ // Each subpacket has an unaccounted for 2 bytes which is the opcode
+ // and the length field
+ curr_payload += len + 2;
+
+ // All subpackets are 32-bit aligned
+ int align_offset = 4 - (curr_payload % 4);
+
+ if(align_offset != 4)
+ curr_payload += align_offset;
+
+ }
+
+ // If the packet has data in the payload, it needs queued
+ if(q_pkt->payload_len() > 0)
+ d_cs_queue.push(pmt_list2(invocation_handle, v_pkt));
+
+ return;
+}
+
+REGISTER_MBLOCK_CLASS(usrp_tx_stub);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_TX_STUB_H
+#define INCLUDED_USRP_TX_STUB_H
+
+#include <mblock/mblock.h>
+#include <vector>
+#include "usrp_standard.h"
+#include <fstream>
+#include <usrp_inband_usb_packet.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+/*!
+ * \brief Implements the low level usb interface to the USRP
+ */
+class usrp_tx_stub : public mb_mblock
+{
+ public:
+
+ mb_port_sptr d_cs;
+ usrp_standard_tx* d_utx;
+
+ std::ofstream d_ofile;
+ std::ofstream d_cs_ofile;
+
+ bool d_disk_write;
+
+ public:
+ usrp_tx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_tx_stub();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ private:
+ void write(pmt_t data);
+ void parse_cs(pmt_t invocation_handle, transport_pkt pkt);
+
+};
+
+
+#endif /* INCLUDED_USRP_TX_STUB_H */
+
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <usrp_usb_interface.h>
+
+#include <iostream>
+#include <vector>
+#include <usb.h>
+#include <mblock/class_registry.h>
+#include <usrp_inband_usb_packet.h>
+#include <fpga_regs_common.h>
+#include "usrp_rx.h"
+#include <usrp_rx_stub.h>
+#include "usrp_tx.h"
+#include "usrp_standard.h"
+#include <stdio.h>
+#include <usrp_dbid.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+#include <symbols_usrp_interface_cs.h>
+#include <symbols_usrp_tx_cs.h>
+#include <symbols_usrp_rx_cs.h>
+static pmt_t s_shutdown = pmt_intern("%shutdown");
+
+static const bool verbose = false;
+
+
+/*!
+ * \brief Initializes the USB interface m-block.
+ *
+ * The \p user_arg should be a PMT dictionary which can contain optional
+ * arguments for the block, such as the decimatoin and interpolation rate.
+ */
+usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_fake_usrp(false),
+ d_rx_reading(false),
+ d_interp_tx(128),
+ d_decim_rx(128),
+ d_rf_freq(-1),
+ d_rbf("inband_tx_rx.rbf")
+{
+ // Dictionary for arguments to all of the components
+ pmt_t usrp_dict = user_arg;
+
+ // Default TX/RX interface
+ std::string tx_interface = "usrp_tx";
+ std::string rx_interface = "usrp_rx";
+
+ if (pmt_is_dict(usrp_dict)) {
+
+ // The 'fake-usrp' key enables the TX and RX stubs if PMT_T
+ if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_NIL)) {
+ if(pmt_eqv(fake_usrp, PMT_T)) {
+ tx_interface = "usrp_tx_stub";
+ rx_interface = "usrp_rx_stub";
+ d_fake_usrp=true;
+ }
+ }
+
+ // Read the TX interpolations
+ if(pmt_t interp_tx = pmt_dict_ref(usrp_dict,
+ pmt_intern("interp-tx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(interp_tx, PMT_NIL))
+ d_interp_tx = pmt_to_long(interp_tx);
+ }
+
+ // Read the RX decimation rate
+ if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
+ pmt_intern("decim-rx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(decim_rx, PMT_NIL))
+ d_decim_rx = pmt_to_long(decim_rx);
+ }
+
+ // Read the RBF
+ if(pmt_t rbf = pmt_dict_ref(usrp_dict,
+ pmt_intern("rbf"),
+ PMT_NIL)) {
+ if(!pmt_eqv(rbf, PMT_NIL))
+ d_rbf = pmt_symbol_to_string(rbf);
+ }
+
+ // The RF center frequency
+ if(pmt_t rf_freq = pmt_dict_ref(usrp_dict,
+ pmt_intern("rf-freq"),
+ PMT_NIL)) {
+ if(!pmt_eqv(rf_freq, PMT_NIL))
+ d_rf_freq = pmt_to_double(rf_freq);
+ }
+ }
+
+ if (verbose) {
+ std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to "
+ << d_rbf << std::endl;
+
+ std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to "
+ << d_interp_tx << std::endl;
+
+ std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to "
+ << d_decim_rx << std::endl;
+
+ std::cout << "[USRP_USB_INTERFACE] Using TX interface: "
+ << tx_interface << "\n";
+
+ std::cout << "[USRP_USB_INTERFACE] Using RX interface: "
+ << rx_interface << "\n";
+
+ }
+
+ d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL);
+ d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL);
+ d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL);
+
+ // Connect to TX and RX
+ define_component("tx", tx_interface, usrp_dict);
+ define_component("rx", rx_interface, usrp_dict);
+ connect("self", "rx_cs", "rx", "cs");
+ connect("self", "tx_cs", "tx", "cs");
+
+ // FIXME: the code should query the FPGA to retrieve the number of channels and such
+ d_ntx_chan = 2;
+ d_nrx_chan = 2;
+}
+
+usrp_usb_interface::~usrp_usb_interface()
+{
+
+}
+
+void
+usrp_usb_interface::initial_transition()
+{
+
+}
+
+/*!
+ * \brief Handles all incoming signals to the block from the lowest m-blocks
+ * which read/write to the bus, or the higher m-block which is the USRP server.
+ */
+void
+usrp_usb_interface::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal(); // the "name" of the message
+ pmt_t port_id = msg->port_id(); // which port it came in on
+ pmt_t data = msg->data();
+ pmt_t invocation_handle;
+
+ if (pmt_eq(event, s_shutdown)) // ignore (for now)
+ return;
+
+ //------------- CONTROL / STATUS -------------//
+ if (pmt_eq(port_id, d_cs->port_symbol())) {
+
+ //------------ OPEN --------------//
+ if (pmt_eq(event, s_cmd_usrp_open)){
+ handle_cmd_open(data);
+ return;
+ }
+ //----------- CLOSE -------------//
+ else if (pmt_eq(event, s_cmd_usrp_close)) {
+ handle_cmd_close(data);
+ return;
+ }
+ //---------- NTX CHAN ----------//
+ else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ d_cs->send(s_response_usrp_ntx_chan,
+ pmt_list2(invocation_handle,
+ pmt_from_long(d_ntx_chan)));
+ return;
+ }
+ //---------- NRX CHAN ----------//
+ else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ d_cs->send(s_response_usrp_nrx_chan,
+ pmt_list2(invocation_handle,
+ pmt_from_long(d_nrx_chan)));
+ return;
+ }
+ //------------ WRITE -----------//
+ else if(pmt_eq(event, s_cmd_usrp_write)) {
+ handle_cmd_write(data);
+ return;
+ }
+ //-------- START READING --------//
+ else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
+ handle_cmd_start_reading(data);
+ return;
+ }
+ //-------- STOP READING --------//
+ else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
+ handle_cmd_stop_reading(data);
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ //---------------- RX ------------------//
+ if (pmt_eq(port_id, d_rx_cs->port_symbol())) {
+
+ // Relay reads back up
+ if(pmt_eq(event, s_response_usrp_rx_read)) {
+ d_cs->send(s_response_usrp_read, data);
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ //---------------- TX ------------------//
+ if (pmt_eq(port_id, d_tx_cs->port_symbol())) {
+
+ if(pmt_eq(event, s_response_usrp_tx_write)) {
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ d_cs->send(s_response_usrp_write,
+ pmt_list3(invocation_handle,
+ status,
+ channel));
+
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ unhandled:
+ std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * open a USB connection to the USRP (cmd-usrp-open).
+ *
+ * The \p data parameter is a PMT list, where the elements are an invocation
+ * handle and the USRP number.
+ */
+void
+usrp_usb_interface::handle_cmd_open(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long which_usrp = pmt_to_long(pmt_nth(1, data));
+ pmt_t reply_data;
+
+ if(d_fake_usrp) {
+ d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
+ return;
+ }
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
+
+ // Open up a standard RX and TX for communication with the USRP
+
+ d_utx = usrp_standard_tx::make(which_usrp,
+ d_interp_tx,
+ 1, // 1 channel
+ -1, // mux
+ 4096, // USB block size
+ 16, // nblocks for async transfers
+ d_rbf
+ );
+
+ if(d_utx==0) {
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ // Perform TX daughterboard tuning
+ double target_freq;
+ unsigned int mux;
+ int tgain, rgain;
+ float input_rate;
+ bool ok;
+ usrp_tune_result r;
+
+ // Cast to usrp_basic and then detect daughterboards
+ d_ub_tx = d_utx;
+ usrp_subdev_spec tspec = pick_tx_subdevice();
+ db_base_sptr tsubdev = d_ub_tx->selected_subdev(tspec);
+
+ // Set the TX mux value
+ mux = d_utx->determine_tx_mux_value(tspec);
+ d_utx->set_mux(mux);
+
+ // Set the TX gain and determine rate
+ tgain = tsubdev->gain_max();
+ tsubdev->set_gain(tgain);
+ input_rate = d_ub_tx->converter_rate() / d_utx->interp_rate();
+
+ // Perform the actual tuning, if no frequency specified then pick
+ if(d_rf_freq==-1)
+ target_freq = tsubdev->freq_min()+((tsubdev->freq_max()-tsubdev->freq_min())/2.0);
+ else
+ target_freq = d_rf_freq;
+ ok = d_utx->tune(tsubdev->which(), tsubdev, target_freq, &r);
+ tsubdev->set_enable(true);
+
+ if(verbose) {
+ printf("TX Subdevice name is %s\n", tsubdev->name().c_str());
+ printf("TX Subdevice freq range: (%g, %g)\n",
+ tsubdev->freq_min(), tsubdev->freq_max());
+ printf("mux: %#08x\n", mux);
+ printf("target_freq: %f\n", target_freq);
+ printf("ok: %s\n", ok ? "true" : "false");
+ printf("gain: %d\n", tgain);
+ printf("r.baseband_freq: %f\n", r.baseband_freq);
+ printf("r.dxc_freq: %f\n", r.dxc_freq);
+ printf("r.residual_freq: %f\n", r.residual_freq);
+ printf("r.inverted: %d\n", r.inverted);
+ }
+
+ if(!ok) {
+ std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ d_utx->start();
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
+
+ d_urx =
+ usrp_standard_rx::make (which_usrp,
+ d_decim_rx,
+ 1, // nchan
+ -1, // mux
+ 0, // set blank mode to start
+ 4096, // USB block size
+ 16, // number of blocks for async transfers
+ d_rbf);
+
+ if(!d_urx) {
+ if (verbose)
+ std::cout << "[usrp_server] Failed to open RX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ // Cast to usrp_basic and then detect daughterboards
+ d_ub_rx = d_urx;
+ usrp_subdev_spec rspec = pick_rx_subdevice();
+ db_base_sptr rsubdev = d_ub_rx->selected_subdev(rspec);
+
+ // Set the RX mux value
+ mux = d_urx->determine_rx_mux_value(rspec);
+ d_urx->set_mux(mux);
+
+ // Set the RX gain and determine rate
+ rgain = rsubdev->gain_max()/2.0;
+ rsubdev->set_gain(rgain);
+ input_rate = d_ub_rx->converter_rate() / d_urx->decim_rate();
+
+ ok = d_urx->tune(rsubdev->which(), rsubdev, target_freq, &r);
+ rsubdev->set_enable(true);
+
+ if(verbose) {
+ printf("RX Subdevice name is %s\n", rsubdev->name().c_str());
+ printf("RX Subdevice freq range: (%g, %g)\n",
+ rsubdev->freq_min(), rsubdev->freq_max());
+ printf("mux: %#08x\n", mux);
+ printf("target_freq: %f\n", target_freq);
+ printf("ok: %s\n", ok ? "true" : "false");
+ printf("gain: %d\n", rgain);
+ printf("r.baseband_freq: %f\n", r.baseband_freq);
+ printf("r.dxc_freq: %f\n", r.dxc_freq);
+ printf("r.residual_freq: %f\n", r.residual_freq);
+ printf("r.inverted: %d\n", r.inverted);
+ }
+
+ if(!ok) {
+ std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on RX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
+
+// d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
+// d_utx->_write_oe(0, 0xffff, 0xffff);
+// d_urx->_write_oe(0, 0xffff, 0xffff);
+// d_utx->_write_oe(1, 0xffff, 0xffff);
+// d_urx->_write_oe(1, 0xffff, 0xffff);
+
+ d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * write data to the USB bus (cmd-usrp-write).
+ *
+ * The \p data parameter is a PMT list containing 3 mandatory elements in the
+ * following order: an invocation handle, channel, and a uniform vector
+ * representation of the packets.
+ */
+void
+usrp_usb_interface::handle_cmd_write(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t channel = pmt_nth(1, data);
+ pmt_t pkts = pmt_nth(2, data);
+
+ pmt_t tx_handle = pmt_make_any(d_utx);
+
+ d_tx_cs->send(s_cmd_usrp_tx_write,
+ pmt_list4(invocation_handle,
+ channel,
+ pkts,
+ tx_handle));
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * start reading data from the USB bus (cmd-usrp-start-reading).
+ *
+ * The \p data parameter is a PMT list with a single element: an invocation
+ * handle which can be returned with the response.
+ */
+void
+usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ if(verbose)
+ std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
+
+ if(!d_fake_usrp)
+ d_urx->start();
+
+ pmt_t rx_handle = pmt_make_any(d_urx);
+
+ d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
+
+ d_rx_reading = true;
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * stop reading data from the USB bus (cmd-usrp-stop-reading).
+ *
+ * The \p data parameter is a PMT list with a single element: an invocation
+ * handle which can be returned with the response.
+ */
+void
+usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ if(!d_fake_usrp) {
+ if(verbose)
+ std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
+ usrp_rx_stop = true;
+
+ // Used to allow a read() being called by a lower layer to complete before
+ // stopping, else there can be partial data left on the bus and can generate
+ // errors.
+ while(usrp_rx_stop) {usleep(1);}
+ d_urx->stop();
+ }
+ else {
+ if(verbose)
+ std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
+ usrp_rx_stop_stub = true; // extern to communicate with stub to wait
+ }
+
+ d_rx_reading = false;
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * close the USB connection to the USRP.
+ *
+ * The \p data parameter is a PMT list with a single element: an invocation
+ * handle which can be returned with the response.
+ */
+void
+usrp_usb_interface::handle_cmd_close(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ if(d_rx_reading)
+ handle_cmd_stop_reading(PMT_NIL);
+
+ if(d_fake_usrp) {
+ d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
+ return;
+ }
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
+
+ d_utx.reset();
+ d_urx.reset();
+
+ d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
+
+ // FIXME This seems like a _very_ strange place to be calling shutdown_all.
+ // That decision should be left to high-level code, not low-level code like this.
+ shutdown_all(PMT_T);
+}
+
+usrp_subdev_spec
+usrp_usb_interface::pick_rx_subdevice()
+{
+ int dbids[] = {
+ USRP_DBID_FLEX_400_RX,
+ USRP_DBID_FLEX_900_RX,
+ USRP_DBID_FLEX_1200_RX,
+ USRP_DBID_FLEX_2400_RX,
+ USRP_DBID_TV_RX,
+ USRP_DBID_TV_RX_REV_2,
+ USRP_DBID_DBS_RX,
+ USRP_DBID_BASIC_RX
+ };
+
+ std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
+ return pick_subdev(d_ub_rx, candidates);
+}
+
+usrp_subdev_spec
+usrp_usb_interface::pick_tx_subdevice()
+{
+ int dbids[] = {
+ USRP_DBID_FLEX_400_TX,
+ USRP_DBID_FLEX_900_TX,
+ USRP_DBID_FLEX_1200_TX,
+ USRP_DBID_FLEX_2400_TX,
+ USRP_DBID_BASIC_TX
+ };
+
+ std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
+ return pick_subdev(d_ub_tx, candidates);
+}
+
+usrp_subdev_spec
+usrp_usb_interface::pick_subdev(boost::shared_ptr<usrp_basic> d_usrp_basic, std::vector<int> candidates)
+{
+ int dbid0 = d_usrp_basic->selected_subdev(usrp_subdev_spec(0, 0))->dbid();
+ int dbid1 = d_usrp_basic->selected_subdev(usrp_subdev_spec(1, 0))->dbid();
+
+ for (int i = 0; i < candidates.size(); i++) {
+ int dbid = candidates[i];
+ if (dbid0 == dbid)
+ return usrp_subdev_spec(0, 0);
+ if (dbid1 == dbid)
+ return usrp_subdev_spec(1, 0);
+ }
+
+ if (dbid0 >= 0)
+ return usrp_subdev_spec(0, 0);
+ if (dbid1 >= 0)
+ return usrp_subdev_spec(1, 0);
+
+ throw std::runtime_error("No suitable daughterboard found!");
+}
+
+
+REGISTER_MBLOCK_CLASS(usrp_usb_interface);
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_USRP_USB_INTERFACE_H
+#define INCLUDED_USRP_USB_INTERFACE_H
+
+#include <mblock/mblock.h>
+#include <vector>
+#include "usrp_standard.h"
+
+/*!
+ * \brief Implements the low level usb interface to the USRP
+ */
+class usrp_usb_interface : public mb_mblock
+{
+ public:
+
+ usrp_standard_tx_sptr d_utx;
+ usrp_standard_rx_sptr d_urx;
+
+ boost::shared_ptr<usrp_basic> d_ub_tx;
+ boost::shared_ptr<usrp_basic> d_ub_rx;
+
+ mb_port_sptr d_cs;
+ mb_port_sptr d_rx_cs;
+ mb_port_sptr d_tx_cs;
+
+ long d_ntx_chan;
+ long d_nrx_chan;
+
+ bool d_fake_usrp;
+
+ bool d_rx_reading;
+
+ long d_interp_tx;
+ long d_decim_rx;
+
+ double d_rf_freq;
+
+ std::string d_rbf;
+
+ public:
+ usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_usb_interface();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+ usrp_subdev_spec pick_rx_subdevice();
+ usrp_subdev_spec pick_tx_subdevice();
+ usrp_subdev_spec pick_subdev(boost::shared_ptr<usrp_basic> d_usrp_basic, std::vector<int> candidates);
+
+ private:
+ void handle_cmd_open(pmt_t data);
+ void handle_cmd_close(pmt_t data);
+ void handle_cmd_write(pmt_t data);
+ void handle_cmd_start_reading(pmt_t data);
+ void handle_cmd_stop_reading(pmt_t data);
+
+};
+
+
+#endif /* INCLUDED_USRP_USB_INTERFACE_H */
+++ /dev/null
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: usrp-inband
-Description: USRP C++ Interface with in-band signaling
-Requires: usrp pmt mblock
-Version: @VERSION@
-Libs: -L${libdir} -lusrp-inband
-Cflags: -I${includedir}