From: jcorgan Date: Thu, 9 Jul 2009 02:55:51 +0000 (+0000) Subject: Merged r11377:11390 from jcorgan/usrp-headers in to trunk. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=c276a4ffee9314d2528166547abfd2c09d29713f;p=debian%2Fgnuradio Merged r11377:11390 from jcorgan/usrp-headers in to trunk. * Public USRP(1) header files are now in their own source directory and install into $(includedir)/usrp. This was done to avoid name clashes in the top-level include directory. Only users who are developing directly to libusrp in C++ are affected; the GNU Radio C++ and Python APIs are unchanged. The simple change required by this update is to change: #include to #include ...in your source code. * Removed usrp-inband code from tree (put into limbo directory.) This code has become unmaintained and has started to suffer from bitrot. A checkpoint tag has been made for anyone still needing to use it: http://gnuradio.org/svn/gnuradio/tags/checkpoints/trunk-20090708-pre-usrp-reorg The plan during the 3.2->3.3 development cycle is to replace the functions done by the in-band code with extensions to the existing gr-usrp blocks using the new message passing architecture. The USRP hardware FPGA code that provided the inband interface has not been removed; however, it too has become unmaintained and will likely be rewritten/replaced during the 3.3 timeframe. The trunk passes distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11394 221aa14e-8319-0410-a670-987f0aec2ac5 --- diff --git a/Makefile.common b/Makefile.common index c0625c7c..14cbe269 100644 --- a/Makefile.common +++ b/Makefile.common @@ -81,10 +81,6 @@ GRUEL_LA = @gruel_LA@ 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@ diff --git a/config/grc_usrp.m4 b/config/grc_usrp.m4 index 3b8bb28f..14c64608 100644 --- a/config/grc_usrp.m4 +++ b/config/grc_usrp.m4 @@ -20,12 +20,10 @@ dnl Boston, MA 02110-1301, USA. 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. @@ -46,9 +44,6 @@ AC_DEFUN([GRC_USRP],[ 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.])]) @@ -57,20 +52,14 @@ AC_DEFUN([GRC_USRP],[ 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*) @@ -85,20 +74,18 @@ AC_DEFUN([GRC_USRP],[ 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 \ diff --git a/gnuradio-core/src/lib/io/gri_wavfile.cc b/gnuradio-core/src/lib/io/gri_wavfile.cc index c1a2b7c7..b8375edc 100644 --- a/gnuradio-core/src/lib/io/gri_wavfile.cc +++ b/gnuradio-core/src/lib/io/gri_wavfile.cc @@ -32,8 +32,7 @@ // 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 diff --git a/gr-usrp/apps/Makefile.am b/gr-usrp/apps/Makefile.am index 824a4897..92938061 100644 --- a/gr-usrp/apps/Makefile.am +++ b/gr-usrp/apps/Makefile.am @@ -24,9 +24,7 @@ include $(top_srcdir)/Makefile.common # For compiling within the GNU Radio build tree AM_CPPFLAGS=$(STD_DEFINES_AND_INCLUDES) \ -I$(top_srcdir)/gr-usrp/src \ - -I$(top_srcdir)/usrp/host/lib/legacy \ - -I\${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 diff --git a/gr-usrp/src/usrp_base.cc b/gr-usrp/src/usrp_base.cc index a4cf64ed..1d632a56 100644 --- a/gr-usrp/src/usrp_base.cc +++ b/gr-usrp/src/usrp_base.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2008 Free Software Foundation, Inc. + * Copyright 2004,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,7 +23,7 @@ #include #endif #include -#include +#include class truth_table_element_t { diff --git a/gr-usrp/src/usrp_base.h b/gr-usrp/src/usrp_base.h index a914159e..7947723f 100644 --- a/gr-usrp/src/usrp_base.h +++ b/gr-usrp/src/usrp_base.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2008 Free Software Foundation, Inc. + * Copyright 2004,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,8 +24,8 @@ #include #include #include -#include -#include +#include +#include class usrp_basic; diff --git a/gr-usrp/src/usrp_sink_base.cc b/gr-usrp/src/usrp_sink_base.cc index cb65e02c..635d9345 100644 --- a/gr-usrp/src/usrp_sink_base.cc +++ b/gr-usrp/src/usrp_sink_base.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2008 Free Software Foundation, Inc. + * Copyright 2004,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff --git a/gr-usrp/src/usrp_sink_base.h b/gr-usrp/src/usrp_sink_base.h index b27813a4..8d573af1 100644 --- a/gr-usrp/src/usrp_sink_base.h +++ b/gr-usrp/src/usrp_sink_base.h @@ -1,7 +1,7 @@ /* -*- 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 * @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include class usrp_standard_tx; diff --git a/gr-usrp/src/usrp_sink_c.cc b/gr-usrp/src/usrp_sink_c.cc index 363a113f..40750b47 100644 --- a/gr-usrp/src/usrp_sink_c.cc +++ b/gr-usrp/src/usrp_sink_c.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2004,2006,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include usrp_sink_c_sptr usrp_make_sink_c (int which_board, diff --git a/gr-usrp/src/usrp_sink_s.cc b/gr-usrp/src/usrp_sink_s.cc index adbf3acb..1f51da24 100644 --- a/gr-usrp/src/usrp_sink_s.cc +++ b/gr-usrp/src/usrp_sink_s.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2004,2006,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include usrp_sink_s_sptr usrp_make_sink_s (int which_board, diff --git a/gr-usrp/src/usrp_source_base.cc b/gr-usrp/src/usrp_source_base.cc index 99efbcdd..85bd9171 100644 --- a/gr-usrp/src/usrp_source_base.cc +++ b/gr-usrp/src/usrp_source_base.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2008 Free Software Foundation, Inc. + * Copyright 2004,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff --git a/gr-usrp/src/usrp_source_base.h b/gr-usrp/src/usrp_source_base.h index e1d091d8..4def48e2 100644 --- a/gr-usrp/src/usrp_source_base.h +++ b/gr-usrp/src/usrp_source_base.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2008 Free Software Foundation, Inc. + * Copyright 2004,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -25,8 +25,8 @@ #include #include -#include -#include +#include +#include class usrp_standard_rx; diff --git a/gr-usrp/src/usrp_source_c.cc b/gr-usrp/src/usrp_source_c.cc index 71ca1e0d..26d95dc1 100644 --- a/gr-usrp/src/usrp_source_c.cc +++ b/gr-usrp/src/usrp_source_c.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2004,2006,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include static const int NBASIC_SAMPLES_PER_ITEM = 2; // I & Q diff --git a/gr-usrp/src/usrp_source_s.cc b/gr-usrp/src/usrp_source_s.cc index f2038459..88b8495d 100644 --- a/gr-usrp/src/usrp_source_s.cc +++ b/gr-usrp/src/usrp_source_s.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2004,2006,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include static const int NBASIC_SAMPLES_PER_ITEM = 1; diff --git a/gr-usrp/src/usrp_standard.i b/gr-usrp/src/usrp_standard.i index 7d32cdf8..61053bb3 100644 --- a/gr-usrp/src/usrp_standard.i +++ b/gr-usrp/src/usrp_standard.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2008 Free Software Foundation, Inc. + * Copyright 2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,13 +23,13 @@ // FIXME: move to usrp/usrpm component %{ -#include +#include #include -#include +#include %} %include -%include +%include %constant int FPGA_MODE_NORMAL = usrp_standard_rx::FPGA_MODE_NORMAL; %constant int FPGA_MODE_LOOPBACK = usrp_standard_rx::FPGA_MODE_LOOPBACK; diff --git a/gr-usrp/src/usrp_swig.i b/gr-usrp/src/usrp_swig.i index f5841985..2a47877c 100644 --- a/gr-usrp/src/usrp_swig.i +++ b/gr-usrp/src/usrp_swig.i @@ -26,8 +26,8 @@ #include %} -%include -%include +%include +%include %include %include %include "usrp_standard.i" diff --git a/usrp/Makefile.am b/usrp/Makefile.am index 6f5abbd5..c3e529da 100644 --- a/usrp/Makefile.am +++ b/usrp/Makefile.am @@ -21,7 +21,6 @@ EXTRA_DIST = \ usrp.pc.in \ - usrp-inband.pc.in \ usrp.iss.in \ usrp.inf @@ -29,6 +28,4 @@ SUBDIRS = host firmware fpga doc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = \ - usrp.pc \ - usrp-inband.pc - + usrp.pc diff --git a/usrp/firmware/include/Makefile.am b/usrp/firmware/include/Makefile.am index 97ca60bf..e17726c0 100644 --- a/usrp/firmware/include/Makefile.am +++ b/usrp/firmware/include/Makefile.am @@ -19,7 +19,9 @@ # Boston, MA 02110-1301, USA. # -include_HEADERS = \ +usrpincludedir = $(includedir)/usrp + +usrpinclude_HEADERS = \ usrp_i2c_addr.h \ usrp_spi_defs.h \ fpga_regs_common.h \ diff --git a/usrp/host/Makefile.am b/usrp/host/Makefile.am index 514b835a..aa94fbd6 100644 --- a/usrp/host/Makefile.am +++ b/usrp/host/Makefile.am @@ -19,7 +19,7 @@ # Boston, MA 02110-1301, USA. # -SUBDIRS = misc lib apps apps-inband +SUBDIRS = misc lib include apps if PYTHON SUBDIRS += swig diff --git a/usrp/host/apps-inband/Makefile.am b/usrp/host/apps-inband/Makefile.am deleted file mode 100644 index 0a44d811..00000000 --- a/usrp/host/apps-inband/Makefile.am +++ /dev/null @@ -1,77 +0,0 @@ -# -# 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) diff --git a/usrp/host/apps-inband/read_packets.cc b/usrp/host/apps-inband/read_packets.cc deleted file mode 100644 index 24a1e88b..00000000 --- a/usrp/host/apps-inband/read_packets.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include - -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 \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(); - -} diff --git a/usrp/host/apps-inband/test_usrp_inband_2rx.cc b/usrp/host/apps-inband/test_usrp_inband_2rx.cc deleted file mode 100644 index c210f196..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_2rx.cc +++ /dev/null @@ -1,371 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include // QA only -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include the symbols needed for communication with USRP server -#include -#include -#include -#include - -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); - -} diff --git a/usrp/host/apps-inband/test_usrp_inband_2tx.cc b/usrp/host/apps-inband/test_usrp_inband_2tx.cc deleted file mode 100644 index 11a1a491..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_2tx.cc +++ /dev/null @@ -1,430 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include // QA only -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -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 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); -} diff --git a/usrp/host/apps-inband/test_usrp_inband_overrun.cc b/usrp/host/apps-inband/test_usrp_inband_overrun.cc deleted file mode 100644 index cd0fa525..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_overrun.cc +++ /dev/null @@ -1,375 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include the symbols needed for communication with USRP server -#include -#include -#include -#include - -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 <= 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); -} diff --git a/usrp/host/apps-inband/test_usrp_inband_ping.cc b/usrp/host/apps-inband/test_usrp_inband_ping.cc deleted file mode 100644 index d779c9a6..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_ping.cc +++ /dev/null @@ -1,374 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include the symbols needed for communication with USRP server -#include -#include -#include -#include -#include - -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); diff --git a/usrp/host/apps-inband/test_usrp_inband_registers.cc b/usrp/host/apps-inband/test_usrp_inband_registers.cc deleted file mode 100644 index d9bd2db1..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_registers.cc +++ /dev/null @@ -1,435 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include - -// Include the symbols needed for communication with USRP server -#include -#include -#include -#include -#include - -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); diff --git a/usrp/host/apps-inband/test_usrp_inband_rx.cc b/usrp/host/apps-inband/test_usrp_inband_rx.cc deleted file mode 100644 index 4f21e4af..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_rx.cc +++ /dev/null @@ -1,362 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include the symbols needed for communication with USRP server -#include -#include -#include -#include - -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); - -} diff --git a/usrp/host/apps-inband/test_usrp_inband_timestamps.cc b/usrp/host/apps-inband/test_usrp_inband_timestamps.cc deleted file mode 100644 index 3b874d1a..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_timestamps.cc +++ /dev/null @@ -1,506 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#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 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); -} diff --git a/usrp/host/apps-inband/test_usrp_inband_tx.cc b/usrp/host/apps-inband/test_usrp_inband_tx.cc deleted file mode 100644 index 9f294e77..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_tx.cc +++ /dev/null @@ -1,411 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -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 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); -} diff --git a/usrp/host/apps-inband/test_usrp_inband_underrun.cc b/usrp/host/apps-inband/test_usrp_inband_underrun.cc deleted file mode 100644 index 11babb04..00000000 --- a/usrp/host/apps-inband/test_usrp_inband_underrun.cc +++ /dev/null @@ -1,674 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include the symbols needed for communication with USRP server -#include -#include -#include -#include -#include - -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 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 <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); diff --git a/usrp/host/apps-inband/ui_nco.h b/usrp/host/apps-inband/ui_nco.h deleted file mode 100644 index e6d7814a..00000000 --- a/usrp/host/apps-inband/ui_nco.h +++ /dev/null @@ -1,202 +0,0 @@ -/* -*- 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 -#include -#include - -#include -typedef std::complex gr_complex; - - -/*! - * \brief base class template for Numerically Controlled Oscillator (NCO) - */ - - -//FIXME Eventually generalize this to fixed point - -template -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 -void -ui_nco::sincos (float *sinx, float *cosx) const -{ - ui_sincosf (phase, sinx, cosx); -} - -template -void -ui_nco::sin (float *output, int noutput_items, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = (float)(sin () * ampl); - step (); - } -} - -template -void -ui_nco::cos (float *output, int noutput_items, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = (float)(cos () * ampl); - step (); - } -} - -template -void -ui_nco::sin (short *output, int noutput_items, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = (short)(sin() * ampl); - step (); - } -} - -template -void -ui_nco::cos (short *output, int noutput_items, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = (short)(cos () * ampl); - step (); - } -} - -template -void -ui_nco::sin (int *output, int noutput_items, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = (int)(sin () * ampl); - step (); - } -} - -template -void -ui_nco::cos (int *output, int noutput_items, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = (int)(cos () * ampl); - step (); - } -} - -template -void -ui_nco::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 */ - diff --git a/usrp/host/apps-inband/ui_sincos.c b/usrp/host/apps-inband/ui_sincos.c deleted file mode 100644 index 27841f01..00000000 --- a/usrp/host/apps-inband/ui_sincos.c +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define _GNU_SOURCE // ask for GNU extensions if available - -#include "ui_sincos.h" -#include - -// ---------------------------------------------------------------- - -#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 diff --git a/usrp/host/apps-inband/ui_sincos.h b/usrp/host/apps-inband/ui_sincos.h deleted file mode 100644 index d2d6e4b7..00000000 --- a/usrp/host/apps-inband/ui_sincos.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- 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 */ diff --git a/usrp/host/apps/test_usrp_standard_rx.cc b/usrp/host/apps/test_usrp_standard_rx.cc index 4a47daa9..f6897ed2 100644 --- a/usrp/host/apps/test_usrp_standard_rx.cc +++ b/usrp/host/apps/test_usrp_standard_rx.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2006,2008 Free Software Foundation, Inc. + * Copyright 2003,2006,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -33,8 +33,8 @@ #include #include #include "time_stuff.h" -#include "usrp_standard.h" -#include "usrp_bytesex.h" +#include +#include #include "fpga_regs_common.h" #include "fpga_regs_standard.h" diff --git a/usrp/host/apps/test_usrp_standard_tx.cc b/usrp/host/apps/test_usrp_standard_tx.cc index 3cc20c44..3f881737 100644 --- a/usrp/host/apps/test_usrp_standard_tx.cc +++ b/usrp/host/apps/test_usrp_standard_tx.cc @@ -34,8 +34,8 @@ #include #include #include "time_stuff.h" -#include "usrp_standard.h" -#include "usrp_bytesex.h" +#include +#include #include enum { diff --git a/usrp/host/apps/usrp_cal_dc_offset.cc b/usrp/host/apps/usrp_cal_dc_offset.cc index 5ebac12a..22d427df 100644 --- a/usrp/host/apps/usrp_cal_dc_offset.cc +++ b/usrp/host/apps/usrp_cal_dc_offset.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005,2008 Free Software Foundation, Inc. + * Copyright 2005,2008,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -33,9 +33,9 @@ #include #include #include -#include "usrp_local_sighandler.h" -#include "usrp_standard.h" -#include "usrp_bytesex.h" +#include +#include +#include char *prog_name; diff --git a/usrp/host/apps/usrper.cc b/usrp/host/apps/usrper.cc index 3740022e..fe8ff90d 100644 --- a/usrp/host/apps/usrper.cc +++ b/usrp/host/apps/usrper.cc @@ -2,7 +2,7 @@ /* * 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 @@ -28,7 +28,7 @@ #include #include -#include "usrp_prims.h" +#include "usrp/usrp_prims.h" #include "usrp_spi_defs.h" #include diff --git a/usrp/host/include/Makefile.am b/usrp/host/include/Makefile.am new file mode 100644 index 00000000..5de5fe58 --- /dev/null +++ b/usrp/host/include/Makefile.am @@ -0,0 +1,23 @@ +# +# 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 + diff --git a/usrp/host/include/usrp/Makefile.am b/usrp/host/include/usrp/Makefile.am new file mode 100644 index 00000000..91d43923 --- /dev/null +++ b/usrp/host/include/usrp/Makefile.am @@ -0,0 +1,49 @@ +# +# 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 diff --git a/usrp/host/include/usrp/db_base.h b/usrp/host/include/usrp/db_base.h new file mode 100644 index 00000000..35470891 --- /dev/null +++ b/usrp/host/include/usrp/db_base.h @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. +// + +#ifndef INCLUDED_DB_BASE_H +#define INCLUDED_DB_BASE_H + +#include +#include +#include +#include + +class db_base; +typedef boost::shared_ptr db_base_sptr; + +class usrp_basic; +typedef boost::shared_ptr usrp_basic_sptr; + +struct freq_result_t +{ + bool ok; + double baseband_freq; +}; + +/******************************************************************************/ + +/*! + * \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, 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 */ diff --git a/usrp/host/include/usrp/db_base.i b/usrp/host/include/usrp/db_base.i new file mode 100644 index 00000000..78c72b8c --- /dev/null +++ b/usrp/host/include/usrp/db_base.i @@ -0,0 +1,102 @@ +/* -*- 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 +%} + +%include + +class usrp_tune_result +{ +public: + usrp_tune_result(double baseband=0, double dxc=0, + double residual=0, bool inv=0); + ~usrp_tune_result(); + + double baseband_freq; + double dxc_freq; + double residual_freq; + bool inverted; +}; + +struct freq_result_t +{ + bool ok; + double baseband_freq; +}; + +class db_base +{ + private: + db_base(boost::shared_ptr usrp, int which); + + public: + virtual ~db_base(); + + int dbid(); + std::string name(); + std::string side_and_name(); + int which() { return d_which; } + + bool bypass_adc_buffers(bool bypass); + bool set_atr_mask(int v); + bool set_atr_txval(int v); + bool set_atr_rxval(int v); + bool set_atr_tx_delay(int v); + bool set_atr_rx_delay(int v); + bool set_lo_offset(double offset); + double lo_offset() { return d_lo_offset; } + + virtual float gain_min() = 0; + virtual float gain_max() = 0; + virtual float gain_db_per_step() = 0; + virtual double freq_min() = 0; + virtual double freq_max() = 0; + virtual struct freq_result_t set_freq(double target_freq) = 0; + virtual bool set_gain(float gain) = 0; + virtual bool is_quadrature() = 0; + virtual bool i_and_q_swapped(); + virtual bool spectrum_inverted(); + virtual bool set_enable(bool on); + virtual bool set_auto_tr(bool on); + virtual bool select_rx_antenna(int which_antenna); + virtual bool select_rx_antenna(const std::string &antenna); + 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_sptr; +%template(db_base_sptr) boost::shared_ptr; +%template(db_base_sptr_vector) std::vector; +%template(db_base_sptr_vector_vector) std::vector >; + +// Set better class name in Python +// Enable freq_range and gain_range from public methods of class not implemented in C++ +// And create a dummy wrapper for backwards compatability with some of the example code +%pythoncode %{ + db_base_sptr.__repr__ = lambda self: "" % (self.name(),) + db_base_sptr.freq_range = lambda self: (self.freq_min(), self.freq_max(), 1) + db_base_sptr.gain_range = lambda self: (self.gain_min(), self.gain_max(), self.gain_db_per_step()) + +%} diff --git a/usrp/host/include/usrp/db_basic.h b/usrp/host/include/usrp/db_basic.h new file mode 100644 index 00000000..7f81733f --- /dev/null +++ b/usrp/host/include/usrp/db_basic.h @@ -0,0 +1,99 @@ +/* -*- 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 + + +/******************************************************************************/ + + +class db_basic_tx : public db_base +{ +public: + db_basic_tx(usrp_basic_sptr usrp, int which); + ~db_basic_tx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + bool set_gain(float gain); + bool is_quadrature(); +}; + + +/******************************************************************************/ + + +class db_basic_rx : public db_base +{ + public: + db_basic_rx(usrp_basic_sptr usrp, int which, int subdev); + ~db_basic_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + bool set_gain(float gain); + bool is_quadrature(); + +private: + int d_subdev; +}; + + +/******************************************************************************/ + + +class db_lf_rx : public db_basic_rx +{ + public: + db_lf_rx(usrp_basic_sptr usrp, int which, int subdev); + ~db_lf_rx(); + + double freq_min(); + double freq_max(); +}; + + +/******************************************************************************/ + + +class db_lf_tx : public db_basic_tx +{ + public: + db_lf_tx(usrp_basic_sptr usrp, int which); + ~db_lf_tx(); + + double freq_min(); + double freq_max(); +}; + + +#endif diff --git a/usrp/host/include/usrp/db_dbs_rx.h b/usrp/host/include/usrp/db_dbs_rx.h new file mode 100644 index 00000000..7f869637 --- /dev/null +++ b/usrp/host/include/usrp/db_dbs_rx.h @@ -0,0 +1,83 @@ +/* -*- 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 +#include + +#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 &vals); + std::vector _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 diff --git a/usrp/host/include/usrp/db_dtt754.h b/usrp/host/include/usrp/db_dtt754.h new file mode 100644 index 00000000..4fb95282 --- /dev/null +++ b/usrp/host/include/usrp/db_dtt754.h @@ -0,0 +1,57 @@ +/* -*- 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 +#include + +class db_dtt754 : public db_base +{ +public: + db_dtt754(usrp_basic_sptr usrp, int which); + ~db_dtt754(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + + bool is_quadrature(); + bool spectrum_inverted(); + 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 diff --git a/usrp/host/include/usrp/db_dtt768.h b/usrp/host/include/usrp/db_dtt768.h new file mode 100644 index 00000000..78e157e7 --- /dev/null +++ b/usrp/host/include/usrp/db_dtt768.h @@ -0,0 +1,57 @@ +/* -*- 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 +#include + +class db_dtt768 : public db_base +{ +public: + db_dtt768(usrp_basic_sptr usrp, int which); + ~db_dtt768(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + + bool is_quadrature(); + bool spectrum_inverted(); + 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 diff --git a/usrp/host/include/usrp/db_flexrf.h b/usrp/host/include/usrp/db_flexrf.h new file mode 100644 index 00000000..3adad302 --- /dev/null +++ b/usrp/host/include/usrp/db_flexrf.h @@ -0,0 +1,355 @@ +/* -*- 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 +#include + +//debug_using_gui = true // Must be set to True or False +#define debug_using_gui false // Must be set to True or False + +class _AD4360_common; + +class flexrf_base : public db_base +{ +public: + flexrf_base(usrp_basic_sptr usrp, int which, int _power_on=0); + ~flexrf_base(); + + struct freq_result_t set_freq(double freq); + + bool is_quadrature(); + double freq_min(); + double freq_max(); + +protected: + void _write_all(int R, int control, int N); + void _write_control(int control); + void _write_R(int R); + void _write_N(int N); + void _write_it(int v); + bool _lock_detect(); + + virtual bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); + int _compute_control_reg(); + int _refclk_divisor(); + double _refclk_freq(); + + bool _set_pga(float pga_gain); + + int power_on() { return d_power_on; } + int power_off() { return 0; } + + bool d_first; + int d_spi_format; + int d_spi_enable; + int d_power_on; + int d_PD; + + _AD4360_common *d_common; +}; + +// ---------------------------------------------------------------- + +class flexrf_base_tx : public flexrf_base +{ +protected: + void shutdown(); + +public: + flexrf_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~flexrf_base_tx(); + + // All RFX tx d'boards have fixed gain + float gain_min(); + float gain_max(); + float gain_db_per_step(); + + bool set_auto_tr(bool on); + bool set_enable(bool on); + bool set_gain(float gain); +}; + +class flexrf_base_rx : public flexrf_base +{ +protected: + void shutdown(); + +public: + flexrf_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~flexrf_base_rx(); + + bool set_auto_tr(bool on); + bool select_rx_antenna(int which_antenna); + bool select_rx_antenna(const std::string &which_antenna); + bool set_gain(float gain); + +}; + +// ---------------------------------------------------------------- + + +class _AD4360_common +{ +public: + _AD4360_common(); + virtual ~_AD4360_common(); + + virtual double freq_min() = 0; + virtual double freq_max() = 0; + + bool _compute_regs(double refclk_freq, double freq, int &retR, + int &retcontrol, int &retN, double &retfreq); + int _compute_control_reg(); + virtual int _refclk_divisor(); + int _prescaler(); + + void R_DIV(int div) { d_R_DIV = div; } + +protected: + int d_R_RSV, d_BSC, d_TEST, d_LDP, d_ABP, d_N_RSV, d_PL, d_MTLD; + int d_CPG, d_CP3S, d_PDP, d_MUXOUT, d_CR, d_PC; + + // FIXME: d_PD might cause conflict from flexrf_base + int d_A_DIV, d_B_DIV, d_R_DIV, d_P, d_PD, d_CP2, d_CP1, d_DIVSEL; + int d_DIV2, d_CPGAIN, d_freq_mult; + +}; + +//---------------------------------------------------------------------- + +class _2400_common : public _AD4360_common +{ + public: + _2400_common(); + ~_2400_common() {} + + double freq_min(); + double freq_max(); +}; + +//---------------------------------------------------------------------- + +class _1200_common : public _AD4360_common +{ +public: + _1200_common(); + ~_1200_common() {} + + double freq_min(); + double freq_max(); +}; + +//------------------------------------------------------------------------- + +class _1800_common : public _AD4360_common +{ + public: + _1800_common(); + ~_1800_common() {} + + double freq_min(); + double freq_max(); +}; + +//------------------------------------------------------------------------- + +class _900_common : public _AD4360_common +{ +public: + _900_common(); + ~_900_common() {} + + double freq_min(); + double freq_max(); +}; + +//------------------------------------------------------------------------- + +class _400_common : public _AD4360_common +{ +public: + _400_common(); + ~_400_common() {} + + double freq_min(); + double freq_max(); +}; + +class _400_tx : public _400_common +{ +public: + _400_tx(); + ~_400_tx() {} +}; + +class _400_rx : public _400_common +{ +public: + _400_rx(); + ~_400_rx() {} +}; + +//------------------------------------------------------------ + +class db_flexrf_2400_tx : public flexrf_base_tx +{ + public: + db_flexrf_2400_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_2400_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_2400_rx : public flexrf_base_rx +{ +public: + db_flexrf_2400_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_2400_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +//------------------------------------------------------------ + +class db_flexrf_1200_tx : public flexrf_base_tx +{ +public: + db_flexrf_1200_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1200_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_1200_rx : public flexrf_base_rx +{ +public: + db_flexrf_1200_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1200_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +//------------------------------------------------------------ + +class db_flexrf_1800_tx : public flexrf_base_tx +{ + public: + db_flexrf_1800_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1800_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_1800_rx : public flexrf_base_rx +{ +public: + db_flexrf_1800_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_1800_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +//------------------------------------------------------------ + +class db_flexrf_900_tx : public flexrf_base_tx +{ + public: + db_flexrf_900_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_900_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_900_rx : public flexrf_base_rx +{ +public: + db_flexrf_900_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_900_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + + +//------------------------------------------------------------ + +class db_flexrf_400_tx : public flexrf_base_tx +{ + public: + db_flexrf_400_tx(usrp_basic_sptr usrp, int which); + ~db_flexrf_400_tx(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +class db_flexrf_400_rx : public flexrf_base_rx +{ +public: + db_flexrf_400_rx(usrp_basic_sptr usrp, int which); + ~db_flexrf_400_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +#endif diff --git a/usrp/host/include/usrp/db_flexrf_mimo.h b/usrp/host/include/usrp/db_flexrf_mimo.h new file mode 100644 index 00000000..771f3b27 --- /dev/null +++ b/usrp/host/include/usrp/db_flexrf_mimo.h @@ -0,0 +1,163 @@ +/* + * 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 + +class db_flexrf_2400_tx_mimo_a : public db_flexrf_2400_tx +{ + public: + db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_2400_rx_mimo_a : public db_flexrf_2400_rx +{ + public: + db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_2400_tx_mimo_b : public db_flexrf_2400_tx +{ + public: + db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_2400_rx_mimo_b : public db_flexrf_2400_rx +{ + public: + db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + + +class db_flexrf_1800_tx_mimo_a : public db_flexrf_1800_tx +{ + public: + db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1800_rx_mimo_a : public db_flexrf_1800_rx +{ + public: + db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1800_tx_mimo_b : public db_flexrf_1800_tx +{ + public: + db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1800_rx_mimo_b : public db_flexrf_1800_rx +{ + public: + db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_tx_mimo_a : public db_flexrf_1200_tx +{ + public: + db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_rx_mimo_a : public db_flexrf_1200_rx +{ + public: + db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_tx_mimo_b : public db_flexrf_1200_tx +{ + public: + db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_1200_rx_mimo_b : public db_flexrf_1200_rx +{ + public: + db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_tx_mimo_a : public db_flexrf_900_tx +{ + public: + db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_rx_mimo_a : public db_flexrf_900_rx +{ + public: + db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_tx_mimo_b : public db_flexrf_900_tx +{ + public: + db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_900_rx_mimo_b : public db_flexrf_900_rx +{ + public: + db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_tx_mimo_a : public db_flexrf_400_tx +{ + public: + db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_rx_mimo_a : public db_flexrf_400_rx +{ + public: + db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_tx_mimo_b : public db_flexrf_400_tx +{ + public: + db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; + +class db_flexrf_400_rx_mimo_b : public db_flexrf_400_rx +{ + public: + db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which); + int _refclk_divisor(); +}; diff --git a/usrp/host/include/usrp/db_tv_rx.h b/usrp/host/include/usrp/db_tv_rx.h new file mode 100644 index 00000000..ee3ed2bf --- /dev/null +++ b/usrp/host/include/usrp/db_tv_rx.h @@ -0,0 +1,56 @@ +/* -*- 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 + +class db_tv_rx : public db_base +{ +private: + void _set_rfagc(float gain); + void _set_ifagc(float gain); + void _set_pga(float pga_gain); + + int d_i2c_addr; + double d_first_IF, d_second_IF; + int d_reference_divisor; + bool d_fast_tuning; + bool d_inverted; + +public: + db_tv_rx(usrp_basic_sptr usrp, int which, + double first_IF, double second_IF); + ~db_tv_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + double freq_min(); + double freq_max(); + struct freq_result_t set_freq(double target_freq); + bool set_gain(float gain); + bool is_quadrature(); + bool spectrum_inverted(); +}; + +#endif diff --git a/usrp/host/include/usrp/db_xcvr2450.h b/usrp/host/include/usrp/db_xcvr2450.h new file mode 100644 index 00000000..305c60d0 --- /dev/null +++ b/usrp/host/include/usrp/db_xcvr2450.h @@ -0,0 +1,92 @@ +/* -*- 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 +#include + +class xcvr2450; +typedef boost::shared_ptr 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 diff --git a/usrp/host/include/usrp/usrp_basic.h b/usrp/host/include/usrp/usrp_basic.h new file mode 100644 index 00000000..fbbf49d5 --- /dev/null +++ b/usrp/host/include/usrp/usrp_basic.h @@ -0,0 +1,991 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +struct usb_dev_handle; +class fusb_devhandle; +class fusb_ephandle; + +enum txrx_t { + C_RX = 0, + C_TX = 1 +}; + +/*! + * \brief 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 > 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 > db() const { return d_db; } + + /*! + * Return a vector of size >= 1 that contains shared pointers + * to the daughterboard instance(s) associated with the specified side. + * + * \param which_side [0,1] which daughterboard + * + * It is an error to use the returned objects after the usrp_basic + * object has been destroyed. + */ + std::vector db(int which_side); + + /*! + * \brief is the subdev_spec valid? + */ + bool is_valid(const usrp_subdev_spec &ss); + + /*! + * \brief given a subdev_spec, return the corresponding daughterboard object. + * \throws std::invalid_ argument if ss is invalid. + * + * \param ss specifies the side and subdevice + */ + db_base_sptr selected_subdev(const usrp_subdev_spec &ss); + + /*! + * \brief return frequency of master oscillator on USRP + */ + 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. + * + *
+   * The 4 low bits are significant:
+   *
+   *   ADC0 = (1 << 0)
+   *   ADC1 = (1 << 1)
+   *   ADC2 = (1 << 2)
+   *   ADC3 = (1 << 3)
+   * 
+ * + * By default the control loop is enabled on all ADC's. + */ + bool set_dc_offset_cl_enable(int bits, int mask); + + /*! + * \brief return the usrp's serial number. + * + * \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); + + + // ================================================================ + // Routines to access and control daughterboard specific i/o + // + // Those with a common_ prefix access either the Tx or Rx side depending + // on the txrx parameter. Those without the common_ prefix are virtual + // and are overriden in usrp_basic_rx and usrp_basic_tx to access the + // the Rx or Tx sides automatically. We provide the common_ versions + // for those daughterboards such as the WBX and XCVR2450 that share + // h/w resources (such as the LO) between the Tx and Rx sides. + + // ---------------------------------------------------------------- + // BEGIN common_ daughterboard control functions + + /*! + * \brief Set Programmable Gain Amplifier(PGA) + * + * \param txrx Tx or Rx? + * \param which_amp which amp [0,3] + * \param gain_in_db gain value(linear in dB) + * + * gain is rounded to closest setting supported by hardware. + * + * \returns true iff sucessful. + * + * \sa pga_min(), pga_max(), pga_db_per_step() + */ + bool common_set_pga(txrx_t txrx, int which_amp, double gain_in_db); + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param txrx Tx or Rx? + * \param which_amp which amp [0,3] + */ + double common_pga(txrx_t txrx, int which_amp) const; + + /*! + * \brief Return minimum legal PGA gain in dB. + * \param txrx Tx or Rx? + */ + double common_pga_min(txrx_t txrx) const; + + /*! + * \brief Return maximum legal PGA gain in dB. + * \param txrx Tx or Rx? + */ + double common_pga_max(txrx_t txrx) const; + + /*! + * \brief Return hardware step size of PGA(linear in dB). + * \param txrx Tx or Rx? + */ + double common_pga_db_per_step(txrx_t txrx) const; + + /*! + * \brief Write direction register(output enables) for pins that go to daughterboard. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which size + * \param value value to write into register + * \param mask which bits of value to write into reg + * + * Each d'board has 16-bits of general purpose i/o. + * Setting the bit makes it an output from the FPGA to the d'board. + * + * This register is initialized based on a value stored in the + * d'board EEPROM. In general, you shouldn't be using this routine + * without a very good reason. Using this method incorrectly will + * kill your USRP motherboard and/or daughterboard. + */ + bool _common_write_oe(txrx_t txrx, int which_side, int value, int mask); + + /*! + * \brief Write daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value value to write into register + * \param mask which bits of value to write into reg + */ + bool common_write_io(txrx_t txrx, int which_side, int value, int mask); + + /*! + * \brief Read daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value output + */ + bool common_read_io(txrx_t txrx, int which_side, int *value); + + /*! + * \brief Read daughterboard i/o pin value + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \returns register value if successful, else READ_FAILED + */ + int common_read_io(txrx_t txrx, int which_side); + + /*! + * \brief Write daughterboard refclk config register + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param value value to write into register, see below + * + *
+   * Control whether a reference clock is sent to the daughterboards,
+   * and what frequency.  The refclk is sent on d'board i/o pin 0.
+   * 
+   *     3                   2                   1                       
+   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   *  +-----------------------------------------------+-+------------+
+   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
+   *  +-----------------------------------------------+-+------------+
+   * 
+   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
+   *  Bits 6:0 Divider value
+   * 
+ */ + bool common_write_refclk(txrx_t txrx, int which_side, int value); + + /*! + * \brief Automatic Transmit/Receive switching + *
+   *
+   * If automatic transmit/receive (ATR) switching is enabled in the
+   * FR_ATR_CTL register, the presence or absence of data in the FPGA
+   * transmit fifo selects between two sets of values for each of the 4
+   * banks of daughterboard i/o pins.
+   *
+   * Each daughterboard slot has 3 16-bit registers associated with it:
+   *   FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_*
+   *
+   * FR_ATR_MASK_{0,1,2,3}: 
+   *
+   *   These registers determine which of the daugherboard i/o pins are
+   *   affected by ATR switching.  If a bit in the mask is set, the
+   *   corresponding i/o bit is controlled by ATR, else it's output
+   *   value comes from the normal i/o pin output register:
+   *   FR_IO_{0,1,2,3}.
+   *
+   * FR_ATR_TXVAL_{0,1,2,3}:
+   * FR_ATR_RXVAL_{0,1,2,3}:
+   *
+   *   If the Tx fifo contains data, then the bits from TXVAL that are
+   *   selected by MASK are output.  Otherwise, the bits from RXVAL that
+   *   are selected by MASK are output.
+   * 
+ */ + bool common_write_atr_mask(txrx_t txrx, int which_side, int value); + bool common_write_atr_txval(txrx_t txrx, int which_side, int value); + bool common_write_atr_rxval(txrx_t txrx, int which_side, int value); + + /*! + * \brief Write auxiliary digital to analog converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. + * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. + * \param which_dac [2,3] TX slots must use only 2 and 3. + * \param value [0,4095] + * \returns true iff successful + */ + bool common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value); + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \param value return 12-bit value [0,4095] + * \returns true iff successful + */ + bool common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value); + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param txrx Tx or Rx? + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. + */ + int common_read_aux_adc(txrx_t txrx, int which_side, int which_adc); + + // END common_ daughterboard control functions + // ---------------------------------------------------------------- + // BEGIN virtual daughterboard control functions + + /*! + * \brief Set Programmable Gain Amplifier (PGA) + * + * \param which_amp which amp [0,3] + * \param gain_in_db gain value (linear in dB) + * + * gain is rounded to closest setting supported by hardware. + * + * \returns true iff sucessful. + * + * \sa pga_min(), pga_max(), pga_db_per_step() + */ + virtual bool set_pga (int which_amp, double gain_in_db) = 0; + + /*! + * \brief Return programmable gain amplifier gain setting in dB. + * + * \param which_amp which amp [0,3] + */ + virtual double pga (int which_amp) const = 0; + + /*! + * \brief Return minimum legal PGA gain in dB. + */ + virtual double pga_min () const = 0; + + /*! + * \brief Return maximum legal PGA gain in dB. + */ + virtual double pga_max () const = 0; + + /*! + * \brief Return hardware step size of PGA (linear in dB). + */ + virtual double pga_db_per_step () const = 0; + + /*! + * \brief Write direction register (output enables) for pins that go to daughterboard. + * + * \param which_side [0,1] which size + * \param value value to write into register + * \param mask which bits of value to write into reg + * + * Each d'board has 16-bits of general purpose i/o. + * Setting the bit makes it an output from the FPGA to the d'board. + * + * This register is initialized based on a value stored in the + * d'board EEPROM. In general, you shouldn't be using this routine + * without a very good reason. Using this method incorrectly will + * kill your USRP motherboard and/or daughterboard. + */ + virtual bool _write_oe (int which_side, int value, int mask) = 0; + + /*! + * \brief Write daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \param value value to write into register + * \param mask which bits of value to write into reg + */ + virtual bool write_io (int which_side, int value, int mask) = 0; + + /*! + * \brief Read daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \param value output + */ + virtual bool read_io (int which_side, int *value) = 0; + + /*! + * \brief Read daughterboard i/o pin value + * + * \param which_side [0,1] which d'board + * \returns register value if successful, else READ_FAILED + */ + virtual int read_io (int which_side) = 0; + + /*! + * \brief Write daughterboard refclk config register + * + * \param which_side [0,1] which d'board + * \param value value to write into register, see below + * + *
+   * Control whether a reference clock is sent to the daughterboards,
+   * and what frequency.  The refclk is sent on d'board i/o pin 0.
+   * 
+   *     3                   2                   1                       
+   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   *  +-----------------------------------------------+-+------------+
+   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
+   *  +-----------------------------------------------+-+------------+
+   * 
+   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
+   *  Bits 6:0 Divider value
+   * 
+ */ + virtual bool write_refclk(int which_side, int value) = 0; + + virtual bool write_atr_mask(int which_side, int value) = 0; + virtual bool write_atr_txval(int which_side, int value) = 0; + virtual bool write_atr_rxval(int which_side, int value) = 0; + + /*! + * \brief Write auxiliary digital to analog converter. + * + * \param which_side [0,1] which d'board + * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. + * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. + * \param which_dac [2,3] TX slots must use only 2 and 3. + * \param value [0,4095] + * \returns true iff successful + */ + virtual bool write_aux_dac (int which_side, int which_dac, int value) = 0; + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \param value return 12-bit value [0,4095] + * \returns true iff successful + */ + virtual bool read_aux_adc (int which_side, int which_adc, int *value) = 0; + + /*! + * \brief Read auxiliary analog to digital converter. + * + * \param which_side [0,1] which d'board + * \param which_adc [0,1] + * \returns value in the range [0,4095] if successful, else READ_FAILED. + */ + virtual int read_aux_adc (int which_side, int which_adc) = 0; + + /*! + * \brief returns current fusb block size + */ + virtual int block_size() const = 0; + + /*! + * \brief returns A/D or D/A converter rate in Hz + */ + virtual long converter_rate() const = 0; + + // END virtual daughterboard control functions + + // ---------------------------------------------------------------- + // Low level implementation routines. + // You probably shouldn't be using these... + // + + bool _set_led (int which_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 (); +}; + + /*! + * \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 (); +}; + + /*! + * \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 diff --git a/usrp/host/include/usrp/usrp_bytesex.h b/usrp/host/include/usrp/usrp_bytesex.h new file mode 100644 index 00000000..331db31c --- /dev/null +++ b/usrp/host/include/usrp/usrp_bytesex.h @@ -0,0 +1,108 @@ +/* -*- 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 +#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 */ diff --git a/usrp/host/include/usrp/usrp_local_sighandler.h b/usrp/host/include/usrp/usrp_local_sighandler.h new file mode 100644 index 00000000..ee336750 --- /dev/null +++ b/usrp/host/include/usrp/usrp_local_sighandler.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 +#include + +/*! + * \brief Representation of signal. + */ +class usrp_signal +{ + int d_signum; +public: + usrp_signal (int signum) : d_signum (signum) {} + int signal () const { return d_signum; } + std::string name () const; +}; + + +/*! + * \brief Get and set signal handler. + * + * Constructor installs new handler, destructor reinstalls + * original value. + */ +class usrp_local_sighandler { + int d_signum; +#ifdef HAVE_SIGACTION + struct sigaction d_old_action; +#endif +public: + usrp_local_sighandler (int signum, void (*new_handler)(int)); + ~usrp_local_sighandler (); + + /* throw usrp_signal (signum) */ + static void throw_signal (int signum) throw (usrp_signal); +}; + +#endif /* INCLUDED_USRP_LOCAL_SIGHANDLER_H */ diff --git a/usrp/host/include/usrp/usrp_prims.h b/usrp/host/include/usrp/usrp_prims.h new file mode 100644 index 00000000..aa088705 --- /dev/null +++ b/usrp/host/include/usrp/usrp_prims.h @@ -0,0 +1,294 @@ +/* -*- 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 +#include + +static const int USRP_HASH_SIZE = 16; + +enum usrp_load_status_t { ULS_ERROR = 0, ULS_OK, ULS_ALREADY_LOADED }; + +struct usb_dev_handle; +struct usb_device; + +/*! + * \brief initialize libusb; probe busses and devices. + * Safe to call more than once. + */ +void usrp_one_time_init (); + +/* + * force a rescan of the buses and devices + */ +void usrp_rescan (); + +/*! + * \brief locate Nth (zero based) USRP device in system. + * Return pointer or 0 if not found. + * + * The following kinds of devices are considered USRPs: + * + * unconfigured USRP (no firwmare loaded) + * configured USRP (firmware loaded) + * unconfigured Cypress FX2 (only if fx2_ok_p is true) + */ +struct usb_device *usrp_find_device (int nth, bool fx2_ok_p = false); + +bool usrp_usrp_p (struct usb_device *q); //< is this a USRP +bool usrp_usrp0_p (struct usb_device *q); //< is this a USRP Rev 0 +bool usrp_usrp1_p (struct usb_device *q); //< is this a USRP Rev 1 +bool usrp_usrp2_p (struct usb_device *q); //< is this a USRP Rev 2 +int usrp_hw_rev (struct usb_device *q); //< return h/w rev code + +bool usrp_fx2_p (struct usb_device *q); //< is this an unconfigured Cypress FX2 + +bool usrp_unconfigured_usrp_p (struct usb_device *q); //< some kind of unconfigured USRP +bool usrp_configured_usrp_p (struct usb_device *q); //< some kind of configured USRP + +/*! + * \brief given a usb_device return an instance of the appropriate usb_dev_handle + * + * These routines claim the specified interface and select the + * correct alternate interface. (USB nomenclature is totally screwed!) + * + * If interface can't be opened, or is already claimed by some other + * process, 0 is returned. + */ +struct usb_dev_handle *usrp_open_cmd_interface (struct usb_device *dev); +struct usb_dev_handle *usrp_open_rx_interface (struct usb_device *dev); +struct usb_dev_handle *usrp_open_tx_interface (struct usb_device *dev); + +/*! + * \brief close interface. + */ +bool usrp_close_interface (struct usb_dev_handle *udh); + +/*! + * \brief load intel hex format file into USRP/Cypress FX2 (8051). + * + * The filename extension is typically *.ihx + * + * Note that loading firmware may cause the device to renumerate. I.e., + * change its configuration, invalidating the current device handle. + */ + +usrp_load_status_t +usrp_load_firmware (struct usb_dev_handle *udh, const char *filename, bool force); + +/*! + * \brief load intel hex format file into USRP FX2 (8051). + * + * The filename extension is typically *.ihx + * + * Note that loading firmware may cause the device to renumerate. I.e., + * change its configuration, invalidating the current device handle. + * If the result is ULS_OK, usrp_load_firmware_nth delays 1 second + * then rescans the busses and devices. + */ +usrp_load_status_t +usrp_load_firmware_nth (int nth, const char *filename, bool force); + +/*! + * \brief load fpga configuration bitstream + */ +usrp_load_status_t +usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, bool force); + +/*! + * \brief load the regular firmware and fpga bitstream in the Nth USRP. + * + * This is the normal starting point... + */ +bool usrp_load_standard_bits (int nth, bool force, + const std::string fpga_filename = "", + const std::string firmware_filename = ""); + +/*! + * \brief copy the given \p hash into the USRP hash slot \p which. + * The usrp implements two hash slots, 0 and 1. + */ +bool usrp_set_hash (struct usb_dev_handle *udh, int which, + const unsigned char hash[USRP_HASH_SIZE]); + +/*! + * \brief retrieve the \p hash from the USRP hash slot \p which. + * The usrp implements two hash slots, 0 and 1. + */ +bool usrp_get_hash (struct usb_dev_handle *udh, int which, + unsigned char hash[USRP_HASH_SIZE]); + +bool usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value); +bool usrp_read_fpga_reg (struct usb_dev_handle *udh, int reg, int *value); +bool usrp_set_fpga_reset (struct usb_dev_handle *udh, bool on); +bool usrp_set_fpga_tx_enable (struct usb_dev_handle *udh, bool on); +bool usrp_set_fpga_rx_enable (struct usb_dev_handle *udh, bool on); +bool usrp_set_fpga_tx_reset (struct usb_dev_handle *udh, bool on); +bool usrp_set_fpga_rx_reset (struct usb_dev_handle *udh, bool on); +bool usrp_set_led (struct usb_dev_handle *udh, int which, bool on); + +bool usrp_check_rx_overrun (struct usb_dev_handle *udh, bool *overrun_p); +bool usrp_check_tx_underrun (struct usb_dev_handle *udh, bool *underrun_p); + +// i2c_read and i2c_write are limited to a maximum len of 64 bytes. + +bool usrp_i2c_write (struct usb_dev_handle *udh, int i2c_addr, + const void *buf, int len); + +bool usrp_i2c_read (struct usb_dev_handle *udh, int i2c_addr, + void *buf, int len); + +// spi_read and spi_write are limited to a maximum of 64 bytes +// See usrp_spi_defs.h for more info + +bool usrp_spi_write (struct usb_dev_handle *udh, + int optional_header, int enables, int format, + const void *buf, int len); + +bool usrp_spi_read (struct usb_dev_handle *udh, + int optional_header, int enables, int format, + void *buf, int len); + + +bool usrp_9862_write (struct usb_dev_handle *udh, + int which_codec, // [0, 1] + int regno, // [0, 63] + int value); // [0, 255] + +bool usrp_9862_read (struct usb_dev_handle *udh, + int which_codec, // [0, 1] + int regno, // [0, 63] + unsigned char *value); // [0, 255] + +/*! + * \brief Write multiple 9862 regs at once. + * + * \p buf contains alternating register_number, register_value pairs. + * \p len must be even and is the length of buf in bytes. + */ +bool usrp_9862_write_many (struct usb_dev_handle *udh, int which_codec, + const unsigned char *buf, int len); + + +/*! + * \brief write specified regs to all 9862's in the system + */ +bool usrp_9862_write_many_all (struct usb_dev_handle *udh, + const unsigned char *buf, int len); + + +// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr. See i2c_addr.h + +bool usrp_eeprom_write (struct usb_dev_handle *udh, int i2c_addr, + int eeprom_offset, const void *buf, int len); + + +// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr. See i2c_addr.h + +bool usrp_eeprom_read (struct usb_dev_handle *udh, int i2c_addr, + int eeprom_offset, void *buf, int len); + + +// Slot specific i/o routines + +/*! + * \brief write to the specified aux dac. + * + * \p slot: which Tx or Rx slot to write. + * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's + * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's + * + * \p which_dac: [0,3] RX slots must use only 0 and 1. + * TX slots must use only 2 and 3. + * + * AUX DAC 3 is really the 9862 sigma delta output. + * + * \p value to write to aux dac. All dacs take straight + * binary values. Although dacs 0, 1 and 2 are 8-bit and dac 3 is 12-bit, + * the interface is in terms of 12-bit values [0,4095] + */ +bool usrp_write_aux_dac (struct usb_dev_handle *uhd, int slot, + int which_dac, int value); + +/*! + * \brief Read the specified aux adc + * + * \p slot: which Tx or Rx slot to read aux dac + * \p which_adc: [0,1] which of the two adcs to read + * \p *value: return value, 12-bit straight binary. + */ +bool usrp_read_aux_adc (struct usb_dev_handle *udh, int slot, + int which_adc, int *value); + + +/*! + * \brief usrp daughterboard id to name mapping + */ +const std::string usrp_dbid_to_string (int dbid); + + +enum usrp_dbeeprom_status_t { UDBE_OK, UDBE_BAD_SLOT, UDBE_NO_EEPROM, UDBE_INVALID_EEPROM }; + +struct usrp_dboard_eeprom { + unsigned short id; // d'board identifier code + unsigned short oe; // fpga output enables: + // If bit set, i/o pin is an output from FPGA. + short offset[2]; // ADC/DAC offset correction +}; + +/*! + * \brief Read and return parsed daughterboard eeprom + */ +usrp_dbeeprom_status_t +usrp_read_dboard_eeprom (struct usb_dev_handle *udh, + int slot_id, usrp_dboard_eeprom *eeprom); + +/*! + * \brief write ADC/DAC offset calibration constants to d'board eeprom + */ +bool usrp_write_dboard_offsets (struct usb_dev_handle *udh, int slot_id, + short offset0, short offset1); + +/*! + * \brief return a usrp's serial number. + * + * Note that this only works on a configured usrp. + * \returns non-zero length string iff successful. + */ +std::string usrp_serial_number(struct usb_dev_handle *udh); + +#endif /* _USRP_PRIMS_H_ */ diff --git a/usrp/host/include/usrp/usrp_slots.h b/usrp/host/include/usrp/usrp_slots.h new file mode 100644 index 00000000..d2c50fc4 --- /dev/null +++ b/usrp/host/include/usrp/usrp_slots.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 */ diff --git a/usrp/host/include/usrp/usrp_standard.h b/usrp/host/include/usrp/usrp_standard.h new file mode 100644 index 00000000..a631f8b0 --- /dev/null +++ b/usrp/host/include/usrp/usrp_standard.h @@ -0,0 +1,452 @@ +/* -*- 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 +#include +#include + +class usrp_standard_tx; +class usrp_standard_rx; + +typedef boost::shared_ptr usrp_standard_tx_sptr; +typedef boost::shared_ptr usrp_standard_rx_sptr; + +/*! + * \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. + * + *
+   * 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
+   * 
+ */ + 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. + * + *
+   *     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
+   * 
+ */ + 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 */ diff --git a/usrp/host/include/usrp/usrp_subdev_spec.h b/usrp/host/include/usrp/usrp_subdev_spec.h new file mode 100644 index 00000000..e841ff83 --- /dev/null +++ b/usrp/host/include/usrp/usrp_subdev_spec.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_USRP_SUBDEV_SPEC_H +#define INCLUDED_USRP_SUBDEV_SPEC_H + +/*! + * \brief specify a daughterboard and subdevice on a daughterboard. + * + * In the USRP1, there are two sides, A and B. + * + * A daughterboard generally implements a single subdevice, but may in + * general implement any number of subdevices. At this time, all daughterboards + * with the exception of the Basic Rx and LF Rx implement a single subdevice. + * + * The Basic Rx and LF Rx implement 2 subdevices (soon 3). Subdevice + * 0 routes input RX-A to the DDC I input and routes a constant zero + * to the DDC Q input. Similarly, subdevice 1 routes input RX-B to + * the DDC I input and routes a constant zero to the DDC Q + * input. Subdevice 2 (when implemented) will route RX-A to the DDC I + * input and RX-B to the DDC Q input. + */ + +struct usrp_subdev_spec { + unsigned int side; // 0 -> A; 1 -> B + unsigned int subdev; // which subdevice (usually zero) + + usrp_subdev_spec(unsigned int _side = 0, unsigned int _subdev = 0) + : side(_side), subdev(_subdev) {} +}; + +#endif /* INCLUDED_USRP_SUBDEV_SPEC_H */ diff --git a/usrp/host/include/usrp/usrp_tune_result.h b/usrp/host/include/usrp/usrp_tune_result.h new file mode 100644 index 00000000..200541a3 --- /dev/null +++ b/usrp/host/include/usrp/usrp_tune_result.h @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_USRP_TUNE_RESULT_H +#define INCLUDED_USRP_TUNE_RESULT_H + +class usrp_tune_result +{ +public: + // RF frequency that corresponds to DC in the IF + double baseband_freq; + + // frequency programmed into the DDC/DUC + double dxc_freq; + + // residual frequency (typically < 0.01 Hz) + double residual_freq; + + // is the spectrum inverted? + bool inverted; + + usrp_tune_result(double baseband=0, double dxc=0, double residual=0, bool _inverted=false) + : baseband_freq(baseband), dxc_freq(dxc), + residual_freq(residual), inverted(_inverted) {} +}; + +#endif /* INCLUDED_USRP_TUNE_RESULT_H */ diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am index 2062bda6..8482485f 100644 --- a/usrp/host/lib/Makefile.am +++ b/usrp/host/lib/Makefile.am @@ -1,7 +1,7 @@ # # 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 @@ -20,5 +20,154 @@ 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 _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 diff --git a/usrp/host/lib/README_OSX b/usrp/host/lib/README_OSX new file mode 100644 index 00000000..37026f25 --- /dev/null +++ b/usrp/host/lib/README_OSX @@ -0,0 +1,63 @@ +USRP Darwin Fast USB Changes +Version 0.2 of 2006-04-27 +Michael Dickens + +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 diff --git a/usrp/host/lib/ad9862.h b/usrp/host/lib/ad9862.h new file mode 100644 index 00000000..4375d93d --- /dev/null +++ b/usrp/host/lib/ad9862.h @@ -0,0 +1,221 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 */ diff --git a/usrp/host/lib/check_data.py b/usrp/host/lib/check_data.py new file mode 100755 index 00000000..100f0f6d --- /dev/null +++ b/usrp/host/lib/check_data.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 + + + + diff --git a/usrp/host/lib/circular_buffer.h b/usrp/host/lib/circular_buffer.h new file mode 100644 index 00000000..8898e419 --- /dev/null +++ b/usrp/host/lib/circular_buffer.h @@ -0,0 +1,317 @@ +/* -*- 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 + +#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 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_ */ diff --git a/usrp/host/lib/circular_linked_list.h b/usrp/host/lib/circular_linked_list.h new file mode 100644 index 00000000..e495d609 --- /dev/null +++ b/usrp/host/lib/circular_linked_list.h @@ -0,0 +1,284 @@ +/* -*- 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 +#include + +#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 s_both; + +template class s_node +{ + typedef s_node* s_node_ptr; + +private: + T d_object; + bool d_available; + s_node_ptr d_prev, d_next; + s_both* 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* 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* l_both) { d_both = l_both; }; +}; + +template class circular_linked_list { + typedef s_node* 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 (); + l_prev->set_available (); + l_prev->next (l_prev); + l_prev->prev (l_prev); + if (n_nodes > 1) { + l_next = new s_node (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 (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 s_both +{ +private: + s_node* d_node; + void* d_this; +public: + __INLINE__ s_both (s_node* l_node, void* l_this) + : d_node (l_node), d_this (l_this) {}; + __INLINE__ ~s_both () {}; + __INLINE__ s_node* node () { return (d_node); }; + __INLINE__ void* This () { return (d_this); }; + __INLINE__ void set (s_node* l_node, void* l_this) { + d_node = l_node; d_this = l_this;}; +}; + +#endif /* _CIRCULAR_LINKED_LIST_H_ */ diff --git a/usrp/host/lib/darwin_libusb.h b/usrp/host/lib/darwin_libusb.h new file mode 100644 index 00000000..063a2e9c --- /dev/null +++ b/usrp/host/lib/darwin_libusb.h @@ -0,0 +1,190 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio. + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 + * (c) 2002-2005 Nathan Hjelm + * All rights reserved. + */ + +#ifndef __DARWIN_LIBUSB_H__ +#define __DARWIN_LIBUSB_H__ + +#include +#include +#include +#include + +extern "C" { +static char * +darwin_error_str (int result) +{ + switch (result) { + case kIOReturnSuccess: + return "no error"; + case kIOReturnNotOpen: + return "device not opened for exclusive access"; + case kIOReturnNoDevice: + return "no connection to an IOService"; + case kIOUSBNoAsyncPortErr: + return "no asyc port has been opened for interface"; + case kIOReturnExclusiveAccess: + return "another process has device opened for exclusive access"; + case kIOUSBPipeStalled: + return "pipe is stalled"; + case kIOReturnError: + return "could not establish a connection to Darin kernel"; + case kIOReturnBadArgument: + return "invalid argument"; + default: + return "unknown error"; + } +} + +/* not a valid errorno outside darwin.c */ +#define LUSBDARWINSTALL (ELAST+1) + +static int +darwin_to_errno (int result) +{ + switch (result) { + case kIOReturnSuccess: + return 0; + case kIOReturnNotOpen: + return EBADF; + case kIOReturnNoDevice: + case kIOUSBNoAsyncPortErr: + return ENXIO; + case kIOReturnExclusiveAccess: + return EBUSY; + case kIOUSBPipeStalled: + return LUSBDARWINSTALL; + case kIOReturnBadArgument: + return EINVAL; + case kIOReturnError: + default: + return 1; + } +} + +typedef enum { + USB_ERROR_TYPE_NONE = 0, + USB_ERROR_TYPE_STRING, + USB_ERROR_TYPE_ERRNO, +} usb_error_type_t; + +extern char usb_error_str[1024]; +extern int usb_error_errno; +extern usb_error_type_t usb_error_type; + +#define USB_ERROR(r, x) \ + do { \ + usb_error_type = USB_ERROR_TYPE_ERRNO; \ + usb_error_errno = x; \ + return r; \ + } while (0) + +#define USB_ERROR_STR(r, x, format, args...) \ + do { \ + usb_error_type = USB_ERROR_TYPE_STRING; \ + snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ + if (usb_debug) \ + fprintf(stderr, "USB error: %s\n", usb_error_str); \ + return r; \ + } while (0) + +#define USB_ERROR_STR_ORIG(x, format, args...) \ + do { \ + usb_error_type = USB_ERROR_TYPE_STRING; \ + snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ + if (usb_debug) \ + fprintf(stderr, "USB error: %s\n", usb_error_str); \ + return x; \ + } while (0) + +#define USB_ERROR_STR_NO_RET(x, format, args...) \ + do { \ + usb_error_type = USB_ERROR_TYPE_STRING; \ + snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ + if (usb_debug) \ + fprintf(stderr, "USB error: %s\n", usb_error_str); \ + } while (0) + +/* simple function that figures out what pipeRef is associated with an endpoint */ +static int ep_to_pipeRef (darwin_dev_handle *device, int ep) +{ + io_return_t ret; + UInt8 numep, direction, number; + UInt8 dont_care1, dont_care3; + UInt16 dont_care2; + int i; + + if (usb_debug > 3) + fprintf(stderr, "Converting ep address to pipeRef.\n"); + + /* retrieve the total number of endpoints on this interface */ + ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep); + if ( ret ) { + if ( usb_debug > 3 ) + fprintf ( stderr, "ep_to_pipeRef: interface is %p\n", device->interface ); + USB_ERROR_STR_ORIG ( -ret, "ep_to_pipeRef: can't get number of endpoints for interface" ); + } + + /* iterate through the pipeRefs until we find the correct one */ + for (i = 1 ; i <= numep ; i++) { + ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number, + &dont_care1, &dont_care2, &dont_care3); + + if (ret != kIOReturnSuccess) { + fprintf (stderr, "ep_to_pipeRef: an error occurred getting pipe information on pipe %d\n", + i ); + USB_ERROR_STR_ORIG (-darwin_to_errno(ret), "ep_to_pipeRef(GetPipeProperties): %s", darwin_error_str(ret)); + } + + if (usb_debug > 3) + fprintf (stderr, "ep_to_pipeRef: Pipe %i: DIR: %i number: %i\n", i, direction, number); + + /* calculate the endpoint of the pipe and check it versus the requested endpoint */ + if ( ((direction << 7 & USB_ENDPOINT_DIR_MASK) | (number & USB_ENDPOINT_ADDRESS_MASK)) == ep ) { + if (usb_debug > 3) + fprintf(stderr, "ep_to_pipeRef: pipeRef for ep address 0x%02x found: 0x%02x\n", ep, i); + + return i; + } + } + + if (usb_debug > 3) + fprintf(stderr, "ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep); + + /* none of the found pipes match the requested endpoint */ + return -1; +} + +} +#endif /* __DARWIN_LIBUSB_H__ */ diff --git a/usrp/host/lib/db_base.cc b/usrp/host/lib/db_base.cc new file mode 100644 index 00000000..102166a8 --- /dev/null +++ b/usrp/host/lib/db_base.cc @@ -0,0 +1,252 @@ +// +// 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 +#include + +#if 0 +tune_result::tune_result(double baseband, double dxc, double residual, bool inv) + : ok(false), baseband_freq(baseband), dxc_freq(dxc), + residual_freq(residual), inverted(inv) +{ +} + +tune_result::~tune_result() +{ +} +#endif + + +/*****************************************************************************/ + +db_base::db_base(usrp_basic_sptr usrp, int which) + : d_is_shutdown(false), d_raw_usrp(usrp.get()), d_which(which), d_lo_offset(0.0) +{ +} + +db_base::~db_base() +{ + shutdown(); +} + +void +db_base::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + } +} + +int +db_base::dbid() +{ + return usrp()->daughterboard_id(d_which); +} + +std::string +db_base::name() +{ + return usrp_dbid_to_string(dbid()); +} + +std::string +db_base::side_and_name() +{ + if(d_which == 0) + return "A: " + name(); + else + return "B: " + name(); +} + +// Function to bypass ADC buffers. Any board which is DC-coupled +// should bypass the buffers + +bool +db_base::bypass_adc_buffers(bool bypass) +{ + //if(d_tx) { + // throw std::runtime_error("TX Board has no adc buffers\n"); + //} + + bool ok = true; + if(d_which==0) { + ok &= usrp()->set_adc_buffer_bypass(0, bypass); + ok &= usrp()->set_adc_buffer_bypass(1, bypass); + } + else { + ok &= usrp()->set_adc_buffer_bypass(2, bypass); + ok &= usrp()->set_adc_buffer_bypass(3, bypass); + } + return ok; +} + +bool +db_base::set_atr_mask(int v) +{ + // Set Auto T/R mask. + return usrp()->write_atr_mask(d_which, v); +} + +bool +db_base::set_atr_txval(int v) +{ + // Set Auto T/R register value to be used when transmitting. + return usrp()->write_atr_txval(d_which, v); +} + +bool +db_base::set_atr_rxval(int v) +{ + // Set Auto T/R register value to be used when receiving. + return usrp()->write_atr_rxval(d_which, v); +} + +bool +db_base::set_atr_tx_delay(int v) +{ + // Set Auto T/R delay (in clock ticks) from when Tx fifo gets data to + // when T/R switches. + return usrp()->write_atr_tx_delay(v); +} + +bool +db_base::set_atr_rx_delay(int v) +{ + // Set Auto T/R delay (in clock ticks) from when Tx fifo goes empty to + // when T/R switches. + return usrp()->write_atr_rx_delay(v); +} + +bool +db_base::i_and_q_swapped() +{ + // Return True if this is a quadrature device and (for RX) ADC 0 is Q + // or (for TX) DAC 0 is Q + return false; +} + +bool +db_base::spectrum_inverted() +{ + // Return True if the dboard gives an inverted spectrum + + return false; +} + +bool +db_base::set_enable(bool on) +{ + // For tx daughterboards, this controls the transmitter enable. + + return true; // default is nop +} + +bool +db_base::set_auto_tr(bool on) +{ + // Enable automatic Transmit/Receive switching (ATR). + // + // Should be overridden in subclasses that care. This will typically + // set the atr_mask, txval and rxval. + + return true; +} + +bool +db_base::set_lo_offset(double offset) +{ + // Set how much LO is offset from requested frequency + + d_lo_offset = offset; + return true; +} + +bool +db_base::select_rx_antenna(int which_antenna) +{ + // Specify which antenna port to use for reception. + // Should be overriden by daughterboards that care. + + return which_antenna == 0; +} + +bool +db_base::select_rx_antenna(const std::string &which_antenna) +{ + // Specify which antenna port to use for reception. + // Should be overriden by daughterboards that care. + + return which_antenna == ""; +} + + +// Reference Clock section +// +// Control whether a reference clock is sent to the daughterboards, +// and what frequency +// +// Bit 7 -- 1 turns on refclk, 0 allows IO use +// Bits 6:0 Divider value +// + +double +db_base::_refclk_freq() +{ + return usrp()->fpga_master_clock_freq() / _refclk_divisor(); +} + +void +db_base::_enable_refclk(bool enable) +{ + int CLOCK_OUT = 1; // Clock is on lowest bit + int REFCLK_ENABLE = 0x80; + int REFCLK_DIVISOR_MASK = 0x7f; + + if(enable) { + usrp()->_write_oe(d_which, CLOCK_OUT, CLOCK_OUT); // output enable + usrp()->write_refclk(d_which, (_refclk_divisor() & REFCLK_DIVISOR_MASK) | REFCLK_ENABLE); + } + else { + usrp()->write_refclk(d_which, 0); + } +} + +int +db_base::_refclk_divisor() +{ + // Return value to stick in REFCLK_DIVISOR register + throw std::runtime_error("_reflck_divisor() called from base class\n");; +} + +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; +} diff --git a/usrp/host/lib/db_base_impl.h b/usrp/host/lib/db_base_impl.h new file mode 100644 index 00000000..9d5ca437 --- /dev/null +++ b/usrp/host/lib/db_base_impl.h @@ -0,0 +1,33 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#endif /* INCLUDED_DB_BASE_IMPL_H */ diff --git a/usrp/host/lib/db_basic.cc b/usrp/host/lib/db_basic.cc new file mode 100644 index 00000000..0c6bedec --- /dev/null +++ b/usrp/host/lib/db_basic.cc @@ -0,0 +1,262 @@ +// +// 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 +#include + +db_basic_tx::db_basic_tx(boost::shared_ptr usrp, int which) + : db_base(usrp, which) +{ + // Handler for Basic Tx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively + + set_gain((gain_min() + gain_max()) / 2); // initialize gain +} + +db_basic_tx::~db_basic_tx() +{ +} + +double +db_basic_tx::freq_min() +{ + return -90e9; +} + +double +db_basic_tx::freq_max() +{ + return 90e9; +} + +struct freq_result_t +db_basic_tx::set_freq(double target_freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + + struct freq_result_t args = {false, 0}; + args.ok = true; + args.baseband_freq = 0.0; + return args; +} + +float +db_basic_tx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_basic_tx::gain_max() +{ + return usrp()->pga_max(); +} + +float +db_basic_tx::gain_db_per_step() +{ + return usrp()->pga_db_per_step(); +} + +bool +db_basic_tx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + bool ok = usrp()->set_pga(d_which * 2 + 0, gain); + ok = ok && usrp()->set_pga(d_which * 2 + 1, gain); + return ok; +} + +bool +db_basic_tx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + + return true; +} + + +/******************************************************************************/ + + +db_basic_rx::db_basic_rx(usrp_basic_sptr usrp, int which, int subdev) + : db_base(usrp, which) +{ + // Handler for Basic Rx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively + // @param subdev: which analog i/o channel: 0 or 1 + // @type subdev: int + + d_subdev = subdev; + + bypass_adc_buffers(true); + + if(0) { // Doing this would give us a different default than the historical values... + set_gain(float(gain_min() + gain_max()) / 2.0); // initialize gain + } +} + +db_basic_rx::~db_basic_rx() +{ +} + +double +db_basic_rx::freq_min() +{ + return -90e9; +} + +double +db_basic_rx::freq_max() +{ + return 90e9; +} + +struct freq_result_t +db_basic_rx::set_freq(double target_freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + + struct freq_result_t args = {true, 0.0}; + return args; +} + +float +db_basic_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_basic_rx::gain_max() +{ + return usrp()->pga_max(); +} + +float +db_basic_rx::gain_db_per_step() +{ + return usrp()->pga_db_per_step(); +} + +bool +db_basic_rx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + return usrp()->set_pga(d_which * 2 + d_subdev, gain); +} + +bool +db_basic_rx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + + // This bit of info is useful when setting up the USRP Rx mux register. + + return (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; +} + + diff --git a/usrp/host/lib/db_boards.cc b/usrp/host/lib/db_boards.cc new file mode 100644 index 00000000..070b8dd4 --- /dev/null +++ b/usrp/host/lib/db_boards.cc @@ -0,0 +1,217 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::vector +instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) +{ + std::vector db; + + switch(dbid) { + + case(USRP_DBID_BASIC_TX): + db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); + break; + + case(USRP_DBID_BASIC_RX): + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); + 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)){ + db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); + } + else { + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); + } + break; + + case(-2): + default: + if (boost::dynamic_pointer_cast(usrp)){ + fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Tx.\"\n"); + fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n"); + db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); + } + else { + fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Rx.\"\n"); + fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n"); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); + db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); + } + break; + } + + return db; +} diff --git a/usrp/host/lib/db_boards.h b/usrp/host/lib/db_boards.h new file mode 100644 index 00000000..136091c5 --- /dev/null +++ b/usrp/host/lib/db_boards.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. +// + +#ifndef DB_BOARDS_H +#define DB_BOARDS_H + +#include +#include + +std::vector instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side); + +#endif + + diff --git a/usrp/host/lib/db_dbs_rx.cc b/usrp/host/lib/db_dbs_rx.cc new file mode 100644 index 00000000..99f66c78 --- /dev/null +++ b/usrp/host/lib/db_dbs_rx.cc @@ -0,0 +1,497 @@ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include +#include +#include + + +/*****************************************************************************/ + + +db_dbs_rx::db_dbs_rx(usrp_basic_sptr _usrp, int which) + : db_base(_usrp, which) +{ + // Control DBS receiver based USRP daughterboard. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively + + usrp()->_write_oe(d_which, 0x0001, 0x0001); + if(which == 0) { + d_i2c_addr = 0x67; + } + else { + d_i2c_addr = 0x65; + } + + d_n = 950; + d_div2 = 0; + d_osc = 5; + d_cp = 3; + d_r = 4; + d_r_int = 1; + d_fdac = 127; + d_m = 2; + d_dl = 0; + d_ade = 0; + d_adl = 0; + d_gc1 = 0; + d_gc2 = 31; + d_diag = 0; + + _enable_refclk(true); + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain + + bypass_adc_buffers(true); +} + +db_dbs_rx::~db_dbs_rx() +{ + shutdown(); +} + +void +db_dbs_rx::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown orderly + _enable_refclk(false); + } +} + +void +db_dbs_rx::_write_reg (int regno, int v) +{ + //regno is in [0,5], v is value to write to register""" + assert (0 <= regno && regno <= 5); + std::vector args(2); + args[0] = regno; + args[1] = v; + usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args)); +} + +void +db_dbs_rx::_write_regs (int starting_regno, const std::vector &vals) +{ + // starting_regno is in [0,5], + // vals is a seq of integers to write to consecutive registers""" + + //FIXME + std::vector args; + args.push_back(starting_regno); + args.insert(args.end(), vals.begin(), vals.end()); + usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args)); +} + +std::vector +db_dbs_rx::_read_status () +{ + //If successful, return list of two ints: [status_info, filter_DAC]""" + std::string s = usrp()->read_i2c (d_i2c_addr, 2); + if(s.size() != 2) { + std::vector ret(0); + return ret; + } + return str_to_int_seq (s); +} + +void +db_dbs_rx::_send_reg(int regno) +{ + assert(0 <= regno && regno <= 5); + if(regno == 0) + _write_reg(0,(d_div2<<7) + (d_n>>8)); + if(regno == 1) + _write_reg(1,d_n & 255); + if(regno == 2) + _write_reg(2,d_osc + (d_cp<<3) + (d_r_int<<5)); + if(regno == 3) + _write_reg(3,d_fdac); + if(regno == 4) + _write_reg(4,d_m + (d_dl<<5) + (d_ade<<6) + (d_adl<<7)); + if(regno == 5) + _write_reg(5,d_gc2 + (d_diag<<5)); +} + +// BW setting +void +db_dbs_rx::_set_m(int m) +{ + assert(m>0 && m<32); + d_m = m; + _send_reg(4); +} + +void +db_dbs_rx::_set_fdac(int fdac) +{ + assert(fdac>=0 && fdac<128); + d_fdac = fdac; + _send_reg(3); +} + +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(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(round(31.0 * (1-gain/24.0))); + gain = 0; + } + else { + gc2 = 0; + gain -=24; + } + + if(gain >= 4.58) { + dl = 1; + gain -= 4.58; + } + + pga = gain; + _set_gc1(gc1); + _set_gc2(gc2); + _set_dl(dl); + _set_pga(pga); + + return true; +} + +// Frequency setting +void +db_dbs_rx::_set_osc(int osc) +{ + assert(osc>=0 && osc<8); + d_osc = osc; + _send_reg(2); +} + +void +db_dbs_rx::_set_cp(int cp) +{ + assert(cp>=0 && cp<4); + d_cp = cp; + _send_reg(2); +} + +void +db_dbs_rx::_set_n(int n) +{ + assert(n>256 && n<32768); + d_n = n; + _send_reg(0); + _send_reg(1); +} + +void +db_dbs_rx::_set_div2(int div2) +{ + assert(div2 == 0 || div2 == 1); + d_div2 = div2; + _send_reg(0); +} + +void +db_dbs_rx::_set_r(int r) +{ + assert(r>=0 && r<128); + d_r = r; + d_r_int = static_cast(round(log10(r)/log10(2)) - 1); + _send_reg(2); +} + +// FIXME How do we handle ADE and ADL properly? +void +db_dbs_rx::_set_ade(int ade) +{ + assert(ade == 0 || ade == 1); + d_ade = ade; + _send_reg(4); +} + +double +db_dbs_rx::freq_min() +{ + return 500e6; +} + +double +db_dbs_rx::freq_max() +{ + return 2.6e9; +} + +struct freq_result_t +db_dbs_rx::set_freq(double freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is RF frequency that corresponds to DC in the IF. + + freq_result_t args = {false, 0}; + + if(!(freq>=freq_min() && freq<=freq_max())) { + return args; + } + + double vcofreq; + if(freq<1150e6) { + _set_div2(0); + vcofreq = 4 * freq; + } + else { + _set_div2(1); + vcofreq = 2 * freq; + } + + _set_ade(1); + int rmin = std::max(2, (int)(_refclk_freq()/2e6)); + int rmax = std::min(128, (int)(_refclk_freq()/500e3)); + int r = 2; + int n = 0; + int best_r = 2; + int best_n = 0; + int best_delta = 10e6; + int delta; + + while(r <= rmax) { + n = static_cast(round(freq/(_refclk_freq()/r))); + if(r(round(best_n))); + + int vco; + if(vcofreq < 2433e6) + vco = 0; + else if(vcofreq < 2711e6) + vco=1; + else if(vcofreq < 3025e6) + vco=2; + else if(vcofreq < 3341e6) + vco=3; + else if(vcofreq < 3727e6) + vco=4; + else if(vcofreq < 4143e6) + vco=5; + else if(vcofreq < 4493e6) + vco=6; + else + vco=7; + + _set_osc(vco); + + // Set CP current + int adc_val = 0; + std::vector bytes(2); + while(adc_val == 0 || adc_val == 7) { + bytes = _read_status(); + adc_val = bytes[0] >> 2; + if(adc_val == 0) { + if(vco <= 0) { + return args; + } + else { + vco = vco - 1; + } + } + else if(adc_val == 7) { + if(vco >= 7) { + return args; + } + else { + vco = vco + 1; + } + } + _set_osc(vco); + } + + if(adc_val == 1 || adc_val == 2) { + _set_cp(1); + } + else if(adc_val == 3 || adc_val == 4) { + _set_cp(2); + } + else { + _set_cp(3); + } + + args.ok = true; + args.baseband_freq = d_n * _refclk_freq() / d_r; + return args; +} + +int +db_dbs_rx::_refclk_divisor() +{ + //Return value to stick in REFCLK_DIVISOR register + return 16; +} + +bool +db_dbs_rx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + return true; +} diff --git a/usrp/host/lib/db_dtt754.cc b/usrp/host/lib/db_dtt754.cc new file mode 100644 index 00000000..d78c5b32 --- /dev/null +++ b/usrp/host/lib/db_dtt754.cc @@ -0,0 +1,323 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include + +int +control_byte_1() +{ + int RS = 0; // 0 = 166.66kHz reference + int ATP = 7; // Disable internal AGC + return (0x80 | ATP<<3 | RS); +} + +int +control_byte_2() +{ + int STBY = 0; // powered on + int XTO = 1; // turn off xtal out, which we don't have + int ATC = 0; // not clear exactly, possibly speeds up or slows down AGC, which we are not using + + int c = 0xc2 | ATC<<5 | STBY<<4 | XTO; + return c; +} + +int +bandswitch_byte(float freq, float bw) +{ + int P5, CP, BS; + + if(bw>7.5e6) { + P5 = 1; + } + else { + P5 = 0; + } + + if(freq < 121e6) { + CP = 0; + BS = 1; + } + else if(freq < 141e6) { + CP = 1; + BS = 1; + } + else if(freq < 166e6) { + CP = 2; + BS = 1; + } + else if(freq < 182e6) { + CP = 3; + BS = 1; + } + else if(freq < 286e6) { + CP = 0; + BS = 2; + } + else if(freq < 386e6) { + CP = 1; + BS = 2; + } + else if(freq < 446e6) { + CP = 2; + BS = 2; + } + else if(freq < 466e6) { + CP = 3; + BS = 2; + } + else if(freq < 506e6) { + CP = 0; + BS = 8; + } + else if(freq < 761e6) { + CP = 1; + BS = 8; + } + else if(freq < 846e6) { + CP = 2; + BS = 8; + } + else { // limit is ~905 MHz + CP = 3; + BS = 8; + } + return (CP<<6 | P5 << 4 | BS); +} + +db_dtt754::db_dtt754(usrp_basic_sptr _usrp, int which) + : db_base(_usrp, which) +{ + /* + * Control custom DTT75403-based daughterboard. + * + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively + * @type which: int + */ + + // FIXME: DTT754 and DTT768 can probably inherit from a DTT class + + if(d_which == 0) { + d_i2c_addr = 0x60; + } + else { + d_i2c_addr = 0x62; + } + + d_bw = 7e6; + d_IF = 36e6; + + d_f_ref = 166.6666e3; + d_inverted = false; + + set_gain((gain_min() + gain_max()) / 2.0); + + bypass_adc_buffers(false); +} + +db_dtt754::~db_dtt754() +{ +} + +float +db_dtt754::gain_min() +{ + return 0; +} + +float +db_dtt754::gain_max() +{ + return 115; +} + +float +db_dtt754::gain_db_per_step() +{ + return 1; +} + +bool +db_dtt754::set_gain(float gain) +{ + assert(gain>=0 && gain<=115); + + float rfgain, ifgain, pgagain; + if(gain > 60) { + rfgain = 60; + gain = gain - 60; + } + else { + rfgain = gain; + gain = 0; + } + + if(gain > 35) { + ifgain = 35; + gain = gain - 35; + } + else { + ifgain = gain; + gain = 0; + } + pgagain = gain; + + _set_rfagc(rfgain); + _set_ifagc(ifgain); + _set_pga(pgagain); + + return true; // can't fail with the assert in place +} + +double +db_dtt754::freq_min() +{ + return 44e6; +} + +double +db_dtt754::freq_max() +{ + return 900e6; +} + +struct freq_result_t +db_dtt754::set_freq(double target_freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + freq_result_t ret = {false, 0.0}; + + if(target_freq < freq_min() || target_freq > freq_max()) { + return ret; + } + + double target_lo_freq = target_freq + d_IF; // High side mixing + + int divisor = (int)(0.5+(target_lo_freq / d_f_ref)); + double actual_lo_freq = d_f_ref*divisor; + + if((divisor & ~0x7fff) != 0) { // must be 15-bits or less + return ret; + } + + // build i2c command string + std::vector buf(5); + buf[0] = (divisor >> 8) & 0xff; // DB1 + buf[1] = divisor & 0xff; // DB2 + buf[2] = control_byte_1(); + buf[3] = bandswitch_byte(actual_lo_freq, d_bw); + buf[4] = control_byte_2(); + + bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); + + d_freq = actual_lo_freq - d_IF; + + ret.ok = ok; + ret.baseband_freq = actual_lo_freq; + + return ret; + +} + +bool +db_dtt754::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + + return false; +} + +bool +db_dtt754::spectrum_inverted() +{ + /* + * The 43.75 MHz version is inverted + */ + + return d_inverted; +} + +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); + } +} diff --git a/usrp/host/lib/db_dtt768.cc b/usrp/host/lib/db_dtt768.cc new file mode 100644 index 00000000..a520fdc6 --- /dev/null +++ b/usrp/host/lib/db_dtt768.cc @@ -0,0 +1,296 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include + +int +control_byte_4() +{ + int C = 0; // Charge Pump Current, no info on how to choose + int R = 4; // 125 kHz fref + + // int ATP = 7; // Disable internal AGC + return (0x80 | C<<5 | R); +} + +int +control_byte_5(float freq, int agcmode = 1) +{ + if(agcmode) { + if(freq < 150e6) { + return 0x3B; + } + else if(freq < 420e6) { + return 0x7E; + } + else { + return 0xB7; + } + } + else { + if(freq < 150e6) { + return 0x39; + } + else if(freq < 420e6) { + return 0x7C; + } + else { + return 0xB5; + } + } +} + +int +control_byte_6() +{ + int ATC = 0; // AGC time constant = 100ms, 1 = 3S + int IFE = 1; // IF AGC amplifier enable + int AT = 0; // AGC control, ??? + + return (ATC << 5 | IFE << 4 | AT); +} + +int +control_byte_7() +{ + int SAS = 1; // SAW Digital mode + int AGD = 1; // AGC disable + int ADS = 0; // AGC detector into ADC converter + int T = 0; // Test mode, undocumented + return (SAS << 7 | AGD << 5 | ADS << 4 | T); +} + +db_dtt768::db_dtt768(usrp_basic_sptr _usrp, int which) + : db_base(_usrp, which) +{ + /* + * Control custom DTT76803-based daughterboard. + * + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively + * @type which: int + */ + + if(d_which == 0) { + d_i2c_addr = 0x60; + } + else { + d_i2c_addr = 0x62; + } + + d_IF = 44e6; + + d_f_ref = 125e3; + d_inverted = false; + + set_gain((gain_min() + gain_max()) / 2.0); + + bypass_adc_buffers(false); +} + +db_dtt768::~db_dtt768() +{ +} + +float +db_dtt768::gain_min() +{ + return 0; +} + +float +db_dtt768::gain_max() +{ + return 115; +} + +float +db_dtt768::gain_db_per_step() +{ + return 1; +} + +bool +db_dtt768::set_gain(float gain) +{ + assert(gain>=0 && gain<=115); + + float rfgain, ifgain, pgagain; + if(gain > 60) { + rfgain = 60; + gain = gain - 60; + } + else { + rfgain = gain; + gain = 0; + } + + if(gain > 35) { + ifgain = 35; + gain = gain - 35; + } + else { + ifgain = gain; + gain = 0; + } + pgagain = gain; + + _set_rfagc(rfgain); + _set_ifagc(ifgain); + _set_pga(pgagain); + + return true; +} + +double +db_dtt768::freq_min() +{ + return 44e6; +} + +double +db_dtt768::freq_max() +{ + return 900e6; +} + +struct freq_result_t +db_dtt768::set_freq(double target_freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + freq_result_t ret = {false, 0.0}; + + if(target_freq < freq_min() || target_freq > freq_max()) { + return ret; + } + + double target_lo_freq = target_freq + d_IF; // High side mixing + + int divisor = (int)(0.5+(target_lo_freq / d_f_ref)); + double actual_lo_freq = d_f_ref*divisor; + + if((divisor & ~0x7fff) != 0) { // must be 15-bits or less + return ret; + } + + // build i2c command string + std::vector buf(6); + buf[0] = (divisor >> 8) & 0xff; // DB1 + buf[1] = divisor & 0xff; // DB2 + buf[2] = control_byte_4(); + buf[3] = control_byte_5(target_freq); + buf[4] = control_byte_6(); + buf[5] = control_byte_7(); + + bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); + + d_freq = actual_lo_freq - d_IF; + + ret.ok = ok; + ret.baseband_freq = actual_lo_freq; + + return ret; + +} + +bool +db_dtt768::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + + return false; +} + +bool +db_dtt768::spectrum_inverted() +{ + /* + * The 43.75 MHz version is inverted + */ + + return d_inverted; +} + +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); + } +} diff --git a/usrp/host/lib/db_flexrf.cc b/usrp/host/lib/db_flexrf.cc new file mode 100644 index 00000000..a8f4684b --- /dev/null +++ b/usrp/host/lib/db_flexrf.cc @@ -0,0 +1,1148 @@ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include + +// d'board i/o pin defs +// Tx and Rx have shared defs, but different i/o regs +#define AUX_RXAGC (1 << 8) +#define POWER_UP (1 << 7) // enables power supply +#define RX_TXN (1 << 6) // Tx only: T/R antenna switch for TX/RX port +#define RX2_RX1N (1 << 6) // Rx only: antenna switch between RX2 and TX/RX port +#define ENABLE (1 << 5) // enables mixer +#define AUX_SEN (1 << 4) +#define AUX_SCLK (1 << 3) +#define PLL_LOCK_DETECT (1 << 2) +#define AUX_SDO (1 << 1) +#define CLOCK_OUT (1 << 0) + +flexrf_base::flexrf_base(usrp_basic_sptr _usrp, int which, int _power_on) + : db_base(_usrp, which), d_power_on(_power_on) +{ + /* + @param usrp: instance of usrp.source_c + @param which: which side: 0 or 1 corresponding to side A or B respectively + @type which: int + */ + + d_first = true; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs + _enable_refclk(false); // disable refclk + + set_auto_tr(false); +} + +flexrf_base::~flexrf_base() +{ + delete d_common; +} + +void +flexrf_base::_write_all(int R, int control, int N) +{ + /* + Write R counter latch, control latch and N counter latch to VCO. + + Adds 10ms delay between writing control and N if this is first call. + This is the required power-up sequence. + + @param R: 24-bit R counter latch + @type R: int + @param control: 24-bit control latch + @type control: int + @param N: 24-bit N counter latch + @type N: int + */ + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + + _write_R(R); + _write_control(control); + if(d_first) { + //time.sleep(0.010); + nanosleep(&t, NULL); + d_first = false; + } + _write_N(N); +} + +void +flexrf_base::_write_control(int control) +{ + _write_it((control & ~0x3) | 0); +} + +void +flexrf_base::_write_R(int R) +{ + _write_it((R & ~0x3) | 1); +} + +void +flexrf_base::_write_N(int N) +{ + _write_it((N & ~0x3) | 2); +} + +void +flexrf_base::_write_it(int v) +{ + char s[3]; + s[0] = (char)((v >> 16) & 0xff); + s[1] = (char)((v >> 8) & 0xff); + s[2] = (char)(v & 0xff); + std::string str(s, 3); + usrp()->_write_spi(0, d_spi_enable, d_spi_format, str); +} + +bool +flexrf_base::_lock_detect() +{ + /* + @returns: the value of the VCO/PLL lock detect bit. + @rtype: 0 or 1 + */ + if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { + return true; + } + else { // Give it a second chance + // FIXME: make portable sleep + timespec t; + t.tv_sec = 0; + t.tv_nsec = 100000000; + nanosleep(&t, NULL); + + if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { + return true; + } + else { + return false; + } + } +} + +bool +flexrf_base::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + /* + Determine values of R, control, and N registers, along with actual freq. + + @param freq: target frequency in Hz + @type freq: float + @returns: (R, control, N, actual_freq) + @rtype: tuple(int, int, int, float) + + Override this in derived classes. + */ + + //raise NotImplementedError; + throw std::runtime_error("_compute_regs called from flexrf_base\n"); +} + +int +flexrf_base::_compute_control_reg() +{ + return d_common->_compute_control_reg(); +} + +int +flexrf_base::_refclk_divisor() +{ + return d_common->_refclk_divisor(); +} + +double +flexrf_base::_refclk_freq() +{ + return 64e6/_refclk_divisor(); +} + +struct freq_result_t +flexrf_base::set_freq(double freq) +{ + /* + @returns (ok, actual_baseband_freq) where: + ok is True or False and indicates success or failure, + actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + struct freq_result_t args = {false, 0}; + + // Offsetting the LO helps get the Tx carrier leakage out of the way. + // This also ensures that on Rx, we're not getting hosed by the + // FPGA's DC removal loop's time constant. We were seeing a + // problem when running with discontinuous transmission. + // Offsetting the LO made the problem go away. + freq += d_lo_offset; + + int R, control, N; + double actual_freq; + _compute_regs(freq, R, control, N, actual_freq); + + if(R==0) { + return args; + } + + _write_all(R, control, N); + args.ok = _lock_detect(); + args.baseband_freq = actual_freq; + return args; +} + +bool +flexrf_base::_set_pga(float pga_gain) +{ + if(d_which == 0) { + usrp()->set_pga(0, pga_gain); + usrp()->set_pga(1, pga_gain); + } + else { + usrp()->set_pga(2, pga_gain); + usrp()->set_pga(3, pga_gain); + } + return true; +} + +bool +flexrf_base::is_quadrature() +{ + /* + Return True if this board requires both I & Q analog channels. + + This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + +double +flexrf_base::freq_min() +{ + return d_common->freq_min(); +} + +double +flexrf_base::freq_max() +{ + return d_common->freq_max(); +} + +// ---------------------------------------------------------------- + +flexrf_base_tx::flexrf_base_tx(usrp_basic_sptr _usrp, int which, int _power_on) + : flexrf_base(_usrp, which, _power_on) +{ + /* + @param usrp: instance of usrp.sink_c + @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. + */ + + if(which == 0) { + d_spi_enable = SPI_ENABLE_TX_A; + } + else { + d_spi_enable = SPI_ENABLE_TX_B; + } + + // power up the transmit side, but don't enable the mixer + usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff); + usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); + set_lo_offset(4e6); + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +flexrf_base_tx::~flexrf_base_tx() +{ + shutdown(); +} + + +void +flexrf_base_tx::shutdown() +{ + // fprintf(stderr, "flexrf_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown); + + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + // Power down and leave the T/R switch in the R position + usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); + + // Power down VCO/PLL + d_PD = 3; + + _write_control(_compute_control_reg()); + _enable_refclk(false); // turn off refclk + set_auto_tr(false); + } +} + +bool +flexrf_base_tx::set_auto_tr(bool on) +{ + bool ok = true; + if(on) { + ok &= set_atr_mask (RX_TXN | ENABLE); + ok &= set_atr_txval(0 | ENABLE); + ok &= set_atr_rxval(RX_TXN | 0); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + return ok; +} + +bool +flexrf_base_tx::set_enable(bool on) +{ + /* + Enable transmitter if on is true + */ + + int v; + int mask = RX_TXN | ENABLE; + if(on) { + v = ENABLE; + } + else { + v = RX_TXN; + } + return usrp()->write_io(d_which, v, mask); +} + +float +flexrf_base_tx::gain_min() +{ + return usrp()->pga_max(); +} + +float +flexrf_base_tx::gain_max() +{ + return usrp()->pga_max(); +} + +float +flexrf_base_tx::gain_db_per_step() +{ + return 1; +} + +bool +flexrf_base_tx::set_gain(float gain) +{ + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + return _set_pga(usrp()->pga_max()); +} + + +/**************************************************************************/ + + +flexrf_base_rx::flexrf_base_rx(usrp_basic_sptr _usrp, int which, int _power_on) + : flexrf_base(_usrp, which, _power_on) +{ + /* + @param usrp: instance of usrp.source_c + @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + if(which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff); + usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE), + (POWER_UP|RX2_RX1N|ENABLE)); + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + set_lo_offset(-4e6); +} + +flexrf_base_rx::~flexrf_base_rx() +{ + shutdown(); +} + +void +flexrf_base_rx::shutdown() +{ + // fprintf(stderr, "flexrf_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown); + + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + // Power down + usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE)); + + // Power down VCO/PLL + d_PD = 3; + + + // fprintf(stderr, "flexrf_base_rx::shutdown before _write_control\n"); + _write_control(_compute_control_reg()); + + // fprintf(stderr, "flexrf_base_rx::shutdown before _enable_refclk\n"); + _enable_refclk(false); // turn off refclk + + // fprintf(stderr, "flexrf_base_rx::shutdown before set_auto_tr\n"); + set_auto_tr(false); + + // fprintf(stderr, "flexrf_base_rx::shutdown after set_auto_tr\n"); + } +} + +bool +flexrf_base_rx::set_auto_tr(bool on) +{ + bool ok = true; + if(on) { + ok &= set_atr_mask (ENABLE); + ok &= set_atr_txval( 0); + ok &= set_atr_rxval(ENABLE); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + return true; +} + +bool +flexrf_base_rx::select_rx_antenna(int which_antenna) +{ + /* + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == 0) { + usrp()->write_io(d_which, 0,RX2_RX1N); + } + else if(which_antenna == 1) { + usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + return false; + // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } + return true; +} + +bool +flexrf_base_rx::select_rx_antenna(const std::string &which_antenna) +{ + /* + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == "TX/RX") { + usrp()->write_io(d_which, 0, RX2_RX1N); + } + else if(which_antenna == "RX2") { + usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + return false; + } + return true; +} + +bool +flexrf_base_rx::set_gain(float gain) +{ + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + + // clamp gain + gain = std::max(gain_min(), std::min(gain, gain_max())); + + float pga_gain, agc_gain; + float V_maxgain, V_mingain, V_fullscale, dac_value; + + float maxgain = gain_max() - usrp()->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= usrp()->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + V_maxgain = .2; + V_mingain = 1.2; + V_fullscale = 3.3; + dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + + return (usrp()->write_aux_dac(d_which, 0, int(dac_value)) + && _set_pga(int(pga_gain))); +} + +// ---------------------------------------------------------------- + + +_AD4360_common::_AD4360_common() +{ + // R-Register Common Values + d_R_RSV = 0; // bits 23,22 + d_BSC = 3; // bits 21,20 Div by 8 to be safe + d_TEST = 0; // bit 19 + d_LDP = 1; // bit 18 + d_ABP = 0; // bit 17,16 3ns + + // N-Register Common Values + d_N_RSV = 0; // bit 7 + + // Control Register Common Values + d_PD = 0; // bits 21,20 Normal operation + d_PL = 0; // bits 13,12 11mA + d_MTLD = 1; // bit 11 enabled + d_CPG = 0; // bit 10 CP setting 1 + d_CP3S = 0; // bit 9 Normal + d_PDP = 1; // bit 8 Positive + d_MUXOUT = 1; // bits 7:5 Digital Lock Detect + d_CR = 0; // bit 4 Normal + d_PC = 1; // bits 3,2 Core power 10mA +} + +_AD4360_common::~_AD4360_common() +{ +} + +bool +_AD4360_common::_compute_regs(double refclk_freq, double freq, int &retR, + int &retcontrol, int &retN, double &retfreq) +{ + /* + Determine values of R, control, and N registers, along with actual freq. + + @param freq: target frequency in Hz + @type freq: float + @returns: (R, control, N, actual_freq) + @rtype: tuple(int, int, int, float) + */ + + // Band-specific N-Register Values + //float phdet_freq = _refclk_freq()/d_R_DIV; + double phdet_freq = refclk_freq/d_R_DIV; + double desired_n = round(freq*d_freq_mult/phdet_freq); + double actual_freq = desired_n * phdet_freq; + int B = floor(desired_n/_prescaler()); + int A = desired_n - _prescaler()*B; + d_B_DIV = int(B); // bits 20:8 + d_A_DIV = int(A); // bit 6:2 + + //assert db_B_DIV >= db_A_DIV + if(d_B_DIV < d_A_DIV) { + retR = 0; + retcontrol = 0; + retN = 0; + retfreq = 0; + return false; + } + + int R = (d_R_RSV<<22) | (d_BSC<<20) | (d_TEST<<19) | + (d_LDP<<18) | (d_ABP<<16) | (d_R_DIV<<2); + + int control = _compute_control_reg(); + + int N = (d_DIVSEL<<23) | (d_DIV2<<22) | (d_CPGAIN<<21) | + (d_B_DIV<<8) | (d_N_RSV<<7) | (d_A_DIV<<2); + + retR = R; + retcontrol = control; + retN = N; + retfreq = actual_freq/d_freq_mult; + return true; +} + +int +_AD4360_common::_compute_control_reg() +{ + int control = (d_P<<22) | (d_PD<<20) | (d_CP2<<17) | (d_CP1<<14) + | (d_PL<<12) | (d_MTLD<<11) | (d_CPG<<10) | (d_CP3S<<9) | (d_PDP<<8) + | (d_MUXOUT<<5) | (d_CR<<4) | (d_PC<<2); + + return control; +} + +int +_AD4360_common::_refclk_divisor() +{ + /* + Return value to stick in REFCLK_DIVISOR register + */ + return 1; +} + +int +_AD4360_common::_prescaler() +{ + if(d_P == 0) { + return 8; + } + else if(d_P == 1) { + return 16; + } + else { + return 32; + } +} + +//---------------------------------------------------------------------- + +_2400_common::_2400_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 + d_CP1 = 7; // bits 16:14 + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 1; +} + +double +_2400_common::freq_min() +{ + return 2300e6; +} + +double +_2400_common::freq_max() +{ + return 2700e6; +} + +//---------------------------------------------------------------------- + +_1200_common::_1200_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 1; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 2; +} + +double +_1200_common::freq_min() +{ + return 1150e6; +} + +double +_1200_common::freq_max() +{ + return 1350e6; +} + +//------------------------------------------------------------------------- + +_1800_common::_1800_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_freq_mult = 1; + d_CPGAIN = 0; // bit 21 +} + +double +_1800_common::freq_min() +{ + return 1600e6; +} + +double +_1800_common::freq_max() +{ + return 2000e6; +} + +//------------------------------------------------------------------------- + +_900_common::_900_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq + + // Band-specific C-Register values + d_P = 1; // bits 23,22 Div by 16/17 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 1; // bit 22 + d_freq_mult = 2; + d_CPGAIN = 0; // bit 21 +} + +double +_900_common::freq_min() +{ + return 800e6; +} + +double +_900_common::freq_max() +{ + return 1000e6; +} + +//------------------------------------------------------------------------- + +_400_common::_400_common() + : _AD4360_common() +{ + // Band-specific R-Register Values + d_R_DIV = 16; // bits 15:2 + + // Band-specific C-Register values + d_P = 0; // bits 23,22 Div by 8/9 + d_CP2 = 7; // bits 19:17 1.25 mA + d_CP1 = 7; // bits 16:14 1.25 mA + + // Band specifc N-Register Values These are different for TX/RX + d_DIVSEL = 0; // bit 23 + d_freq_mult = 2; + + d_CPGAIN = 0; // bit 21 +} + +double +_400_common::freq_min() +{ + return 400e6; +} + +double +_400_common::freq_max() +{ + return 500e6; +} + +_400_tx::_400_tx() + : _400_common() +{ + d_DIV2 = 1; // bit 22 +} + +_400_rx::_400_rx() + : _400_common() +{ + d_DIV2 = 0; // bit 22 // RX side has built-in DIV2 in AD8348 +} + +//------------------------------------------------------------ + +db_flexrf_2400_tx::db_flexrf_2400_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _2400_common(); +} + +db_flexrf_2400_tx::~db_flexrf_2400_tx() +{ +} + +bool +db_flexrf_2400_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + +db_flexrf_2400_rx::db_flexrf_2400_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _2400_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_2400_rx::~db_flexrf_2400_rx() +{ +} + +float +db_flexrf_2400_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_2400_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_2400_rx::gain_db_per_step() +{ + return 0.05; +} + + +bool +db_flexrf_2400_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_2400_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + +//------------------------------------------------------------ + + +db_flexrf_1200_tx::db_flexrf_1200_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _1200_common(); +} + +db_flexrf_1200_tx::~db_flexrf_1200_tx() +{ +} + +bool +db_flexrf_1200_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + + +db_flexrf_1200_rx::db_flexrf_1200_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _1200_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_1200_rx::~db_flexrf_1200_rx() +{ +} + +float +db_flexrf_1200_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_1200_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_1200_rx::gain_db_per_step() +{ + return 0.05; +} + +bool +db_flexrf_1200_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_1200_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + +//------------------------------------------------------------ + + +db_flexrf_1800_tx::db_flexrf_1800_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _1800_common(); +} + +db_flexrf_1800_tx::~db_flexrf_1800_tx() +{ +} + +bool +db_flexrf_1800_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + +db_flexrf_1800_rx::db_flexrf_1800_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _1800_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_1800_rx::~db_flexrf_1800_rx() +{ +} + + +float +db_flexrf_1800_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_1800_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_1800_rx::gain_db_per_step() +{ + return 0.05; +} + +bool +db_flexrf_1800_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_1800_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + +//------------------------------------------------------------ + + +db_flexrf_900_tx::db_flexrf_900_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which) +{ + d_common = new _900_common(); +} + +db_flexrf_900_tx::~db_flexrf_900_tx() +{ +} + +bool +db_flexrf_900_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + +db_flexrf_900_rx::db_flexrf_900_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which) +{ + d_common = new _900_common(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_900_rx::~db_flexrf_900_rx() +{ +} + +float +db_flexrf_900_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_900_rx::gain_max() +{ + return usrp()->pga_max()+70; +} + +float +db_flexrf_900_rx::gain_db_per_step() +{ + return 0.05; +} + +bool +db_flexrf_900_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_900_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + +//------------------------------------------------------------ + + +db_flexrf_400_tx::db_flexrf_400_tx(usrp_basic_sptr usrp, int which) + : flexrf_base_tx(usrp, which, POWER_UP) +{ + d_common = new _400_tx(); +} + +db_flexrf_400_tx::~db_flexrf_400_tx() +{ +} + +bool +db_flexrf_400_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + + + +db_flexrf_400_rx::db_flexrf_400_rx(usrp_basic_sptr usrp, int which) + : flexrf_base_rx(usrp, which, POWER_UP) +{ + d_common = new _400_rx(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_flexrf_400_rx::~db_flexrf_400_rx() +{ +} + +float +db_flexrf_400_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_flexrf_400_rx::gain_max() +{ + return usrp()->pga_max()+45; +} + +float + +db_flexrf_400_rx::gain_db_per_step() +{ + return 0.035; +} + + +bool +db_flexrf_400_rx::i_and_q_swapped() +{ + return true; +} + +bool +db_flexrf_400_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); +} + diff --git a/usrp/host/lib/db_flexrf_mimo.cc b/usrp/host/lib/db_flexrf_mimo.cc new file mode 100644 index 00000000..e2db5cd1 --- /dev/null +++ b/usrp/host/lib/db_flexrf_mimo.cc @@ -0,0 +1,276 @@ +/* + * 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 +#include +#include +#include +#include + + +db_flexrf_2400_tx_mimo_a::db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_2400_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_2400_rx_mimo_a::db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_2400_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_2400_tx_mimo_b::db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_2400_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_2400_rx_mimo_b::db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_2400_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_2400_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1800_tx_mimo_a::db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1800_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1800_rx_mimo_a::db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1800_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1800_tx_mimo_b::db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1800_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1800_rx_mimo_b::db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1800_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1800_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1200_tx_mimo_a::db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1200_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1200_rx_mimo_a::db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_1200_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_1200_tx_mimo_b::db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1200_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_1200_rx_mimo_b::db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_1200_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_1200_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_900_tx_mimo_a::db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_900_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_900_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_900_rx_mimo_a::db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_900_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_900_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_900_tx_mimo_b::db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_900_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_900_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_900_rx_mimo_b::db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_900_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int db_flexrf_900_rx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_400_tx_mimo_a::db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_400_tx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_400_tx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_400_rx_mimo_a::db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which) + : db_flexrf_400_rx(usrp, which) +{ + _enable_refclk(true); + d_common->R_DIV(1); +} + +int +db_flexrf_400_rx_mimo_a::_refclk_divisor() +{ + return 16; +} + +db_flexrf_400_tx_mimo_b::db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_400_tx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_400_tx_mimo_b::_refclk_divisor() +{ + return 1; +} + +db_flexrf_400_rx_mimo_b::db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which) + : db_flexrf_400_rx(usrp, which) +{ + d_common->R_DIV(16); +} + +int +db_flexrf_400_rx_mimo_b::_refclk_divisor() +{ + return 1; +} diff --git a/usrp/host/lib/db_tv_rx.cc b/usrp/host/lib/db_tv_rx.cc new file mode 100644 index 00000000..494ee7a1 --- /dev/null +++ b/usrp/host/lib/db_tv_rx.cc @@ -0,0 +1,274 @@ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include + +/*****************************************************************************/ + +int +control_byte_1(bool fast_tuning_p, int reference_divisor) +{ + int c = 0x88; + if(fast_tuning_p) { + c |= 0x40; + } + + if(reference_divisor == 512) { + c |= 0x3 << 1; + } + else if(reference_divisor == 640) { + c |= 0x0 << 1; + } + else if(reference_divisor == 1024) { + c |= 0x1 << 1; + } + else { + assert(0); + } + + return c; +} + +int +control_byte_2(double target_freq, bool shutdown_tx_PGA) +{ + int c; + if(target_freq < 158e6) { // VHF low + c = 0xa0; + } + else if(target_freq < 464e6) { // VHF high + c = 0x90; + } + else { // UHF + c = 0x30; + } + + if(shutdown_tx_PGA) { + c |= 0x08; + } + + return c; +} + + +/*****************************************************************************/ + + +db_tv_rx::db_tv_rx(usrp_basic_sptr usrp, int which, + double first_IF, double second_IF) + : db_base(usrp, which) +{ + // Handler for Tv Rx daughterboards. + // + // @param usrp: instance of usrp.source_c + // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively + + if(which == 0) { + d_i2c_addr = 0x60; + } + else { + d_i2c_addr = 0x61; + } + + d_first_IF = first_IF; + d_second_IF = second_IF; + d_reference_divisor = 640; + d_fast_tuning = false; + d_inverted = false; // FIXME get rid of this + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain + + bypass_adc_buffers(false); +} + +db_tv_rx::~db_tv_rx() +{ +} + +// Gain setting +void +db_tv_rx::_set_rfagc(float gain) +{ + float voltage; + + assert(gain <= 60 && gain >= 0); + // FIXME this has a 0.5V step between gain = 60 and gain = 59. + // Why are there two cases instead of a single linear case? + if(gain == 60) { + voltage = 4; + } + else { + voltage = gain/60.0 * 2.25 + 1.25; + } + int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 1, dacword); +} + +void +db_tv_rx::_set_ifagc(float gain) +{ + float voltage; + + assert(gain <= 35 && gain >= 0); + voltage = gain/35.0 * 2.1 + 1.4; + int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain + + assert(dacword>=0 && dacword<4096); + usrp()->write_aux_dac(d_which, 0, dacword); +} + +void +db_tv_rx::_set_pga(float pga_gain) +{ + assert(pga_gain >=0 && pga_gain <=20); + if(d_which == 0) { + usrp()->set_pga(0, pga_gain); + } + else { + usrp()->set_pga (2, pga_gain); + } +} + +double +db_tv_rx::freq_min() +{ + return 50e6; +} + +double +db_tv_rx::freq_max() +{ + return 860e6; +} + +struct freq_result_t +db_tv_rx::set_freq(double target_freq) +{ + // Set the frequency. + // + // @param freq: target RF frequency in Hz + // @type freq: double + // + // @returns (ok, actual_baseband_freq) where: + // ok is True or False and indicates success or failure, + // actual_baseband_freq is RF frequency that corresponds to DC in the IF. + + freq_result_t args = {false, 0}; + + double fmin = freq_min(); + double fmax = freq_max(); + if((target_freq < fmin) || (target_freq > fmax)) { + return args; + } + + double target_lo_freq = target_freq + d_first_IF; // High side mixing + double f_ref = 4.0e6 / (double)(d_reference_divisor); // frequency steps + + int divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8)); + double actual_lo_freq = (f_ref * 8 * divisor); + double actual_freq = actual_lo_freq - d_first_IF; + + if((divisor & ~0x7fff) != 0) { // must be 15-bits or less + return args; + } + + // build i2c command string + std::vector buf(4); + buf[0] = (divisor >> 8) & 0xff; // DB1 + buf[1] = divisor & 0xff; // DB2 + buf[2] = control_byte_1(d_fast_tuning, d_reference_divisor); + buf[3] = control_byte_2(actual_freq, true); + + args.ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); + args.baseband_freq = actual_freq - d_second_IF; + return args; +} + +float +db_tv_rx::gain_min() +{ + return 0; +} + +float +db_tv_rx::gain_max() +{ + return 115; +} + +float +db_tv_rx::gain_db_per_step() +{ + return 1; +} + +bool +db_tv_rx::set_gain(float gain) +{ + // Set the gain. + // + // @param gain: gain in decibels + // @returns True/False + + float rfgain, ifgain, pgagain; + + assert(gain>=0 && gain<=115); + if(gain>60) { + rfgain = 60; + gain = gain - 60; + } + else { + rfgain = gain; + gain = 0; + } + + if(gain > 35) { + ifgain = 35; + gain = gain - 35; + } + else { + ifgain = gain; + gain = 0; + } + + pgagain = gain; + _set_rfagc(rfgain); + _set_ifagc(ifgain); + _set_pga(pgagain); + + return true; +} + +bool +db_tv_rx::is_quadrature() +{ + // Return True if this board requires both I & Q analog channels. + return false; +} + +bool +db_tv_rx::spectrum_inverted() +{ + // The 43.75 MHz version is inverted + return d_inverted; +} diff --git a/usrp/host/lib/db_util.cc b/usrp/host/lib/db_util.cc new file mode 100644 index 00000000..4b46383b --- /dev/null +++ b/usrp/host/lib/db_util.cc @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +std::string +int_seq_to_str(std::vector &seq) +{ + //convert a sequence of integers into a string + + std::stringstream str; + std::vector::iterator i; + for(i = seq.begin(); i != seq.end(); i++) { + str << char((unsigned int)*i); + } + return str.str(); +} + +std::vector +str_to_int_seq(std::string str) +{ + //convert a string to a list of integers + std::vector seq; + std::vector::iterator sitr; + std::string::iterator i; + for(i=str.begin(); i != str.end(); i++) { + int a = (int)(*i); + seq.push_back(a); + } + return seq; +} + diff --git a/usrp/host/lib/db_util.h b/usrp/host/lib/db_util.h new file mode 100644 index 00000000..e07abb60 --- /dev/null +++ b/usrp/host/lib/db_util.h @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_DB_UTIL_H +#define INCLUDED_DB_UTIL_H + +#include +#include + +std::string int_seq_to_str(std::vector &seq); +std::vector str_to_int_seq(std::string str); + +#endif /* INCLUDED_DB_UTIL_H */ diff --git a/usrp/host/lib/db_xcvr2450.cc b/usrp/host/lib/db_xcvr2450.cc new file mode 100644 index 00000000..408a0558 --- /dev/null +++ b/usrp/host/lib/db_xcvr2450.cc @@ -0,0 +1,791 @@ +// +// 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 +#include +#include +#include +#include +#include + +#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 value; + + xcvr2450_table_entry(const xcvr2450_key &_key, boost::weak_ptr _value) + : key(_key), value(_value) {} +}; + +typedef std::vector 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); +} diff --git a/usrp/host/lib/dump_data.py b/usrp/host/lib/dump_data.py new file mode 100755 index 00000000..034586d8 --- /dev/null +++ b/usrp/host/lib/dump_data.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 + + + diff --git a/usrp/host/lib/fusb.cc b/usrp/host/lib/fusb.cc new file mode 100644 index 00000000..6e4358f5 --- /dev/null +++ b/usrp/host/lib/fusb.cc @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 + + +// ------------------------------------------------------------------------ +// device handle +// ------------------------------------------------------------------------ + +fusb_devhandle::fusb_devhandle (usb_dev_handle *udh) + : d_udh (udh) +{ + // that's it +}; + +fusb_devhandle::~fusb_devhandle () +{ + // nop +} + +// ------------------------------------------------------------------------ +// end point handle +// ------------------------------------------------------------------------ + +fusb_ephandle::fusb_ephandle (int endpoint, bool input_p, + int block_size, int nblocks) + : d_endpoint (endpoint), d_input_p (input_p), + d_block_size (block_size), d_nblocks (nblocks), d_started (false) +{ + // that't it +} + +fusb_ephandle::~fusb_ephandle () +{ + // nop +} diff --git a/usrp/host/lib/fusb.h b/usrp/host/lib/fusb.h new file mode 100644 index 00000000..769e51cc --- /dev/null +++ b/usrp/host/lib/fusb.h @@ -0,0 +1,138 @@ +/* -*- 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_ */ diff --git a/usrp/host/lib/fusb_darwin.cc b/usrp/host/lib/fusb_darwin.cc new file mode 100644 index 00000000..737387b8 --- /dev/null +++ b/usrp/host/lib/fusb_darwin.cc @@ -0,0 +1,572 @@ +/* -*- 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 +#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 (NUM_QUEUE_ITEMS * d_bufLenBytes, + !d_input_p, d_input_p); + +// create the queue + d_queue = new circular_linked_list (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 (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(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(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(refCon); + fusb_ephandle_darwin* This = static_cast(l_both->This ()); + s_node_ptr l_node = l_both->node (); + circular_buffer* 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(refCon); + fusb_ephandle_darwin* This = static_cast(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); +} diff --git a/usrp/host/lib/fusb_darwin.h b/usrp/host/lib/fusb_darwin.h new file mode 100644 index 00000000..bb717b58 --- /dev/null +++ b/usrp/host/lib/fusb_darwin.h @@ -0,0 +1,215 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio. + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 +#include "fusb.h" +#include +#include +#include +#include +#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_node_ptr; +typedef circular_linked_list* s_queue_ptr; +typedef s_both* 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* d_buffer; + UInt32 d_bufLenBytes; + mld_mutex_ptr d_readRunning; + mld_condition_ptr d_runBlock, d_readBlock; + +// CREATORS + + fusb_ephandle_darwin (fusb_devhandle_darwin *dh, int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + virtual ~fusb_ephandle_darwin (); + +// MANIPULATORS + + virtual bool start (); //!< begin streaming i/o + virtual bool stop (); //!< stop streaming i/o + + /*! + * \returns \p nbytes if write was successfully enqueued, else -1. + * Will block if no free buffers available. + */ + virtual int write (const void* buffer, int nbytes); + + /*! + * \returns number of bytes read or -1 if error. + * number of bytes read will be <= nbytes. + * Will block if no input available. + */ + virtual int read (void* buffer, int nbytes); + + /* + * abort any pending IO transfers + */ + void abort (); + + /* + * block until all outstanding writes have completed + */ + virtual void wait_for_completion (); +}; + +#endif /* _FUSB_DARWIN_H_ */ diff --git a/usrp/host/lib/fusb_generic.cc b/usrp/host/lib/fusb_generic.cc new file mode 100644 index 00000000..0958716d --- /dev/null +++ b/usrp/host/lib/fusb_generic.cc @@ -0,0 +1,108 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + + +static const int USB_TIMEOUT = 1000; // in milliseconds + + +fusb_devhandle_generic::fusb_devhandle_generic (usb_dev_handle *udh) + : fusb_devhandle (udh) +{ + // that's it +} + +fusb_devhandle_generic::~fusb_devhandle_generic () +{ + // nop +} + +fusb_ephandle * +fusb_devhandle_generic::make_ephandle (int endpoint, bool input_p, + int block_size, int nblocks) +{ + return new fusb_ephandle_generic (this, endpoint, input_p, + block_size, nblocks); +} + +// ---------------------------------------------------------------- + +fusb_ephandle_generic::fusb_ephandle_generic (fusb_devhandle_generic *dh, + int endpoint, bool input_p, + int block_size, int nblocks) + : fusb_ephandle (endpoint, input_p, block_size, nblocks), + d_devhandle (dh) +{ + // that's it +} + +fusb_ephandle_generic::~fusb_ephandle_generic () +{ + // nop +} + +bool +fusb_ephandle_generic::start () +{ + d_started = true; + return true; +} + +bool +fusb_ephandle_generic::stop () +{ + d_started = false; + return true; +} + +int +fusb_ephandle_generic::write (const void *buffer, int nbytes) +{ + if (!d_started) // doesn't matter here, but keeps semantics constant + return -1; + + if (d_input_p) + return -1; + + return usb_bulk_write (d_devhandle->get_usb_dev_handle (), + d_endpoint, (char *) buffer, nbytes, USB_TIMEOUT); +} + +int +fusb_ephandle_generic::read (void *buffer, int nbytes) +{ + if (!d_started) // doesn't matter here, but keeps semantics constant + return -1; + + if (!d_input_p) + return -1; + + return usb_bulk_read (d_devhandle->get_usb_dev_handle (), + d_endpoint|USB_ENDPOINT_IN, (char *) buffer, nbytes, + USB_TIMEOUT); +} diff --git a/usrp/host/lib/fusb_generic.h b/usrp/host/lib/fusb_generic.h new file mode 100644 index 00000000..b9aef273 --- /dev/null +++ b/usrp/host/lib/fusb_generic.h @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 + +/*! + * \brief generic implementation of fusb_devhandle using only libusb + */ +class fusb_devhandle_generic : public fusb_devhandle +{ +public: + // CREATORS + fusb_devhandle_generic (usb_dev_handle *udh); + virtual ~fusb_devhandle_generic (); + + // MANIPULATORS + virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); +}; + + +/*! + * \brief generic implementation of fusb_ephandle using only libusb + */ +class fusb_ephandle_generic : public fusb_ephandle +{ +private: + fusb_devhandle_generic *d_devhandle; + +public: + // CREATORS + fusb_ephandle_generic (fusb_devhandle_generic *dh, int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + virtual ~fusb_ephandle_generic (); + + // MANIPULATORS + + virtual bool start (); //!< begin streaming i/o + virtual bool stop (); //!< stop streaming i/o + + /*! + * \returns \p nbytes if write was successfully enqueued, else -1. + * Will block if no free buffers available. + */ + virtual int write (const void *buffer, int nbytes); + + /*! + * \returns number of bytes read or -1 if error. + * number of bytes read will be <= nbytes. + * Will block if no input available. + */ + virtual int read (void *buffer, int nbytes); + + /* + * block until all outstanding writes have completed + */ + virtual void wait_for_completion () { }; +}; + +#endif /* _FUSB_GENERIC_H_ */ + diff --git a/usrp/host/lib/fusb_linux.cc b/usrp/host/lib/fusb_linux.cc new file mode 100644 index 00000000..6c484569 --- /dev/null +++ b/usrp/host/lib/fusb_linux.cc @@ -0,0 +1,692 @@ +/* -*- 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 +#include // libusb header +#include +#ifdef HAVE_LINUX_COMPILER_H +#include +#endif +#include // interface to kernel portion of user mode usb driver +#include +#include +#include +#include +#include +#include +#include + +#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::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::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::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; +} + // ------------------------------------------------------------------------ +// 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; +} diff --git a/usrp/host/lib/fusb_linux.h b/usrp/host/lib/fusb_linux.h new file mode 100644 index 00000000..107e1af7 --- /dev/null +++ b/usrp/host/lib/fusb_linux.h @@ -0,0 +1,116 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 +#include + +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 d_pending_rqsts; + + void pending_add (usbdevfs_urb *urb); + bool pending_remove (usbdevfs_urb *urb); + usbdevfs_urb * pending_get (); + + +public: + // CREATORS + fusb_devhandle_linux (usb_dev_handle *udh); + virtual ~fusb_devhandle_linux (); + + // MANIPULATORS + virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + + // internal use only + bool _submit_urb (usbdevfs_urb *urb); + bool _cancel_urb (usbdevfs_urb *urb); + void _cancel_pending_rqsts (fusb_ephandle_linux *eph); + bool _reap (bool ok_to_block_p); + void _wait_for_completion (); +}; + + /*! + * \brief linux specific implementation of fusb_ephandle using usbdevice_fs + */ + +class fusb_ephandle_linux : public fusb_ephandle { +private: + fusb_devhandle_linux *d_devhandle; + std::list d_free_list; + std::list d_completed_list; + usbdevfs_urb *d_write_work_in_progress; + unsigned char *d_write_buffer; + usbdevfs_urb *d_read_work_in_progress; + unsigned char *d_read_buffer; + unsigned char *d_read_buffer_end; + + usbdevfs_urb *get_write_work_in_progress (); + void reap_complete_writes (); + bool reload_read_buffer (); + bool submit_urb (usbdevfs_urb *urb); + +public: + fusb_ephandle_linux (fusb_devhandle_linux *dh, int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + virtual ~fusb_ephandle_linux (); + + virtual bool start (); //!< begin streaming i/o + virtual bool stop (); //!< stop streaming i/o + + /*! + * \returns \p nbytes if write was successfully enqueued, else -1. + * Will block if no free buffers available. + */ + virtual int write (const void *buffer, int nbytes); + + /*! + * \returns number of bytes read or -1 if error. + * number of bytes read will be <= nbytes. + * Will block if no input available. + */ + virtual int read (void *buffer, int nbytes); + + /* + * block until all outstanding writes have completed + */ + virtual void wait_for_completion (); + + // internal use only + void free_list_add (usbdevfs_urb *urb); + void completed_list_add (usbdevfs_urb *urb); + usbdevfs_urb *free_list_get (); // pop and return head of list or 0 + usbdevfs_urb *completed_list_get (); // pop and return head of list or 0 +}; + +#endif /* _FUSB_LINUX_H_ */ diff --git a/usrp/host/lib/fusb_ra_wb.cc b/usrp/host/lib/fusb_ra_wb.cc new file mode 100644 index 00000000..699a34b3 --- /dev/null +++ b/usrp/host/lib/fusb_ra_wb.cc @@ -0,0 +1,258 @@ +/* -*- 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 +#include + +#include +#include +#include + +#include +#include + +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); + } +} diff --git a/usrp/host/lib/fusb_ra_wb.h b/usrp/host/lib/fusb_ra_wb.h new file mode 100644 index 00000000..233976ab --- /dev/null +++ b/usrp/host/lib/fusb_ra_wb.h @@ -0,0 +1,84 @@ +/* -*- 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 + +/*! + * \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_ */ + diff --git a/usrp/host/lib/fusb_sysconfig_darwin.cc b/usrp/host/lib/fusb_sysconfig_darwin.cc new file mode 100644 index 00000000..4d19d129 --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_darwin.cc @@ -0,0 +1,49 @@ +/* -*- 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 +#include + +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; +} + diff --git a/usrp/host/lib/fusb_sysconfig_generic.cc b/usrp/host/lib/fusb_sysconfig_generic.cc new file mode 100644 index 00000000..58baba5a --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_generic.cc @@ -0,0 +1,48 @@ +/* -*- 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 +#include + +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; +} diff --git a/usrp/host/lib/fusb_sysconfig_linux.cc b/usrp/host/lib/fusb_sysconfig_linux.cc new file mode 100644 index 00000000..3c2f5937 --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_linux.cc @@ -0,0 +1,49 @@ +/* -*- 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 +#include + +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; +} diff --git a/usrp/host/lib/fusb_sysconfig_ra_wb.cc b/usrp/host/lib/fusb_sysconfig_ra_wb.cc new file mode 100644 index 00000000..9da831fd --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_ra_wb.cc @@ -0,0 +1,52 @@ +/* -*- 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 +#include + +//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; +} diff --git a/usrp/host/lib/fusb_sysconfig_win32.cc b/usrp/host/lib/fusb_sysconfig_win32.cc new file mode 100644 index 00000000..16eaaa64 --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_win32.cc @@ -0,0 +1,48 @@ +/* -*- 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 +#include + +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; +} diff --git a/usrp/host/lib/fusb_win32.cc b/usrp/host/lib/fusb_win32.cc new file mode 100644 index 00000000..8900576d --- /dev/null +++ b/usrp/host/lib/fusb_win32.cc @@ -0,0 +1,266 @@ +/* -*- 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 +#include +#include +#include +#include + +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 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 + +/*! + * \brief win32 implementation of fusb_devhandle using libusb-win32 + */ +class fusb_devhandle_win32 : public fusb_devhandle +{ +public: + // CREATORS + fusb_devhandle_win32 (usb_dev_handle *udh); + virtual ~fusb_devhandle_win32 (); + + // MANIPULATORS + virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); +}; + + +/*! + * \brief win32 implementation of fusb_ephandle using libusb-win32 + */ +class fusb_ephandle_win32 : public fusb_ephandle +{ +private: + fusb_devhandle_win32 *d_devhandle; + + unsigned d_curr; + unsigned d_outstanding_write; + int d_output_short; + int d_input_leftover; + void ** d_context; + char * d_buffer; + +public: + // CREATORS + fusb_ephandle_win32 (fusb_devhandle_win32 *dh, int endpoint, bool input_p, + int block_size = 0, int nblocks = 0); + virtual ~fusb_ephandle_win32 (); + + // MANIPULATORS + + virtual bool start (); //!< begin streaming i/o + virtual bool stop (); //!< stop streaming i/o + + /*! + * \returns \p nbytes if write was successfully enqueued, else -1. + * Will block if no free buffers available. + */ + virtual int write (const void *buffer, int nbytes); + + /*! + * \returns number of bytes read or -1 if error. + * number of bytes read will be <= nbytes. + * Will block if no input available. + */ + virtual int read (void *buffer, int nbytes); + + /* + * block until all outstanding writes have completed + */ + virtual void wait_for_completion (); +}; + +#endif /* _FUSB_WIN32_H_ */ + diff --git a/usrp/host/lib/gen_usrp_dbid.py b/usrp/host/lib/gen_usrp_dbid.py new file mode 100755 index 00000000..c7d3770c --- /dev/null +++ b/usrp/host/lib/gen_usrp_dbid.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +import sys +import os +import os.path +import re +from optparse import OptionParser + +def write_header(f, comment_char): + f.write(comment_char); f.write('\n') + f.write(comment_char); f.write(' Machine generated by gen_usrp_dbid.py from usrp_dbid.dat\n') + f.write(comment_char); f.write(' Do not edit by hand. All edits will be overwritten.\n') + f.write(comment_char); f.write('\n') + f.write('\n') + +def gen_dbid_py(r): + f = open('usrp_dbid.py', 'w') + comment_char = '#' + write_header(f, comment_char) + f.write(comment_char); f.write('\n') + f.write(comment_char); f.write(" USRP Daughterboard ID's\n") + f.write(comment_char); f.write('\n') + f.write('\n') + for x in r: + f.write('%-16s = %s\n' % (x[1], x[2])) + +def gen_dbid_h(r): + f = open('../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 +#include +#include + +#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 ""; + + if (dbid == -2) + return ""; + + for (unsigned i = 0; i < NELEM (dbid_map); i++) + if (dbid == dbid_map[i].dbid) + return dbid_map[i].name; + + char tmp[64]; + snprintf (tmp, sizeof (tmp), "Unknown (0x%04x)", dbid); + return tmp; +} +''' + f.write(head) + for x in r: + f.write(' { %-27s "%s" },\n' % ( + 'USRP_DBID_' + x[1] + ',', x[0])) + f.write(tail) + +def gen_all(src_filename): + src_file = open(src_filename, 'r') + r = [] + for line in src_file: + line = line.strip() + line = re.sub(r'\s*#.*$','', line) + if len(line) == 0: + continue + mo = re.match('"([^"]+)"\s*(0x[0-9a-fA-F]+)', line) + if mo: + str_name = mo.group(1) + id_name = str_name.upper().replace(' ', '_') + id_val = mo.group(2) + r.append((str_name, id_name, id_val)) + #sys.stdout.write('%-16s\t%-16s\t%s\n' % ('"'+str_name+'"', id_name, id_val)) + + gen_dbid_h(r) + gen_dbid_py(r) + gen_dbid_cc(r) + + +def main(): + usage = "usage: %prog [options] usrp_dbid.dat" + parser = OptionParser(usage=usage) + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + sys.exit(1) + + gen_all(args[0]) + +if __name__ == '__main__': + main() diff --git a/usrp/host/lib/inband/Makefile.am b/usrp/host/lib/inband/Makefile.am deleted file mode 100644 index 650a25ff..00000000 --- a/usrp/host/lib/inband/Makefile.am +++ /dev/null @@ -1,114 +0,0 @@ -# -# 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 diff --git a/usrp/host/lib/inband/dump_packets.py b/usrp/host/lib/inband/dump_packets.py deleted file mode 100755 index 23736240..00000000 --- a/usrp/host/lib/inband/dump_packets.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/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() diff --git a/usrp/host/lib/inband/gen_test_packets.py b/usrp/host/lib/inband/gen_test_packets.py deleted file mode 100755 index 2ee64638..00000000 --- a/usrp/host/lib/inband/gen_test_packets.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/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")) diff --git a/usrp/host/lib/inband/qa_inband.cc b/usrp/host/lib/inband/qa_inband.cc deleted file mode 100644 index 6f33a6ea..00000000 --- a/usrp/host/lib/inband/qa_inband.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- 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 -#include -#include - -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; -} diff --git a/usrp/host/lib/inband/qa_inband.h b/usrp/host/lib/inband/qa_inband.h deleted file mode 100644 index ab8f7f25..00000000 --- a/usrp/host/lib/inband/qa_inband.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- 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 - -//! 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 */ diff --git a/usrp/host/lib/inband/qa_inband_packet_prims.cc b/usrp/host/lib/inband/qa_inband_packet_prims.cc deleted file mode 100644 index d9bbbec2..00000000 --- a/usrp/host/lib/inband/qa_inband_packet_prims.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include // 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); - -} -////////////////////////////////////////////////////////////////////// diff --git a/usrp/host/lib/inband/qa_inband_packet_prims.h b/usrp/host/lib/inband/qa_inband_packet_prims.h deleted file mode 100644 index 71c0d737..00000000 --- a/usrp/host/lib/inband/qa_inband_packet_prims.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- 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 -#include - -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 */ diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc deleted file mode 100644 index 6049a8a8..00000000 --- a/usrp/host/lib/inband/qa_inband_usrp_server.cc +++ /dev/null @@ -1,1575 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -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 d_tx_chans; - std::vector 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; isend(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)); -} diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.h b/usrp/host/lib/inband/qa_inband_usrp_server.h deleted file mode 100644 index 52a4a0b0..00000000 --- a/usrp/host/lib/inband/qa_inband_usrp_server.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- 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 -#include - -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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_channel.h b/usrp/host/lib/inband/symbols_usrp_channel.h deleted file mode 100644 index a0114cf3..00000000 --- a/usrp/host/lib/inband/symbols_usrp_channel.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_interface_cs.h b/usrp/host/lib/inband/symbols_usrp_interface_cs.h deleted file mode 100644 index 72c8fcc9..00000000 --- a/usrp/host/lib/inband/symbols_usrp_interface_cs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_low_level_cs.h b/usrp/host/lib/inband/symbols_usrp_low_level_cs.h deleted file mode 100644 index a7260603..00000000 --- a/usrp/host/lib/inband/symbols_usrp_low_level_cs.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_rx.h b/usrp/host/lib/inband/symbols_usrp_rx.h deleted file mode 100644 index 07d58a3f..00000000 --- a/usrp/host/lib/inband/symbols_usrp_rx.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_rx_cs.h b/usrp/host/lib/inband/symbols_usrp_rx_cs.h deleted file mode 100644 index bf4f0338..00000000 --- a/usrp/host/lib/inband/symbols_usrp_rx_cs.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_server_cs.h b/usrp/host/lib/inband/symbols_usrp_server_cs.h deleted file mode 100644 index e612e24e..00000000 --- a/usrp/host/lib/inband/symbols_usrp_server_cs.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_tx.h b/usrp/host/lib/inband/symbols_usrp_tx.h deleted file mode 100644 index 4e58e2cf..00000000 --- a/usrp/host/lib/inband/symbols_usrp_tx.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/symbols_usrp_tx_cs.h b/usrp/host/lib/inband/symbols_usrp_tx_cs.h deleted file mode 100644 index d02ef1d2..00000000 --- a/usrp/host/lib/inband/symbols_usrp_tx_cs.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- 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 - -// 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 */ diff --git a/usrp/host/lib/inband/test_inband.cc b/usrp/host/lib/inband/test_inband.cc deleted file mode 100644 index 77cdca55..00000000 --- a/usrp/host/lib/inband/test_inband.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- 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 -#include - -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; -} diff --git a/usrp/host/lib/inband/usb_packet.py b/usrp/host/lib/inband/usb_packet.py deleted file mode 100644 index 6dfcf863..00000000 --- a/usrp/host/lib/inband/usb_packet.py +++ /dev/null @@ -1,115 +0,0 @@ -# -# Copyright 2007 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.cc b/usrp/host/lib/inband/usrp_inband_usb_packet.cc deleted file mode 100644 index 72bc45cc..00000000 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.cc +++ /dev/null @@ -1,793 +0,0 @@ -/* -*- 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 -#endif - -#include - -#include -#include -#include -#include - -/*! - * \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; - - } -} - diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.h b/usrp/host/lib/inband/usrp_inband_usb_packet.h deleted file mode 100644 index 6f1a3feb..00000000 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.h +++ /dev/null @@ -1,240 +0,0 @@ -/* -*- 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 -#include -#include -#include - -#include - -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<> 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 diff --git a/usrp/host/lib/inband/usrp_interface.mbh b/usrp/host/lib/inband/usrp_interface.mbh deleted file mode 100644 index ad0f78b4..00000000 --- a/usrp/host/lib/inband/usrp_interface.mbh +++ /dev/null @@ -1,88 +0,0 @@ -;; -*- 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 - ) - ) diff --git a/usrp/host/lib/inband/usrp_rx.cc b/usrp/host/lib/inband/usrp_rx.cc deleted file mode 100644 index fe9486cf..00000000 --- a/usrp/host/lib/inband/usrp_rx.cc +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- 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 -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -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(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); diff --git a/usrp/host/lib/inband/usrp_rx.h b/usrp/host/lib/inband/usrp_rx.h deleted file mode 100644 index 1006235b..00000000 --- a/usrp/host/lib/inband/usrp_rx.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- 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 -#include -#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 */ - diff --git a/usrp/host/lib/inband/usrp_rx_stub.cc b/usrp/host/lib/inband/usrp_rx_stub.cc deleted file mode 100644 index e5c454d2..00000000 --- a/usrp/host/lib/inband/usrp_rx_stub.cc +++ /dev/null @@ -1,227 +0,0 @@ -/* -*- 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 -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include "usrp_standard.h" -#include -#include -#include -#include - -#include - -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 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); diff --git a/usrp/host/lib/inband/usrp_rx_stub.h b/usrp/host/lib/inband/usrp_rx_stub.h deleted file mode 100644 index 238b4568..00000000 --- a/usrp/host/lib/inband/usrp_rx_stub.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- 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 -#include -#include "usrp_standard.h" -#include -#include -#include -#include - -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 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 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 */ - diff --git a/usrp/host/lib/inband/usrp_server.cc b/usrp/host/lib/inband/usrp_server.cc deleted file mode 100644 index ac263630..00000000 --- a/usrp/host/lib/inband/usrp_server.cc +++ /dev/null @@ -1,1860 +0,0 @@ -/* -*- 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 -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -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 &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 &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 &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(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 &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 &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< &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<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 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 &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); diff --git a/usrp/host/lib/inband/usrp_server.h b/usrp/host/lib/inband/usrp_server.h deleted file mode 100644 index dd1825d5..00000000 --- a/usrp/host/lib/inband/usrp_server.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include - -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 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 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 d_chaninfo_tx; - std::vector d_chaninfo_rx; - - std::queue 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 &chan_info, pmt_t data); - void handle_cmd_deallocate_channel(mb_port_sptr port, std::vector &chan_info, pmt_t data); - void handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector &chan_info, pmt_t data); - void handle_cmd_to_control_channel(mb_port_sptr port, std::vector &chan_info, pmt_t data); - void handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector &chan_info, pmt_t data); - void handle_cmd_stop_recv_raw_samples(mb_port_sptr port, std::vector &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 &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 */ diff --git a/usrp/host/lib/inband/usrp_server.mbh b/usrp/host/lib/inband/usrp_server.mbh deleted file mode 100644 index ed7943fc..00000000 --- a/usrp/host/lib/inband/usrp_server.mbh +++ /dev/null @@ -1,255 +0,0 @@ -;; -*- 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) - ) - ) diff --git a/usrp/host/lib/inband/usrp_tx.cc b/usrp/host/lib/inband/usrp_tx.cc deleted file mode 100644 index 0d4a8461..00000000 --- a/usrp/host/lib/inband/usrp_tx.cc +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -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(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(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); diff --git a/usrp/host/lib/inband/usrp_tx.h b/usrp/host/lib/inband/usrp_tx.h deleted file mode 100644 index d3a6f8b5..00000000 --- a/usrp/host/lib/inband/usrp_tx.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- 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 -#include -#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 */ - diff --git a/usrp/host/lib/inband/usrp_tx_stub.cc b/usrp/host/lib/inband/usrp_tx_stub.cc deleted file mode 100644 index c78b1a7b..00000000 --- a/usrp/host/lib/inband/usrp_tx_stub.cc +++ /dev/null @@ -1,344 +0,0 @@ -/* -*- 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "usrp_standard.h" -#include -#include -#include - -#include - -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(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(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; isend(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); diff --git a/usrp/host/lib/inband/usrp_tx_stub.h b/usrp/host/lib/inband/usrp_tx_stub.h deleted file mode 100644 index b81037ad..00000000 --- a/usrp/host/lib/inband/usrp_tx_stub.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- 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 -#include -#include "usrp_standard.h" -#include -#include - -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 */ - diff --git a/usrp/host/lib/inband/usrp_usb_interface.cc b/usrp/host/lib/inband/usrp_usb_interface.cc deleted file mode 100644 index fb7109a5..00000000 --- a/usrp/host/lib/inband/usrp_usb_interface.cc +++ /dev/null @@ -1,601 +0,0 @@ -/* -*- 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 -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include "usrp_rx.h" -#include -#include "usrp_tx.h" -#include "usrp_standard.h" -#include -#include - -typedef usrp_inband_usb_packet transport_pkt; - -#include -#include -#include -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 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 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 d_usrp_basic, std::vector 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); diff --git a/usrp/host/lib/inband/usrp_usb_interface.h b/usrp/host/lib/inband/usrp_usb_interface.h deleted file mode 100644 index 4d7750a7..00000000 --- a/usrp/host/lib/inband/usrp_usb_interface.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- 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 -#include -#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 d_ub_tx; - boost::shared_ptr 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 d_usrp_basic, std::vector 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 */ diff --git a/usrp/host/lib/legacy/Makefile.am b/usrp/host/lib/legacy/Makefile.am deleted file mode 100644 index e1b1b850..00000000 --- a/usrp/host/lib/legacy/Makefile.am +++ /dev/null @@ -1,196 +0,0 @@ -# -# 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 _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 diff --git a/usrp/host/lib/legacy/README_OSX b/usrp/host/lib/legacy/README_OSX deleted file mode 100644 index 37026f25..00000000 --- a/usrp/host/lib/legacy/README_OSX +++ /dev/null @@ -1,63 +0,0 @@ -USRP Darwin Fast USB Changes -Version 0.2 of 2006-04-27 -Michael Dickens - -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 diff --git a/usrp/host/lib/legacy/ad9862.h b/usrp/host/lib/legacy/ad9862.h deleted file mode 100644 index 4375d93d..00000000 --- a/usrp/host/lib/legacy/ad9862.h +++ /dev/null @@ -1,221 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AD9862_H -#define INCLUDED_AD9862_H - -/* - * Analog Devices AD9862 registers and some fields - */ - -#define BEGIN_AD9862 namespace ad9862 { -#define END_AD962 } -#define DEF static const int - -BEGIN_AD9862; - -DEF REG_GENERAL = 0; -DEF REG_RX_PWR_DN = 1; -DEF RX_PWR_DN_VREF_DIFF = (1 << 7); -DEF RX_PWR_DN_VREF = (1 << 6); -DEF RX_PWR_DN_RX_DIGIGAL = (1 << 5); -DEF RX_PWR_DN_RX_B = (1 << 4); -DEF RX_PWR_DN_RX_A = (1 << 3); -DEF RX_PWR_DN_BUF_B = (1 << 2); -DEF RX_PWR_DN_BUF_A = (1 << 1); -DEF RX_PWR_DN_ALL = (1 << 0); - -DEF REG_RX_A = 2; // bypass input buffer / RxPGA -DEF REG_RX_B = 3; // pypass input buffer / RxPGA -DEF RX_X_BYPASS_INPUT_BUFFER = (1 << 7); - -DEF REG_RX_MISC = 4; -DEF RX_MISC_HS_DUTY_CYCLE = (1 << 2); -DEF RX_MISC_SHARED_REF = (1 << 1); -DEF RX_MISC_CLK_DUTY = (1 << 0); - -DEF REG_RX_IF = 5; -DEF RX_IF_THREE_STATE = (1 << 4); -DEF RX_IF_USE_CLKOUT1 = (0 << 3); -DEF RX_IF_USE_CLKOUT2 = (1 << 3); // aka Rx Retime -DEF RX_IF_2S_COMP = (1 << 2); -DEF RX_IF_INV_RX_SYNC = (1 << 1); -DEF RX_IF_MUX_OUT = (1 << 0); - -DEF REG_RX_DIGITAL = 6; -DEF RX_DIGITAL_2_CHAN = (1 << 3); -DEF RX_DIGITAL_KEEP_MINUS_VE = (1 << 2); -DEF RX_DIGITAL_HILBERT = (1 << 1); -DEF RX_DIGITAL_DECIMATE = (1 << 0); - -DEF REG_RESERVED_7 = 7; - -DEF REG_TX_PWR_DN = 8; -DEF TX_PWR_DN_ALT_TIMING_MODE = (1 << 5); -DEF TX_PWR_DN_TX_OFF_ENABLE = (1 << 4); -DEF TX_PWR_DN_TX_DIGITAL = (1 << 3); -DEF TX_PWR_DN_TX_ANALOG_B = 0x4; -DEF TX_PWR_DN_TX_ANALOG_A = 0x2; -DEF TX_PWR_DN_TX_ANALOG_BOTH = 0x7; - -DEF REG_RESERVED_9 = 9; - -DEF REG_TX_A_OFFSET_LO = 10; -DEF REG_TX_A_OFFSET_HI = 11; -DEF REG_TX_B_OFFSET_LO = 12; -DEF REG_TX_B_OFFSET_HI = 13; - -DEF REG_TX_A_GAIN = 14; // fine trim for matching -DEF REG_TX_B_GAIN = 15; // fine trim for matching -DEF TX_X_GAIN_COARSE_FULL = (3 << 6); -DEF TX_X_GAIN_COARSE_1_HALF = (1 << 6); -DEF TX_X_GAIN_COARSE_1_ELEVENTH = (0 << 6); - -DEF REG_TX_PGA = 16; // 20 dB continuous gain in 0.1 dB steps - // 0x00 = min gain (-20 dB) - // 0xff = max gain ( 0 dB) - -DEF REG_TX_MISC = 17; -DEF TX_MISC_SLAVE_ENABLE = (1 << 1); -DEF TX_MISC_TX_PGA_FAST = (1 << 0); - -DEF REG_TX_IF = 18; -DEF TX_IF_USE_CLKOUT2 = (0 << 6); -DEF TX_IF_USE_CLKOUT1 = (1 << 6); // aka Tx Retime -DEF TX_IF_I_FIRST = (0 << 5); -DEF TX_IF_Q_FIRST = (1 << 5); -DEF TX_IF_INV_TX_SYNC = (1 << 4); -DEF TX_IF_2S_COMP = (1 << 3); -DEF TX_IF_INVERSE_SAMPLE = (1 << 2); -DEF TX_IF_TWO_EDGES = (1 << 1); -DEF TX_IF_INTERLEAVED = (1 << 0); - -DEF REG_TX_DIGITAL = 19; -DEF TX_DIGITAL_2_DATA_PATHS = (1 << 4); -DEF TX_DIGITAL_KEEP_NEGATIVE = (1 << 3); -DEF TX_DIGITAL_HILBERT = (1 << 2); -DEF TX_DIGITAL_INTERPOLATE_NONE = 0x0; -DEF TX_DIGITAL_INTERPOLATE_2X = 0x1; -DEF TX_DIGITAL_INTERPOLATE_4X = 0x2; - -DEF REG_TX_MODULATOR = 20; -DEF TX_MODULATOR_NEG_FINE_TUNE = (1 << 5); -DEF TX_MODULATOR_DISABLE_NCO = (0 << 4); -DEF TX_MODULATOR_ENABLE_NCO = (1 << 4); // aka Fine Mode -DEF TX_MODULATOR_REAL_MIX_MODE = (1 << 3); -DEF TX_MODULATOR_NEG_COARSE_TUNE = (1 << 2); -DEF TX_MODULATOR_COARSE_MODULATION_NONE = 0x0; -DEF TX_MODULATOR_COARSE_MODULATION_F_OVER_4 = 0x1; -DEF TX_MODULATOR_COARSE_MODULATION_F_OVER_8 = 0x2; -DEF TX_MODULATOR_CM_MASK = 0x7; - - -DEF REG_TX_NCO_FTW_7_0 = 21; -DEF REG_TX_NCO_FTW_15_8 = 22; -DEF REG_TX_NCO_FTW_23_16= 23; - -DEF REG_DLL = 24; -DEF DLL_DISABLE_INTERNAL_XTAL_OSC = (1 << 6); // aka Input Clock Ctrl -DEF DLL_ADC_DIV2 = (1 << 5); -DEF DLL_MULT_1X = (0 << 3); -DEF DLL_MULT_2X = (1 << 3); -DEF DLL_MULT_4X = (2 << 3); -DEF DLL_PWR_DN = (1 << 2); -// undefined bit = (1 << 1); -DEF DLL_FAST = (1 << 0); - -DEF REG_CLKOUT = 25; -DEF CLKOUT2_EQ_DLL = (0 << 6); -DEF CLKOUT2_EQ_DLL_OVER_2 = (1 << 6); -DEF CLKOUT2_EQ_DLL_OVER_4 = (2 << 6); -DEF CLKOUT2_EQ_DLL_OVER_8 = (3 << 6); -DEF CLKOUT_INVERT_CLKOUT2 = (1 << 5); -DEF CLKOUT_DISABLE_CLKOUT2 = (1 << 4); -// undefined bit = (1 << 3); -// undefined bit = (1 << 2); -DEF CLKOUT_INVERT_CLKOUT1 = (1 << 1); -DEF CLKOUT_DISABLE_CLKOUT1 = (1 << 0); - -DEF REG_AUX_ADC_A2_LO = 26; -DEF REG_AUX_ADC_A2_HI = 27; -DEF REG_AUX_ADC_A1_LO = 28; -DEF REG_AUX_ADC_A1_HI = 29; -DEF REG_AUX_ADC_B2_LO = 30; -DEF REG_AUX_ADC_B2_HI = 31; -DEF REG_AUX_ADC_B1_LO = 32; -DEF REG_AUX_ADC_B1_HI = 33; - -DEF REG_AUX_ADC_CTRL = 34; -DEF AUX_ADC_CTRL_AUX_SPI = (1 << 7); -DEF AUX_ADC_CTRL_SELBNOTA = (1 << 6); -DEF AUX_ADC_CTRL_REFSEL_B = (1 << 5); -DEF AUX_ADC_CTRL_SELECT_B2 = (0 << 4); -DEF AUX_ADC_CTRL_SELECT_B1 = (1 << 4); -DEF AUX_ADC_CTRL_START_B = (1 << 3); -DEF AUX_ADC_CTRL_REFSEL_A = (1 << 2); -DEF AUX_ADC_CTRL_SELECT_A2 = (0 << 1); -DEF AUX_ADC_CTRL_SELECT_A1 = (1 << 1); -DEF AUX_ADC_CTRL_START_A = (1 << 0); - -DEF REG_AUX_ADC_CLK = 35; -DEF AUX_ADC_CLK_CLK_OVER_4 = (1 << 0); - -DEF REG_AUX_DAC_A = 36; -DEF REG_AUX_DAC_B = 37; -DEF REG_AUX_DAC_C = 38; - -DEF REG_AUX_DAC_UPDATE = 39; -DEF AUX_DAC_UPDATE_SLAVE_ENABLE = (1 << 7); -DEF AUX_DAC_UPDATE_C = (1 << 2); -DEF AUX_DAC_UPDATE_B = (1 << 1); -DEF AUX_DAC_UPDATE_A = (1 << 0); - -DEF REG_AUX_DAC_PWR_DN = 40; -DEF AUX_DAC_PWR_DN_C = (1 << 2); -DEF AUX_DAC_PWR_DN_B = (1 << 1); -DEF AUX_DAC_PWR_DN_A = (1 << 0); - -DEF REG_AUX_DAC_CTRL = 41; -DEF AUX_DAC_CTRL_INV_C = (1 << 4); -DEF AUX_DAC_CTRL_INV_B = (1 << 2); -DEF AUX_DAC_CTRL_INV_A = (1 << 0); - -DEF REG_SIGDELT_LO = 42; -DEF REG_SIGDELT_HI = 43; - -// 44 to 48 reserved - -DEF REG_ADC_LOW_PWR_LO = 49; -DEF REG_ADC_LOW_PWR_HI = 50; - -// 51 to 62 reserved - -DEF REG_CHIP_ID = 63; - - -END_AD962; - -#undef DEF -#undef BEGIN_AD9862 -#undef END_AD962 - -#endif /* INCLUDED_AD9862_H */ diff --git a/usrp/host/lib/legacy/check_data.py b/usrp/host/lib/legacy/check_data.py deleted file mode 100755 index 100f0f6d..00000000 --- a/usrp/host/lib/legacy/check_data.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/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 - - - - diff --git a/usrp/host/lib/legacy/circular_buffer.h b/usrp/host/lib/legacy/circular_buffer.h deleted file mode 100644 index 8898e419..00000000 --- a/usrp/host/lib/legacy/circular_buffer.h +++ /dev/null @@ -1,317 +0,0 @@ -/* -*- 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 - -#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 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_ */ diff --git a/usrp/host/lib/legacy/circular_linked_list.h b/usrp/host/lib/legacy/circular_linked_list.h deleted file mode 100644 index e495d609..00000000 --- a/usrp/host/lib/legacy/circular_linked_list.h +++ /dev/null @@ -1,284 +0,0 @@ -/* -*- 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 -#include - -#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 s_both; - -template class s_node -{ - typedef s_node* s_node_ptr; - -private: - T d_object; - bool d_available; - s_node_ptr d_prev, d_next; - s_both* 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* 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* l_both) { d_both = l_both; }; -}; - -template class circular_linked_list { - typedef s_node* 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 (); - l_prev->set_available (); - l_prev->next (l_prev); - l_prev->prev (l_prev); - if (n_nodes > 1) { - l_next = new s_node (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 (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 s_both -{ -private: - s_node* d_node; - void* d_this; -public: - __INLINE__ s_both (s_node* l_node, void* l_this) - : d_node (l_node), d_this (l_this) {}; - __INLINE__ ~s_both () {}; - __INLINE__ s_node* node () { return (d_node); }; - __INLINE__ void* This () { return (d_this); }; - __INLINE__ void set (s_node* l_node, void* l_this) { - d_node = l_node; d_this = l_this;}; -}; - -#endif /* _CIRCULAR_LINKED_LIST_H_ */ diff --git a/usrp/host/lib/legacy/darwin_libusb.h b/usrp/host/lib/legacy/darwin_libusb.h deleted file mode 100644 index 063a2e9c..00000000 --- a/usrp/host/lib/legacy/darwin_libusb.h +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- 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 - * (c) 2002-2005 Nathan Hjelm - * All rights reserved. - */ - -#ifndef __DARWIN_LIBUSB_H__ -#define __DARWIN_LIBUSB_H__ - -#include -#include -#include -#include - -extern "C" { -static char * -darwin_error_str (int result) -{ - switch (result) { - case kIOReturnSuccess: - return "no error"; - case kIOReturnNotOpen: - return "device not opened for exclusive access"; - case kIOReturnNoDevice: - return "no connection to an IOService"; - case kIOUSBNoAsyncPortErr: - return "no asyc port has been opened for interface"; - case kIOReturnExclusiveAccess: - return "another process has device opened for exclusive access"; - case kIOUSBPipeStalled: - return "pipe is stalled"; - case kIOReturnError: - return "could not establish a connection to Darin kernel"; - case kIOReturnBadArgument: - return "invalid argument"; - default: - return "unknown error"; - } -} - -/* not a valid errorno outside darwin.c */ -#define LUSBDARWINSTALL (ELAST+1) - -static int -darwin_to_errno (int result) -{ - switch (result) { - case kIOReturnSuccess: - return 0; - case kIOReturnNotOpen: - return EBADF; - case kIOReturnNoDevice: - case kIOUSBNoAsyncPortErr: - return ENXIO; - case kIOReturnExclusiveAccess: - return EBUSY; - case kIOUSBPipeStalled: - return LUSBDARWINSTALL; - case kIOReturnBadArgument: - return EINVAL; - case kIOReturnError: - default: - return 1; - } -} - -typedef enum { - USB_ERROR_TYPE_NONE = 0, - USB_ERROR_TYPE_STRING, - USB_ERROR_TYPE_ERRNO, -} usb_error_type_t; - -extern char usb_error_str[1024]; -extern int usb_error_errno; -extern usb_error_type_t usb_error_type; - -#define USB_ERROR(r, x) \ - do { \ - usb_error_type = USB_ERROR_TYPE_ERRNO; \ - usb_error_errno = x; \ - return r; \ - } while (0) - -#define USB_ERROR_STR(r, x, format, args...) \ - do { \ - usb_error_type = USB_ERROR_TYPE_STRING; \ - snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ - if (usb_debug) \ - fprintf(stderr, "USB error: %s\n", usb_error_str); \ - return r; \ - } while (0) - -#define USB_ERROR_STR_ORIG(x, format, args...) \ - do { \ - usb_error_type = USB_ERROR_TYPE_STRING; \ - snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ - if (usb_debug) \ - fprintf(stderr, "USB error: %s\n", usb_error_str); \ - return x; \ - } while (0) - -#define USB_ERROR_STR_NO_RET(x, format, args...) \ - do { \ - usb_error_type = USB_ERROR_TYPE_STRING; \ - snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ - if (usb_debug) \ - fprintf(stderr, "USB error: %s\n", usb_error_str); \ - } while (0) - -/* simple function that figures out what pipeRef is associated with an endpoint */ -static int ep_to_pipeRef (darwin_dev_handle *device, int ep) -{ - io_return_t ret; - UInt8 numep, direction, number; - UInt8 dont_care1, dont_care3; - UInt16 dont_care2; - int i; - - if (usb_debug > 3) - fprintf(stderr, "Converting ep address to pipeRef.\n"); - - /* retrieve the total number of endpoints on this interface */ - ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep); - if ( ret ) { - if ( usb_debug > 3 ) - fprintf ( stderr, "ep_to_pipeRef: interface is %p\n", device->interface ); - USB_ERROR_STR_ORIG ( -ret, "ep_to_pipeRef: can't get number of endpoints for interface" ); - } - - /* iterate through the pipeRefs until we find the correct one */ - for (i = 1 ; i <= numep ; i++) { - ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number, - &dont_care1, &dont_care2, &dont_care3); - - if (ret != kIOReturnSuccess) { - fprintf (stderr, "ep_to_pipeRef: an error occurred getting pipe information on pipe %d\n", - i ); - USB_ERROR_STR_ORIG (-darwin_to_errno(ret), "ep_to_pipeRef(GetPipeProperties): %s", darwin_error_str(ret)); - } - - if (usb_debug > 3) - fprintf (stderr, "ep_to_pipeRef: Pipe %i: DIR: %i number: %i\n", i, direction, number); - - /* calculate the endpoint of the pipe and check it versus the requested endpoint */ - if ( ((direction << 7 & USB_ENDPOINT_DIR_MASK) | (number & USB_ENDPOINT_ADDRESS_MASK)) == ep ) { - if (usb_debug > 3) - fprintf(stderr, "ep_to_pipeRef: pipeRef for ep address 0x%02x found: 0x%02x\n", ep, i); - - return i; - } - } - - if (usb_debug > 3) - fprintf(stderr, "ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep); - - /* none of the found pipes match the requested endpoint */ - return -1; -} - -} -#endif /* __DARWIN_LIBUSB_H__ */ diff --git a/usrp/host/lib/legacy/db_base.cc b/usrp/host/lib/legacy/db_base.cc deleted file mode 100644 index 80c6d466..00000000 --- a/usrp/host/lib/legacy/db_base.cc +++ /dev/null @@ -1,252 +0,0 @@ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. -// - -#include -#include - -#if 0 -tune_result::tune_result(double baseband, double dxc, double residual, bool inv) - : ok(false), baseband_freq(baseband), dxc_freq(dxc), - residual_freq(residual), inverted(inv) -{ -} - -tune_result::~tune_result() -{ -} -#endif - - -/*****************************************************************************/ - -db_base::db_base(usrp_basic_sptr usrp, int which) - : d_is_shutdown(false), d_raw_usrp(usrp.get()), d_which(which), d_lo_offset(0.0) -{ -} - -db_base::~db_base() -{ - shutdown(); -} - -void -db_base::shutdown() -{ - if (!d_is_shutdown){ - d_is_shutdown = true; - // do whatever there is to do to shutdown - } -} - -int -db_base::dbid() -{ - return usrp()->daughterboard_id(d_which); -} - -std::string -db_base::name() -{ - return usrp_dbid_to_string(dbid()); -} - -std::string -db_base::side_and_name() -{ - if(d_which == 0) - return "A: " + name(); - else - return "B: " + name(); -} - -// Function to bypass ADC buffers. Any board which is DC-coupled -// should bypass the buffers - -bool -db_base::bypass_adc_buffers(bool bypass) -{ - //if(d_tx) { - // throw std::runtime_error("TX Board has no adc buffers\n"); - //} - - bool ok = true; - if(d_which==0) { - ok &= usrp()->set_adc_buffer_bypass(0, bypass); - ok &= usrp()->set_adc_buffer_bypass(1, bypass); - } - else { - ok &= usrp()->set_adc_buffer_bypass(2, bypass); - ok &= usrp()->set_adc_buffer_bypass(3, bypass); - } - return ok; -} - -bool -db_base::set_atr_mask(int v) -{ - // Set Auto T/R mask. - return usrp()->write_atr_mask(d_which, v); -} - -bool -db_base::set_atr_txval(int v) -{ - // Set Auto T/R register value to be used when transmitting. - return usrp()->write_atr_txval(d_which, v); -} - -bool -db_base::set_atr_rxval(int v) -{ - // Set Auto T/R register value to be used when receiving. - return usrp()->write_atr_rxval(d_which, v); -} - -bool -db_base::set_atr_tx_delay(int v) -{ - // Set Auto T/R delay (in clock ticks) from when Tx fifo gets data to - // when T/R switches. - return usrp()->write_atr_tx_delay(v); -} - -bool -db_base::set_atr_rx_delay(int v) -{ - // Set Auto T/R delay (in clock ticks) from when Tx fifo goes empty to - // when T/R switches. - return usrp()->write_atr_rx_delay(v); -} - -bool -db_base::i_and_q_swapped() -{ - // Return True if this is a quadrature device and (for RX) ADC 0 is Q - // or (for TX) DAC 0 is Q - return false; -} - -bool -db_base::spectrum_inverted() -{ - // Return True if the dboard gives an inverted spectrum - - return false; -} - -bool -db_base::set_enable(bool on) -{ - // For tx daughterboards, this controls the transmitter enable. - - return true; // default is nop -} - -bool -db_base::set_auto_tr(bool on) -{ - // Enable automatic Transmit/Receive switching (ATR). - // - // Should be overridden in subclasses that care. This will typically - // set the atr_mask, txval and rxval. - - return true; -} - -bool -db_base::set_lo_offset(double offset) -{ - // Set how much LO is offset from requested frequency - - d_lo_offset = offset; - return true; -} - -bool -db_base::select_rx_antenna(int which_antenna) -{ - // Specify which antenna port to use for reception. - // Should be overriden by daughterboards that care. - - return which_antenna == 0; -} - -bool -db_base::select_rx_antenna(const std::string &which_antenna) -{ - // Specify which antenna port to use for reception. - // Should be overriden by daughterboards that care. - - return which_antenna == ""; -} - - -// Reference Clock section -// -// Control whether a reference clock is sent to the daughterboards, -// and what frequency -// -// Bit 7 -- 1 turns on refclk, 0 allows IO use -// Bits 6:0 Divider value -// - -double -db_base::_refclk_freq() -{ - return usrp()->fpga_master_clock_freq() / _refclk_divisor(); -} - -void -db_base::_enable_refclk(bool enable) -{ - int CLOCK_OUT = 1; // Clock is on lowest bit - int REFCLK_ENABLE = 0x80; - int REFCLK_DIVISOR_MASK = 0x7f; - - if(enable) { - usrp()->_write_oe(d_which, CLOCK_OUT, CLOCK_OUT); // output enable - usrp()->write_refclk(d_which, (_refclk_divisor() & REFCLK_DIVISOR_MASK) | REFCLK_ENABLE); - } - else { - usrp()->write_refclk(d_which, 0); - } -} - -int -db_base::_refclk_divisor() -{ - // Return value to stick in REFCLK_DIVISOR register - throw std::runtime_error("_reflck_divisor() called from base class\n");; -} - -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; -} diff --git a/usrp/host/lib/legacy/db_base.h b/usrp/host/lib/legacy/db_base.h deleted file mode 100644 index 35470891..00000000 --- a/usrp/host/lib/legacy/db_base.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. -// - -#ifndef INCLUDED_DB_BASE_H -#define INCLUDED_DB_BASE_H - -#include -#include -#include -#include - -class db_base; -typedef boost::shared_ptr db_base_sptr; - -class usrp_basic; -typedef boost::shared_ptr usrp_basic_sptr; - -struct freq_result_t -{ - bool ok; - double baseband_freq; -}; - -/******************************************************************************/ - -/*! - * \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, 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 */ diff --git a/usrp/host/lib/legacy/db_base.i b/usrp/host/lib/legacy/db_base.i deleted file mode 100644 index bd5483aa..00000000 --- a/usrp/host/lib/legacy/db_base.i +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- 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 - -class usrp_tune_result -{ -public: - usrp_tune_result(double baseband=0, double dxc=0, - double residual=0, bool inv=0); - ~usrp_tune_result(); - - double baseband_freq; - double dxc_freq; - double residual_freq; - bool inverted; -}; - -struct freq_result_t -{ - bool ok; - double baseband_freq; -}; - -class db_base -{ - private: - db_base(boost::shared_ptr usrp, int which); - - public: - virtual ~db_base(); - - int dbid(); - std::string name(); - std::string side_and_name(); - int which() { return d_which; } - - bool bypass_adc_buffers(bool bypass); - bool set_atr_mask(int v); - bool set_atr_txval(int v); - bool set_atr_rxval(int v); - bool set_atr_tx_delay(int v); - bool set_atr_rx_delay(int v); - bool set_lo_offset(double offset); - double lo_offset() { return d_lo_offset; } - - virtual float gain_min() = 0; - virtual float gain_max() = 0; - virtual float gain_db_per_step() = 0; - virtual double freq_min() = 0; - virtual double freq_max() = 0; - virtual struct freq_result_t set_freq(double target_freq) = 0; - virtual bool set_gain(float gain) = 0; - virtual bool is_quadrature() = 0; - virtual bool i_and_q_swapped(); - virtual bool spectrum_inverted(); - virtual bool set_enable(bool on); - virtual bool set_auto_tr(bool on); - virtual bool select_rx_antenna(int which_antenna); - virtual bool select_rx_antenna(const std::string &antenna); - 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_sptr; -%template(db_base_sptr) boost::shared_ptr; -%template(db_base_sptr_vector) std::vector; -%template(db_base_sptr_vector_vector) std::vector >; - -// Set better class name in Python -// Enable freq_range and gain_range from public methods of class not implemented in C++ -// And create a dummy wrapper for backwards compatability with some of the example code -%pythoncode %{ - db_base_sptr.__repr__ = lambda self: "" % (self.name(),) - db_base_sptr.freq_range = lambda self: (self.freq_min(), self.freq_max(), 1) - db_base_sptr.gain_range = lambda self: (self.gain_min(), self.gain_max(), self.gain_db_per_step()) - -%} diff --git a/usrp/host/lib/legacy/db_base_impl.h b/usrp/host/lib/legacy/db_base_impl.h deleted file mode 100644 index bb4d95d7..00000000 --- a/usrp/host/lib/legacy/db_base_impl.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef INCLUDED_DB_BASE_IMPL_H -#define INCLUDED_DB_BASE_IMPL_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#endif /* INCLUDED_DB_BASE_IMPL_H */ diff --git a/usrp/host/lib/legacy/db_basic.cc b/usrp/host/lib/legacy/db_basic.cc deleted file mode 100644 index 4bafc939..00000000 --- a/usrp/host/lib/legacy/db_basic.cc +++ /dev/null @@ -1,263 +0,0 @@ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include - - -db_basic_tx::db_basic_tx(boost::shared_ptr usrp, int which) - : db_base(usrp, which) -{ - // Handler for Basic Tx daughterboards. - // - // @param usrp: instance of usrp.source_c - // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively - - set_gain((gain_min() + gain_max()) / 2); // initialize gain -} - -db_basic_tx::~db_basic_tx() -{ -} - -double -db_basic_tx::freq_min() -{ - return -90e9; -} - -double -db_basic_tx::freq_max() -{ - return 90e9; -} - -struct freq_result_t -db_basic_tx::set_freq(double target_freq) -{ - // Set the frequency. - // - // @param freq: target RF frequency in Hz - // @type freq: double - // - // @returns (ok, actual_baseband_freq) where: - // ok is True or False and indicates success or failure, - // actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - - struct freq_result_t args = {false, 0}; - args.ok = true; - args.baseband_freq = 0.0; - return args; -} - -float -db_basic_tx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_basic_tx::gain_max() -{ - return usrp()->pga_max(); -} - -float -db_basic_tx::gain_db_per_step() -{ - return usrp()->pga_db_per_step(); -} - -bool -db_basic_tx::set_gain(float gain) -{ - // Set the gain. - // - // @param gain: gain in decibels - // @returns True/False - - bool ok = usrp()->set_pga(d_which * 2 + 0, gain); - ok = ok && usrp()->set_pga(d_which * 2 + 1, gain); - return ok; -} - -bool -db_basic_tx::is_quadrature() -{ - // Return True if this board requires both I & Q analog channels. - - return true; -} - - -/******************************************************************************/ - - -db_basic_rx::db_basic_rx(usrp_basic_sptr usrp, int which, int subdev) - : db_base(usrp, which) -{ - // Handler for Basic Rx daughterboards. - // - // @param usrp: instance of usrp.source_c - // @param which: which side: 0 or 1 corresponding to TX_A or TX_B respectively - // @param subdev: which analog i/o channel: 0 or 1 - // @type subdev: int - - d_subdev = subdev; - - bypass_adc_buffers(true); - - if(0) { // Doing this would give us a different default than the historical values... - set_gain(float(gain_min() + gain_max()) / 2.0); // initialize gain - } -} - -db_basic_rx::~db_basic_rx() -{ -} - -double -db_basic_rx::freq_min() -{ - return -90e9; -} - -double -db_basic_rx::freq_max() -{ - return 90e9; -} - -struct freq_result_t -db_basic_rx::set_freq(double target_freq) -{ - // Set the frequency. - // - // @param freq: target RF frequency in Hz - // @type freq: double - // - // @returns (ok, actual_baseband_freq) where: - // ok is True or False and indicates success or failure, - // actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - - struct freq_result_t args = {true, 0.0}; - return args; -} - -float -db_basic_rx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_basic_rx::gain_max() -{ - return usrp()->pga_max(); -} - -float -db_basic_rx::gain_db_per_step() -{ - return usrp()->pga_db_per_step(); -} - -bool -db_basic_rx::set_gain(float gain) -{ - // Set the gain. - // - // @param gain: gain in decibels - // @returns True/False - - return usrp()->set_pga(d_which * 2 + d_subdev, gain); -} - -bool -db_basic_rx::is_quadrature() -{ - // Return True if this board requires both I & Q analog channels. - - // This bit of info is useful when setting up the USRP Rx mux register. - - return (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; -} - - diff --git a/usrp/host/lib/legacy/db_basic.h b/usrp/host/lib/legacy/db_basic.h deleted file mode 100644 index 4dd92b99..00000000 --- a/usrp/host/lib/legacy/db_basic.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_BASIC_H -#define DB_BASIC_H - -#include - - -/******************************************************************************/ - - -class db_basic_tx : public db_base -{ -public: - db_basic_tx(usrp_basic_sptr usrp, int which); - ~db_basic_tx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - double freq_min(); - double freq_max(); - struct freq_result_t set_freq(double target_freq); - bool set_gain(float gain); - bool is_quadrature(); -}; - - -/******************************************************************************/ - - -class db_basic_rx : public db_base -{ - public: - db_basic_rx(usrp_basic_sptr usrp, int which, int subdev); - ~db_basic_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - double freq_min(); - double freq_max(); - struct freq_result_t set_freq(double target_freq); - bool set_gain(float gain); - bool is_quadrature(); - -private: - int d_subdev; -}; - - -/******************************************************************************/ - - -class db_lf_rx : public db_basic_rx -{ - public: - db_lf_rx(usrp_basic_sptr usrp, int which, int subdev); - ~db_lf_rx(); - - double freq_min(); - double freq_max(); -}; - - -/******************************************************************************/ - - -class db_lf_tx : public db_basic_tx -{ - public: - db_lf_tx(usrp_basic_sptr usrp, int which); - ~db_lf_tx(); - - double freq_min(); - double freq_max(); -}; - - -#endif diff --git a/usrp/host/lib/legacy/db_boards.cc b/usrp/host/lib/legacy/db_boards.cc deleted file mode 100644 index b537698b..00000000 --- a/usrp/host/lib/legacy/db_boards.cc +++ /dev/null @@ -1,218 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -std::vector -instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) -{ - std::vector db; - - switch(dbid) { - - case(USRP_DBID_BASIC_TX): - db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); - break; - - case(USRP_DBID_BASIC_RX): - db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); - db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); - 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)){ - db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); - } - else { - db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); - db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); - } - break; - - case(-2): - default: - if (boost::dynamic_pointer_cast(usrp)){ - fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Tx.\"\n"); - fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n"); - db.push_back(db_base_sptr(new db_basic_tx(usrp, which_side))); - } - else { - fprintf(stderr, "\n\aWarning: Treating daughterboard with invalid EEPROM contents as if it were a \"Basic Rx.\"\n"); - fprintf(stderr, "Warning: This is almost certainly wrong... Use appropriate burn-*-eeprom utility.\n\n"); - db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 0))); - db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); - } - break; - } - - return db; -} diff --git a/usrp/host/lib/legacy/db_boards.h b/usrp/host/lib/legacy/db_boards.h deleted file mode 100644 index 037c4603..00000000 --- a/usrp/host/lib/legacy/db_boards.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. -// - -#ifndef DB_BOARDS_H -#define DB_BOARDS_H - -#include -#include - -std::vector instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side); - -#endif - - diff --git a/usrp/host/lib/legacy/db_dbs_rx.cc b/usrp/host/lib/legacy/db_dbs_rx.cc deleted file mode 100644 index 6094f913..00000000 --- a/usrp/host/lib/legacy/db_dbs_rx.cc +++ /dev/null @@ -1,497 +0,0 @@ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include -#include -#include - - -/*****************************************************************************/ - - -db_dbs_rx::db_dbs_rx(usrp_basic_sptr _usrp, int which) - : db_base(_usrp, which) -{ - // Control DBS receiver based USRP daughterboard. - // - // @param usrp: instance of usrp.source_c - // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively - - usrp()->_write_oe(d_which, 0x0001, 0x0001); - if(which == 0) { - d_i2c_addr = 0x67; - } - else { - d_i2c_addr = 0x65; - } - - d_n = 950; - d_div2 = 0; - d_osc = 5; - d_cp = 3; - d_r = 4; - d_r_int = 1; - d_fdac = 127; - d_m = 2; - d_dl = 0; - d_ade = 0; - d_adl = 0; - d_gc1 = 0; - d_gc2 = 31; - d_diag = 0; - - _enable_refclk(true); - - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain - - bypass_adc_buffers(true); -} - -db_dbs_rx::~db_dbs_rx() -{ - shutdown(); -} - -void -db_dbs_rx::shutdown() -{ - if (!d_is_shutdown){ - d_is_shutdown = true; - // do whatever there is to do to shutdown orderly - _enable_refclk(false); - } -} - -void -db_dbs_rx::_write_reg (int regno, int v) -{ - //regno is in [0,5], v is value to write to register""" - assert (0 <= regno && regno <= 5); - std::vector args(2); - args[0] = regno; - args[1] = v; - usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args)); -} - -void -db_dbs_rx::_write_regs (int starting_regno, const std::vector &vals) -{ - // starting_regno is in [0,5], - // vals is a seq of integers to write to consecutive registers""" - - //FIXME - std::vector args; - args.push_back(starting_regno); - args.insert(args.end(), vals.begin(), vals.end()); - usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args)); -} - -std::vector -db_dbs_rx::_read_status () -{ - //If successful, return list of two ints: [status_info, filter_DAC]""" - std::string s = usrp()->read_i2c (d_i2c_addr, 2); - if(s.size() != 2) { - std::vector ret(0); - return ret; - } - return str_to_int_seq (s); -} - -void -db_dbs_rx::_send_reg(int regno) -{ - assert(0 <= regno && regno <= 5); - if(regno == 0) - _write_reg(0,(d_div2<<7) + (d_n>>8)); - if(regno == 1) - _write_reg(1,d_n & 255); - if(regno == 2) - _write_reg(2,d_osc + (d_cp<<3) + (d_r_int<<5)); - if(regno == 3) - _write_reg(3,d_fdac); - if(regno == 4) - _write_reg(4,d_m + (d_dl<<5) + (d_ade<<6) + (d_adl<<7)); - if(regno == 5) - _write_reg(5,d_gc2 + (d_diag<<5)); -} - -// BW setting -void -db_dbs_rx::_set_m(int m) -{ - assert(m>0 && m<32); - d_m = m; - _send_reg(4); -} - -void -db_dbs_rx::_set_fdac(int fdac) -{ - assert(fdac>=0 && fdac<128); - d_fdac = fdac; - _send_reg(3); -} - -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(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(round(31.0 * (1-gain/24.0))); - gain = 0; - } - else { - gc2 = 0; - gain -=24; - } - - if(gain >= 4.58) { - dl = 1; - gain -= 4.58; - } - - pga = gain; - _set_gc1(gc1); - _set_gc2(gc2); - _set_dl(dl); - _set_pga(pga); - - return true; -} - -// Frequency setting -void -db_dbs_rx::_set_osc(int osc) -{ - assert(osc>=0 && osc<8); - d_osc = osc; - _send_reg(2); -} - -void -db_dbs_rx::_set_cp(int cp) -{ - assert(cp>=0 && cp<4); - d_cp = cp; - _send_reg(2); -} - -void -db_dbs_rx::_set_n(int n) -{ - assert(n>256 && n<32768); - d_n = n; - _send_reg(0); - _send_reg(1); -} - -void -db_dbs_rx::_set_div2(int div2) -{ - assert(div2 == 0 || div2 == 1); - d_div2 = div2; - _send_reg(0); -} - -void -db_dbs_rx::_set_r(int r) -{ - assert(r>=0 && r<128); - d_r = r; - d_r_int = static_cast(round(log10(r)/log10(2)) - 1); - _send_reg(2); -} - -// FIXME How do we handle ADE and ADL properly? -void -db_dbs_rx::_set_ade(int ade) -{ - assert(ade == 0 || ade == 1); - d_ade = ade; - _send_reg(4); -} - -double -db_dbs_rx::freq_min() -{ - return 500e6; -} - -double -db_dbs_rx::freq_max() -{ - return 2.6e9; -} - -struct freq_result_t -db_dbs_rx::set_freq(double freq) -{ - // Set the frequency. - // - // @param freq: target RF frequency in Hz - // @type freq: double - // - // @returns (ok, actual_baseband_freq) where: - // ok is True or False and indicates success or failure, - // actual_baseband_freq is RF frequency that corresponds to DC in the IF. - - freq_result_t args = {false, 0}; - - if(!(freq>=freq_min() && freq<=freq_max())) { - return args; - } - - double vcofreq; - if(freq<1150e6) { - _set_div2(0); - vcofreq = 4 * freq; - } - else { - _set_div2(1); - vcofreq = 2 * freq; - } - - _set_ade(1); - int rmin = std::max(2, (int)(_refclk_freq()/2e6)); - int rmax = std::min(128, (int)(_refclk_freq()/500e3)); - int r = 2; - int n = 0; - int best_r = 2; - int best_n = 0; - int best_delta = 10e6; - int delta; - - while(r <= rmax) { - n = static_cast(round(freq/(_refclk_freq()/r))); - if(r(round(best_n))); - - int vco; - if(vcofreq < 2433e6) - vco = 0; - else if(vcofreq < 2711e6) - vco=1; - else if(vcofreq < 3025e6) - vco=2; - else if(vcofreq < 3341e6) - vco=3; - else if(vcofreq < 3727e6) - vco=4; - else if(vcofreq < 4143e6) - vco=5; - else if(vcofreq < 4493e6) - vco=6; - else - vco=7; - - _set_osc(vco); - - // Set CP current - int adc_val = 0; - std::vector bytes(2); - while(adc_val == 0 || adc_val == 7) { - bytes = _read_status(); - adc_val = bytes[0] >> 2; - if(adc_val == 0) { - if(vco <= 0) { - return args; - } - else { - vco = vco - 1; - } - } - else if(adc_val == 7) { - if(vco >= 7) { - return args; - } - else { - vco = vco + 1; - } - } - _set_osc(vco); - } - - if(adc_val == 1 || adc_val == 2) { - _set_cp(1); - } - else if(adc_val == 3 || adc_val == 4) { - _set_cp(2); - } - else { - _set_cp(3); - } - - args.ok = true; - args.baseband_freq = d_n * _refclk_freq() / d_r; - return args; -} - -int -db_dbs_rx::_refclk_divisor() -{ - //Return value to stick in REFCLK_DIVISOR register - return 16; -} - -bool -db_dbs_rx::is_quadrature() -{ - // Return True if this board requires both I & Q analog channels. - return true; -} diff --git a/usrp/host/lib/legacy/db_dbs_rx.h b/usrp/host/lib/legacy/db_dbs_rx.h deleted file mode 100644 index 723771f1..00000000 --- a/usrp/host/lib/legacy/db_dbs_rx.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_DBS_RX_H -#define DB_DBS_RX_H - -#include -#include - -#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 &vals); - std::vector _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 diff --git a/usrp/host/lib/legacy/db_dtt754.cc b/usrp/host/lib/legacy/db_dtt754.cc deleted file mode 100644 index 4a6a1a29..00000000 --- a/usrp/host/lib/legacy/db_dtt754.cc +++ /dev/null @@ -1,323 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include - -int -control_byte_1() -{ - int RS = 0; // 0 = 166.66kHz reference - int ATP = 7; // Disable internal AGC - return (0x80 | ATP<<3 | RS); -} - -int -control_byte_2() -{ - int STBY = 0; // powered on - int XTO = 1; // turn off xtal out, which we don't have - int ATC = 0; // not clear exactly, possibly speeds up or slows down AGC, which we are not using - - int c = 0xc2 | ATC<<5 | STBY<<4 | XTO; - return c; -} - -int -bandswitch_byte(float freq, float bw) -{ - int P5, CP, BS; - - if(bw>7.5e6) { - P5 = 1; - } - else { - P5 = 0; - } - - if(freq < 121e6) { - CP = 0; - BS = 1; - } - else if(freq < 141e6) { - CP = 1; - BS = 1; - } - else if(freq < 166e6) { - CP = 2; - BS = 1; - } - else if(freq < 182e6) { - CP = 3; - BS = 1; - } - else if(freq < 286e6) { - CP = 0; - BS = 2; - } - else if(freq < 386e6) { - CP = 1; - BS = 2; - } - else if(freq < 446e6) { - CP = 2; - BS = 2; - } - else if(freq < 466e6) { - CP = 3; - BS = 2; - } - else if(freq < 506e6) { - CP = 0; - BS = 8; - } - else if(freq < 761e6) { - CP = 1; - BS = 8; - } - else if(freq < 846e6) { - CP = 2; - BS = 8; - } - else { // limit is ~905 MHz - CP = 3; - BS = 8; - } - return (CP<<6 | P5 << 4 | BS); -} - -db_dtt754::db_dtt754(usrp_basic_sptr _usrp, int which) - : db_base(_usrp, which) -{ - /* - * Control custom DTT75403-based daughterboard. - * - * @param usrp: instance of usrp.source_c - * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - * @type which: int - */ - - // FIXME: DTT754 and DTT768 can probably inherit from a DTT class - - if(d_which == 0) { - d_i2c_addr = 0x60; - } - else { - d_i2c_addr = 0x62; - } - - d_bw = 7e6; - d_IF = 36e6; - - d_f_ref = 166.6666e3; - d_inverted = false; - - set_gain((gain_min() + gain_max()) / 2.0); - - bypass_adc_buffers(false); -} - -db_dtt754::~db_dtt754() -{ -} - -float -db_dtt754::gain_min() -{ - return 0; -} - -float -db_dtt754::gain_max() -{ - return 115; -} - -float -db_dtt754::gain_db_per_step() -{ - return 1; -} - -bool -db_dtt754::set_gain(float gain) -{ - assert(gain>=0 && gain<=115); - - float rfgain, ifgain, pgagain; - if(gain > 60) { - rfgain = 60; - gain = gain - 60; - } - else { - rfgain = gain; - gain = 0; - } - - if(gain > 35) { - ifgain = 35; - gain = gain - 35; - } - else { - ifgain = gain; - gain = 0; - } - pgagain = gain; - - _set_rfagc(rfgain); - _set_ifagc(ifgain); - _set_pga(pgagain); - - return true; // can't fail with the assert in place -} - -double -db_dtt754::freq_min() -{ - return 44e6; -} - -double -db_dtt754::freq_max() -{ - return 900e6; -} - -struct freq_result_t -db_dtt754::set_freq(double target_freq) -{ - /* - * @returns (ok, actual_baseband_freq) where: - * ok is True or False and indicates success or failure, - * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - */ - - freq_result_t ret = {false, 0.0}; - - if(target_freq < freq_min() || target_freq > freq_max()) { - return ret; - } - - double target_lo_freq = target_freq + d_IF; // High side mixing - - int divisor = (int)(0.5+(target_lo_freq / d_f_ref)); - double actual_lo_freq = d_f_ref*divisor; - - if((divisor & ~0x7fff) != 0) { // must be 15-bits or less - return ret; - } - - // build i2c command string - std::vector buf(5); - buf[0] = (divisor >> 8) & 0xff; // DB1 - buf[1] = divisor & 0xff; // DB2 - buf[2] = control_byte_1(); - buf[3] = bandswitch_byte(actual_lo_freq, d_bw); - buf[4] = control_byte_2(); - - bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); - - d_freq = actual_lo_freq - d_IF; - - ret.ok = ok; - ret.baseband_freq = actual_lo_freq; - - return ret; - -} - -bool -db_dtt754::is_quadrature() -{ - /* - * Return True if this board requires both I & Q analog channels. - * - * This bit of info is useful when setting up the USRP Rx mux register. - */ - - return false; -} - -bool -db_dtt754::spectrum_inverted() -{ - /* - * The 43.75 MHz version is inverted - */ - - return d_inverted; -} - -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); - } -} diff --git a/usrp/host/lib/legacy/db_dtt754.h b/usrp/host/lib/legacy/db_dtt754.h deleted file mode 100644 index 0c104ac0..00000000 --- a/usrp/host/lib/legacy/db_dtt754.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_DTT754_H -#define DB_DTT754_H - -#include -#include - -class db_dtt754 : public db_base -{ -public: - db_dtt754(usrp_basic_sptr usrp, int which); - ~db_dtt754(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool set_gain(float gain); - - double freq_min(); - double freq_max(); - struct freq_result_t set_freq(double target_freq); - - bool is_quadrature(); - bool spectrum_inverted(); - 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 diff --git a/usrp/host/lib/legacy/db_dtt768.cc b/usrp/host/lib/legacy/db_dtt768.cc deleted file mode 100644 index cae8b734..00000000 --- a/usrp/host/lib/legacy/db_dtt768.cc +++ /dev/null @@ -1,296 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include - -int -control_byte_4() -{ - int C = 0; // Charge Pump Current, no info on how to choose - int R = 4; // 125 kHz fref - - // int ATP = 7; // Disable internal AGC - return (0x80 | C<<5 | R); -} - -int -control_byte_5(float freq, int agcmode = 1) -{ - if(agcmode) { - if(freq < 150e6) { - return 0x3B; - } - else if(freq < 420e6) { - return 0x7E; - } - else { - return 0xB7; - } - } - else { - if(freq < 150e6) { - return 0x39; - } - else if(freq < 420e6) { - return 0x7C; - } - else { - return 0xB5; - } - } -} - -int -control_byte_6() -{ - int ATC = 0; // AGC time constant = 100ms, 1 = 3S - int IFE = 1; // IF AGC amplifier enable - int AT = 0; // AGC control, ??? - - return (ATC << 5 | IFE << 4 | AT); -} - -int -control_byte_7() -{ - int SAS = 1; // SAW Digital mode - int AGD = 1; // AGC disable - int ADS = 0; // AGC detector into ADC converter - int T = 0; // Test mode, undocumented - return (SAS << 7 | AGD << 5 | ADS << 4 | T); -} - -db_dtt768::db_dtt768(usrp_basic_sptr _usrp, int which) - : db_base(_usrp, which) -{ - /* - * Control custom DTT76803-based daughterboard. - * - * @param usrp: instance of usrp.source_c - * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively - * @type which: int - */ - - if(d_which == 0) { - d_i2c_addr = 0x60; - } - else { - d_i2c_addr = 0x62; - } - - d_IF = 44e6; - - d_f_ref = 125e3; - d_inverted = false; - - set_gain((gain_min() + gain_max()) / 2.0); - - bypass_adc_buffers(false); -} - -db_dtt768::~db_dtt768() -{ -} - -float -db_dtt768::gain_min() -{ - return 0; -} - -float -db_dtt768::gain_max() -{ - return 115; -} - -float -db_dtt768::gain_db_per_step() -{ - return 1; -} - -bool -db_dtt768::set_gain(float gain) -{ - assert(gain>=0 && gain<=115); - - float rfgain, ifgain, pgagain; - if(gain > 60) { - rfgain = 60; - gain = gain - 60; - } - else { - rfgain = gain; - gain = 0; - } - - if(gain > 35) { - ifgain = 35; - gain = gain - 35; - } - else { - ifgain = gain; - gain = 0; - } - pgagain = gain; - - _set_rfagc(rfgain); - _set_ifagc(ifgain); - _set_pga(pgagain); - - return true; -} - -double -db_dtt768::freq_min() -{ - return 44e6; -} - -double -db_dtt768::freq_max() -{ - return 900e6; -} - -struct freq_result_t -db_dtt768::set_freq(double target_freq) -{ - /* - * @returns (ok, actual_baseband_freq) where: - * ok is True or False and indicates success or failure, - * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - */ - - freq_result_t ret = {false, 0.0}; - - if(target_freq < freq_min() || target_freq > freq_max()) { - return ret; - } - - double target_lo_freq = target_freq + d_IF; // High side mixing - - int divisor = (int)(0.5+(target_lo_freq / d_f_ref)); - double actual_lo_freq = d_f_ref*divisor; - - if((divisor & ~0x7fff) != 0) { // must be 15-bits or less - return ret; - } - - // build i2c command string - std::vector buf(6); - buf[0] = (divisor >> 8) & 0xff; // DB1 - buf[1] = divisor & 0xff; // DB2 - buf[2] = control_byte_4(); - buf[3] = control_byte_5(target_freq); - buf[4] = control_byte_6(); - buf[5] = control_byte_7(); - - bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); - - d_freq = actual_lo_freq - d_IF; - - ret.ok = ok; - ret.baseband_freq = actual_lo_freq; - - return ret; - -} - -bool -db_dtt768::is_quadrature() -{ - /* - * Return True if this board requires both I & Q analog channels. - * - * This bit of info is useful when setting up the USRP Rx mux register. - */ - - return false; -} - -bool -db_dtt768::spectrum_inverted() -{ - /* - * The 43.75 MHz version is inverted - */ - - return d_inverted; -} - -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); - } -} diff --git a/usrp/host/lib/legacy/db_dtt768.h b/usrp/host/lib/legacy/db_dtt768.h deleted file mode 100644 index dd5a59ab..00000000 --- a/usrp/host/lib/legacy/db_dtt768.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_DTT768_H -#define DB_DTT768_H - -#include -#include - -class db_dtt768 : public db_base -{ -public: - db_dtt768(usrp_basic_sptr usrp, int which); - ~db_dtt768(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool set_gain(float gain); - - double freq_min(); - double freq_max(); - struct freq_result_t set_freq(double target_freq); - - bool is_quadrature(); - bool spectrum_inverted(); - 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 diff --git a/usrp/host/lib/legacy/db_flexrf.cc b/usrp/host/lib/legacy/db_flexrf.cc deleted file mode 100644 index 662d9095..00000000 --- a/usrp/host/lib/legacy/db_flexrf.cc +++ /dev/null @@ -1,1148 +0,0 @@ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include - -// d'board i/o pin defs -// Tx and Rx have shared defs, but different i/o regs -#define AUX_RXAGC (1 << 8) -#define POWER_UP (1 << 7) // enables power supply -#define RX_TXN (1 << 6) // Tx only: T/R antenna switch for TX/RX port -#define RX2_RX1N (1 << 6) // Rx only: antenna switch between RX2 and TX/RX port -#define ENABLE (1 << 5) // enables mixer -#define AUX_SEN (1 << 4) -#define AUX_SCLK (1 << 3) -#define PLL_LOCK_DETECT (1 << 2) -#define AUX_SDO (1 << 1) -#define CLOCK_OUT (1 << 0) - -flexrf_base::flexrf_base(usrp_basic_sptr _usrp, int which, int _power_on) - : db_base(_usrp, which), d_power_on(_power_on) -{ - /* - @param usrp: instance of usrp.source_c - @param which: which side: 0 or 1 corresponding to side A or B respectively - @type which: int - */ - - d_first = true; - d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; - - usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs - _enable_refclk(false); // disable refclk - - set_auto_tr(false); -} - -flexrf_base::~flexrf_base() -{ - delete d_common; -} - -void -flexrf_base::_write_all(int R, int control, int N) -{ - /* - Write R counter latch, control latch and N counter latch to VCO. - - Adds 10ms delay between writing control and N if this is first call. - This is the required power-up sequence. - - @param R: 24-bit R counter latch - @type R: int - @param control: 24-bit control latch - @type control: int - @param N: 24-bit N counter latch - @type N: int - */ - timespec t; - t.tv_sec = 0; - t.tv_nsec = 10000000; - - _write_R(R); - _write_control(control); - if(d_first) { - //time.sleep(0.010); - nanosleep(&t, NULL); - d_first = false; - } - _write_N(N); -} - -void -flexrf_base::_write_control(int control) -{ - _write_it((control & ~0x3) | 0); -} - -void -flexrf_base::_write_R(int R) -{ - _write_it((R & ~0x3) | 1); -} - -void -flexrf_base::_write_N(int N) -{ - _write_it((N & ~0x3) | 2); -} - -void -flexrf_base::_write_it(int v) -{ - char s[3]; - s[0] = (char)((v >> 16) & 0xff); - s[1] = (char)((v >> 8) & 0xff); - s[2] = (char)(v & 0xff); - std::string str(s, 3); - usrp()->_write_spi(0, d_spi_enable, d_spi_format, str); -} - -bool -flexrf_base::_lock_detect() -{ - /* - @returns: the value of the VCO/PLL lock detect bit. - @rtype: 0 or 1 - */ - if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { - return true; - } - else { // Give it a second chance - // FIXME: make portable sleep - timespec t; - t.tv_sec = 0; - t.tv_nsec = 100000000; - nanosleep(&t, NULL); - - if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { - return true; - } - else { - return false; - } - } -} - -bool -flexrf_base::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - /* - Determine values of R, control, and N registers, along with actual freq. - - @param freq: target frequency in Hz - @type freq: float - @returns: (R, control, N, actual_freq) - @rtype: tuple(int, int, int, float) - - Override this in derived classes. - */ - - //raise NotImplementedError; - throw std::runtime_error("_compute_regs called from flexrf_base\n"); -} - -int -flexrf_base::_compute_control_reg() -{ - return d_common->_compute_control_reg(); -} - -int -flexrf_base::_refclk_divisor() -{ - return d_common->_refclk_divisor(); -} - -double -flexrf_base::_refclk_freq() -{ - return 64e6/_refclk_divisor(); -} - -struct freq_result_t -flexrf_base::set_freq(double freq) -{ - /* - @returns (ok, actual_baseband_freq) where: - ok is True or False and indicates success or failure, - actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - */ - - struct freq_result_t args = {false, 0}; - - // Offsetting the LO helps get the Tx carrier leakage out of the way. - // This also ensures that on Rx, we're not getting hosed by the - // FPGA's DC removal loop's time constant. We were seeing a - // problem when running with discontinuous transmission. - // Offsetting the LO made the problem go away. - freq += d_lo_offset; - - int R, control, N; - double actual_freq; - _compute_regs(freq, R, control, N, actual_freq); - - if(R==0) { - return args; - } - - _write_all(R, control, N); - args.ok = _lock_detect(); - args.baseband_freq = actual_freq; - return args; -} - -bool -flexrf_base::_set_pga(float pga_gain) -{ - if(d_which == 0) { - usrp()->set_pga(0, pga_gain); - usrp()->set_pga(1, pga_gain); - } - else { - usrp()->set_pga(2, pga_gain); - usrp()->set_pga(3, pga_gain); - } - return true; -} - -bool -flexrf_base::is_quadrature() -{ - /* - Return True if this board requires both I & Q analog channels. - - This bit of info is useful when setting up the USRP Rx mux register. - */ - return true; -} - -double -flexrf_base::freq_min() -{ - return d_common->freq_min(); -} - -double -flexrf_base::freq_max() -{ - return d_common->freq_max(); -} - -// ---------------------------------------------------------------- - -flexrf_base_tx::flexrf_base_tx(usrp_basic_sptr _usrp, int which, int _power_on) - : flexrf_base(_usrp, which, _power_on) -{ - /* - @param usrp: instance of usrp.sink_c - @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. - */ - - if(which == 0) { - d_spi_enable = SPI_ENABLE_TX_A; - } - else { - d_spi_enable = SPI_ENABLE_TX_B; - } - - // power up the transmit side, but don't enable the mixer - usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff); - usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); - set_lo_offset(4e6); - - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain -} - -flexrf_base_tx::~flexrf_base_tx() -{ - shutdown(); -} - - -void -flexrf_base_tx::shutdown() -{ - // fprintf(stderr, "flexrf_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown); - - if (!d_is_shutdown){ - d_is_shutdown = true; - // do whatever there is to do to shutdown - - // Power down and leave the T/R switch in the R position - usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); - - // Power down VCO/PLL - d_PD = 3; - - _write_control(_compute_control_reg()); - _enable_refclk(false); // turn off refclk - set_auto_tr(false); - } -} - -bool -flexrf_base_tx::set_auto_tr(bool on) -{ - bool ok = true; - if(on) { - ok &= set_atr_mask (RX_TXN | ENABLE); - ok &= set_atr_txval(0 | ENABLE); - ok &= set_atr_rxval(RX_TXN | 0); - } - else { - ok &= set_atr_mask (0); - ok &= set_atr_txval(0); - ok &= set_atr_rxval(0); - } - return ok; -} - -bool -flexrf_base_tx::set_enable(bool on) -{ - /* - Enable transmitter if on is true - */ - - int v; - int mask = RX_TXN | ENABLE; - if(on) { - v = ENABLE; - } - else { - v = RX_TXN; - } - return usrp()->write_io(d_which, v, mask); -} - -float -flexrf_base_tx::gain_min() -{ - return usrp()->pga_max(); -} - -float -flexrf_base_tx::gain_max() -{ - return usrp()->pga_max(); -} - -float -flexrf_base_tx::gain_db_per_step() -{ - return 1; -} - -bool -flexrf_base_tx::set_gain(float gain) -{ - /* - Set the gain. - - @param gain: gain in decibels - @returns True/False - */ - return _set_pga(usrp()->pga_max()); -} - - -/**************************************************************************/ - - -flexrf_base_rx::flexrf_base_rx(usrp_basic_sptr _usrp, int which, int _power_on) - : flexrf_base(_usrp, which, _power_on) -{ - /* - @param usrp: instance of usrp.source_c - @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. - */ - - if(which == 0) { - d_spi_enable = SPI_ENABLE_RX_A; - } - else { - d_spi_enable = SPI_ENABLE_RX_B; - } - - usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff); - usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE), - (POWER_UP|RX2_RX1N|ENABLE)); - - // set up for RX on TX/RX port - select_rx_antenna("TX/RX"); - - bypass_adc_buffers(true); - - set_lo_offset(-4e6); -} - -flexrf_base_rx::~flexrf_base_rx() -{ - shutdown(); -} - -void -flexrf_base_rx::shutdown() -{ - // fprintf(stderr, "flexrf_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown); - - if (!d_is_shutdown){ - d_is_shutdown = true; - // do whatever there is to do to shutdown - - // Power down - usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE)); - - // Power down VCO/PLL - d_PD = 3; - - - // fprintf(stderr, "flexrf_base_rx::shutdown before _write_control\n"); - _write_control(_compute_control_reg()); - - // fprintf(stderr, "flexrf_base_rx::shutdown before _enable_refclk\n"); - _enable_refclk(false); // turn off refclk - - // fprintf(stderr, "flexrf_base_rx::shutdown before set_auto_tr\n"); - set_auto_tr(false); - - // fprintf(stderr, "flexrf_base_rx::shutdown after set_auto_tr\n"); - } -} - -bool -flexrf_base_rx::set_auto_tr(bool on) -{ - bool ok = true; - if(on) { - ok &= set_atr_mask (ENABLE); - ok &= set_atr_txval( 0); - ok &= set_atr_rxval(ENABLE); - } - else { - ok &= set_atr_mask (0); - ok &= set_atr_txval(0); - ok &= set_atr_rxval(0); - } - return true; -} - -bool -flexrf_base_rx::select_rx_antenna(int which_antenna) -{ - /* - Specify which antenna port to use for reception. - @param which_antenna: either 'TX/RX' or 'RX2' - */ - - if(which_antenna == 0) { - usrp()->write_io(d_which, 0,RX2_RX1N); - } - else if(which_antenna == 1) { - usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); - } - else { - return false; - // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); - } - return true; -} - -bool -flexrf_base_rx::select_rx_antenna(const std::string &which_antenna) -{ - /* - Specify which antenna port to use for reception. - @param which_antenna: either 'TX/RX' or 'RX2' - */ - - if(which_antenna == "TX/RX") { - usrp()->write_io(d_which, 0, RX2_RX1N); - } - else if(which_antenna == "RX2") { - usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); - } - else { - // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); - return false; - } - return true; -} - -bool -flexrf_base_rx::set_gain(float gain) -{ - /* - Set the gain. - - @param gain: gain in decibels - @returns True/False - */ - - // clamp gain - gain = std::max(gain_min(), std::min(gain, gain_max())); - - float pga_gain, agc_gain; - float V_maxgain, V_mingain, V_fullscale, dac_value; - - float maxgain = gain_max() - usrp()->pga_max(); - float mingain = gain_min(); - if(gain > maxgain) { - pga_gain = gain-maxgain; - assert(pga_gain <= usrp()->pga_max()); - agc_gain = maxgain; - } - else { - pga_gain = 0; - agc_gain = gain; - } - - V_maxgain = .2; - V_mingain = 1.2; - V_fullscale = 3.3; - dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; - - assert(dac_value>=0 && dac_value<4096); - - return (usrp()->write_aux_dac(d_which, 0, int(dac_value)) - && _set_pga(int(pga_gain))); -} - -// ---------------------------------------------------------------- - - -_AD4360_common::_AD4360_common() -{ - // R-Register Common Values - d_R_RSV = 0; // bits 23,22 - d_BSC = 3; // bits 21,20 Div by 8 to be safe - d_TEST = 0; // bit 19 - d_LDP = 1; // bit 18 - d_ABP = 0; // bit 17,16 3ns - - // N-Register Common Values - d_N_RSV = 0; // bit 7 - - // Control Register Common Values - d_PD = 0; // bits 21,20 Normal operation - d_PL = 0; // bits 13,12 11mA - d_MTLD = 1; // bit 11 enabled - d_CPG = 0; // bit 10 CP setting 1 - d_CP3S = 0; // bit 9 Normal - d_PDP = 1; // bit 8 Positive - d_MUXOUT = 1; // bits 7:5 Digital Lock Detect - d_CR = 0; // bit 4 Normal - d_PC = 1; // bits 3,2 Core power 10mA -} - -_AD4360_common::~_AD4360_common() -{ -} - -bool -_AD4360_common::_compute_regs(double refclk_freq, double freq, int &retR, - int &retcontrol, int &retN, double &retfreq) -{ - /* - Determine values of R, control, and N registers, along with actual freq. - - @param freq: target frequency in Hz - @type freq: float - @returns: (R, control, N, actual_freq) - @rtype: tuple(int, int, int, float) - */ - - // Band-specific N-Register Values - //float phdet_freq = _refclk_freq()/d_R_DIV; - double phdet_freq = refclk_freq/d_R_DIV; - double desired_n = round(freq*d_freq_mult/phdet_freq); - double actual_freq = desired_n * phdet_freq; - int B = floor(desired_n/_prescaler()); - int A = desired_n - _prescaler()*B; - d_B_DIV = int(B); // bits 20:8 - d_A_DIV = int(A); // bit 6:2 - - //assert db_B_DIV >= db_A_DIV - if(d_B_DIV < d_A_DIV) { - retR = 0; - retcontrol = 0; - retN = 0; - retfreq = 0; - return false; - } - - int R = (d_R_RSV<<22) | (d_BSC<<20) | (d_TEST<<19) | - (d_LDP<<18) | (d_ABP<<16) | (d_R_DIV<<2); - - int control = _compute_control_reg(); - - int N = (d_DIVSEL<<23) | (d_DIV2<<22) | (d_CPGAIN<<21) | - (d_B_DIV<<8) | (d_N_RSV<<7) | (d_A_DIV<<2); - - retR = R; - retcontrol = control; - retN = N; - retfreq = actual_freq/d_freq_mult; - return true; -} - -int -_AD4360_common::_compute_control_reg() -{ - int control = (d_P<<22) | (d_PD<<20) | (d_CP2<<17) | (d_CP1<<14) - | (d_PL<<12) | (d_MTLD<<11) | (d_CPG<<10) | (d_CP3S<<9) | (d_PDP<<8) - | (d_MUXOUT<<5) | (d_CR<<4) | (d_PC<<2); - - return control; -} - -int -_AD4360_common::_refclk_divisor() -{ - /* - Return value to stick in REFCLK_DIVISOR register - */ - return 1; -} - -int -_AD4360_common::_prescaler() -{ - if(d_P == 0) { - return 8; - } - else if(d_P == 1) { - return 16; - } - else { - return 32; - } -} - -//---------------------------------------------------------------------- - -_2400_common::_2400_common() - : _AD4360_common() -{ - // Band-specific R-Register Values - d_R_DIV = 16; // bits 15:2 - - // Band-specific C-Register values - d_P = 1; // bits 23,22 Div by 16/17 - d_CP2 = 7; // bits 19:17 - d_CP1 = 7; // bits 16:14 - - // Band specifc N-Register Values - d_DIVSEL = 0; // bit 23 - d_DIV2 = 0; // bit 22 - d_CPGAIN = 0; // bit 21 - d_freq_mult = 1; -} - -double -_2400_common::freq_min() -{ - return 2300e6; -} - -double -_2400_common::freq_max() -{ - return 2700e6; -} - -//---------------------------------------------------------------------- - -_1200_common::_1200_common() - : _AD4360_common() -{ - // Band-specific R-Register Values - d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq - - // Band-specific C-Register values - d_P = 1; // bits 23,22 Div by 16/17 - d_CP2 = 7; // bits 19:17 1.25 mA - d_CP1 = 7; // bits 16:14 1.25 mA - - // Band specifc N-Register Values - d_DIVSEL = 0; // bit 23 - d_DIV2 = 1; // bit 22 - d_CPGAIN = 0; // bit 21 - d_freq_mult = 2; -} - -double -_1200_common::freq_min() -{ - return 1150e6; -} - -double -_1200_common::freq_max() -{ - return 1350e6; -} - -//------------------------------------------------------------------------- - -_1800_common::_1800_common() - : _AD4360_common() -{ - // Band-specific R-Register Values - d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq - - // Band-specific C-Register values - d_P = 1; // bits 23,22 Div by 16/17 - d_CP2 = 7; // bits 19:17 1.25 mA - d_CP1 = 7; // bits 16:14 1.25 mA - - // Band specifc N-Register Values - d_DIVSEL = 0; // bit 23 - d_DIV2 = 0; // bit 22 - d_freq_mult = 1; - d_CPGAIN = 0; // bit 21 -} - -double -_1800_common::freq_min() -{ - return 1600e6; -} - -double -_1800_common::freq_max() -{ - return 2000e6; -} - -//------------------------------------------------------------------------- - -_900_common::_900_common() - : _AD4360_common() -{ - // Band-specific R-Register Values - d_R_DIV = 16; // bits 15:2 DIV by 16 for a 1 MHz phase detector freq - - // Band-specific C-Register values - d_P = 1; // bits 23,22 Div by 16/17 - d_CP2 = 7; // bits 19:17 1.25 mA - d_CP1 = 7; // bits 16:14 1.25 mA - - // Band specifc N-Register Values - d_DIVSEL = 0; // bit 23 - d_DIV2 = 1; // bit 22 - d_freq_mult = 2; - d_CPGAIN = 0; // bit 21 -} - -double -_900_common::freq_min() -{ - return 800e6; -} - -double -_900_common::freq_max() -{ - return 1000e6; -} - -//------------------------------------------------------------------------- - -_400_common::_400_common() - : _AD4360_common() -{ - // Band-specific R-Register Values - d_R_DIV = 16; // bits 15:2 - - // Band-specific C-Register values - d_P = 0; // bits 23,22 Div by 8/9 - d_CP2 = 7; // bits 19:17 1.25 mA - d_CP1 = 7; // bits 16:14 1.25 mA - - // Band specifc N-Register Values These are different for TX/RX - d_DIVSEL = 0; // bit 23 - d_freq_mult = 2; - - d_CPGAIN = 0; // bit 21 -} - -double -_400_common::freq_min() -{ - return 400e6; -} - -double -_400_common::freq_max() -{ - return 500e6; -} - -_400_tx::_400_tx() - : _400_common() -{ - d_DIV2 = 1; // bit 22 -} - -_400_rx::_400_rx() - : _400_common() -{ - d_DIV2 = 0; // bit 22 // RX side has built-in DIV2 in AD8348 -} - -//------------------------------------------------------------ - -db_flexrf_2400_tx::db_flexrf_2400_tx(usrp_basic_sptr usrp, int which) - : flexrf_base_tx(usrp, which) -{ - d_common = new _2400_common(); -} - -db_flexrf_2400_tx::~db_flexrf_2400_tx() -{ -} - -bool -db_flexrf_2400_tx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - - -db_flexrf_2400_rx::db_flexrf_2400_rx(usrp_basic_sptr usrp, int which) - : flexrf_base_rx(usrp, which) -{ - d_common = new _2400_common(); - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain -} - -db_flexrf_2400_rx::~db_flexrf_2400_rx() -{ -} - -float -db_flexrf_2400_rx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_flexrf_2400_rx::gain_max() -{ - return usrp()->pga_max()+70; -} - -float -db_flexrf_2400_rx::gain_db_per_step() -{ - return 0.05; -} - - -bool -db_flexrf_2400_rx::i_and_q_swapped() -{ - return true; -} - -bool -db_flexrf_2400_rx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - -//------------------------------------------------------------ - - -db_flexrf_1200_tx::db_flexrf_1200_tx(usrp_basic_sptr usrp, int which) - : flexrf_base_tx(usrp, which) -{ - d_common = new _1200_common(); -} - -db_flexrf_1200_tx::~db_flexrf_1200_tx() -{ -} - -bool -db_flexrf_1200_tx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - - - -db_flexrf_1200_rx::db_flexrf_1200_rx(usrp_basic_sptr usrp, int which) - : flexrf_base_rx(usrp, which) -{ - d_common = new _1200_common(); - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain -} - -db_flexrf_1200_rx::~db_flexrf_1200_rx() -{ -} - -float -db_flexrf_1200_rx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_flexrf_1200_rx::gain_max() -{ - return usrp()->pga_max()+70; -} - -float -db_flexrf_1200_rx::gain_db_per_step() -{ - return 0.05; -} - -bool -db_flexrf_1200_rx::i_and_q_swapped() -{ - return true; -} - -bool -db_flexrf_1200_rx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - -//------------------------------------------------------------ - - -db_flexrf_1800_tx::db_flexrf_1800_tx(usrp_basic_sptr usrp, int which) - : flexrf_base_tx(usrp, which) -{ - d_common = new _1800_common(); -} - -db_flexrf_1800_tx::~db_flexrf_1800_tx() -{ -} - -bool -db_flexrf_1800_tx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - - -db_flexrf_1800_rx::db_flexrf_1800_rx(usrp_basic_sptr usrp, int which) - : flexrf_base_rx(usrp, which) -{ - d_common = new _1800_common(); - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain -} - -db_flexrf_1800_rx::~db_flexrf_1800_rx() -{ -} - - -float -db_flexrf_1800_rx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_flexrf_1800_rx::gain_max() -{ - return usrp()->pga_max()+70; -} - -float -db_flexrf_1800_rx::gain_db_per_step() -{ - return 0.05; -} - -bool -db_flexrf_1800_rx::i_and_q_swapped() -{ - return true; -} - -bool -db_flexrf_1800_rx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - -//------------------------------------------------------------ - - -db_flexrf_900_tx::db_flexrf_900_tx(usrp_basic_sptr usrp, int which) - : flexrf_base_tx(usrp, which) -{ - d_common = new _900_common(); -} - -db_flexrf_900_tx::~db_flexrf_900_tx() -{ -} - -bool -db_flexrf_900_tx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - -db_flexrf_900_rx::db_flexrf_900_rx(usrp_basic_sptr usrp, int which) - : flexrf_base_rx(usrp, which) -{ - d_common = new _900_common(); - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain -} - -db_flexrf_900_rx::~db_flexrf_900_rx() -{ -} - -float -db_flexrf_900_rx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_flexrf_900_rx::gain_max() -{ - return usrp()->pga_max()+70; -} - -float -db_flexrf_900_rx::gain_db_per_step() -{ - return 0.05; -} - -bool -db_flexrf_900_rx::i_and_q_swapped() -{ - return true; -} - -bool -db_flexrf_900_rx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - -//------------------------------------------------------------ - - -db_flexrf_400_tx::db_flexrf_400_tx(usrp_basic_sptr usrp, int which) - : flexrf_base_tx(usrp, which, POWER_UP) -{ - d_common = new _400_tx(); -} - -db_flexrf_400_tx::~db_flexrf_400_tx() -{ -} - -bool -db_flexrf_400_tx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - - - -db_flexrf_400_rx::db_flexrf_400_rx(usrp_basic_sptr usrp, int which) - : flexrf_base_rx(usrp, which, POWER_UP) -{ - d_common = new _400_rx(); - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain -} - -db_flexrf_400_rx::~db_flexrf_400_rx() -{ -} - -float -db_flexrf_400_rx::gain_min() -{ - return usrp()->pga_min(); -} - -float -db_flexrf_400_rx::gain_max() -{ - return usrp()->pga_max()+45; -} - -float - -db_flexrf_400_rx::gain_db_per_step() -{ - return 0.035; -} - - -bool -db_flexrf_400_rx::i_and_q_swapped() -{ - return true; -} - -bool -db_flexrf_400_rx::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - return d_common->_compute_regs(_refclk_freq(), freq, retR, - retcontrol, retN, retfreq); -} - diff --git a/usrp/host/lib/legacy/db_flexrf.h b/usrp/host/lib/legacy/db_flexrf.h deleted file mode 100644 index b9ccfc3a..00000000 --- a/usrp/host/lib/legacy/db_flexrf.h +++ /dev/null @@ -1,355 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_FLEXRF_H -#define DB_FLEXRF_H - -#include -#include - -//debug_using_gui = true // Must be set to True or False -#define debug_using_gui false // Must be set to True or False - -class _AD4360_common; - -class flexrf_base : public db_base -{ -public: - flexrf_base(usrp_basic_sptr usrp, int which, int _power_on=0); - ~flexrf_base(); - - struct freq_result_t set_freq(double freq); - - bool is_quadrature(); - double freq_min(); - double freq_max(); - -protected: - void _write_all(int R, int control, int N); - void _write_control(int control); - void _write_R(int R); - void _write_N(int N); - void _write_it(int v); - bool _lock_detect(); - - virtual bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); - int _compute_control_reg(); - int _refclk_divisor(); - double _refclk_freq(); - - bool _set_pga(float pga_gain); - - int power_on() { return d_power_on; } - int power_off() { return 0; } - - bool d_first; - int d_spi_format; - int d_spi_enable; - int d_power_on; - int d_PD; - - _AD4360_common *d_common; -}; - -// ---------------------------------------------------------------- - -class flexrf_base_tx : public flexrf_base -{ -protected: - void shutdown(); - -public: - flexrf_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0); - ~flexrf_base_tx(); - - // All RFX tx d'boards have fixed gain - float gain_min(); - float gain_max(); - float gain_db_per_step(); - - bool set_auto_tr(bool on); - bool set_enable(bool on); - bool set_gain(float gain); -}; - -class flexrf_base_rx : public flexrf_base -{ -protected: - void shutdown(); - -public: - flexrf_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0); - ~flexrf_base_rx(); - - bool set_auto_tr(bool on); - bool select_rx_antenna(int which_antenna); - bool select_rx_antenna(const std::string &which_antenna); - bool set_gain(float gain); - -}; - -// ---------------------------------------------------------------- - - -class _AD4360_common -{ -public: - _AD4360_common(); - virtual ~_AD4360_common(); - - virtual double freq_min() = 0; - virtual double freq_max() = 0; - - bool _compute_regs(double refclk_freq, double freq, int &retR, - int &retcontrol, int &retN, double &retfreq); - int _compute_control_reg(); - virtual int _refclk_divisor(); - int _prescaler(); - - void R_DIV(int div) { d_R_DIV = div; } - -protected: - int d_R_RSV, d_BSC, d_TEST, d_LDP, d_ABP, d_N_RSV, d_PL, d_MTLD; - int d_CPG, d_CP3S, d_PDP, d_MUXOUT, d_CR, d_PC; - - // FIXME: d_PD might cause conflict from flexrf_base - int d_A_DIV, d_B_DIV, d_R_DIV, d_P, d_PD, d_CP2, d_CP1, d_DIVSEL; - int d_DIV2, d_CPGAIN, d_freq_mult; - -}; - -//---------------------------------------------------------------------- - -class _2400_common : public _AD4360_common -{ - public: - _2400_common(); - ~_2400_common() {} - - double freq_min(); - double freq_max(); -}; - -//---------------------------------------------------------------------- - -class _1200_common : public _AD4360_common -{ -public: - _1200_common(); - ~_1200_common() {} - - double freq_min(); - double freq_max(); -}; - -//------------------------------------------------------------------------- - -class _1800_common : public _AD4360_common -{ - public: - _1800_common(); - ~_1800_common() {} - - double freq_min(); - double freq_max(); -}; - -//------------------------------------------------------------------------- - -class _900_common : public _AD4360_common -{ -public: - _900_common(); - ~_900_common() {} - - double freq_min(); - double freq_max(); -}; - -//------------------------------------------------------------------------- - -class _400_common : public _AD4360_common -{ -public: - _400_common(); - ~_400_common() {} - - double freq_min(); - double freq_max(); -}; - -class _400_tx : public _400_common -{ -public: - _400_tx(); - ~_400_tx() {} -}; - -class _400_rx : public _400_common -{ -public: - _400_rx(); - ~_400_rx() {} -}; - -//------------------------------------------------------------ - -class db_flexrf_2400_tx : public flexrf_base_tx -{ - public: - db_flexrf_2400_tx(usrp_basic_sptr usrp, int which); - ~db_flexrf_2400_tx(); - - // Wrapper calls to d_common functions - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -class db_flexrf_2400_rx : public flexrf_base_rx -{ -public: - db_flexrf_2400_rx(usrp_basic_sptr usrp, int which); - ~db_flexrf_2400_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool i_and_q_swapped(); - - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -//------------------------------------------------------------ - -class db_flexrf_1200_tx : public flexrf_base_tx -{ -public: - db_flexrf_1200_tx(usrp_basic_sptr usrp, int which); - ~db_flexrf_1200_tx(); - - // Wrapper calls to d_common functions - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -class db_flexrf_1200_rx : public flexrf_base_rx -{ -public: - db_flexrf_1200_rx(usrp_basic_sptr usrp, int which); - ~db_flexrf_1200_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool i_and_q_swapped(); - - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -//------------------------------------------------------------ - -class db_flexrf_1800_tx : public flexrf_base_tx -{ - public: - db_flexrf_1800_tx(usrp_basic_sptr usrp, int which); - ~db_flexrf_1800_tx(); - - // Wrapper calls to d_common functions - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -class db_flexrf_1800_rx : public flexrf_base_rx -{ -public: - db_flexrf_1800_rx(usrp_basic_sptr usrp, int which); - ~db_flexrf_1800_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool i_and_q_swapped(); - - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -//------------------------------------------------------------ - -class db_flexrf_900_tx : public flexrf_base_tx -{ - public: - db_flexrf_900_tx(usrp_basic_sptr usrp, int which); - ~db_flexrf_900_tx(); - - // Wrapper calls to d_common functions - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -class db_flexrf_900_rx : public flexrf_base_rx -{ -public: - db_flexrf_900_rx(usrp_basic_sptr usrp, int which); - ~db_flexrf_900_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool i_and_q_swapped(); - - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - - -//------------------------------------------------------------ - -class db_flexrf_400_tx : public flexrf_base_tx -{ - public: - db_flexrf_400_tx(usrp_basic_sptr usrp, int which); - ~db_flexrf_400_tx(); - - // Wrapper calls to d_common functions - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -class db_flexrf_400_rx : public flexrf_base_rx -{ -public: - db_flexrf_400_rx(usrp_basic_sptr usrp, int which); - ~db_flexrf_400_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool i_and_q_swapped(); - - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); -}; - -#endif diff --git a/usrp/host/lib/legacy/db_flexrf_mimo.cc b/usrp/host/lib/legacy/db_flexrf_mimo.cc deleted file mode 100644 index fd996bfa..00000000 --- a/usrp/host/lib/legacy/db_flexrf_mimo.cc +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include - - -db_flexrf_2400_tx_mimo_a::db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_2400_tx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_2400_tx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_2400_rx_mimo_a::db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_2400_rx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_2400_rx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_2400_tx_mimo_b::db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_2400_tx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_2400_tx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_2400_rx_mimo_b::db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_2400_rx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_2400_rx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_1800_tx_mimo_a::db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_1800_tx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_1800_tx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_1800_rx_mimo_a::db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_1800_rx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_1800_rx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_1800_tx_mimo_b::db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_1800_tx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_1800_tx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_1800_rx_mimo_b::db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_1800_rx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_1800_rx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_1200_tx_mimo_a::db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_1200_tx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_1200_tx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_1200_rx_mimo_a::db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_1200_rx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_1200_rx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_1200_tx_mimo_b::db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_1200_tx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_1200_tx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_1200_rx_mimo_b::db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_1200_rx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_1200_rx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_900_tx_mimo_a::db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_900_tx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_900_tx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_900_rx_mimo_a::db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_900_rx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_900_rx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_900_tx_mimo_b::db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_900_tx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_900_tx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_900_rx_mimo_b::db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_900_rx(usrp, which) -{ - d_common->R_DIV(16); -} - -int db_flexrf_900_rx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_400_tx_mimo_a::db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_400_tx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_400_tx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_400_rx_mimo_a::db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which) - : db_flexrf_400_rx(usrp, which) -{ - _enable_refclk(true); - d_common->R_DIV(1); -} - -int -db_flexrf_400_rx_mimo_a::_refclk_divisor() -{ - return 16; -} - -db_flexrf_400_tx_mimo_b::db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_400_tx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_400_tx_mimo_b::_refclk_divisor() -{ - return 1; -} - -db_flexrf_400_rx_mimo_b::db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which) - : db_flexrf_400_rx(usrp, which) -{ - d_common->R_DIV(16); -} - -int -db_flexrf_400_rx_mimo_b::_refclk_divisor() -{ - return 1; -} diff --git a/usrp/host/lib/legacy/db_flexrf_mimo.h b/usrp/host/lib/legacy/db_flexrf_mimo.h deleted file mode 100644 index aeff5325..00000000 --- a/usrp/host/lib/legacy/db_flexrf_mimo.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include - -class db_flexrf_2400_tx_mimo_a : public db_flexrf_2400_tx -{ - public: - db_flexrf_2400_tx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_2400_rx_mimo_a : public db_flexrf_2400_rx -{ - public: - db_flexrf_2400_rx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_2400_tx_mimo_b : public db_flexrf_2400_tx -{ - public: - db_flexrf_2400_tx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_2400_rx_mimo_b : public db_flexrf_2400_rx -{ - public: - db_flexrf_2400_rx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - - -class db_flexrf_1800_tx_mimo_a : public db_flexrf_1800_tx -{ - public: - db_flexrf_1800_tx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1800_rx_mimo_a : public db_flexrf_1800_rx -{ - public: - db_flexrf_1800_rx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1800_tx_mimo_b : public db_flexrf_1800_tx -{ - public: - db_flexrf_1800_tx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1800_rx_mimo_b : public db_flexrf_1800_rx -{ - public: - db_flexrf_1800_rx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1200_tx_mimo_a : public db_flexrf_1200_tx -{ - public: - db_flexrf_1200_tx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1200_rx_mimo_a : public db_flexrf_1200_rx -{ - public: - db_flexrf_1200_rx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1200_tx_mimo_b : public db_flexrf_1200_tx -{ - public: - db_flexrf_1200_tx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_1200_rx_mimo_b : public db_flexrf_1200_rx -{ - public: - db_flexrf_1200_rx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_900_tx_mimo_a : public db_flexrf_900_tx -{ - public: - db_flexrf_900_tx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_900_rx_mimo_a : public db_flexrf_900_rx -{ - public: - db_flexrf_900_rx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_900_tx_mimo_b : public db_flexrf_900_tx -{ - public: - db_flexrf_900_tx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_900_rx_mimo_b : public db_flexrf_900_rx -{ - public: - db_flexrf_900_rx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_400_tx_mimo_a : public db_flexrf_400_tx -{ - public: - db_flexrf_400_tx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_400_rx_mimo_a : public db_flexrf_400_rx -{ - public: - db_flexrf_400_rx_mimo_a(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_400_tx_mimo_b : public db_flexrf_400_tx -{ - public: - db_flexrf_400_tx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; - -class db_flexrf_400_rx_mimo_b : public db_flexrf_400_rx -{ - public: - db_flexrf_400_rx_mimo_b(usrp_basic_sptr usrp, int which); - int _refclk_divisor(); -}; diff --git a/usrp/host/lib/legacy/db_tv_rx.cc b/usrp/host/lib/legacy/db_tv_rx.cc deleted file mode 100644 index 803ebf86..00000000 --- a/usrp/host/lib/legacy/db_tv_rx.cc +++ /dev/null @@ -1,274 +0,0 @@ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include - -/*****************************************************************************/ - -int -control_byte_1(bool fast_tuning_p, int reference_divisor) -{ - int c = 0x88; - if(fast_tuning_p) { - c |= 0x40; - } - - if(reference_divisor == 512) { - c |= 0x3 << 1; - } - else if(reference_divisor == 640) { - c |= 0x0 << 1; - } - else if(reference_divisor == 1024) { - c |= 0x1 << 1; - } - else { - assert(0); - } - - return c; -} - -int -control_byte_2(double target_freq, bool shutdown_tx_PGA) -{ - int c; - if(target_freq < 158e6) { // VHF low - c = 0xa0; - } - else if(target_freq < 464e6) { // VHF high - c = 0x90; - } - else { // UHF - c = 0x30; - } - - if(shutdown_tx_PGA) { - c |= 0x08; - } - - return c; -} - - -/*****************************************************************************/ - - -db_tv_rx::db_tv_rx(usrp_basic_sptr usrp, int which, - double first_IF, double second_IF) - : db_base(usrp, which) -{ - // Handler for Tv Rx daughterboards. - // - // @param usrp: instance of usrp.source_c - // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively - - if(which == 0) { - d_i2c_addr = 0x60; - } - else { - d_i2c_addr = 0x61; - } - - d_first_IF = first_IF; - d_second_IF = second_IF; - d_reference_divisor = 640; - d_fast_tuning = false; - d_inverted = false; // FIXME get rid of this - - set_gain((gain_min() + gain_max()) / 2.0); // initialize gain - - bypass_adc_buffers(false); -} - -db_tv_rx::~db_tv_rx() -{ -} - -// Gain setting -void -db_tv_rx::_set_rfagc(float gain) -{ - float voltage; - - assert(gain <= 60 && gain >= 0); - // FIXME this has a 0.5V step between gain = 60 and gain = 59. - // Why are there two cases instead of a single linear case? - if(gain == 60) { - voltage = 4; - } - else { - voltage = gain/60.0 * 2.25 + 1.25; - } - int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain - - assert(dacword>=0 && dacword<4096); - usrp()->write_aux_dac(d_which, 1, dacword); -} - -void -db_tv_rx::_set_ifagc(float gain) -{ - float voltage; - - assert(gain <= 35 && gain >= 0); - voltage = gain/35.0 * 2.1 + 1.4; - int dacword = int(4096*voltage/1.22/3.3); // 1.22 = opamp gain - - assert(dacword>=0 && dacword<4096); - usrp()->write_aux_dac(d_which, 0, dacword); -} - -void -db_tv_rx::_set_pga(float pga_gain) -{ - assert(pga_gain >=0 && pga_gain <=20); - if(d_which == 0) { - usrp()->set_pga(0, pga_gain); - } - else { - usrp()->set_pga (2, pga_gain); - } -} - -double -db_tv_rx::freq_min() -{ - return 50e6; -} - -double -db_tv_rx::freq_max() -{ - return 860e6; -} - -struct freq_result_t -db_tv_rx::set_freq(double target_freq) -{ - // Set the frequency. - // - // @param freq: target RF frequency in Hz - // @type freq: double - // - // @returns (ok, actual_baseband_freq) where: - // ok is True or False and indicates success or failure, - // actual_baseband_freq is RF frequency that corresponds to DC in the IF. - - freq_result_t args = {false, 0}; - - double fmin = freq_min(); - double fmax = freq_max(); - if((target_freq < fmin) || (target_freq > fmax)) { - return args; - } - - double target_lo_freq = target_freq + d_first_IF; // High side mixing - double f_ref = 4.0e6 / (double)(d_reference_divisor); // frequency steps - - int divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8)); - double actual_lo_freq = (f_ref * 8 * divisor); - double actual_freq = actual_lo_freq - d_first_IF; - - if((divisor & ~0x7fff) != 0) { // must be 15-bits or less - return args; - } - - // build i2c command string - std::vector buf(4); - buf[0] = (divisor >> 8) & 0xff; // DB1 - buf[1] = divisor & 0xff; // DB2 - buf[2] = control_byte_1(d_fast_tuning, d_reference_divisor); - buf[3] = control_byte_2(actual_freq, true); - - args.ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf)); - args.baseband_freq = actual_freq - d_second_IF; - return args; -} - -float -db_tv_rx::gain_min() -{ - return 0; -} - -float -db_tv_rx::gain_max() -{ - return 115; -} - -float -db_tv_rx::gain_db_per_step() -{ - return 1; -} - -bool -db_tv_rx::set_gain(float gain) -{ - // Set the gain. - // - // @param gain: gain in decibels - // @returns True/False - - float rfgain, ifgain, pgagain; - - assert(gain>=0 && gain<=115); - if(gain>60) { - rfgain = 60; - gain = gain - 60; - } - else { - rfgain = gain; - gain = 0; - } - - if(gain > 35) { - ifgain = 35; - gain = gain - 35; - } - else { - ifgain = gain; - gain = 0; - } - - pgagain = gain; - _set_rfagc(rfgain); - _set_ifagc(ifgain); - _set_pga(pgagain); - - return true; -} - -bool -db_tv_rx::is_quadrature() -{ - // Return True if this board requires both I & Q analog channels. - return false; -} - -bool -db_tv_rx::spectrum_inverted() -{ - // The 43.75 MHz version is inverted - return d_inverted; -} diff --git a/usrp/host/lib/legacy/db_tv_rx.h b/usrp/host/lib/legacy/db_tv_rx.h deleted file mode 100644 index ed916263..00000000 --- a/usrp/host/lib/legacy/db_tv_rx.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_TV_RX_H -#define DB_TV_RX_H - -#include - -class db_tv_rx : public db_base -{ -private: - void _set_rfagc(float gain); - void _set_ifagc(float gain); - void _set_pga(float pga_gain); - - int d_i2c_addr; - double d_first_IF, d_second_IF; - int d_reference_divisor; - bool d_fast_tuning; - bool d_inverted; - -public: - db_tv_rx(usrp_basic_sptr usrp, int which, - double first_IF, double second_IF); - ~db_tv_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - double freq_min(); - double freq_max(); - struct freq_result_t set_freq(double target_freq); - bool set_gain(float gain); - bool is_quadrature(); - bool spectrum_inverted(); -}; - -#endif diff --git a/usrp/host/lib/legacy/db_util.cc b/usrp/host/lib/legacy/db_util.cc deleted file mode 100644 index 4b46383b..00000000 --- a/usrp/host/lib/legacy/db_util.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include - -std::string -int_seq_to_str(std::vector &seq) -{ - //convert a sequence of integers into a string - - std::stringstream str; - std::vector::iterator i; - for(i = seq.begin(); i != seq.end(); i++) { - str << char((unsigned int)*i); - } - return str.str(); -} - -std::vector -str_to_int_seq(std::string str) -{ - //convert a string to a list of integers - std::vector seq; - std::vector::iterator sitr; - std::string::iterator i; - for(i=str.begin(); i != str.end(); i++) { - int a = (int)(*i); - seq.push_back(a); - } - return seq; -} - diff --git a/usrp/host/lib/legacy/db_util.h b/usrp/host/lib/legacy/db_util.h deleted file mode 100644 index e07abb60..00000000 --- a/usrp/host/lib/legacy/db_util.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef INCLUDED_DB_UTIL_H -#define INCLUDED_DB_UTIL_H - -#include -#include - -std::string int_seq_to_str(std::vector &seq); -std::vector str_to_int_seq(std::string str); - -#endif /* INCLUDED_DB_UTIL_H */ diff --git a/usrp/host/lib/legacy/db_wbx.cc b/usrp/host/lib/legacy/db_wbx.cc deleted file mode 100644 index 9f1d7293..00000000 --- a/usrp/host/lib/legacy/db_wbx.cc +++ /dev/null @@ -1,953 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#include -#include -#include -#include -#include -#include -#include - -// d'board i/o pin defs - -// TX IO Pins -#define TX_POWER (1 << 0) // TX Side Power -#define RX_TXN (1 << 1) // T/R antenna switch for TX/RX port -#define TX_ENB_MIX (1 << 2) // Enable IQ mixer -#define TX_ENB_VGA (1 << 3) - -// RX IO Pins -#define RX2_RX1N (1 << 0) // antenna switch between RX2 and TX/RX port -#define RXENABLE (1 << 1) // enables mixer -#define PLL_LOCK_DETECT (1 << 2) // Muxout pin from PLL -- MUST BE INPUT -#define MReset (1 << 3) // NB6L239 Master Reset, asserted low -#define SELA0 (1 << 4) // NB6L239 SelA0 -#define SELA1 (1 << 5) // NB6L239 SelA1 -#define SELB0 (1 << 6) // NB6L239 SelB0 -#define SELB1 (1 << 7) // NB6L239 SelB1 -#define PLL_ENABLE (1 << 8) // CE Pin on PLL -#define AUX_SCLK (1 << 9) // ALT SPI SCLK -#define AUX_SDO (1 << 10) // ALT SPI SDO -#define AUX_SEN (1 << 11) // ALT SPI SEN - - -wbx_base::wbx_base(usrp_basic_sptr usrp, int which) - : db_base(usrp, which) -{ - /* - * @param usrp: instance of usrp.source_c - * @param which: which side: 0 or 1 corresponding to side A or B respectively - * @type which: int - */ - - d_first = true; - d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; - - // FIXME -- the write reg functions don't work with 0xffff for masks - _rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff); - _rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE)); - - _tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff); - _tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); // TX off, TR switch set to RX - - if(d_which == 0) { - d_spi_enable = SPI_ENABLE_RX_A; - } - else { - d_spi_enable = SPI_ENABLE_RX_B; - } - - set_auto_tr(false); - -} - -wbx_base::~wbx_base() -{ - shutdown(); -} - - -void -wbx_base::shutdown() -{ - if (!d_is_shutdown){ - d_is_shutdown = true; - // do whatever there is to do to shutdown - - write_io(d_which, d_power_off, POWER_UP); // turn off power to board - _write_oe(d_which, 0, 0xffff); // turn off all outputs - set_auto_tr(false); // disable auto transmit - } -} - -bool -wbx_base::_lock_detect() -{ - /* - * @returns: the value of the VCO/PLL lock detect bit. - * @rtype: 0 or 1 - */ - - if(_rx_read_io() & PLL_LOCK_DETECT) { - return true; - } - else { // Give it a second chance - if(_rx_read_io() & PLL_LOCK_DETECT) { - return true; - } - else { - return false; - } - } -} - -bool -wbx_base::_tx_write_oe(int value, int mask) -{ - int reg = (d_which == 0 ? FR_OE_0 : FR_OE_2); - return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); -} - -bool -wbx_base::_rx_write_oe(int value, int mask) -{ - int reg = (d_which == 0 ? FR_OE_1 : FR_OE_3); - return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); -} - -bool -wbx_base::_tx_write_io(int value, int mask) -{ - int reg = (d_which == 0 ? FR_IO_0 : FR_IO_2); - return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); -} - -bool -wbx_base::_rx_write_io(int value, int mask) -{ - int reg = (d_which == 0 ? FR_IO_1 : FR_IO_3); - return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); -} - -bool -wbx_base::_rx_read_io() -{ - int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); - int t = d_usrp->_read_fpga_reg(reg); - return (t >> 16) & 0xffff; -} - -bool -wbx_base::_tx_read_io() -{ - int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); - int t = d_usrp->_read_fpga_reg(reg); - return (t & 0xffff); -} - -bool -wbx_base::_compute_regs(double freq) -{ - /* - * Determine values of registers, along with actual freq. - * - * @param freq: target frequency in Hz - * @type freq: double - * @returns: (R, N, func, init, actual_freq) - * @rtype: tuple(int, int, int, int, double) - * - * Override this in derived classes. - */ - throw std::runtime_error("_compute_regs called from base class\n"); -} - -double -wbx_base::_refclk_freq() -{ - return (double)(d_usrp->fpga_master_clock_freq())/_refclk_divisor(); -} - -int -wbx_base::_refclk_divisor() -{ - /* - * Return value to stick in REFCLK_DIVISOR register - */ - return 1; -} - -struct freq_result_t -wbx_base::set_freq(double freq) -{ - /* - * @returns (ok, actual_baseband_freq) where: - * ok is True or False and indicates success or failure, - * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. - */ - throw std::runtime_error("set_freq called from base class\n"); -} - -float -wbx_base::gain_min() -{ - throw std::runtime_error("gain_min called from base class\n"); -} - -float -wbx_base::gain_max() -{ - throw std::runtime_error("gain_max called from base class\n"); -} - -float -wbx_base::gain_db_per_step() -{ - throw std::runtime_error("gain_db_per_step called from base class\n"); -} - -bool -wbx_base::set_gain(float gain) -{ - /* - * Set the gain. - * - * @param gain: gain in decibels - * @returns True/False - */ - throw std::runtime_error("set_gain called from base class\n"); -} - -bool -wbx_base::_set_pga(float pga_gain) -{ - bool ok; - if(d_which == 0) { - ok = d_usrp->set_pga(0, pga_gain); - ok |= d_usrp->set_pga(1, pga_gain); - } - else { - ok = d_usrp->set_pga(2, pga_gain); - ok |= d_usrp->set_pga(3, pga_gain); - } - return ok; -} - -bool -wbx_base::is_quadrature() -{ - /* - * Return True if this board requires both I & Q analog channels. - * - * This bit of info is useful when setting up the USRP Rx mux register. - */ - return true; -} - - -/****************************************************************************/ - - -wbx_base_tx::wbx_base_tx(usrp_basic_sptr usrp, int which) - : wbx_base(usrp, which) -{ - /* - * @param usrp: instance of usrp.sink_c - * @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. - */ - - // power up the transmit side, NO -- but set antenna to receive - d_usrp->write_io(d_which, (TX_POWER), (TX_POWER|RX_TXN)); - d_lo_offset = 0e6; - - // Gain is not set by the PGA, but the PGA must be set at max gain in the TX - _set_pga(d_usrp->pga_max()); -} - -wbx_base_tx::~wbx_base_tx() -{ - // Power down and leave the T/R switch in the R position - d_usrp->write_io(d_which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); -} - -void -wbx_base_tx::set_auto_tr(bool on) -{ - if(on) { - set_atr_mask (RX_TXN); - set_atr_txval(0); - set_atr_rxval(RX_TXN); - } - else { - set_atr_mask (0); - set_atr_txval(0); - set_atr_rxval(0); - } -} - -void -wbx_base_tx::set_enable(bool on) -{ - /* - * Enable transmitter if on is True - */ - - int mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA; - //printf("HERE!!!!\n"); - if(on) { - d_usrp->write_io(d_which, TX_ENB_MIX|TX_ENB_VGA, mask); - } - else { - d_usrp->write_io(d_which, RX_TXN, mask); - } -} - -void -wbx_base_tx::set_lo_offset(double offset) -{ - /* - * Set amount by which LO is offset from requested tuning frequency. - * - * @param offset: offset in Hz - */ - - d_lo_offset = offset; -} - -double -wbx_base_tx::lo_offset() -{ - /* - * Get amount by which LO is offset from requested tuning frequency. - * - * @returns Offset in Hz - */ - - return d_lo_offset; -} - - -/****************************************************************************/ - - -wbx_base_rx::wbx_base_rx(usrp_basic_sptr usrp, int which) - : wbx_base(usrp, which) -{ - /* - * @param usrp: instance of usrp.source_c - * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. - */ - - // set up for RX on TX/RX port - select_rx_antenna("TX/RX"); - - bypass_adc_buffers(true); - - d_lo_offset = 0.0; -} - -wbx_base_rx::~wbx_base_rx() -{ - // Power down - d_usrp->write_io(d_which, 0, (RXENABLE)); -} - -void -wbx_base_rx::set_auto_tr(bool on) -{ - if(on) { - // FIXME: where does ENABLE come from? - //set_atr_mask (ENABLE); - set_atr_txval( 0); - //set_atr_rxval(ENABLE); - } - else { - set_atr_mask (0); - set_atr_txval(0); - set_atr_rxval(0); - } -} - -void -wbx_base_rx::select_rx_antenna(int which_antenna) -{ - /* - * Specify which antenna port to use for reception. - * @param which_antenna: either 'TX/RX' or 'RX2' - */ - - if(which_antenna == 0) { - d_usrp->write_io(d_which, 0, RX2_RX1N); - } - else if(which_antenna == 1) { - d_usrp->write_io(d_which, RX2_RX1N, RX2_RX1N); - } - else { - throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); - } -} - -void -wbx_base_rx::select_rx_antenna(const std::string &which_antenna) -{ - if(which_antenna == "TX/RX") { - select_rx_antenna(0); - } - else if(which_antenna == "RX2") { - select_rx_antenna(1); - } - else { - throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); - } -} - -bool -wbx_base_rx::set_gain(float gain) -{ - /* - * Set the gain. - * - * @param gain: gain in decibels - * @returns True/False - */ - - float pga_gain, agc_gain; - float maxgain = gain_max() - d_usrp->pga_max(); - float mingain = gain_min(); - if(gain > maxgain) { - pga_gain = gain-maxgain; - assert(pga_gain <= d_usrp->pga_max()); - agc_gain = maxgain; - } - else { - pga_gain = 0; - agc_gain = gain; - } - - float V_maxgain = .2; - float V_mingain = 1.2; - float V_fullscale = 3.3; - float dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; - - assert(dac_value>=0 && dac_value<4096); - - return d_usrp->write_aux_dac(d_which, 0, (int)(dac_value)) && _set_pga((int)(pga_gain)); -} - -void -wbx_base_rx::set_lo_offset(double offset) -{ - /* - * Set amount by which LO is offset from requested tuning frequency. - * - * @param offset: offset in Hz - */ - d_lo_offset = offset; -} - -double -wbx_base_rx::lo_offset() -{ - /* - * Get amount by which LO is offset from requested tuning frequency. - * - * @returns Offset in Hz - */ - return d_lo_offset; -} - -bool -wbx_base_rx::i_and_q_swapped() -{ - /* - * Return True if this is a quadrature device and ADC 0 is Q. - */ - return false; -} - - -/****************************************************************************/ - -_ADF410X_common::_ADF410X_common() -{ - // R-Register Common Values - d_R_RSV = 0; // bits 23,22,21 - d_LDP = 1; // bit 20 Lock detect in 5 cycles - d_TEST = 0; // bit 19,18 Normal - d_ABP = 0; // bit 17,16 2.9ns - - // N-Register Common Values - d_N_RSV = 0; // 23,22 - d_CP_GAIN = 0; // 21 - - // Function Register Common Values - d_P = 0; // bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65 - d_PD2 = 0; // bit 21 Normal operation - d_CP2 = 4; // bits 20,19,18 CP Gain = 5mA - d_CP1 = 4; // bits 17,16,15 CP Gain = 5mA - d_TC = 0; // bits 14-11 PFD Timeout - d_FL = 0; // bit 10,9 Fastlock Disabled - d_CP3S = 0; // bit 8 CP Enabled - d_PDP = 0; // bit 7 Phase detector polarity, Positive=1 - d_MUXOUT = 1; // bits 6:4 Digital Lock Detect - d_PD1 = 0; // bit 3 Normal operation - d_CR = 0; // bit 2 Normal operation -} - -_ADF410X_common::~_ADF410X_common() -{ -} - -bool -_ADF410X_common::_compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq) -{ - /* - * Determine values of R, control, and N registers, along with actual freq. - * - * @param freq: target frequency in Hz - * @type freq: double - * @returns: (R, N, control, actual_freq) - * @rtype: tuple(int, int, int, double) - */ - - // Band-specific N-Register Values - double phdet_freq = _refclk_freq()/d_R_DIV; - printf("phdet_freq = %f\n", phdet_freq); - - double desired_n = round(freq*d_freq_mult/phdet_freq); - printf("desired_n %f\n", desired_n); - - double actual_freq = desired_n * phdet_freq; - printf("actual freq %f\n", actual_freq); - - double B = floor(desired_n/_prescaler()); - double A = desired_n - _prescaler()*B; - printf("A %f B %f\n", A, B); - - d_B_DIV = int(B); // bits 20:8; - d_A_DIV = int(A); // bit 6:2; - - if(d_B_DIV < d_A_DIV) { - retR = 0; - retN = 0; - retcontrol = 0; - retfreq = 0; - return false; - } - - retR = (d_R_RSV<<21) | (d_LDP<<20) | (d_TEST<<18) | - (d_ABP<<16) | (d_R_DIV<<2); - - retN = (d_N_RSV<<22) | (d_CP_GAIN<<21) | (d_B_DIV<<8) | (d_A_DIV<<2); - - retcontrol = (d_P<<22) | (d_PD2<<21) | (d_CP2<<18) | (d_CP1<<15) | - (d_TC<<11) | (d_FL<<9) | (d_CP3S<<8) | (d_PDP<<7) | - (d_MUXOUT<<4) | (d_PD1<<3) | (d_CR<<2); - - retfreq = actual_freq/d_freq_mult; - - return true; -} - -void -_ADF410X_common::_write_all(int R, int N, int control) -{ - /* - * Write all PLL registers: - * R counter latch, - * N counter latch, - * Function latch, - * Initialization latch - * - * Adds 10ms delay between writing control and N if this is first call. - * This is the required power-up sequence. - * - * @param R: 24-bit R counter latch - * @type R: int - * @param N: 24-bit N counter latch - * @type N: int - * @param control: 24-bit control latch - * @type control: int - */ - static bool first = true; - - timespec t; - t.tv_sec = 0; - t.tv_nsec = 10000000; - - _write_R(R); - _write_func(control); - _write_init(control); - if(first) { - //time.sleep(0.010); - nanosleep(&t, NULL); - first = false; - } - _write_N(N); -} - -void -_ADF410X_common::_write_R(int R) -{ - _write_it((R & ~0x3) | 0); -} - -void -_ADF410X_common::_write_N(int N) -{ - _write_it((N & ~0x3) | 1); -} - -void -_ADF410X_common::_write_func(int func) -{ - _write_it((func & ~0x3) | 2); -} - -void -_ADF410X_common::_write_init(int init) -{ - _write_it((init & ~0x3) | 3); -} - -void -_ADF410X_common::_write_it(int v) -{ - char c[3]; - c[0] = (char)((v >> 16) & 0xff); - c[1] = (char)((v >> 8) & 0xff); - c[2] = (char)((v & 0xff)); - std::string s(c, 3); - //d_usrp->_write_spi(0, d_spi_enable, d_spi_format, s); - usrp()->_write_spi(0, d_spi_enable, d_spi_format, s); -} - -int -_ADF410X_common::_prescaler() -{ - if(d_P == 0) { - return 8; - } - else if(d_P == 1) { - return 16; - } - else if(d_P == 2) { - return 32; - } - else if(d_P == 3) { - return 64; - } - else { - throw std::invalid_argument("Prescaler out of range\n"); - } -} - -double -_ADF410X_common::_refclk_freq() -{ - throw std::runtime_error("_refclk_freq called from base class."); -} - -bool -_ADF410X_common::_rx_write_io(int value, int mask) -{ - throw std::runtime_error("_rx_write_io called from base class."); -} - -bool -_ADF410X_common::_lock_detect() -{ - throw std::runtime_error("_lock_detect called from base class."); -} - -usrp_basic* -_ADF410X_common::usrp() -{ - throw std::runtime_error("usrp() called from base class."); -} - - -/****************************************************************************/ - - -_lo_common::_lo_common() - : _ADF410X_common() -{ - // Band-specific R-Register Values - d_R_DIV = 4; // bits 15:2 - - // Band-specific C-Register values - d_P = 0; // bits 23,22 0 = Div by 8/9 - d_CP2 = 4; // bits 19:17 - d_CP1 = 4; // bits 16:14 - - // Band specifc N-Register Values - d_DIVSEL = 0; // bit 23 - d_DIV2 = 0; // bit 22 - d_CPGAIN = 0; // bit 21 - d_freq_mult = 1; - - d_div = 1; - d_aux_div = 2; - d_main_div = 0; -} - -_lo_common::~_lo_common() -{ -} - -double -_lo_common::freq_min() -{ - return 50e6; -} - -double -_lo_common::freq_max() -{ - return 1000e6; -} - -void -_lo_common::set_divider(int main_or_aux, int divisor) -{ - if(main_or_aux == 0) { - if((divisor != 1) || (divisor != 2) || (divisor != 4) || (divisor != 8)) { - throw std::invalid_argument("Main Divider Must be 1, 2, 4, or 8\n"); - } - d_main_div = (int)(log10(divisor)/log10(2.0)); - } - else if(main_or_aux == 1) { - if((divisor != 2) || (divisor != 4) || (divisor != 8) || (divisor != 16)) { - throw std::invalid_argument("Aux Divider Must be 2, 4, 8 or 16\n"); - } - d_main_div = (int)(log10(divisor/2.0)/log10(2.0)); - } - else { - throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); - } - - int vala = d_main_div*SELA0; - int valb = d_aux_div*SELB0; - int mask = SELA0|SELA1|SELB0|SELB1; - - _rx_write_io((vala | valb), mask); -} - -void -_lo_common::set_divider(const std::string &main_or_aux, int divisor) -{ - if(main_or_aux == "main") { - set_divider(0, divisor); - } - else if(main_or_aux == "aux") { - set_divider(1, divisor); - } - else { - throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); - } -} - -struct freq_result_t -_lo_common::set_freq(double freq) -{ - struct freq_result_t ret; - - if(freq < 20e6 or freq > 1200e6) { - throw std::invalid_argument("Requested frequency out of range\n"); - } - - int div = 1; - double lo_freq = freq * 2; - while((lo_freq < 1e9) && (div < 8)) { - div = div * 2; - lo_freq = lo_freq * 2; - } - - printf("For RF freq of %f, we set DIV=%d and LO Freq=%f\n", freq, div, lo_freq); - - set_divider("main", div); - set_divider("aux", div*2); - - int R, N, control; - double actual_freq; - _compute_regs(lo_freq, R, N, control, actual_freq); - - printf("R %d N %d control %d actual freq %f\n", R, N, control, actual_freq); - if(R==0) { - ret.ok = false; - ret.baseband_freq = 0.0; - return ret; - } - _write_all(R, N, control); - - ret.ok = _lock_detect(); - ret.baseband_freq = actual_freq/div/2; - return ret; -} - - -/****************************************************************************/ - - -db_wbx_lo_tx::db_wbx_lo_tx(usrp_basic_sptr usrp, int which) - : _lo_common(), - wbx_base_tx(usrp, which) -{ -} - -db_wbx_lo_tx::~db_wbx_lo_tx() -{ -} - -float -db_wbx_lo_tx::gain_min() -{ - return -56.0; -} - -float -db_wbx_lo_tx::gain_max() -{ - return 0.0; -} - -float -db_wbx_lo_tx::gain_db_per_step() -{ - return 0.1; -} - -bool -db_wbx_lo_tx::set_gain(float gain) -{ - /* - * Set the gain. - * - * @param gain: gain in decibels - * @returns True/False - */ - - float txvga_gain; - float maxgain = gain_max(); - float mingain = gain_min(); - if(gain > maxgain) { - txvga_gain = maxgain; - } - else if(gain < mingain) { - txvga_gain = mingain; - } - else { - txvga_gain = gain; - } - - float V_maxgain = 1.4; - float V_mingain = 0.1; - float V_fullscale = 3.3; - float dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/ - (maxgain-mingain) + V_mingain)*4096/V_fullscale; - - assert(dac_value>=0 && dac_value<4096); - printf("DAC value %f\n", dac_value); - - return d_usrp->write_aux_dac(d_which, 1, (int)(dac_value)); -} - -double -db_wbx_lo_tx::_refclk_freq() -{ - return wbx_base::_refclk_freq(); -} - -bool -db_wbx_lo_tx::_rx_write_io(int value, int mask) -{ - return wbx_base::_rx_write_io(value, mask); -} - -bool -db_wbx_lo_tx::_lock_detect() -{ - return wbx_base::_lock_detect(); -} - -usrp_basic* -db_wbx_lo_tx::usrp() -{ - return d_usrp; -} - - -/****************************************************************************/ - - -db_wbx_lo_rx::db_wbx_lo_rx(usrp_basic_sptr usrp, int which) - : _lo_common(), - wbx_base_rx(usrp, which) -{ -} - -db_wbx_lo_rx::~db_wbx_lo_rx() -{ -} - -float -db_wbx_lo_rx::gain_min() -{ - return d_usrp->pga_min(); -} - -float -db_wbx_lo_rx::gain_max() -{ - return d_usrp->pga_max() + 45; -} - -float -db_wbx_lo_rx::gain_db_per_step() -{ - return 0.05; -} - -double -db_wbx_lo_rx::_refclk_freq() -{ - return wbx_base::_refclk_freq(); -} - -bool -db_wbx_lo_rx::_rx_write_io(int value, int mask) -{ - return wbx_base::_rx_write_io(value, mask); -} - -bool -db_wbx_lo_rx::_lock_detect() -{ - return wbx_base::_lock_detect(); -} - -usrp_basic* -db_wbx_lo_rx::usrp() -{ - return d_usrp; -} diff --git a/usrp/host/lib/legacy/db_wbx.h b/usrp/host/lib/legacy/db_wbx.h deleted file mode 100644 index 3202d368..00000000 --- a/usrp/host/lib/legacy/db_wbx.h +++ /dev/null @@ -1,221 +0,0 @@ -/* -*- c++ -*- */ -// -// Copyright 2008 Free Software Foundation, Inc. -// -// This file is part of GNU Radio -// -// GNU Radio is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either asversion 3, or (at your option) -// any later version. -// -// GNU Radio is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with GNU Radio; see the file COPYING. If not, write to -// the Free Software Foundation, Inc., 51 Franklin Street, -// Boston, MA 02110-1301, USA. - -#ifndef DB_WBX_H -#define DB_WBX_H - -#include -#include - - -/* - A few comments about the WBX boards: - They are half-duplex. I.e., transmit and receive are mutually exclusive. - There is a single LO for both the Tx and Rx sides. - The the shared control signals are hung off of the Rx side. - The shared io controls are duplexed onto the Rx side pins. - The wbx_high d'board always needs to be in 'auto_tr_mode' -*/ - - -class wbx_base : public db_base -{ -protected: - void shutdown(); - - /* - * Abstract base class for all wbx boards. - * - * Derive board specific subclasses from db_wbx_base_{tx,rx} - */ - -public: - wbx_base(usrp_basic_sptr usrp, int which); - ~wbx_base(); - - struct freq_result_t set_freq(double freq); - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool set_gain(float gain); - bool is_quadrature(); - - -protected: - virtual bool _lock_detect(); - - // FIXME: After testing, replace these with usrp_basic::common_write_io/oe - bool _tx_write_oe(int value, int mask); - bool _rx_write_oe(int value, int mask); - bool _tx_write_io(int value, int mask); - bool _rx_write_io(int value, int mask); - virtual bool _rx_read_io(); - bool _tx_read_io(); - bool _compute_regs(double freq); - virtual double _refclk_freq(); - int _refclk_divisor(); - - bool _set_pga(float pga_gain); - - bool d_first; - int d_spi_format; - int d_spi_enable; - double d_lo_offset; -}; - - -/****************************************************************************/ - - -class wbx_base_tx : public wbx_base -{ -public: - wbx_base_tx(usrp_basic_sptr usrp, int which); - ~wbx_base_tx(); - - bool set_auto_tr(bool on); - bool set_enable(bool on); -}; - - -/****************************************************************************/ - - -class wbx_base_rx : public wbx_base -{ -public: - wbx_base_rx(usrp_basic_sptr usrp, int which); - ~wbx_base_rx(); - - bool set_auto_tr(bool on); - bool select_rx_antenna(int which_antenna); - bool select_rx_antenna(const std::string &which_antenna); - bool set_gain(float gain); - bool i_and_q_swapped(); -}; - - -/****************************************************************************/ - - -class _ADF410X_common -{ -public: - _ADF410X_common(); - virtual ~_ADF410X_common(); - - bool _compute_regs(double freq, int &retR, int &retcontrol, - int &retN, double &retfreq); - void _write_all(int R, int N, int control); - void _write_R(int R); - void _write_N(int N); - void _write_func(int func); - void _write_init(int init); - int _prescaler(); - virtual void _write_it(int v); - virtual double _refclk_freq(); - virtual bool _rx_write_io(int value, int mask); - virtual bool _lock_detect(); - -protected: - virtual usrp_basic* usrp(); - - int d_R_RSV, d_LDP, d_TEST, d_ABP; - int d_N_RSV, d_CP_GAIN; - int d_P, d_PD2, d_CP2, d_CP1, d_TC, d_FL; - int d_CP3S, d_PDP, d_MUXOUT, d_PD1, d_CR; - int d_R_DIV, d_A_DIV, d_B_DIV; - int d_freq_mult; - - int d_spi_format; - int d_spi_enable; -}; - - -/****************************************************************************/ - - -class _lo_common : public _ADF410X_common -{ -public: - _lo_common(); - ~_lo_common(); - - double freq_min(); - double freq_max(); - - void set_divider(int main_or_aux, int divisor); - void set_divider(const std::string &main_or_aux, int divisor); - - struct freq_result_t set_freq(double freq); - -protected: - int d_R_DIV, d_P, d_CP2, d_CP1; - int d_DIVSEL, d_DIV2, d_CPGAIN; - int d_div, d_aux_div, d_main_div; -}; - - -/****************************************************************************/ - - -class db_wbx_lo_tx : public _lo_common, public wbx_base_tx -{ -public: - db_wbx_lo_tx(usrp_basic_sptr usrp, int which); - ~db_wbx_lo_tx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - bool set_gain(float gain); - - double _refclk_freq(); - bool _rx_write_io(int value, int mask); - bool _lock_detect(); - -protected: - usrp_basic* usrp(); -}; - - -/****************************************************************************/ - - -class db_wbx_lo_rx : public _lo_common, public wbx_base_rx -{ -public: - db_wbx_lo_rx(usrp_basic_sptr usrp, int which); - ~db_wbx_lo_rx(); - - float gain_min(); - float gain_max(); - float gain_db_per_step(); - - double _refclk_freq(); - bool _rx_write_io(int value, int mask); - bool _lock_detect(); - -protected: - usrp_basic* usrp(); -}; - -#endif diff --git a/usrp/host/lib/legacy/db_xcvr2450.cc b/usrp/host/lib/legacy/db_xcvr2450.cc deleted file mode 100644 index 9ce3168e..00000000 --- a/usrp/host/lib/legacy/db_xcvr2450.cc +++ /dev/null @@ -1,791 +0,0 @@ -// -// 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 -#include -#include -#include -#include -#include - -#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 value; - - xcvr2450_table_entry(const xcvr2450_key &_key, boost::weak_ptr _value) - : key(_key), value(_value) {} -}; - -typedef std::vector 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); -} diff --git a/usrp/host/lib/legacy/db_xcvr2450.h b/usrp/host/lib/legacy/db_xcvr2450.h deleted file mode 100644 index 1f9dd7c2..00000000 --- a/usrp/host/lib/legacy/db_xcvr2450.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- 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 -#include - -class xcvr2450; -typedef boost::shared_ptr 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 diff --git a/usrp/host/lib/legacy/dump_data.py b/usrp/host/lib/legacy/dump_data.py deleted file mode 100755 index 034586d8..00000000 --- a/usrp/host/lib/legacy/dump_data.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/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 - - - diff --git a/usrp/host/lib/legacy/fusb.cc b/usrp/host/lib/legacy/fusb.cc deleted file mode 100644 index 6e4358f5..00000000 --- a/usrp/host/lib/legacy/fusb.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- 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 - - -// ------------------------------------------------------------------------ -// device handle -// ------------------------------------------------------------------------ - -fusb_devhandle::fusb_devhandle (usb_dev_handle *udh) - : d_udh (udh) -{ - // that's it -}; - -fusb_devhandle::~fusb_devhandle () -{ - // nop -} - -// ------------------------------------------------------------------------ -// end point handle -// ------------------------------------------------------------------------ - -fusb_ephandle::fusb_ephandle (int endpoint, bool input_p, - int block_size, int nblocks) - : d_endpoint (endpoint), d_input_p (input_p), - d_block_size (block_size), d_nblocks (nblocks), d_started (false) -{ - // that't it -} - -fusb_ephandle::~fusb_ephandle () -{ - // nop -} diff --git a/usrp/host/lib/legacy/fusb.h b/usrp/host/lib/legacy/fusb.h deleted file mode 100644 index 769e51cc..00000000 --- a/usrp/host/lib/legacy/fusb.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- 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_ */ diff --git a/usrp/host/lib/legacy/fusb_darwin.cc b/usrp/host/lib/legacy/fusb_darwin.cc deleted file mode 100644 index 737387b8..00000000 --- a/usrp/host/lib/legacy/fusb_darwin.cc +++ /dev/null @@ -1,572 +0,0 @@ -/* -*- 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 -#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 (NUM_QUEUE_ITEMS * d_bufLenBytes, - !d_input_p, d_input_p); - -// create the queue - d_queue = new circular_linked_list (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 (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(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(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(refCon); - fusb_ephandle_darwin* This = static_cast(l_both->This ()); - s_node_ptr l_node = l_both->node (); - circular_buffer* 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(refCon); - fusb_ephandle_darwin* This = static_cast(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); -} diff --git a/usrp/host/lib/legacy/fusb_darwin.h b/usrp/host/lib/legacy/fusb_darwin.h deleted file mode 100644 index bb717b58..00000000 --- a/usrp/host/lib/legacy/fusb_darwin.h +++ /dev/null @@ -1,215 +0,0 @@ -/* -*- 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 -#include "fusb.h" -#include -#include -#include -#include -#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_node_ptr; -typedef circular_linked_list* s_queue_ptr; -typedef s_both* 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* d_buffer; - UInt32 d_bufLenBytes; - mld_mutex_ptr d_readRunning; - mld_condition_ptr d_runBlock, d_readBlock; - -// CREATORS - - fusb_ephandle_darwin (fusb_devhandle_darwin *dh, int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); - virtual ~fusb_ephandle_darwin (); - -// MANIPULATORS - - virtual bool start (); //!< begin streaming i/o - virtual bool stop (); //!< stop streaming i/o - - /*! - * \returns \p nbytes if write was successfully enqueued, else -1. - * Will block if no free buffers available. - */ - virtual int write (const void* buffer, int nbytes); - - /*! - * \returns number of bytes read or -1 if error. - * number of bytes read will be <= nbytes. - * Will block if no input available. - */ - virtual int read (void* buffer, int nbytes); - - /* - * abort any pending IO transfers - */ - void abort (); - - /* - * block until all outstanding writes have completed - */ - virtual void wait_for_completion (); -}; - -#endif /* _FUSB_DARWIN_H_ */ diff --git a/usrp/host/lib/legacy/fusb_generic.cc b/usrp/host/lib/legacy/fusb_generic.cc deleted file mode 100644 index 0958716d..00000000 --- a/usrp/host/lib/legacy/fusb_generic.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- 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 -#include - - -static const int USB_TIMEOUT = 1000; // in milliseconds - - -fusb_devhandle_generic::fusb_devhandle_generic (usb_dev_handle *udh) - : fusb_devhandle (udh) -{ - // that's it -} - -fusb_devhandle_generic::~fusb_devhandle_generic () -{ - // nop -} - -fusb_ephandle * -fusb_devhandle_generic::make_ephandle (int endpoint, bool input_p, - int block_size, int nblocks) -{ - return new fusb_ephandle_generic (this, endpoint, input_p, - block_size, nblocks); -} - -// ---------------------------------------------------------------- - -fusb_ephandle_generic::fusb_ephandle_generic (fusb_devhandle_generic *dh, - int endpoint, bool input_p, - int block_size, int nblocks) - : fusb_ephandle (endpoint, input_p, block_size, nblocks), - d_devhandle (dh) -{ - // that's it -} - -fusb_ephandle_generic::~fusb_ephandle_generic () -{ - // nop -} - -bool -fusb_ephandle_generic::start () -{ - d_started = true; - return true; -} - -bool -fusb_ephandle_generic::stop () -{ - d_started = false; - return true; -} - -int -fusb_ephandle_generic::write (const void *buffer, int nbytes) -{ - if (!d_started) // doesn't matter here, but keeps semantics constant - return -1; - - if (d_input_p) - return -1; - - return usb_bulk_write (d_devhandle->get_usb_dev_handle (), - d_endpoint, (char *) buffer, nbytes, USB_TIMEOUT); -} - -int -fusb_ephandle_generic::read (void *buffer, int nbytes) -{ - if (!d_started) // doesn't matter here, but keeps semantics constant - return -1; - - if (!d_input_p) - return -1; - - return usb_bulk_read (d_devhandle->get_usb_dev_handle (), - d_endpoint|USB_ENDPOINT_IN, (char *) buffer, nbytes, - USB_TIMEOUT); -} diff --git a/usrp/host/lib/legacy/fusb_generic.h b/usrp/host/lib/legacy/fusb_generic.h deleted file mode 100644 index b9aef273..00000000 --- a/usrp/host/lib/legacy/fusb_generic.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- 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 - -/*! - * \brief generic implementation of fusb_devhandle using only libusb - */ -class fusb_devhandle_generic : public fusb_devhandle -{ -public: - // CREATORS - fusb_devhandle_generic (usb_dev_handle *udh); - virtual ~fusb_devhandle_generic (); - - // MANIPULATORS - virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); -}; - - -/*! - * \brief generic implementation of fusb_ephandle using only libusb - */ -class fusb_ephandle_generic : public fusb_ephandle -{ -private: - fusb_devhandle_generic *d_devhandle; - -public: - // CREATORS - fusb_ephandle_generic (fusb_devhandle_generic *dh, int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); - virtual ~fusb_ephandle_generic (); - - // MANIPULATORS - - virtual bool start (); //!< begin streaming i/o - virtual bool stop (); //!< stop streaming i/o - - /*! - * \returns \p nbytes if write was successfully enqueued, else -1. - * Will block if no free buffers available. - */ - virtual int write (const void *buffer, int nbytes); - - /*! - * \returns number of bytes read or -1 if error. - * number of bytes read will be <= nbytes. - * Will block if no input available. - */ - virtual int read (void *buffer, int nbytes); - - /* - * block until all outstanding writes have completed - */ - virtual void wait_for_completion () { }; -}; - -#endif /* _FUSB_GENERIC_H_ */ - diff --git a/usrp/host/lib/legacy/fusb_linux.cc b/usrp/host/lib/legacy/fusb_linux.cc deleted file mode 100644 index 6c484569..00000000 --- a/usrp/host/lib/legacy/fusb_linux.cc +++ /dev/null @@ -1,692 +0,0 @@ -/* -*- 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 -#include // libusb header -#include -#ifdef HAVE_LINUX_COMPILER_H -#include -#endif -#include // interface to kernel portion of user mode usb driver -#include -#include -#include -#include -#include -#include -#include - -#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::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::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::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; -} - // ------------------------------------------------------------------------ -// 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; -} diff --git a/usrp/host/lib/legacy/fusb_linux.h b/usrp/host/lib/legacy/fusb_linux.h deleted file mode 100644 index 107e1af7..00000000 --- a/usrp/host/lib/legacy/fusb_linux.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- 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 -#include - -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 d_pending_rqsts; - - void pending_add (usbdevfs_urb *urb); - bool pending_remove (usbdevfs_urb *urb); - usbdevfs_urb * pending_get (); - - -public: - // CREATORS - fusb_devhandle_linux (usb_dev_handle *udh); - virtual ~fusb_devhandle_linux (); - - // MANIPULATORS - virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); - - // internal use only - bool _submit_urb (usbdevfs_urb *urb); - bool _cancel_urb (usbdevfs_urb *urb); - void _cancel_pending_rqsts (fusb_ephandle_linux *eph); - bool _reap (bool ok_to_block_p); - void _wait_for_completion (); -}; - - /*! - * \brief linux specific implementation of fusb_ephandle using usbdevice_fs - */ - -class fusb_ephandle_linux : public fusb_ephandle { -private: - fusb_devhandle_linux *d_devhandle; - std::list d_free_list; - std::list d_completed_list; - usbdevfs_urb *d_write_work_in_progress; - unsigned char *d_write_buffer; - usbdevfs_urb *d_read_work_in_progress; - unsigned char *d_read_buffer; - unsigned char *d_read_buffer_end; - - usbdevfs_urb *get_write_work_in_progress (); - void reap_complete_writes (); - bool reload_read_buffer (); - bool submit_urb (usbdevfs_urb *urb); - -public: - fusb_ephandle_linux (fusb_devhandle_linux *dh, int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); - virtual ~fusb_ephandle_linux (); - - virtual bool start (); //!< begin streaming i/o - virtual bool stop (); //!< stop streaming i/o - - /*! - * \returns \p nbytes if write was successfully enqueued, else -1. - * Will block if no free buffers available. - */ - virtual int write (const void *buffer, int nbytes); - - /*! - * \returns number of bytes read or -1 if error. - * number of bytes read will be <= nbytes. - * Will block if no input available. - */ - virtual int read (void *buffer, int nbytes); - - /* - * block until all outstanding writes have completed - */ - virtual void wait_for_completion (); - - // internal use only - void free_list_add (usbdevfs_urb *urb); - void completed_list_add (usbdevfs_urb *urb); - usbdevfs_urb *free_list_get (); // pop and return head of list or 0 - usbdevfs_urb *completed_list_get (); // pop and return head of list or 0 -}; - -#endif /* _FUSB_LINUX_H_ */ diff --git a/usrp/host/lib/legacy/fusb_ra_wb.cc b/usrp/host/lib/legacy/fusb_ra_wb.cc deleted file mode 100644 index 699a34b3..00000000 --- a/usrp/host/lib/legacy/fusb_ra_wb.cc +++ /dev/null @@ -1,258 +0,0 @@ -/* -*- 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 -#include - -#include -#include -#include - -#include -#include - -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); - } -} diff --git a/usrp/host/lib/legacy/fusb_ra_wb.h b/usrp/host/lib/legacy/fusb_ra_wb.h deleted file mode 100644 index 233976ab..00000000 --- a/usrp/host/lib/legacy/fusb_ra_wb.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- 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 - -/*! - * \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_ */ - diff --git a/usrp/host/lib/legacy/fusb_sysconfig_darwin.cc b/usrp/host/lib/legacy/fusb_sysconfig_darwin.cc deleted file mode 100644 index 4d19d129..00000000 --- a/usrp/host/lib/legacy/fusb_sysconfig_darwin.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- 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 -#include - -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; -} - diff --git a/usrp/host/lib/legacy/fusb_sysconfig_generic.cc b/usrp/host/lib/legacy/fusb_sysconfig_generic.cc deleted file mode 100644 index 58baba5a..00000000 --- a/usrp/host/lib/legacy/fusb_sysconfig_generic.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- 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 -#include - -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; -} diff --git a/usrp/host/lib/legacy/fusb_sysconfig_linux.cc b/usrp/host/lib/legacy/fusb_sysconfig_linux.cc deleted file mode 100644 index 3c2f5937..00000000 --- a/usrp/host/lib/legacy/fusb_sysconfig_linux.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- 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 -#include - -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; -} diff --git a/usrp/host/lib/legacy/fusb_sysconfig_ra_wb.cc b/usrp/host/lib/legacy/fusb_sysconfig_ra_wb.cc deleted file mode 100644 index 9da831fd..00000000 --- a/usrp/host/lib/legacy/fusb_sysconfig_ra_wb.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- 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 -#include - -//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; -} diff --git a/usrp/host/lib/legacy/fusb_sysconfig_win32.cc b/usrp/host/lib/legacy/fusb_sysconfig_win32.cc deleted file mode 100644 index 16eaaa64..00000000 --- a/usrp/host/lib/legacy/fusb_sysconfig_win32.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- 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 -#include - -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; -} diff --git a/usrp/host/lib/legacy/fusb_win32.cc b/usrp/host/lib/legacy/fusb_win32.cc deleted file mode 100644 index 8900576d..00000000 --- a/usrp/host/lib/legacy/fusb_win32.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include - -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 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 - -/*! - * \brief win32 implementation of fusb_devhandle using libusb-win32 - */ -class fusb_devhandle_win32 : public fusb_devhandle -{ -public: - // CREATORS - fusb_devhandle_win32 (usb_dev_handle *udh); - virtual ~fusb_devhandle_win32 (); - - // MANIPULATORS - virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); -}; - - -/*! - * \brief win32 implementation of fusb_ephandle using libusb-win32 - */ -class fusb_ephandle_win32 : public fusb_ephandle -{ -private: - fusb_devhandle_win32 *d_devhandle; - - unsigned d_curr; - unsigned d_outstanding_write; - int d_output_short; - int d_input_leftover; - void ** d_context; - char * d_buffer; - -public: - // CREATORS - fusb_ephandle_win32 (fusb_devhandle_win32 *dh, int endpoint, bool input_p, - int block_size = 0, int nblocks = 0); - virtual ~fusb_ephandle_win32 (); - - // MANIPULATORS - - virtual bool start (); //!< begin streaming i/o - virtual bool stop (); //!< stop streaming i/o - - /*! - * \returns \p nbytes if write was successfully enqueued, else -1. - * Will block if no free buffers available. - */ - virtual int write (const void *buffer, int nbytes); - - /*! - * \returns number of bytes read or -1 if error. - * number of bytes read will be <= nbytes. - * Will block if no input available. - */ - virtual int read (void *buffer, int nbytes); - - /* - * block until all outstanding writes have completed - */ - virtual void wait_for_completion (); -}; - -#endif /* _FUSB_WIN32_H_ */ - diff --git a/usrp/host/lib/legacy/gen_usrp_dbid.py b/usrp/host/lib/legacy/gen_usrp_dbid.py deleted file mode 100755 index bbfdc750..00000000 --- a/usrp/host/lib/legacy/gen_usrp_dbid.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/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 -#include -#include - -#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 ""; - - if (dbid == -2) - return ""; - - for (unsigned i = 0; i < NELEM (dbid_map); i++) - if (dbid == dbid_map[i].dbid) - return dbid_map[i].name; - - char tmp[64]; - snprintf (tmp, sizeof (tmp), "Unknown (0x%04x)", dbid); - return tmp; -} -''' - f.write(head) - for x in r: - f.write(' { %-27s "%s" },\n' % ( - 'USRP_DBID_' + x[1] + ',', x[0])) - f.write(tail) - -def gen_all(src_filename): - src_file = open(src_filename, 'r') - r = [] - for line in src_file: - line = line.strip() - line = re.sub(r'\s*#.*$','', line) - if len(line) == 0: - continue - mo = re.match('"([^"]+)"\s*(0x[0-9a-fA-F]+)', line) - if mo: - str_name = mo.group(1) - id_name = str_name.upper().replace(' ', '_') - id_val = mo.group(2) - r.append((str_name, id_name, id_val)) - #sys.stdout.write('%-16s\t%-16s\t%s\n' % ('"'+str_name+'"', id_name, id_val)) - - gen_dbid_h(r) - gen_dbid_py(r) - gen_dbid_cc(r) - - -def main(): - usage = "usage: %prog [options] usrp_dbid.dat" - parser = OptionParser(usage=usage) - (options, args) = parser.parse_args() - if len(args) != 1: - parser.print_help() - sys.exit(1) - - gen_all(args[0]) - -if __name__ == '__main__': - main() diff --git a/usrp/host/lib/legacy/md5.c b/usrp/host/lib/legacy/md5.c deleted file mode 100644 index b15ab390..00000000 --- a/usrp/host/lib/legacy/md5.c +++ /dev/null @@ -1,452 +0,0 @@ -/* 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 , 1995. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "md5.h" - -#include - -#include -#include - -// #include "unlocked-io.h" - -#ifdef _LIBC -# include -# if __BYTE_ORDER == __BIG_ENDIAN -# define WORDS_BIGENDIAN 1 -# endif -/* We need to keep the namespace clean so define the MD5 function - protected using leading __ . */ -# define md5_init_ctx __md5_init_ctx -# define md5_process_block __md5_process_block -# define md5_process_bytes __md5_process_bytes -# define md5_finish_ctx __md5_finish_ctx -# define md5_read_ctx __md5_read_ctx -# define md5_stream __md5_stream -# define md5_buffer __md5_buffer -#endif - -#ifdef WORDS_BIGENDIAN -# define SWAP(n) \ - (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) -#else -# define SWAP(n) (n) -#endif - -#define BLOCKSIZE 4096 -/* Ensure that BLOCKSIZE is a multiple of 64. */ -#if BLOCKSIZE % 64 != 0 -/* FIXME-someday (soon?): use #error instead of this kludge. */ -"invalid BLOCKSIZE" -#endif - -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. (RFC 1321, 3.1: Step 1) */ -static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; - - -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -void -md5_init_ctx (struct md5_ctx *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -/* Put result from CTX in first 16 bytes following RESBUF. The result - must be in little endian byte order. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -void * -md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) -{ - ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); - ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); - ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); - ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); - - return resbuf; -} - -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -void * -md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) -{ - /* Take yet unprocessed bytes into account. */ - md5_uint32 bytes = ctx->buflen; - size_t pad; - - /* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; - - pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; - memcpy (&ctx->buffer[bytes], fillbuf, pad); - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); - *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | - (ctx->total[0] >> 29)); - - /* Process last bytes. */ - md5_process_block (ctx->buffer, bytes + pad + 8, ctx); - - return md5_read_ctx (ctx, resbuf); -} - -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes - beginning at RESBLOCK. */ -int -md5_stream (FILE *stream, void *resblock) -{ - struct md5_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - return 1; - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - md5_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - - /* Process any remaining bytes. */ - if (sum > 0) - md5_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - md5_finish_ctx (&ctx, resblock); - return 0; -} - -/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -void * -md5_buffer (const char *buffer, size_t len, void *resblock) -{ - struct md5_ctx ctx; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Process whole buffer but last len % 64 bytes. */ - md5_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return md5_finish_ctx (&ctx, resblock); -} - - -void -md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - size_t left_over = ctx->buflen; - size_t add = 128 - left_over > len ? len : 128 - left_over; - - memcpy (&ctx->buffer[left_over], buffer, add); - ctx->buflen += add; - - if (ctx->buflen > 64) - { - md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); - - ctx->buflen &= 63; - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], - ctx->buflen); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len >= 64) - { -#if !_STRING_ARCH_unaligned -/* To check alignment gcc has an appropriate operator. Other - compilers don't. */ -# if __GNUC__ >= 2 -# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) -# else -# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) -# endif - if (UNALIGNED_P (buffer)) - while (len > 64) - { - md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); - buffer = (const char *) buffer + 64; - len -= 64; - } - else -#endif - { - md5_process_block (buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - size_t left_over = ctx->buflen; - - memcpy (&ctx->buffer[left_over], buffer, len); - left_over += len; - if (left_over >= 64) - { - md5_process_block (ctx->buffer, 64, ctx); - left_over -= 64; - memcpy (ctx->buffer, &ctx->buffer[64], left_over); - } - ctx->buflen = left_over; - } -} - - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. */ - -void -md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - md5_uint32 correct_words[16]; - const md5_uint32 *words = buffer; - size_t nwords = len / sizeof (md5_uint32); - const md5_uint32 *endp = words + nwords; - md5_uint32 A = ctx->A; - md5_uint32 B = ctx->B; - md5_uint32 C = ctx->C; - md5_uint32 D = ctx->D; - - /* First increment the byte count. RFC 1321 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] += len; - if (ctx->total[0] < len) - ++ctx->total[1]; - - /* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - while (words < endp) - { - md5_uint32 *cwp = correct_words; - md5_uint32 A_save = A; - md5_uint32 B_save = B; - md5_uint32 C_save = C; - md5_uint32 D_save = D; - - /* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ - ++words; \ - a = rol (a, s); \ - a += b; \ - } \ - while (0) - - /* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or - perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - - /* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - a = rol (a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - } - - /* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; -} diff --git a/usrp/host/lib/legacy/md5.h b/usrp/host/lib/legacy/md5.h deleted file mode 100644 index 4a4e790c..00000000 --- a/usrp/host/lib/legacy/md5.h +++ /dev/null @@ -1,129 +0,0 @@ -/* 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 -#include - -/* 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 -typedef uint32_t md5_uint32; -typedef uintptr_t md5_uintptr; -#else -# define UINT_MAX_32_BITS 4294967295U - -# if UINT_MAX == UINT_MAX_32_BITS - typedef unsigned int md5_uint32; -# else -# if USHRT_MAX == UINT_MAX_32_BITS - typedef unsigned short md5_uint32; -# else -# if ULONG_MAX == UINT_MAX_32_BITS - typedef unsigned long md5_uint32; -# else - /* The following line is intended to evoke an error. - Using #error is not portable enough. */ - "Cannot determine unsigned 32-bit data type." -# endif -# endif -# endif -/* We have to make a guess about the integer type equivalent in size - to pointers which should always be correct. */ -typedef unsigned long int md5_uintptr; -#endif - -/* Structure to save state of computation between the single steps. */ -struct md5_ctx -{ - md5_uint32 A; - md5_uint32 B; - md5_uint32 C; - md5_uint32 D; - - md5_uint32 total[2]; - md5_uint32 buflen; - char buffer[128]; -}; - -/* - * The following three functions are build up the low level used in - * the functions `md5_stream' and `md5_buffer'. - */ - -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -extern void md5_init_ctx (struct md5_ctx *ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is necessary that LEN is a multiple of 64!!! */ -extern void md5_process_block (const void *buffer, size_t len, - struct md5_ctx *ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is NOT required that LEN is a multiple of 64. */ -extern void md5_process_bytes (const void *buffer, size_t len, - struct md5_ctx *ctx); - -/* Process the remaining bytes in the buffer and put result from CTX - in first 16 bytes following RESBUF. The result is always in little - endian byte order, so that a byte-wise output yields to the wanted - ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF be correctly - aligned for a 32 bits value. */ -extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf); - - -/* Put result from CTX in first 16 bytes following RESBUF. The result is - always in little endian byte order, so that a byte-wise output yields - to the wanted ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf); - - -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes - beginning at RESBLOCK. */ -extern int md5_stream (FILE *stream, void *resblock); - -/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -extern void *md5_buffer (const char *buffer, size_t len, void *resblock); - -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) - -#endif diff --git a/usrp/host/lib/legacy/mld_threads.h b/usrp/host/lib/legacy/mld_threads.h deleted file mode 100644 index 322f557b..00000000 --- a/usrp/host/lib/legacy/mld_threads.h +++ /dev/null @@ -1,275 +0,0 @@ -/* -*- 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 -#else -#include -#endif - -#include - -#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_ */ diff --git a/usrp/host/lib/legacy/rate_to_regval.h b/usrp/host/lib/legacy/rate_to_regval.h deleted file mode 100644 index 1ffdc0f6..00000000 --- a/usrp/host/lib/legacy/rate_to_regval.h +++ /dev/null @@ -1,97 +0,0 @@ - { 1, 0x00 }, - { 2, 0x01 }, - { 3, 0x02 }, - { 4, 0x11 }, - { 5, 0x04 }, - { 6, 0x05 }, - { 7, 0x06 }, - { 8, 0x13 }, - { 9, 0x08 }, - { 10, 0x09 }, - { 11, 0x0a }, - { 12, 0x15 }, - { 13, 0x0c }, - { 14, 0x0d }, - { 15, 0x0e }, - { 16, 0x33 }, - { 18, 0x18 }, - { 20, 0x19 }, - { 21, 0x26 }, - { 22, 0x1a }, - { 24, 0x35 }, - { 25, 0x44 }, - { 26, 0x1c }, - { 27, 0x28 }, - { 28, 0x1d }, - { 30, 0x1e }, - { 32, 0x37 }, - { 33, 0x2a }, - { 35, 0x46 }, - { 36, 0x55 }, - { 39, 0x2c }, - { 40, 0x39 }, - { 42, 0x56 }, - { 44, 0x3a }, - { 45, 0x2e }, - { 48, 0x57 }, - { 49, 0x66 }, - { 50, 0x49 }, - { 52, 0x3c }, - { 54, 0x58 }, - { 55, 0x4a }, - { 56, 0x3d }, - { 60, 0x59 }, - { 63, 0x68 }, - { 64, 0x77 }, - { 65, 0x4c }, - { 66, 0x5a }, - { 70, 0x69 }, - { 72, 0x5b }, - { 75, 0x4e }, - { 77, 0x6a }, - { 78, 0x5c }, - { 80, 0x79 }, - { 81, 0x88 }, - { 84, 0x5d }, - { 88, 0x7a }, - { 90, 0x5e }, - { 91, 0x6c }, - { 96, 0x7b }, - { 98, 0x6d }, - { 99, 0x8a }, - { 100, 0x99 }, - { 104, 0x7c }, - { 105, 0x6e }, - { 108, 0x8b }, - { 110, 0x9a }, - { 112, 0x7d }, - { 117, 0x8c }, - { 120, 0x9b }, - { 121, 0xaa }, - { 126, 0x8d }, - { 128, 0x7f }, - { 130, 0x9c }, - { 132, 0xab }, - { 135, 0x8e }, - { 140, 0x9d }, - { 143, 0xac }, - { 144, 0xbb }, - { 150, 0x9e }, - { 154, 0xad }, - { 156, 0xbc }, - { 160, 0x9f }, - { 165, 0xae }, - { 168, 0xbd }, - { 169, 0xcc }, - { 176, 0xaf }, - { 180, 0xbe }, - { 182, 0xcd }, - { 192, 0xbf }, - { 195, 0xce }, - { 196, 0xdd }, - { 208, 0xcf }, - { 210, 0xde }, - { 224, 0xdf }, - { 225, 0xee }, - { 240, 0xef }, - { 256, 0xff } diff --git a/usrp/host/lib/legacy/std_paths.h.in b/usrp/host/lib/legacy/std_paths.h.in deleted file mode 100644 index e09499e0..00000000 --- a/usrp/host/lib/legacy/std_paths.h.in +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- 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 -}; diff --git a/usrp/host/lib/legacy/usrp_basic.cc b/usrp/host/lib/legacy/usrp_basic.cc deleted file mode 100644 index 295c62f8..00000000 --- a/usrp/host/lib/legacy/usrp_basic.cc +++ /dev/null @@ -1,1552 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include -#include -#include - -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 -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 = ""; - _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 = ""; - _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(); } - diff --git a/usrp/host/lib/legacy/usrp_basic.h b/usrp/host/lib/legacy/usrp_basic.h deleted file mode 100644 index 86c48635..00000000 --- a/usrp/host/lib/legacy/usrp_basic.h +++ /dev/null @@ -1,991 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include -#include - -struct usb_dev_handle; -class fusb_devhandle; -class fusb_ephandle; - -enum txrx_t { - C_RX = 0, - C_TX = 1 -}; - -/*! - * \brief 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 > 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 > db() const { return d_db; } - - /*! - * Return a vector of size >= 1 that contains shared pointers - * to the daughterboard instance(s) associated with the specified side. - * - * \param which_side [0,1] which daughterboard - * - * It is an error to use the returned objects after the usrp_basic - * object has been destroyed. - */ - std::vector db(int which_side); - - /*! - * \brief is the subdev_spec valid? - */ - bool is_valid(const usrp_subdev_spec &ss); - - /*! - * \brief given a subdev_spec, return the corresponding daughterboard object. - * \throws std::invalid_ argument if ss is invalid. - * - * \param ss specifies the side and subdevice - */ - db_base_sptr selected_subdev(const usrp_subdev_spec &ss); - - /*! - * \brief return frequency of master oscillator on USRP - */ - 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. - * - *
-   * The 4 low bits are significant:
-   *
-   *   ADC0 = (1 << 0)
-   *   ADC1 = (1 << 1)
-   *   ADC2 = (1 << 2)
-   *   ADC3 = (1 << 3)
-   * 
- * - * By default the control loop is enabled on all ADC's. - */ - bool set_dc_offset_cl_enable(int bits, int mask); - - /*! - * \brief return the usrp's serial number. - * - * \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); - - - // ================================================================ - // Routines to access and control daughterboard specific i/o - // - // Those with a common_ prefix access either the Tx or Rx side depending - // on the txrx parameter. Those without the common_ prefix are virtual - // and are overriden in usrp_basic_rx and usrp_basic_tx to access the - // the Rx or Tx sides automatically. We provide the common_ versions - // for those daughterboards such as the WBX and XCVR2450 that share - // h/w resources (such as the LO) between the Tx and Rx sides. - - // ---------------------------------------------------------------- - // BEGIN common_ daughterboard control functions - - /*! - * \brief Set Programmable Gain Amplifier(PGA) - * - * \param txrx Tx or Rx? - * \param which_amp which amp [0,3] - * \param gain_in_db gain value(linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - bool common_set_pga(txrx_t txrx, int which_amp, double gain_in_db); - - /*! - * \brief Return programmable gain amplifier gain setting in dB. - * - * \param txrx Tx or Rx? - * \param which_amp which amp [0,3] - */ - double common_pga(txrx_t txrx, int which_amp) const; - - /*! - * \brief Return minimum legal PGA gain in dB. - * \param txrx Tx or Rx? - */ - double common_pga_min(txrx_t txrx) const; - - /*! - * \brief Return maximum legal PGA gain in dB. - * \param txrx Tx or Rx? - */ - double common_pga_max(txrx_t txrx) const; - - /*! - * \brief Return hardware step size of PGA(linear in dB). - * \param txrx Tx or Rx? - */ - double common_pga_db_per_step(txrx_t txrx) const; - - /*! - * \brief Write direction register(output enables) for pins that go to daughterboard. - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which size - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - bool _common_write_oe(txrx_t txrx, int which_side, int value, int mask); - - /*! - * \brief Write daughterboard i/o pin value - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - bool common_write_io(txrx_t txrx, int which_side, int value, int mask); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * \param value output - */ - bool common_read_io(txrx_t txrx, int which_side, int *value); - - /*! - * \brief Read daughterboard i/o pin value - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - int common_read_io(txrx_t txrx, int which_side); - - /*! - * \brief Write daughterboard refclk config register - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * \param value value to write into register, see below - * - *
-   * Control whether a reference clock is sent to the daughterboards,
-   * and what frequency.  The refclk is sent on d'board i/o pin 0.
-   * 
-   *     3                   2                   1                       
-   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-   *  +-----------------------------------------------+-+------------+
-   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
-   *  +-----------------------------------------------+-+------------+
-   * 
-   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
-   *  Bits 6:0 Divider value
-   * 
- */ - bool common_write_refclk(txrx_t txrx, int which_side, int value); - - /*! - * \brief Automatic Transmit/Receive switching - *
-   *
-   * If automatic transmit/receive (ATR) switching is enabled in the
-   * FR_ATR_CTL register, the presence or absence of data in the FPGA
-   * transmit fifo selects between two sets of values for each of the 4
-   * banks of daughterboard i/o pins.
-   *
-   * Each daughterboard slot has 3 16-bit registers associated with it:
-   *   FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_*
-   *
-   * FR_ATR_MASK_{0,1,2,3}: 
-   *
-   *   These registers determine which of the daugherboard i/o pins are
-   *   affected by ATR switching.  If a bit in the mask is set, the
-   *   corresponding i/o bit is controlled by ATR, else it's output
-   *   value comes from the normal i/o pin output register:
-   *   FR_IO_{0,1,2,3}.
-   *
-   * FR_ATR_TXVAL_{0,1,2,3}:
-   * FR_ATR_RXVAL_{0,1,2,3}:
-   *
-   *   If the Tx fifo contains data, then the bits from TXVAL that are
-   *   selected by MASK are output.  Otherwise, the bits from RXVAL that
-   *   are selected by MASK are output.
-   * 
- */ - bool common_write_atr_mask(txrx_t txrx, int which_side, int value); - bool common_write_atr_txval(txrx_t txrx, int which_side, int value); - bool common_write_atr_rxval(txrx_t txrx, int which_side, int value); - - /*! - * \brief Write auxiliary digital to analog converter. - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. - * \param which_dac [2,3] TX slots must use only 2 and 3. - * \param value [0,4095] - * \returns true iff successful - */ - bool common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * \param which_adc [0,1] - * \param value return 12-bit value [0,4095] - * \returns true iff successful - */ - bool common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value); - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param txrx Tx or Rx? - * \param which_side [0,1] which d'board - * \param which_adc [0,1] - * \returns value in the range [0,4095] if successful, else READ_FAILED. - */ - int common_read_aux_adc(txrx_t txrx, int which_side, int which_adc); - - // END common_ daughterboard control functions - // ---------------------------------------------------------------- - // BEGIN virtual daughterboard control functions - - /*! - * \brief Set Programmable Gain Amplifier (PGA) - * - * \param which_amp which amp [0,3] - * \param gain_in_db gain value (linear in dB) - * - * gain is rounded to closest setting supported by hardware. - * - * \returns true iff sucessful. - * - * \sa pga_min(), pga_max(), pga_db_per_step() - */ - virtual bool set_pga (int which_amp, double gain_in_db) = 0; - - /*! - * \brief Return programmable gain amplifier gain setting in dB. - * - * \param which_amp which amp [0,3] - */ - virtual double pga (int which_amp) const = 0; - - /*! - * \brief Return minimum legal PGA gain in dB. - */ - virtual double pga_min () const = 0; - - /*! - * \brief Return maximum legal PGA gain in dB. - */ - virtual double pga_max () const = 0; - - /*! - * \brief Return hardware step size of PGA (linear in dB). - */ - virtual double pga_db_per_step () const = 0; - - /*! - * \brief Write direction register (output enables) for pins that go to daughterboard. - * - * \param which_side [0,1] which size - * \param value value to write into register - * \param mask which bits of value to write into reg - * - * Each d'board has 16-bits of general purpose i/o. - * Setting the bit makes it an output from the FPGA to the d'board. - * - * This register is initialized based on a value stored in the - * d'board EEPROM. In general, you shouldn't be using this routine - * without a very good reason. Using this method incorrectly will - * kill your USRP motherboard and/or daughterboard. - */ - virtual bool _write_oe (int which_side, int value, int mask) = 0; - - /*! - * \brief Write daughterboard i/o pin value - * - * \param which_side [0,1] which d'board - * \param value value to write into register - * \param mask which bits of value to write into reg - */ - virtual bool write_io (int which_side, int value, int mask) = 0; - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_side [0,1] which d'board - * \param value output - */ - virtual bool read_io (int which_side, int *value) = 0; - - /*! - * \brief Read daughterboard i/o pin value - * - * \param which_side [0,1] which d'board - * \returns register value if successful, else READ_FAILED - */ - virtual int read_io (int which_side) = 0; - - /*! - * \brief Write daughterboard refclk config register - * - * \param which_side [0,1] which d'board - * \param value value to write into register, see below - * - *
-   * Control whether a reference clock is sent to the daughterboards,
-   * and what frequency.  The refclk is sent on d'board i/o pin 0.
-   * 
-   *     3                   2                   1                       
-   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-   *  +-----------------------------------------------+-+------------+
-   *  |             Reserved (Must be zero)           |E|   DIVISOR  |
-   *  +-----------------------------------------------+-+------------+
-   * 
-   *  Bit 7  -- 1 turns on refclk, 0 allows IO use
-   *  Bits 6:0 Divider value
-   * 
- */ - virtual bool write_refclk(int which_side, int value) = 0; - - virtual bool write_atr_mask(int which_side, int value) = 0; - virtual bool write_atr_txval(int which_side, int value) = 0; - virtual bool write_atr_rxval(int which_side, int value) = 0; - - /*! - * \brief Write auxiliary digital to analog converter. - * - * \param which_side [0,1] which d'board - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's. - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's. - * \param which_dac [2,3] TX slots must use only 2 and 3. - * \param value [0,4095] - * \returns true iff successful - */ - virtual bool write_aux_dac (int which_side, int which_dac, int value) = 0; - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_side [0,1] which d'board - * \param which_adc [0,1] - * \param value return 12-bit value [0,4095] - * \returns true iff successful - */ - virtual bool read_aux_adc (int which_side, int which_adc, int *value) = 0; - - /*! - * \brief Read auxiliary analog to digital converter. - * - * \param which_side [0,1] which d'board - * \param which_adc [0,1] - * \returns value in the range [0,4095] if successful, else READ_FAILED. - */ - virtual int read_aux_adc (int which_side, int which_adc) = 0; - - /*! - * \brief returns current fusb block size - */ - virtual int block_size() const = 0; - - /*! - * \brief returns A/D or D/A converter rate in Hz - */ - virtual long converter_rate() const = 0; - - // END virtual daughterboard control functions - - // ---------------------------------------------------------------- - // Low level implementation routines. - // You probably shouldn't be using these... - // - - bool _set_led (int which_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 (); -}; - - /*! - * \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 (); -}; - - /*! - * \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 diff --git a/usrp/host/lib/legacy/usrp_bytesex.h b/usrp/host/lib/legacy/usrp_bytesex.h deleted file mode 100644 index 331db31c..00000000 --- a/usrp/host/lib/legacy/usrp_bytesex.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#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 -#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 */ diff --git a/usrp/host/lib/legacy/usrp_config.cc b/usrp/host/lib/legacy/usrp_config.cc deleted file mode 100644 index fcf207f6..00000000 --- a/usrp/host/lib/legacy/usrp_config.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- 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; -} diff --git a/usrp/host/lib/legacy/usrp_config.h b/usrp/host/lib/legacy/usrp_config.h deleted file mode 100644 index ee5cb63b..00000000 --- a/usrp/host/lib/legacy/usrp_config.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- 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_ */ diff --git a/usrp/host/lib/legacy/usrp_dbid.dat b/usrp/host/lib/legacy/usrp_dbid.dat deleted file mode 100644 index bd7fd7ec..00000000 --- a/usrp/host/lib/legacy/usrp_dbid.dat +++ /dev/null @@ -1,82 +0,0 @@ -# -# 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 diff --git a/usrp/host/lib/legacy/usrp_local_sighandler.cc b/usrp/host/lib/legacy/usrp_local_sighandler.cc deleted file mode 100644 index 69cde0b3..00000000 --- a/usrp/host/lib/legacy/usrp_local_sighandler.cc +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -/* - * 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 -#include -#include -#include - -usrp_local_sighandler::usrp_local_sighandler (int signum, - void (*new_handler)(int)) - : d_signum (signum) -{ -#ifdef HAVE_SIGACTION - struct sigaction new_action; - memset (&new_action, 0, sizeof (new_action)); - - new_action.sa_handler = new_handler; - sigemptyset (&new_action.sa_mask); - new_action.sa_flags = 0; - - if (sigaction (d_signum, &new_action, &d_old_action) < 0){ - perror ("sigaction (install new)"); - throw std::runtime_error ("sigaction"); - } -#endif -} - -usrp_local_sighandler::~usrp_local_sighandler () -{ -#ifdef HAVE_SIGACTION - if (sigaction (d_signum, &d_old_action, 0) < 0){ - perror ("sigaction (restore old)"); - throw std::runtime_error ("sigaction"); - } -#endif -} - -void -usrp_local_sighandler::throw_signal(int signum) throw(usrp_signal) -{ - throw usrp_signal (signum); -} - -/* - * Semi-hideous way to may a signal number into a signal name - */ - -#define SIGNAME(x) case x: return #x - -std::string -usrp_signal::name () const -{ - char tmp[128]; - - switch (signal ()){ -#ifdef SIGHUP - SIGNAME (SIGHUP); -#endif -#ifdef SIGINT - SIGNAME (SIGINT); -#endif -#ifdef SIGQUIT - SIGNAME (SIGQUIT); -#endif -#ifdef SIGILL - SIGNAME (SIGILL); -#endif -#ifdef SIGTRAP - SIGNAME (SIGTRAP); -#endif -#ifdef SIGABRT - SIGNAME (SIGABRT); -#endif -#ifdef SIGBUS - SIGNAME (SIGBUS); -#endif -#ifdef SIGFPE - SIGNAME (SIGFPE); -#endif -#ifdef SIGKILL - SIGNAME (SIGKILL); -#endif -#ifdef SIGUSR1 - SIGNAME (SIGUSR1); -#endif -#ifdef SIGSEGV - SIGNAME (SIGSEGV); -#endif -#ifdef SIGUSR2 - SIGNAME (SIGUSR2); -#endif -#ifdef SIGPIPE - SIGNAME (SIGPIPE); -#endif -#ifdef SIGALRM - SIGNAME (SIGALRM); -#endif -#ifdef SIGTERM - SIGNAME (SIGTERM); -#endif -#ifdef SIGSTKFLT - SIGNAME (SIGSTKFLT); -#endif -#ifdef SIGCHLD - SIGNAME (SIGCHLD); -#endif -#ifdef SIGCONT - SIGNAME (SIGCONT); -#endif -#ifdef SIGSTOP - SIGNAME (SIGSTOP); -#endif -#ifdef SIGTSTP - SIGNAME (SIGTSTP); -#endif -#ifdef SIGTTIN - SIGNAME (SIGTTIN); -#endif -#ifdef SIGTTOU - SIGNAME (SIGTTOU); -#endif -#ifdef SIGURG - SIGNAME (SIGURG); -#endif -#ifdef SIGXCPU - SIGNAME (SIGXCPU); -#endif -#ifdef SIGXFSZ - SIGNAME (SIGXFSZ); -#endif -#ifdef SIGVTALRM - SIGNAME (SIGVTALRM); -#endif -#ifdef SIGPROF - SIGNAME (SIGPROF); -#endif -#ifdef SIGWINCH - SIGNAME (SIGWINCH); -#endif -#ifdef SIGIO - SIGNAME (SIGIO); -#endif -#ifdef SIGPWR - SIGNAME (SIGPWR); -#endif -#ifdef SIGSYS - SIGNAME (SIGSYS); -#endif - default: -#if defined (HAVE_SNPRINTF) -#if defined (SIGRTMIN) && defined (SIGRTMAX) - if (signal () >= SIGRTMIN && signal () <= SIGRTMAX){ - snprintf (tmp, sizeof (tmp), "SIGRTMIN + %d", signal ()); - return tmp; - } -#endif - snprintf (tmp, sizeof (tmp), "SIGNAL %d", signal ()); - return tmp; -#else - return "Unknown signal"; -#endif - } -} diff --git a/usrp/host/lib/legacy/usrp_local_sighandler.h b/usrp/host/lib/legacy/usrp_local_sighandler.h deleted file mode 100644 index ee336750..00000000 --- a/usrp/host/lib/legacy/usrp_local_sighandler.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_USRP_LOCAL_SIGHANDLER_H -#define INCLUDED_USRP_LOCAL_SIGHANDLER_H - -#include -#include - -/*! - * \brief Representation of signal. - */ -class usrp_signal -{ - int d_signum; -public: - usrp_signal (int signum) : d_signum (signum) {} - int signal () const { return d_signum; } - std::string name () const; -}; - - -/*! - * \brief Get and set signal handler. - * - * Constructor installs new handler, destructor reinstalls - * original value. - */ -class usrp_local_sighandler { - int d_signum; -#ifdef HAVE_SIGACTION - struct sigaction d_old_action; -#endif -public: - usrp_local_sighandler (int signum, void (*new_handler)(int)); - ~usrp_local_sighandler (); - - /* throw usrp_signal (signum) */ - static void throw_signal (int signum) throw (usrp_signal); -}; - -#endif /* INCLUDED_USRP_LOCAL_SIGHANDLER_H */ diff --git a/usrp/host/lib/legacy/usrp_prims.cc b/usrp/host/lib/legacy/usrp_prims.cc deleted file mode 100644 index c2f74f5f..00000000 --- a/usrp/host/lib/legacy/usrp_prims.cc +++ /dev/null @@ -1,1357 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include -#include -#include -#include // FIXME should check with autoconf (nanosleep) -#include -#include -#include - -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 - -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 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; -} diff --git a/usrp/host/lib/legacy/usrp_prims.h b/usrp/host/lib/legacy/usrp_prims.h deleted file mode 100644 index aa134742..00000000 --- a/usrp/host/lib/legacy/usrp_prims.h +++ /dev/null @@ -1,294 +0,0 @@ -/* -*- 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 -#include - -static const int USRP_HASH_SIZE = 16; - -enum usrp_load_status_t { ULS_ERROR = 0, ULS_OK, ULS_ALREADY_LOADED }; - -struct usb_dev_handle; -struct usb_device; - -/*! - * \brief initialize libusb; probe busses and devices. - * Safe to call more than once. - */ -void usrp_one_time_init (); - -/* - * force a rescan of the buses and devices - */ -void usrp_rescan (); - -/*! - * \brief locate Nth (zero based) USRP device in system. - * Return pointer or 0 if not found. - * - * The following kinds of devices are considered USRPs: - * - * unconfigured USRP (no firwmare loaded) - * configured USRP (firmware loaded) - * unconfigured Cypress FX2 (only if fx2_ok_p is true) - */ -struct usb_device *usrp_find_device (int nth, bool fx2_ok_p = false); - -bool usrp_usrp_p (struct usb_device *q); //< is this a USRP -bool usrp_usrp0_p (struct usb_device *q); //< is this a USRP Rev 0 -bool usrp_usrp1_p (struct usb_device *q); //< is this a USRP Rev 1 -bool usrp_usrp2_p (struct usb_device *q); //< is this a USRP Rev 2 -int usrp_hw_rev (struct usb_device *q); //< return h/w rev code - -bool usrp_fx2_p (struct usb_device *q); //< is this an unconfigured Cypress FX2 - -bool usrp_unconfigured_usrp_p (struct usb_device *q); //< some kind of unconfigured USRP -bool usrp_configured_usrp_p (struct usb_device *q); //< some kind of configured USRP - -/*! - * \brief given a usb_device return an instance of the appropriate usb_dev_handle - * - * These routines claim the specified interface and select the - * correct alternate interface. (USB nomenclature is totally screwed!) - * - * If interface can't be opened, or is already claimed by some other - * process, 0 is returned. - */ -struct usb_dev_handle *usrp_open_cmd_interface (struct usb_device *dev); -struct usb_dev_handle *usrp_open_rx_interface (struct usb_device *dev); -struct usb_dev_handle *usrp_open_tx_interface (struct usb_device *dev); - -/*! - * \brief close interface. - */ -bool usrp_close_interface (struct usb_dev_handle *udh); - -/*! - * \brief load intel hex format file into USRP/Cypress FX2 (8051). - * - * The filename extension is typically *.ihx - * - * Note that loading firmware may cause the device to renumerate. I.e., - * change its configuration, invalidating the current device handle. - */ - -usrp_load_status_t -usrp_load_firmware (struct usb_dev_handle *udh, const char *filename, bool force); - -/*! - * \brief load intel hex format file into USRP FX2 (8051). - * - * The filename extension is typically *.ihx - * - * Note that loading firmware may cause the device to renumerate. I.e., - * change its configuration, invalidating the current device handle. - * If the result is ULS_OK, usrp_load_firmware_nth delays 1 second - * then rescans the busses and devices. - */ -usrp_load_status_t -usrp_load_firmware_nth (int nth, const char *filename, bool force); - -/*! - * \brief load fpga configuration bitstream - */ -usrp_load_status_t -usrp_load_fpga (struct usb_dev_handle *udh, const char *filename, bool force); - -/*! - * \brief load the regular firmware and fpga bitstream in the Nth USRP. - * - * This is the normal starting point... - */ -bool usrp_load_standard_bits (int nth, bool force, - const std::string fpga_filename = "", - const std::string firmware_filename = ""); - -/*! - * \brief copy the given \p hash into the USRP hash slot \p which. - * The usrp implements two hash slots, 0 and 1. - */ -bool usrp_set_hash (struct usb_dev_handle *udh, int which, - const unsigned char hash[USRP_HASH_SIZE]); - -/*! - * \brief retrieve the \p hash from the USRP hash slot \p which. - * The usrp implements two hash slots, 0 and 1. - */ -bool usrp_get_hash (struct usb_dev_handle *udh, int which, - unsigned char hash[USRP_HASH_SIZE]); - -bool usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value); -bool usrp_read_fpga_reg (struct usb_dev_handle *udh, int reg, int *value); -bool usrp_set_fpga_reset (struct usb_dev_handle *udh, bool on); -bool usrp_set_fpga_tx_enable (struct usb_dev_handle *udh, bool on); -bool usrp_set_fpga_rx_enable (struct usb_dev_handle *udh, bool on); -bool usrp_set_fpga_tx_reset (struct usb_dev_handle *udh, bool on); -bool usrp_set_fpga_rx_reset (struct usb_dev_handle *udh, bool on); -bool usrp_set_led (struct usb_dev_handle *udh, int which, bool on); - -bool usrp_check_rx_overrun (struct usb_dev_handle *udh, bool *overrun_p); -bool usrp_check_tx_underrun (struct usb_dev_handle *udh, bool *underrun_p); - -// i2c_read and i2c_write are limited to a maximum len of 64 bytes. - -bool usrp_i2c_write (struct usb_dev_handle *udh, int i2c_addr, - const void *buf, int len); - -bool usrp_i2c_read (struct usb_dev_handle *udh, int i2c_addr, - void *buf, int len); - -// spi_read and spi_write are limited to a maximum of 64 bytes -// See usrp_spi_defs.h for more info - -bool usrp_spi_write (struct usb_dev_handle *udh, - int optional_header, int enables, int format, - const void *buf, int len); - -bool usrp_spi_read (struct usb_dev_handle *udh, - int optional_header, int enables, int format, - void *buf, int len); - - -bool usrp_9862_write (struct usb_dev_handle *udh, - int which_codec, // [0, 1] - int regno, // [0, 63] - int value); // [0, 255] - -bool usrp_9862_read (struct usb_dev_handle *udh, - int which_codec, // [0, 1] - int regno, // [0, 63] - unsigned char *value); // [0, 255] - -/*! - * \brief Write multiple 9862 regs at once. - * - * \p buf contains alternating register_number, register_value pairs. - * \p len must be even and is the length of buf in bytes. - */ -bool usrp_9862_write_many (struct usb_dev_handle *udh, int which_codec, - const unsigned char *buf, int len); - - -/*! - * \brief write specified regs to all 9862's in the system - */ -bool usrp_9862_write_many_all (struct usb_dev_handle *udh, - const unsigned char *buf, int len); - - -// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. -// Which EEPROM is determined by i2c_addr. See i2c_addr.h - -bool usrp_eeprom_write (struct usb_dev_handle *udh, int i2c_addr, - int eeprom_offset, const void *buf, int len); - - -// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. -// Which EEPROM is determined by i2c_addr. See i2c_addr.h - -bool usrp_eeprom_read (struct usb_dev_handle *udh, int i2c_addr, - int eeprom_offset, void *buf, int len); - - -// Slot specific i/o routines - -/*! - * \brief write to the specified aux dac. - * - * \p slot: which Tx or Rx slot to write. - * N.B., SLOT_TX_A and SLOT_RX_A share the same AUX DAC's - * SLOT_TX_B and SLOT_RX_B share the same AUX DAC's - * - * \p which_dac: [0,3] RX slots must use only 0 and 1. - * TX slots must use only 2 and 3. - * - * AUX DAC 3 is really the 9862 sigma delta output. - * - * \p value to write to aux dac. All dacs take straight - * binary values. Although dacs 0, 1 and 2 are 8-bit and dac 3 is 12-bit, - * the interface is in terms of 12-bit values [0,4095] - */ -bool usrp_write_aux_dac (struct usb_dev_handle *uhd, int slot, - int which_dac, int value); - -/*! - * \brief Read the specified aux adc - * - * \p slot: which Tx or Rx slot to read aux dac - * \p which_adc: [0,1] which of the two adcs to read - * \p *value: return value, 12-bit straight binary. - */ -bool usrp_read_aux_adc (struct usb_dev_handle *udh, int slot, - int which_adc, int *value); - - -/*! - * \brief usrp daughterboard id to name mapping - */ -const std::string usrp_dbid_to_string (int dbid); - - -enum usrp_dbeeprom_status_t { UDBE_OK, UDBE_BAD_SLOT, UDBE_NO_EEPROM, UDBE_INVALID_EEPROM }; - -struct usrp_dboard_eeprom { - unsigned short id; // d'board identifier code - unsigned short oe; // fpga output enables: - // If bit set, i/o pin is an output from FPGA. - short offset[2]; // ADC/DAC offset correction -}; - -/*! - * \brief Read and return parsed daughterboard eeprom - */ -usrp_dbeeprom_status_t -usrp_read_dboard_eeprom (struct usb_dev_handle *udh, - int slot_id, usrp_dboard_eeprom *eeprom); - -/*! - * \brief write ADC/DAC offset calibration constants to d'board eeprom - */ -bool usrp_write_dboard_offsets (struct usb_dev_handle *udh, int slot_id, - short offset0, short offset1); - -/*! - * \brief return a usrp's serial number. - * - * Note that this only works on a configured usrp. - * \returns non-zero length string iff successful. - */ -std::string usrp_serial_number(struct usb_dev_handle *udh); - -#endif /* _USRP_PRIMS_H_ */ diff --git a/usrp/host/lib/legacy/usrp_slots.h b/usrp/host/lib/legacy/usrp_slots.h deleted file mode 100644 index d2c50fc4..00000000 --- a/usrp/host/lib/legacy/usrp_slots.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_USRP_SLOTS_H -#define INCLUDED_USRP_SLOTS_H - -// daughterboard slot numbers used in some calls - -static const int SLOT_TX_A = 0; -static const int SLOT_RX_A = 1; -static const int SLOT_TX_B = 2; -static const int SLOT_RX_B = 3; - -#endif /* INCLUDED_USRP_SLOTS_H */ diff --git a/usrp/host/lib/legacy/usrp_standard.cc b/usrp/host/lib/legacy/usrp_standard.cc deleted file mode 100644 index b810f99c..00000000 --- a/usrp/host/lib/legacy/usrp_standard.cc +++ /dev/null @@ -1,1167 +0,0 @@ -/* -*- 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 - -#include "usrp_prims.h" -#include "fpga_regs_common.h" -#include "fpga_regs_standard.h" -#include -#include -#include -#include -#include - - -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 = 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_a = this->db(ss_a.side); - std::vector 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 = 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); -} diff --git a/usrp/host/lib/legacy/usrp_standard.h b/usrp/host/lib/legacy/usrp_standard.h deleted file mode 100644 index 734fff4b..00000000 --- a/usrp/host/lib/legacy/usrp_standard.h +++ /dev/null @@ -1,452 +0,0 @@ -/* -*- 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 -#include -#include - -class usrp_standard_tx; -class usrp_standard_rx; - -typedef boost::shared_ptr usrp_standard_tx_sptr; -typedef boost::shared_ptr usrp_standard_rx_sptr; - -/*! - * \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. - * - *
-   * 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
-   * 
- */ - 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. - * - *
-   *     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
-   * 
- */ - 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 */ diff --git a/usrp/host/lib/legacy/usrp_subdev_spec.h b/usrp/host/lib/legacy/usrp_subdev_spec.h deleted file mode 100644 index e841ff83..00000000 --- a/usrp/host/lib/legacy/usrp_subdev_spec.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef INCLUDED_USRP_SUBDEV_SPEC_H -#define INCLUDED_USRP_SUBDEV_SPEC_H - -/*! - * \brief specify a daughterboard and subdevice on a daughterboard. - * - * In the USRP1, there are two sides, A and B. - * - * A daughterboard generally implements a single subdevice, but may in - * general implement any number of subdevices. At this time, all daughterboards - * with the exception of the Basic Rx and LF Rx implement a single subdevice. - * - * The Basic Rx and LF Rx implement 2 subdevices (soon 3). Subdevice - * 0 routes input RX-A to the DDC I input and routes a constant zero - * to the DDC Q input. Similarly, subdevice 1 routes input RX-B to - * the DDC I input and routes a constant zero to the DDC Q - * input. Subdevice 2 (when implemented) will route RX-A to the DDC I - * input and RX-B to the DDC Q input. - */ - -struct usrp_subdev_spec { - unsigned int side; // 0 -> A; 1 -> B - unsigned int subdev; // which subdevice (usually zero) - - usrp_subdev_spec(unsigned int _side = 0, unsigned int _subdev = 0) - : side(_side), subdev(_subdev) {} -}; - -#endif /* INCLUDED_USRP_SUBDEV_SPEC_H */ diff --git a/usrp/host/lib/legacy/usrp_tune_result.h b/usrp/host/lib/legacy/usrp_tune_result.h deleted file mode 100644 index 200541a3..00000000 --- a/usrp/host/lib/legacy/usrp_tune_result.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef INCLUDED_USRP_TUNE_RESULT_H -#define INCLUDED_USRP_TUNE_RESULT_H - -class usrp_tune_result -{ -public: - // RF frequency that corresponds to DC in the IF - double baseband_freq; - - // frequency programmed into the DDC/DUC - double dxc_freq; - - // residual frequency (typically < 0.01 Hz) - double residual_freq; - - // is the spectrum inverted? - bool inverted; - - usrp_tune_result(double baseband=0, double dxc=0, double residual=0, bool _inverted=false) - : baseband_freq(baseband), dxc_freq(dxc), - residual_freq(residual), inverted(_inverted) {} -}; - -#endif /* INCLUDED_USRP_TUNE_RESULT_H */ diff --git a/usrp/host/lib/limbo/db_wbx.cc b/usrp/host/lib/limbo/db_wbx.cc new file mode 100644 index 00000000..9f1d7293 --- /dev/null +++ b/usrp/host/lib/limbo/db_wbx.cc @@ -0,0 +1,953 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#include +#include +#include +#include +#include +#include +#include + +// d'board i/o pin defs + +// TX IO Pins +#define TX_POWER (1 << 0) // TX Side Power +#define RX_TXN (1 << 1) // T/R antenna switch for TX/RX port +#define TX_ENB_MIX (1 << 2) // Enable IQ mixer +#define TX_ENB_VGA (1 << 3) + +// RX IO Pins +#define RX2_RX1N (1 << 0) // antenna switch between RX2 and TX/RX port +#define RXENABLE (1 << 1) // enables mixer +#define PLL_LOCK_DETECT (1 << 2) // Muxout pin from PLL -- MUST BE INPUT +#define MReset (1 << 3) // NB6L239 Master Reset, asserted low +#define SELA0 (1 << 4) // NB6L239 SelA0 +#define SELA1 (1 << 5) // NB6L239 SelA1 +#define SELB0 (1 << 6) // NB6L239 SelB0 +#define SELB1 (1 << 7) // NB6L239 SelB1 +#define PLL_ENABLE (1 << 8) // CE Pin on PLL +#define AUX_SCLK (1 << 9) // ALT SPI SCLK +#define AUX_SDO (1 << 10) // ALT SPI SDO +#define AUX_SEN (1 << 11) // ALT SPI SEN + + +wbx_base::wbx_base(usrp_basic_sptr usrp, int which) + : db_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: which side: 0 or 1 corresponding to side A or B respectively + * @type which: int + */ + + d_first = true; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + // FIXME -- the write reg functions don't work with 0xffff for masks + _rx_write_oe(int(PLL_ENABLE|MReset|SELA0|SELA1|SELB0|SELB1|RX2_RX1N|RXENABLE), 0x7fff); + _rx_write_io((PLL_ENABLE|MReset|0|RXENABLE), (PLL_ENABLE|MReset|RX2_RX1N|RXENABLE)); + + _tx_write_oe((TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA), 0x7fff); + _tx_write_io((0|RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); // TX off, TR switch set to RX + + if(d_which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + set_auto_tr(false); + +} + +wbx_base::~wbx_base() +{ + shutdown(); +} + + +void +wbx_base::shutdown() +{ + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + write_io(d_which, d_power_off, POWER_UP); // turn off power to board + _write_oe(d_which, 0, 0xffff); // turn off all outputs + set_auto_tr(false); // disable auto transmit + } +} + +bool +wbx_base::_lock_detect() +{ + /* + * @returns: the value of the VCO/PLL lock detect bit. + * @rtype: 0 or 1 + */ + + if(_rx_read_io() & PLL_LOCK_DETECT) { + return true; + } + else { // Give it a second chance + if(_rx_read_io() & PLL_LOCK_DETECT) { + return true; + } + else { + return false; + } + } +} + +bool +wbx_base::_tx_write_oe(int value, int mask) +{ + int reg = (d_which == 0 ? FR_OE_0 : FR_OE_2); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_write_oe(int value, int mask) +{ + int reg = (d_which == 0 ? FR_OE_1 : FR_OE_3); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_tx_write_io(int value, int mask) +{ + int reg = (d_which == 0 ? FR_IO_0 : FR_IO_2); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_write_io(int value, int mask) +{ + int reg = (d_which == 0 ? FR_IO_1 : FR_IO_3); + return d_usrp->_write_fpga_reg(reg, ((mask & 0xffff) << 16) | (value & 0xffff)); +} + +bool +wbx_base::_rx_read_io() +{ + int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); + int t = d_usrp->_read_fpga_reg(reg); + return (t >> 16) & 0xffff; +} + +bool +wbx_base::_tx_read_io() +{ + int reg = (d_which == 0 ? FR_RB_IO_RX_A_IO_TX_A : FR_RB_IO_RX_B_IO_TX_B); + int t = d_usrp->_read_fpga_reg(reg); + return (t & 0xffff); +} + +bool +wbx_base::_compute_regs(double freq) +{ + /* + * Determine values of registers, along with actual freq. + * + * @param freq: target frequency in Hz + * @type freq: double + * @returns: (R, N, func, init, actual_freq) + * @rtype: tuple(int, int, int, int, double) + * + * Override this in derived classes. + */ + throw std::runtime_error("_compute_regs called from base class\n"); +} + +double +wbx_base::_refclk_freq() +{ + return (double)(d_usrp->fpga_master_clock_freq())/_refclk_divisor(); +} + +int +wbx_base::_refclk_divisor() +{ + /* + * Return value to stick in REFCLK_DIVISOR register + */ + return 1; +} + +struct freq_result_t +wbx_base::set_freq(double freq) +{ + /* + * @returns (ok, actual_baseband_freq) where: + * ok is True or False and indicates success or failure, + * actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + throw std::runtime_error("set_freq called from base class\n"); +} + +float +wbx_base::gain_min() +{ + throw std::runtime_error("gain_min called from base class\n"); +} + +float +wbx_base::gain_max() +{ + throw std::runtime_error("gain_max called from base class\n"); +} + +float +wbx_base::gain_db_per_step() +{ + throw std::runtime_error("gain_db_per_step called from base class\n"); +} + +bool +wbx_base::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + throw std::runtime_error("set_gain called from base class\n"); +} + +bool +wbx_base::_set_pga(float pga_gain) +{ + bool ok; + if(d_which == 0) { + ok = d_usrp->set_pga(0, pga_gain); + ok |= d_usrp->set_pga(1, pga_gain); + } + else { + ok = d_usrp->set_pga(2, pga_gain); + ok |= d_usrp->set_pga(3, pga_gain); + } + return ok; +} + +bool +wbx_base::is_quadrature() +{ + /* + * Return True if this board requires both I & Q analog channels. + * + * This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + + +/****************************************************************************/ + + +wbx_base_tx::wbx_base_tx(usrp_basic_sptr usrp, int which) + : wbx_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.sink_c + * @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. + */ + + // power up the transmit side, NO -- but set antenna to receive + d_usrp->write_io(d_which, (TX_POWER), (TX_POWER|RX_TXN)); + d_lo_offset = 0e6; + + // Gain is not set by the PGA, but the PGA must be set at max gain in the TX + _set_pga(d_usrp->pga_max()); +} + +wbx_base_tx::~wbx_base_tx() +{ + // Power down and leave the T/R switch in the R position + d_usrp->write_io(d_which, (RX_TXN), (TX_POWER|RX_TXN|TX_ENB_MIX|TX_ENB_VGA)); +} + +void +wbx_base_tx::set_auto_tr(bool on) +{ + if(on) { + set_atr_mask (RX_TXN); + set_atr_txval(0); + set_atr_rxval(RX_TXN); + } + else { + set_atr_mask (0); + set_atr_txval(0); + set_atr_rxval(0); + } +} + +void +wbx_base_tx::set_enable(bool on) +{ + /* + * Enable transmitter if on is True + */ + + int mask = RX_TXN|TX_ENB_MIX|TX_ENB_VGA; + //printf("HERE!!!!\n"); + if(on) { + d_usrp->write_io(d_which, TX_ENB_MIX|TX_ENB_VGA, mask); + } + else { + d_usrp->write_io(d_which, RX_TXN, mask); + } +} + +void +wbx_base_tx::set_lo_offset(double offset) +{ + /* + * Set amount by which LO is offset from requested tuning frequency. + * + * @param offset: offset in Hz + */ + + d_lo_offset = offset; +} + +double +wbx_base_tx::lo_offset() +{ + /* + * Get amount by which LO is offset from requested tuning frequency. + * + * @returns Offset in Hz + */ + + return d_lo_offset; +} + + +/****************************************************************************/ + + +wbx_base_rx::wbx_base_rx(usrp_basic_sptr usrp, int which) + : wbx_base(usrp, which) +{ + /* + * @param usrp: instance of usrp.source_c + * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + d_lo_offset = 0.0; +} + +wbx_base_rx::~wbx_base_rx() +{ + // Power down + d_usrp->write_io(d_which, 0, (RXENABLE)); +} + +void +wbx_base_rx::set_auto_tr(bool on) +{ + if(on) { + // FIXME: where does ENABLE come from? + //set_atr_mask (ENABLE); + set_atr_txval( 0); + //set_atr_rxval(ENABLE); + } + else { + set_atr_mask (0); + set_atr_txval(0); + set_atr_rxval(0); + } +} + +void +wbx_base_rx::select_rx_antenna(int which_antenna) +{ + /* + * Specify which antenna port to use for reception. + * @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == 0) { + d_usrp->write_io(d_which, 0, RX2_RX1N); + } + else if(which_antenna == 1) { + d_usrp->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } +} + +void +wbx_base_rx::select_rx_antenna(const std::string &which_antenna) +{ + if(which_antenna == "TX/RX") { + select_rx_antenna(0); + } + else if(which_antenna == "RX2") { + select_rx_antenna(1); + } + else { + throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } +} + +bool +wbx_base_rx::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + + float pga_gain, agc_gain; + float maxgain = gain_max() - d_usrp->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= d_usrp->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + float V_maxgain = .2; + float V_mingain = 1.2; + float V_fullscale = 3.3; + float dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + + return d_usrp->write_aux_dac(d_which, 0, (int)(dac_value)) && _set_pga((int)(pga_gain)); +} + +void +wbx_base_rx::set_lo_offset(double offset) +{ + /* + * Set amount by which LO is offset from requested tuning frequency. + * + * @param offset: offset in Hz + */ + d_lo_offset = offset; +} + +double +wbx_base_rx::lo_offset() +{ + /* + * Get amount by which LO is offset from requested tuning frequency. + * + * @returns Offset in Hz + */ + return d_lo_offset; +} + +bool +wbx_base_rx::i_and_q_swapped() +{ + /* + * Return True if this is a quadrature device and ADC 0 is Q. + */ + return false; +} + + +/****************************************************************************/ + +_ADF410X_common::_ADF410X_common() +{ + // R-Register Common Values + d_R_RSV = 0; // bits 23,22,21 + d_LDP = 1; // bit 20 Lock detect in 5 cycles + d_TEST = 0; // bit 19,18 Normal + d_ABP = 0; // bit 17,16 2.9ns + + // N-Register Common Values + d_N_RSV = 0; // 23,22 + d_CP_GAIN = 0; // 21 + + // Function Register Common Values + d_P = 0; // bits 23,22 0 = 8/9, 1 = 16/17, 2 = 32/33, 3 = 64/65 + d_PD2 = 0; // bit 21 Normal operation + d_CP2 = 4; // bits 20,19,18 CP Gain = 5mA + d_CP1 = 4; // bits 17,16,15 CP Gain = 5mA + d_TC = 0; // bits 14-11 PFD Timeout + d_FL = 0; // bit 10,9 Fastlock Disabled + d_CP3S = 0; // bit 8 CP Enabled + d_PDP = 0; // bit 7 Phase detector polarity, Positive=1 + d_MUXOUT = 1; // bits 6:4 Digital Lock Detect + d_PD1 = 0; // bit 3 Normal operation + d_CR = 0; // bit 2 Normal operation +} + +_ADF410X_common::~_ADF410X_common() +{ +} + +bool +_ADF410X_common::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + /* + * Determine values of R, control, and N registers, along with actual freq. + * + * @param freq: target frequency in Hz + * @type freq: double + * @returns: (R, N, control, actual_freq) + * @rtype: tuple(int, int, int, double) + */ + + // Band-specific N-Register Values + double phdet_freq = _refclk_freq()/d_R_DIV; + printf("phdet_freq = %f\n", phdet_freq); + + double desired_n = round(freq*d_freq_mult/phdet_freq); + printf("desired_n %f\n", desired_n); + + double actual_freq = desired_n * phdet_freq; + printf("actual freq %f\n", actual_freq); + + double B = floor(desired_n/_prescaler()); + double A = desired_n - _prescaler()*B; + printf("A %f B %f\n", A, B); + + d_B_DIV = int(B); // bits 20:8; + d_A_DIV = int(A); // bit 6:2; + + if(d_B_DIV < d_A_DIV) { + retR = 0; + retN = 0; + retcontrol = 0; + retfreq = 0; + return false; + } + + retR = (d_R_RSV<<21) | (d_LDP<<20) | (d_TEST<<18) | + (d_ABP<<16) | (d_R_DIV<<2); + + retN = (d_N_RSV<<22) | (d_CP_GAIN<<21) | (d_B_DIV<<8) | (d_A_DIV<<2); + + retcontrol = (d_P<<22) | (d_PD2<<21) | (d_CP2<<18) | (d_CP1<<15) | + (d_TC<<11) | (d_FL<<9) | (d_CP3S<<8) | (d_PDP<<7) | + (d_MUXOUT<<4) | (d_PD1<<3) | (d_CR<<2); + + retfreq = actual_freq/d_freq_mult; + + return true; +} + +void +_ADF410X_common::_write_all(int R, int N, int control) +{ + /* + * Write all PLL registers: + * R counter latch, + * N counter latch, + * Function latch, + * Initialization latch + * + * Adds 10ms delay between writing control and N if this is first call. + * This is the required power-up sequence. + * + * @param R: 24-bit R counter latch + * @type R: int + * @param N: 24-bit N counter latch + * @type N: int + * @param control: 24-bit control latch + * @type control: int + */ + static bool first = true; + + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + + _write_R(R); + _write_func(control); + _write_init(control); + if(first) { + //time.sleep(0.010); + nanosleep(&t, NULL); + first = false; + } + _write_N(N); +} + +void +_ADF410X_common::_write_R(int R) +{ + _write_it((R & ~0x3) | 0); +} + +void +_ADF410X_common::_write_N(int N) +{ + _write_it((N & ~0x3) | 1); +} + +void +_ADF410X_common::_write_func(int func) +{ + _write_it((func & ~0x3) | 2); +} + +void +_ADF410X_common::_write_init(int init) +{ + _write_it((init & ~0x3) | 3); +} + +void +_ADF410X_common::_write_it(int v) +{ + char c[3]; + c[0] = (char)((v >> 16) & 0xff); + c[1] = (char)((v >> 8) & 0xff); + c[2] = (char)((v & 0xff)); + std::string s(c, 3); + //d_usrp->_write_spi(0, d_spi_enable, d_spi_format, s); + usrp()->_write_spi(0, d_spi_enable, d_spi_format, s); +} + +int +_ADF410X_common::_prescaler() +{ + if(d_P == 0) { + return 8; + } + else if(d_P == 1) { + return 16; + } + else if(d_P == 2) { + return 32; + } + else if(d_P == 3) { + return 64; + } + else { + throw std::invalid_argument("Prescaler out of range\n"); + } +} + +double +_ADF410X_common::_refclk_freq() +{ + throw std::runtime_error("_refclk_freq called from base class."); +} + +bool +_ADF410X_common::_rx_write_io(int value, int mask) +{ + throw std::runtime_error("_rx_write_io called from base class."); +} + +bool +_ADF410X_common::_lock_detect() +{ + throw std::runtime_error("_lock_detect called from base class."); +} + +usrp_basic* +_ADF410X_common::usrp() +{ + throw std::runtime_error("usrp() called from base class."); +} + + +/****************************************************************************/ + + +_lo_common::_lo_common() + : _ADF410X_common() +{ + // Band-specific R-Register Values + d_R_DIV = 4; // bits 15:2 + + // Band-specific C-Register values + d_P = 0; // bits 23,22 0 = Div by 8/9 + d_CP2 = 4; // bits 19:17 + d_CP1 = 4; // bits 16:14 + + // Band specifc N-Register Values + d_DIVSEL = 0; // bit 23 + d_DIV2 = 0; // bit 22 + d_CPGAIN = 0; // bit 21 + d_freq_mult = 1; + + d_div = 1; + d_aux_div = 2; + d_main_div = 0; +} + +_lo_common::~_lo_common() +{ +} + +double +_lo_common::freq_min() +{ + return 50e6; +} + +double +_lo_common::freq_max() +{ + return 1000e6; +} + +void +_lo_common::set_divider(int main_or_aux, int divisor) +{ + if(main_or_aux == 0) { + if((divisor != 1) || (divisor != 2) || (divisor != 4) || (divisor != 8)) { + throw std::invalid_argument("Main Divider Must be 1, 2, 4, or 8\n"); + } + d_main_div = (int)(log10(divisor)/log10(2.0)); + } + else if(main_or_aux == 1) { + if((divisor != 2) || (divisor != 4) || (divisor != 8) || (divisor != 16)) { + throw std::invalid_argument("Aux Divider Must be 2, 4, 8 or 16\n"); + } + d_main_div = (int)(log10(divisor/2.0)/log10(2.0)); + } + else { + throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); + } + + int vala = d_main_div*SELA0; + int valb = d_aux_div*SELB0; + int mask = SELA0|SELA1|SELB0|SELB1; + + _rx_write_io((vala | valb), mask); +} + +void +_lo_common::set_divider(const std::string &main_or_aux, int divisor) +{ + if(main_or_aux == "main") { + set_divider(0, divisor); + } + else if(main_or_aux == "aux") { + set_divider(1, divisor); + } + else { + throw std::invalid_argument("main_or_aux must be 'main' or 'aux'\n"); + } +} + +struct freq_result_t +_lo_common::set_freq(double freq) +{ + struct freq_result_t ret; + + if(freq < 20e6 or freq > 1200e6) { + throw std::invalid_argument("Requested frequency out of range\n"); + } + + int div = 1; + double lo_freq = freq * 2; + while((lo_freq < 1e9) && (div < 8)) { + div = div * 2; + lo_freq = lo_freq * 2; + } + + printf("For RF freq of %f, we set DIV=%d and LO Freq=%f\n", freq, div, lo_freq); + + set_divider("main", div); + set_divider("aux", div*2); + + int R, N, control; + double actual_freq; + _compute_regs(lo_freq, R, N, control, actual_freq); + + printf("R %d N %d control %d actual freq %f\n", R, N, control, actual_freq); + if(R==0) { + ret.ok = false; + ret.baseband_freq = 0.0; + return ret; + } + _write_all(R, N, control); + + ret.ok = _lock_detect(); + ret.baseband_freq = actual_freq/div/2; + return ret; +} + + +/****************************************************************************/ + + +db_wbx_lo_tx::db_wbx_lo_tx(usrp_basic_sptr usrp, int which) + : _lo_common(), + wbx_base_tx(usrp, which) +{ +} + +db_wbx_lo_tx::~db_wbx_lo_tx() +{ +} + +float +db_wbx_lo_tx::gain_min() +{ + return -56.0; +} + +float +db_wbx_lo_tx::gain_max() +{ + return 0.0; +} + +float +db_wbx_lo_tx::gain_db_per_step() +{ + return 0.1; +} + +bool +db_wbx_lo_tx::set_gain(float gain) +{ + /* + * Set the gain. + * + * @param gain: gain in decibels + * @returns True/False + */ + + float txvga_gain; + float maxgain = gain_max(); + float mingain = gain_min(); + if(gain > maxgain) { + txvga_gain = maxgain; + } + else if(gain < mingain) { + txvga_gain = mingain; + } + else { + txvga_gain = gain; + } + + float V_maxgain = 1.4; + float V_mingain = 0.1; + float V_fullscale = 3.3; + float dac_value = ((txvga_gain-mingain)*(V_maxgain-V_mingain)/ + (maxgain-mingain) + V_mingain)*4096/V_fullscale; + + assert(dac_value>=0 && dac_value<4096); + printf("DAC value %f\n", dac_value); + + return d_usrp->write_aux_dac(d_which, 1, (int)(dac_value)); +} + +double +db_wbx_lo_tx::_refclk_freq() +{ + return wbx_base::_refclk_freq(); +} + +bool +db_wbx_lo_tx::_rx_write_io(int value, int mask) +{ + return wbx_base::_rx_write_io(value, mask); +} + +bool +db_wbx_lo_tx::_lock_detect() +{ + return wbx_base::_lock_detect(); +} + +usrp_basic* +db_wbx_lo_tx::usrp() +{ + return d_usrp; +} + + +/****************************************************************************/ + + +db_wbx_lo_rx::db_wbx_lo_rx(usrp_basic_sptr usrp, int which) + : _lo_common(), + wbx_base_rx(usrp, which) +{ +} + +db_wbx_lo_rx::~db_wbx_lo_rx() +{ +} + +float +db_wbx_lo_rx::gain_min() +{ + return d_usrp->pga_min(); +} + +float +db_wbx_lo_rx::gain_max() +{ + return d_usrp->pga_max() + 45; +} + +float +db_wbx_lo_rx::gain_db_per_step() +{ + return 0.05; +} + +double +db_wbx_lo_rx::_refclk_freq() +{ + return wbx_base::_refclk_freq(); +} + +bool +db_wbx_lo_rx::_rx_write_io(int value, int mask) +{ + return wbx_base::_rx_write_io(value, mask); +} + +bool +db_wbx_lo_rx::_lock_detect() +{ + return wbx_base::_lock_detect(); +} + +usrp_basic* +db_wbx_lo_rx::usrp() +{ + return d_usrp; +} diff --git a/usrp/host/lib/limbo/db_wbx.h b/usrp/host/lib/limbo/db_wbx.h new file mode 100644 index 00000000..3202d368 --- /dev/null +++ b/usrp/host/lib/limbo/db_wbx.h @@ -0,0 +1,221 @@ +/* -*- c++ -*- */ +// +// Copyright 2008 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either asversion 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Radio; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, +// Boston, MA 02110-1301, USA. + +#ifndef DB_WBX_H +#define DB_WBX_H + +#include +#include + + +/* + A few comments about the WBX boards: + They are half-duplex. I.e., transmit and receive are mutually exclusive. + There is a single LO for both the Tx and Rx sides. + The the shared control signals are hung off of the Rx side. + The shared io controls are duplexed onto the Rx side pins. + The wbx_high d'board always needs to be in 'auto_tr_mode' +*/ + + +class wbx_base : public db_base +{ +protected: + void shutdown(); + + /* + * Abstract base class for all wbx boards. + * + * Derive board specific subclasses from db_wbx_base_{tx,rx} + */ + +public: + wbx_base(usrp_basic_sptr usrp, int which); + ~wbx_base(); + + struct freq_result_t set_freq(double freq); + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + bool is_quadrature(); + + +protected: + virtual bool _lock_detect(); + + // FIXME: After testing, replace these with usrp_basic::common_write_io/oe + bool _tx_write_oe(int value, int mask); + bool _rx_write_oe(int value, int mask); + bool _tx_write_io(int value, int mask); + bool _rx_write_io(int value, int mask); + virtual bool _rx_read_io(); + bool _tx_read_io(); + bool _compute_regs(double freq); + virtual double _refclk_freq(); + int _refclk_divisor(); + + bool _set_pga(float pga_gain); + + bool d_first; + int d_spi_format; + int d_spi_enable; + double d_lo_offset; +}; + + +/****************************************************************************/ + + +class wbx_base_tx : public wbx_base +{ +public: + wbx_base_tx(usrp_basic_sptr usrp, int which); + ~wbx_base_tx(); + + bool set_auto_tr(bool on); + bool set_enable(bool on); +}; + + +/****************************************************************************/ + + +class wbx_base_rx : public wbx_base +{ +public: + wbx_base_rx(usrp_basic_sptr usrp, int which); + ~wbx_base_rx(); + + bool set_auto_tr(bool on); + bool select_rx_antenna(int which_antenna); + bool select_rx_antenna(const std::string &which_antenna); + bool set_gain(float gain); + bool i_and_q_swapped(); +}; + + +/****************************************************************************/ + + +class _ADF410X_common +{ +public: + _ADF410X_common(); + virtual ~_ADF410X_common(); + + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); + void _write_all(int R, int N, int control); + void _write_R(int R); + void _write_N(int N); + void _write_func(int func); + void _write_init(int init); + int _prescaler(); + virtual void _write_it(int v); + virtual double _refclk_freq(); + virtual bool _rx_write_io(int value, int mask); + virtual bool _lock_detect(); + +protected: + virtual usrp_basic* usrp(); + + int d_R_RSV, d_LDP, d_TEST, d_ABP; + int d_N_RSV, d_CP_GAIN; + int d_P, d_PD2, d_CP2, d_CP1, d_TC, d_FL; + int d_CP3S, d_PDP, d_MUXOUT, d_PD1, d_CR; + int d_R_DIV, d_A_DIV, d_B_DIV; + int d_freq_mult; + + int d_spi_format; + int d_spi_enable; +}; + + +/****************************************************************************/ + + +class _lo_common : public _ADF410X_common +{ +public: + _lo_common(); + ~_lo_common(); + + double freq_min(); + double freq_max(); + + void set_divider(int main_or_aux, int divisor); + void set_divider(const std::string &main_or_aux, int divisor); + + struct freq_result_t set_freq(double freq); + +protected: + int d_R_DIV, d_P, d_CP2, d_CP1; + int d_DIVSEL, d_DIV2, d_CPGAIN; + int d_div, d_aux_div, d_main_div; +}; + + +/****************************************************************************/ + + +class db_wbx_lo_tx : public _lo_common, public wbx_base_tx +{ +public: + db_wbx_lo_tx(usrp_basic_sptr usrp, int which); + ~db_wbx_lo_tx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool set_gain(float gain); + + double _refclk_freq(); + bool _rx_write_io(int value, int mask); + bool _lock_detect(); + +protected: + usrp_basic* usrp(); +}; + + +/****************************************************************************/ + + +class db_wbx_lo_rx : public _lo_common, public wbx_base_rx +{ +public: + db_wbx_lo_rx(usrp_basic_sptr usrp, int which); + ~db_wbx_lo_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + + double _refclk_freq(); + bool _rx_write_io(int value, int mask); + bool _lock_detect(); + +protected: + usrp_basic* usrp(); +}; + +#endif diff --git a/usrp/host/lib/md5.c b/usrp/host/lib/md5.c new file mode 100644 index 00000000..b15ab390 --- /dev/null +++ b/usrp/host/lib/md5.c @@ -0,0 +1,452 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 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 , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "md5.h" + +#include + +#include +#include + +// #include "unlocked-io.h" + +#ifdef _LIBC +# include +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ . */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + +#define BLOCKSIZE 4096 +/* Ensure that BLOCKSIZE is a multiple of 64. */ +#if BLOCKSIZE % 64 != 0 +/* FIXME-someday (soon?): use #error instead of this kludge. */ +"invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) +# else +# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + md5_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + a = rol (a, s); \ + a += b; \ + } \ + while (0) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or + perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + a = rol (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/usrp/host/lib/md5.h b/usrp/host/lib/md5.h new file mode 100644 index 00000000..4a4e790c --- /dev/null +++ b/usrp/host/lib/md5.h @@ -0,0 +1,129 @@ +/* md5.h - Declaration of functions and data types used for MD5 sum + computing library functions. + Copyright (C) 1995, 1996, 1999, 2000, 2003 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 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 +#include + +/* 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 +typedef uint32_t md5_uint32; +typedef uintptr_t md5_uintptr; +#else +# define UINT_MAX_32_BITS 4294967295U + +# if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +# else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +# endif +/* We have to make a guess about the integer type equivalent in size + to pointers which should always be correct. */ +typedef unsigned long int md5_uintptr; +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void md5_init_ctx (struct md5_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF be correctly + aligned for a 32 bits value. */ +extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int md5_stream (FILE *stream, void *resblock); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *md5_buffer (const char *buffer, size_t len, void *resblock); + +#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) + +#endif diff --git a/usrp/host/lib/mld_threads.h b/usrp/host/lib/mld_threads.h new file mode 100644 index 00000000..322f557b --- /dev/null +++ b/usrp/host/lib/mld_threads.h @@ -0,0 +1,275 @@ +/* -*- 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 +#else +#include +#endif + +#include + +#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_ */ diff --git a/usrp/host/lib/rate_to_regval.h b/usrp/host/lib/rate_to_regval.h new file mode 100644 index 00000000..1ffdc0f6 --- /dev/null +++ b/usrp/host/lib/rate_to_regval.h @@ -0,0 +1,97 @@ + { 1, 0x00 }, + { 2, 0x01 }, + { 3, 0x02 }, + { 4, 0x11 }, + { 5, 0x04 }, + { 6, 0x05 }, + { 7, 0x06 }, + { 8, 0x13 }, + { 9, 0x08 }, + { 10, 0x09 }, + { 11, 0x0a }, + { 12, 0x15 }, + { 13, 0x0c }, + { 14, 0x0d }, + { 15, 0x0e }, + { 16, 0x33 }, + { 18, 0x18 }, + { 20, 0x19 }, + { 21, 0x26 }, + { 22, 0x1a }, + { 24, 0x35 }, + { 25, 0x44 }, + { 26, 0x1c }, + { 27, 0x28 }, + { 28, 0x1d }, + { 30, 0x1e }, + { 32, 0x37 }, + { 33, 0x2a }, + { 35, 0x46 }, + { 36, 0x55 }, + { 39, 0x2c }, + { 40, 0x39 }, + { 42, 0x56 }, + { 44, 0x3a }, + { 45, 0x2e }, + { 48, 0x57 }, + { 49, 0x66 }, + { 50, 0x49 }, + { 52, 0x3c }, + { 54, 0x58 }, + { 55, 0x4a }, + { 56, 0x3d }, + { 60, 0x59 }, + { 63, 0x68 }, + { 64, 0x77 }, + { 65, 0x4c }, + { 66, 0x5a }, + { 70, 0x69 }, + { 72, 0x5b }, + { 75, 0x4e }, + { 77, 0x6a }, + { 78, 0x5c }, + { 80, 0x79 }, + { 81, 0x88 }, + { 84, 0x5d }, + { 88, 0x7a }, + { 90, 0x5e }, + { 91, 0x6c }, + { 96, 0x7b }, + { 98, 0x6d }, + { 99, 0x8a }, + { 100, 0x99 }, + { 104, 0x7c }, + { 105, 0x6e }, + { 108, 0x8b }, + { 110, 0x9a }, + { 112, 0x7d }, + { 117, 0x8c }, + { 120, 0x9b }, + { 121, 0xaa }, + { 126, 0x8d }, + { 128, 0x7f }, + { 130, 0x9c }, + { 132, 0xab }, + { 135, 0x8e }, + { 140, 0x9d }, + { 143, 0xac }, + { 144, 0xbb }, + { 150, 0x9e }, + { 154, 0xad }, + { 156, 0xbc }, + { 160, 0x9f }, + { 165, 0xae }, + { 168, 0xbd }, + { 169, 0xcc }, + { 176, 0xaf }, + { 180, 0xbe }, + { 182, 0xcd }, + { 192, 0xbf }, + { 195, 0xce }, + { 196, 0xdd }, + { 208, 0xcf }, + { 210, 0xde }, + { 224, 0xdf }, + { 225, 0xee }, + { 240, 0xef }, + { 256, 0xff } diff --git a/usrp/host/lib/std_paths.h.in b/usrp/host/lib/std_paths.h.in new file mode 100644 index 00000000..e09499e0 --- /dev/null +++ b/usrp/host/lib/std_paths.h.in @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 +}; diff --git a/usrp/host/lib/usrp_basic.cc b/usrp/host/lib/usrp_basic.cc new file mode 100644 index 00000000..4f3df521 --- /dev/null +++ b/usrp/host/lib/usrp_basic.cc @@ -0,0 +1,1552 @@ +/* -*- 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 +#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 +#include +#include +#include +#include +#include +#include + +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 +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 = ""; + _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 = ""; + _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(); } + diff --git a/usrp/host/lib/usrp_config.cc b/usrp/host/lib/usrp_config.cc new file mode 100644 index 00000000..fcf207f6 --- /dev/null +++ b/usrp/host/lib/usrp_config.cc @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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; +} diff --git a/usrp/host/lib/usrp_config.h b/usrp/host/lib/usrp_config.h new file mode 100644 index 00000000..ee5cb63b --- /dev/null +++ b/usrp/host/lib/usrp_config.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_ */ diff --git a/usrp/host/lib/usrp_dbid.dat b/usrp/host/lib/usrp_dbid.dat new file mode 100644 index 00000000..bd7fd7ec --- /dev/null +++ b/usrp/host/lib/usrp_dbid.dat @@ -0,0 +1,82 @@ +# +# 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 diff --git a/usrp/host/lib/usrp_local_sighandler.cc b/usrp/host/lib/usrp_local_sighandler.cc new file mode 100644 index 00000000..59013972 --- /dev/null +++ b/usrp/host/lib/usrp_local_sighandler.cc @@ -0,0 +1,191 @@ +/* -*- 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 +#include +#include +#include + +usrp_local_sighandler::usrp_local_sighandler (int signum, + void (*new_handler)(int)) + : d_signum (signum) +{ +#ifdef HAVE_SIGACTION + struct sigaction new_action; + memset (&new_action, 0, sizeof (new_action)); + + new_action.sa_handler = new_handler; + sigemptyset (&new_action.sa_mask); + new_action.sa_flags = 0; + + if (sigaction (d_signum, &new_action, &d_old_action) < 0){ + perror ("sigaction (install new)"); + throw std::runtime_error ("sigaction"); + } +#endif +} + +usrp_local_sighandler::~usrp_local_sighandler () +{ +#ifdef HAVE_SIGACTION + if (sigaction (d_signum, &d_old_action, 0) < 0){ + perror ("sigaction (restore old)"); + throw std::runtime_error ("sigaction"); + } +#endif +} + +void +usrp_local_sighandler::throw_signal(int signum) throw(usrp_signal) +{ + throw usrp_signal (signum); +} + +/* + * Semi-hideous way to may a signal number into a signal name + */ + +#define SIGNAME(x) case x: return #x + +std::string +usrp_signal::name () const +{ + char tmp[128]; + + switch (signal ()){ +#ifdef SIGHUP + SIGNAME (SIGHUP); +#endif +#ifdef SIGINT + SIGNAME (SIGINT); +#endif +#ifdef SIGQUIT + SIGNAME (SIGQUIT); +#endif +#ifdef SIGILL + SIGNAME (SIGILL); +#endif +#ifdef SIGTRAP + SIGNAME (SIGTRAP); +#endif +#ifdef SIGABRT + SIGNAME (SIGABRT); +#endif +#ifdef SIGBUS + SIGNAME (SIGBUS); +#endif +#ifdef SIGFPE + SIGNAME (SIGFPE); +#endif +#ifdef SIGKILL + SIGNAME (SIGKILL); +#endif +#ifdef SIGUSR1 + SIGNAME (SIGUSR1); +#endif +#ifdef SIGSEGV + SIGNAME (SIGSEGV); +#endif +#ifdef SIGUSR2 + SIGNAME (SIGUSR2); +#endif +#ifdef SIGPIPE + SIGNAME (SIGPIPE); +#endif +#ifdef SIGALRM + SIGNAME (SIGALRM); +#endif +#ifdef SIGTERM + SIGNAME (SIGTERM); +#endif +#ifdef SIGSTKFLT + SIGNAME (SIGSTKFLT); +#endif +#ifdef SIGCHLD + SIGNAME (SIGCHLD); +#endif +#ifdef SIGCONT + SIGNAME (SIGCONT); +#endif +#ifdef SIGSTOP + SIGNAME (SIGSTOP); +#endif +#ifdef SIGTSTP + SIGNAME (SIGTSTP); +#endif +#ifdef SIGTTIN + SIGNAME (SIGTTIN); +#endif +#ifdef SIGTTOU + SIGNAME (SIGTTOU); +#endif +#ifdef SIGURG + SIGNAME (SIGURG); +#endif +#ifdef SIGXCPU + SIGNAME (SIGXCPU); +#endif +#ifdef SIGXFSZ + SIGNAME (SIGXFSZ); +#endif +#ifdef SIGVTALRM + SIGNAME (SIGVTALRM); +#endif +#ifdef SIGPROF + SIGNAME (SIGPROF); +#endif +#ifdef SIGWINCH + SIGNAME (SIGWINCH); +#endif +#ifdef SIGIO + SIGNAME (SIGIO); +#endif +#ifdef SIGPWR + SIGNAME (SIGPWR); +#endif +#ifdef SIGSYS + SIGNAME (SIGSYS); +#endif + default: +#if defined (HAVE_SNPRINTF) +#if defined (SIGRTMIN) && defined (SIGRTMAX) + if (signal () >= SIGRTMIN && signal () <= SIGRTMAX){ + snprintf (tmp, sizeof (tmp), "SIGRTMIN + %d", signal ()); + return tmp; + } +#endif + snprintf (tmp, sizeof (tmp), "SIGNAL %d", signal ()); + return tmp; +#else + return "Unknown signal"; +#endif + } +} diff --git a/usrp/host/lib/usrp_prims.cc b/usrp/host/lib/usrp_prims.cc new file mode 100644 index 00000000..3d87d245 --- /dev/null +++ b/usrp/host/lib/usrp_prims.cc @@ -0,0 +1,1357 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include // FIXME should check with autoconf (nanosleep) +#include +#include +#include + +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 + +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 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; +} diff --git a/usrp/host/lib/usrp_standard.cc b/usrp/host/lib/usrp_standard.cc new file mode 100644 index 00000000..b112dbe0 --- /dev/null +++ b/usrp/host/lib/usrp_standard.cc @@ -0,0 +1,1167 @@ +/* -*- 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 + +#include "usrp/usrp_prims.h" +#include "fpga_regs_common.h" +#include "fpga_regs_standard.h" +#include +#include +#include +#include +#include + + +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 = 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_a = this->db(ss_a.side); + std::vector 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 = 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); +} diff --git a/usrp/host/swig/usrp_prims.i b/usrp/host/swig/usrp_prims.i index d973c6d7..78a775cf 100644 --- a/usrp/host/swig/usrp_prims.i +++ b/usrp/host/swig/usrp_prims.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003,2004 Free Software Foundation, Inc. + * Copyright 2003,2004,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -36,7 +36,7 @@ %{ -#include +#include %} diff --git a/usrp/limbo/apps-inband/Makefile.am b/usrp/limbo/apps-inband/Makefile.am new file mode 100644 index 00000000..0a44d811 --- /dev/null +++ b/usrp/limbo/apps-inband/Makefile.am @@ -0,0 +1,77 @@ +# +# 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) diff --git a/usrp/limbo/apps-inband/read_packets.cc b/usrp/limbo/apps-inband/read_packets.cc new file mode 100644 index 00000000..24a1e88b --- /dev/null +++ b/usrp/limbo/apps-inband/read_packets.cc @@ -0,0 +1,109 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include + +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 \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(); + +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_2rx.cc b/usrp/limbo/apps-inband/test_usrp_inband_2rx.cc new file mode 100644 index 00000000..c210f196 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_2rx.cc @@ -0,0 +1,371 @@ +/* -*- 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 +#endif + +#include +#include +#include // QA only +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include the symbols needed for communication with USRP server +#include +#include +#include +#include + +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); + +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_2tx.cc b/usrp/limbo/apps-inband/test_usrp_inband_2tx.cc new file mode 100644 index 00000000..11a1a491 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_2tx.cc @@ -0,0 +1,430 @@ +/* -*- 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 +#endif + +#include +#include +#include // QA only +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 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); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_overrun.cc b/usrp/limbo/apps-inband/test_usrp_inband_overrun.cc new file mode 100644 index 00000000..cd0fa525 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_overrun.cc @@ -0,0 +1,375 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include the symbols needed for communication with USRP server +#include +#include +#include +#include + +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 <= 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); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_ping.cc b/usrp/limbo/apps-inband/test_usrp_inband_ping.cc new file mode 100644 index 00000000..d779c9a6 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_ping.cc @@ -0,0 +1,374 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include the symbols needed for communication with USRP server +#include +#include +#include +#include +#include + +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); diff --git a/usrp/limbo/apps-inband/test_usrp_inband_registers.cc b/usrp/limbo/apps-inband/test_usrp_inband_registers.cc new file mode 100644 index 00000000..d9bd2db1 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_registers.cc @@ -0,0 +1,435 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include + +// Include the symbols needed for communication with USRP server +#include +#include +#include +#include +#include + +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); diff --git a/usrp/limbo/apps-inband/test_usrp_inband_rx.cc b/usrp/limbo/apps-inband/test_usrp_inband_rx.cc new file mode 100644 index 00000000..4f21e4af --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_rx.cc @@ -0,0 +1,362 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include the symbols needed for communication with USRP server +#include +#include +#include +#include + +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); + +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc b/usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc new file mode 100644 index 00000000..3b874d1a --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc @@ -0,0 +1,506 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 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); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_tx.cc b/usrp/limbo/apps-inband/test_usrp_inband_tx.cc new file mode 100644 index 00000000..9f294e77 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_tx.cc @@ -0,0 +1,411 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 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); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_underrun.cc b/usrp/limbo/apps-inband/test_usrp_inband_underrun.cc new file mode 100644 index 00000000..11babb04 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_underrun.cc @@ -0,0 +1,674 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include the symbols needed for communication with USRP server +#include +#include +#include +#include +#include + +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 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 <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); diff --git a/usrp/limbo/apps-inband/ui_nco.h b/usrp/limbo/apps-inband/ui_nco.h new file mode 100644 index 00000000..e6d7814a --- /dev/null +++ b/usrp/limbo/apps-inband/ui_nco.h @@ -0,0 +1,202 @@ +/* -*- 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 +#include +#include + +#include +typedef std::complex gr_complex; + + +/*! + * \brief base class template for Numerically Controlled Oscillator (NCO) + */ + + +//FIXME Eventually generalize this to fixed point + +template +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 +void +ui_nco::sincos (float *sinx, float *cosx) const +{ + ui_sincosf (phase, sinx, cosx); +} + +template +void +ui_nco::sin (float *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (float)(sin () * ampl); + step (); + } +} + +template +void +ui_nco::cos (float *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (float)(cos () * ampl); + step (); + } +} + +template +void +ui_nco::sin (short *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (short)(sin() * ampl); + step (); + } +} + +template +void +ui_nco::cos (short *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (short)(cos () * ampl); + step (); + } +} + +template +void +ui_nco::sin (int *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (int)(sin () * ampl); + step (); + } +} + +template +void +ui_nco::cos (int *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (int)(cos () * ampl); + step (); + } +} + +template +void +ui_nco::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 */ + diff --git a/usrp/limbo/apps-inband/ui_sincos.c b/usrp/limbo/apps-inband/ui_sincos.c new file mode 100644 index 00000000..27841f01 --- /dev/null +++ b/usrp/limbo/apps-inband/ui_sincos.c @@ -0,0 +1,81 @@ +/* -*- 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 + +// ---------------------------------------------------------------- + +#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 diff --git a/usrp/limbo/apps-inband/ui_sincos.h b/usrp/limbo/apps-inband/ui_sincos.h new file mode 100644 index 00000000..d2d6e4b7 --- /dev/null +++ b/usrp/limbo/apps-inband/ui_sincos.h @@ -0,0 +1,39 @@ +/* -*- 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 */ diff --git a/usrp/limbo/inband/Makefile.am b/usrp/limbo/inband/Makefile.am new file mode 100644 index 00000000..650a25ff --- /dev/null +++ b/usrp/limbo/inband/Makefile.am @@ -0,0 +1,114 @@ +# +# 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 diff --git a/usrp/limbo/inband/dump_packets.py b/usrp/limbo/inband/dump_packets.py new file mode 100755 index 00000000..23736240 --- /dev/null +++ b/usrp/limbo/inband/dump_packets.py @@ -0,0 +1,65 @@ +#!/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() diff --git a/usrp/limbo/inband/gen_test_packets.py b/usrp/limbo/inband/gen_test_packets.py new file mode 100755 index 00000000..2ee64638 --- /dev/null +++ b/usrp/limbo/inband/gen_test_packets.py @@ -0,0 +1,88 @@ +#!/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")) diff --git a/usrp/limbo/inband/qa_inband.cc b/usrp/limbo/inband/qa_inband.cc new file mode 100644 index 00000000..6f33a6ea --- /dev/null +++ b/usrp/limbo/inband/qa_inband.cc @@ -0,0 +1,35 @@ +/* -*- 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 +#include +#include + +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; +} diff --git a/usrp/limbo/inband/qa_inband.h b/usrp/limbo/inband/qa_inband.h new file mode 100644 index 00000000..ab8f7f25 --- /dev/null +++ b/usrp/limbo/inband/qa_inband.h @@ -0,0 +1,35 @@ +/* -*- 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 + +//! 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 */ diff --git a/usrp/limbo/inband/qa_inband_packet_prims.cc b/usrp/limbo/inband/qa_inband_packet_prims.cc new file mode 100644 index 00000000..d9bbbec2 --- /dev/null +++ b/usrp/limbo/inband/qa_inband_packet_prims.cc @@ -0,0 +1,162 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include // 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); + +} +////////////////////////////////////////////////////////////////////// diff --git a/usrp/limbo/inband/qa_inband_packet_prims.h b/usrp/limbo/inband/qa_inband_packet_prims.h new file mode 100644 index 00000000..71c0d737 --- /dev/null +++ b/usrp/limbo/inband/qa_inband_packet_prims.h @@ -0,0 +1,41 @@ +/* -*- 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 +#include + +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 */ diff --git a/usrp/limbo/inband/qa_inband_usrp_server.cc b/usrp/limbo/inband/qa_inband_usrp_server.cc new file mode 100644 index 00000000..6049a8a8 --- /dev/null +++ b/usrp/limbo/inband/qa_inband_usrp_server.cc @@ -0,0 +1,1575 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 d_tx_chans; + std::vector 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; isend(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)); +} diff --git a/usrp/limbo/inband/qa_inband_usrp_server.h b/usrp/limbo/inband/qa_inband_usrp_server.h new file mode 100644 index 00000000..52a4a0b0 --- /dev/null +++ b/usrp/limbo/inband/qa_inband_usrp_server.h @@ -0,0 +1,50 @@ +/* -*- 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 +#include + +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 */ diff --git a/usrp/limbo/inband/symbols_usrp_channel.h b/usrp/limbo/inband/symbols_usrp_channel.h new file mode 100644 index 00000000..a0114cf3 --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_channel.h @@ -0,0 +1,40 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_interface_cs.h b/usrp/limbo/inband/symbols_usrp_interface_cs.h new file mode 100644 index 00000000..72c8fcc9 --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_interface_cs.h @@ -0,0 +1,43 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_low_level_cs.h b/usrp/limbo/inband/symbols_usrp_low_level_cs.h new file mode 100644 index 00000000..a7260603 --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_low_level_cs.h @@ -0,0 +1,47 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_rx.h b/usrp/limbo/inband/symbols_usrp_rx.h new file mode 100644 index 00000000..07d58a3f --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_rx.h @@ -0,0 +1,36 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_rx_cs.h b/usrp/limbo/inband/symbols_usrp_rx_cs.h new file mode 100644 index 00000000..bf4f0338 --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_rx_cs.h @@ -0,0 +1,32 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_server_cs.h b/usrp/limbo/inband/symbols_usrp_server_cs.h new file mode 100644 index 00000000..e612e24e --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_server_cs.h @@ -0,0 +1,47 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_tx.h b/usrp/limbo/inband/symbols_usrp_tx.h new file mode 100644 index 00000000..4e58e2cf --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_tx.h @@ -0,0 +1,32 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/symbols_usrp_tx_cs.h b/usrp/limbo/inband/symbols_usrp_tx_cs.h new file mode 100644 index 00000000..d02ef1d2 --- /dev/null +++ b/usrp/limbo/inband/symbols_usrp_tx_cs.h @@ -0,0 +1,32 @@ +/* -*- 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 + +// 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 */ diff --git a/usrp/limbo/inband/test_inband.cc b/usrp/limbo/inband/test_inband.cc new file mode 100644 index 00000000..77cdca55 --- /dev/null +++ b/usrp/limbo/inband/test_inband.cc @@ -0,0 +1,36 @@ +/* -*- 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 +#include + +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; +} diff --git a/usrp/limbo/inband/usb_packet.py b/usrp/limbo/inband/usb_packet.py new file mode 100644 index 00000000..6dfcf863 --- /dev/null +++ b/usrp/limbo/inband/usb_packet.py @@ -0,0 +1,115 @@ +# +# 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 diff --git a/usrp/limbo/inband/usrp_inband_usb_packet.cc b/usrp/limbo/inband/usrp_inband_usb_packet.cc new file mode 100644 index 00000000..72bc45cc --- /dev/null +++ b/usrp/limbo/inband/usrp_inband_usb_packet.cc @@ -0,0 +1,793 @@ +/* -*- 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 +#endif + +#include + +#include +#include +#include +#include + +/*! + * \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; + + } +} + diff --git a/usrp/limbo/inband/usrp_inband_usb_packet.h b/usrp/limbo/inband/usrp_inband_usb_packet.h new file mode 100644 index 00000000..6f1a3feb --- /dev/null +++ b/usrp/limbo/inband/usrp_inband_usb_packet.h @@ -0,0 +1,240 @@ +/* -*- 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 +#include +#include +#include + +#include + +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<> 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 diff --git a/usrp/limbo/inband/usrp_interface.mbh b/usrp/limbo/inband/usrp_interface.mbh new file mode 100644 index 00000000..ad0f78b4 --- /dev/null +++ b/usrp/limbo/inband/usrp_interface.mbh @@ -0,0 +1,88 @@ +;; -*- 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 + ) + ) diff --git a/usrp/limbo/inband/usrp_rx.cc b/usrp/limbo/inband/usrp_rx.cc new file mode 100644 index 00000000..fe9486cf --- /dev/null +++ b/usrp/limbo/inband/usrp_rx.cc @@ -0,0 +1,184 @@ +/* -*- 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 +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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(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); diff --git a/usrp/limbo/inband/usrp_rx.h b/usrp/limbo/inband/usrp_rx.h new file mode 100644 index 00000000..1006235b --- /dev/null +++ b/usrp/limbo/inband/usrp_rx.h @@ -0,0 +1,58 @@ +/* -*- 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 +#include +#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 */ + diff --git a/usrp/limbo/inband/usrp_rx_stub.cc b/usrp/limbo/inband/usrp_rx_stub.cc new file mode 100644 index 00000000..e5c454d2 --- /dev/null +++ b/usrp/limbo/inband/usrp_rx_stub.cc @@ -0,0 +1,227 @@ +/* -*- 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 +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include "usrp_standard.h" +#include +#include +#include +#include + +#include + +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 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); diff --git a/usrp/limbo/inband/usrp_rx_stub.h b/usrp/limbo/inband/usrp_rx_stub.h new file mode 100644 index 00000000..238b4568 --- /dev/null +++ b/usrp/limbo/inband/usrp_rx_stub.h @@ -0,0 +1,79 @@ +/* -*- 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 +#include +#include "usrp_standard.h" +#include +#include +#include +#include + +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 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 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 */ + diff --git a/usrp/limbo/inband/usrp_server.cc b/usrp/limbo/inband/usrp_server.cc new file mode 100644 index 00000000..ac263630 --- /dev/null +++ b/usrp/limbo/inband/usrp_server.cc @@ -0,0 +1,1860 @@ +/* -*- 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 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 &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 &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 &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(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 &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 &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< &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<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 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 &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); diff --git a/usrp/limbo/inband/usrp_server.h b/usrp/limbo/inband/usrp_server.h new file mode 100644 index 00000000..dd1825d5 --- /dev/null +++ b/usrp/limbo/inband/usrp_server.h @@ -0,0 +1,131 @@ +/* -*- 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 +#include +#include +#include +#include + +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 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 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 d_chaninfo_tx; + std::vector d_chaninfo_rx; + + std::queue 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 &chan_info, pmt_t data); + void handle_cmd_deallocate_channel(mb_port_sptr port, std::vector &chan_info, pmt_t data); + void handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector &chan_info, pmt_t data); + void handle_cmd_to_control_channel(mb_port_sptr port, std::vector &chan_info, pmt_t data); + void handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector &chan_info, pmt_t data); + void handle_cmd_stop_recv_raw_samples(mb_port_sptr port, std::vector &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 &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 */ diff --git a/usrp/limbo/inband/usrp_server.mbh b/usrp/limbo/inband/usrp_server.mbh new file mode 100644 index 00000000..ed7943fc --- /dev/null +++ b/usrp/limbo/inband/usrp_server.mbh @@ -0,0 +1,255 @@ +;; -*- 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) + ) + ) diff --git a/usrp/limbo/inband/usrp_tx.cc b/usrp/limbo/inband/usrp_tx.cc new file mode 100644 index 00000000..0d4a8461 --- /dev/null +++ b/usrp/limbo/inband/usrp_tx.cc @@ -0,0 +1,150 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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(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(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); diff --git a/usrp/limbo/inband/usrp_tx.h b/usrp/limbo/inband/usrp_tx.h new file mode 100644 index 00000000..d3a6f8b5 --- /dev/null +++ b/usrp/limbo/inband/usrp_tx.h @@ -0,0 +1,52 @@ +/* -*- 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 +#include +#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 */ + diff --git a/usrp/limbo/inband/usrp_tx_stub.cc b/usrp/limbo/inband/usrp_tx_stub.cc new file mode 100644 index 00000000..c78b1a7b --- /dev/null +++ b/usrp/limbo/inband/usrp_tx_stub.cc @@ -0,0 +1,344 @@ +/* -*- 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "usrp_standard.h" +#include +#include +#include + +#include + +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(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(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; isend(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); diff --git a/usrp/limbo/inband/usrp_tx_stub.h b/usrp/limbo/inband/usrp_tx_stub.h new file mode 100644 index 00000000..b81037ad --- /dev/null +++ b/usrp/limbo/inband/usrp_tx_stub.h @@ -0,0 +1,61 @@ +/* -*- 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 +#include +#include "usrp_standard.h" +#include +#include + +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 */ + diff --git a/usrp/limbo/inband/usrp_usb_interface.cc b/usrp/limbo/inband/usrp_usb_interface.cc new file mode 100644 index 00000000..fb7109a5 --- /dev/null +++ b/usrp/limbo/inband/usrp_usb_interface.cc @@ -0,0 +1,601 @@ +/* -*- 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 +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include "usrp_rx.h" +#include +#include "usrp_tx.h" +#include "usrp_standard.h" +#include +#include + +typedef usrp_inband_usb_packet transport_pkt; + +#include +#include +#include +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 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 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 d_usrp_basic, std::vector 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); diff --git a/usrp/limbo/inband/usrp_usb_interface.h b/usrp/limbo/inband/usrp_usb_interface.h new file mode 100644 index 00000000..4d7750a7 --- /dev/null +++ b/usrp/limbo/inband/usrp_usb_interface.h @@ -0,0 +1,78 @@ +/* -*- 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 +#include +#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 d_ub_tx; + boost::shared_ptr 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 d_usrp_basic, std::vector 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 */ diff --git a/usrp/usrp-inband.pc.in b/usrp/usrp-inband.pc.in deleted file mode 100644 index 57e27462..00000000 --- a/usrp/usrp-inband.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -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}