summaryrefslogtreecommitdiff
path: root/usrp/limbo/inband/usrp_usb_interface.cc
diff options
context:
space:
mode:
authorjcorgan2009-07-09 02:55:51 +0000
committerjcorgan2009-07-09 02:55:51 +0000
commitc276a4ffee9314d2528166547abfd2c09d29713f (patch)
tree03b06ac67874342ba671a4a0405e006de1ece9ba /usrp/limbo/inband/usrp_usb_interface.cc
parenteefb51c0c0fac68d16544e492aebd883528607e1 (diff)
downloadgnuradio-c276a4ffee9314d2528166547abfd2c09d29713f.tar.gz
gnuradio-c276a4ffee9314d2528166547abfd2c09d29713f.tar.bz2
gnuradio-c276a4ffee9314d2528166547abfd2c09d29713f.zip
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 <usrp_*.h> to #include <usrp/usrp_*.h> ...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
Diffstat (limited to 'usrp/limbo/inband/usrp_usb_interface.cc')
-rw-r--r--usrp/limbo/inband/usrp_usb_interface.cc601
1 files changed, 601 insertions, 0 deletions
diff --git a/usrp/limbo/inband/usrp_usb_interface.cc b/usrp/limbo/inband/usrp_usb_interface.cc
new file mode 100644
index 000000000..fb7109a5a
--- /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 <config.h>
+#endif
+
+#include <usrp_usb_interface.h>
+
+#include <iostream>
+#include <vector>
+#include <usb.h>
+#include <mblock/class_registry.h>
+#include <usrp_inband_usb_packet.h>
+#include <fpga_regs_common.h>
+#include "usrp_rx.h"
+#include <usrp_rx_stub.h>
+#include "usrp_tx.h"
+#include "usrp_standard.h"
+#include <stdio.h>
+#include <usrp_dbid.h>
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+#include <symbols_usrp_interface_cs.h>
+#include <symbols_usrp_tx_cs.h>
+#include <symbols_usrp_rx_cs.h>
+static pmt_t s_shutdown = pmt_intern("%shutdown");
+
+static const bool verbose = false;
+
+
+/*!
+ * \brief Initializes the USB interface m-block.
+ *
+ * The \p user_arg should be a PMT dictionary which can contain optional
+ * arguments for the block, such as the decimatoin and interpolation rate.
+ */
+usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg),
+ d_fake_usrp(false),
+ d_rx_reading(false),
+ d_interp_tx(128),
+ d_decim_rx(128),
+ d_rf_freq(-1),
+ d_rbf("inband_tx_rx.rbf")
+{
+ // Dictionary for arguments to all of the components
+ pmt_t usrp_dict = user_arg;
+
+ // Default TX/RX interface
+ std::string tx_interface = "usrp_tx";
+ std::string rx_interface = "usrp_rx";
+
+ if (pmt_is_dict(usrp_dict)) {
+
+ // The 'fake-usrp' key enables the TX and RX stubs if PMT_T
+ if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict,
+ pmt_intern("fake-usrp"),
+ PMT_NIL)) {
+ if(pmt_eqv(fake_usrp, PMT_T)) {
+ tx_interface = "usrp_tx_stub";
+ rx_interface = "usrp_rx_stub";
+ d_fake_usrp=true;
+ }
+ }
+
+ // Read the TX interpolations
+ if(pmt_t interp_tx = pmt_dict_ref(usrp_dict,
+ pmt_intern("interp-tx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(interp_tx, PMT_NIL))
+ d_interp_tx = pmt_to_long(interp_tx);
+ }
+
+ // Read the RX decimation rate
+ if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
+ pmt_intern("decim-rx"),
+ PMT_NIL)) {
+ if(!pmt_eqv(decim_rx, PMT_NIL))
+ d_decim_rx = pmt_to_long(decim_rx);
+ }
+
+ // Read the RBF
+ if(pmt_t rbf = pmt_dict_ref(usrp_dict,
+ pmt_intern("rbf"),
+ PMT_NIL)) {
+ if(!pmt_eqv(rbf, PMT_NIL))
+ d_rbf = pmt_symbol_to_string(rbf);
+ }
+
+ // The RF center frequency
+ if(pmt_t rf_freq = pmt_dict_ref(usrp_dict,
+ pmt_intern("rf-freq"),
+ PMT_NIL)) {
+ if(!pmt_eqv(rf_freq, PMT_NIL))
+ d_rf_freq = pmt_to_double(rf_freq);
+ }
+ }
+
+ if (verbose) {
+ std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to "
+ << d_rbf << std::endl;
+
+ std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to "
+ << d_interp_tx << std::endl;
+
+ std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to "
+ << d_decim_rx << std::endl;
+
+ std::cout << "[USRP_USB_INTERFACE] Using TX interface: "
+ << tx_interface << "\n";
+
+ std::cout << "[USRP_USB_INTERFACE] Using RX interface: "
+ << rx_interface << "\n";
+
+ }
+
+ d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL);
+ d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL);
+ d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL);
+
+ // Connect to TX and RX
+ define_component("tx", tx_interface, usrp_dict);
+ define_component("rx", rx_interface, usrp_dict);
+ connect("self", "rx_cs", "rx", "cs");
+ connect("self", "tx_cs", "tx", "cs");
+
+ // FIXME: the code should query the FPGA to retrieve the number of channels and such
+ d_ntx_chan = 2;
+ d_nrx_chan = 2;
+}
+
+usrp_usb_interface::~usrp_usb_interface()
+{
+
+}
+
+void
+usrp_usb_interface::initial_transition()
+{
+
+}
+
+/*!
+ * \brief Handles all incoming signals to the block from the lowest m-blocks
+ * which read/write to the bus, or the higher m-block which is the USRP server.
+ */
+void
+usrp_usb_interface::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal(); // the "name" of the message
+ pmt_t port_id = msg->port_id(); // which port it came in on
+ pmt_t data = msg->data();
+ pmt_t invocation_handle;
+
+ if (pmt_eq(event, s_shutdown)) // ignore (for now)
+ return;
+
+ //------------- CONTROL / STATUS -------------//
+ if (pmt_eq(port_id, d_cs->port_symbol())) {
+
+ //------------ OPEN --------------//
+ if (pmt_eq(event, s_cmd_usrp_open)){
+ handle_cmd_open(data);
+ return;
+ }
+ //----------- CLOSE -------------//
+ else if (pmt_eq(event, s_cmd_usrp_close)) {
+ handle_cmd_close(data);
+ return;
+ }
+ //---------- NTX CHAN ----------//
+ else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ d_cs->send(s_response_usrp_ntx_chan,
+ pmt_list2(invocation_handle,
+ pmt_from_long(d_ntx_chan)));
+ return;
+ }
+ //---------- NRX CHAN ----------//
+ else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ d_cs->send(s_response_usrp_nrx_chan,
+ pmt_list2(invocation_handle,
+ pmt_from_long(d_nrx_chan)));
+ return;
+ }
+ //------------ WRITE -----------//
+ else if(pmt_eq(event, s_cmd_usrp_write)) {
+ handle_cmd_write(data);
+ return;
+ }
+ //-------- START READING --------//
+ else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
+ handle_cmd_start_reading(data);
+ return;
+ }
+ //-------- STOP READING --------//
+ else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
+ handle_cmd_stop_reading(data);
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ //---------------- RX ------------------//
+ if (pmt_eq(port_id, d_rx_cs->port_symbol())) {
+
+ // Relay reads back up
+ if(pmt_eq(event, s_response_usrp_rx_read)) {
+ d_cs->send(s_response_usrp_read, data);
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ //---------------- TX ------------------//
+ if (pmt_eq(port_id, d_tx_cs->port_symbol())) {
+
+ if(pmt_eq(event, s_response_usrp_tx_write)) {
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ d_cs->send(s_response_usrp_write,
+ pmt_list3(invocation_handle,
+ status,
+ channel));
+
+ return;
+ }
+
+ goto unhandled;
+ }
+
+ unhandled:
+ std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * open a USB connection to the USRP (cmd-usrp-open).
+ *
+ * The \p data parameter is a PMT list, where the elements are an invocation
+ * handle and the USRP number.
+ */
+void
+usrp_usb_interface::handle_cmd_open(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long which_usrp = pmt_to_long(pmt_nth(1, data));
+ pmt_t reply_data;
+
+ if(d_fake_usrp) {
+ d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
+ return;
+ }
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
+
+ // Open up a standard RX and TX for communication with the USRP
+
+ d_utx = usrp_standard_tx::make(which_usrp,
+ d_interp_tx,
+ 1, // 1 channel
+ -1, // mux
+ 4096, // USB block size
+ 16, // nblocks for async transfers
+ d_rbf
+ );
+
+ if(d_utx==0) {
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ // Perform TX daughterboard tuning
+ double target_freq;
+ unsigned int mux;
+ int tgain, rgain;
+ float input_rate;
+ bool ok;
+ usrp_tune_result r;
+
+ // Cast to usrp_basic and then detect daughterboards
+ d_ub_tx = d_utx;
+ usrp_subdev_spec tspec = pick_tx_subdevice();
+ db_base_sptr tsubdev = d_ub_tx->selected_subdev(tspec);
+
+ // Set the TX mux value
+ mux = d_utx->determine_tx_mux_value(tspec);
+ d_utx->set_mux(mux);
+
+ // Set the TX gain and determine rate
+ tgain = tsubdev->gain_max();
+ tsubdev->set_gain(tgain);
+ input_rate = d_ub_tx->converter_rate() / d_utx->interp_rate();
+
+ // Perform the actual tuning, if no frequency specified then pick
+ if(d_rf_freq==-1)
+ target_freq = tsubdev->freq_min()+((tsubdev->freq_max()-tsubdev->freq_min())/2.0);
+ else
+ target_freq = d_rf_freq;
+ ok = d_utx->tune(tsubdev->which(), tsubdev, target_freq, &r);
+ tsubdev->set_enable(true);
+
+ if(verbose) {
+ printf("TX Subdevice name is %s\n", tsubdev->name().c_str());
+ printf("TX Subdevice freq range: (%g, %g)\n",
+ tsubdev->freq_min(), tsubdev->freq_max());
+ printf("mux: %#08x\n", mux);
+ printf("target_freq: %f\n", target_freq);
+ printf("ok: %s\n", ok ? "true" : "false");
+ printf("gain: %d\n", tgain);
+ printf("r.baseband_freq: %f\n", r.baseband_freq);
+ printf("r.dxc_freq: %f\n", r.dxc_freq);
+ printf("r.residual_freq: %f\n", r.residual_freq);
+ printf("r.inverted: %d\n", r.inverted);
+ }
+
+ if(!ok) {
+ std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ d_utx->start();
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
+
+ d_urx =
+ usrp_standard_rx::make (which_usrp,
+ d_decim_rx,
+ 1, // nchan
+ -1, // mux
+ 0, // set blank mode to start
+ 4096, // USB block size
+ 16, // number of blocks for async transfers
+ d_rbf);
+
+ if(!d_urx) {
+ if (verbose)
+ std::cout << "[usrp_server] Failed to open RX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ // Cast to usrp_basic and then detect daughterboards
+ d_ub_rx = d_urx;
+ usrp_subdev_spec rspec = pick_rx_subdevice();
+ db_base_sptr rsubdev = d_ub_rx->selected_subdev(rspec);
+
+ // Set the RX mux value
+ mux = d_urx->determine_rx_mux_value(rspec);
+ d_urx->set_mux(mux);
+
+ // Set the RX gain and determine rate
+ rgain = rsubdev->gain_max()/2.0;
+ rsubdev->set_gain(rgain);
+ input_rate = d_ub_rx->converter_rate() / d_urx->decim_rate();
+
+ ok = d_urx->tune(rsubdev->which(), rsubdev, target_freq, &r);
+ rsubdev->set_enable(true);
+
+ if(verbose) {
+ printf("RX Subdevice name is %s\n", rsubdev->name().c_str());
+ printf("RX Subdevice freq range: (%g, %g)\n",
+ rsubdev->freq_min(), rsubdev->freq_max());
+ printf("mux: %#08x\n", mux);
+ printf("target_freq: %f\n", target_freq);
+ printf("ok: %s\n", ok ? "true" : "false");
+ printf("gain: %d\n", rgain);
+ printf("r.baseband_freq: %f\n", r.baseband_freq);
+ printf("r.dxc_freq: %f\n", r.dxc_freq);
+ printf("r.residual_freq: %f\n", r.residual_freq);
+ printf("r.inverted: %d\n", r.inverted);
+ }
+
+ if(!ok) {
+ std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on RX\n";
+ reply_data = pmt_list2(invocation_handle, PMT_F);
+ d_cs->send(s_response_usrp_open, reply_data);
+ return;
+ }
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
+
+// d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
+// d_utx->_write_oe(0, 0xffff, 0xffff);
+// d_urx->_write_oe(0, 0xffff, 0xffff);
+// d_utx->_write_oe(1, 0xffff, 0xffff);
+// d_urx->_write_oe(1, 0xffff, 0xffff);
+
+ d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * write data to the USB bus (cmd-usrp-write).
+ *
+ * The \p data parameter is a PMT list containing 3 mandatory elements in the
+ * following order: an invocation handle, channel, and a uniform vector
+ * representation of the packets.
+ */
+void
+usrp_usb_interface::handle_cmd_write(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t channel = pmt_nth(1, data);
+ pmt_t pkts = pmt_nth(2, data);
+
+ pmt_t tx_handle = pmt_make_any(d_utx);
+
+ d_tx_cs->send(s_cmd_usrp_tx_write,
+ pmt_list4(invocation_handle,
+ channel,
+ pkts,
+ tx_handle));
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * start reading data from the USB bus (cmd-usrp-start-reading).
+ *
+ * The \p data parameter is a PMT list with a single element: an invocation
+ * handle which can be returned with the response.
+ */
+void
+usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ if(verbose)
+ std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
+
+ if(!d_fake_usrp)
+ d_urx->start();
+
+ pmt_t rx_handle = pmt_make_any(d_urx);
+
+ d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
+
+ d_rx_reading = true;
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * stop reading data from the USB bus (cmd-usrp-stop-reading).
+ *
+ * The \p data parameter is a PMT list with a single element: an invocation
+ * handle which can be returned with the response.
+ */
+void
+usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ if(!d_fake_usrp) {
+ if(verbose)
+ std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
+ usrp_rx_stop = true;
+
+ // Used to allow a read() being called by a lower layer to complete before
+ // stopping, else there can be partial data left on the bus and can generate
+ // errors.
+ while(usrp_rx_stop) {usleep(1);}
+ d_urx->stop();
+ }
+ else {
+ if(verbose)
+ std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
+ usrp_rx_stop_stub = true; // extern to communicate with stub to wait
+ }
+
+ d_rx_reading = false;
+
+ return;
+}
+
+/*!
+ * \brief Called by the handle_message() method when the incoming signal is to
+ * close the USB connection to the USRP.
+ *
+ * The \p data parameter is a PMT list with a single element: an invocation
+ * handle which can be returned with the response.
+ */
+void
+usrp_usb_interface::handle_cmd_close(pmt_t data)
+{
+ pmt_t invocation_handle = pmt_nth(0, data);
+
+ if(d_rx_reading)
+ handle_cmd_stop_reading(PMT_NIL);
+
+ if(d_fake_usrp) {
+ d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
+ return;
+ }
+
+ if (verbose)
+ std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
+
+ d_utx.reset();
+ d_urx.reset();
+
+ d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
+
+ // FIXME This seems like a _very_ strange place to be calling shutdown_all.
+ // That decision should be left to high-level code, not low-level code like this.
+ shutdown_all(PMT_T);
+}
+
+usrp_subdev_spec
+usrp_usb_interface::pick_rx_subdevice()
+{
+ int dbids[] = {
+ USRP_DBID_FLEX_400_RX,
+ USRP_DBID_FLEX_900_RX,
+ USRP_DBID_FLEX_1200_RX,
+ USRP_DBID_FLEX_2400_RX,
+ USRP_DBID_TV_RX,
+ USRP_DBID_TV_RX_REV_2,
+ USRP_DBID_DBS_RX,
+ USRP_DBID_BASIC_RX
+ };
+
+ std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
+ return pick_subdev(d_ub_rx, candidates);
+}
+
+usrp_subdev_spec
+usrp_usb_interface::pick_tx_subdevice()
+{
+ int dbids[] = {
+ USRP_DBID_FLEX_400_TX,
+ USRP_DBID_FLEX_900_TX,
+ USRP_DBID_FLEX_1200_TX,
+ USRP_DBID_FLEX_2400_TX,
+ USRP_DBID_BASIC_TX
+ };
+
+ std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
+ return pick_subdev(d_ub_tx, candidates);
+}
+
+usrp_subdev_spec
+usrp_usb_interface::pick_subdev(boost::shared_ptr<usrp_basic> d_usrp_basic, std::vector<int> candidates)
+{
+ int dbid0 = d_usrp_basic->selected_subdev(usrp_subdev_spec(0, 0))->dbid();
+ int dbid1 = d_usrp_basic->selected_subdev(usrp_subdev_spec(1, 0))->dbid();
+
+ for (int i = 0; i < candidates.size(); i++) {
+ int dbid = candidates[i];
+ if (dbid0 == dbid)
+ return usrp_subdev_spec(0, 0);
+ if (dbid1 == dbid)
+ return usrp_subdev_spec(1, 0);
+ }
+
+ if (dbid0 >= 0)
+ return usrp_subdev_spec(0, 0);
+ if (dbid1 >= 0)
+ return usrp_subdev_spec(1, 0);
+
+ throw std::runtime_error("No suitable daughterboard found!");
+}
+
+
+REGISTER_MBLOCK_CLASS(usrp_usb_interface);