From 1b3b856f5a5d06628d4176071cad424a146433c9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 17 Sep 2010 16:50:59 -0700 Subject: usrp2: provide clock over mimo connector so usrp2 can share refs --- host/lib/usrp/usrp2/clock_ctrl.cpp | 51 +++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index 02227afad..1e1c9b7b8 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -20,6 +20,7 @@ #include "usrp2_regs.hpp" //spi slave constants #include #include +#include using namespace uhd; @@ -67,12 +68,60 @@ public: this->enable_dac_clock(true); this->enable_adc_clock(true); + /* always driving the mimo reference */ + this->enable_mimo_clock_out(true); } ~usrp2_clock_ctrl_impl(void){ - /* private clock enables, must be set here */ + //power down clock outputs + this->enable_external_ref(false); + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); this->enable_dac_clock(false); this->enable_adc_clock(false); + this->enable_mimo_clock_out(false); + } + + void enable_mimo_clock_out(bool enb){ + //FIXME TODO put this revision read in a common place + boost::uint8_t rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0); + + //calculate the low and high dividers + size_t divider = size_t(this->get_master_clock_rate()/10e6); + size_t high = divider/2; + size_t low = divider - high; + + switch(rev_hi){ + case 3: //clock 2 + _ad9510_regs.power_down_lvpecl_out2 = enb? + ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : + ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD; + _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_810MV; + //set the registers (divider - 1) + _ad9510_regs.divider_low_cycles_out2 = low - 1; + _ad9510_regs.divider_high_cycles_out2 = high - 1; + _ad9510_regs.bypass_divider_out2 = 0; + this->write_reg(0x3e); + this->write_reg(0x4c); + break; + + case 4: //clock 5 + _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_LVDS; + _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA; + //set the registers (divider - 1) + _ad9510_regs.divider_low_cycles_out5 = low - 1; + _ad9510_regs.divider_high_cycles_out5 = high - 1; + _ad9510_regs.bypass_divider_out5 = 0; + this->write_reg(0x41); + this->write_reg(0x52); + break; + + //TODO FIXME do i want to throw, what about uninitialized boards? + //default: throw std::runtime_error("unknown rev hi in mboard eeprom"); + default: std::cerr << "unknown rev hi: " << rev_hi << std::endl; + } + this->update_regs(); } //uses output clock 7 (cmos) -- cgit v1.2.3 From 1625bcb4139a317189ff2a4c71b96473944aba50 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 20 Sep 2010 16:59:44 -0700 Subject: uhd: added single usrp interface, added usrp1 properties to prop names --- host/docs/coding.rst | 12 +- host/examples/benchmark_rx_rate.cpp | 8 +- host/examples/rx_timed_samples.cpp | 6 +- host/examples/test_async_messages.cpp | 12 +- host/examples/test_pps_input.cpp | 6 +- host/examples/tx_timed_samples.cpp | 6 +- host/examples/tx_waveforms.cpp | 6 +- host/include/uhd/device.hpp | 13 -- host/include/uhd/device.ipp | 26 --- host/include/uhd/usrp/CMakeLists.txt | 1 + host/include/uhd/usrp/simple_usrp.hpp | 2 +- host/include/uhd/usrp/single_usrp.hpp | 172 +++++++++++++++++++ host/lib/usrp/CMakeLists.txt | 1 + host/lib/usrp/single_usrp.cpp | 309 ++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp1/dsp_impl.cpp | 10 +- host/lib/usrp/usrp1/mboard_impl.cpp | 39 ++--- host/lib/usrp/usrp1/usrp1_impl.hpp | 6 + 17 files changed, 546 insertions(+), 89 deletions(-) create mode 100644 host/include/uhd/usrp/single_usrp.hpp create mode 100644 host/lib/usrp/single_usrp.cpp (limited to 'host/lib/usrp') diff --git a/host/docs/coding.rst b/host/docs/coding.rst index 23f350b0f..d6a19d250 100644 --- a/host/docs/coding.rst +++ b/host/docs/coding.rst @@ -23,11 +23,11 @@ The device API provides ways to: See the documentation in *device.hpp* for reference. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -High-Level: The simple usrp +High-Level: The single usrp ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The goal of the simple usrp API is to wrap high level functions around the device properties. -The simple usrp provides a fat interface to access the most common properties. -The simple usrp provides ways to: +The goal of the single usrp API is to wrap high level functions around the device properties. +The single usrp provides a fat interface to access the most common properties. +The single usrp provides ways to: * Set and get daughterboard gains. * Set and get daughterboard antennas. @@ -38,13 +38,13 @@ The simple usrp provides ways to: * Set the usrp time registers. * Get the underlying device (as discussed above). -See the documentation in *usrp/simple_usrp.hpp* for reference. +See the documentation in *usrp/single_usrp.hpp* for reference. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ High-Level: The mimo usrp ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The mimo usrp API provides a wrapper around a device that represents several motherboards. -This API provides convenience calls just like the simple usrp, +This API provides convenience calls just like the single usrp, however the calls either work across all channels in the configuration, or take a channel argument to specify which channel to configure. The mimo usrp provides ways to: diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 8fae813cf..36611f97f 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -27,7 +27,7 @@ namespace po = boost::program_options; static inline void test_device( - uhd::usrp::simple_usrp::sptr sdev, + uhd::usrp::single_usrp::sptr sdev, double rx_rate_sps, double duration_secs ){ @@ -118,7 +118,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("args", po::value(&args)->default_value(""), "single uhd device address args") ("duration", po::value(&duration)->default_value(10.0), "duration for each test in seconds") ("rate", po::value(&only_rate), "specify to perform a single test as this rate (sps)") ; @@ -135,7 +135,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args); std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //stop if left running diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 4856f6779..441665900 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -38,7 +38,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("args", po::value(&args)->default_value(""), "single uhd device address args") ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to receive") ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to receive") ("rxrate", po::value(&rx_rate)->default_value(100e6/16), "rate of incoming samples") @@ -60,7 +60,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args); uhd::device::sptr dev = sdev->get_device(); std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_async_messages.cpp index e02bc5f40..4c9d18121 100644 --- a/host/examples/test_async_messages.cpp +++ b/host/examples/test_async_messages.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -33,7 +33,7 @@ static const size_t async_to_ms = 100; * Send a burst of many samples that will fragment internally. * We expect to not get any async messages. */ -void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){ +void test_no_async_message(uhd::usrp::single_usrp::sptr sdev){ uhd::device::sptr dev = sdev->get_device(); std::cout << "Test no async message... " << std::flush; @@ -73,7 +73,7 @@ void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){ * Send a start of burst packet with no following end of burst. * We expect to get an underflow(within a burst) async message. */ -void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){ +void test_underflow_message(uhd::usrp::single_usrp::sptr sdev){ uhd::device::sptr dev = sdev->get_device(); std::cout << "Test underflow message... " << std::flush; @@ -117,7 +117,7 @@ void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){ * Send a burst packet that occurs at a time in the past. * We expect to get a time error async message. */ -void test_time_error_message(uhd::usrp::simple_usrp::sptr sdev){ +void test_time_error_message(uhd::usrp::single_usrp::sptr sdev){ uhd::device::sptr dev = sdev->get_device(); std::cout << "Test time error message... " << std::flush; @@ -170,7 +170,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("args", po::value(&args)->default_value(""), "single uhd device address args") ("rate", po::value(&rate)->default_value(1.5e6), "rate of outgoing samples") ; po::variables_map vm; @@ -186,7 +186,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args); std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; //set the tx sample rate diff --git a/host/examples/test_pps_input.cpp b/host/examples/test_pps_input.cpp index e01d32910..d1b49d320 100644 --- a/host/examples/test_pps_input.cpp +++ b/host/examples/test_pps_input.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -37,7 +37,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("args", po::value(&args)->default_value(""), "single uhd device address args") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); @@ -52,7 +52,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args); uhd::device::sptr dev = sdev->get_device(); std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 5b72bd72f..f34c121d5 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -40,7 +40,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("args", po::value(&args)->default_value(""), "single uhd device address args") ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit") ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to transmit") ("spp", po::value(&samps_per_packet)->default_value(1000), "number of samples per packet") @@ -64,7 +64,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args); uhd::device::sptr dev = sdev->get_device(); std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp index 3f319cf68..50982cf88 100644 --- a/host/examples/tx_waveforms.cpp +++ b/host/examples/tx_waveforms.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include //system time #include @@ -70,7 +70,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("args", po::value(&args)->default_value(""), "single uhd device address args") ("duration", po::value(&total_duration)->default_value(3), "number of seconds to transmit") ("spb", po::value(&spb)->default_value(10000), "samples per buffer") ("rate", po::value(&rate)->default_value(1.5e6), "rate of outgoing samples") @@ -93,7 +93,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args); uhd::device::sptr dev = sdev->get_device(); std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index c48b3dfff..2077cae62 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include namespace uhd{ @@ -140,12 +139,6 @@ public: send_mode_t send_mode ); - //! Deprecated - size_t send( - const boost::asio::const_buffer &, const tx_metadata_t &, - const io_type_t &, send_mode_t send_mode - ); - /*! * Receive buffers containing IF data described by the metadata. * @@ -196,12 +189,6 @@ public: size_t timeout_ms = default_recv_timeout_ms ); - //! Deprecated - size_t recv( - const boost::asio::mutable_buffer &, rx_metadata_t &, - const io_type_t &, recv_mode_t - ); - /*! * Get the maximum number of samples per packet on send. * \return the number of samples diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp index 603c52859..60a3f535d 100644 --- a/host/include/uhd/device.ipp +++ b/host/include/uhd/device.ipp @@ -34,19 +34,6 @@ namespace uhd{ ); } - UHD_DEPRECATED UHD_INLINE size_t device::send( - const boost::asio::const_buffer &buff, - const tx_metadata_t &metadata, - const io_type_t &io_type, - send_mode_t send_mode - ){ - return this->send( - boost::asio::buffer_cast(buff), - boost::asio::buffer_size(buff)/io_type.size, - metadata, io_type, send_mode - ); - } - UHD_INLINE size_t device::recv( void *buff, size_t nsamps_per_buff, @@ -62,19 +49,6 @@ namespace uhd{ ); } - UHD_DEPRECATED UHD_INLINE size_t device::recv( - const boost::asio::mutable_buffer &buff, - rx_metadata_t &metadata, - const io_type_t &io_type, - recv_mode_t recv_mode - ){ - return this->recv( - boost::asio::buffer_cast(buff), - boost::asio::buffer_size(buff)/io_type.size, - metadata, io_type, recv_mode - ); - } - } //namespace uhd #endif /* INCLUDED_UHD_DEVICE_IPP */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index 130956f8a..f973e401a 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -40,6 +40,7 @@ INSTALL(FILES ### interfaces ### simple_usrp.hpp + single_usrp.hpp mimo_usrp.hpp DESTINATION ${INCLUDE_DIR}/uhd/usrp diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 08b9c01ea..169411f19 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -38,7 +38,7 @@ namespace uhd{ namespace usrp{ * The wrapper provides convenience functions to tune the devices * as well as to set the dboard gains, antennas, and other properties. */ -class UHD_API simple_usrp : boost::noncopyable{ +class UHD_API UHD_DEPRECATED simple_usrp : boost::noncopyable{ public: typedef boost::shared_ptr sptr; diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp new file mode 100644 index 000000000..1b89a3620 --- /dev/null +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -0,0 +1,172 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#ifndef INCLUDED_UHD_USRP_SINGLE_USRP_HPP +#define INCLUDED_UHD_USRP_SINGLE_USRP_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uhd{ namespace usrp{ + +/*! + * The single USRP device class: + * A single usrp facilitates ease-of-use for most use-case scenarios. + * The wrapper provides convenience functions to tune the devices + * as well as to set the dboard gains, antennas, and other properties. + * This wrapper supports multi-channel configurations per motherboard. + */ +class UHD_API single_usrp : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new single usrp from the device address. + * \param dev_addr the device address + * \return a new single usrp object + */ + static sptr make(const device_addr_t &dev_addr); + + /*! + * Get the underlying device object. + * This is needed to get access to the streaming API and properties. + * \return the device object within this single usrp + */ + virtual device::sptr get_device(void) = 0; + + /*! + * Get a printable name for this usrp. + * \return a printable string + */ + virtual std::string get_pp_string(void) = 0; + + /******************************************************************* + * Misc + ******************************************************************/ + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + + /*! + * Sets the time registers on the usrp immediately. + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_now(const time_spec_t &time_spec) = 0; + + /*! + * Set the time registers on the usrp at the next pps tick. + * The values will not be latched in until the pulse occurs. + * It is recommended that the user sleep(1) after calling to ensure + * that the time registers will be in a known state prior to use. + * + * Note: Because this call sets the time on the "next" pps, + * the seconds in the time spec should be current seconds + 1. + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + + /*! + * Issue a stream command to the usrp device. + * This tells the usrp to send samples into the host. + * See the documentation for stream_cmd_t for more info. + * \param stream_cmd the stream command to issue + */ + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + + /*! + * Set the clock configuration for the usrp device. + * This tells the usrp how to get a 10Mhz reference and PPS clock. + * See the documentation for clock_config_t for more info. + * \param clock_config the clock configuration to set + */ + virtual void set_clock_config(const clock_config_t &clock_config) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; + virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0; + + virtual void set_rx_rate(double rate) = 0; + virtual double get_rx_rate(void) = 0; + + virtual tune_result_t set_rx_freq(double freq, size_t chan = 0) = 0; + virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan = 0) = 0; + virtual double get_rx_freq(size_t chan = 0) = 0; + virtual freq_range_t get_rx_freq_range(size_t chan = 0) = 0; + + virtual void set_rx_gain(float gain, size_t chan = 0) = 0; + virtual float get_rx_gain(size_t chan = 0) = 0; + virtual gain_range_t get_rx_gain_range(size_t chan = 0) = 0; + + virtual void set_rx_antenna(const std::string &ant, size_t chan = 0) = 0; + virtual std::string get_rx_antenna(size_t chan = 0) = 0; + virtual std::vector get_rx_antennas(size_t chan = 0) = 0; + + virtual bool get_rx_lo_locked(size_t chan = 0) = 0; + + /*! + * Read the RSSI value from a usrp device. + * Or throw if the dboard does not support an RSSI readback. + * \return the rssi in dB + */ + virtual float read_rssi(size_t chan = 0) = 0; + + virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan = 0) = 0; + + /******************************************************************* + * TX methods + ******************************************************************/ + virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; + virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0; + + virtual void set_tx_rate(double rate) = 0; + virtual double get_tx_rate(void) = 0; + + virtual tune_result_t set_tx_freq(double freq, size_t chan = 0) = 0; + virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan = 0) = 0; + virtual double get_tx_freq(size_t chan = 0) = 0; + virtual freq_range_t get_tx_freq_range(size_t chan = 0) = 0; + + virtual void set_tx_gain(float gain, size_t chan = 0) = 0; + virtual float get_tx_gain(size_t chan = 0) = 0; + virtual gain_range_t get_tx_gain_range(size_t chan = 0) = 0; + + virtual void set_tx_antenna(const std::string &ant, size_t chan = 0) = 0; + virtual std::string get_tx_antenna(size_t chan = 0) = 0; + virtual std::vector get_tx_antennas(size_t chan = 0) = 0; + + virtual bool get_tx_lo_locked(size_t chan = 0) = 0; + + virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan = 0) = 0; +}; + +}} + +#endif /* INCLUDED_UHD_USRP_SINGLE_USRP_HPP */ diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index b5c545988..69a190bfa 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -26,6 +26,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp ) diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp new file mode 100644 index 000000000..77e705c71 --- /dev/null +++ b/host/lib/usrp/single_usrp.cpp @@ -0,0 +1,309 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ + double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); + return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} + +/*********************************************************************** + * Simple USRP Implementation + **********************************************************************/ +class single_usrp_impl : public single_usrp{ +public: + single_usrp_impl(const device_addr_t &addr){ + _dev = device::make(addr); + } + + ~single_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_pp_string(void){ + std::string buff = str(boost::format( + "Single USRP:\n" + " Device: %s\n" + " Mboard: %s\n" + ) + % (*_dev)[DEVICE_PROP_NAME].as() + % _mboard()[MBOARD_PROP_NAME].as() + ); + + //----------- rx side of life ---------------------------------- + buff += str(boost::format( + " RX DSP: %s\n" + ) + % _rx_dsp()[DSP_PROP_NAME].as() + ); + for (size_t chan = 0; chan < this->get_rx_subdev_spec().size(); chan++){ + buff += str(boost::format( + " RX Channel: %u\n" + " RX Dboard: %s\n" + " RX Subdev: %s\n" + ) % chan + % _rx_dboard(chan)[DBOARD_PROP_NAME].as() + % _rx_subdev(chan)[SUBDEV_PROP_NAME].as() + ); + } + + //----------- tx side of life ---------------------------------- + buff += str(boost::format( + " TX DSP: %s\n" + ) + % _tx_dsp()[DSP_PROP_NAME].as() + ); + for (size_t chan = 0; chan < this->get_tx_subdev_spec().size(); chan++){ + buff += str(boost::format( + " TX Channel: %u\n" + " TX Dboard: %s\n" + " TX Subdev: %s\n" + ) % chan + % _tx_dboard(chan)[DBOARD_PROP_NAME].as() + % _tx_subdev(chan)[SUBDEV_PROP_NAME].as() + ); + } + + return buff; + } + + /******************************************************************* + * Misc + ******************************************************************/ + time_spec_t get_time_now(void){ + return _mboard()[MBOARD_PROP_TIME_NOW].as(); + } + + void set_time_now(const time_spec_t &time_spec){ + _mboard()[MBOARD_PROP_TIME_NOW] = time_spec; + } + + void set_time_next_pps(const time_spec_t &time_spec){ + _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd; + } + + void set_clock_config(const clock_config_t &clock_config){ + _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_subdev_spec(const subdev_spec_t &spec){ + _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; + std::cout << "RX " << this->get_rx_subdev_spec().to_pp_string() << std::endl; + } + + subdev_spec_t get_rx_subdev_spec(void){ + return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as(); + } + + void set_rx_rate(double rate){ + _rx_dsp()[DSP_PROP_HOST_RATE] = rate; + } + + double get_rx_rate(void){ + return _rx_dsp()[DSP_PROP_HOST_RATE].as(); + } + + tune_result_t set_rx_freq(double target_freq, size_t chan){ + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(/*TODO*/), target_freq); + } + + tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(/*TODO*/), target_freq, lo_off); + } + + double get_rx_freq(size_t chan){ + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(/*TODO*/)); + } + + freq_range_t get_rx_freq_range(size_t chan){ + return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp()); + } + + void set_rx_gain(float gain, size_t chan){ + return _rx_gain_group(chan)->set_value(gain); + } + + float get_rx_gain(size_t chan){ + return _rx_gain_group(chan)->get_value(); + } + + gain_range_t get_rx_gain_range(size_t chan){ + return _rx_gain_group(chan)->get_range(); + } + + void set_rx_antenna(const std::string &ant, size_t chan){ + _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_rx_antennas(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_rx_lo_locked(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + float read_rssi(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); + } + + dboard_iface::sptr get_rx_dboard_iface(size_t chan){ + return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_subdev_spec(const subdev_spec_t &spec){ + _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; + std::cout << "TX " << this->get_tx_subdev_spec().to_pp_string() << std::endl; + } + + subdev_spec_t get_tx_subdev_spec(void){ + return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as(); + } + + void set_tx_rate(double rate){ + _tx_dsp()[DSP_PROP_HOST_RATE] = rate; + } + + double get_tx_rate(void){ + return _tx_dsp()[DSP_PROP_HOST_RATE].as(); + } + + tune_result_t set_tx_freq(double target_freq, size_t chan){ + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(/*TODO*/), target_freq); + } + + tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(/*TODO*/), target_freq, lo_off); + } + + double get_tx_freq(size_t chan){ + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(/*TODO*/)); + } + + freq_range_t get_tx_freq_range(size_t chan){ + return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp()); + } + + void set_tx_gain(float gain, size_t chan){ + return _tx_gain_group(chan)->set_value(gain); + } + + float get_tx_gain(size_t chan){ + return _tx_gain_group(chan)->get_value(); + } + + gain_range_t get_tx_gain_range(size_t chan){ + return _tx_gain_group(chan)->get_range(); + } + + void set_tx_antenna(const std::string &ant, size_t chan){ + _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_tx_antennas(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_tx_lo_locked(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + dboard_iface::sptr get_tx_dboard_iface(size_t chan){ + return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); + } + +private: + device::sptr _dev; + wax::obj _mboard(void){ + return (*_dev)[DEVICE_PROP_MBOARD]; + } + wax::obj _rx_dsp(void){ + return _mboard()[MBOARD_PROP_RX_DSP]; + } + wax::obj _tx_dsp(void){ + return _mboard()[MBOARD_PROP_TX_DSP]; + } + wax::obj _rx_dboard(size_t chan){ + std::string db_name = this->get_rx_subdev_spec().at(chan).db_name; + return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + } + wax::obj _tx_dboard(size_t chan){ + std::string db_name = this->get_tx_subdev_spec().at(chan).db_name; + return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + } + wax::obj _rx_subdev(size_t chan){ + std::string sd_name = this->get_rx_subdev_spec().at(chan).sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + wax::obj _tx_subdev(size_t chan){ + std::string sd_name = this->get_tx_subdev_spec().at(chan).sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + gain_group::sptr _rx_gain_group(size_t chan){ + std::string sd_name = this->get_rx_subdev_spec().at(chan).sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); + } + gain_group::sptr _tx_gain_group(size_t chan){ + std::string sd_name = this->get_tx_subdev_spec().at(chan).sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); + } +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +single_usrp::sptr single_usrp::make(const device_addr_t &dev_addr){ + return sptr(new single_usrp_impl(dev_addr)); +} diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index d5a88fa2d..ba05fa6ed 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -46,7 +46,10 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) { switch(key.as()){ case DSP_PROP_NAME: - val = std::string("usrp1 ddc0"); + val = str(boost::format("usrp1 ddc %uX %s") + % this->get_num_ddcs() + % (this->has_rx_halfband()? "+ hb" : "") + ); return; case DSP_PROP_OTHERS: @@ -137,7 +140,10 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) { switch(key.as()) { case DSP_PROP_NAME: - val = std::string("usrp1 duc0"); + val = str(boost::format("usrp1 duc %uX %s") + % this->get_num_ducs() + % (this->has_tx_halfband()? "+ hb" : "") + ); return; case DSP_PROP_OTHERS: diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index a90532cb8..464a82494 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -172,23 +172,23 @@ static boost::uint32_t calc_tx_mux( * | Reserved |T|DUCs |R|DDCs | * +-----------------------------------------------+-+-----+-+-----+ */ -static int num_ddcs(boost::uint32_t regval) -{ +size_t usrp1_impl::get_num_ddcs(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); return (regval >> 0) & 0x0007; } -static int num_ducs(boost::uint32_t regval) -{ +size_t usrp1_impl::get_num_ducs(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); return (regval >> 4) & 0x0007; } -static bool has_rx_halfband(boost::uint32_t regval) -{ +bool usrp1_impl::has_rx_halfband(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); return (regval >> 3) & 0x0001; } -static bool has_tx_halfband(boost::uint32_t regval) -{ +bool usrp1_impl::has_tx_halfband(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); return (regval >> 7) & 0x0001; } @@ -224,22 +224,23 @@ void usrp1_impl::mboard_init(void) // // Do something useful with the capabilities register // - boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); std::cout << "USRP1 Capabilities" << std::endl; - std::cout << " number of duc's: " << num_ddcs(regval) << std::endl; - std::cout << " number of ddc's: " << num_ducs(regval) << std::endl; - std::cout << " rx halfband: " << has_rx_halfband(regval) << std::endl; - std::cout << " tx halfband: " << has_tx_halfband(regval) << std::endl; + std::cout << " number of duc's: " << get_num_ddcs() << std::endl; + std::cout << " number of ddc's: " << get_num_ducs() << std::endl; + std::cout << " rx halfband: " << has_rx_halfband() << std::endl; + std::cout << " tx halfband: " << has_tx_halfband() << std::endl; } void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) { - if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) { - _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0); - } + switch(stream_cmd.stream_mode){ + case stream_cmd_t::STREAM_MODE_START_CONTINUOUS: + return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0); + + case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS: + return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0); - if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { - _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0); + default: throw std::runtime_error("unsupported stream command type for USRP1"); } } @@ -269,7 +270,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) //handle the get request conditioned on the key switch(key.as()){ case MBOARD_PROP_NAME: - val = std::string("usrp1 mboard"); + val = std::string("usrp1 mboard - " + (*_mboard_proxy)[std::string("serial")].as()); return; case MBOARD_PROP_OTHERS: diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index c2f693eeb..663fbb34b 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -192,6 +192,12 @@ private: //transports uhd::transport::usb_zero_copy::sptr _data_transport; usrp_ctrl::sptr _ctrl_transport; + + //capabilities + size_t get_num_ducs(void); + size_t get_num_ddcs(void); + bool has_rx_halfband(void); + bool has_tx_halfband(void); }; #endif /* INCLUDED_USRP1_IMPL_HPP */ -- cgit v1.2.3 From d68922ed306cd73eb761165369619cdbac2ca637 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 20 Sep 2010 18:17:52 -0700 Subject: usrp1: implemented multi-channel dsp control of shift freq usrp: simple usrp calls into single usrp and prints deprecation warning usrp: tune helper now supports multi-channel dsps --- host/include/uhd/usrp/dsp_props.hpp | 11 +-- host/include/uhd/usrp/simple_usrp.hpp | 3 +- host/include/uhd/usrp/tune_helper.hpp | 18 ++-- host/lib/usrp/mimo_usrp.cpp | 12 +-- host/lib/usrp/simple_usrp.cpp | 163 +++++++++++----------------------- host/lib/usrp/single_usrp.cpp | 14 ++- host/lib/usrp/tune_helper.cpp | 38 ++++---- host/lib/usrp/usrp1/dsp_impl.cpp | 77 ++++++++++------ host/lib/usrp/usrp1/mboard_impl.cpp | 34 ++++--- host/lib/usrp/usrp1/usrp1_impl.hpp | 6 +- host/test/tune_helper_test.cpp | 22 +++-- 11 files changed, 191 insertions(+), 207 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp index 75d8c0a60..54ea5666b 100644 --- a/host/include/uhd/usrp/dsp_props.hpp +++ b/host/include/uhd/usrp/dsp_props.hpp @@ -37,11 +37,12 @@ namespace uhd{ namespace usrp{ * Set the shift property and read it back to get actual shift. */ enum dsp_prop_t{ - DSP_PROP_NAME = 'n', //ro, std::string - DSP_PROP_OTHERS = 'o', //ro, prop_names_t - DSP_PROP_FREQ_SHIFT = 'f', //rw, double Hz - DSP_PROP_CODEC_RATE = 'c', //ro, double Sps - DSP_PROP_HOST_RATE = 'h' //rw, double Sps + DSP_PROP_NAME = 'n', //ro, std::string + DSP_PROP_OTHERS = 'o', //ro, prop_names_t + DSP_PROP_FREQ_SHIFT = 'f', //rw, double Hz + DSP_PROP_FREQ_SHIFT_NAMES = 'F', //ro, prop_names_t + DSP_PROP_CODEC_RATE = 'c', //ro, double Sps + DSP_PROP_HOST_RATE = 'h' //rw, double Sps }; }} //namespace diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 169411f19..6149f739c 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -33,7 +33,8 @@ namespace uhd{ namespace usrp{ /*! - * The simple USRP device class: + * The simple USRP device class (DEPRECATED): + * This interface has been deprecated in favor of the single USRP interface. * A simple usrp facilitates ease-of-use for most use-case scenarios. * The wrapper provides convenience functions to tune the devices * as well as to set the dboard gains, antennas, and other properties. diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp index df3907b3e..ec133fa08 100644 --- a/host/include/uhd/usrp/tune_helper.hpp +++ b/host/include/uhd/usrp/tune_helper.hpp @@ -31,12 +31,13 @@ namespace uhd{ namespace usrp{ * The ddc cordic is setup to bring the IF down to baseband. * \param subdev the dboard subdevice object with properties * \param ddc the mboard dsp object with properties + * \param chan the channel of the dsp to tune * \param target_freq the desired center frequency * \param lo_offset an offset for the subdevice IF from center * \return a tune result struct */ UHD_API tune_result_t tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, + wax::obj subdev, wax::obj ddc, size_t chan, double target_freq, double lo_offset ); @@ -46,17 +47,19 @@ namespace uhd{ namespace usrp{ * is calculated based on the subdevice and BW. */ UHD_API tune_result_t tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, double target_freq + wax::obj subdev, wax::obj ddc, + size_t chan, double target_freq ); /*! * Calculate the overall frequency from the combination of dboard IF and DDC shift. * \param subdev the dboard subdevice object with properties * \param ddc the mboard dsp object with properties + * \param chan the channel of the dsp to tune * \return the overall tune frequency of the system in Hz */ UHD_API double derive_freq_from_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc + wax::obj subdev, wax::obj ddc, size_t chan ); /*! @@ -66,12 +69,13 @@ namespace uhd{ namespace usrp{ * The duc cordic is setup to bring the baseband up to IF. * \param subdev the dboard subdevice object with properties * \param duc the mboard dsp object with properties + * \param chan the channel of the dsp to tune * \param target_freq the desired center frequency * \param lo_offset an offset for the subdevice IF from center * \return a tune result struct */ UHD_API tune_result_t tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, + wax::obj subdev, wax::obj duc, size_t chan, double target_freq, double lo_offset ); @@ -81,17 +85,19 @@ namespace uhd{ namespace usrp{ * is calculated based on the subdevice and BW. */ UHD_API tune_result_t tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, double target_freq + wax::obj subdev, wax::obj duc, + size_t chan, double target_freq ); /*! * Calculate the overall frequency from the combination of dboard IF and DUC shift. * \param subdev the dboard subdevice object with properties * \param duc the mboard dsp object with properties + * \param chan the channel of the dsp to tune * \return the overall tune frequency of the system in Hz */ UHD_API double derive_freq_from_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc + wax::obj subdev, wax::obj duc, size_t chan ); }} diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index e78d38fc0..9331c7fbb 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -179,15 +179,15 @@ public: } tune_result_t set_rx_freq(size_t chan, double target_freq){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq); + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq); } tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq, lo_off); + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off); } double get_rx_freq(size_t chan){ - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan)); + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0); } freq_range_t get_rx_freq_range(size_t chan){ @@ -255,15 +255,15 @@ public: } tune_result_t set_tx_freq(size_t chan, double target_freq){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq); + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq); } tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq, lo_off); + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off); } double get_tx_freq(size_t chan){ - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan)); + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0); } freq_range_t get_tx_freq_range(size_t chan){ diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index e573d0fc0..d29952955 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -15,35 +15,20 @@ // along with this program. If not, see . // +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include using namespace uhd; using namespace uhd::usrp; -static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ - double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); - return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); -} - /*********************************************************************** * Simple USRP Implementation **********************************************************************/ class simple_usrp_impl : public simple_usrp{ public: simple_usrp_impl(const device_addr_t &addr){ - _dev = device::make(addr); + _sdev = single_usrp::make(addr); } ~simple_usrp_impl(void){ @@ -51,235 +36,187 @@ public: } device::sptr get_device(void){ - return _dev; + return _sdev->get_device(); } std::string get_pp_string(void){ - return str(boost::format( - "Simple USRP:\n" - " Device: %s\n" - " Mboard: %s\n" - " RX DSP: %s\n" - " RX Dboard: %s\n" - " RX Subdev: %s\n" - " TX DSP: %s\n" - " TX Dboard: %s\n" - " TX Subdev: %s\n" - ) - % (*_dev)[DEVICE_PROP_NAME].as() - % _mboard()[MBOARD_PROP_NAME].as() - % _rx_dsp()[DSP_PROP_NAME].as() - % _rx_dboard()[DBOARD_PROP_NAME].as() - % _rx_subdev()[SUBDEV_PROP_NAME].as() - % _tx_dsp()[DSP_PROP_NAME].as() - % _tx_dboard()[DBOARD_PROP_NAME].as() - % _tx_subdev()[SUBDEV_PROP_NAME].as() - ); + return _sdev->get_pp_string(); } /******************************************************************* * Misc ******************************************************************/ time_spec_t get_time_now(void){ - return _mboard()[MBOARD_PROP_TIME_NOW].as(); + return _sdev->get_time_now(); } void set_time_now(const time_spec_t &time_spec){ - _mboard()[MBOARD_PROP_TIME_NOW] = time_spec; + return _sdev->set_time_now(time_spec); } void set_time_next_pps(const time_spec_t &time_spec){ - _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + return _sdev->set_time_next_pps(time_spec); } void issue_stream_cmd(const stream_cmd_t &stream_cmd){ - _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd; + return _sdev->issue_stream_cmd(stream_cmd); } void set_clock_config(const clock_config_t &clock_config){ - _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + return _sdev->set_clock_config(clock_config); } /******************************************************************* * RX methods ******************************************************************/ void set_rx_subdev_spec(const subdev_spec_t &spec){ - _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; - std::cout << "RX " << _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as().to_pp_string() << std::endl; + return _sdev->set_rx_subdev_spec(spec); } subdev_spec_t get_rx_subdev_spec(void){ - return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as(); + return _sdev->get_rx_subdev_spec(); } void set_rx_rate(double rate){ - _rx_dsp()[DSP_PROP_HOST_RATE] = rate; + return _sdev->set_rx_rate(rate); } double get_rx_rate(void){ - return _rx_dsp()[DSP_PROP_HOST_RATE].as(); + return _sdev->get_rx_rate(); } tune_result_t set_rx_freq(double target_freq){ - return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq); + return _sdev->set_rx_freq(target_freq); } tune_result_t set_rx_freq(double target_freq, double lo_off){ - return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq, lo_off); + return _sdev->set_rx_freq(target_freq, lo_off); } double get_rx_freq(void){ - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp()); + return _sdev->get_rx_freq(); } freq_range_t get_rx_freq_range(void){ - return add_dsp_shift(_rx_subdev()[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp()); + return _sdev->get_rx_freq_range(); } void set_rx_gain(float gain){ - return _rx_gain_group()->set_value(gain); + return _sdev->set_rx_gain(gain); } float get_rx_gain(void){ - return _rx_gain_group()->get_value(); + return _sdev->get_rx_gain(); } gain_range_t get_rx_gain_range(void){ - return _rx_gain_group()->get_range(); + return _sdev->get_rx_gain_range(); } void set_rx_antenna(const std::string &ant){ - _rx_subdev()[SUBDEV_PROP_ANTENNA] = ant; + return _sdev->set_rx_antenna(ant); } std::string get_rx_antenna(void){ - return _rx_subdev()[SUBDEV_PROP_ANTENNA].as(); + return _sdev->get_rx_antenna(); } std::vector get_rx_antennas(void){ - return _rx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as(); + return _sdev->get_rx_antennas(); } bool get_rx_lo_locked(void){ - return _rx_subdev()[SUBDEV_PROP_LO_LOCKED].as(); + return _sdev->get_rx_lo_locked(); } float read_rssi(void){ - return _rx_subdev()[SUBDEV_PROP_RSSI].as(); + return _sdev->read_rssi(); } dboard_iface::sptr get_rx_dboard_iface(void){ - return _rx_dboard()[DBOARD_PROP_DBOARD_IFACE].as(); + return _sdev->get_rx_dboard_iface(); } /******************************************************************* * TX methods ******************************************************************/ void set_tx_subdev_spec(const subdev_spec_t &spec){ - _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; - std::cout << "TX " << _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as().to_pp_string() << std::endl; + return _sdev->set_tx_subdev_spec(spec); } subdev_spec_t get_tx_subdev_spec(void){ - return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as(); + return _sdev->get_tx_subdev_spec(); } void set_tx_rate(double rate){ - _tx_dsp()[DSP_PROP_HOST_RATE] = rate; + return _sdev->set_tx_rate(rate); } double get_tx_rate(void){ - return _tx_dsp()[DSP_PROP_HOST_RATE].as(); + return _sdev->get_tx_rate(); } tune_result_t set_tx_freq(double target_freq){ - return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq); + return _sdev->set_tx_freq(target_freq); } tune_result_t set_tx_freq(double target_freq, double lo_off){ - return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq, lo_off); + return _sdev->set_tx_freq(target_freq, lo_off); } double get_tx_freq(void){ - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp()); + return _sdev->get_tx_freq(); } freq_range_t get_tx_freq_range(void){ - return add_dsp_shift(_tx_subdev()[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp()); + return _sdev->get_tx_freq_range(); } void set_tx_gain(float gain){ - return _tx_gain_group()->set_value(gain); + return _sdev->set_tx_gain(gain); } float get_tx_gain(void){ - return _tx_gain_group()->get_value(); + return _sdev->get_tx_gain(); } gain_range_t get_tx_gain_range(void){ - return _tx_gain_group()->get_range(); + return _sdev->get_tx_gain_range(); } void set_tx_antenna(const std::string &ant){ - _tx_subdev()[SUBDEV_PROP_ANTENNA] = ant; + return _sdev->set_tx_antenna(ant); } std::string get_tx_antenna(void){ - return _tx_subdev()[SUBDEV_PROP_ANTENNA].as(); + return _sdev->get_tx_antenna(); } std::vector get_tx_antennas(void){ - return _tx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as(); + return _sdev->get_tx_antennas(); } bool get_tx_lo_locked(void){ - return _tx_subdev()[SUBDEV_PROP_LO_LOCKED].as(); + return _sdev->get_tx_lo_locked(); } dboard_iface::sptr get_tx_dboard_iface(void){ - return _tx_dboard()[DBOARD_PROP_DBOARD_IFACE].as(); + return _sdev->get_tx_dboard_iface(); } private: - device::sptr _dev; - wax::obj _mboard(void){ - return (*_dev)[DEVICE_PROP_MBOARD]; - } - wax::obj _rx_dsp(void){ - return _mboard()[MBOARD_PROP_RX_DSP]; - } - wax::obj _tx_dsp(void){ - return _mboard()[MBOARD_PROP_TX_DSP]; - } - wax::obj _rx_dboard(void){ - std::string db_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().db_name; - return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; - } - wax::obj _tx_dboard(void){ - std::string db_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().db_name; - return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; - } - wax::obj _rx_subdev(void){ - std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().sd_name; - return _rx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; - } - wax::obj _tx_subdev(void){ - std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().sd_name; - return _tx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; - } - gain_group::sptr _rx_gain_group(void){ - std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().sd_name; - return _rx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); - } - gain_group::sptr _tx_gain_group(void){ - std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().sd_name; - return _tx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); - } + single_usrp::sptr _sdev; }; /*********************************************************************** * The Make Function **********************************************************************/ simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ + uhd::print_warning( + "The simple USRP interface has been deprecated.\n" + "Please switch to the single USRP interface.\n" + "#include \n" + "simple_usrp::sptr sdev = simple_usrp::make(args);\n" + ); return sptr(new simple_usrp_impl(dev_addr)); } diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index 77e705c71..bb4af44b8 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -129,7 +129,6 @@ public: ******************************************************************/ void set_rx_subdev_spec(const subdev_spec_t &spec){ _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; - std::cout << "RX " << this->get_rx_subdev_spec().to_pp_string() << std::endl; } subdev_spec_t get_rx_subdev_spec(void){ @@ -145,15 +144,15 @@ public: } tune_result_t set_rx_freq(double target_freq, size_t chan){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(/*TODO*/), target_freq); + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq); } tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(/*TODO*/), target_freq, lo_off); + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off); } double get_rx_freq(size_t chan){ - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(/*TODO*/)); + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan); } freq_range_t get_rx_freq_range(size_t chan){ @@ -201,7 +200,6 @@ public: ******************************************************************/ void set_tx_subdev_spec(const subdev_spec_t &spec){ _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; - std::cout << "TX " << this->get_tx_subdev_spec().to_pp_string() << std::endl; } subdev_spec_t get_tx_subdev_spec(void){ @@ -217,15 +215,15 @@ public: } tune_result_t set_tx_freq(double target_freq, size_t chan){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(/*TODO*/), target_freq); + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq); } tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(/*TODO*/), target_freq, lo_off); + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off); } double get_tx_freq(size_t chan){ - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(/*TODO*/)); + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan); } freq_range_t get_tx_freq_range(size_t chan){ diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp index e516477d3..7633c67f2 100644 --- a/host/lib/usrp/tune_helper.cpp +++ b/host/lib/usrp/tune_helper.cpp @@ -30,11 +30,12 @@ using namespace uhd::usrp; **********************************************************************/ static tune_result_t tune_xx_subdev_and_dxc( dboard_iface::unit_t unit, - wax::obj subdev, wax::obj dxc, + wax::obj subdev, wax::obj dxc, size_t chan, double target_freq, double lo_offset ){ wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; - wax::obj dxc_freq_proxy = dxc[DSP_PROP_FREQ_SHIFT]; + std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as().at(chan); + wax::obj dxc_freq_proxy = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)]; double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as(); // Ask the d'board to tune as closely as it can to target_freq+lo_offset @@ -65,11 +66,12 @@ static tune_result_t tune_xx_subdev_and_dxc( static double derive_freq_from_xx_subdev_and_dxc( dboard_iface::unit_t unit, - wax::obj subdev, wax::obj dxc + wax::obj subdev, wax::obj dxc, size_t chan ){ //extract actual dsp and IF frequencies double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as(); - double actual_dxc_freq = dxc[DSP_PROP_FREQ_SHIFT].as(); + std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as().at(chan); + double actual_dxc_freq = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as(); //invert the sign on the dxc freq given the following conditions if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0; @@ -81,50 +83,54 @@ static double derive_freq_from_xx_subdev_and_dxc( * RX Tune **********************************************************************/ tune_result_t usrp::tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, + wax::obj subdev, wax::obj ddc, size_t chan, double target_freq, double lo_offset ){ - return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, target_freq, lo_offset); + return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan, target_freq, lo_offset); } tune_result_t usrp::tune_rx_subdev_and_dsp( wax::obj subdev, wax::obj ddc, - double target_freq + size_t chan, double target_freq ){ double lo_offset = 0.0; //if the local oscillator will be in the passband, use an offset if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as()){ lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as(); } - return tune_rx_subdev_and_dsp(subdev, ddc, target_freq, lo_offset); + return tune_rx_subdev_and_dsp(subdev, ddc, chan, target_freq, lo_offset); } -double usrp::derive_freq_from_rx_subdev_and_dsp(wax::obj subdev, wax::obj ddc){ - return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc); +double usrp::derive_freq_from_rx_subdev_and_dsp( + wax::obj subdev, wax::obj ddc, size_t chan +){ + return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan); } /*********************************************************************** * TX Tune **********************************************************************/ tune_result_t usrp::tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, + wax::obj subdev, wax::obj duc, size_t chan, double target_freq, double lo_offset ){ - return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, target_freq, lo_offset); + return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan, target_freq, lo_offset); } tune_result_t usrp::tune_tx_subdev_and_dsp( wax::obj subdev, wax::obj duc, - double target_freq + size_t chan, double target_freq ){ double lo_offset = 0.0; //if the local oscillator will be in the passband, use an offset if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as()){ lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as(); } - return tune_tx_subdev_and_dsp(subdev, duc, target_freq, lo_offset); + return tune_tx_subdev_and_dsp(subdev, duc, chan, target_freq, lo_offset); } -double usrp::derive_freq_from_tx_subdev_and_dsp(wax::obj subdev, wax::obj duc){ - return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc); +double usrp::derive_freq_from_tx_subdev_and_dsp( + wax::obj subdev, wax::obj duc, size_t chan +){ + return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan); } diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index ba05fa6ed..573bce21f 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -42,8 +44,9 @@ void usrp1_impl::rx_dsp_init(void) /*********************************************************************** * RX DDC Get **********************************************************************/ -void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) -{ +void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_NAME: val = str(boost::format("usrp1 ddc %uX %s") @@ -57,7 +60,16 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_FREQ_SHIFT: - val = _rx_dsp_freq; + val = _rx_dsp_freqs[key.name]; + return; + + case DSP_PROP_FREQ_SHIFT_NAMES:{ + prop_names_t names; + for(size_t i = 0; i < this->get_num_ddcs(); i++){ + names.push_back(boost::lexical_cast(i)); + } + val = names; + } return; case DSP_PROP_CODEC_RATE: @@ -76,25 +88,22 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) /*********************************************************************** * RX DDC Set **********************************************************************/ -void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) -{ +void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update( new_freq, _clock_ctrl->get_master_clock_freq()); - //TODO TODO TODO TODO TODO TODO TODO TODO TODO - // - // Handle multiple receive channels / DDC's - // - //TODO TODO TODO TODO TODO TODO TODO TODO TODO - _iface->poke32(FR_RX_FREQ_0, reg_word); - _iface->poke32(FR_RX_FREQ_1, reg_word); - _iface->poke32(FR_RX_FREQ_2, reg_word); - _iface->poke32(FR_RX_FREQ_3, reg_word); - - _rx_dsp_freq = new_freq; + static const uhd::dict + freq_name_to_reg_val = boost::assign::map_list_of + ("0", FR_RX_FREQ_0) ("1", FR_RX_FREQ_1) + ("2", FR_RX_FREQ_2) ("3", FR_RX_FREQ_3) + ; + _iface->poke32(freq_name_to_reg_val[key.name], reg_word); + _rx_dsp_freqs[key.name] = new_freq; return; } case DSP_PROP_HOST_RATE: { @@ -136,8 +145,9 @@ void usrp1_impl::tx_dsp_init(void) /*********************************************************************** * TX DUC Get **********************************************************************/ -void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) -{ +void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()) { case DSP_PROP_NAME: val = str(boost::format("usrp1 duc %uX %s") @@ -151,7 +161,16 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_FREQ_SHIFT: - val = _tx_dsp_freq; + val = _tx_dsp_freqs[key.name]; + return; + + case DSP_PROP_FREQ_SHIFT_NAMES:{ + prop_names_t names; + for(size_t i = 0; i < this->get_num_ducs(); i++){ + names.push_back(boost::lexical_cast(i)); + } + val = names; + } return; case DSP_PROP_CODEC_RATE: @@ -170,20 +189,20 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) /*********************************************************************** * TX DUC Set **********************************************************************/ -void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) -{ +void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()) { - //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - // - // Set both codec frequencies until we have duality properties - // - //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); - _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); - _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); - _tx_dsp_freq = new_freq; + + //map the freq shift key to a subdev spec to a particular codec chip + std::string db_name = _tx_subdev_spec.at(boost::lexical_cast(key.name)).db_name; + if (db_name == "A") _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); + if (db_name == "B") _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); + + _tx_dsp_freqs[key.name] = new_freq; return; } diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 464a82494..e55c3685b 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -36,6 +36,8 @@ using namespace uhd; using namespace uhd::usrp; +static const bool usrp1_mboard_verbose = false; + /*********************************************************************** * Calculate the RX mux value: * The I and Q mux values are intentionally reversed to flip I and Q @@ -220,15 +222,13 @@ void usrp1_impl::mboard_init(void) // Set default for TX format to 16-bit I&Q _iface->poke32(FR_TX_FORMAT, 0x00000000); - // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - // - // Do something useful with the capabilities register - // - std::cout << "USRP1 Capabilities" << std::endl; - std::cout << " number of duc's: " << get_num_ddcs() << std::endl; - std::cout << " number of ddc's: " << get_num_ducs() << std::endl; - std::cout << " rx halfband: " << has_rx_halfband() << std::endl; - std::cout << " tx halfband: " << has_tx_halfband() << std::endl; + if (usrp1_mboard_verbose){ + std::cout << "USRP1 Capabilities" << std::endl; + std::cout << " number of duc's: " << get_num_ddcs() << std::endl; + std::cout << " number of ddc's: " << get_num_ducs() << std::endl; + std::cout << " rx halfband: " << has_rx_halfband() << std::endl; + std::cout << " tx halfband: " << has_tx_halfband() << std::endl; + } } void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) @@ -362,18 +362,26 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) case MBOARD_PROP_RX_SUBDEV_SPEC: _rx_subdev_spec = val.as(); + if (_rx_subdev_spec.size() > this->get_num_ddcs()){ + throw std::runtime_error(str(boost::format( + "USRP1 suports up to %u RX channels.\n" + "However, this RX subdev spec requires %u channels\n" + ) % this->get_num_ddcs() % _rx_subdev_spec.size())); + } verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2); //set the mux and set the number of rx channels _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link())); return; case MBOARD_PROP_TX_SUBDEV_SPEC: _tx_subdev_spec = val.as(); + if (_tx_subdev_spec.size() > this->get_num_ducs()){ + throw std::runtime_error(str(boost::format( + "USRP1 suports up to %u TX channels.\n" + "However, this TX subdev spec requires %u channels\n" + ) % this->get_num_ducs() % _tx_subdev_spec.size())); + } verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2); //set the mux and set the number of tx channels _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link())); return; diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 663fbb34b..f5e423654 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -179,14 +179,16 @@ private: void rx_dsp_init(void); void rx_dsp_get(const wax::obj &, wax::obj &); void rx_dsp_set(const wax::obj &, const wax::obj &); - double _rx_dsp_freq; size_t _rx_dsp_decim; + uhd::dict _rx_dsp_freqs; + size_t _rx_dsp_decim; wax_obj_proxy::sptr _rx_dsp_proxy; //tx dsp functions and settings void tx_dsp_init(void); void tx_dsp_get(const wax::obj &, wax::obj &); void tx_dsp_set(const wax::obj &, const wax::obj &); - double _tx_dsp_freq; size_t _tx_dsp_interp; + uhd::dict _tx_dsp_freqs; + size_t _tx_dsp_interp; wax_obj_proxy::sptr _tx_dsp_proxy; //transports diff --git a/host/test/tune_helper_test.cpp b/host/test/tune_helper_test.cpp index 570f47293..1ef4af330 100644 --- a/host/test/tune_helper_test.cpp +++ b/host/test/tune_helper_test.cpp @@ -99,7 +99,8 @@ public: /* NOP */ } private: - void get(const wax::obj &key, wax::obj &val){ + void get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); switch(key.as()){ case DSP_PROP_CODEC_RATE: val = _codec_rate; @@ -109,11 +110,16 @@ private: val = _freq_shift; return; + case DSP_PROP_FREQ_SHIFT_NAMES: + val = prop_names_t(1, ""); + return; + default: UHD_THROW_PROP_GET_ERROR(); } } - void set(const wax::obj &key, const wax::obj &val){ + void set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); switch(key.as()){ case DSP_PROP_FREQ_SHIFT: _freq_shift = val.as(); @@ -136,12 +142,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx){ dummy_dsp dsp(100e6); std::cout << "Testing tune helper RX automatic LO offset" << std::endl; - tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); + tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance); BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance); - double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); + double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0); BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); } @@ -150,12 +156,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_tx){ dummy_dsp dsp(100e6); std::cout << "Testing tune helper TX automatic LO offset" << std::endl; - tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); + tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance); BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance); - double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); + double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0); BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); } @@ -164,11 +170,11 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){ dummy_dsp dsp(100e6); std::cout << "Testing tune helper RX dummy basic board" << std::endl; - tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6); + tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 55e6); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 0.0, tolerance); BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance); - double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); + double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0); BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance); } -- cgit v1.2.3 From 887aab36a0618124c3f2dffa8df9e8d943dfb1ee Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 20 Sep 2010 18:22:40 -0700 Subject: usrp2: make usrp2 dsp multi-channel compatible --- host/lib/usrp/usrp2/dsp_impl.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 6422142ce..0c85e643f 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -56,7 +56,9 @@ void usrp2_mboard_impl::init_ddc_config(void){ /*********************************************************************** * DDC Properties **********************************************************************/ -void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 ddc0"); @@ -70,6 +72,10 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ val = _ddc_freq; return; + case DSP_PROP_FREQ_SHIFT_NAMES: + val = prop_names_t(1, ""); + return; + case DSP_PROP_CODEC_RATE: val = get_master_clock_freq(); return; @@ -82,7 +88,9 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ @@ -131,7 +139,9 @@ void usrp2_mboard_impl::init_duc_config(void){ /*********************************************************************** * DUC Properties **********************************************************************/ -void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 duc0"); @@ -145,6 +155,10 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ val = _duc_freq; return; + case DSP_PROP_FREQ_SHIFT_NAMES: + val = prop_names_t(1, ""); + return; + case DSP_PROP_CODEC_RATE: val = get_master_clock_freq(); return; @@ -157,7 +171,9 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ -- cgit v1.2.3 From ba658f4d2cac9fb0f9d22060da989c9078cc4d1e Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 21 Sep 2010 10:41:05 -0700 Subject: added db_tvrx, regmap gen_dtt75403_regs.py --- host/lib/ic_reg_maps/CMakeLists.txt | 5 + host/lib/ic_reg_maps/gen_dtt75403_regs.py | 85 ++++++++ host/lib/ic_reg_maps/gen_max2118_regs.py | 0 host/lib/usrp/dboard/db_tvrx.cpp | 316 ++++++++++++++++++++++++++++++ 4 files changed, 406 insertions(+) create mode 100755 host/lib/ic_reg_maps/gen_dtt75403_regs.py mode change 100644 => 100755 host/lib/ic_reg_maps/gen_max2118_regs.py create mode 100644 host/lib/usrp/dboard/db_tvrx.cpp (limited to 'host/lib/usrp') diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index f8e15c13d..b396db4ca 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -68,3 +68,8 @@ LIBUHD_PYTHON_GEN_SOURCE( ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9522_regs.py ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9522_regs.hpp ) + +LIBUHD_PYTHON_GEN_SOURCE( + ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_dtt75403_regs.py + ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/dtt75403_regs.py +) diff --git a/host/lib/ic_reg_maps/gen_dtt75403_regs.py b/host/lib/ic_reg_maps/gen_dtt75403_regs.py new file mode 100755 index 000000000..fe64bd92a --- /dev/null +++ b/host/lib/ic_reg_maps/gen_dtt75403_regs.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# +# Copyright 2010 Ettus Research LLC +# +# 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, see . +# + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## +######################################################################## +## Address byte +######################################################################## +adb 0[1:2] 0 +######################################################################## +## Divider byte 1 +######################################################################## +db1 1[0:6] 0x00 +######################################################################## +## Divider byte 2 +######################################################################## +db2 2[0:7] 0x00 +######################################################################## +## Control byte 1 +######################################################################## +atp 3[3:5] 0 112, 109, 106, 103, 100, 94, 94, disable +refdiv 3[0:2] 0 166.667khz, 142.857khz, 80khz, 62.5khz, 31.25khz, 50khz +######################################################################## +## Band switch byte +######################################################################## +cpsel 4[6:7] 0 +filterbw 4[4] 0 8mhz, 7mhz +bandsel 4[0:3] 0 +######################################################################## +## Control byte 2 +######################################################################## +atc 5[5] 0 low, high +stby 5[4] 0 standby, on +xto 5[0] 0 disable, enable +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ + boost::uint8_t reg = 0; + switch(addr){ + #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) + case $addr: + #for $reg in filter(lambda r: r.get_addr() == addr, $regs) + reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); + #end for + break; + #end for + } + return boost::uint8_t(reg); +} + +""" + +if __name__ == '__main__': + import common; common.generate( + name='dtt75403_regs', + regs_tmpl=REGS_TMPL, + body_tmpl=BODY_TMPL, + file=__file__, + ) diff --git a/host/lib/ic_reg_maps/gen_max2118_regs.py b/host/lib/ic_reg_maps/gen_max2118_regs.py old mode 100644 new mode 100755 diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp new file mode 100644 index 000000000..5582dbe33 --- /dev/null +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -0,0 +1,316 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +// No RX IO Pins Used + +// RX IO Functions + +//ADC/DAC functions: +//DAC 1: RF AGC +//DAC 2: IF AGC + +//min freq: 50e6 +//max freq: 860e6 +//gain range: [0:1dB:115dB] + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The tvrx constants + **********************************************************************/ +static const bool tvrx_debug = true; + +static const freq_range_t tvrx_freq_range(50e6, 860e6); + +static const prop_names_t tvrx_antennas = ""; //only got one + +static const uhd::dict tvrx_gain_ranges = map_list_of + ("RF", gain_range_t(0, 60, float(60.0/4096))) //both gains are analog and controlled by DAC + ("IF", gain_range_t(0, 35, float(35.0/4096))) //the old driver used 1dB for both; i don't think that's right? +; + +static const uhd::dict tvrx_freq_ranges = map_list_of + ("VHFLO", freq_range_t(50e6, 158e6)) //this isn't used outside this driver. just for us. + ("VHFHI", freq_range_t(158e6, 454e6)) + ("UHF" , freq_range_t(454e6, 860e6)) +; + +//we might need to spec the various bands for band selection. + +static const double tvrx_lo_freq = 36e6; //LO freq of TVRX module + +/*********************************************************************** + * The tvrx dboard class + **********************************************************************/ +class tvrx : public rx_dboard_base{ +public: + tvrx(ctor_args_t args); + ~tvrx(void); + + void rx_get(const wax::obj &key, wax::obj &val); + void rx_set(const wax::obj &key, const wax::obj &val); + +private: + uhd::dict _gains; + dtt75403_regs_t _dtt75403_regs; + boost::uint8_t _dtt75403_addr(void){ + return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call + }; + + void set_gain(float gain, const std::string &name); + + void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ + //why is this an inline anyway? bring this out + start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5)); + stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x5)); + + for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ + int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; + + //create buffer for register data (+1 for start address) + byte_vector_t regs_vector(num_bytes + 1); + + //first byte is the address of first register + regs_vector[0] = start_addr; + + //get the register data + for(int i=0; iget_iface()->write_i2c( + _max2118_addr(), regs_vector + ); + } + } + +}; + +/*********************************************************************** + * Register the tvrx dboard + **********************************************************************/ +static dboard_base::sptr make_tvrx(dboard_base::ctor_args_t args){ + return dboard_base::sptr(new tvrx(args)); +} + +UHD_STATIC_BLOCK(reg_tvrx_dboard){ + //register the factory function for the rx dbid + dboard_manager::register_dboard(0x0003, &make_tvrx, "tvrx"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ + //enable only the clocks we need + + //TODO: YOU GOT SOME CLOCK SETUP TO DO HERE, DOGGGG + + this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); + + //set the gpio directions and atr controls (identically) + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr + if (this->get_iface()->get_special_props().soft_clock_divider){ + this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x1); // GPIO0 is clock + } + else{ + this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs + } + + //send initial register settings + //HAAAAY GUYYYYYSSS + + //set default gains + BOOST_FOREACH(const std::string &name, tvrx_gain_ranges.keys()){ + set_gain(tvrx_gain_ranges[name].min, name); + } +} + +tvrx::~tvrx(void){ +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +/*! + * Convert a requested gain for the GC2 vga into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 5 bit the register value + */ + +//yo this should look the same as the below one for the IF, dogg +static int gain_to_gc2_vga_reg(float &gain){ + int reg = 0; + gain = std::clip(float(boost::math::iround(gain)), tvrx_gain_ranges["GC2"].min, tvrx_gain_ranges["GC2"].max); + + // Half dB steps from 0-5dB, 1dB steps from 5-24dB + if (gain < 5) { + reg = boost::math::iround(31.0 - gain/0.5); + gain = float(boost::math::iround(gain) * 0.5); + } else { + reg = boost::math::iround(22.0 - (gain - 4.0)); + gain = float(boost::math::iround(gain)); + } + + if (tvrx_debug) std::cerr << boost::format( + "tvrx GC2 Gain: %f dB, reg: %d" + ) % gain % reg << std::endl; + + return reg; +} + +/*! + * Convert a requested gain for the RF gain into the dac_volts value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return dac voltage value + */ + +//yo what about the 1.22 opamp gain of the USRP1 -- is this replicated on U2? +static float gain_to_rfgain_dac(float &gain){ + //clip the input + gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + + //voltage level constants + static const float max_volts = float(0), min_volts = float(3.3); + static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + + //calculate the voltage for the aux dac + float dac_volts = gain*slope + min_volts; + + if (tvrx_debug) std::cerr << boost::format( + "tvrx RFAGC Gain: %f dB, dac_volts: %f V" + ) % gain % dac_volts << std::endl; + + //the actual gain setting + gain = (dac_volts - min_volts)/slope; + + return dac_volts; +} + +void tvrx::set_gain(float gain, const std::string &name){ + assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); + if (name == "RF"){ +//should look the same as below + } + else if(name == "IF"){ + //write the new voltage to the aux dac CHECK THIS + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain)); + } + else UHD_THROW_INVALID_CODE_PATH(); + _gains[name] = gain; +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case SUBDEV_PROP_NAME: + val = get_rx_id().to_pp_string(); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + assert_has(_gains.keys(), key.name, "tvrx gain name"); + val = _gains[key.name]; + return; + + case SUBDEV_PROP_GAIN_RANGE: + assert_has(tvrx_gain_ranges.keys(), key.name, "tvrx gain name"); + val = tvrx_gain_ranges[key.name]; + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(tvrx_gain_ranges.keys()); + return; + + case SUBDEV_PROP_FREQ: + val = tvrx_lo_freq; + return; + + case SUBDEV_PROP_FREQ_RANGE: + val = tvrx_freq_range; + return; + + case SUBDEV_PROP_ANTENNA: + val = std::string(tvrx_antennas); + return; + + case SUBDEV_PROP_ANTENNA_NAMES: + val = tvrx_antennas; + return; + + case SUBDEV_PROP_CONNECTION: + val = SUBDEV_CONN_COMPLEX_IQ; + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = false; + return; + + case SUBDEV_PROP_LO_LOCKED: + val = true; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +//for smaaht kids to use to set advanced props +void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case SUBDEV_PROP_GAIN: + this->set_gain(val.as(), key.name); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} + -- cgit v1.2.3 From 000578892e9cf8f0117b55dc5d770faad36740d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 22 Sep 2010 17:36:18 -0700 Subject: usrp1: reworked the io_impl for usrp1 to use the vrt packet handler used dummy packers and unpackets that have a header size of zero created wrapper around the data transport to handle non-512 multiple sends honor the eob flag on send to flush the send buffer --- host/lib/usrp/simple_usrp.cpp | 2 +- host/lib/usrp/usrp1/io_impl.cpp | 476 ++++++++++++++++++------------------- host/lib/usrp/usrp1/usrp1_impl.hpp | 12 +- host/lib/usrp/usrp2/io_impl.cpp | 2 +- 4 files changed, 242 insertions(+), 250 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index d29952955..b89b76eed 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -216,7 +216,7 @@ simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ "The simple USRP interface has been deprecated.\n" "Please switch to the single USRP interface.\n" "#include \n" - "simple_usrp::sptr sdev = simple_usrp::make(args);\n" + "single_usrp::sptr sdev = single_usrp::make(args);\n" ); return sptr(new simple_usrp_impl(dev_addr)); } diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 92e8bc20a..7446c7f7c 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,294 +33,278 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -struct usrp1_send_state { - uhd::transport::managed_send_buffer::sptr send_buff; - size_t bytes_written; - size_t underrun_poll_samp_count; - - size_t bytes_free() +/*********************************************************************** + * Pseudo send buffer implementation + **********************************************************************/ +class pseudo_managed_send_buffer : public managed_send_buffer{ +public: + + pseudo_managed_send_buffer( + const boost::asio::mutable_buffer &buff, + const boost::function &commit + ): + _buff(buff), + _commit(commit) { - if (send_buff != NULL) - return send_buff->size() - bytes_written; - else - return 0; + /* NOP */ } -}; -struct usrp1_recv_state { - uhd::transport::managed_recv_buffer::sptr recv_buff; - size_t bytes_read; - size_t overrun_poll_samp_count; + ssize_t commit(size_t num_bytes){ + return _commit(num_bytes); + } - size_t bytes_avail() - { - if (recv_buff != NULL) - return recv_buff->size() - bytes_read; - else - return 0; +private: + const boost::asio::mutable_buffer &get(void) const{ + return _buff; } -}; -/*********************************************************************** - * IO Implementation Details - **********************************************************************/ -struct usrp1_impl::io_impl { - io_impl(); - ~io_impl(void); - - //state handling for buffer management - usrp1_recv_state recv_state; - usrp1_send_state send_state; - - //send transport management - bool get_send_buffer(zero_copy_if::sptr zc_if); - size_t copy_convert_send_samps(const void *buff, size_t num_samps, - size_t sample_offset, const io_type_t io_type, - otw_type_t otw_type); - bool conditional_buff_commit(bool force); - bool check_underrun(usrp_ctrl::sptr ctrl_if, - size_t poll_interval, bool force); - - //recv transport management - bool get_recv_buffer(zero_copy_if::sptr zc_if); - size_t copy_convert_recv_samps(void *buff, size_t num_samps, - size_t sample_offset, const io_type_t io_type, - otw_type_t otw_type); - bool check_overrun(usrp_ctrl::sptr ctrl_if, - size_t poll_interval, bool force); + const boost::asio::mutable_buffer _buff; + const boost::function _commit; }; -usrp1_impl::io_impl::io_impl() -{ - send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); - recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr(); -} - -usrp1_impl::io_impl::~io_impl(void) -{ - /* NOP */ -} - -void usrp1_impl::io_init(void) -{ - _rx_otw_type.width = 16; - _rx_otw_type.shift = 0; - _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _io_impl = UHD_PIMPL_MAKE(io_impl, ()); -} - /*********************************************************************** - * Data Send + * IO Implementation Details **********************************************************************/ -bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if) -{ - if (send_state.send_buff == NULL) { +struct usrp1_impl::io_impl{ + io_impl(zero_copy_if::sptr data_transport): + data_transport(data_transport), + underflow_poll_samp_count(0), + overflow_poll_samp_count(0), + send_buff(data_transport->get_send_buff()), + num_bytes_committed(0) + { + /* NOP */ + } - send_state.send_buff = zc_if->get_send_buff(); - if (send_state.send_buff == NULL) - return false; + ~io_impl(void){ + flush_send_buff(); + } - send_state.bytes_written = 0; + zero_copy_if::sptr data_transport; + + //state management for the vrt packet handler code + vrt_packet_handler::recv_state packet_handler_recv_state; + vrt_packet_handler::send_state packet_handler_send_state; + + //state management for overflow and underflow + size_t underflow_poll_samp_count; + size_t overflow_poll_samp_count; + + //wrapper around the actual send buffer interface + //all of this to ensure only full buffers are committed + managed_send_buffer::sptr send_buff; + size_t num_bytes_committed; + boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; + ssize_t phony_commit_pseudo_buff(size_t num_bytes); + ssize_t phony_commit_send_buff(size_t num_bytes); + ssize_t commit_send_buff(void); + void flush_send_buff(void); + bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &); + + //helpers to get at the send buffer + offset + inline void *get_send_mem_ptr(void){ + return send_buff->cast() + num_bytes_committed; + } + inline size_t get_send_mem_size(void){ + return send_buff->size() - num_bytes_committed; } +}; - return true; +/*! + * Accept a commit of num bytes to the pseudo buffer. + * Memcpy the entire contents of pseudo buffer into send buffers. + * + * Under most conditions: + * The first loop iteration will fill the remainder of the send buffer. + * The second loop iteration will empty the pseudo buffer remainder. + */ +ssize_t usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){ + size_t bytes_to_copy = num_bytes, bytes_copied = 0; + while(bytes_to_copy){ + size_t bytes_copied_here = std::min(bytes_to_copy, get_send_mem_size()); + std::memcpy(get_send_mem_ptr(), pseudo_buff + bytes_copied, bytes_copied_here); + ssize_t ret = phony_commit_send_buff(bytes_copied_here); + if (ret < 0) return ret; + bytes_to_copy -= ret; + bytes_copied += ret; + } + return bytes_copied; } -size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff, - size_t num_samps, - size_t sample_offset, - const io_type_t io_type, - otw_type_t otw_type) -{ - UHD_ASSERT_THROW(send_state.bytes_free() % otw_type.get_sample_size() == 0); - - size_t samps_free = send_state.bytes_free() / otw_type.get_sample_size(); - size_t copy_samps = std::min(num_samps - sample_offset, samps_free); - - const boost::uint8_t *io_mem = - reinterpret_cast(buff); - - boost::uint8_t *otw_mem = send_state.send_buff->cast(); - - convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size, - io_type, - otw_mem + send_state.bytes_written, - otw_type, - copy_samps); - - send_state.bytes_written += copy_samps * otw_type.get_sample_size(); - send_state.underrun_poll_samp_count += copy_samps; - - return copy_samps; +/*! + * Accept a commit of num bytes to the send buffer. + * Conditionally commit the send buffer if full. + */ +ssize_t usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){ + num_bytes_committed += num_bytes; + if (num_bytes_committed != send_buff->size()) return num_bytes; + ssize_t ret = commit_send_buff(); + return (ret < 0)? ret : num_bytes; } -bool usrp1_impl::io_impl::conditional_buff_commit(bool force) -{ - if (send_state.bytes_written % 512) - return false; - - if (force || send_state.bytes_free() == 0) { - send_state.send_buff->commit(send_state.bytes_written); - send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); - return true; - } - - return false; +/*! + * Flush the send buffer: + * Zero-pad the send buffer to the nearest 512 byte boundary and commit. + */ +void usrp1_impl::io_impl::flush_send_buff(void){ + size_t bytes_to_pad = (-1*num_bytes_committed)%512; + std::memset(get_send_mem_ptr(), 0, bytes_to_pad); + num_bytes_committed += bytes_to_pad; + commit_send_buff(); } -bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if, - size_t poll_interval, - bool force) -{ - unsigned char underrun = 0; - - bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval; - - if (force || ready_to_poll) { - int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, - 0, - GS_TX_UNDERRUN, - &underrun, sizeof(char)); - if (ret < 0) - std::cerr << "USRP: underrun check failed" << std::endl; - if (underrun) - std::cerr << "U" << std::flush; - - send_state.underrun_poll_samp_count = 0; - } - - return (bool) underrun; +/*! + * Perform an actual commit on the send buffer: + * Commit the contents of the send buffer and request a new buffer. + */ +ssize_t usrp1_impl::io_impl::commit_send_buff(void){ + ssize_t ret = send_buff->commit(num_bytes_committed); + send_buff = data_transport->get_send_buff(); + num_bytes_committed = 0; + return ret; } -size_t usrp1_impl::send(const std::vector &buffs, - size_t num_samps, - const tx_metadata_t &, - const io_type_t &io_type, - send_mode_t) -{ +bool usrp1_impl::io_impl::get_send_buffs( + vrt_packet_handler::managed_send_buffs_t &buffs +){ UHD_ASSERT_THROW(buffs.size() == 1); - size_t total_samps_sent = 0; - - while (total_samps_sent < num_samps) { - if (!_io_impl->get_send_buffer(_data_transport)) - return 0; - - total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0], - num_samps, - total_samps_sent, - io_type, - _tx_otw_type); - if (total_samps_sent == num_samps) - _io_impl->conditional_buff_commit(true); - else - _io_impl->conditional_buff_commit(false); - - _io_impl->check_underrun(_ctrl_transport, - _tx_samps_per_poll_interval, false); + //not enough bytes free -> use the pseudo buffer + if (get_send_mem_size() < BYTES_PER_PACKET){ + buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( + boost::asio::buffer(pseudo_buff), + boost::bind(&usrp1_impl::io_impl::phony_commit_pseudo_buff, this, _1) + )); + } + //otherwise use the send buffer offset by the bytes written + else{ + buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( + boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()), + boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1) + )); } - return total_samps_sent; + return buffs[0].get(); } /*********************************************************************** - * Data Recv + * Initialize internals within this file **********************************************************************/ -bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if) -{ - if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail() == 0)) { - - recv_state.recv_buff = zc_if->get_recv_buff(); - if (recv_state.recv_buff == NULL) - return false; +void usrp1_impl::io_init(void){ + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - recv_state.bytes_read = 0; - } + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - return true; + _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); } -size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff, - size_t num_samps, - size_t sample_offset, - const io_type_t io_type, - otw_type_t otw_type) -{ - UHD_ASSERT_THROW(recv_state.bytes_avail() % otw_type.get_sample_size() == 0); - - size_t samps_avail = recv_state.bytes_avail() / otw_type.get_sample_size(); - size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); - - const boost::uint8_t *otw_mem = - recv_state.recv_buff->cast(); - - boost::uint8_t *io_mem = reinterpret_cast(buff); - - convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read, - otw_type, - io_mem + sample_offset * io_type.size, - io_type, - copy_samps); - - recv_state.bytes_read += copy_samps * otw_type.get_sample_size(); - recv_state.overrun_poll_samp_count += copy_samps; - - return copy_samps; +/*********************************************************************** + * Data send + helper functions + **********************************************************************/ +static void usrp1_bs_vrt_packer( + boost::uint32_t *, + vrt::if_packet_info_t &if_packet_info +){ + if_packet_info.num_header_words32 = 0; + if_packet_info.num_packet_words32 = if_packet_info.num_payload_words32; } -bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if, - size_t poll_interval, - bool force) -{ - unsigned char overrun = 0; - - bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval; - - if (force || ready_to_poll) { - int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, - 0, - GS_RX_OVERRUN, - &overrun, sizeof(char)); - if (ret < 0) - std::cerr << "USRP: overrrun check failed" << std::endl; - if (overrun) - std::cerr << "O" << std::flush; - - recv_state.overrun_poll_samp_count = 0; +size_t usrp1_impl::send( + const std::vector &buffs, size_t num_samps, + const tx_metadata_t &metadata, const io_type_t &io_type, + send_mode_t send_mode +){ + size_t num_samps_sent = vrt_packet_handler::send( + _io_impl->packet_handler_send_state, //last state of the send handler + buffs, num_samps, //buffer to fill + metadata, send_mode, //samples metadata + io_type, _tx_otw_type, //input and output types to convert + _clock_ctrl->get_master_clock_freq(), //master clock tick rate + &usrp1_bs_vrt_packer, + boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1), + get_max_send_samps_per_packet() + ); + + //Don't honor sob because it is normal to be always bursting... + //handle eob flag (commit the buffer) + if (metadata.end_of_burst) _io_impl->flush_send_buff(); + + //handle the polling for underflow conditions + _io_impl->underflow_poll_samp_count += num_samps_sent; + if (_io_impl->underflow_poll_samp_count >= _tx_samps_per_poll_interval){ + _io_impl->underflow_poll_samp_count = 0; //reset count + boost::uint8_t underflow = 0; + ssize_t ret = _ctrl_transport->usrp_control_read( + VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, + &underflow, sizeof(underflow) + ); + if (ret < 0) std::cerr << "USRP: underflow check failed" << std::endl; + else if (underflow) std::cerr << "U" << std::flush; } - return (bool) overrun; + return num_samps_sent; } -size_t usrp1_impl::recv(const std::vector &buffs, - size_t num_samps, - rx_metadata_t &, - const io_type_t &io_type, - recv_mode_t, - size_t) -{ - UHD_ASSERT_THROW(buffs.size() == 1); - - size_t total_samps_recv = 0; - - while (total_samps_recv < num_samps) { +/*********************************************************************** + * Data recv + helper functions + **********************************************************************/ +static void usrp1_bs_vrt_unpacker( + const boost::uint32_t *, + vrt::if_packet_info_t &if_packet_info +){ + if_packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA; + if_packet_info.num_payload_words32 = if_packet_info.num_packet_words32; + if_packet_info.num_header_words32 = 0; + if_packet_info.packet_count = 0; + if_packet_info.sob = false; + if_packet_info.eob = false; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tsi = false; + if_packet_info.has_tsf = false; + if_packet_info.has_tlr = false; +} - if (!_io_impl->get_recv_buffer(_data_transport)) - return 0; +static bool get_recv_buffs( + zero_copy_if::sptr zc_if, + vrt_packet_handler::managed_recv_buffs_t &buffs +){ + UHD_ASSERT_THROW(buffs.size() == 1); + buffs[0] = zc_if->get_recv_buff(); + return buffs[0].get(); +} - total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0], - num_samps, - total_samps_recv, - io_type, - _rx_otw_type); - _io_impl->check_overrun(_ctrl_transport, - _rx_samps_per_poll_interval, false); +size_t usrp1_impl::recv( + const std::vector &buffs, size_t num_samps, + rx_metadata_t &metadata, const io_type_t &io_type, + recv_mode_t recv_mode, size_t /*timeout_ms TODO*/ +){ + size_t num_samps_recvd = vrt_packet_handler::recv( + _io_impl->packet_handler_recv_state, //last state of the recv handler + buffs, num_samps, //buffer to fill + metadata, recv_mode, //samples metadata + io_type, _rx_otw_type, //input and output types to convert + _clock_ctrl->get_master_clock_freq(), //master clock tick rate + &usrp1_bs_vrt_unpacker, + boost::bind(&get_recv_buffs, _data_transport, _1) + ); + + //handle the polling for overflow conditions + _io_impl->overflow_poll_samp_count += num_samps_recvd; + if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){ + _io_impl->overflow_poll_samp_count = 0; //reset count + boost::uint8_t overflow = 0; + ssize_t ret = _ctrl_transport->usrp_control_read( + VRQ_GET_STATUS, 0, GS_RX_OVERRUN, + &overflow, sizeof(overflow) + ); + if (ret < 0) std::cerr << "USRP: overflow check failed" << std::endl; + else if (overflow) std::cerr << "O" << std::flush; } - return total_samps_recv; + return num_samps_recvd; } diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f5e423654..3ea35f970 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -91,8 +91,16 @@ public: recv_mode_t, size_t timeout); - size_t get_max_send_samps_per_packet(void) const { return 0; } - size_t get_max_recv_samps_per_packet(void) const { return 0; } + static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size + + size_t get_max_send_samps_per_packet(void) const { + return BYTES_PER_PACKET/_tx_otw_type.get_sample_size(); + } + + size_t get_max_recv_samps_per_packet(void) const { + return BYTES_PER_PACKET/_rx_otw_type.get_sample_size(); + } + bool recv_async_msg(uhd::async_metadata_t &, size_t); private: diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 4e883cf81..91a1b2344 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -189,7 +189,7 @@ bool usrp2_impl::recv_async_msg( /*********************************************************************** * Send Data **********************************************************************/ -bool get_send_buffs( +static bool get_send_buffs( const std::vector &trans, vrt_packet_handler::managed_send_buffs_t &buffs ){ -- cgit v1.2.3 From 7ee585f2b9f74a3732e364095f7e5b8f18ae3595 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 22 Sep 2010 19:14:57 -0700 Subject: usrp1: multi-channel rx working, modified vrt handler to deinterleave --- host/lib/transport/gen_convert_types.py | 10 +++++----- host/lib/transport/vrt_packet_handler.hpp | 30 ++++++++++++++++++++---------- host/lib/usrp/usrp1/io_impl.cpp | 5 ++++- 3 files changed, 29 insertions(+), 16 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index adbd22868..f9509c81d 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -99,9 +99,9 @@ void transport::convert_io_type_to_otw_type( nsamps_per_io_buff ); #else - for (size_t i = 0; i < nsamps_per_io_buff; i++){ + for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){ #for $j in range($num_chans) - reinterpret_cast<$(out_type)_t *>(otw_buff)[i*$num_chans + $j] = + reinterpret_cast<$(out_type)_t *>(otw_buff)[j++] = #if $ph.get_swap_type($pred) == 'bswap' uhd::byteswap($(converter)(reinterpret_cast(io_buffs[$j])[i])); #else @@ -139,13 +139,13 @@ void transport::convert_otw_type_to_io_type( nsamps_per_io_buff ); #else - for (size_t i = 0; i < nsamps_per_io_buff; i++){ + for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){ #for $j in range($num_chans) reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] = #if $ph.get_swap_type($pred) == 'bswap' - $(converter)(uhd::byteswap(reinterpret_cast(otw_buff)[i*$num_chans + $j])); + $(converter)(uhd::byteswap(reinterpret_cast(otw_buff)[j++])); #else - $(converter)(reinterpret_cast(otw_buff)[i*$num_chans + $j]); + $(converter)(reinterpret_cast(otw_buff)[j++]); #end if #end for } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 7e0588f03..596989951 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -150,7 +150,8 @@ template UHD_INLINE T get_context_code( const vrt_unpacker_t &vrt_unpacker, const get_recv_buffs_t &get_recv_buffs, const handle_overflow_t &handle_overflow, - size_t vrt_header_offset_words32 + size_t vrt_header_offset_words32, + size_t chans_per_otw_buff ){ metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE; @@ -184,15 +185,21 @@ template UHD_INLINE T get_context_code( //extract the number of samples available to copy size_t bytes_per_item = otw_type.get_sample_size(); size_t nsamps_available = state.size_of_copy_buffs/bytes_per_item; - size_t nsamps_to_copy = std::min(total_samps, nsamps_available); + size_t nsamps_to_copy = std::min(total_samps*chans_per_otw_buff, nsamps_available); size_t bytes_to_copy = nsamps_to_copy*bytes_per_item; + size_t nsamps_to_copy_per_io_buff = nsamps_to_copy/chans_per_otw_buff; + + std::vector io_buffs(chans_per_otw_buff); + for (size_t i = 0; i < state.width; i+=chans_per_otw_buff){ + + //fill a vector with pointers to the io buffers + for (size_t j = 0; j < chans_per_otw_buff; j++){ + io_buffs[j] = reinterpret_cast(buffs[i+j]) + offset_bytes; + } - for (size_t i = 0; i < state.width; i++){ //copy-convert the samples from the recv buffer uhd::transport::convert_otw_type_to_io_type( - state.copy_buffs[i], otw_type, - reinterpret_cast(buffs[i]) + offset_bytes, - io_type, nsamps_to_copy + state.copy_buffs[i], otw_type, io_buffs, io_type, nsamps_to_copy_per_io_buff ); //update the rx copy buffer to reflect the bytes copied @@ -206,7 +213,7 @@ template UHD_INLINE T get_context_code( metadata.fragment_offset = state.fragment_offset_in_samps; state.fragment_offset_in_samps += nsamps_to_copy; //set for next call - return nsamps_to_copy; + return nsamps_to_copy_per_io_buff; } /******************************************************************* @@ -224,7 +231,8 @@ template UHD_INLINE T get_context_code( const vrt_unpacker_t &vrt_unpacker, const get_recv_buffs_t &get_recv_buffs, const handle_overflow_t &handle_overflow = &handle_overflow_nop, - size_t vrt_header_offset_words32 = 0 + size_t vrt_header_offset_words32 = 0, + size_t chans_per_otw_buff = 1 ){ switch(recv_mode){ @@ -241,7 +249,8 @@ template UHD_INLINE T get_context_code( vrt_unpacker, get_recv_buffs, handle_overflow, - vrt_header_offset_words32 + vrt_header_offset_words32, + chans_per_otw_buff ); } @@ -261,7 +270,8 @@ template UHD_INLINE T get_context_code( vrt_unpacker, get_recv_buffs, handle_overflow, - vrt_header_offset_words32 + vrt_header_offset_words32, + chans_per_otw_buff ); if (num_samps == 0) break; //had a recv timeout or error, break loop accum_num_samps += num_samps; diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 7446c7f7c..a813a0462 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -290,7 +290,10 @@ size_t usrp1_impl::recv( io_type, _rx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_unpacker, - boost::bind(&get_recv_buffs, _data_transport, _1) + boost::bind(&get_recv_buffs, _data_transport, _1), + &vrt_packet_handler::handle_overflow_nop, + 0, //vrt header offset + _rx_subdev_spec.size() //num channels ); //handle the polling for overflow conditions -- cgit v1.2.3 From c36b8a83b1b510a0a8bc6e5600a537cbedea8f30 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 23 Sep 2010 12:37:11 -0700 Subject: usrp1: multi-channel tx working, modified vrt handler to interleave --- host/lib/transport/vrt_packet_handler.hpp | 28 +++++++++++++++++----------- host/lib/usrp/usrp1/io_impl.cpp | 4 +++- host/lib/usrp/usrp1/usrp1_impl.hpp | 4 ++-- 3 files changed, 22 insertions(+), 14 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 596989951..b603f1371 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -313,29 +313,32 @@ template UHD_INLINE T get_context_code( const uhd::otw_type_t &otw_type, const vrt_packer_t &vrt_packer, const get_send_buffs_t &get_send_buffs, - size_t vrt_header_offset_words32 + size_t vrt_header_offset_words32, + size_t chans_per_otw_buff ){ //load the rest of the if_packet_info in here - if_packet_info.num_payload_words32 = (num_samps*otw_type.get_sample_size())/sizeof(boost::uint32_t); + if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t); if_packet_info.packet_count = state.next_packet_seq++; //get send buffers for each channel - managed_send_buffs_t send_buffs(buffs.size()); + managed_send_buffs_t send_buffs(buffs.size()/chans_per_otw_buff); UHD_ASSERT_THROW(get_send_buffs(send_buffs)); - for (size_t i = 0; i < buffs.size(); i++){ + std::vector io_buffs(chans_per_otw_buff); + for (size_t i = 0; i < buffs.size(); i+=chans_per_otw_buff){ //calculate pointers with offsets to io and otw memory - const boost::uint8_t *io_mem = reinterpret_cast(buffs[i]) + offset_bytes; + for (size_t j = 0; j < chans_per_otw_buff; j++){ + io_buffs[j] = reinterpret_cast(buffs[i+j]) + offset_bytes; + } boost::uint32_t *otw_mem = send_buffs[i]->cast() + vrt_header_offset_words32; //pack metadata into a vrt header vrt_packer(otw_mem, if_packet_info); + otw_mem += if_packet_info.num_header_words32; //copy-convert the samples into the send buffer uhd::transport::convert_io_type_to_otw_type( - io_mem, io_type, - otw_mem + if_packet_info.num_header_words32, otw_type, - num_samps + io_buffs, io_type, otw_mem, otw_type, num_samps ); //commit the samples to the zero-copy interface @@ -361,7 +364,8 @@ template UHD_INLINE T get_context_code( const vrt_packer_t &vrt_packer, const get_send_buffs_t &get_send_buffs, size_t max_samples_per_packet, - size_t vrt_header_offset_words32 = 0 + size_t vrt_header_offset_words32 = 0, + size_t chans_per_otw_buff = 1 ){ //translate the metadata to vrt if packet info uhd::transport::vrt::if_packet_info_t if_packet_info; @@ -393,7 +397,8 @@ template UHD_INLINE T get_context_code( io_type, otw_type, vrt_packer, get_send_buffs, - vrt_header_offset_words32 + vrt_header_offset_words32, + chans_per_otw_buff ); return num_samps; } @@ -424,7 +429,8 @@ template UHD_INLINE T get_context_code( io_type, otw_type, vrt_packer, get_send_buffs, - vrt_header_offset_words32 + vrt_header_offset_words32, + chans_per_otw_buff ); } return total_num_samps; diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index a813a0462..146038bd9 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -226,7 +226,9 @@ size_t usrp1_impl::send( _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_packer, boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1), - get_max_send_samps_per_packet() + get_max_send_samps_per_packet(), + 0, //vrt header offset + _tx_subdev_spec.size() //num channels ); //Don't honor sob because it is normal to be always bursting... diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 3ea35f970..20ae3c02a 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -94,11 +94,11 @@ public: static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size size_t get_max_send_samps_per_packet(void) const { - return BYTES_PER_PACKET/_tx_otw_type.get_sample_size(); + return BYTES_PER_PACKET/_tx_otw_type.get_sample_size()/_tx_subdev_spec.size(); } size_t get_max_recv_samps_per_packet(void) const { - return BYTES_PER_PACKET/_rx_otw_type.get_sample_size(); + return BYTES_PER_PACKET/_rx_otw_type.get_sample_size()/_rx_subdev_spec.size(); } bool recv_async_msg(uhd::async_metadata_t &, size_t); -- cgit v1.2.3 From fbcd677284685e666556f396745ec570b01ea830 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 23 Sep 2010 12:47:46 -0700 Subject: usrp1: sanity check, only 1 channel per tx slot --- host/lib/usrp/usrp1/mboard_impl.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index e55c3685b..fe3774eb4 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -148,6 +148,7 @@ static boost::uint32_t calc_tx_mux( //calculate the channel flags int channel_flags = 0, chan = 0; + uhd::dict slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0); BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)]; wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; @@ -157,6 +158,14 @@ static boost::uint32_t calc_tx_mux( if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0; if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8; + //sanity check, only 1 channel per slot + slot_to_chan_count[pair.db_name]++; + if (slot_to_chan_count[pair.db_name] > 1){ + throw std::runtime_error(str(boost::format( + "dboard slot %s assigned to multiple channels in subdev spec %s" + ) % pair.db_name % subdev_spec.to_string())); + } + //increment for the next channel chan++; } -- cgit v1.2.3 From 24bcc7d7644621bd18a998b23cd91b086b87ea90 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 23 Sep 2010 12:58:40 -0700 Subject: basic: added the 4th BA subdevice to basic and lf dboard code --- host/docs/dboards.rst | 10 ++++++---- host/lib/usrp/dboard/db_basic_and_lf.cpp | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 985fbc12b..738a0696d 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -15,11 +15,12 @@ properties of each board as well. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Basic RX and and LFRX ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Basic RX and LFRX boards have 3 subdevices: +The Basic RX and LFRX boards have 4 subdevices: * **Subdevice A:** real signal on antenna RXA * **Subdevice B:** real signal on antenna RXB -* **Subdevice AB:** quadrature subdevice using both antennas +* **Subdevice AB:** quadrature subdevice using both antennas (IQ) +* **Subdevice BA:** quadrature subdevice using both antennas (QI) The boards have no tunable elements or programmable gains. Though the magic of aliasing, you can down-convert signals @@ -28,11 +29,12 @@ greater than the Nyquist rate of the ADC. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Basic TX and and LFTX ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Basic TX and LFTX boards have 3 subdevices: +The Basic TX and LFTX boards have 4 subdevices: * **Subdevice A:** real signal on antenna TXA * **Subdevice B:** real signal on antenna TXB -* **Subdevice AB:** quadrature subdevice using both antennas +* **Subdevice AB:** quadrature subdevice using both antennas (IQ) +* **Subdevice BA:** quadrature subdevice using both antennas (QI) The boards have no tunable elements or programmable gains. Though the magic of aliasing, you can up-convert signals diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 2a9bf2ca5..4b0d8bf27 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -59,6 +59,7 @@ private: static const uhd::dict sd_name_to_conn = map_list_of ("AB", SUBDEV_CONN_COMPLEX_IQ) + ("BA", SUBDEV_CONN_COMPLEX_QI) ("A", SUBDEV_CONN_REAL_I) ("B", SUBDEV_CONN_REAL_Q) ; -- cgit v1.2.3 From f97c4338458a965502d73903983ae5a3ceeebd53 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 23 Sep 2010 18:07:31 -0700 Subject: usrp1: fixes to remove warnings and errors for usrp1 + libusb windows --- host/lib/transport/CMakeLists.txt | 3 +++ host/lib/transport/include/stdint.h | 35 ++++++++++++++++++++++++++++ host/lib/transport/libusb1_base.cpp | 2 +- host/lib/transport/libusb1_device_handle.cpp | 18 +++++++------- host/lib/transport/libusb1_zero_copy.cpp | 3 +-- host/lib/usrp/usrp1/codec_ctrl.cpp | 4 ++-- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 4 ++-- host/lib/usrp/usrp1/usrp1_iface.cpp | 4 ++-- host/lib/usrp/usrp1/usrp1_impl.cpp | 2 +- 9 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 host/lib/transport/include/stdint.h (limited to 'host/lib/usrp') diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index acd699fc5..92c9f3181 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -33,6 +33,9 @@ IF(LIBUSB_FOUND) ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.hpp ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_device_handle.cpp ) + IF(WIN32) #include our custom stdint for libusb + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/transport/include) + ENDIF(WIN32) SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) diff --git a/host/lib/transport/include/stdint.h b/host/lib/transport/include/stdint.h new file mode 100644 index 000000000..b3eb61aae --- /dev/null +++ b/host/lib/transport/include/stdint.h @@ -0,0 +1,35 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#ifndef INCLUDED_LIBUHD_TRANSPORT_STDINT_H +#define INCLUDED_LIBUHD_TRANSPORT_STDINT_H + +#include + +//provide a stdint implementation for libusb + +typedef boost::uint64_t uint64_t; +typedef boost::uint32_t uint32_t; +typedef boost::uint16_t uint16_t; +typedef boost::uint8_t uint8_t; + +typedef boost::int64_t int64_t; +typedef boost::int32_t int32_t; +typedef boost::int16_t int16_t; +typedef boost::int8_t int8_t; + +#endif /* INCLUDED_LIBUHD_TRANSPORT_STDINT_H */ diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index e21c39aa3..1f816c6e2 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -67,7 +67,7 @@ bool libusb::compare_device(libusb_device *dev, std::string serial = handle->get_serial(); boost::uint16_t vendor_id = handle->get_vendor_id(); boost::uint16_t product_id = handle->get_product_id(); - boost::uint8_t device_addr = handle->get_device_addr(); + boost::uint16_t device_addr = handle->get_device_addr(); libusb_device_descriptor libusb_desc; if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 43d0f0e26..7efddd410 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -29,9 +29,9 @@ const int libusb_debug_level = 0; class libusb1_device_handle_impl : public usb_device_handle { public: libusb1_device_handle_impl(std::string serial, - boost::uint32_t product_id, - boost::uint32_t vendor_id, - boost::uint32_t device_addr) + boost::uint16_t product_id, + boost::uint16_t vendor_id, + boost::uint16_t device_addr) : _serial(serial), _product_id(product_id), _vendor_id(vendor_id), _device_addr(device_addr) { @@ -66,9 +66,9 @@ public: private: std::string _serial; - boost::uint32_t _product_id; - boost::uint32_t _vendor_id; - boost::uint32_t _device_addr; + boost::uint16_t _product_id; + boost::uint16_t _vendor_id; + boost::uint16_t _device_addr; }; @@ -81,9 +81,9 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) } std::string serial = libusb::get_serial(dev); - boost::uint32_t product_id = desc.idProduct; - boost::uint32_t vendor_id = desc.idVendor; - boost::uint32_t device_addr = libusb_get_device_address(dev); + boost::uint16_t product_id = desc.idProduct; + boost::uint16_t vendor_id = desc.idVendor; + boost::uint16_t device_addr = libusb_get_device_address(dev); return usb_device_handle::sptr(new libusb1_device_handle_impl( serial, diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index b890a87f9..b3a160462 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -18,7 +18,6 @@ #include "libusb1_base.hpp" #include #include -#include #include #include #include @@ -208,7 +207,7 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) endpoint, // endpoint buff, // buffer buff_len, // length - callback, // callback + libusb_transfer_cb_fn(callback), // callback this, // user_data 0); // timeout return lut; diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 08f2d2a8e..ad16f6b3a 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -126,7 +126,7 @@ usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, _ad9862_regs.clkout2_div_factor = ad9862_regs_t::CLKOUT2_DIV_FACTOR_2; //write the register settings to the codec - for (uint8_t addr = 0; addr <= 25; addr++) { + for (boost::uint8_t addr = 0; addr <= 25; addr++) { this->send_reg(addr); } @@ -199,7 +199,7 @@ float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){ **********************************************************************/ static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low) { - return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; + return float(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff; } float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which) diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 451129ef5..936ffd17d 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -287,7 +287,7 @@ public: int usrp_load_eeprom(std::string filestring) { const char *filename = filestring.c_str(); - const uint16_t i2c_addr = 0x50; + const boost::uint16_t i2c_addr = 0x50; //FIXME: verify types int len; @@ -416,7 +416,7 @@ public: } - int usrp_control_write_cmd(uint8_t request, uint16_t value, uint16_t index) + int usrp_control_write_cmd(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index) { return usrp_control_write(request, value, index, 0, 0); } diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 4bc18dd16..5fd3987d5 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -80,7 +80,7 @@ public: boost::uint32_t peek32(boost::uint32_t addr) { - uint32_t value_out; + boost::uint32_t value_out; boost::uint8_t w_index_h = SPI_ENABLE_FPGA & 0xff; boost::uint8_t w_index_l = (SPI_FMT_MSB | SPI_FMT_HDR_1) & 0xff; @@ -100,7 +100,7 @@ public: boost::uint16_t peek16(boost::uint32_t addr) { - uint32_t val = peek32(addr); + boost::uint32_t val = peek32(addr); return boost::uint16_t(val & 0xff); } diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index a6806dbc3..627180b11 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -62,7 +62,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx" ); } - catch(const std::exception &e){ + catch(...){ uhd::print_warning( "Could not locate USRP1 firmware.\n" "Please install the images package.\n" -- cgit v1.2.3 From af1882ab65bb1395f75dd7a7fbdcfc8535c32479 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 23 Sep 2010 18:32:06 -0700 Subject: usrp1: modified control to use the c++ ifstream over fopen --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 936ffd17d..1dc6e6e25 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -249,38 +249,39 @@ public: unsigned char buf[ep0_size]; int ret; - FILE *fp; - if ((fp = fopen(filename, "rb")) == NULL) { + std::ifstream file; + file.open(filename, std::ios::in | std::ios::binary); + if (not file.good()) { std::cerr << "cannot open fpga input file" << std::endl; - fclose(fp); + file.close(); return -1; } if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_BEGIN) < 0) { std::cerr << "fpga load error" << std::endl; - fclose(fp); + file.close(); return -1; } ssize_t n; - while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { + while ((n = file.readsome((char *)buf, sizeof(buf))) > 0) { ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); if (ret != n) { std::cerr << "fpga load error " << ret << std::endl; - fclose(fp); + file.close(); return -1; } } if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_END) < 0) { std::cerr << "fpga load error" << std::endl; - fclose(fp); + file.close(); return -1; } usrp_set_fpga_hash(hash); - fclose(fp); + file.close(); return 0; } -- cgit v1.2.3 From 42576f1ed98735a69a20cc788d09acd82cb69ae8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 23 Sep 2010 18:46:58 -0700 Subject: usrp1: removed msvc warnings for usrp1 impl code --- host/lib/usrp/usrp1/dsp_impl.cpp | 10 ++++------ host/lib/usrp/usrp1/io_impl.cpp | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 573bce21f..e9a5e60a6 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -107,8 +107,7 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ return; } case DSP_PROP_HOST_RATE: { - unsigned int rate = - _clock_ctrl->get_master_clock_freq() / val.as(); + size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as()); if ((rate & 0x01) || (rate < 4) || (rate > 256)) { std::cerr << "Decimation must be even and between 4 and 256" @@ -118,7 +117,7 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ _rx_dsp_decim = rate; //TODO Poll every 100ms. Make it selectable? - _rx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() / rate; + _rx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate); _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); } @@ -207,8 +206,7 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){ } case DSP_PROP_HOST_RATE: { - unsigned int rate = - _clock_ctrl->get_master_clock_freq() * 2 / val.as(); + size_t rate = size_t(_clock_ctrl->get_master_clock_freq() * 2 / val.as()); if ((rate & 0x01) || (rate < 8) || (rate > 512)) { std::cerr << "Interpolation rate must be even and between 8 and 512" @@ -219,7 +217,7 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){ _tx_dsp_interp = rate; //TODO Poll every 100ms. Make it selectable? - _tx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate; + _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate); _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1); return; diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 146038bd9..73974f2d6 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -184,7 +184,7 @@ bool usrp1_impl::io_impl::get_send_buffs( )); } - return buffs[0].get(); + return buffs[0].get() != NULL; } /*********************************************************************** @@ -277,7 +277,7 @@ static bool get_recv_buffs( ){ UHD_ASSERT_THROW(buffs.size() == 1); buffs[0] = zc_if->get_recv_buff(); - return buffs[0].get(); + return buffs[0].get() != NULL; } size_t usrp1_impl::recv( -- cgit v1.2.3 From 082715d0c90b615874fe6bbe93069fa696b3d47a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 24 Sep 2010 15:56:52 -0700 Subject: usrp-e: updated dsp for multiple shift properties --- host/lib/usrp/usrp_e/dsp_impl.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/dsp_impl.cpp b/host/lib/usrp/usrp_e/dsp_impl.cpp index c133eafae..9312bb603 100644 --- a/host/lib/usrp/usrp_e/dsp_impl.cpp +++ b/host/lib/usrp/usrp_e/dsp_impl.cpp @@ -44,7 +44,9 @@ void usrp_e_impl::rx_ddc_init(void){ /*********************************************************************** * RX DDC Get **********************************************************************/ -void usrp_e_impl::rx_ddc_get(const wax::obj &key, wax::obj &val){ +void usrp_e_impl::rx_ddc_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp-e ddc0"); @@ -58,6 +60,10 @@ void usrp_e_impl::rx_ddc_get(const wax::obj &key, wax::obj &val){ val = _ddc_freq; return; + case DSP_PROP_FREQ_SHIFT_NAMES: + val = prop_names_t(1, ""); + return; + case DSP_PROP_CODEC_RATE: val = MASTER_CLOCK_RATE; return; @@ -73,7 +79,9 @@ void usrp_e_impl::rx_ddc_get(const wax::obj &key, wax::obj &val){ /*********************************************************************** * RX DDC Set **********************************************************************/ -void usrp_e_impl::rx_ddc_set(const wax::obj &key, const wax::obj &val){ +void usrp_e_impl::rx_ddc_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ @@ -119,7 +127,9 @@ void usrp_e_impl::tx_duc_init(void){ /*********************************************************************** * TX DUC Get **********************************************************************/ -void usrp_e_impl::tx_duc_get(const wax::obj &key, wax::obj &val){ +void usrp_e_impl::tx_duc_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp-e duc0"); @@ -133,6 +143,10 @@ void usrp_e_impl::tx_duc_get(const wax::obj &key, wax::obj &val){ val = _duc_freq; return; + case DSP_PROP_FREQ_SHIFT_NAMES: + val = prop_names_t(1, ""); + return; + case DSP_PROP_CODEC_RATE: val = MASTER_CLOCK_RATE; return; @@ -148,7 +162,9 @@ void usrp_e_impl::tx_duc_get(const wax::obj &key, wax::obj &val){ /*********************************************************************** * TX DUC Set **********************************************************************/ -void usrp_e_impl::tx_duc_set(const wax::obj &key, const wax::obj &val){ +void usrp_e_impl::tx_duc_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ -- cgit v1.2.3 From 017e7202468a8800335c05afd4a85cb52c6171e6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 26 Sep 2010 21:07:43 -0700 Subject: usrp1: add print out messages when loading images --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 1dc6e6e25..76e8ce368 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -38,6 +38,8 @@ enum firmware_code { #define FX2_FIRMWARE_LOAD 0xa0 +static const bool load_img_msg = true; + /*********************************************************************** * Helper Functions **********************************************************************/ @@ -178,6 +180,7 @@ public: unsigned char reset_n = 0; //hit the reset line + if (load_img_msg) std::cout << "Loading firmware image " << filestring << "..." << std::flush; usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); @@ -213,7 +216,7 @@ public: //wait for things to settle boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - + if (load_img_msg) std::cout << " done" << std::endl; return USRP_FIRMWARE_LOAD_SUCCESS; } //type anything else is unhandled @@ -249,6 +252,7 @@ public: unsigned char buf[ep0_size]; int ret; + if (load_img_msg) std::cout << "Loading FPGA image: " << filestring << "..." << std::flush; std::ifstream file; file.open(filename, std::ios::in | std::ios::binary); if (not file.good()) { @@ -282,6 +286,7 @@ public: usrp_set_fpga_hash(hash); file.close(); + if (load_img_msg) std::cout << " done" << std::endl; return 0; } -- cgit v1.2.3 From 2f62c39b7135728ed06faa06db46004323b1c70f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 27 Sep 2010 11:35:28 -0700 Subject: uhd: fix warning by adding brackets for while(cond){}; --- host/examples/test_async_messages.cpp | 2 +- host/lib/transport/libusb1_zero_copy.cpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_async_messages.cpp index 4c9d18121..0a5c076ea 100644 --- a/host/examples/test_async_messages.cpp +++ b/host/examples/test_async_messages.cpp @@ -58,7 +58,7 @@ void test_no_async_message(uhd::usrp::single_usrp::sptr sdev){ " Got unexpected event code 0x%x.\n" ) % async_md.event_code << std::endl; //clear the async messages - while (dev->recv_async_msg(async_md, 0)); + while (dev->recv_async_msg(async_md, 0)){}; } else{ std::cout << boost::format( diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index d3888240b..b089d11e0 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -184,7 +184,7 @@ usb_endpoint::~usb_endpoint(void){ } //collect canceled transfers (drain the queue) - while (this->get_lut_with_wait() != NULL); + while (this->get_lut_with_wait() != NULL){}; //free all transfers BOOST_FOREACH(libusb_transfer *lut, _all_luts){ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 91a1b2344..65411801d 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -150,7 +150,7 @@ void usrp2_impl::io_init(void){ std::memcpy(send_buff->cast(), &data, sizeof(data)); send_buff->commit(sizeof(data)); //drain the recv buffers (may have junk) - while (data_transport->get_recv_buff().get()); + while (data_transport->get_recv_buff().get()){}; } //the number of recv frames is the number for the first transport -- cgit v1.2.3 From fd15965442d5a8805a4730022f8d500841f8448d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 27 Sep 2010 16:04:04 -0700 Subject: usrp1: filter the discovery routine on the serial --- host/lib/usrp/usrp1/usrp1_impl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 627180b11..80ea49e9d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -96,7 +96,10 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) device_addr_t new_addr; new_addr["type"] = "usrp1"; new_addr["serial"] = handle->get_serial(); - usrp1_addrs.push_back(new_addr); + //this is a found usrp1 when a hint serial is not specified or it matches + if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){ + usrp1_addrs.push_back(new_addr); + } } return usrp1_addrs; -- cgit v1.2.3 From a6f60ab4911fa756656a62ebe3a1093d52836a6e Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 27 Sep 2010 19:19:55 -0700 Subject: TVRX: not done yet but getting there. gain linearization framework in place. --- host/lib/ic_reg_maps/CMakeLists.txt | 4 +- host/lib/ic_reg_maps/gen_dtt75403_regs.py | 85 ---------- host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py | 75 +++++++++ host/lib/usrp/dboard/db_tvrx.cpp | 218 +++++++++++++++++-------- 4 files changed, 225 insertions(+), 157 deletions(-) delete mode 100755 host/lib/ic_reg_maps/gen_dtt75403_regs.py create mode 100644 host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py (limited to 'host/lib/usrp') diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index b396db4ca..25f34a280 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -70,6 +70,6 @@ LIBUHD_PYTHON_GEN_SOURCE( ) LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_dtt75403_regs.py - ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/dtt75403_regs.py + ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_tuner_4937di5_regs.py + ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/tuner_4937di5_regs.hpp ) diff --git a/host/lib/ic_reg_maps/gen_dtt75403_regs.py b/host/lib/ic_reg_maps/gen_dtt75403_regs.py deleted file mode 100755 index fe64bd92a..000000000 --- a/host/lib/ic_reg_maps/gen_dtt75403_regs.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2010 Ettus Research LLC -# -# 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, see . -# - -######################################################################## -# Template for raw text data describing registers -# name addr[bit range inclusive] default optional enums -######################################################################## -REGS_TMPL="""\ -######################################################################## -## Note: offsets given from perspective of data bits (excludes address) -######################################################################## -## -######################################################################## -## Address byte -######################################################################## -adb 0[1:2] 0 -######################################################################## -## Divider byte 1 -######################################################################## -db1 1[0:6] 0x00 -######################################################################## -## Divider byte 2 -######################################################################## -db2 2[0:7] 0x00 -######################################################################## -## Control byte 1 -######################################################################## -atp 3[3:5] 0 112, 109, 106, 103, 100, 94, 94, disable -refdiv 3[0:2] 0 166.667khz, 142.857khz, 80khz, 62.5khz, 31.25khz, 50khz -######################################################################## -## Band switch byte -######################################################################## -cpsel 4[6:7] 0 -filterbw 4[4] 0 8mhz, 7mhz -bandsel 4[0:3] 0 -######################################################################## -## Control byte 2 -######################################################################## -atc 5[5] 0 low, high -stby 5[4] 0 standby, on -xto 5[0] 0 disable, enable -""" - -######################################################################## -# Template for methods in the body of the struct -######################################################################## -BODY_TMPL="""\ -boost::uint8_t get_reg(boost::uint8_t addr){ - boost::uint8_t reg = 0; - switch(addr){ - #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) - case $addr: - #for $reg in filter(lambda r: r.get_addr() == addr, $regs) - reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); - #end for - break; - #end for - } - return boost::uint8_t(reg); -} - -""" - -if __name__ == '__main__': - import common; common.generate( - name='dtt75403_regs', - regs_tmpl=REGS_TMPL, - body_tmpl=BODY_TMPL, - file=__file__, - ) diff --git a/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py b/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py new file mode 100644 index 000000000..73f7aa3db --- /dev/null +++ b/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# Copyright 2010 Ettus Research LLC +# +# 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, see . +# + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## Divider byte 1 +######################################################################## +db1 0[0:6] 0x00 +######################################################################## +## Divider byte 2 +######################################################################## +db2 1[0:7] 0x00 +######################################################################## +## Control byte 1 +######################################################################## +cb7 2[7] 0x01 +cp 2[6] 0x00 low,high +os 2[0] 0x00 on,off +rs 2[1:2] 0x00 d512=3,d640=0,d1024=1 +test 2[3:5] 0x01 normal=0x01,cpoff=0x02,cpsink=0x06,cpsrc=0x07,cptest1=0x04,cptest2=0x05 +######################################################################## +## Control byte 2 +######################################################################## +bandsel 3[4:7] 0x03 uhf=0x03,vhfhi=0x09,vhflo=0x0a +power 3[3] 0x00 on,off +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ + boost::uint8_t reg = 0; + switch(addr){ + #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) + case $addr: + #for $reg in filter(lambda r: r.get_addr() == addr, $regs) + reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); + #end for + break; + #end for + } + return boost::uint8_t(reg); +} + +""" + +if __name__ == '__main__': + import common; common.generate( + name='tuner_4937di5_regs', + regs_tmpl=REGS_TMPL, + body_tmpl=BODY_TMPL, + file=__file__, + ) diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 5582dbe33..ed6025433 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -42,6 +42,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -57,19 +58,73 @@ static const freq_range_t tvrx_freq_range(50e6, 860e6); static const prop_names_t tvrx_antennas = ""; //only got one static const uhd::dict tvrx_gain_ranges = map_list_of - ("RF", gain_range_t(0, 60, float(60.0/4096))) //both gains are analog and controlled by DAC - ("IF", gain_range_t(0, 35, float(35.0/4096))) //the old driver used 1dB for both; i don't think that's right? + ("RF", gain_range_t(-13.3, 50.3, float(50.3/4096))) //both gains are analog and controlled by DAC + ("IF", gain_range_t(-1.5, 32.5, float(32.5/4096))) //the old driver used 1dB for both; i don't think that's right? ; static const uhd::dict tvrx_freq_ranges = map_list_of - ("VHFLO", freq_range_t(50e6, 158e6)) //this isn't used outside this driver. just for us. + ("VHFLO", freq_range_t(50e6, 158e6)) ("VHFHI", freq_range_t(158e6, 454e6)) ("UHF" , freq_range_t(454e6, 860e6)) ; -//we might need to spec the various bands for band selection. +//gain linearization data +//this is from the datasheet and is dB vs. volts (below) +//i tried to curve fit this, but it's really just so nonlinear that you'd +//need dang near as many coefficients as to just map it like this and interp. +//these numbers are culled from the 4937DI5 datasheet and are probably totally inaccurate +//but if it's better than the old linear fit i'm happy +static const uhd::dict > tvrx_rf_gains_db = map_list_of + ("VHFLO", std::vector(-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, + 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, + 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, + 50.30000, 50.30000)) + ("VHFHI", std::vector(-13.3000, -13.3000, -13.3000, -1.0000, 7.7000, + 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, + 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, + 48.2000, 48.2000)) + ("UHF" , std::vector(-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, + 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, + 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, + 43.2000, 43.8000)) +; + +static const std::vector tvrx_if_gains_db = + std::vector(-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, + 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, + 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, + 32.50000, 32.50000) +; + +//sample voltages for the above points +static const std::vector tvrx_rf_gains_volts = + std::vector(0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0); -static const double tvrx_lo_freq = 36e6; //LO freq of TVRX module + +/*! + * Execute a linear interpolation to find the voltage corresponding to a desired gain + * \param gain the desired gain in dB + * \param db_vector the vector of dB readings + * \param volts_vector the corresponding vector of voltages db_vector was sampled at + * \return a voltage to feed the TVRX analog gain + */ + +static float gain_interp(float gain, std::vector db_vector, std::vector volts_vector) { + float volts; + gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here + + boost::uint8_t gain_step = 0; + for(int i = 0; i < db_vector.size()-1; i++) { + if(gain > db_vector[i] && gain < db_vector.[i+1]) gain_step = i; + } + + + return volts; +} + +static const double opamp_gain = 1.22; //onboard DAC opamp gain +static const double tvrx_lo_freq = 43.75e6; //LO freq of TVRX module +static const boost::uint16_t reference_divider = 640; //clock reference divider to use /*********************************************************************** * The tvrx dboard class @@ -84,40 +139,28 @@ public: private: uhd::dict _gains; - dtt75403_regs_t _dtt75403_regs; - boost::uint8_t _dtt75403_addr(void){ + tuner_4937di5_regs_t _tuner_4937di5_regs; + boost::uint8_t _tuner_4937di5_addr(void){ return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call }; void set_gain(float gain, const std::string &name); - void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ - //why is this an inline anyway? bring this out - start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5)); - stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x5)); - - for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ - int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; - - //create buffer for register data (+1 for start address) - byte_vector_t regs_vector(num_bytes + 1); + void update_regs(void){ + byte_vector_t regs_vector(4); - //first byte is the address of first register - regs_vector[0] = start_addr; - - //get the register data - for(int i=0; iget_iface()->write_i2c( - _max2118_addr(), regs_vector - ); + //get the register data + for(int i=0; i<4; i++){ + regs_vector[i] = _tuner_4937di5_regs.get_reg(i); + if(tvrx_debug) std::cerr << boost::format( + "tvrx: send reg 0x%02x, value 0x%04x" + ) % int(i) % int(regs_vector[i]) << std::endl; } + + //send the data + this->get_iface()->write_i2c( + _tuner_4937di5_addr(), regs_vector + ); } }; @@ -138,10 +181,6 @@ UHD_STATIC_BLOCK(reg_tvrx_dboard){ * Structors **********************************************************************/ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ - //enable only the clocks we need - - //TODO: YOU GOT SOME CLOCK SETUP TO DO HERE, DOGGGG - this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); //set the gpio directions and atr controls (identically) @@ -165,77 +204,114 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ tvrx::~tvrx(void){ } +/*! Return a string corresponding to the relevant band + * \param freq the frequency of interest + * \return a string corresponding to the band + */ + +static std::string get_band(double freq) { + BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { + if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) + return name; + } + UHD_THROW_INVALID_CODE_PATH(); +} + /*********************************************************************** * Gain Handling **********************************************************************/ +/* + * Gain accuracy on this thing is basically a crap shoot. In other words, there is none. + * The old driver basically picked a linear approximation of the median gain, but the actual + * gain slope is heavily nonlinear and varies both with gain and with frequency. + * It also probably varies markedly over temperature, but there's only so much we can do. + * The best approximation to the RF gain data is fifth-order. If we ignore the curve portions + * below 0dB (yes, it's a pad below a certain gain value) and if we ignore the curve portions + * near the max-gain asymptotes, it looks pretty close to third-order. This is less insane to + * approximate. + */ + /*! - * Convert a requested gain for the GC2 vga into the integer register value. + * Convert a requested gain for the RF gain into a DAC voltage. * The gain passed into the function will be set to the actual value. * \param gain the requested gain in dB - * \return 5 bit the register value + * \return dac voltage value */ -//yo this should look the same as the below one for the IF, dogg -static int gain_to_gc2_vga_reg(float &gain){ - int reg = 0; - gain = std::clip(float(boost::math::iround(gain)), tvrx_gain_ranges["GC2"].min, tvrx_gain_ranges["GC2"].max); - - // Half dB steps from 0-5dB, 1dB steps from 5-24dB - if (gain < 5) { - reg = boost::math::iround(31.0 - gain/0.5); - gain = float(boost::math::iround(gain) * 0.5); - } else { - reg = boost::math::iround(22.0 - (gain - 4.0)); - gain = float(boost::math::iround(gain)); - } +static float rf_gain_to_voltage(float &gain){ + //clip the input + gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + + //voltage level constants + static const float max_volts = float(4.0), min_volts = float(0.6); + static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + + //this is the voltage at the TVRX gain input + float gain_volts = gain*slope + min_volts + //this is the voltage at the USRP DAC output + float dac_volts = gain_volts / opamp_gain; + + //the actual gain setting + gain = (dac_volts - min_volts)/slope; if (tvrx_debug) std::cerr << boost::format( - "tvrx GC2 Gain: %f dB, reg: %d" - ) % gain % reg << std::endl; + "tvrx RF AGC gain: %f dB, dac_volts: %f V" + ) % gain % dac_volts << std::endl; - return reg; + return dac_volts; } /*! - * Convert a requested gain for the RF gain into the dac_volts value. + * Convert a requested gain for the IF gain into a DAC voltage. * The gain passed into the function will be set to the actual value. * \param gain the requested gain in dB * \return dac voltage value */ -//yo what about the 1.22 opamp gain of the USRP1 -- is this replicated on U2? -static float gain_to_rfgain_dac(float &gain){ +static float if_gain_to_voltage(float &gain){ //clip the input - gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + gain = std::clip(gain, tvrx_gain_ranges["IF"].min, tvrx_gain_ranges["IF"].max); //voltage level constants - static const float max_volts = float(0), min_volts = float(3.3); - static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + static const float max_volts = float(4.0), min_volts = float(0.0); + static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["IF"].max; - //calculate the voltage for the aux dac - float dac_volts = gain*slope + min_volts; - - if (tvrx_debug) std::cerr << boost::format( - "tvrx RFAGC Gain: %f dB, dac_volts: %f V" - ) % gain % dac_volts << std::endl; + //this is the voltage at the TVRX gain input + float gain_volts = gain*slope + 1.25; + //this is the voltage at the USRP DAC output + float dac_volts = gain_volts / opamp_gain; //the actual gain setting gain = (dac_volts - min_volts)/slope; + if (tvrx_debug) std::cerr << boost::format( + "tvrx IF AGC gain: %f dB, dac_volts: %f V" + ) % gain % dac_volts << std::endl; + return dac_volts; } void tvrx::set_gain(float gain, const std::string &name){ assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); if (name == "RF"){ -//should look the same as below + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain)); } else if(name == "IF"){ - //write the new voltage to the aux dac CHECK THIS - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); } else UHD_THROW_INVALID_CODE_PATH(); _gains[name] = gain; +} + +/*! + * Set the tuner to center the desired frequency at 43.75MHz + * \param freq the requested frequency + */ + +void tvrx::set_freq(double freq) { + + + } /*********************************************************************** @@ -300,7 +376,6 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ } } -//for smaaht kids to use to set advanced props void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ named_prop_t key = named_prop_t::extract(key_); @@ -309,6 +384,9 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_GAIN: this->set_gain(val.as(), key.name); return; + case SUBDEV_PROP_FREQ: + this->set_freq(val.as()); + return; default: UHD_THROW_PROP_SET_ERROR(); } -- cgit v1.2.3 From 852f5c5f7b31bfb2e7561a86ca9f5380bd53d130 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 10:21:11 -0700 Subject: dboard: better warnings for invalid IDs and invalid ID combinations --- host/lib/usrp/dboard_manager.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index ab80875f5..181f843a0 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -18,6 +18,7 @@ #include "dboard_ctor_args.hpp" #include #include +#include #include #include #include @@ -176,10 +177,6 @@ static args_t get_dboard_args( ){ //special case, the none id was provided, use the following ids if (dboard_id == dboard_id_t::none() or force_to_unknown){ - std::cerr << boost::format( - "Warning: unknown dboard-id or dboard-id combination: %s\n" - " -> defaulting to the unknown board type" - ) % dboard_id.to_pp_string() << std::endl; UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1)); UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0)); switch(unit){ @@ -191,6 +188,9 @@ static args_t get_dboard_args( //verify that there is a registered constructor for this id if (not get_id_to_args_map().has_key(dboard_id)){ + uhd::print_warning(str(boost::format( + "Unknown dboard ID: %s.\n" + ) % dboard_id.to_pp_string())); return get_dboard_args(unit, dboard_id, true); } @@ -214,12 +214,25 @@ dboard_manager_impl::dboard_manager_impl( (get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id) ); + //warn for invalid dboard id xcvr combinations + if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){ + uhd::print_warning(str(boost::format( + "Unknown transceiver board ID combination...\n" + "RX dboard ID: %s\n" + "TX dboard ID: %s\n" + ) % rx_dboard_id.to_pp_string() % tx_dboard_id.to_pp_string())); + } + //extract dboard constructor and settings (force to unknown for messed up xcvr status) dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs; - boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr); + boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args( + dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr + ); dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs; - boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr); + boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args( + dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr + ); //initialize the gpio pins before creating subdevs set_nice_dboard_if(); -- cgit v1.2.3 From 137aa0ab1ed0b8f7f31a6c484fcf5a845682db80 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 10:24:53 -0700 Subject: usrp1: modify fpga file load to use read (readsome seems to not work here in windows land) --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 76e8ce368..2e1bd85cd 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -267,8 +267,9 @@ public: return -1; } - ssize_t n; - while ((n = file.readsome((char *)buf, sizeof(buf))) > 0) { + while (not file.eof()) { + file.read((char *)buf, sizeof(buf)); + size_t n = file.gcount(); ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); if (ret != n) { -- cgit v1.2.3 From f5bdb7ccb39ef23d4b2c0872fe410e9d5d031958 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 11:08:41 -0700 Subject: usrp1: move the get handles call into the for loop scope to facilitate decontruction --- host/lib/usrp/usrp1/usrp1_impl.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 627180b11..a56649305 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -74,14 +74,14 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) boost::uint16_t vid = hint.has_key("uninit") ? FX2_VENDOR_ID : USRP1_VENDOR_ID; boost::uint16_t pid = hint.has_key("uninit") ? FX2_PRODUCT_ID : USRP1_PRODUCT_ID; - //see what we got on the USB bus - std::vector device_list = - usb_device_handle::get_device_list(vid, pid); - - if(device_list.size() == 0) return usrp1_addrs; //return nothing if no USRPs found + // Important note: + // The get device list calls are nested inside the for loop. + // This allows the usb guts to decontruct when not in use, + // so that re-enumeration after fw load can occur successfully. + // This requirement is a courtesy of libusb1.0 on windows. //find the usrps and load firmware - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_firmware(usrp1_fw_image); @@ -90,9 +90,8 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) //get descriptors again with serial number, but using the initialized VID/PID now since we have firmware vid = USRP1_VENDOR_ID; pid = USRP1_PRODUCT_ID; - device_list = usb_device_handle::get_device_list(vid, pid); - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { device_addr_t new_addr; new_addr["type"] = "usrp1"; new_addr["serial"] = handle->get_serial(); -- cgit v1.2.3 From 15eacbd920a0527ec16c24baeb1d6b87f29d9110 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 13:52:09 -0700 Subject: TVRX: Don't have mboard impl modified for ADC buffer disable. The rest of TVRX should be in there. Not debugged. --- host/lib/usrp/dboard/CMakeLists.txt | 1 + host/lib/usrp/dboard/db_tvrx.cpp | 219 +++++++++++++++++++++--------------- host/lib/usrp/usrp1/codec_ctrl.cpp | 13 +++ host/lib/usrp/usrp1/codec_ctrl.hpp | 3 + 4 files changed, 147 insertions(+), 89 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 3e995009e..8d3d11530 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -24,5 +24,6 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_tvrx.cpp ) diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index ed6025433..2988367e2 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -39,9 +39,11 @@ #include #include #include +#include #include #include #include +#include #include using namespace uhd; @@ -55,12 +57,11 @@ static const bool tvrx_debug = true; static const freq_range_t tvrx_freq_range(50e6, 860e6); -static const prop_names_t tvrx_antennas = ""; //only got one +static const std::string tvrx_antennas = std::string(""); //only got one -static const uhd::dict tvrx_gain_ranges = map_list_of - ("RF", gain_range_t(-13.3, 50.3, float(50.3/4096))) //both gains are analog and controlled by DAC - ("IF", gain_range_t(-1.5, 32.5, float(32.5/4096))) //the old driver used 1dB for both; i don't think that's right? -; +//a note on these: the gain of the TVRX varies over frequency. the gain ranges +//below correspond to the maximum and minimum gains over the entire frequency range. +//specifying a gain higher or lower than the TVRX can accomplish will of course just clip. static const uhd::dict tvrx_freq_ranges = map_list_of ("VHFLO", freq_range_t(50e6, 158e6)) @@ -68,63 +69,68 @@ static const uhd::dict tvrx_freq_ranges = map_list_of ("UHF" , freq_range_t(454e6, 860e6)) ; +static const boost::array vhflo_gains_db = + {{-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, + 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, + 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, + 50.30000, 50.30000}}; + +static const boost::array vhfhi_gains_db = + {{13.3000, -13.3000, -13.3000, -1.0000, 7.7000, + 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, + 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, + 48.2000, 48.2000}}; + +static const boost::array uhf_gains_db = + {{-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, + 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, + 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, + 43.2000, 43.8000}}; + +static const boost::array tvrx_if_gains_db = + {{-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, + 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, + 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, + 32.50000, 32.50000}}; + //gain linearization data //this is from the datasheet and is dB vs. volts (below) //i tried to curve fit this, but it's really just so nonlinear that you'd //need dang near as many coefficients as to just map it like this and interp. //these numbers are culled from the 4937DI5 datasheet and are probably totally inaccurate //but if it's better than the old linear fit i'm happy -static const uhd::dict > tvrx_rf_gains_db = map_list_of - ("VHFLO", std::vector(-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, - 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, - 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, - 50.30000, 50.30000)) - ("VHFHI", std::vector(-13.3000, -13.3000, -13.3000, -1.0000, 7.7000, - 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, - 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, - 48.2000, 48.2000)) - ("UHF" , std::vector(-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, - 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, - 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, - 43.2000, 43.8000)) -; - -static const std::vector tvrx_if_gains_db = - std::vector(-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, - 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, - 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, - 32.50000, 32.50000) +static const uhd::dict > tvrx_rf_gains_db = map_list_of + ("VHFLO", vhflo_gains_db) + ("VHFHI", vhfhi_gains_db) + ("UHF" , uhf_gains_db) ; //sample voltages for the above points -static const std::vector tvrx_rf_gains_volts = - std::vector(0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0); - - -/*! - * Execute a linear interpolation to find the voltage corresponding to a desired gain - * \param gain the desired gain in dB - * \param db_vector the vector of dB readings - * \param volts_vector the corresponding vector of voltages db_vector was sampled at - * \return a voltage to feed the TVRX analog gain - */ - -static float gain_interp(float gain, std::vector db_vector, std::vector volts_vector) { - float volts; - gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here - - boost::uint8_t gain_step = 0; - for(int i = 0; i < db_vector.size()-1; i++) { - if(gain > db_vector[i] && gain < db_vector.[i+1]) gain_step = i; +static const boost::array tvrx_gains_volts = + {{0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0}}; + +static uhd::dict get_tvrx_gain_ranges(void) { + float rfmax = 0.0, rfmin = FLT_MAX; + BOOST_FOREACH(const std::string range, tvrx_rf_gains_db.keys()) { + float my_max = tvrx_rf_gains_db[range].back(); //we're assuming it's monotonic + float my_min = tvrx_rf_gains_db[range].front(); //if it's not this is wrong wrong wrong + if(my_max > rfmax) rfmax = my_max; + if(my_min < rfmin) rfmin = my_min; } - - return volts; + float ifmin = tvrx_if_gains_db.front(); + float ifmax = tvrx_if_gains_db.back(); + + return map_list_of + ("RF", gain_range_t(rfmin, rfmax, (rfmax-rfmin)/4096.0)) + ("IF", gain_range_t(ifmin, ifmax, (ifmax-ifmin)/4096.0)) + ; } static const double opamp_gain = 1.22; //onboard DAC opamp gain -static const double tvrx_lo_freq = 43.75e6; //LO freq of TVRX module +static const double tvrx_if_freq = 43.75e6; //IF freq of TVRX module static const boost::uint16_t reference_divider = 640; //clock reference divider to use +static const double reference_freq = 4.0e6; /*********************************************************************** * The tvrx dboard class @@ -139,12 +145,14 @@ public: private: uhd::dict _gains; + double _lo_freq; tuner_4937di5_regs_t _tuner_4937di5_regs; boost::uint8_t _tuner_4937di5_addr(void){ return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call }; void set_gain(float gain, const std::string &name); + void set_freq(double freq); void update_regs(void){ byte_vector_t regs_vector(4); @@ -192,12 +200,14 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs } - //send initial register settings - //HAAAAY GUYYYYYSSS + //send initial register settings if necessary + + //set default freq + set_freq(tvrx_freq_range.min); //set default gains - BOOST_FOREACH(const std::string &name, tvrx_gain_ranges.keys()){ - set_gain(tvrx_gain_ranges[name].min, name); + BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){ + set_gain(get_tvrx_gain_ranges()[name].min, name); } } @@ -212,7 +222,7 @@ tvrx::~tvrx(void){ static std::string get_band(double freq) { BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) - return name; + return band; } UHD_THROW_INVALID_CODE_PATH(); } @@ -220,17 +230,34 @@ static std::string get_band(double freq) { /*********************************************************************** * Gain Handling **********************************************************************/ -/* - * Gain accuracy on this thing is basically a crap shoot. In other words, there is none. - * The old driver basically picked a linear approximation of the median gain, but the actual - * gain slope is heavily nonlinear and varies both with gain and with frequency. - * It also probably varies markedly over temperature, but there's only so much we can do. - * The best approximation to the RF gain data is fifth-order. If we ignore the curve portions - * below 0dB (yes, it's a pad below a certain gain value) and if we ignore the curve portions - * near the max-gain asymptotes, it looks pretty close to third-order. This is less insane to - * approximate. +/*! + * Execute a linear interpolation to find the voltage corresponding to a desired gain + * \param gain the desired gain in dB + * \param db_vector the vector of dB readings + * \param volts_vector the corresponding vector of voltages db_vector was sampled at + * \return a voltage to feed the TVRX analog gain */ +static float gain_interp(float gain, boost::array db_vector, boost::array volts_vector) { + float volts; + gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here + + boost::uint8_t gain_step = 0; + //find which bin we're in + for(size_t i = 0; i < db_vector.size()-1; i++) { + if(gain > db_vector[i] && gain < db_vector[i+1]) gain_step = i; + } + + //find the current slope for linear interpolation + float slope = (volts_vector[gain_step + 1] - volts_vector[gain_step]) + / (db_vector[gain_step + 1] - db_vector[gain_step]); + + //use the volts per dB slope to find the final interpolated voltage + volts = volts_vector[gain_step] + (slope * (gain - db_vector[gain_step])); + + return volts; +} + /*! * Convert a requested gain for the RF gain into a DAC voltage. * The gain passed into the function will be set to the actual value. @@ -238,22 +265,18 @@ static std::string get_band(double freq) { * \return dac voltage value */ -static float rf_gain_to_voltage(float &gain){ +static float rf_gain_to_voltage(float gain, double lo_freq){ //clip the input - gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + gain = std::clip(gain, get_tvrx_gain_ranges()["RF"].min, get_tvrx_gain_ranges()["RF"].max); - //voltage level constants - static const float max_volts = float(4.0), min_volts = float(0.6); - static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + //first we need to find out what band we're in, because gains are different across different bands + std::string band = get_band(lo_freq + tvrx_if_freq); //this is the voltage at the TVRX gain input - float gain_volts = gain*slope + min_volts + float gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts); //this is the voltage at the USRP DAC output float dac_volts = gain_volts / opamp_gain; - //the actual gain setting - gain = (dac_volts - min_volts)/slope; - if (tvrx_debug) std::cerr << boost::format( "tvrx RF AGC gain: %f dB, dac_volts: %f V" ) % gain % dac_volts << std::endl; @@ -268,22 +291,13 @@ static float rf_gain_to_voltage(float &gain){ * \return dac voltage value */ -static float if_gain_to_voltage(float &gain){ +static float if_gain_to_voltage(float gain){ //clip the input - gain = std::clip(gain, tvrx_gain_ranges["IF"].min, tvrx_gain_ranges["IF"].max); - - //voltage level constants - static const float max_volts = float(4.0), min_volts = float(0.0); - static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["IF"].max; - - //this is the voltage at the TVRX gain input - float gain_volts = gain*slope + 1.25; - //this is the voltage at the USRP DAC output + gain = std::clip(gain, get_tvrx_gain_ranges()["IF"].min, get_tvrx_gain_ranges()["IF"].max); + + float gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts); float dac_volts = gain_volts / opamp_gain; - //the actual gain setting - gain = (dac_volts - min_volts)/slope; - if (tvrx_debug) std::cerr << boost::format( "tvrx IF AGC gain: %f dB, dac_volts: %f V" ) % gain % dac_volts << std::endl; @@ -292,9 +306,9 @@ static float if_gain_to_voltage(float &gain){ } void tvrx::set_gain(float gain, const std::string &name){ - assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); + assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name"); if (name == "RF"){ - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain, _lo_freq)); } else if(name == "IF"){ this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); @@ -309,9 +323,36 @@ void tvrx::set_gain(float gain, const std::string &name){ */ void tvrx::set_freq(double freq) { + freq = std::clip(freq, tvrx_freq_range.min, tvrx_freq_range.max); + std::string prev_band = get_band(_lo_freq + tvrx_if_freq); + std::string new_band = get_band(freq); + double lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing + double f_ref = reference_freq / double(reference_divider); //your tuning step size + int divisor = int(lo_freq + (f_ref * 4.0)) / (f_ref * 8); //the divisor we'll use + double actual_lo_freq = (f_ref * 8 * divisor); //the LO freq we'll actually get + + if((divisor & ~0x7fff)) UHD_THROW_INVALID_CODE_PATH(); + + //now we update the registers + _tuner_4937di5_regs.db1 = (divisor >> 8) & 0xff; + _tuner_4937di5_regs.db2 = divisor & 0xff; + + if(new_band == "VHFLO") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFLO; + else if(new_band == "VHFHI") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFHI; + else if(new_band == "UHF") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_UHF; + else UHD_THROW_INVALID_CODE_PATH(); + + _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_ON; + update_regs(); + + //ok don't forget to reset RF gain here if the new band != the old band + //we do this because the gains are different for different band settings + //not FAR off, but we do this to be consistent + if(prev_band != new_band) set_gain(_gains["RF"], "RF"); + _lo_freq = actual_lo_freq; //for rx props } /*********************************************************************** @@ -336,16 +377,16 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN_RANGE: - assert_has(tvrx_gain_ranges.keys(), key.name, "tvrx gain name"); - val = tvrx_gain_ranges[key.name]; + assert_has(get_tvrx_gain_ranges().keys(), key.name, "tvrx gain name"); + val = get_tvrx_gain_ranges()[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: - val = prop_names_t(tvrx_gain_ranges.keys()); + val = prop_names_t(get_tvrx_gain_ranges().keys()); return; case SUBDEV_PROP_FREQ: - val = tvrx_lo_freq; + val = _lo_freq - tvrx_if_freq; return; case SUBDEV_PROP_FREQ_RANGE: diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 08f2d2a8e..3ab02eeeb 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -61,6 +61,9 @@ public: float get_tx_pga_gain(void); void set_rx_pga_gain(float, char); float get_rx_pga_gain(char); + + //rx adc buffer control + void bypass_adc_buffers(bool bypass); private: usrp1_iface::sptr _iface; @@ -418,6 +421,16 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq) this->send_reg(23); } +/*********************************************************************** + * Codec Control ADC buffer bypass + * Enable this for DC-coupled daughterboards (TVRX) + **********************************************************************/ +void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) { + _ad9862_regs.byp_buffer_a = bypass; + _ad9862_regs.byp_buffer_b = bypass; + this->send_reg(2); +} + /*********************************************************************** * Codec Control Make **********************************************************************/ diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 259d10ef4..e2e8a010d 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -92,6 +92,9 @@ public: //! Set the TX modulator frequency virtual void set_duc_freq(double freq) = 0; + + //! Enable or disable ADC buffer bypass + virtual void bypass_adc_buffers(bool bypass) = 0; }; #endif /* INCLUDED_USRP1_CODEC_CTRL_HPP */ -- cgit v1.2.3 From b70d4430d4a898fe99b54740a1c4821ed9a1077b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 15:31:38 -0700 Subject: wbx: fix for id swap typo --- host/lib/usrp/dboard/db_wbx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index ccd897674..e473ce41e 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -154,7 +154,7 @@ static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){ } UHD_STATIC_BLOCK(reg_wbx_dboards){ - dboard_manager::register_dboard(0x0052, 0x0053, &make_wbx, "WBX"); + dboard_manager::register_dboard(0x0053, 0x0052, &make_wbx, "WBX"); } /*********************************************************************** -- cgit v1.2.3 From e4c6f42ff30aeaedf2d1eb426a221b85236fb74e Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 16:53:52 -0700 Subject: usb: submit should return ssize_t, usrp1: set hash before reset after fw load --- host/include/uhd/transport/usb_control.hpp | 4 ++-- host/lib/transport/libusb1_control.cpp | 2 +- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6137ecf84..f9829c3ec 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -50,9 +50,9 @@ public: * \param index 2-byte (wIndex) * \param buff buffer to hold send or receive data * \param length 2-byte (wLength) - * \return number of bytes submitted + * \return number of bytes submitted or error code */ - virtual size_t submit(boost::uint8_t request_type, + virtual ssize_t submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index c989a788c..f903907d0 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -33,7 +33,7 @@ public: _handle->claim_interface(0 /* control interface */); } - size_t submit(boost::uint8_t request_type, + ssize_t submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 2e1bd85cd..5d73e6dd9 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -209,9 +209,9 @@ public: } //type 0x01 is end else if (type == 0x01) { + usrp_set_firmware_hash(hash); //set hash before reset usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); - usrp_set_firmware_hash(hash); file.close(); //wait for things to settle -- cgit v1.2.3 From 7cb95203f8d7173e3d7070d24f68358be67d0b29 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 17:45:07 -0700 Subject: TVRX: First version that works. The gain linearity is still borked. I'll probably give up on the complicated linearizing stuff and just use the values from the old driver. The tuner's gain-vs-voltage is nothing like the datasheet. --- host/lib/usrp/dboard/db_tvrx.cpp | 44 ++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 2988367e2..f5b544c18 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include using namespace uhd; @@ -59,10 +60,6 @@ static const freq_range_t tvrx_freq_range(50e6, 860e6); static const std::string tvrx_antennas = std::string(""); //only got one -//a note on these: the gain of the TVRX varies over frequency. the gain ranges -//below correspond to the maximum and minimum gains over the entire frequency range. -//specifying a gain higher or lower than the TVRX can accomplish will of course just clip. - static const uhd::dict tvrx_freq_ranges = map_list_of ("VHFLO", freq_range_t(50e6, 158e6)) ("VHFHI", freq_range_t(158e6, 454e6)) @@ -148,7 +145,7 @@ private: double _lo_freq; tuner_4937di5_regs_t _tuner_4937di5_regs; boost::uint8_t _tuner_4937di5_addr(void){ - return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call + return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x61 : 0x60; //ok really? we could rename that call }; void set_gain(float gain, const std::string &name); @@ -182,7 +179,7 @@ static dboard_base::sptr make_tvrx(dboard_base::ctor_args_t args){ UHD_STATIC_BLOCK(reg_tvrx_dboard){ //register the factory function for the rx dbid - dboard_manager::register_dboard(0x0003, &make_tvrx, "tvrx"); + dboard_manager::register_dboard(0x0040, &make_tvrx, "tvrx"); } /*********************************************************************** @@ -203,6 +200,7 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ //send initial register settings if necessary //set default freq + _lo_freq = tvrx_freq_range.min + tvrx_if_freq; //init _lo_freq to a sane default set_freq(tvrx_freq_range.min); //set default gains @@ -220,9 +218,12 @@ tvrx::~tvrx(void){ */ static std::string get_band(double freq) { + std::cout << "get_band called with freq " << freq << std::endl; BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { - if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) + if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max){ + std::cout << "Holy poop you're in band " << band << std::endl; return band; + } } UHD_THROW_INVALID_CODE_PATH(); } @@ -245,15 +246,25 @@ static float gain_interp(float gain, boost::array db_vector, boost::a boost::uint8_t gain_step = 0; //find which bin we're in for(size_t i = 0; i < db_vector.size()-1; i++) { - if(gain > db_vector[i] && gain < db_vector[i+1]) gain_step = i; + if(gain >= db_vector[i] && gain <= db_vector[i+1]) gain_step = i; } //find the current slope for linear interpolation float slope = (volts_vector[gain_step + 1] - volts_vector[gain_step]) / (db_vector[gain_step + 1] - db_vector[gain_step]); + + //the problem here is that for gains approaching the maximum, the voltage slope becomes infinite + //i.e., a small change in gain requires an infinite change in voltage + //to cope, we limit the slope + + if(slope == std::numeric_limits::infinity()) + return volts_vector[gain_step]; //use the volts per dB slope to find the final interpolated voltage volts = volts_vector[gain_step] + (slope * (gain - db_vector[gain_step])); + + if(tvrx_debug) + std::cout << "Gain interp: gain: " << gain << ", gain_step: " << int(gain_step) << ", slope: " << slope << ", volts: " << volts << std::endl; return volts; } @@ -276,6 +287,8 @@ static float rf_gain_to_voltage(float gain, double lo_freq){ float gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts); //this is the voltage at the USRP DAC output float dac_volts = gain_volts / opamp_gain; + + dac_volts = std::clip(dac_volts, 0.0, 3.3); if (tvrx_debug) std::cerr << boost::format( "tvrx RF AGC gain: %f dB, dac_volts: %f V" @@ -297,6 +310,8 @@ static float if_gain_to_voltage(float gain){ float gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts); float dac_volts = gain_volts / opamp_gain; + + dac_volts = std::clip(dac_volts, 0.0, 3.3); if (tvrx_debug) std::cerr << boost::format( "tvrx IF AGC gain: %f dB, dac_volts: %f V" @@ -324,13 +339,13 @@ void tvrx::set_gain(float gain, const std::string &name){ void tvrx::set_freq(double freq) { freq = std::clip(freq, tvrx_freq_range.min, tvrx_freq_range.max); - std::string prev_band = get_band(_lo_freq + tvrx_if_freq); + std::string prev_band = get_band(_lo_freq - tvrx_if_freq); std::string new_band = get_band(freq); - double lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing + double target_lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing double f_ref = reference_freq / double(reference_divider); //your tuning step size - int divisor = int(lo_freq + (f_ref * 4.0)) / (f_ref * 8); //the divisor we'll use + int divisor = int((target_lo_freq + (f_ref * 4.0)) / (f_ref * 8)); //the divisor we'll use double actual_lo_freq = (f_ref * 8 * divisor); //the LO freq we'll actually get if((divisor & ~0x7fff)) UHD_THROW_INVALID_CODE_PATH(); @@ -344,7 +359,7 @@ void tvrx::set_freq(double freq) { else if(new_band == "UHF") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_UHF; else UHD_THROW_INVALID_CODE_PATH(); - _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_ON; + _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_OFF; update_regs(); //ok don't forget to reset RF gain here if the new band != the old band @@ -352,6 +367,9 @@ void tvrx::set_freq(double freq) { //not FAR off, but we do this to be consistent if(prev_band != new_band) set_gain(_gains["RF"], "RF"); + if(tvrx_debug) + std::cout << boost::format("set_freq: target LO: %f f_ref: %f divisor: %i actual LO: %f") % target_lo_freq % f_ref % divisor % actual_lo_freq << std::endl; + _lo_freq = actual_lo_freq; //for rx props } @@ -386,7 +404,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = _lo_freq - tvrx_if_freq; + val = _lo_freq - 2*tvrx_if_freq; return; case SUBDEV_PROP_FREQ_RANGE: -- cgit v1.2.3 From 560cbf9a2900a02391f025a3fd50a1616893c8c7 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 18:04:35 -0700 Subject: TVRX: Fixed spectrum inversion (derp derp derp). Removed debug printing. --- host/lib/usrp/dboard/db_tvrx.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index f5b544c18..83a638810 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -54,7 +54,7 @@ using namespace boost::assign; /*********************************************************************** * The tvrx constants **********************************************************************/ -static const bool tvrx_debug = true; +static const bool tvrx_debug = false; static const freq_range_t tvrx_freq_range(50e6, 860e6); @@ -218,10 +218,9 @@ tvrx::~tvrx(void){ */ static std::string get_band(double freq) { - std::cout << "get_band called with freq " << freq << std::endl; BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max){ - std::cout << "Holy poop you're in band " << band << std::endl; + if(tvrx_debug) std::cout << "Band: " << band << std::endl; return band; } } @@ -404,7 +403,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = _lo_freq - 2*tvrx_if_freq; + val = _lo_freq; return; case SUBDEV_PROP_FREQ_RANGE: -- cgit v1.2.3 From 6fe533e19a29ea6cd241b70c38081499a8f3ba55 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 18:09:04 -0700 Subject: TVRX: Mixed up DAC channels. Gain is much more linear now. --- host/lib/usrp/dboard/db_tvrx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 83a638810..71aff1680 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -322,10 +322,10 @@ static float if_gain_to_voltage(float gain){ void tvrx::set_gain(float gain, const std::string &name){ assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name"); if (name == "RF"){ - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain, _lo_freq)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, rf_gain_to_voltage(gain, _lo_freq)); } else if(name == "IF"){ - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, if_gain_to_voltage(gain)); } else UHD_THROW_INVALID_CODE_PATH(); _gains[name] = gain; -- cgit v1.2.3 From 302078474312ad87db69a9c06b63e3f8a0c19cd5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Sep 2010 09:51:41 -0700 Subject: usrp1: fixed compile time warning, tweaked fw load message --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 5d73e6dd9..5043aed7d 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -180,7 +180,7 @@ public: unsigned char reset_n = 0; //hit the reset line - if (load_img_msg) std::cout << "Loading firmware image " << filestring << "..." << std::flush; + if (load_img_msg) std::cout << "Loading firmware image: " << filestring << "..." << std::flush; usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); @@ -272,7 +272,7 @@ public: size_t n = file.gcount(); ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); - if (ret != n) { + if (ret < 0 or size_t(ret) != n) { std::cerr << "fpga load error " << ret << std::endl; file.close(); return -1; -- cgit v1.2.3 From 543a63648f11d0e502e897f3cd98667005580c9e Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Sep 2010 15:35:54 -0700 Subject: usrp: transfer resize options and documentation --- host/docs/usrp1.rst | 27 ++++++ host/include/uhd/transport/usb_zero_copy.hpp | 24 +++-- host/lib/transport/libusb1_zero_copy.cpp | 140 ++++++++++++++------------- host/lib/usrp/usrp1/usrp1_impl.cpp | 26 +++-- 4 files changed, 137 insertions(+), 80 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index 3c1431d30..7cf447719 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -95,6 +95,27 @@ Notice that the subdevice name is always specified in the 3 possible cases. B:B + +------------------------------------------------------------------------ +Change USB transfer parameters +------------------------------------------------------------------------ +The advanced user may manipulate parameters of the usb bulk transfers +for various reasons, such as lowering latency or increasing buffer size. +By default, the UHD will use values for these parameters +that are known to perform well on a variety of systems. + +The following device address can be used to manipulate USB bulk transfers: + +* **recv_xfer_size:** the size of each receive bulk transfer in bytes +* **recv_num_xfers:** the number of simultaneous receive bulk transfers +* **send_xfer_size:** the size of each send bulk transfer in bytes +* **send_num_xfers:** the number of simultaneous send bulk transfers + +Example, set the args string to the following: +:: + + serial=12345678, recv_num_xfers=16 + ------------------------------------------------------------------------ OS Specific Notes ------------------------------------------------------------------------ @@ -113,3 +134,9 @@ so that non-root users may access the device: sudo mv tmpfile /etc/udev/rules.d/10-usrp.rules sudo udevadm control --reload-rules +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install libusb driver on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On Windows, a driver must be installed the first time the USRP1 is attached to the host computer. +A download link for this driver can be found on the Ettus Research UHD wiki page. +Download and unpack the driver, and direct the Windows driver install wizard to the *.inf file. diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 75232c22a..61bf380ba 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -45,16 +45,22 @@ public: * The underlying implementation may be platform specific. * * \param handle a device handle that uniquely identifying the device - * \param rx_endpoint an integer specifiying an IN endpoint number - * \param tx_endpoint an integer specifiying an OUT endpoint number - * \param buff_size total number of bytes of buffer space to allocate - * \param block_size number of bytes allocated for each I/O transaction + * \param recv_endpoint an integer specifiying an IN endpoint number + * \param send_endpoint an integer specifiying an OUT endpoint number + * \param recv_xfer_size the number of bytes for each receive transfer + * \param recv_num_xfers the number of simultaneous receive transfers + * \param send_xfer_size the number of bytes for each send transfer + * \param send_num_xfers the number of simultaneous send transfers */ - static sptr make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size = 0, - size_t block_size = 0); + static sptr make( + usb_device_handle::sptr handle, + unsigned int recv_endpoint, + unsigned int send_endpoint, + size_t recv_xfer_size = 0, + size_t recv_num_xfers = 0, + size_t send_xfer_size = 0, + size_t send_num_xfers = 0 + ); }; }} //namespace diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index b089d11e0..f2dcff6b5 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -30,6 +30,9 @@ using namespace uhd::transport; const int libusb_timeout = 0; +static const size_t DEFAULT_NUM_XFERS = 16; //num xfers +static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes + /*********************************************************************** * Helper functions ***********************************************************************/ @@ -56,7 +59,7 @@ void pp_transfer(libusb_transfer *lut) * create a bidirectional interface. It is a zero copy implementation * with respect to libusb, however, each send and recv requires a copy * operation from kernel to userspace; this is due to the usbfs - * interface provided by the kernel. + * interface provided by the kernel. **********************************************************************/ class usb_endpoint { public: @@ -107,7 +110,7 @@ private: //! a list of shared arrays for the transfer buffers std::vector > _buffers; - // Calls for processing asynchronous I/O + // Calls for processing asynchronous I/O libusb_transfer *allocate_transfer(int buff_len); void print_transfer_status(libusb_transfer *lut); }; @@ -142,7 +145,7 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){ * Constructor * Allocate libusb transfers and mark as free. For IN endpoints, * submit the transfers so that they're ready to return when - * data is available. + * data is available. */ usb_endpoint::usb_endpoint( libusb::device_handle::sptr handle, @@ -194,7 +197,7 @@ usb_endpoint::~usb_endpoint(void){ /* - * Allocate a libusb transfer + * Allocate a libusb transfer * The allocated transfer - and buffer it contains - is repeatedly * submitted, reaped, and reused and should not be freed until shutdown. * \param buff_len size of the individual buffer held by each transfer @@ -225,7 +228,7 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len){ * Asynchonous transfer submission * Submit a libusb transfer to libusb add pending status * \param lut pointer to libusb_transfer - * \return true on success or false on error + * \return true on success or false on error */ void usb_endpoint::submit(libusb_transfer *lut){ UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0); @@ -281,14 +284,14 @@ libusb_transfer *usb_endpoint::get_lut_with_wait(size_t timeout_ms){ } /*********************************************************************** - * Managed buffers + * Managed buffers **********************************************************************/ /* * Libusb managed receive buffer * Construct a recv buffer from a libusb transfer. The memory held by * the libusb transfer is exposed through the managed buffer interface. * Upon destruction, the transfer and buffer are resubmitted to the - * endpoint for further use. + * endpoint for further use. */ class libusb_managed_recv_buffer_impl : public managed_recv_buffer { public: @@ -307,7 +310,7 @@ public: private: const boost::asio::const_buffer &get() const { - return _buff; + return _buff; } libusb_transfer *_lut; @@ -327,9 +330,8 @@ private: class libusb_managed_send_buffer_impl : public managed_send_buffer { public: libusb_managed_send_buffer_impl(libusb_transfer *lut, - usb_endpoint::sptr endpoint, - size_t buff_size) - : _buff(lut->buffer, buff_size), _committed(false) + usb_endpoint::sptr endpoint) + : _buff(lut->buffer, lut->length), _committed(false) { _lut = lut; _endpoint = endpoint; @@ -349,7 +351,7 @@ public: std::cerr << "UHD: send buffer already committed" << std::endl; return 0; } - + UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff)); _lut->length = num_bytes; @@ -369,7 +371,7 @@ public: private: const boost::asio::mutable_buffer &get() const { - return _buff; + return _buff; } libusb_transfer *_lut; @@ -385,61 +387,71 @@ private: class libusb_zero_copy_impl : public usb_zero_copy { private: - usb_endpoint::sptr _rx_ep, _tx_ep; - libusb::device_handle::sptr _handle; - - size_t _recv_buff_size; - size_t _send_buff_size; - size_t _num_frames; + size_t _recv_num_frames, _send_num_frames; + usb_endpoint::sptr _recv_ep, _send_ep; public: typedef boost::shared_ptr sptr; - libusb_zero_copy_impl(libusb::device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t recv_buff_size, - size_t send_buff_size); + libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers + ); managed_recv_buffer::sptr get_recv_buff(void); managed_send_buffer::sptr get_send_buff(void); - size_t get_num_recv_frames(void) const { return _num_frames; } - size_t get_num_send_frames(void) const { return _num_frames; } + size_t get_num_recv_frames(void) const { return _recv_num_frames; } + size_t get_num_send_frames(void) const { return _send_num_frames; } }; /* * Constructor * Initializes libusb, opens devices, and sets up interfaces for I/O. - * Finally, creates endpoints for asynchronous I/O. + * Finally, creates endpoints for asynchronous I/O. */ -libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size, - size_t block_size) - : _handle(handle), - _recv_buff_size(block_size), _send_buff_size(block_size), - _num_frames(buff_size / block_size) -{ - _handle->claim_interface(2 /*in interface*/); +libusb_zero_copy_impl::libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers +){ + _handle = handle; + + //if the sizes are left at 0 (automatic) -> use the defaults + if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; + if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; + if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; + if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; + + //sanity check the transfer sizes + UHD_ASSERT_THROW(recv_xfer_size % 512 == 0); + UHD_ASSERT_THROW(send_xfer_size % 512 == 0); + + //store the num xfers for the num frames count + _recv_num_frames = recv_num_xfers; + _send_num_frames = send_num_xfers; + + _handle->claim_interface(2 /*in interface*/); _handle->claim_interface(1 /*out interface*/); - _rx_ep = usb_endpoint::sptr(new usb_endpoint( + _recv_ep = usb_endpoint::sptr(new usb_endpoint( _handle, // libusb device_handle - rx_endpoint, // USB endpoint number + recv_endpoint, // USB endpoint number true, // IN endpoint - _recv_buff_size, // buffer size per transfer - _num_frames // number of libusb transfers + recv_xfer_size, // buffer size per transfer + recv_num_xfers // number of libusb transfers )); - _tx_ep = usb_endpoint::sptr(new usb_endpoint( + _send_ep = usb_endpoint::sptr(new usb_endpoint( _handle, // libusb device_handle - tx_endpoint, // USB endpoint number + send_endpoint, // USB endpoint number false, // OUT endpoint - _send_buff_size, // buffer size per transfer - _num_frames // number of libusb transfers + send_xfer_size, // buffer size per transfer + send_num_xfers // number of libusb transfers )); } @@ -447,17 +459,17 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle, * Construct a managed receive buffer from a completed libusb transfer * (happy with buffer full of data) obtained from the receive endpoint. * Return empty pointer if no transfer is available (timeout or error). - * \return pointer to a managed receive buffer + * \return pointer to a managed receive buffer */ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ - libusb_transfer *lut = _rx_ep->get_lut_with_wait(/* TODO timeout API */); + libusb_transfer *lut = _recv_ep->get_lut_with_wait(/* TODO timeout API */); if (lut == NULL) { return managed_recv_buffer::sptr(); } else { return managed_recv_buffer::sptr( new libusb_managed_recv_buffer_impl(lut, - _rx_ep)); + _recv_ep)); } } @@ -466,38 +478,36 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ * Construct a managed send buffer from a free libusb transfer (with * empty buffer). Return empty pointer of no transfer is available * (timeout or error). - * \return pointer to a managed send buffer + * \return pointer to a managed send buffer */ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){ - libusb_transfer *lut = _tx_ep->get_lut_with_wait(/* TODO timeout API */); + libusb_transfer *lut = _send_ep->get_lut_with_wait(/* TODO timeout API */); if (lut == NULL) { return managed_send_buffer::sptr(); } else { return managed_send_buffer::sptr( new libusb_managed_send_buffer_impl(lut, - _tx_ep, - _send_buff_size)); + _send_ep)); } } - /*********************************************************************** * USB zero_copy make functions **********************************************************************/ -usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size, - size_t block_size) - -{ +usb_zero_copy::sptr usb_zero_copy::make( + usb_device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers +){ libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( boost::static_pointer_cast(handle)->get_device() )); - return sptr(new libusb_zero_copy_impl(dev_handle, - rx_endpoint, - tx_endpoint, - buff_size, - block_size)); + return sptr(new libusb_zero_copy_impl( + dev_handle, + recv_endpoint, send_endpoint, + recv_xfer_size, recv_num_xfers, + send_xfer_size, send_num_xfers + )); } diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index b4c23bf12..793e3027d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include using namespace uhd; @@ -107,6 +108,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) /*********************************************************************** * Make **********************************************************************/ +template static output_type cast_from_dev_addr( + const device_addr_t &device_addr, + const std::string &key, + output_type def_val +){ + return (device_addr.has_key(key))? + boost::lexical_cast(device_addr[key]) : def_val; +} + static device::sptr usrp1_make(const device_addr_t &device_addr) { //extract the FPGA path for the USRP1 @@ -130,11 +140,15 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - data_transport = usb_zero_copy::make(handle, // identifier - 6, // IN endpoint - 2, // OUT endpoint - 2 * (1 << 20), // buffer size - 16384); // transfer size + data_transport = usb_zero_copy::make( + handle, // identifier + 6, // IN endpoint + 2, // OUT endpoint + size_t(cast_from_dev_addr(device_addr, "recv_xfer_size", 0)), + size_t(cast_from_dev_addr(device_addr, "recv_num_xfers", 0)), + size_t(cast_from_dev_addr(device_addr, "send_xfer_size", 0)), + size_t(cast_from_dev_addr(device_addr, "send_num_xfers", 0)) + ); break; } } @@ -173,7 +187,7 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, //initialize the mboard mboard_init(); - //initialize the dboards + //initialize the dboards dboard_init(); //initialize the dsps -- cgit v1.2.3 From 83596f1feb73a15a1ef8741c1c520e8cae46c2a6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Sep 2010 17:43:26 -0700 Subject: usrp: added get codec rate to dboard iface --- host/include/uhd/usrp/dboard_iface.hpp | 9 +++++++++ host/lib/usrp/usrp1/dboard_iface.cpp | 5 +++++ host/lib/usrp/usrp2/dboard_iface.cpp | 4 ++++ 3 files changed, 18 insertions(+) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index c7db244f2..c430ecd3f 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -242,6 +242,15 @@ public: * \param enb true for enabled */ virtual void set_clock_enabled(unit_t unit, bool enb) = 0; + + /*! + * Get the rate of the codec. + * For rx, this is the rate the ADC feeds the DSP. + * For tx, this is the rate the DSP feeds the DAC. + * \param unit which unit rx or tx + * \return the codec rate in Hz + */ + virtual double get_codec_rate(unit_t unit) = 0; }; }} //namespace diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 4791b55ce..4f0549a37 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -93,6 +93,7 @@ public: std::vector get_clock_rates(unit_t); double get_clock_rate(unit_t); void set_clock_enabled(unit_t, bool); + double get_codec_rate(unit_t); private: usrp1_iface::sptr _iface; @@ -170,6 +171,10 @@ void usrp1_dboard_iface::set_clock_enabled(unit_t, bool) //TODO we can only enable for special case anyway... } +double usrp1_dboard_iface::get_codec_rate(unit_t){ + return _clock->get_master_clock_freq(); +} + /*********************************************************************** * GPIO **********************************************************************/ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index f6d2b718a..fdfbf0d17 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -61,6 +61,7 @@ public: double get_clock_rate(unit_t); std::vector get_clock_rates(unit_t); void set_clock_enabled(unit_t, bool); + double get_codec_rate(unit_t); void write_spi( unit_t unit, @@ -158,6 +159,9 @@ void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ } } +double usrp2_dboard_iface::get_codec_rate(unit_t){ + return _clock_ctrl->get_master_clock_rate(); +} /*********************************************************************** * GPIO **********************************************************************/ -- cgit v1.2.3 From 56751efbe6e0751a2b8cd0f7a31d5dfd07fec5dd Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 29 Sep 2010 18:27:08 -0700 Subject: TVRX: works for USRP and USRP2. --- host/lib/usrp/dboard/db_tvrx.cpp | 11 ++++++++++- host/lib/usrp/usrp1/codec_ctrl.cpp | 3 ++- host/lib/usrp/usrp1/dboard_iface.cpp | 6 ++++++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 71aff1680..6b71a3c6e 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -377,6 +377,7 @@ void tvrx::set_freq(double freq) { **********************************************************************/ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ named_prop_t key = named_prop_t::extract(key_); + int codec_rate; //handle the get request conditioned on the key switch(key.as()){ @@ -403,7 +404,15 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = _lo_freq; + /* + * so here we have to do some magic. because the TVRX uses a relatively high IF, + * we have to watch the sample rate to see if the IF will be aliased + * or if it will fall within Nyquist. + */ + codec_rate = this->get_iface()->get_codec_rate(dboard_iface::UNIT_RX); + if(codec_rate/2 > tvrx_if_freq) val = _lo_freq; + //ok take a deep breath i am positive there is an easier way to get this number + else val = _lo_freq - tvrx_if_freq - (tvrx_if_freq-codec_rate)*int(tvrx_if_freq / (codec_rate/2)); return; case SUBDEV_PROP_FREQ_RANGE: diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 33b18b196..4aa730573 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -423,7 +423,8 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq) /*********************************************************************** * Codec Control ADC buffer bypass - * Enable this for DC-coupled daughterboards (TVRX) + * Disable this for AC-coupled daughterboards (TVRX) + * By default it is initialized TRUE. **********************************************************************/ void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) { _ad9862_regs.byp_buffer_a = bypass; diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 4f0549a37..1ac15a46a 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -32,6 +32,8 @@ using namespace uhd; using namespace uhd::usrp; using namespace boost::assign; +static const dboard_id_t tvrx_id(0x0040); + class usrp1_dboard_iface : public dboard_iface { public: @@ -51,6 +53,10 @@ public: //init the clock rate shadows this->set_clock_rate(UNIT_RX, this->get_clock_rates(UNIT_RX).front()); this->set_clock_rate(UNIT_TX, this->get_clock_rates(UNIT_TX).front()); + + //yes this is evil but it's necessary for TVRX to work on USRP1 + if(_rx_dboard_id == tvrx_id) _codec->bypass_adc_buffers(false); + //else _codec->bypass_adc_buffers(false); //don't think this is necessary } ~usrp1_dboard_iface() -- cgit v1.2.3 From 04c74a3c74907e55e339f1568a1d5b4cdf190daf Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 10:07:13 -0700 Subject: usrp1: replace byteswap with htonx (it was wrong to just swap) also removed unused poke and peek 16 bit calls --- host/lib/usrp/usrp1/usrp1_iface.cpp | 16 ++-------------- host/lib/usrp/usrp1/usrp1_iface.hpp | 14 -------------- 2 files changed, 2 insertions(+), 28 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 5fd3987d5..64ced2905 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -49,7 +49,7 @@ public: ******************************************************************/ void poke32(boost::uint32_t addr, boost::uint32_t value) { - boost::uint32_t swapped = byteswap(value); + boost::uint32_t swapped = uhd::htonx(value); if (iface_debug) { std::cout.fill('0'); @@ -72,12 +72,6 @@ public: std::cerr << "USRP: failed memory write: " << ret << std::endl; } - void poke16(boost::uint32_t, boost::uint16_t) - { - //fpga only handles 32 bit writes - std::cerr << "USRP: unsupported operation: poke16()" << std::endl; - } - boost::uint32_t peek32(boost::uint32_t addr) { boost::uint32_t value_out; @@ -95,13 +89,7 @@ public: if (ret < 0) std::cerr << "USRP: failed memory read: " << ret << std::endl; - return byteswap(value_out); - } - - boost::uint16_t peek16(boost::uint32_t addr) - { - boost::uint32_t val = peek32(addr); - return boost::uint16_t(val & 0xff); + return uhd::ntohx(value_out); } /******************************************************************* diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp index 9a3fdd6bc..3f608584a 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.hpp +++ b/host/lib/usrp/usrp1/usrp1_iface.hpp @@ -53,20 +53,6 @@ public: */ virtual boost::uint32_t peek32(boost::uint32_t addr) = 0; - /*! - * Write a register (16 bits) - * \param addr the address - * \param data the 16bit data - */ - virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0; - - /*! - * read a register (16 bits) - * \param addr the address - * \return the 16bit data - */ - virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; - /*! * Perform an spi transaction. * \param which_slave the slave device number -- cgit v1.2.3 From a4f8ad59b2abc6d4b1a6c65aa2652083486e3065 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 11:05:33 -0700 Subject: usrp: added subdev enabled property the dboard manager will disable all subdevs at startup and shutdown setting the subdev spec will enable only the subdevs in use all dboards are currently implemented as always enabled nothing tested --- host/include/uhd/usrp/subdev_props.hpp | 1 + host/include/uhd/usrp/subdev_spec.hpp | 6 +++++- host/lib/usrp/dboard/db_basic_and_lf.cpp | 14 ++++++++++++++ host/lib/usrp/dboard/db_dbsrx.cpp | 7 +++++++ host/lib/usrp/dboard/db_rfx.cpp | 14 ++++++++++++++ host/lib/usrp/dboard/db_unknown.cpp | 14 ++++++++++++++ host/lib/usrp/dboard/db_wbx.cpp | 14 ++++++++++++++ host/lib/usrp/dboard/db_xcvr2450.cpp | 14 ++++++++++++++ host/lib/usrp/dboard_manager.cpp | 12 +++++++++++- host/lib/usrp/misc_utils.cpp | 17 +++++++++++++++++ host/lib/usrp/subdev_spec.cpp | 4 ++++ 11 files changed, 115 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp index cd07cb7a8..8f096ffe4 100644 --- a/host/include/uhd/usrp/subdev_props.hpp +++ b/host/include/uhd/usrp/subdev_props.hpp @@ -53,6 +53,7 @@ namespace uhd{ namespace usrp{ SUBDEV_PROP_ANTENNA_NAMES = 'A', //ro, prop_names_t SUBDEV_PROP_LO_LOCKED = 'L', //ro, bool SUBDEV_PROP_CONNECTION = 'c', //ro, subdev_conn_t + SUBDEV_PROP_ENABLED = 'e', //rw, bool SUBDEV_PROP_USE_LO_OFFSET = 'l', //ro, bool SUBDEV_PROP_RSSI = 'R', //ro, float SUBDEV_PROP_BANDWIDTH = 'B' //rw, double diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp index 2f32509b9..5de3bb3b8 100644 --- a/host/include/uhd/usrp/subdev_spec.hpp +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -19,6 +19,7 @@ #define INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP #include +#include #include #include @@ -27,7 +28,7 @@ namespace uhd{ namespace usrp{ /*! * A subdevice specification (daughterboard, subdevice) name pairing. */ - struct UHD_API subdev_spec_pair_t{ + struct UHD_API subdev_spec_pair_t : boost::equality_comparable{ //! The daughterboard name std::string db_name; @@ -45,6 +46,9 @@ namespace uhd{ namespace usrp{ ); }; + //! overloaded comparison operator for subdev_spec_pair_t + UHD_API bool operator==(const subdev_spec_pair_t &, const subdev_spec_pair_t &); + /*! * A list of (daughterboard name, subdevice name) pairs: * diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 4b0d8bf27..41f6f8002 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -149,6 +149,10 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = sd_name_to_conn[get_subdev_name()]; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -178,6 +182,9 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_FREQ: return; // it wont do you much good, but you can set it + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } @@ -241,6 +248,10 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ val = sd_name_to_conn[get_subdev_name()]; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -270,6 +281,9 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_FREQ: return; // it wont do you much good, but you can set it + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 81434f054..23cafea53 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -551,6 +551,10 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -587,6 +591,9 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){ this->set_gain(val.as(), key.name); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + case SUBDEV_PROP_BANDWIDTH: this->set_bandwidth(val.as()); return; diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index c3ab96e59..cfc34381e 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -444,6 +444,10 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_QI; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -474,6 +478,9 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ this->set_rx_ant(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } @@ -524,6 +531,10 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = true; return; @@ -554,6 +565,9 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ this->set_tx_ant(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp index f6f4f4a61..ec7ab440b 100644 --- a/host/lib/usrp/dboard/db_unknown.cpp +++ b/host/lib/usrp/dboard/db_unknown.cpp @@ -122,6 +122,10 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -151,6 +155,9 @@ void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_FREQ: return; // it wont do you much good, but you can set it + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } @@ -211,6 +218,10 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -240,6 +251,9 @@ void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_FREQ: return; // it wont do you much good, but you can set it + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index e473ce41e..907268aac 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -513,6 +513,10 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -543,6 +547,9 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ this->set_rx_ant(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } @@ -597,6 +604,10 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -627,6 +638,9 @@ void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ this->set_tx_ant(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 798ff74a3..0ee133f3d 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -484,6 +484,10 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -518,6 +522,9 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){ this->set_rx_ant(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } @@ -572,6 +579,10 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_QI; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -602,6 +613,9 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){ this->set_tx_ant(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 181f843a0..78daa1b4d 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -86,7 +86,7 @@ std::string dboard_id_t::to_pp_string(void) const{ } /*********************************************************************** - * internal helper classe + * internal helper classes **********************************************************************/ /*! * A special wax proxy object that forwards calls to a subdev. @@ -330,4 +330,14 @@ void dboard_manager_impl::set_nice_dboard_if(void){ _iface->set_pin_ctrl(unit, 0x0000); //all gpio _iface->set_clock_enabled(unit, false); //clock off } + + //disable all rx subdevices + BOOST_FOREACH(const std::string &sd_name, this->get_rx_subdev_names()){ + this->get_rx_subdev(sd_name)[SUBDEV_PROP_ENABLED] = false; + } + + //disable all tx subdevices + BOOST_FOREACH(const std::string &sd_name, this->get_tx_subdev_names()){ + this->get_tx_subdev(sd_name)[SUBDEV_PROP_ENABLED] = false; + } } diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index 5cfcdc8d3..05308baba 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -186,6 +187,22 @@ static void verify_xx_subdev_spec( "Validate %s subdev spec failed: %s\n %s" ) % xx_type % subdev_spec.to_string() % e.what())); } + + //now use the subdev spec to enable the subdevices in use and vice-versa + BOOST_FOREACH(const std::string &db_name, mboard[dboard_names_prop].as()){ + wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; + BOOST_FOREACH(const std::string &sd_name, dboard[DBOARD_PROP_SUBDEV_NAMES].as()){ + try{ + bool enable = std::has(subdev_spec, subdev_spec_pair_t(db_name, sd_name)); + dboard[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)][SUBDEV_PROP_ENABLED] = enable; + } + catch(const std::exception &e){ + throw std::runtime_error(str(boost::format( + "Cannot set enabled property on subdevice %s:%s\n %s" + ) % db_name % sd_name % e.what())); + } + } + } } void usrp::verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){ diff --git a/host/lib/usrp/subdev_spec.cpp b/host/lib/usrp/subdev_spec.cpp index 7a3e72867..95d2cbb12 100644 --- a/host/lib/usrp/subdev_spec.cpp +++ b/host/lib/usrp/subdev_spec.cpp @@ -34,6 +34,10 @@ subdev_spec_pair_t::subdev_spec_pair_t( /* NOP */ } +bool usrp::operator==(const subdev_spec_pair_t &lhs, const subdev_spec_pair_t &rhs){ + return (lhs.db_name == rhs.db_name) and (lhs.sd_name == rhs.sd_name); +} + subdev_spec_t::subdev_spec_t(const std::string &markup){ BOOST_FOREACH(const std::string &pair, std::split_string(markup)){ if (pair == "") continue; -- cgit v1.2.3 From 046d8a9a5a5b0addb7e6c8bfde7973f3051d48b1 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Thu, 30 Sep 2010 11:57:40 -0700 Subject: TVRX: Fixed to properly calculate alias frequencies. --- host/lib/usrp/dboard/db_tvrx.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 6b71a3c6e..1cb74c5ae 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -372,12 +372,30 @@ void tvrx::set_freq(double freq) { _lo_freq = actual_lo_freq; //for rx props } +/*********************************************************************** + * Get the alias frequency of frequency freq when sampled at fs. + * \param freq the frequency of interest + * \param fs the sample rate + * \return the alias frequency + **********************************************************************/ + +static double get_alias(double freq, double fs) { + double alias; + freq = fmod(freq, fs); + if(freq >= (fs/2)) { + alias = fs - freq; + } else { + alias = freq; + } + return alias; +} + /*********************************************************************** * RX Get and Set **********************************************************************/ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ named_prop_t key = named_prop_t::extract(key_); - int codec_rate; + double codec_rate; //handle the get request conditioned on the key switch(key.as()){ @@ -410,9 +428,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ * or if it will fall within Nyquist. */ codec_rate = this->get_iface()->get_codec_rate(dboard_iface::UNIT_RX); - if(codec_rate/2 > tvrx_if_freq) val = _lo_freq; - //ok take a deep breath i am positive there is an easier way to get this number - else val = _lo_freq - tvrx_if_freq - (tvrx_if_freq-codec_rate)*int(tvrx_if_freq / (codec_rate/2)); + val = (_lo_freq - tvrx_if_freq) + get_alias(tvrx_if_freq, codec_rate); return; case SUBDEV_PROP_FREQ_RANGE: -- cgit v1.2.3 From 2c8a7c7debf19d92065661cc1d258f97bd38e224 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 14:36:24 -0700 Subject: uhd: implemented recv timeout for zero copy interface --- host/include/uhd/transport/zero_copy.hpp | 11 +++++--- host/lib/transport/libusb1_zero_copy.cpp | 42 +++++++++++++++---------------- host/lib/transport/udp_zero_copy_asio.cpp | 5 ++-- host/lib/transport/zero_copy.cpp | 4 +-- host/lib/usrp/usrp1/io_impl.cpp | 8 +++--- host/lib/usrp/usrp2/io_impl.cpp | 5 ++-- 6 files changed, 39 insertions(+), 36 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 513291b63..8ecafd3fb 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -122,9 +122,10 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. + * \param timeout_ms the timeout to get the buffer in ms * \return a managed buffer, or null sptr on timeout/error */ - virtual managed_recv_buffer::sptr get_recv_buff(void) = 0; + virtual managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms) = 0; /*! * Get the maximum number of receive frames: @@ -171,16 +172,19 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. + * \param timeout_ms the timeout to get the buffer in ms + * \return a managed buffer, or null sptr on timeout/error */ - managed_recv_buffer::sptr get_recv_buff(void); + managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms); private: /*! * Perform a private copying recv. * \param buff the buffer to write data into + * \param timeout_ms the timeout to get the buffer in ms * \return the number of bytes written to buff, 0 for timeout, negative for error */ - virtual ssize_t recv(const boost::asio::mutable_buffer &buff) = 0; + virtual ssize_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms) = 0; UHD_PIMPL_DECL(impl) _impl; }; @@ -204,6 +208,7 @@ namespace uhd{ namespace transport{ /*! * Get a new send buffer from this transport object. + * \return a managed buffer, or null sptr on timeout/error */ managed_send_buffer::sptr get_send_buff(void); diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f2dcff6b5..f9beb0b4c 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -308,8 +308,7 @@ public: } private: - const boost::asio::const_buffer &get() const - { + const boost::asio::const_buffer &get(void) const{ return _buff; } @@ -369,8 +368,7 @@ public: } private: - const boost::asio::mutable_buffer &get() const - { + const boost::asio::mutable_buffer &get(void) const{ return _buff; } @@ -395,13 +393,13 @@ public: typedef boost::shared_ptr sptr; libusb_zero_copy_impl( - libusb::device_handle::sptr handle, - unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers - ); + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers + ); - managed_recv_buffer::sptr get_recv_buff(void); + managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms); managed_send_buffer::sptr get_send_buff(void); size_t get_num_recv_frames(void) const { return _recv_num_frames; } @@ -419,23 +417,23 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( size_t recv_xfer_size, size_t recv_num_xfers, size_t send_xfer_size, size_t send_num_xfers ){ - _handle = handle; + _handle = handle; - //if the sizes are left at 0 (automatic) -> use the defaults - if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; - if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; - if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; - if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; + //if the sizes are left at 0 (automatic) -> use the defaults + if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; + if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; + if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; + if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; //sanity check the transfer sizes UHD_ASSERT_THROW(recv_xfer_size % 512 == 0); UHD_ASSERT_THROW(send_xfer_size % 512 == 0); - //store the num xfers for the num frames count - _recv_num_frames = recv_num_xfers; - _send_num_frames = send_num_xfers; + //store the num xfers for the num frames count + _recv_num_frames = recv_num_xfers; + _send_num_frames = send_num_xfers; - _handle->claim_interface(2 /*in interface*/); + _handle->claim_interface(2 /*in interface*/); _handle->claim_interface(1 /*out interface*/); _recv_ep = usb_endpoint::sptr(new usb_endpoint( @@ -461,8 +459,8 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( * Return empty pointer if no transfer is available (timeout or error). * \return pointer to a managed receive buffer */ -managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ - libusb_transfer *lut = _recv_ep->get_lut_with_wait(/* TODO timeout API */); +managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(size_t timeout_ms){ + libusb_transfer *lut = _recv_ep->get_lut_with_wait(timeout_ms); if (lut == NULL) { return managed_recv_buffer::sptr(); } diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index ee989ee2b..0a6c9f2af 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -35,7 +35,6 @@ static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 2 //Perhaps this is due to the kernel scheduling, //but may change with host-based flow control. static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3); -static const double RECV_TIMEOUT = 0.1; //100 ms /*********************************************************************** * Zero Copy UDP implementation with ASIO: @@ -110,11 +109,11 @@ private: boost::asio::io_service _io_service; int _sock_fd; - ssize_t recv(const boost::asio::mutable_buffer &buff){ + ssize_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){ //setup timeval for timeout timeval tv; tv.tv_sec = 0; - tv.tv_usec = int(RECV_TIMEOUT*1e6); + tv.tv_usec = timeout_ms*1000; //setup rset for timeout fd_set rset; diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp index 8a1cde694..1fcf846a0 100644 --- a/host/lib/transport/zero_copy.cpp +++ b/host/lib/transport/zero_copy.cpp @@ -68,12 +68,12 @@ phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){ /* NOP */ } -managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(void){ +managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(size_t timeout_ms){ //allocate memory boost::uint8_t *recv_mem = new boost::uint8_t[_impl->max_buff_size]; //call recv() with timeout option - ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size)); + ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size), timeout_ms); if (num_bytes <= 0) return managed_recv_buffer::sptr(); //NULL sptr diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 73974f2d6..aee760a83 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -272,18 +272,18 @@ static void usrp1_bs_vrt_unpacker( } static bool get_recv_buffs( - zero_copy_if::sptr zc_if, + zero_copy_if::sptr zc_if, size_t timeout_ms, vrt_packet_handler::managed_recv_buffs_t &buffs ){ UHD_ASSERT_THROW(buffs.size() == 1); - buffs[0] = zc_if->get_recv_buff(); + buffs[0] = zc_if->get_recv_buff(timeout_ms); return buffs[0].get() != NULL; } size_t usrp1_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, size_t /*timeout_ms TODO*/ + recv_mode_t recv_mode, size_t timeout_ms ){ size_t num_samps_recvd = vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler @@ -292,7 +292,7 @@ size_t usrp1_impl::recv( io_type, _rx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_unpacker, - boost::bind(&get_recv_buffs, _data_transport, _1), + boost::bind(&get_recv_buffs, _data_transport, timeout_ms, _1), &vrt_packet_handler::handle_overflow_nop, 0, //vrt header offset _rx_subdev_spec.size() //num channels diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 65411801d..3395f94e2 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -33,6 +33,7 @@ using namespace uhd::transport; namespace asio = boost::asio; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; +static const double RECV_TIMEOUT_MS = 100; /*********************************************************************** * io impl details (internal to this file) @@ -90,7 +91,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); + managed_recv_buffer::sptr buff = zc_if->get_recv_buff(RECV_TIMEOUT_MS); if (not buff.get()) continue; //ignore timeout/error buffers try{ @@ -150,7 +151,7 @@ void usrp2_impl::io_init(void){ std::memcpy(send_buff->cast(), &data, sizeof(data)); send_buff->commit(sizeof(data)); //drain the recv buffers (may have junk) - while (data_transport->get_recv_buff().get()){}; + while (data_transport->get_recv_buff(RECV_TIMEOUT_MS).get()){}; } //the number of recv frames is the number for the first transport -- cgit v1.2.3 From cc97c6ee0b3dbc8e0ed6bfae01505fcb209d13cb Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 15:12:30 -0700 Subject: usrp-e: update to build with the master --- host/lib/usrp/usrp_e/dboard_iface.cpp | 5 +++++ host/lib/usrp/usrp_e/io_impl.cpp | 18 +++++------------- 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/dboard_iface.cpp b/host/lib/usrp/usrp_e/dboard_iface.cpp index 1bd177f60..6898df8df 100644 --- a/host/lib/usrp/usrp_e/dboard_iface.cpp +++ b/host/lib/usrp/usrp_e/dboard_iface.cpp @@ -91,6 +91,7 @@ public: std::vector get_clock_rates(unit_t); double get_clock_rate(unit_t); void set_clock_enabled(unit_t, bool); + double get_codec_rate(unit_t); private: usrp_e_iface::sptr _iface; @@ -140,6 +141,10 @@ void usrp_e_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ } } +double usrp_e_dboard_iface::get_codec_rate(unit_t){ + return _clock->get_fpga_clock_rate(); +} + /*********************************************************************** * GPIO **********************************************************************/ diff --git a/host/lib/usrp/usrp_e/io_impl.cpp b/host/lib/usrp/usrp_e/io_impl.cpp index 31ea4c6c0..e57d6ce35 100644 --- a/host/lib/usrp/usrp_e/io_impl.cpp +++ b/host/lib/usrp/usrp_e/io_impl.cpp @@ -39,6 +39,7 @@ static const size_t MAX_BUFF_SIZE = 2048; static const bool usrp_e_io_impl_verbose = false; static const size_t tx_async_report_sid = 1; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; +static const double recv_timeout_ms = 100; /*********************************************************************** * Data Transport (phony zero-copy with read/write) @@ -74,7 +75,7 @@ private: boost::asio::buffer_size(buff) ); } - ssize_t recv(const boost::asio::mutable_buffer &buff){ + ssize_t recv(const boost::asio::mutable_buffer &buff, size_t to_ms){ //std::cout << boost::format( // "calling read on fd %d, buff size is %d" //) % _fd % boost::asio::buffer_size(buff) << std::endl; @@ -84,7 +85,7 @@ private: pollfd pfd; pfd.fd = _fd; pfd.events = POLLIN; - ssize_t poll_ret = poll(&pfd, 1, 100/*ms*/); + ssize_t poll_ret = poll(&pfd, 1, to_ms); if (poll_ret <= 0){ if (usrp_e_io_impl_verbose) std::cerr << boost::format( "usrp-e io impl recv(): poll() returned non-positive value: %d\n" @@ -170,7 +171,7 @@ void usrp_e_impl::io_impl::recv_pirate_loop( //size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = this->transport.get_recv_buff(); + managed_recv_buffer::sptr buff = this->transport.get_recv_buff(recv_timeout_ms); if (not buff.get()) continue; //ignore timeout/error buffers try{ @@ -262,7 +263,7 @@ bool get_send_buffs( ){ UHD_ASSERT_THROW(buffs.size() == 1); buffs[0] = trans->get_send_buff(); - return buffs[0].get(); + return buffs[0].get() != NULL; } size_t usrp_e_impl::send( @@ -292,15 +293,6 @@ size_t usrp_e_impl::send( /*********************************************************************** * Data Recv **********************************************************************/ -bool get_recv_buffs( - data_transport *trans, - vrt_packet_handler::managed_recv_buffs_t &buffs -){ - UHD_ASSERT_THROW(buffs.size() == 1); - buffs[0] = trans->get_recv_buff(); - return buffs[0].get(); -} - size_t usrp_e_impl::recv( const std::vector &buffs, size_t num_samps, -- cgit v1.2.3 From 46d2fc423d2fdcf32454621c6f41e555d2496702 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 17:56:36 -0700 Subject: usrp-e: untested attempt at zero copy iface for mmap --- host/lib/usrp/usrp_e/CMakeLists.txt | 1 + host/lib/usrp/usrp_e/io_impl.cpp | 97 ++---------- host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp | 201 +++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 87 deletions(-) create mode 100644 host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/CMakeLists.txt b/host/lib/usrp/usrp_e/CMakeLists.txt index da759d931..bab868f90 100644 --- a/host/lib/usrp/usrp_e/CMakeLists.txt +++ b/host/lib/usrp/usrp_e/CMakeLists.txt @@ -54,6 +54,7 @@ IF(ENABLE_USRP_E) ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_impl.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_iface.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_regs.hpp ) ELSE(ENABLE_USRP_E) diff --git a/host/lib/usrp/usrp_e/io_impl.cpp b/host/lib/usrp/usrp_e/io_impl.cpp index e57d6ce35..0b5fa054b 100644 --- a/host/lib/usrp/usrp_e/io_impl.cpp +++ b/host/lib/usrp/usrp_e/io_impl.cpp @@ -22,8 +22,6 @@ #include #include "../../transport/vrt_packet_handler.hpp" #include -#include //read, write -#include #include #include #include @@ -32,90 +30,15 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; +zero_copy_if::sptr usrp_e_make_mmap_zero_copy(usrp_e_iface::sptr iface); + /*********************************************************************** * Constants **********************************************************************/ -static const size_t MAX_BUFF_SIZE = 2048; -static const bool usrp_e_io_impl_verbose = false; static const size_t tx_async_report_sid = 1; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; static const double recv_timeout_ms = 100; -/*********************************************************************** - * Data Transport (phony zero-copy with read/write) - **********************************************************************/ -class data_transport: - public transport::phony_zero_copy_recv_if, - public transport::phony_zero_copy_send_if -{ -public: - data_transport(int fd): - transport::phony_zero_copy_recv_if(MAX_BUFF_SIZE), - transport::phony_zero_copy_send_if(MAX_BUFF_SIZE), - _fd(fd) - { - /* NOP */ - } - - size_t get_num_recv_frames(void) const{ - return 100; //FIXME no idea! - //this will be an important number when packet ring gets implemented - } - - size_t get_num_send_frames(void) const{ - return 100; //FIXME no idea! - //this will be an important number when packet ring gets implemented - } - -private: - int _fd; - ssize_t send(const boost::asio::const_buffer &buff){ - return write(_fd, - boost::asio::buffer_cast(buff), - boost::asio::buffer_size(buff) - ); - } - ssize_t recv(const boost::asio::mutable_buffer &buff, size_t to_ms){ - //std::cout << boost::format( - // "calling read on fd %d, buff size is %d" - //) % _fd % boost::asio::buffer_size(buff) << std::endl; - - //setup and call poll on the file descriptor - //return 0 and do not read when poll times out - pollfd pfd; - pfd.fd = _fd; - pfd.events = POLLIN; - ssize_t poll_ret = poll(&pfd, 1, to_ms); - if (poll_ret <= 0){ - if (usrp_e_io_impl_verbose) std::cerr << boost::format( - "usrp-e io impl recv(): poll() returned non-positive value: %d\n" - " -> return 0 for timeout" - ) % poll_ret << std::endl; - return 0; //timeout - } - - //perform the blocking read(...) - ssize_t read_ret = read(_fd, - boost::asio::buffer_cast(buff), - boost::asio::buffer_size(buff) - ); - if (read_ret < 0){ - if (usrp_e_io_impl_verbose) std::cerr << boost::format( - "usrp-e io impl recv(): read() returned small value: %d\n" - " -> return -1 for error" - ) % read_ret << std::endl; - return -1; - } - - //std::cout << "len " << int(read_ret) << std::endl; - //for (size_t i = 0; i < 9; i++){ - // std::cout << boost::format(" 0x%08x") % boost::asio::buffer_cast(buff)[i] << std::endl; - //} - - return read_ret; - } -}; - /*********************************************************************** * io impl details (internal to this file) * - pirate crew of 1 @@ -127,11 +50,11 @@ struct usrp_e_impl::io_impl{ //state management for the vrt packet handler code vrt_packet_handler::recv_state packet_handler_recv_state; vrt_packet_handler::send_state packet_handler_send_state; - data_transport transport; + zero_copy_if::sptr data_xport; bool continuous_streaming; - io_impl(int fd): - transport(fd), - recv_pirate_booty(recv_booty_type::make(transport.get_num_recv_frames())), + io_impl(usrp_e_iface::sptr iface): + data_xport(usrp_e_make_mmap_zero_copy(iface)), + recv_pirate_booty(recv_booty_type::make(data_xport->get_num_recv_frames())), async_msg_fifo(bounded_buffer::make(100/*messages deep*/)) { /* NOP */ @@ -171,7 +94,7 @@ void usrp_e_impl::io_impl::recv_pirate_loop( //size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = this->transport.get_recv_buff(recv_timeout_ms); + managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(recv_timeout_ms); if (not buff.get()) continue; //ignore timeout/error buffers try{ @@ -229,7 +152,7 @@ void usrp_e_impl::io_init(void){ _iface->poke32(UE_REG_CTRL_TX_REPORT_SID, tx_async_report_sid); _iface->poke32(UE_REG_CTRL_TX_POLICY, UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET); - _io_impl = UHD_PIMPL_MAKE(io_impl, (_iface->get_file_descriptor())); + _io_impl = UHD_PIMPL_MAKE(io_impl, (_iface)); //spawn a pirate, yarrr! _io_impl->recv_pirate_crew.create_thread(boost::bind( @@ -258,7 +181,7 @@ void usrp_e_impl::handle_overrun(size_t){ * Data Send **********************************************************************/ bool get_send_buffs( - data_transport *trans, + zero_copy_if::sptr trans, vrt_packet_handler::managed_send_buffs_t &buffs ){ UHD_ASSERT_THROW(buffs.size() == 1); @@ -285,7 +208,7 @@ size_t usrp_e_impl::send( io_type, send_otw_type, //input and output types to convert MASTER_CLOCK_RATE, //master clock tick rate uhd::transport::vrt::if_hdr_pack_le, - boost::bind(&get_send_buffs, &_io_impl->transport, _1), + boost::bind(&get_send_buffs, _io_impl->data_xport, _1), get_max_send_samps_per_packet() ); } diff --git a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp new file mode 100644 index 000000000..0910caa6f --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp @@ -0,0 +1,201 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#include +#include +#include +#include //mmap +#include //getpagesize +#include //poll +#include +#include "usrp_e_iface.hpp" + +using namespace uhd; +using namespace uhd::transport; + +static const bool debug_verbose = false; + +/*********************************************************************** + * The managed receive buffer implementation + **********************************************************************/ +class usrp_e_mmap_managed_recv_buffer : public managed_recv_buffer{ +public: + usrp_e_mmap_managed_recv_buffer( + const void *mem, size_t len, ring_buffer_info *info + ): + _buff(mem, len), _info(info) + { + /* NOP */ + } + + ~usrp_e_mmap_managed_recv_buffer(void){ + _info->flags = RB_KERNEL; + } + +private: + const boost::asio::const_buffer &get(void) const{ + return _buff; + } + + const boost::asio::const_buffer _buff; + ring_buffer_info *_info; +}; + +/*********************************************************************** + * The managed send buffer implementation + **********************************************************************/ +class usrp_e_mmap_managed_send_buffer : public managed_send_buffer{ +public: + usrp_e_mmap_managed_send_buffer( + void *mem, size_t len, ring_buffer_info *info, int fd + ): + _buff(mem, len), _info(info), _fd(fd), _commited(false) + { + /* NOP */ + } + + ~usrp_e_mmap_managed_send_buffer(void){ + if (not _commited) this->commit(0); + } + + ssize_t commit(size_t num_bytes){ + _commited = true; + _info->len = num_bytes; + _info->flags = RB_USER; + ssize_t ret = ::write(_fd, NULL, 0); + return (ret < 0)? ret : num_bytes; + } + +private: + const boost::asio::mutable_buffer &get(void) const{ + return _buff; + } + + const boost::asio::mutable_buffer _buff; + ring_buffer_info *_info; + int _fd; + bool _commited; +}; + +/*********************************************************************** + * The zero copy interface implementation + **********************************************************************/ +class usrp_e_mmap_zero_copy_impl : public zero_copy_if{ +public: + usrp_e_mmap_zero_copy_impl(usrp_e_iface::sptr iface): + _fd(iface->get_file_descriptor()), _recv_index(0), _send_index(0) + { + //get system sizes + iface->ioctl(USRP_E_GET_RB_INFO, &_rb_size); + size_t page_size = getpagesize(); + _frame_size = page_size/2; + + //calculate the memory size + size_t map_size = + (_rb_size.num_pages_rx_flags + _rb_size.num_pages_tx_flags) * page_size + + (_rb_size.num_rx_frames + _rb_size.num_tx_frames) * _frame_size; + + //call mmap to get the memory + void *ring_buffer = mmap( + NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0 + ); + UHD_ASSERT_THROW(ring_buffer != MAP_FAILED); + + //calculate the memory offsets for info and buffers + size_t recv_info_off = 0; + size_t recv_buff_off = recv_info_off + (_rb_size.num_pages_rx_flags * page_size); + size_t send_info_off = recv_buff_off + (_rb_size.num_rx_frames * _frame_size); + size_t send_buff_off = send_info_off + (_rb_size.num_pages_tx_flags * page_size); + + //set the internal pointers for info and buffers + typedef ring_buffer_info (*rbi_pta)[]; + boost::uint8_t *rb_ptr = reinterpret_cast(ring_buffer); + _recv_info = reinterpret_cast(rb_ptr + recv_info_off); + _recv_buff = rb_ptr + recv_buff_off; + _send_info = reinterpret_cast(rb_ptr + send_info_off); + _send_buff = rb_ptr + send_buff_off; + } + + managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms){ + //grab pointers to the info and buffer + ring_buffer_info *info = (*_recv_info) + _recv_index; + void *mem = _recv_buff + _frame_size*_recv_index; + + //poll/wait for a ready frame + if (not (info->flags & RB_USER)){ + pollfd pfd; + pfd.fd = _fd; + pfd.events = POLLIN; + ssize_t poll_ret = poll(&pfd, 1, timeout_ms); + if (poll_ret <= 0) return managed_recv_buffer::sptr(); + } + + //increment the index for the next call + if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0; + + //return the managed buffer for this frame + return managed_recv_buffer::sptr( + new usrp_e_mmap_managed_recv_buffer(mem, info->len, info) + ); + } + + size_t get_num_recv_frames(void) const{ + return _rb_size.num_rx_frames; + } + + managed_send_buffer::sptr get_send_buff(void){ + //grab pointers to the info and buffer + ring_buffer_info *info = (*_send_info) + _send_index; + void *mem = _send_buff + _frame_size*_send_index; + + //poll/wait for a ready frame + if (not (info->flags & RB_KERNEL)){ + pollfd pfd; + pfd.fd = _fd; + pfd.events = POLLOUT; + ssize_t poll_ret = poll(&pfd, 1, -1 /*forever*/); + if (poll_ret <= 0) return managed_send_buffer::sptr(); + } + + //increment the index for the next call + if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0; + + //return the managed buffer for this frame + return managed_send_buffer::sptr( + new usrp_e_mmap_managed_send_buffer(mem, _frame_size, info, _fd) + ); + } + + size_t get_num_send_frames(void) const{ + return _rb_size.num_tx_frames; + } + +private: + int _fd; + usrp_e_ring_buffer_size_t _rb_size; + size_t _frame_size; + ring_buffer_info (*_recv_info)[], (*_send_info)[]; + boost::uint8_t *_recv_buff, *_send_buff; + size_t _recv_index, _send_index; +}; + +/*********************************************************************** + * The zero copy interface make function + **********************************************************************/ +zero_copy_if::sptr usrp_e_make_mmap_zero_copy(usrp_e_iface::sptr iface){ + return zero_copy_if::sptr(new usrp_e_mmap_zero_copy_impl(iface)); +} -- cgit v1.2.3 From 67e302ee255922c021ce2c12efdbbaad46a787dc Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Fri, 1 Oct 2010 11:07:11 -0700 Subject: TVRX: fixed antenna prop enumeration --- host/lib/usrp/dboard/db_tvrx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 1cb74c5ae..41c52fbf5 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -58,7 +58,7 @@ static const bool tvrx_debug = false; static const freq_range_t tvrx_freq_range(50e6, 860e6); -static const std::string tvrx_antennas = std::string(""); //only got one +static const prop_names_t tvrx_antennas = list_of(""); //only got one static const uhd::dict tvrx_freq_ranges = map_list_of ("VHFLO", freq_range_t(50e6, 158e6)) @@ -436,7 +436,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_ANTENNA: - val = std::string(tvrx_antennas); + val = std::string(""); return; case SUBDEV_PROP_ANTENNA_NAMES: -- cgit v1.2.3 From 348b5b12ad9ec916c92d642bfb28e47264473535 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 1 Oct 2010 11:54:22 -0700 Subject: usb: catch open errors and print message, device: catch exceptions at discovery time --- host/lib/device.cpp | 18 ++++++++++++------ host/lib/transport/libusb1_base.cpp | 16 +++++++++++----- host/lib/usrp/usrp1/usrp1_impl.cpp | 28 +++++++++++++--------------- 3 files changed, 36 insertions(+), 26 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/device.cpp b/host/lib/device.cpp index d575ebaab..386588a08 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace uhd; @@ -73,12 +74,17 @@ device_addrs_t device::find(const device_addr_t &hint){ device_addrs_t device_addrs; BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){ - device_addrs_t discovered_addrs = fcn.get<0>()(hint); - device_addrs.insert( - device_addrs.begin(), - discovered_addrs.begin(), - discovered_addrs.end() - ); + try{ + device_addrs_t discovered_addrs = fcn.get<0>()(hint); + device_addrs.insert( + device_addrs.begin(), + discovered_addrs.begin(), + discovered_addrs.end() + ); + } + catch(const std::exception &e){ + std::cerr << "Device discovery error: " << e.what() << std::endl; + } } return device_addrs; diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 49f524a32..910b04fc8 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -213,15 +213,21 @@ private: libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::sptr dev){ static uhd::dict > handles; - //not expired -> get existing session + //not expired -> get existing handle if (handles.has_key(dev->get()) and not handles[dev->get()].expired()){ return handles[dev->get()].lock(); } - //create a new global session - sptr new_handle(new libusb_device_handle_impl(dev)); - handles[dev->get()] = new_handle; - return new_handle; + //create a new cached handle + try{ + sptr new_handle(new libusb_device_handle_impl(dev)); + handles[dev->get()] = new_handle; + return new_handle; + } + catch(const std::exception &e){ + std::cerr << "USB open failed: see the application notes for your device." << std::endl; + throw std::runtime_error(e.what()); + } } /*********************************************************************** diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 793e3027d..156fc119f 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -83,9 +83,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) //find the usrps and load firmware BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { - usb_control::sptr ctrl_transport = usb_control::make(handle); - usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); - usrp_ctrl->usrp_load_firmware(usrp1_fw_image); + usrp_ctrl::make(usb_control::make(handle))->usrp_load_firmware(usrp1_fw_image); } //get descriptors again with serial number, but using the initialized VID/PID now since we have firmware @@ -93,13 +91,13 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) pid = USRP1_PRODUCT_ID; BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { - device_addr_t new_addr; - new_addr["type"] = "usrp1"; - new_addr["serial"] = handle->get_serial(); - //this is a found usrp1 when a hint serial is not specified or it matches - if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){ - usrp1_addrs.push_back(new_addr); - } + device_addr_t new_addr; + new_addr["type"] = "usrp1"; + new_addr["serial"] = handle->get_serial(); + //this is a found usrp1 when a hint serial is not specified or it matches + if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){ + usrp1_addrs.push_back(new_addr); + } } return usrp1_addrs; @@ -109,12 +107,12 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) * Make **********************************************************************/ template static output_type cast_from_dev_addr( - const device_addr_t &device_addr, - const std::string &key, - output_type def_val + const device_addr_t &device_addr, + const std::string &key, + output_type def_val ){ - return (device_addr.has_key(key))? - boost::lexical_cast(device_addr[key]) : def_val; + return (device_addr.has_key(key))? + boost::lexical_cast(device_addr[key]) : def_val; } static device::sptr usrp1_make(const device_addr_t &device_addr) -- cgit v1.2.3 From 00cd6018405b57a0982b0ce103ff858c646ee18c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 1 Oct 2010 18:22:41 -0700 Subject: uhd: implemented a double timeout (in seconds) for send and recv chains converted all size_t timeout_ms to double timeout bounded and alignment buffer now take double timeout added timeout to device::send and zero_copy_if::get_send_buff --- host/include/uhd/device.hpp | 27 ++++++++------ host/include/uhd/device.ipp | 9 +++-- host/include/uhd/transport/alignment_buffer.hpp | 9 ++--- host/include/uhd/transport/alignment_buffer.ipp | 15 +++----- host/include/uhd/transport/bounded_buffer.hpp | 12 ++---- host/include/uhd/transport/bounded_buffer.ipp | 15 ++++++-- host/include/uhd/transport/zero_copy.hpp | 18 +++++---- host/lib/transport/libusb1_zero_copy.cpp | 42 ++++++++++----------- host/lib/transport/udp_zero_copy_asio.cpp | 4 +- host/lib/transport/vrt_packet_handler.hpp | 49 +++++++++++++------------ host/lib/transport/zero_copy.cpp | 6 +-- host/lib/usrp/usrp1/io_impl.cpp | 20 +++++----- host/lib/usrp/usrp1/usrp1_impl.cpp | 4 +- host/lib/usrp/usrp1/usrp1_impl.hpp | 7 ++-- host/lib/usrp/usrp2/io_impl.cpp | 32 ++++++++-------- host/lib/usrp/usrp2/usrp2_impl.hpp | 6 +-- host/test/buffer_test.cpp | 2 +- 17 files changed, 140 insertions(+), 137 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 2077cae62..992276928 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -41,9 +41,6 @@ public: typedef boost::function find_t; typedef boost::function make_t; - //! A reasonable default timeout for receive - static const size_t default_recv_timeout_ms = 100; - /*! * Register a device into the discovery and factory system. * @@ -112,12 +109,15 @@ public: * * This is a blocking call and will not return until the number * of samples returned have been read out of each buffer. + * Under a timeout condition, the number of samples returned + * may be less than the number of samples specified. * * \param buffs a vector of read-only memory containing IF data * \param nsamps_per_buff the number of samples to send, per buffer * \param metadata data describing the buffer's contents * \param io_type the type of data loaded in the buffer * \param send_mode tells send how to unload the buffer + * \param timeout the timeout in seconds to wait on a packet * \return the number of samples sent */ virtual size_t send( @@ -125,7 +125,8 @@ public: size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, + double timeout = 0.1 ) = 0; /*! @@ -136,7 +137,8 @@ public: size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, + double timeout = 0.1 ); /*! @@ -154,7 +156,9 @@ public: * See the rx metadata fragment flags and offset fields for details. * * This is a blocking call and will not return until the number - * of samples returned have been written into each buffer or timeout. + * of samples returned have been written into each buffer. + * Under a timeout condition, the number of samples returned + * may be less than the number of samples specified. * * When using the full buffer recv mode, the metadata only applies * to the first packet received and written into the recv buffers. @@ -165,7 +169,7 @@ public: * \param metadata data to fill describing the buffer * \param io_type the type of data to fill into the buffer * \param recv_mode tells recv how to load the buffer - * \param timeout_ms the timeout in milliseconds to wait for a packet + * \param timeout the timeout in seconds to wait for a packet * \return the number of samples received or 0 on error */ virtual size_t recv( @@ -174,7 +178,7 @@ public: rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, - size_t timeout_ms = default_recv_timeout_ms + double timeout = 0.1 ) = 0; /*! @@ -186,7 +190,7 @@ public: rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, - size_t timeout_ms = default_recv_timeout_ms + double timeout = 0.1 ); /*! @@ -204,12 +208,11 @@ public: /*! * Receive and asynchronous message from the device. * \param async_metadata the metadata to be filled in - * \param timeout_ms the timeout in milliseconds to wait for a message + * \param timeout the timeout in seconds to wait for a message * \return true when the async_metadata is valid, false for timeout */ virtual bool recv_async_msg( - async_metadata_t &async_metadata, - size_t timeout_ms = default_recv_timeout_ms + async_metadata_t &async_metadata, double timeout = 0.1 ) = 0; }; diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp index 60a3f535d..e2e51ecd0 100644 --- a/host/include/uhd/device.ipp +++ b/host/include/uhd/device.ipp @@ -25,12 +25,13 @@ namespace uhd{ size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, + double timeout ){ return this->send( std::vector(1, buff), nsamps_per_buff, metadata, - io_type, send_mode + io_type, send_mode, timeout ); } @@ -40,12 +41,12 @@ namespace uhd{ rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, - size_t timeout_ms + double timeout ){ return this->recv( std::vector(1, buff), nsamps_per_buff, metadata, - io_type, recv_mode, timeout_ms + io_type, recv_mode, timeout ); } diff --git a/host/include/uhd/transport/alignment_buffer.hpp b/host/include/uhd/transport/alignment_buffer.hpp index 29ba74efc..f44a037f8 100644 --- a/host/include/uhd/transport/alignment_buffer.hpp +++ b/host/include/uhd/transport/alignment_buffer.hpp @@ -48,20 +48,17 @@ namespace uhd{ namespace transport{ * \return true if the element fit without popping for space */ virtual bool push_with_pop_on_full( - const elem_type &elem, - const seq_type &seq, - size_t index + const elem_type &elem, const seq_type &seq, size_t index ) = 0; /*! * Pop an aligned set of elements from this alignment buffer. * \param elems a collection to store the aligned elements - * \param time the timeout time + * \param timeout the timeout in seconds * \return false when the operation times out */ virtual bool pop_elems_with_timed_wait( - std::vector &elems, - const time_duration_t &time + std::vector &elems, double timeout ) = 0; }; diff --git a/host/include/uhd/transport/alignment_buffer.ipp b/host/include/uhd/transport/alignment_buffer.ipp index 61b3b60f5..5f09de0d9 100644 --- a/host/include/uhd/transport/alignment_buffer.ipp +++ b/host/include/uhd/transport/alignment_buffer.ipp @@ -41,9 +41,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ } UHD_INLINE bool push_with_pop_on_full( - const elem_type &elem, - const seq_type &seq, - size_t index + const elem_type &elem, const seq_type &seq, size_t index ){ //clear the buffer for this index if the seqs are mis-ordered if (seq < _last_seqs[index]){ @@ -54,17 +52,16 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ } UHD_INLINE bool pop_elems_with_timed_wait( - std::vector &elems, - const time_duration_t &time + std::vector &elems, double timeout ){ - boost::system_time exit_time = boost::get_system_time() + time; + boost::system_time exit_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1e6)); buff_contents_type buff_contents_tmp; std::list indexes_to_do(_all_indexes); //do an initial pop to load an initial sequence id size_t index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait( - buff_contents_tmp, exit_time - boost::get_system_time() + buff_contents_tmp, 1e-6*(exit_time - boost::get_system_time()).total_microseconds() )) return false; elems[index] = buff_contents_tmp.first; seq_type expected_seq_id = buff_contents_tmp.second; @@ -79,7 +76,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ indexes_to_do = _all_indexes; index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait( - buff_contents_tmp, exit_time - boost::get_system_time() + buff_contents_tmp, 1e-6*(exit_time - boost::get_system_time()).total_microseconds() )) return false; elems[index] = buff_contents_tmp.first; expected_seq_id = buff_contents_tmp.second; @@ -89,7 +86,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ //pop an element off for this index index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait( - buff_contents_tmp, exit_time - boost::get_system_time() + buff_contents_tmp, 1e-6*(exit_time - boost::get_system_time()).total_microseconds() )) return false; //if the sequence id matches: diff --git a/host/include/uhd/transport/bounded_buffer.hpp b/host/include/uhd/transport/bounded_buffer.hpp index d1deece96..aca93b071 100644 --- a/host/include/uhd/transport/bounded_buffer.hpp +++ b/host/include/uhd/transport/bounded_buffer.hpp @@ -20,13 +20,9 @@ #include #include -#include namespace uhd{ namespace transport{ - //! typedef for the time duration type for wait operations - typedef boost::posix_time::time_duration time_duration_t; - /*! * Implement a templated bounded buffer: * Used for passing elements between threads in a producer-consumer model. @@ -64,10 +60,10 @@ namespace uhd{ namespace transport{ * Push a new element into the bounded_buffer. * Wait until the bounded_buffer becomes non-full or timeout. * \param elem the new element to push - * \param time the timeout time + * \param timeout the timeout in seconds * \return false when the operation times out */ - virtual bool push_with_timed_wait(const elem_type &elem, const time_duration_t &time) = 0; + virtual bool push_with_timed_wait(const elem_type &elem, double timeout) = 0; /*! * Pop an element from the bounded_buffer. @@ -80,10 +76,10 @@ namespace uhd{ namespace transport{ * Pop an element from the bounded_buffer. * Wait until the bounded_buffer becomes non-empty or timeout. * \param elem the element reference pop to - * \param time the timeout time + * \param timeout the timeout in seconds * \return false when the operation times out */ - virtual bool pop_with_timed_wait(elem_type &elem, const time_duration_t &time) = 0; + virtual bool pop_with_timed_wait(elem_type &elem, double timeout) = 0; /*! * Clear all elements from the bounded_buffer. diff --git a/host/include/uhd/transport/bounded_buffer.ipp b/host/include/uhd/transport/bounded_buffer.ipp index e106e229e..71143741e 100644 --- a/host/include/uhd/transport/bounded_buffer.ipp +++ b/host/include/uhd/transport/bounded_buffer.ipp @@ -21,6 +21,7 @@ #include #include #include +#include namespace uhd{ namespace transport{ namespace{ /*anon*/ @@ -57,9 +58,12 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ _empty_cond.notify_one(); } - bool push_with_timed_wait(const elem_type &elem, const time_duration_t &time){ + bool push_with_timed_wait(const elem_type &elem, double timeout){ boost::unique_lock lock(_mutex); - if (not _full_cond.timed_wait(lock, time, boost::bind(&bounded_buffer_impl::not_full, this))) return false; + if (not _full_cond.timed_wait( + lock, boost::posix_time::microseconds(long(timeout*1e6)), + boost::bind(&bounded_buffer_impl::not_full, this) + )) return false; _buffer.push_front(elem); lock.unlock(); _empty_cond.notify_one(); @@ -74,9 +78,12 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ _full_cond.notify_one(); } - bool pop_with_timed_wait(elem_type &elem, const time_duration_t &time){ + bool pop_with_timed_wait(elem_type &elem, double timeout){ boost::unique_lock lock(_mutex); - if (not _empty_cond.timed_wait(lock, time, boost::bind(&bounded_buffer_impl::not_empty, this))) return false; + if (not _empty_cond.timed_wait( + lock, boost::posix_time::microseconds(long(timeout*1e6)), + boost::bind(&bounded_buffer_impl::not_empty, this) + )) return false; elem = _buffer.back(); _buffer.pop_back(); lock.unlock(); _full_cond.notify_one(); diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 8ecafd3fb..ba19b193c 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -122,10 +122,10 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. - * \param timeout_ms the timeout to get the buffer in ms + * \param timeout the timeout to get the buffer in seconds * \return a managed buffer, or null sptr on timeout/error */ - virtual managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms) = 0; + virtual managed_recv_buffer::sptr get_recv_buff(double timeout = 0.1) = 0; /*! * Get the maximum number of receive frames: @@ -138,9 +138,10 @@ namespace uhd{ namespace transport{ /*! * Get a new send buffer from this transport object. + * \param timeout the timeout to get the buffer in seconds * \return a managed buffer, or null sptr on timeout/error */ - virtual managed_send_buffer::sptr get_send_buff(void) = 0; + virtual managed_send_buffer::sptr get_send_buff(double timeout = 0.1) = 0; /*! * Get the maximum number of send frames: @@ -172,19 +173,19 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. - * \param timeout_ms the timeout to get the buffer in ms + * \param timeout the timeout to get the buffer in seconds * \return a managed buffer, or null sptr on timeout/error */ - managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms); + managed_recv_buffer::sptr get_recv_buff(double timeout); private: /*! * Perform a private copying recv. * \param buff the buffer to write data into - * \param timeout_ms the timeout to get the buffer in ms + * \param timeout the timeout to get the buffer in seconds * \return the number of bytes written to buff, 0 for timeout, negative for error */ - virtual ssize_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms) = 0; + virtual ssize_t recv(const boost::asio::mutable_buffer &buff, double timeout) = 0; UHD_PIMPL_DECL(impl) _impl; }; @@ -208,9 +209,10 @@ namespace uhd{ namespace transport{ /*! * Get a new send buffer from this transport object. + * \param timeout the timeout to get the buffer in seconds * \return a managed buffer, or null sptr on timeout/error */ - managed_send_buffer::sptr get_send_buff(void); + managed_send_buffer::sptr get_send_buff(double timeout); private: /*! diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f9beb0b4c..7f2bc3468 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -24,12 +24,10 @@ #include #include #include -#include using namespace uhd::transport; -const int libusb_timeout = 0; - +static const double CLEANUP_TIMEOUT = 0.2; //seconds static const size_t DEFAULT_NUM_XFERS = 16; //num xfers static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes @@ -84,10 +82,10 @@ public: * Get an available transfer: * For inputs, this is a just filled transfer. * For outputs, this is a just emptied transfer. - * \param timeout_ms the timeout to wait for a lut + * \param timeout the timeout to wait for a lut * \return the transfer pointer or NULL if timeout */ - libusb_transfer *get_lut_with_wait(size_t timeout_ms = 100); + libusb_transfer *get_lut_with_wait(double timeout); //Callback use only void callback_handle_transfer(libusb_transfer *lut); @@ -187,7 +185,7 @@ usb_endpoint::~usb_endpoint(void){ } //collect canceled transfers (drain the queue) - while (this->get_lut_with_wait() != NULL){}; + while (this->get_lut_with_wait(CLEANUP_TIMEOUT) != NULL){}; //free all transfers BOOST_FOREACH(libusb_transfer *lut, _all_luts){ @@ -274,12 +272,10 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut){ } } -libusb_transfer *usb_endpoint::get_lut_with_wait(size_t timeout_ms){ +libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){ boost::this_thread::disable_interruption di; //disable because the wait can throw libusb_transfer *lut; - if (_completed_list->pop_with_timed_wait( - lut, boost::posix_time::milliseconds(timeout_ms) - )) return lut; + if (_completed_list->pop_with_timed_wait(lut, timeout)) return lut; return NULL; } @@ -399,8 +395,8 @@ public: size_t send_xfer_size, size_t send_num_xfers ); - managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms); - managed_send_buffer::sptr get_send_buff(void); + managed_recv_buffer::sptr get_recv_buff(double); + managed_send_buffer::sptr get_send_buff(double); size_t get_num_recv_frames(void) const { return _recv_num_frames; } size_t get_num_send_frames(void) const { return _send_num_frames; } @@ -459,8 +455,8 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( * Return empty pointer if no transfer is available (timeout or error). * \return pointer to a managed receive buffer */ -managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(size_t timeout_ms){ - libusb_transfer *lut = _recv_ep->get_lut_with_wait(timeout_ms); +managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(double timeout){ + libusb_transfer *lut = _recv_ep->get_lut_with_wait(timeout); if (lut == NULL) { return managed_recv_buffer::sptr(); } @@ -478,8 +474,8 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(size_t timeout_ms * (timeout or error). * \return pointer to a managed send buffer */ -managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){ - libusb_transfer *lut = _send_ep->get_lut_with_wait(/* TODO timeout API */); +managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){ + libusb_transfer *lut = _send_ep->get_lut_with_wait(timeout); if (lut == NULL) { return managed_send_buffer::sptr(); } @@ -494,18 +490,18 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){ * USB zero_copy make functions **********************************************************************/ usb_zero_copy::sptr usb_zero_copy::make( - usb_device_handle::sptr handle, + usb_device_handle::sptr handle, unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers ){ libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( boost::static_pointer_cast(handle)->get_device() )); return sptr(new libusb_zero_copy_impl( - dev_handle, - recv_endpoint, send_endpoint, - recv_xfer_size, recv_num_xfers, - send_xfer_size, send_num_xfers + dev_handle, + recv_endpoint, send_endpoint, + recv_xfer_size, recv_num_xfers, + send_xfer_size, send_num_xfers )); } diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 0a6c9f2af..3130830a5 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -109,11 +109,11 @@ private: boost::asio::io_service _io_service; int _sock_fd; - ssize_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){ + ssize_t recv(const boost::asio::mutable_buffer &buff, double timeout){ //setup timeval for timeout timeval tv; tv.tv_sec = 0; - tv.tv_usec = timeout_ms*1000; + tv.tv_usec = long(timeout*1e6); //setup rset for timeout fd_set rset; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index b603f1371..e11afff30 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -303,18 +303,18 @@ template UHD_INLINE T get_context_code( * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send ******************************************************************/ - static UHD_INLINE void _send1( + static UHD_INLINE size_t _send1( send_state &state, const std::vector &buffs, - size_t offset_bytes, - size_t num_samps, + const size_t offset_bytes, + const size_t num_samps, uhd::transport::vrt::if_packet_info_t &if_packet_info, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, const vrt_packer_t &vrt_packer, const get_send_buffs_t &get_send_buffs, - size_t vrt_header_offset_words32, - size_t chans_per_otw_buff + const size_t vrt_header_offset_words32, + const size_t chans_per_otw_buff ){ //load the rest of the if_packet_info in here if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t); @@ -322,7 +322,7 @@ template UHD_INLINE T get_context_code( //get send buffers for each channel managed_send_buffs_t send_buffs(buffs.size()/chans_per_otw_buff); - UHD_ASSERT_THROW(get_send_buffs(send_buffs)); + if (not get_send_buffs(send_buffs)) return 0; std::vector io_buffs(chans_per_otw_buff); for (size_t i = 0; i < buffs.size(); i+=chans_per_otw_buff){ @@ -347,6 +347,7 @@ template UHD_INLINE T get_context_code( std::cerr << "commit to send buffer returned less than commit size" << std::endl; } } + return num_samps; } /******************************************************************* @@ -381,7 +382,6 @@ template UHD_INLINE T get_context_code( //////////////////////////////////////////////////////////////// case uhd::device::SEND_MODE_ONE_PACKET:{ //////////////////////////////////////////////////////////////// - size_t num_samps = std::min(total_num_samps, max_samples_per_packet); //fill in parts of the packet info overwrote in full buff mode if_packet_info.has_tsi = metadata.has_time_spec; @@ -389,10 +389,10 @@ template UHD_INLINE T get_context_code( if_packet_info.sob = metadata.start_of_burst; if_packet_info.eob = metadata.end_of_burst; - _send1( + return _send1( state, buffs, 0, - num_samps, + std::min(total_num_samps, max_samples_per_packet), if_packet_info, io_type, otw_type, vrt_packer, @@ -400,31 +400,32 @@ template UHD_INLINE T get_context_code( vrt_header_offset_words32, chans_per_otw_buff ); - return num_samps; } //////////////////////////////////////////////////////////////// case uhd::device::SEND_MODE_FULL_BUFF:{ //////////////////////////////////////////////////////////////// - //calculate constants for fragmentation - const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; - static const size_t first_fragment_index = 0; - const size_t final_fragment_index = num_fragments-1; + size_t total_num_samps_sent = 0; //loop through the following fragment indexes - for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + while(total_num_samps_sent < total_num_samps){ + + //calculate per-loop-iteration variables + const size_t total_num_samps_unsent = total_num_samps - total_num_samps_sent; + const bool first_fragment = (total_num_samps_sent == 0); + const bool final_fragment = (total_num_samps_unsent <= max_samples_per_packet); //calculate new flags for the fragments - if_packet_info.has_tsi = metadata.has_time_spec and (n == first_fragment_index); - if_packet_info.has_tsf = metadata.has_time_spec and (n == first_fragment_index); - if_packet_info.sob = metadata.start_of_burst and (n == first_fragment_index); - if_packet_info.eob = metadata.end_of_burst and (n == final_fragment_index); + if_packet_info.has_tsi = metadata.has_time_spec and first_fragment; + if_packet_info.has_tsf = if_packet_info.has_tsi; + if_packet_info.sob = metadata.start_of_burst and first_fragment; + if_packet_info.eob = metadata.end_of_burst and final_fragment; //send the fragment with the helper function - _send1( + const size_t num_samps_sent = _send1( state, - buffs, n*max_samples_per_packet*io_type.size, - (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, + buffs, total_num_samps_sent*io_type.size, + std::min(total_num_samps_unsent, max_samples_per_packet), if_packet_info, io_type, otw_type, vrt_packer, @@ -432,8 +433,10 @@ template UHD_INLINE T get_context_code( vrt_header_offset_words32, chans_per_otw_buff ); + total_num_samps_sent += num_samps_sent; + if (num_samps_sent == 0) return total_num_samps_sent; } - return total_num_samps; + return total_num_samps_sent; } default: throw std::runtime_error("unknown send mode"); diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp index 1fcf846a0..dfb65951f 100644 --- a/host/lib/transport/zero_copy.cpp +++ b/host/lib/transport/zero_copy.cpp @@ -68,12 +68,12 @@ phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){ /* NOP */ } -managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(size_t timeout_ms){ +managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(double timeout){ //allocate memory boost::uint8_t *recv_mem = new boost::uint8_t[_impl->max_buff_size]; //call recv() with timeout option - ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size), timeout_ms); + ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size), timeout); if (num_bytes <= 0) return managed_recv_buffer::sptr(); //NULL sptr @@ -138,6 +138,6 @@ phony_zero_copy_send_if::~phony_zero_copy_send_if(void){ delete [] _impl->send_mem; } -managed_send_buffer::sptr phony_zero_copy_send_if::get_send_buff(void){ +managed_send_buffer::sptr phony_zero_copy_send_if::get_send_buff(double){ return _impl->send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these } diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index aee760a83..8d9c68961 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -94,12 +94,13 @@ struct usrp1_impl::io_impl{ //all of this to ensure only full buffers are committed managed_send_buffer::sptr send_buff; size_t num_bytes_committed; + double send_timeout; boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; ssize_t phony_commit_pseudo_buff(size_t num_bytes); ssize_t phony_commit_send_buff(size_t num_bytes); ssize_t commit_send_buff(void); void flush_send_buff(void); - bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &); + bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double); //helpers to get at the send buffer + offset inline void *get_send_mem_ptr(void){ @@ -159,14 +160,15 @@ void usrp1_impl::io_impl::flush_send_buff(void){ */ ssize_t usrp1_impl::io_impl::commit_send_buff(void){ ssize_t ret = send_buff->commit(num_bytes_committed); - send_buff = data_transport->get_send_buff(); + send_buff = data_transport->get_send_buff(send_timeout); num_bytes_committed = 0; return ret; } bool usrp1_impl::io_impl::get_send_buffs( - vrt_packet_handler::managed_send_buffs_t &buffs + vrt_packet_handler::managed_send_buffs_t &buffs, double timeout ){ + send_timeout = timeout; UHD_ASSERT_THROW(buffs.size() == 1); //not enough bytes free -> use the pseudo buffer @@ -216,7 +218,7 @@ static void usrp1_bs_vrt_packer( size_t usrp1_impl::send( const std::vector &buffs, size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, double timeout ){ size_t num_samps_sent = vrt_packet_handler::send( _io_impl->packet_handler_send_state, //last state of the send handler @@ -225,7 +227,7 @@ size_t usrp1_impl::send( io_type, _tx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_packer, - boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1), + boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1, timeout), get_max_send_samps_per_packet(), 0, //vrt header offset _tx_subdev_spec.size() //num channels @@ -272,18 +274,18 @@ static void usrp1_bs_vrt_unpacker( } static bool get_recv_buffs( - zero_copy_if::sptr zc_if, size_t timeout_ms, + zero_copy_if::sptr zc_if, double timeout, vrt_packet_handler::managed_recv_buffs_t &buffs ){ UHD_ASSERT_THROW(buffs.size() == 1); - buffs[0] = zc_if->get_recv_buff(timeout_ms); + buffs[0] = zc_if->get_recv_buff(timeout); return buffs[0].get() != NULL; } size_t usrp1_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, size_t timeout_ms + recv_mode_t recv_mode, double timeout ){ size_t num_samps_recvd = vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler @@ -292,7 +294,7 @@ size_t usrp1_impl::recv( io_type, _rx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_unpacker, - boost::bind(&get_recv_buffs, _data_transport, timeout_ms, _1), + boost::bind(&get_recv_buffs, _data_transport, timeout, _1), &vrt_packet_handler::handle_overflow_nop, 0, //vrt header offset _rx_subdev_spec.size() //num channels diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 156fc119f..6ebd6bb09 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -209,9 +209,9 @@ usrp1_impl::~usrp1_impl(void){ /* NOP */ } -bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, size_t timeout_ms){ +bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, double timeout){ //dummy fill-in for the recv_async_msg - boost::this_thread::sleep(boost::posix_time::milliseconds(timeout_ms)); + boost::this_thread::sleep(boost::posix_time::microseconds(long(timeout*1e6))); return false; } diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 20ae3c02a..f2c464610 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -83,13 +83,12 @@ public: size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, - send_mode_t); + send_mode_t, double); size_t recv(const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, - recv_mode_t, - size_t timeout); + recv_mode_t, double); static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size @@ -101,7 +100,7 @@ public: return BYTES_PER_PACKET/_rx_otw_type.get_sample_size()/_rx_subdev_spec.size(); } - bool recv_async_msg(uhd::async_metadata_t &, size_t); + bool recv_async_msg(uhd::async_metadata_t &, double); private: /*! diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 3395f94e2..c0d8ab029 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -33,7 +33,6 @@ using namespace uhd::transport; namespace asio = boost::asio; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; -static const double RECV_TIMEOUT_MS = 100; /*********************************************************************** * io impl details (internal to this file) @@ -59,9 +58,9 @@ struct usrp2_impl::io_impl{ recv_pirate_crew.join_all(); } - bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, size_t timeout_ms){ + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){ boost::this_thread::disable_interruption di; //disable because the wait can throw - return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(timeout_ms)); + return recv_pirate_booty->pop_elems_with_timed_wait(buffs, timeout); } //state management for the vrt packet handler code @@ -91,7 +90,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = zc_if->get_recv_buff(RECV_TIMEOUT_MS); + managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); if (not buff.get()) continue; //ignore timeout/error buffers try{ @@ -151,7 +150,7 @@ void usrp2_impl::io_init(void){ std::memcpy(send_buff->cast(), &data, sizeof(data)); send_buff->commit(sizeof(data)); //drain the recv buffers (may have junk) - while (data_transport->get_recv_buff(RECV_TIMEOUT_MS).get()){}; + while (data_transport->get_recv_buff().get()){}; } //the number of recv frames is the number for the first transport @@ -179,12 +178,10 @@ void usrp2_impl::io_init(void){ * Async Data **********************************************************************/ bool usrp2_impl::recv_async_msg( - async_metadata_t &async_metadata, size_t timeout_ms + async_metadata_t &async_metadata, double timeout ){ boost::this_thread::disable_interruption di; //disable because the wait can throw - return _io_impl->async_msg_fifo->pop_with_timed_wait( - async_metadata, boost::posix_time::milliseconds(timeout_ms) - ); + return _io_impl->async_msg_fifo->pop_with_timed_wait(async_metadata, timeout); } /*********************************************************************** @@ -192,19 +189,22 @@ bool usrp2_impl::recv_async_msg( **********************************************************************/ static bool get_send_buffs( const std::vector &trans, - vrt_packet_handler::managed_send_buffs_t &buffs + vrt_packet_handler::managed_send_buffs_t &buffs, + double timeout ){ UHD_ASSERT_THROW(trans.size() == buffs.size()); + bool good = true; for (size_t i = 0; i < buffs.size(); i++){ - buffs[i] = trans[i]->get_send_buff(); + buffs[i] = trans[i]->get_send_buff(timeout); + good = good and (buffs[i].get() != NULL); } - return true; + return good; } size_t usrp2_impl::send( const std::vector &buffs, size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, double timeout ){ return vrt_packet_handler::send( _io_impl->packet_handler_send_state, //last state of the send handler @@ -213,7 +213,7 @@ size_t usrp2_impl::send( io_type, _io_helper.get_tx_otw_type(), //input and output types to convert _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_pack_be, - boost::bind(&get_send_buffs, _data_transports, _1), + boost::bind(&get_send_buffs, _data_transports, _1, timeout), get_max_send_samps_per_packet() ); } @@ -224,7 +224,7 @@ size_t usrp2_impl::send( size_t usrp2_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, size_t timeout_ms + recv_mode_t recv_mode, double timeout ){ return vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler @@ -233,6 +233,6 @@ size_t usrp2_impl::recv( io_type, _io_helper.get_rx_otw_type(), //input and output types to convert _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_unpack_be, - boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout_ms) + boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout) ); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 157d17057..e8763b284 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -234,7 +234,7 @@ public: size_t send( const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, - uhd::device::send_mode_t + uhd::device::send_mode_t, double ); size_t get_max_recv_samps_per_packet(void) const{ return _io_helper.get_max_recv_samps_per_packet(); @@ -242,9 +242,9 @@ public: size_t recv( const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, - uhd::device::recv_mode_t, size_t + uhd::device::recv_mode_t, double ); - bool recv_async_msg(uhd::async_metadata_t &, size_t); + bool recv_async_msg(uhd::async_metadata_t &, double); private: //device properties interface diff --git a/host/test/buffer_test.cpp b/host/test/buffer_test.cpp index aadb3f951..8445412e7 100644 --- a/host/test/buffer_test.cpp +++ b/host/test/buffer_test.cpp @@ -23,7 +23,7 @@ using namespace boost::assign; using namespace uhd::transport; -static const boost::posix_time::milliseconds timeout(10); +static const double timeout = 0.01/*secs*/; BOOST_AUTO_TEST_CASE(test_bounded_buffer_with_timed_wait){ bounded_buffer::sptr bb(bounded_buffer::make(3)); -- cgit v1.2.3 From 7352c95037fa57d37dd7adc4c2ea6935006b56c8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 2 Oct 2010 23:15:46 -0700 Subject: uhd: reworked the zero copy interface - recv buffers have a release call - safe make function for recv buffers (buff + release callback) - send buffer commits now have a void return - safe make function for send buffers (buff + commit callback) The reason for the void return from commit is that ssize_t num_bytes was never returning anything of use. That is for all of the zero copy implementations so far, commit cannot really error (being asynchronous). libusb zero copy impl was reworked to support the new interface. USRP1 io_impl with the psuedo managed buffer was replaced with safe_make. Also, usrp1 io_impl was simplified greatly due to commit returning void now. UDP zero copy asio was disabled (in this commit, until its reworked). Phony send and recv interfaces were removed completely. --- host/include/uhd/transport/zero_copy.hpp | 112 +++++++--------------- host/lib/transport/CMakeLists.txt | 4 +- host/lib/transport/libusb1_zero_copy.cpp | 149 +++++++----------------------- host/lib/transport/vrt_packet_handler.hpp | 4 +- host/lib/transport/zero_copy.cpp | 121 +++++++++--------------- host/lib/usrp/usrp1/io_impl.cpp | 65 ++++--------- 6 files changed, 130 insertions(+), 325 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index ba19b193c..9dd16280c 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -19,10 +19,10 @@ #define INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP #include -#include #include #include #include +#include namespace uhd{ namespace transport{ @@ -34,14 +34,27 @@ namespace uhd{ namespace transport{ class UHD_API managed_recv_buffer : boost::noncopyable{ public: typedef boost::shared_ptr sptr; + typedef boost::function release_fcn_t; + + /*! + * Make a safe managed receive buffer: + * A safe managed buffer ensures that release is called once, + * either by the user or automatically upon deconstruction. + * \param buff a reference to the constant buffer + * \param release_fcn callback to release the memory + * \return a new managed receive buffer + */ + static sptr make_safe( + const boost::asio::const_buffer &buff, + const release_fcn_t &release_fcn + ); /*! - * Managed recv buffer destructor: * Signal to the transport that we are done with the buffer. - * This should be called to release the buffer to the transport. + * This should be called to release the buffer to the transport object. * After calling, the referenced memory should be considered invalid. */ - virtual ~managed_recv_buffer(void) = 0; + virtual void release(void) = 0; /*! * Get the size of the underlying buffer. @@ -71,20 +84,34 @@ namespace uhd{ namespace transport{ /*! * A managed send buffer: * Contains a reference to transport-managed memory, - * and a method to release the memory after writing. + * and a method to commit the memory after writing. */ class UHD_API managed_send_buffer : boost::noncopyable{ public: typedef boost::shared_ptr sptr; + typedef boost::function commit_fcn_t; + + /*! + * Make a safe managed send buffer: + * A safe managed buffer ensures that commit is called once, + * either by the user or automatically upon deconstruction. + * In the later case, the deconstructor will call commit(0). + * \param buff a reference to the mutable buffer + * \param commit_fcn callback to commit the memory + * \return a new managed send buffer + */ + static sptr make_safe( + const boost::asio::mutable_buffer &buff, + const commit_fcn_t &commit_fcn + ); /*! * Signal to the transport that we are done with the buffer. * This should be called to commit the write to the transport object. * After calling, the referenced memory should be considered invalid. * \param num_bytes the number of bytes written into the buffer - * \return the number of bytes written, 0 for timeout, negative for error */ - virtual ssize_t commit(size_t num_bytes) = 0; + virtual void commit(size_t num_bytes) = 0; /*! * Get the size of the underlying buffer. @@ -154,77 +181,6 @@ namespace uhd{ namespace transport{ }; - /*! - * A phony-zero-copy interface for transport objects that - * provides a zero-copy interface on top of copying transport. - * This interface implements the get managed recv buffer, - * the base class must implement the private recv method. - */ - class UHD_API phony_zero_copy_recv_if : public virtual zero_copy_if{ - public: - /*! - * Create a phony zero copy recv interface. - * \param max_buff_size max buffer size in bytes - */ - phony_zero_copy_recv_if(size_t max_buff_size); - - //! destructor - virtual ~phony_zero_copy_recv_if(void); - - /*! - * Get a new receive buffer from this transport object. - * \param timeout the timeout to get the buffer in seconds - * \return a managed buffer, or null sptr on timeout/error - */ - managed_recv_buffer::sptr get_recv_buff(double timeout); - - private: - /*! - * Perform a private copying recv. - * \param buff the buffer to write data into - * \param timeout the timeout to get the buffer in seconds - * \return the number of bytes written to buff, 0 for timeout, negative for error - */ - virtual ssize_t recv(const boost::asio::mutable_buffer &buff, double timeout) = 0; - - UHD_PIMPL_DECL(impl) _impl; - }; - - /*! - * A phony-zero-copy interface for transport objects that - * provides a zero-copy interface on top of copying transport. - * This interface implements the get managed send buffer, - * the base class must implement the private send method. - */ - class UHD_API phony_zero_copy_send_if : public virtual zero_copy_if{ - public: - /*! - * Create a phony zero copy send interface. - * \param max_buff_size max buffer size in bytes - */ - phony_zero_copy_send_if(size_t max_buff_size); - - //! destructor - virtual ~phony_zero_copy_send_if(void); - - /*! - * Get a new send buffer from this transport object. - * \param timeout the timeout to get the buffer in seconds - * \return a managed buffer, or null sptr on timeout/error - */ - managed_send_buffer::sptr get_send_buff(double timeout); - - private: - /*! - * Perform a private copying send. - * \param buff the buffer to read data from - * \return the number of bytes read from buff, 0 for timeout, negative for error - */ - virtual ssize_t send(const boost::asio::const_buffer &buff) = 0; - - UHD_PIMPL_DECL(impl) _impl; - }; - }} //namespace #endif /* INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP */ diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 61616d077..2be2c89ec 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -36,6 +36,8 @@ IF(LIBUSB_FOUND) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/transport/msvc) ENDIF(MSVC) SET(HAVE_USB_SUPPORT TRUE) +ELSE(LIBUSB_FOUND) + #TODO dummy usb ENDIF(LIBUSB_FOUND) IF(HAVE_USB_SUPPORT) @@ -99,7 +101,7 @@ SET_SOURCE_FILES_PROPERTIES( LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp - ${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp + #${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp ${CMAKE_SOURCE_DIR}/lib/transport/zero_copy.cpp ) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 7f2bc3468..e1cc8398c 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -95,9 +95,6 @@ private: int _endpoint; bool _input; - size_t _transfer_size; - size_t _num_transfers; - //! hold a bounded buffer of completed transfers typedef bounded_buffer lut_buff_type; lut_buff_type::sptr _completed_list; @@ -154,14 +151,12 @@ usb_endpoint::usb_endpoint( ): _handle(handle), _endpoint(endpoint), - _input(input), - _transfer_size(transfer_size), - _num_transfers(num_transfers) + _input(input) { _completed_list = lut_buff_type::make(num_transfers); - for (size_t i = 0; i < _num_transfers; i++){ - _all_luts.push_back(allocate_transfer(_transfer_size)); + for (size_t i = 0; i < num_transfers; i++){ + _all_luts.push_back(allocate_transfer(transfer_size)); //input luts are immediately submitted to be filled //output luts go into the completed list as free buffers @@ -280,126 +275,44 @@ libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){ } /*********************************************************************** - * Managed buffers + * USB zero_copy device class **********************************************************************/ -/* - * Libusb managed receive buffer - * Construct a recv buffer from a libusb transfer. The memory held by - * the libusb transfer is exposed through the managed buffer interface. - * Upon destruction, the transfer and buffer are resubmitted to the - * endpoint for further use. - */ -class libusb_managed_recv_buffer_impl : public managed_recv_buffer { +class libusb_zero_copy_impl : public usb_zero_copy { public: - libusb_managed_recv_buffer_impl(libusb_transfer *lut, - usb_endpoint::sptr endpoint) - : _buff(lut->buffer, lut->length) - { - _lut = lut; - _endpoint = endpoint; - } - - ~libusb_managed_recv_buffer_impl(void){ - _endpoint->submit(_lut); - } + typedef boost::shared_ptr sptr; -private: - const boost::asio::const_buffer &get(void) const{ - return _buff; - } + libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers + ); - libusb_transfer *_lut; - usb_endpoint::sptr _endpoint; - const boost::asio::const_buffer _buff; -}; + managed_recv_buffer::sptr get_recv_buff(double); + managed_send_buffer::sptr get_send_buff(double); -/* - * Libusb managed send buffer - * Construct a send buffer from a libusb transfer. The memory held by - * the libusb transfer is exposed through the managed buffer interface. - * Committing the buffer will set the data length and submit the buffer - * to the endpoint. Submitting a buffer multiple times or destroying - * the buffer before committing is an error. For the latter, the transfer - * is returned to the endpoint with no data for reuse. - */ -class libusb_managed_send_buffer_impl : public managed_send_buffer { -public: - libusb_managed_send_buffer_impl(libusb_transfer *lut, - usb_endpoint::sptr endpoint) - : _buff(lut->buffer, lut->length), _committed(false) - { - _lut = lut; - _endpoint = endpoint; - } + size_t get_num_recv_frames(void) const { return _recv_num_frames; } + size_t get_num_send_frames(void) const { return _send_num_frames; } - ~libusb_managed_send_buffer_impl(void){ - if (!_committed) { - _lut->length = 0; - _lut->actual_length = 0; - _endpoint->submit(_lut); - } +private: + void release(libusb_transfer *lut){ + _recv_ep->submit(lut); } - ssize_t commit(size_t num_bytes) - { - if (_committed) { - std::cerr << "UHD: send buffer already committed" << std::endl; - return 0; - } - - UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff)); - - _lut->length = num_bytes; - _lut->actual_length = 0; - + void commit(libusb_transfer *lut, size_t num_bytes){ + lut->length = num_bytes; try{ - _endpoint->submit(_lut); - _committed = true; - return num_bytes; + _send_ep->submit(lut); } catch(const std::exception &e){ std::cerr << "Error in commit: " << e.what() << std::endl; - return -1; } } -private: - const boost::asio::mutable_buffer &get(void) const{ - return _buff; - } - - libusb_transfer *_lut; - usb_endpoint::sptr _endpoint; - const boost::asio::mutable_buffer _buff; - bool _committed; -}; - - -/*********************************************************************** - * USB zero_copy device class - **********************************************************************/ -class libusb_zero_copy_impl : public usb_zero_copy -{ -private: libusb::device_handle::sptr _handle; + size_t _recv_xfer_size, _send_xfer_size; size_t _recv_num_frames, _send_num_frames; usb_endpoint::sptr _recv_ep, _send_ep; - -public: - typedef boost::shared_ptr sptr; - - libusb_zero_copy_impl( - libusb::device_handle::sptr handle, - unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers - ); - - managed_recv_buffer::sptr get_recv_buff(double); - managed_send_buffer::sptr get_send_buff(double); - - size_t get_num_recv_frames(void) const { return _recv_num_frames; } - size_t get_num_send_frames(void) const { return _send_num_frames; } }; /* @@ -426,7 +339,9 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( UHD_ASSERT_THROW(send_xfer_size % 512 == 0); //store the num xfers for the num frames count + _recv_xfer_size = recv_xfer_size; _recv_num_frames = recv_num_xfers; + _send_xfer_size = send_xfer_size; _send_num_frames = send_num_xfers; _handle->claim_interface(2 /*in interface*/); @@ -461,9 +376,10 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(double timeout){ return managed_recv_buffer::sptr(); } else { - return managed_recv_buffer::sptr( - new libusb_managed_recv_buffer_impl(lut, - _recv_ep)); + return managed_recv_buffer::make_safe( + boost::asio::const_buffer(lut->buffer, lut->actual_length), + boost::bind(&libusb_zero_copy_impl::release, this, lut) + ); } } @@ -480,9 +396,10 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){ return managed_send_buffer::sptr(); } else { - return managed_send_buffer::sptr( - new libusb_managed_send_buffer_impl(lut, - _send_ep)); + return managed_send_buffer::make_safe( + boost::asio::mutable_buffer(lut->buffer, _send_xfer_size), + boost::bind(&libusb_zero_copy_impl::commit, this, lut, _1) + ); } } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index e11afff30..939517411 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -343,9 +343,7 @@ template UHD_INLINE T get_context_code( //commit the samples to the zero-copy interface size_t num_bytes_total = (vrt_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t); - if (send_buffs[i]->commit(num_bytes_total) < ssize_t(num_bytes_total)){ - std::cerr << "commit to send buffer returned less than commit size" << std::endl; - } + send_buffs[i]->commit(num_bytes_total); } return num_samps; } diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp index dfb65951f..a5a864a04 100644 --- a/host/lib/transport/zero_copy.cpp +++ b/host/lib/transport/zero_copy.cpp @@ -16,32 +16,35 @@ // #include -#include -#include -#include using namespace uhd::transport; /*********************************************************************** - * The pure-virtual deconstructor needs an implementation to be happy + * Safe managed receive buffer **********************************************************************/ -managed_recv_buffer::~managed_recv_buffer(void){ +static void release_nop(void){ /* NOP */ } -/*********************************************************************** - * Phony zero-copy recv interface implementation - **********************************************************************/ - -//! phony zero-copy recv buffer implementation -class managed_recv_buffer_impl : public managed_recv_buffer{ +class safe_managed_receive_buffer : public managed_recv_buffer{ public: - managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ + safe_managed_receive_buffer( + const boost::asio::const_buffer &buff, + const release_fcn_t &release_fcn + ): + _buff(buff), _release_fcn(release_fcn) + { /* NOP */ } - ~managed_recv_buffer_impl(void){ - delete [] this->cast(); + ~safe_managed_receive_buffer(void){ + _release_fcn(); + } + + void release(void){ + release_fcn_t release_fcn = _release_fcn; + _release_fcn = &release_nop; + return release_fcn(); } private: @@ -50,64 +53,42 @@ private: } const boost::asio::const_buffer _buff; + release_fcn_t _release_fcn; }; -//! phony zero-copy recv interface implementation -struct phony_zero_copy_recv_if::impl{ - impl(size_t max_buff_size) : max_buff_size(max_buff_size){ - /* NOP */ - } - size_t max_buff_size; -}; - -phony_zero_copy_recv_if::phony_zero_copy_recv_if(size_t max_buff_size){ - _impl = UHD_PIMPL_MAKE(impl, (max_buff_size)); -} - -phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){ - /* NOP */ -} - -managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(double timeout){ - //allocate memory - boost::uint8_t *recv_mem = new boost::uint8_t[_impl->max_buff_size]; - - //call recv() with timeout option - ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size), timeout); - - if (num_bytes <= 0) return managed_recv_buffer::sptr(); //NULL sptr - - //create a new managed buffer to house the data - return managed_recv_buffer::sptr( - new managed_recv_buffer_impl(boost::asio::buffer(recv_mem, num_bytes)) - ); +managed_recv_buffer::sptr managed_recv_buffer::make_safe( + const boost::asio::const_buffer &buff, + const release_fcn_t &release_fcn +){ + return sptr(new safe_managed_receive_buffer(buff, release_fcn)); } /*********************************************************************** - * Phony zero-copy send interface implementation + * Safe managed send buffer **********************************************************************/ +static void commit_nop(size_t){ + /* NOP */ +} -//! phony zero-copy send buffer implementation -class managed_send_buffer_impl : public managed_send_buffer{ +class safe_managed_send_buffer : public managed_send_buffer{ public: - typedef boost::function send_fcn_t; - - managed_send_buffer_impl( + safe_managed_send_buffer( const boost::asio::mutable_buffer &buff, - const send_fcn_t &send_fcn + const commit_fcn_t &commit_fcn ): - _buff(buff), - _send_fcn(send_fcn) + _buff(buff), _commit_fcn(commit_fcn) { /* NOP */ } - ~managed_send_buffer_impl(void){ - /* NOP */ + ~safe_managed_send_buffer(void){ + _commit_fcn(0); } - ssize_t commit(size_t num_bytes){ - return _send_fcn(boost::asio::buffer(_buff, num_bytes)); + void commit(size_t num_bytes){ + commit_fcn_t commit_fcn = _commit_fcn; + _commit_fcn = &commit_nop; + return commit_fcn(num_bytes); } private: @@ -116,28 +97,12 @@ private: } const boost::asio::mutable_buffer _buff; - const send_fcn_t _send_fcn; -}; - -//! phony zero-copy send interface implementation -struct phony_zero_copy_send_if::impl{ - boost::uint8_t *send_mem; - managed_send_buffer::sptr send_buff; + commit_fcn_t _commit_fcn; }; -phony_zero_copy_send_if::phony_zero_copy_send_if(size_t max_buff_size){ - _impl = UHD_PIMPL_MAKE(impl, ()); - _impl->send_mem = new boost::uint8_t[max_buff_size]; - _impl->send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( - boost::asio::buffer(_impl->send_mem, max_buff_size), - boost::bind(&phony_zero_copy_send_if::send, this, _1) - )); -} - -phony_zero_copy_send_if::~phony_zero_copy_send_if(void){ - delete [] _impl->send_mem; -} - -managed_send_buffer::sptr phony_zero_copy_send_if::get_send_buff(double){ - return _impl->send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these +safe_managed_send_buffer::sptr managed_send_buffer::make_safe( + const boost::asio::mutable_buffer &buff, + const commit_fcn_t &commit_fcn +){ + return sptr(new safe_managed_send_buffer(buff, commit_fcn)); } diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 8d9c68961..676b1536a 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,35 +33,6 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -/*********************************************************************** - * Pseudo send buffer implementation - **********************************************************************/ -class pseudo_managed_send_buffer : public managed_send_buffer{ -public: - - pseudo_managed_send_buffer( - const boost::asio::mutable_buffer &buff, - const boost::function &commit - ): - _buff(buff), - _commit(commit) - { - /* NOP */ - } - - ssize_t commit(size_t num_bytes){ - return _commit(num_bytes); - } - -private: - const boost::asio::mutable_buffer &get(void) const{ - return _buff; - } - - const boost::asio::mutable_buffer _buff; - const boost::function _commit; -}; - /*********************************************************************** * IO Implementation Details **********************************************************************/ @@ -96,9 +67,9 @@ struct usrp1_impl::io_impl{ size_t num_bytes_committed; double send_timeout; boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; - ssize_t phony_commit_pseudo_buff(size_t num_bytes); - ssize_t phony_commit_send_buff(size_t num_bytes); - ssize_t commit_send_buff(void); + void phony_commit_pseudo_buff(size_t num_bytes); + void phony_commit_send_buff(size_t num_bytes); + void commit_send_buff(void); void flush_send_buff(void); bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double); @@ -119,28 +90,25 @@ struct usrp1_impl::io_impl{ * The first loop iteration will fill the remainder of the send buffer. * The second loop iteration will empty the pseudo buffer remainder. */ -ssize_t usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){ +void usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){ size_t bytes_to_copy = num_bytes, bytes_copied = 0; while(bytes_to_copy){ size_t bytes_copied_here = std::min(bytes_to_copy, get_send_mem_size()); std::memcpy(get_send_mem_ptr(), pseudo_buff + bytes_copied, bytes_copied_here); - ssize_t ret = phony_commit_send_buff(bytes_copied_here); - if (ret < 0) return ret; - bytes_to_copy -= ret; - bytes_copied += ret; + phony_commit_send_buff(bytes_copied_here); + bytes_to_copy -= bytes_copied_here; + bytes_copied += bytes_copied_here; } - return bytes_copied; } /*! * Accept a commit of num bytes to the send buffer. * Conditionally commit the send buffer if full. */ -ssize_t usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){ +void usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){ num_bytes_committed += num_bytes; - if (num_bytes_committed != send_buff->size()) return num_bytes; - ssize_t ret = commit_send_buff(); - return (ret < 0)? ret : num_bytes; + if (num_bytes_committed != send_buff->size()) return; + commit_send_buff(); } /*! @@ -158,11 +126,10 @@ void usrp1_impl::io_impl::flush_send_buff(void){ * Perform an actual commit on the send buffer: * Commit the contents of the send buffer and request a new buffer. */ -ssize_t usrp1_impl::io_impl::commit_send_buff(void){ - ssize_t ret = send_buff->commit(num_bytes_committed); +void usrp1_impl::io_impl::commit_send_buff(void){ + send_buff->commit(num_bytes_committed); send_buff = data_transport->get_send_buff(send_timeout); num_bytes_committed = 0; - return ret; } bool usrp1_impl::io_impl::get_send_buffs( @@ -173,17 +140,17 @@ bool usrp1_impl::io_impl::get_send_buffs( //not enough bytes free -> use the pseudo buffer if (get_send_mem_size() < BYTES_PER_PACKET){ - buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( + buffs[0] = managed_send_buffer::make_safe( boost::asio::buffer(pseudo_buff), boost::bind(&usrp1_impl::io_impl::phony_commit_pseudo_buff, this, _1) - )); + ); } //otherwise use the send buffer offset by the bytes written else{ - buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( + buffs[0] = managed_send_buffer::make_safe( boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()), boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1) - )); + ); } return buffs[0].get() != NULL; -- cgit v1.2.3 From 4fd922ba3acb8559a3d7d016b230d5e7a0a84da1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 4 Oct 2010 09:48:25 -0700 Subject: usrp2: removed extra print-outs in init --- host/lib/usrp/usrp2/io_impl.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index c0d8ab029..33cec3cbc 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -168,10 +168,6 @@ void usrp2_impl::io_init(void){ _mboards.at(i), i )); } - - std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; - std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; - std::cout << "Recv pirate num frames: " << num_frames << std::endl; } /*********************************************************************** -- cgit v1.2.3 From b34af3c910a54d8afd4b1f00f1254c3ab762c82a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 4 Oct 2010 11:17:01 -0700 Subject: usrp-e: implemented mmap with new zero_copy timeout work, added much debug verbosity --- host/lib/usrp/usrp_e/io_impl.cpp | 48 ++++---- host/lib/usrp/usrp_e/usrp_e_impl.hpp | 6 +- host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp | 161 ++++++++++++------------- 3 files changed, 107 insertions(+), 108 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/io_impl.cpp b/host/lib/usrp/usrp_e/io_impl.cpp index 0b5fa054b..1e577a4df 100644 --- a/host/lib/usrp/usrp_e/io_impl.cpp +++ b/host/lib/usrp/usrp_e/io_impl.cpp @@ -37,7 +37,7 @@ zero_copy_if::sptr usrp_e_make_mmap_zero_copy(usrp_e_iface::sptr iface); **********************************************************************/ static const size_t tx_async_report_sid = 1; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; -static const double recv_timeout_ms = 100; +static const bool recv_debug = true; /*********************************************************************** * io impl details (internal to this file) @@ -66,10 +66,10 @@ struct usrp_e_impl::io_impl{ recv_pirate_crew.join_all(); } - bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, size_t timeout_ms){ + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){ UHD_ASSERT_THROW(buffs.size() == 1); boost::this_thread::disable_interruption di; //disable because the wait can throw - return recv_pirate_booty->pop_with_timed_wait(buffs.front(), boost::posix_time::milliseconds(timeout_ms)); + return recv_pirate_booty->pop_with_timed_wait(buffs.front(), timeout); } //a pirate's life is the life for me! @@ -94,9 +94,17 @@ void usrp_e_impl::io_impl::recv_pirate_loop( //size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(recv_timeout_ms); + managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(); if (not buff.get()) continue; //ignore timeout/error buffers + if (recv_debug){ + std::cout << "len " << buff->size() << std::endl; + for (size_t i = 0; i < 9; i++){ + std::cout << boost::format(" 0x%08x") % buff->cast()[i] << std::endl; + } + std::cout << std::endl << std::endl; + } + try{ //extract the vrt header packet info vrt::if_packet_info_t if_packet_info; @@ -181,20 +189,18 @@ void usrp_e_impl::handle_overrun(size_t){ * Data Send **********************************************************************/ bool get_send_buffs( - zero_copy_if::sptr trans, + zero_copy_if::sptr trans, double timeout, vrt_packet_handler::managed_send_buffs_t &buffs ){ UHD_ASSERT_THROW(buffs.size() == 1); - buffs[0] = trans->get_send_buff(); + buffs[0] = trans->get_send_buff(timeout); return buffs[0].get() != NULL; } size_t usrp_e_impl::send( - const std::vector &buffs, - size_t num_samps, - const tx_metadata_t &metadata, - const io_type_t &io_type, - send_mode_t send_mode + const std::vector &buffs, size_t num_samps, + const tx_metadata_t &metadata, const io_type_t &io_type, + send_mode_t send_mode, double timeout ){ otw_type_t send_otw_type; send_otw_type.width = 16; @@ -208,7 +214,7 @@ size_t usrp_e_impl::send( io_type, send_otw_type, //input and output types to convert MASTER_CLOCK_RATE, //master clock tick rate uhd::transport::vrt::if_hdr_pack_le, - boost::bind(&get_send_buffs, _io_impl->data_xport, _1), + boost::bind(&get_send_buffs, _io_impl->data_xport, timeout, _1), get_max_send_samps_per_packet() ); } @@ -217,12 +223,9 @@ size_t usrp_e_impl::send( * Data Recv **********************************************************************/ size_t usrp_e_impl::recv( - const std::vector &buffs, - size_t num_samps, - rx_metadata_t &metadata, - const io_type_t &io_type, - recv_mode_t recv_mode, - size_t timeout_ms + const std::vector &buffs, size_t num_samps, + rx_metadata_t &metadata, const io_type_t &io_type, + recv_mode_t recv_mode, double timeout ){ otw_type_t recv_otw_type; recv_otw_type.width = 16; @@ -236,7 +239,7 @@ size_t usrp_e_impl::recv( io_type, recv_otw_type, //input and output types to convert MASTER_CLOCK_RATE, //master clock tick rate uhd::transport::vrt::if_hdr_unpack_le, - boost::bind(&usrp_e_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout_ms), + boost::bind(&usrp_e_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout), boost::bind(&usrp_e_impl::handle_overrun, this, _1) ); } @@ -245,11 +248,8 @@ size_t usrp_e_impl::recv( * Async Recv **********************************************************************/ bool usrp_e_impl::recv_async_msg( - async_metadata_t &async_metadata, - size_t timeout_ms + async_metadata_t &async_metadata, double timeout ){ boost::this_thread::disable_interruption di; //disable because the wait can throw - return _io_impl->async_msg_fifo->pop_with_timed_wait( - async_metadata, boost::posix_time::milliseconds(timeout_ms) - ); + return _io_impl->async_msg_fifo->pop_with_timed_wait(async_metadata, timeout); } diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp index 2457e27cc..49912050e 100644 --- a/host/lib/usrp/usrp_e/usrp_e_impl.hpp +++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp @@ -82,9 +82,9 @@ public: ~usrp_e_impl(void); //the io interface - size_t send(const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t); - size_t recv(const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, size_t); - bool recv_async_msg(uhd::async_metadata_t &, size_t); + size_t send(const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); + size_t recv(const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); + bool recv_async_msg(uhd::async_metadata_t &, double); size_t get_max_send_samps_per_packet(void) const{return 503;} size_t get_max_recv_samps_per_packet(void) const{return 503;} diff --git a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp index 0910caa6f..e62205a3f 100644 --- a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp @@ -15,86 +15,27 @@ // along with this program. If not, see . // +#include "usrp_e_iface.hpp" #include #include #include #include //mmap #include //getpagesize #include //poll -#include -#include "usrp_e_iface.hpp" +#include +#include +#include using namespace uhd; using namespace uhd::transport; -static const bool debug_verbose = false; - -/*********************************************************************** - * The managed receive buffer implementation - **********************************************************************/ -class usrp_e_mmap_managed_recv_buffer : public managed_recv_buffer{ -public: - usrp_e_mmap_managed_recv_buffer( - const void *mem, size_t len, ring_buffer_info *info - ): - _buff(mem, len), _info(info) - { - /* NOP */ - } - - ~usrp_e_mmap_managed_recv_buffer(void){ - _info->flags = RB_KERNEL; - } - -private: - const boost::asio::const_buffer &get(void) const{ - return _buff; - } - - const boost::asio::const_buffer _buff; - ring_buffer_info *_info; -}; - -/*********************************************************************** - * The managed send buffer implementation - **********************************************************************/ -class usrp_e_mmap_managed_send_buffer : public managed_send_buffer{ -public: - usrp_e_mmap_managed_send_buffer( - void *mem, size_t len, ring_buffer_info *info, int fd - ): - _buff(mem, len), _info(info), _fd(fd), _commited(false) - { - /* NOP */ - } - - ~usrp_e_mmap_managed_send_buffer(void){ - if (not _commited) this->commit(0); - } - - ssize_t commit(size_t num_bytes){ - _commited = true; - _info->len = num_bytes; - _info->flags = RB_USER; - ssize_t ret = ::write(_fd, NULL, 0); - return (ret < 0)? ret : num_bytes; - } - -private: - const boost::asio::mutable_buffer &get(void) const{ - return _buff; - } - - const boost::asio::mutable_buffer _buff; - ring_buffer_info *_info; - int _fd; - bool _commited; -}; +static const bool fp_verbose = true; //fast-path verbose +static const bool sp_verbose = true; //slow-path verbose /*********************************************************************** * The zero copy interface implementation **********************************************************************/ -class usrp_e_mmap_zero_copy_impl : public zero_copy_if{ +class usrp_e_mmap_zero_copy_impl : public zero_copy_if, public boost::enable_shared_from_this { public: usrp_e_mmap_zero_copy_impl(usrp_e_iface::sptr iface): _fd(iface->get_file_descriptor()), _recv_index(0), _send_index(0) @@ -105,15 +46,26 @@ public: _frame_size = page_size/2; //calculate the memory size - size_t map_size = + _map_size = (_rb_size.num_pages_rx_flags + _rb_size.num_pages_tx_flags) * page_size + (_rb_size.num_rx_frames + _rb_size.num_tx_frames) * _frame_size; + //print sizes summary + if (sp_verbose){ + std::cout << "page_size: " << page_size << std::endl; + std::cout << "frame_size: " << _frame_size << std::endl; + std::cout << "num_pages_rx_flags: " << _rb_size.num_pages_rx_flags << std::endl; + std::cout << "num_rx_frames: " << _rb_size.num_rx_frames << std::endl; + std::cout << "num_pages_tx_flags: " << _rb_size.num_pages_tx_flags << std::endl; + std::cout << "num_tx_frames: " << _rb_size.num_tx_frames << std::endl; + std::cout << "map_size: " << _map_size << std::endl; + } + //call mmap to get the memory - void *ring_buffer = mmap( - NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0 + _mapped_mem = ::mmap( + NULL, _map_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0 ); - UHD_ASSERT_THROW(ring_buffer != MAP_FAILED); + UHD_ASSERT_THROW(_mapped_mem != MAP_FAILED); //calculate the memory offsets for info and buffers size_t recv_info_off = 0; @@ -121,16 +73,31 @@ public: size_t send_info_off = recv_buff_off + (_rb_size.num_rx_frames * _frame_size); size_t send_buff_off = send_info_off + (_rb_size.num_pages_tx_flags * page_size); + //print offset summary + if (sp_verbose){ + std::cout << "recv_info_off: " << recv_info_off << std::endl; + std::cout << "recv_buff_off: " << recv_buff_off << std::endl; + std::cout << "send_info_off: " << send_info_off << std::endl; + std::cout << "send_buff_off: " << send_buff_off << std::endl; + } + //set the internal pointers for info and buffers typedef ring_buffer_info (*rbi_pta)[]; - boost::uint8_t *rb_ptr = reinterpret_cast(ring_buffer); + char *rb_ptr = reinterpret_cast(_mapped_mem); _recv_info = reinterpret_cast(rb_ptr + recv_info_off); _recv_buff = rb_ptr + recv_buff_off; _send_info = reinterpret_cast(rb_ptr + send_info_off); _send_buff = rb_ptr + send_buff_off; } - managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms){ + ~usrp_e_mmap_zero_copy_impl(void){ + if (sp_verbose) std::cout << "cleanup: munmap" << std::endl; + ::munmap(_mapped_mem, _map_size); + } + + managed_recv_buffer::sptr get_recv_buff(double timeout){ + if (fp_verbose) std::cout << "get_recv_buff: " << _recv_index << std::endl; + //grab pointers to the info and buffer ring_buffer_info *info = (*_recv_info) + _recv_index; void *mem = _recv_buff + _frame_size*_recv_index; @@ -140,7 +107,8 @@ public: pollfd pfd; pfd.fd = _fd; pfd.events = POLLIN; - ssize_t poll_ret = poll(&pfd, 1, timeout_ms); + ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3)); + if (fp_verbose) std::cout << " POLLIN: " << poll_ret << std::endl; if (poll_ret <= 0) return managed_recv_buffer::sptr(); } @@ -148,8 +116,10 @@ public: if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0; //return the managed buffer for this frame - return managed_recv_buffer::sptr( - new usrp_e_mmap_managed_recv_buffer(mem, info->len, info) + if (fp_verbose) std::cout << " make_recv_buff: " << info->len << std::endl; + return managed_recv_buffer::make_safe( + boost::asio::const_buffer(mem, info->len), + boost::bind(&usrp_e_mmap_zero_copy_impl::release, shared_from_this(), info) ); } @@ -157,7 +127,9 @@ public: return _rb_size.num_rx_frames; } - managed_send_buffer::sptr get_send_buff(void){ + managed_send_buffer::sptr get_send_buff(double timeout){ + if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl; + //grab pointers to the info and buffer ring_buffer_info *info = (*_send_info) + _send_index; void *mem = _send_buff + _frame_size*_send_index; @@ -167,7 +139,8 @@ public: pollfd pfd; pfd.fd = _fd; pfd.events = POLLOUT; - ssize_t poll_ret = poll(&pfd, 1, -1 /*forever*/); + ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3)); + if (fp_verbose) std::cout << " POLLOUT: " << poll_ret << std::endl; if (poll_ret <= 0) return managed_send_buffer::sptr(); } @@ -175,8 +148,10 @@ public: if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0; //return the managed buffer for this frame - return managed_send_buffer::sptr( - new usrp_e_mmap_managed_send_buffer(mem, _frame_size, info, _fd) + if (fp_verbose) std::cout << " make_send_buff: " << _frame_size << std::endl; + return managed_send_buffer::make_safe( + boost::asio::mutable_buffer(mem, _frame_size), + boost::bind(&usrp_e_mmap_zero_copy_impl::commit, shared_from_this(), info, _1) ); } @@ -185,11 +160,35 @@ public: } private: + + void release(ring_buffer_info *info){ + if (fp_verbose) std::cout << "recv buff: release" << std::endl; + info->flags = RB_KERNEL; + } + + void commit(ring_buffer_info *info, size_t len){ + if (fp_verbose) std::cout << "send buff: commit " << len << std::endl; + info->len = len; + info->flags = RB_USER; + if (::write(_fd, NULL, 0) < 0){ + std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl; + } + } + int _fd; + + //the mapped memory itself + void *_mapped_mem; + + //mapped memory sizes usrp_e_ring_buffer_size_t _rb_size; - size_t _frame_size; + size_t _frame_size, _map_size; + + //pointers to sections in the mapped memory ring_buffer_info (*_recv_info)[], (*_send_info)[]; - boost::uint8_t *_recv_buff, *_send_buff; + char *_recv_buff, *_send_buff; + + //indexes into sub-sections of mapped memory size_t _recv_index, _send_index; }; -- cgit v1.2.3 From f642942dc364c1d26a9128c1ba631d3604d0671a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 4 Oct 2010 15:17:57 -0700 Subject: usrp-e: check if flags are ready after poll --- host/lib/usrp/usrp_e/io_impl.cpp | 6 +++--- host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/io_impl.cpp b/host/lib/usrp/usrp_e/io_impl.cpp index 1e577a4df..2802a6b87 100644 --- a/host/lib/usrp/usrp_e/io_impl.cpp +++ b/host/lib/usrp/usrp_e/io_impl.cpp @@ -130,12 +130,12 @@ void usrp_e_impl::io_impl::recv_pirate_loop( continue; } + //same number of frames as the data transport -> always immediate + recv_pirate_booty->push_with_wait(buff); + }catch(const std::exception &e){ std::cerr << "Error (usrp-e recv pirate loop): " << e.what() << std::endl; } - - //usrp-e back-pressures on receive: push with wait - recv_pirate_booty->push_with_wait(buff); } } diff --git a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp index e62205a3f..9e25ed088 100644 --- a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp @@ -112,6 +112,12 @@ public: if (poll_ret <= 0) return managed_recv_buffer::sptr(); } + //check that the frame is really ready + if (not (info->flags & RB_USER)){ + if (fp_verbose) std::cout << " flags: not ready" << std::endl; + return managed_recv_buffer::sptr(); + } + //increment the index for the next call if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0; @@ -144,6 +150,12 @@ public: if (poll_ret <= 0) return managed_send_buffer::sptr(); } + //check that the frame is really ready + if (not (info->flags & RB_KERNEL)){ + if (fp_verbose) std::cout << " flags: not ready" << std::endl; + return managed_send_buffer::sptr(); + } + //increment the index for the next call if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0; -- cgit v1.2.3 From 0cd5375b5c8a928f112a963d9c9c2556bafed108 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 5 Oct 2010 10:30:28 -0700 Subject: uhd: replaced frame params for the zero copy interfaces with a device address the device address gives a key, value pair of infinite optional capabilities added a cast option to the device address to cast string to type T added call to the zero_copy_if to get send and recv frame sizes changed the usrp2 impl to calculate recv/send spp from the data transport --- host/include/uhd/transport/udp_zero_copy.hpp | 7 ++- host/include/uhd/transport/usb_control.hpp | 2 +- host/include/uhd/transport/usb_zero_copy.hpp | 17 +++---- host/include/uhd/transport/zero_copy.hpp | 26 +++++++--- host/include/uhd/types/device_addr.hpp | 20 ++++++++ host/lib/transport/libusb1_zero_copy.cpp | 67 +++++++++++-------------- host/lib/transport/udp_zero_copy_asio.cpp | 35 +++++++------ host/lib/transport/usb_dummy_impl.cpp | 4 +- host/lib/usrp/usrp1/usrp1_impl.cpp | 48 +++++++----------- host/lib/usrp/usrp2/io_impl.cpp | 4 +- host/lib/usrp/usrp2/mboard_impl.cpp | 8 +-- host/lib/usrp/usrp2/usrp2_impl.cpp | 40 ++++++--------- host/lib/usrp/usrp2/usrp2_impl.hpp | 75 ++++++++-------------------- 13 files changed, 162 insertions(+), 191 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 818709973..bbba97b21 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -20,6 +20,7 @@ #include #include +#include #include namespace uhd{ namespace transport{ @@ -50,14 +51,12 @@ public: * * \param addr a string representing the destination address * \param port a string representing the destination port - * \param recv_buff_size size in bytes for the recv buffer, 0 for automatic - * \param send_buff_size size in bytes for the send buffer, 0 for automatic + * \param hints optional parameters to pass to the underlying transport */ static sptr make( const std::string &addr, const std::string &port, - size_t recv_buff_size = 0, - size_t send_buff_size = 0 + const device_addr_t &hints = device_addr_t() ); }; diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index f9829c3ec..e6c32f78e 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP #define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP -#include "usb_device_handle.hpp" +#include namespace uhd { namespace transport { diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 61bf380ba..b39171fba 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -18,8 +18,9 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP #define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP -#include "usb_device_handle.hpp" +#include #include +#include namespace uhd { namespace transport { @@ -47,19 +48,13 @@ public: * \param handle a device handle that uniquely identifying the device * \param recv_endpoint an integer specifiying an IN endpoint number * \param send_endpoint an integer specifiying an OUT endpoint number - * \param recv_xfer_size the number of bytes for each receive transfer - * \param recv_num_xfers the number of simultaneous receive transfers - * \param send_xfer_size the number of bytes for each send transfer - * \param send_num_xfers the number of simultaneous send transfers + * \param hints optional parameters to pass to the underlying transport */ static sptr make( usb_device_handle::sptr handle, - unsigned int recv_endpoint, - unsigned int send_endpoint, - size_t recv_xfer_size = 0, - size_t recv_num_xfers = 0, - size_t send_xfer_size = 0, - size_t send_num_xfers = 0 + size_t recv_endpoint, + size_t send_endpoint, + const device_addr_t &hints = device_addr_t() ); }; diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 9dd16280c..7d8fb4b83 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -155,14 +155,19 @@ namespace uhd{ namespace transport{ virtual managed_recv_buffer::sptr get_recv_buff(double timeout = 0.1) = 0; /*! - * Get the maximum number of receive frames: - * The maximum number of valid managed recv buffers, - * or the maximum number of frames in the ring buffer, - * depending upon the underlying implementation. + * Get the number of receive frames: + * The number of simultaneous receive buffers in use. * \return number of frames */ virtual size_t get_num_recv_frames(void) const = 0; + /*! + * Get the size of a receive frame: + * The maximum capacity of a single receive buffer. + * \return frame size in bytes + */ + virtual size_t get_recv_frame_size(void) const = 0; + /*! * Get a new send buffer from this transport object. * \param timeout the timeout to get the buffer in seconds @@ -171,14 +176,19 @@ namespace uhd{ namespace transport{ virtual managed_send_buffer::sptr get_send_buff(double timeout = 0.1) = 0; /*! - * Get the maximum number of send frames: - * The maximum number of valid managed send buffers, - * or the maximum number of frames in the ring buffer, - * depending upon the underlying implementation. + * Get the number of send frames: + * The number of simultaneous send buffers in use. * \return number of frames */ virtual size_t get_num_send_frames(void) const = 0; + /*! + * Get the size of a send frame: + * The maximum capacity of a single send buffer. + * \return frame size in bytes + */ + virtual size_t get_send_frame_size(void) const = 0; + }; }} //namespace diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp index e359d9467..eb3394230 100644 --- a/host/include/uhd/types/device_addr.hpp +++ b/host/include/uhd/types/device_addr.hpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include @@ -62,6 +64,24 @@ namespace uhd{ * \return a string with delimiter markup */ std::string to_string(void) const; + + /*! + * Lexically cast a parameter to the specified type, + * or use the default value if the key is not found. + * \param key the key as one of the address parameters + * \param def the value to use when key is not present + * \return the casted value as type T or the default + * \throw error when the parameter cannot be casted + */ + template T cast(const std::string &key, const T &def) const{ + if (not this->has_key(key)) return def; + try{ + return boost::lexical_cast((*this)[key]); + } + catch(const boost::bad_lexical_cast &){ + throw std::runtime_error("cannot cast " + key + " = " + (*this)[key]); + } + } }; //handy typedef for a vector of device addresses diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 819874483..df6db1eb9 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -26,6 +26,7 @@ #include #include +using namespace uhd; using namespace uhd::transport; static const double CLEANUP_TIMEOUT = 0.2; //seconds @@ -284,16 +285,19 @@ public: libusb_zero_copy_impl( libusb::device_handle::sptr handle, - unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers + size_t recv_endpoint, + size_t send_endpoint, + const device_addr_t &hints ); managed_recv_buffer::sptr get_recv_buff(double); managed_send_buffer::sptr get_send_buff(double); - size_t get_num_recv_frames(void) const { return _recv_num_frames; } - size_t get_num_send_frames(void) const { return _send_num_frames; } + size_t get_num_recv_frames(void) const { return _num_recv_frames; } + size_t get_num_send_frames(void) const { return _num_send_frames; } + + size_t get_recv_frame_size(void) const { return _recv_frame_size; } + size_t get_send_frame_size(void) const { return _send_frame_size; } private: void release(libusb_transfer *lut){ @@ -311,8 +315,8 @@ private: } libusb::device_handle::sptr _handle; - size_t _recv_xfer_size, _send_xfer_size; - size_t _recv_num_frames, _send_num_frames; + const size_t _recv_frame_size, _num_recv_frames; + const size_t _send_frame_size, _num_send_frames; usb_endpoint::sptr _recv_ep, _send_ep; }; @@ -323,24 +327,16 @@ private: */ libusb_zero_copy_impl::libusb_zero_copy_impl( libusb::device_handle::sptr handle, - unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers -){ - _handle = handle; - - //if the sizes are left at 0 (automatic) -> use the defaults - if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; - if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; - if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; - if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; - - //store the num xfers for the num frames count - _recv_xfer_size = recv_xfer_size; - _recv_num_frames = recv_num_xfers; - _send_xfer_size = send_xfer_size; - _send_num_frames = send_num_xfers; - + size_t recv_endpoint, + size_t send_endpoint, + const device_addr_t &hints +): + _handle(handle), + _recv_frame_size(size_t(hints.cast("recv_frame_size", DEFAULT_XFER_SIZE))), + _num_recv_frames(size_t(hints.cast("num_recv_frames", DEFAULT_NUM_XFERS))), + _send_frame_size(size_t(hints.cast("send_frame_size", DEFAULT_XFER_SIZE))), + _num_send_frames(size_t(hints.cast("num_send_frames", DEFAULT_NUM_XFERS))) +{ _handle->claim_interface(2 /*in interface*/); _handle->claim_interface(1 /*out interface*/); @@ -348,16 +344,16 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( _handle, // libusb device_handle recv_endpoint, // USB endpoint number true, // IN endpoint - recv_xfer_size, // buffer size per transfer - recv_num_xfers // number of libusb transfers + this->get_recv_frame_size(), // buffer size per transfer + this->get_num_recv_frames() // number of libusb transfers )); _send_ep = usb_endpoint::sptr(new usb_endpoint( _handle, // libusb device_handle send_endpoint, // USB endpoint number false, // OUT endpoint - send_xfer_size, // buffer size per transfer - send_num_xfers // number of libusb transfers + this->get_send_frame_size(), // buffer size per transfer + this->get_num_send_frames() // number of libusb transfers )); } @@ -394,7 +390,7 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){ } else { return managed_send_buffer::make_safe( - boost::asio::mutable_buffer(lut->buffer, _send_xfer_size), + boost::asio::mutable_buffer(lut->buffer, this->get_send_frame_size()), boost::bind(&libusb_zero_copy_impl::commit, shared_from_this(), lut, _1) ); } @@ -405,17 +401,14 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){ **********************************************************************/ usb_zero_copy::sptr usb_zero_copy::make( usb_device_handle::sptr handle, - unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers + size_t recv_endpoint, + size_t send_endpoint, + const device_addr_t &hints ){ libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( boost::static_pointer_cast(handle)->get_device() )); return sptr(new libusb_zero_copy_impl( - dev_handle, - recv_endpoint, send_endpoint, - recv_xfer_size, recv_num_xfers, - send_xfer_size, send_num_xfers + dev_handle, recv_endpoint, send_endpoint, hints )); } diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index e9d91fe45..ada282e07 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -44,7 +44,7 @@ static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(4 * 25e6 * 0.5); static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3); //the number of async frames to allocate for each send and recv -static const size_t DEFAULT_NUM_ASYNC_FRAMES = 32; +static const size_t DEFAULT_NUM_FRAMES = 32; //a single concurrent thread for io_service seems to be the fastest static const size_t CONCURRENCY_HINT = 1; @@ -61,14 +61,15 @@ public: typedef boost::shared_ptr sptr; udp_zero_copy_asio_impl( - const std::string &addr, const std::string &port, - size_t recv_frame_size, size_t num_recv_frames, - size_t send_frame_size, size_t num_send_frames + const std::string &addr, + const std::string &port, + const device_addr_t &hints ): - _io_service(CONCURRENCY_HINT), - _work(new asio::io_service::work(_io_service)), - _recv_frame_size(recv_frame_size), _num_recv_frames(num_recv_frames), - _send_frame_size(send_frame_size), _num_send_frames(num_send_frames) + _io_service(hints.cast("concurrency_hint", CONCURRENCY_HINT)), + _recv_frame_size(size_t(hints.cast("recv_frame_size", udp_simple::mtu))), + _num_recv_frames(size_t(hints.cast("num_recv_frames", DEFAULT_NUM_FRAMES))), + _send_frame_size(size_t(hints.cast("send_frame_size", udp_simple::mtu))), + _num_send_frames(size_t(hints.cast("num_send_frames", DEFAULT_NUM_FRAMES))) { //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; @@ -99,6 +100,7 @@ public: } //spawn the service threads that will run the io service + _work = new asio::io_service::work(_io_service); //new work to delete later for (size_t i = 0; i < CONCURRENCY_HINT; i++) _thread_group.create_thread( boost::bind(&udp_zero_copy_asio_impl::service, this) ); @@ -141,6 +143,7 @@ public: } size_t get_num_recv_frames(void) const {return _num_recv_frames;} + size_t get_recv_frame_size(void) const {return _recv_frame_size;} //! pop an empty send buffer off of the fifo and bind with the commit callback managed_send_buffer::sptr get_send_buff(double timeout){ @@ -159,6 +162,7 @@ public: } size_t get_num_send_frames(void) const {return _num_send_frames;} + size_t get_send_frame_size(void) const {return _send_frame_size;} private: void service(void){ @@ -260,14 +264,15 @@ template static void resize_buff_helper( udp_zero_copy::sptr udp_zero_copy::make( const std::string &addr, const std::string &port, - size_t recv_buff_size, - size_t send_buff_size + const device_addr_t &hints ){ - udp_zero_copy_asio_impl::sptr udp_trans(new udp_zero_copy_asio_impl( - addr, port, - udp_simple::mtu, DEFAULT_NUM_ASYNC_FRAMES, //recv - udp_simple::mtu, DEFAULT_NUM_ASYNC_FRAMES //send - )); + udp_zero_copy_asio_impl::sptr udp_trans( + new udp_zero_copy_asio_impl(addr, port, hints) + ); + + //extract buffer size hints from the device addr + size_t recv_buff_size = size_t(hints.cast("recv_buff_size", 0.0)); + size_t send_buff_size = size_t(hints.cast("send_buff_size", 0.0)); //call the helper to resize send and recv buffers resize_buff_helper(udp_trans, recv_buff_size, "recv"); diff --git a/host/lib/transport/usb_dummy_impl.cpp b/host/lib/transport/usb_dummy_impl.cpp index 518342aba..8a9772e7f 100644 --- a/host/lib/transport/usb_dummy_impl.cpp +++ b/host/lib/transport/usb_dummy_impl.cpp @@ -20,6 +20,7 @@ #include #include +using namespace uhd; using namespace uhd::transport; std::vector usb_device_handle::get_device_list(boost::uint16_t, boost::uint16_t){ @@ -32,8 +33,7 @@ usb_control::sptr usb_control::make(usb_device_handle::sptr){ usb_zero_copy::sptr usb_zero_copy::make( usb_device_handle::sptr, - unsigned int, unsigned int, - size_t, size_t, size_t, size_t + size_t, size_t, const device_addr_t & ){ throw std::runtime_error("no usb support -> usb_zero_copy::make not implemented"); } diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 6ebd6bb09..276ca86f6 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -106,17 +106,8 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) /*********************************************************************** * Make **********************************************************************/ -template static output_type cast_from_dev_addr( - const device_addr_t &device_addr, - const std::string &key, - output_type def_val -){ - return (device_addr.has_key(key))? - boost::lexical_cast(device_addr[key]) : def_val; -} +static device::sptr usrp1_make(const device_addr_t &device_addr){ -static device::sptr usrp1_make(const device_addr_t &device_addr) -{ //extract the FPGA path for the USRP1 std::string usrp1_fpga_image = find_image_path( device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf" @@ -127,29 +118,26 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) std::vector device_list = usb_device_handle::get_device_list(USRP1_VENDOR_ID, USRP1_PRODUCT_ID); - //create data and control transports - usb_zero_copy::sptr data_transport; - usrp_ctrl::sptr usrp_ctrl; - - - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { - if (handle->get_serial() == device_addr["serial"]) { - usb_control::sptr ctrl_transport = usb_control::make(handle); - usrp_ctrl = usrp_ctrl::make(ctrl_transport); - usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - - data_transport = usb_zero_copy::make( - handle, // identifier - 6, // IN endpoint - 2, // OUT endpoint - size_t(cast_from_dev_addr(device_addr, "recv_xfer_size", 0)), - size_t(cast_from_dev_addr(device_addr, "recv_num_xfers", 0)), - size_t(cast_from_dev_addr(device_addr, "send_xfer_size", 0)), - size_t(cast_from_dev_addr(device_addr, "send_num_xfers", 0)) - ); + //locate the matching handle in the device list + usb_device_handle::sptr handle; + BOOST_FOREACH(usb_device_handle::sptr dev_handle, device_list) { + if (dev_handle->get_serial() == device_addr["serial"]){ + handle = dev_handle; break; } } + UHD_ASSERT_THROW(handle.get() != NULL); //better be found + + //create control objects and a data transport + usb_control::sptr ctrl_transport = usb_control::make(handle); + usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); + usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); + usb_zero_copy::sptr data_transport = usb_zero_copy::make( + handle, // identifier + 6, // IN endpoint + 2, // OUT endpoint + device_addr // param hints + ); //create the usrp1 implementation guts return device::sptr(new usrp1_impl(data_transport, usrp_ctrl)); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 33cec3cbc..07eda08c3 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -206,7 +206,7 @@ size_t usrp2_impl::send( _io_impl->packet_handler_send_state, //last state of the send handler buffs, num_samps, //buffer to fill metadata, send_mode, //samples metadata - io_type, _io_helper.get_tx_otw_type(), //input and output types to convert + io_type, _tx_otw_type, //input and output types to convert _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_pack_be, boost::bind(&get_send_buffs, _data_transports, _1, timeout), @@ -226,7 +226,7 @@ size_t usrp2_impl::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler buffs, num_samps, //buffer to fill metadata, recv_mode, //samples metadata - io_type, _io_helper.get_rx_otw_type(), //input and output types to convert + io_type, _rx_otw_type, //input and output types to convert _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_unpack_be, boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout) diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 0b9f8ee83..a0e6adfad 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -38,10 +38,10 @@ using namespace uhd::usrp; usrp2_mboard_impl::usrp2_mboard_impl( size_t index, transport::udp_simple::sptr ctrl_transport, - const usrp2_io_helper &io_helper + size_t recv_frame_size ): _index(index), - _io_helper(io_helper) + _recv_frame_size(recv_frame_size) { //make a new interface for usrp2 stuff _iface = usrp2_iface::make(ctrl_transport); @@ -75,7 +75,7 @@ usrp2_mboard_impl::usrp2_mboard_impl( this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //init the rx control registers - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet()); + _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _recv_frame_size); _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 0 @@ -178,7 +178,7 @@ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, dsp_type1::calc_stream_cmd_word( - stream_cmd, _io_helper.get_max_recv_samps_per_packet() + stream_cmd, _recv_frame_size )); _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 568c87a22..a680708ad 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -124,26 +124,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -template -out_type lexical_cast(const in_type &in){ - try{ - return boost::lexical_cast(in); - }catch(...){ - throw std::runtime_error(str(boost::format( - "failed to cast \"%s\" to type \"%s\"" - ) % boost::lexical_cast(in) % typeid(out_type).name())); - } -} - static device::sptr usrp2_make(const device_addr_t &device_addr){ - //extract the receive and send buffer sizes - size_t recv_buff_size = 0, send_buff_size= 0 ; - if (device_addr.has_key("recv_buff_size")){ - recv_buff_size = size_t(lexical_cast(device_addr["recv_buff_size"])); - } - if (device_addr.has_key("send_buff_size")){ - send_buff_size = size_t(lexical_cast(device_addr["send_buff_size"])); - } //create a ctrl and data transport for each address std::vector ctrl_transports; @@ -154,8 +135,7 @@ static device::sptr usrp2_make(const device_addr_t &device_addr){ addr, num2str(USRP2_UDP_CTRL_PORT) )); data_transports.push_back(udp_zero_copy::make( - addr, num2str(USRP2_UDP_DATA_PORT), - recv_buff_size, send_buff_size + addr, num2str(USRP2_UDP_DATA_PORT), device_addr )); } @@ -178,11 +158,23 @@ usrp2_impl::usrp2_impl( ): _data_transports(data_transports) { + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + //!!!!! set the otw type here before continuing, its used below + //create a new mboard handler for each control transport for(size_t i = 0; i < ctrl_transports.size(); i++){ - _mboards.push_back(usrp2_mboard_impl::sptr( - new usrp2_mboard_impl(i, ctrl_transports[i], _io_helper) - )); + _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl( + i, ctrl_transports[i], this->get_max_recv_samps_per_packet() + ))); //use an empty name when there is only one mboard std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast(i) : ""; _mboard_dict[name] = _mboards.back(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e8763b284..e12c4d6d4 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -71,54 +71,6 @@ private: void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} }; -/*! - * The io helper class encapculates the max packet sizes and otw types. - * The otw types are read-only for now, this will be reimplemented - * when it becomes possible to change the otw type in the usrp2. - */ -class usrp2_io_helper{ -public: - usrp2_io_helper(void){ - //setup rx otw type - _rx_otw_type.width = 16; - _rx_otw_type.shift = 0; - _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; - - //setup tx otw type - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; - } - - inline size_t get_max_send_samps_per_packet(void) const{ - return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); - } - - inline size_t get_max_recv_samps_per_packet(void) const{ - return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); - } - - inline const uhd::otw_type_t &get_rx_otw_type(void) const{ - return _rx_otw_type; - } - - inline const uhd::otw_type_t &get_tx_otw_type(void) const{ - return _tx_otw_type; - } - -private: - uhd::otw_type_t _rx_otw_type, _tx_otw_type; - static const size_t _max_rx_bytes_per_packet = uhd::transport::udp_simple::mtu - - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(uhd::transport::vrt::if_packet_info_t().tlr) //forced to have trailer - + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used - ; - static const size_t _max_tx_bytes_per_packet = uhd::transport::udp_simple::mtu - - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used - ; -}; - /*! * USRP2 mboard implementation guts: * The implementation details are encapsulated here. @@ -129,7 +81,11 @@ public: typedef boost::shared_ptr sptr; //structors - usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr, const usrp2_io_helper &); + usrp2_mboard_impl( + size_t index, + uhd::transport::udp_simple::sptr, + size_t recv_frame_size + ); ~usrp2_mboard_impl(void); inline double get_master_clock_freq(void){ @@ -139,7 +95,7 @@ public: private: size_t _index; int _rev_hi, _rev_lo; - const usrp2_io_helper &_io_helper; + const size_t _recv_frame_size; //properties for this mboard void get(const wax::obj &, wax::obj &); @@ -229,7 +185,8 @@ public: //the io interface size_t get_max_send_samps_per_packet(void) const{ - return _io_helper.get_max_send_samps_per_packet(); + const size_t bytes_per_packet = _data_transports.front()->get_send_frame_size() - _max_tx_header_bytes; + return bytes_per_packet/_tx_otw_type.get_sample_size(); } size_t send( const std::vector &, size_t, @@ -237,7 +194,8 @@ public: uhd::device::send_mode_t, double ); size_t get_max_recv_samps_per_packet(void) const{ - return _io_helper.get_max_recv_samps_per_packet(); + const size_t bytes_per_packet = _data_transports.front()->get_recv_frame_size() - _max_rx_header_bytes; + return bytes_per_packet/_rx_otw_type.get_sample_size(); } size_t recv( const std::vector &, size_t, @@ -257,9 +215,20 @@ private: //io impl methods and members std::vector _data_transports; - const usrp2_io_helper _io_helper; UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); + + //over-the-wire structs and constants + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + static const size_t _max_rx_header_bytes = 0 + + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(uhd::transport::vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used + ; + static const size_t _max_tx_header_bytes = 0 + + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + - sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used + ; }; #endif /* INCLUDED_USRP2_IMPL_HPP */ -- cgit v1.2.3 From d5a0960455560e9f6077aa45d52aa01c469769dd Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 6 Oct 2010 16:26:35 -0700 Subject: usrp-e: implemented the USER_PROCESS flag and CTM poll technique --- host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp | 33 +++++++++++--------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp index 9e25ed088..4e10bcc48 100644 --- a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp @@ -31,6 +31,7 @@ using namespace uhd::transport; static const bool fp_verbose = true; //fast-path verbose static const bool sp_verbose = true; //slow-path verbose +static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout /*********************************************************************** * The zero copy interface implementation @@ -104,19 +105,19 @@ public: //poll/wait for a ready frame if (not (info->flags & RB_USER)){ - pollfd pfd; - pfd.fd = _fd; - pfd.events = POLLIN; - ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3)); - if (fp_verbose) std::cout << " POLLIN: " << poll_ret << std::endl; - if (poll_ret <= 0) return managed_recv_buffer::sptr(); - } - - //check that the frame is really ready - if (not (info->flags & RB_USER)){ - if (fp_verbose) std::cout << " flags: not ready" << std::endl; - return managed_recv_buffer::sptr(); - } + for (size_t i = 0; i < poll_breakout; i++){ + pollfd pfd; + pfd.fd = _fd; + pfd.events = POLLIN; + ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3/poll_breakout)); + if (fp_verbose) std::cout << " POLLIN: " << poll_ret << std::endl; + if (poll_ret > 0) goto found_user_frame; //good poll, continue on + } + return managed_recv_buffer::sptr(); //timed-out for real + } found_user_frame: + + //the process has claimed the frame + info->flags = RB_USER_PROCESS; //increment the index for the next call if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0; @@ -150,12 +151,6 @@ public: if (poll_ret <= 0) return managed_send_buffer::sptr(); } - //check that the frame is really ready - if (not (info->flags & RB_KERNEL)){ - if (fp_verbose) std::cout << " flags: not ready" << std::endl; - return managed_send_buffer::sptr(); - } - //increment the index for the next call if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0; -- cgit v1.2.3 From b40ace72dd1b940fc0ce6e4a5e06346439dd5625 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 6 Oct 2010 18:41:30 -0700 Subject: usrp1: use the transport frame sizes to calculate the max spp The max send spp is the frame size minus the alignment padding. This allows us to copy a remainder into a new buffer and always commit multiples of the alignment size (512 bytes). Reworked the managed send buffer implementation to handle the above. Uses only managed memory, and only mem-copied under the alignment. --- host/lib/usrp/usrp1/io_impl.cpp | 169 +++++++++++++++++++++---------------- host/lib/usrp/usrp1/usrp1_impl.hpp | 10 +-- 2 files changed, 99 insertions(+), 80 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 676b1536a..0a16f7a43 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,6 +33,28 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; +static const size_t alignment_padding = 512; + +/*********************************************************************** + * Helper struct to associate an offset with a buffer + **********************************************************************/ +class offset_send_buffer{ +public: + typedef boost::shared_ptr sptr; + + static sptr make(managed_send_buffer::sptr buff, size_t offset = 0){ + return sptr(new offset_send_buffer(buff, offset)); + } + + //member variables + managed_send_buffer::sptr buff; + size_t offset; /* in bytes */ + +private: + offset_send_buffer(managed_send_buffer::sptr buff, size_t offset): + buff(buff), offset(offset){/* NOP */} +}; + /*********************************************************************** * IO Implementation Details **********************************************************************/ @@ -41,8 +63,7 @@ struct usrp1_impl::io_impl{ data_transport(data_transport), underflow_poll_samp_count(0), overflow_poll_samp_count(0), - send_buff(data_transport->get_send_buff()), - num_bytes_committed(0) + curr_buff(offset_send_buffer::make(data_transport->get_send_buff())) { /* NOP */ } @@ -62,98 +83,88 @@ struct usrp1_impl::io_impl{ size_t overflow_poll_samp_count; //wrapper around the actual send buffer interface - //all of this to ensure only full buffers are committed - managed_send_buffer::sptr send_buff; - size_t num_bytes_committed; - double send_timeout; - boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; - void phony_commit_pseudo_buff(size_t num_bytes); - void phony_commit_send_buff(size_t num_bytes); - void commit_send_buff(void); + //all of this to ensure only aligned lengths are committed + //NOTE: you must commit before getting a new buffer + //since the vrt packet handler obeys this, we are ok + offset_send_buffer::sptr curr_buff; + void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t); void flush_send_buff(void); bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double); - - //helpers to get at the send buffer + offset - inline void *get_send_mem_ptr(void){ - return send_buff->cast() + num_bytes_committed; - } - inline size_t get_send_mem_size(void){ - return send_buff->size() - num_bytes_committed; - } }; /*! - * Accept a commit of num bytes to the pseudo buffer. - * Memcpy the entire contents of pseudo buffer into send buffers. - * - * Under most conditions: - * The first loop iteration will fill the remainder of the send buffer. - * The second loop iteration will empty the pseudo buffer remainder. + * Perform an actual commit on the send buffer: + * Copy the remainder of alignment to the next buffer. + * Commit the current buffer at multiples of alignment. */ -void usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){ - size_t bytes_to_copy = num_bytes, bytes_copied = 0; - while(bytes_to_copy){ - size_t bytes_copied_here = std::min(bytes_to_copy, get_send_mem_size()); - std::memcpy(get_send_mem_ptr(), pseudo_buff + bytes_copied, bytes_copied_here); - phony_commit_send_buff(bytes_copied_here); - bytes_to_copy -= bytes_copied_here; - bytes_copied += bytes_copied_here; - } -} +void usrp1_impl::io_impl::commit_send_buff( + offset_send_buffer::sptr curr, + offset_send_buffer::sptr next, + size_t num_bytes +){ + //total number of bytes now in the current buffer + size_t bytes_in_curr_buffer = curr->offset + num_bytes; -/*! - * Accept a commit of num bytes to the send buffer. - * Conditionally commit the send buffer if full. - */ -void usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){ - num_bytes_committed += num_bytes; - if (num_bytes_committed != send_buff->size()) return; - commit_send_buff(); + //calculate how many to commit and remainder + size_t num_bytes_remaining = bytes_in_curr_buffer % alignment_padding; + size_t num_bytes_to_commit = bytes_in_curr_buffer - num_bytes_remaining; + + //copy the remainder into the next buffer + std::memcpy( + next->buff->cast() + next->offset, + curr->buff->cast() + num_bytes_to_commit, + num_bytes_remaining + ); + + //update the offset into the next buffer + next->offset += num_bytes_remaining; + + //commit the current buffer + curr->buff->commit(num_bytes_to_commit); } /*! - * Flush the send buffer: - * Zero-pad the send buffer to the nearest 512 byte boundary and commit. + * Flush the current buffer by padding out to alignment and committing. */ void usrp1_impl::io_impl::flush_send_buff(void){ - size_t bytes_to_pad = (-1*num_bytes_committed)%512; - std::memset(get_send_mem_ptr(), 0, bytes_to_pad); - num_bytes_committed += bytes_to_pad; - commit_send_buff(); + //calculate the number of bytes to alignment + size_t bytes_to_pad = (-1*curr_buff->offset)%alignment_padding; + + //get the buffer, clear, and commit (really current buffer) + vrt_packet_handler::managed_send_buffs_t buffs(1); + if (this->get_send_buffs(buffs, 0.1)){ + std::memset(buffs[0]->cast(), 0, bytes_to_pad); + buffs[0]->commit(bytes_to_pad); + } } /*! - * Perform an actual commit on the send buffer: - * Commit the contents of the send buffer and request a new buffer. + * Get a managed send buffer with the alignment padding: + * Always grab the next send buffer so we can timeout here. */ -void usrp1_impl::io_impl::commit_send_buff(void){ - send_buff->commit(num_bytes_committed); - send_buff = data_transport->get_send_buff(send_timeout); - num_bytes_committed = 0; -} - bool usrp1_impl::io_impl::get_send_buffs( vrt_packet_handler::managed_send_buffs_t &buffs, double timeout ){ - send_timeout = timeout; UHD_ASSERT_THROW(buffs.size() == 1); - //not enough bytes free -> use the pseudo buffer - if (get_send_mem_size() < BYTES_PER_PACKET){ - buffs[0] = managed_send_buffer::make_safe( - boost::asio::buffer(pseudo_buff), - boost::bind(&usrp1_impl::io_impl::phony_commit_pseudo_buff, this, _1) - ); - } - //otherwise use the send buffer offset by the bytes written - else{ - buffs[0] = managed_send_buffer::make_safe( - boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()), - boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1) - ); - } + //try to get a new managed buffer with timeout + offset_send_buffer::sptr next_buff(offset_send_buffer::make(data_transport->get_send_buff(timeout))); + if (not next_buff->buff.get()) return false; /* propagate timeout here */ - return buffs[0].get() != NULL; + //calculate the buffer pointer and size given the offset + //references to the buffers are held in the bound function + buffs[0] = managed_send_buffer::make_safe( + boost::asio::buffer( + curr_buff->buff->cast() + curr_buff->offset, + curr_buff->buff->size() - curr_buff->offset + ), + boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, curr_buff, next_buff, _1) + ); + + //store the next buffer for the next call + curr_buff = next_buff; + + return true; } /*********************************************************************** @@ -182,6 +193,13 @@ static void usrp1_bs_vrt_packer( if_packet_info.num_packet_words32 = if_packet_info.num_payload_words32; } +size_t usrp1_impl::get_max_send_samps_per_packet(void) const { + return (_data_transport->get_send_frame_size() - alignment_padding) + / _tx_otw_type.get_sample_size() + / _tx_subdev_spec.size() + ; +} + size_t usrp1_impl::send( const std::vector &buffs, size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, @@ -249,6 +267,13 @@ static bool get_recv_buffs( return buffs[0].get() != NULL; } +size_t usrp1_impl::get_max_recv_samps_per_packet(void) const { + return _data_transport->get_recv_frame_size() + / _rx_otw_type.get_sample_size() + / _rx_subdev_spec.size() + ; +} + size_t usrp1_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f2c464610..ff4d40762 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -90,15 +90,9 @@ public: const uhd::io_type_t &, recv_mode_t, double); - static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size + size_t get_max_send_samps_per_packet(void) const; - size_t get_max_send_samps_per_packet(void) const { - return BYTES_PER_PACKET/_tx_otw_type.get_sample_size()/_tx_subdev_spec.size(); - } - - size_t get_max_recv_samps_per_packet(void) const { - return BYTES_PER_PACKET/_rx_otw_type.get_sample_size()/_rx_subdev_spec.size(); - } + size_t get_max_recv_samps_per_packet(void) const; bool recv_async_msg(uhd::async_metadata_t &, double); -- cgit v1.2.3 From be6a6b291400dde7b2b3b935e2eedd8d892e54f8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 7 Oct 2010 10:27:30 -0700 Subject: usrp-e: use frame size to calculate the max samples per packet --- host/lib/usrp/usrp_e/io_impl.cpp | 43 ++++++++++++++++++-------- host/lib/usrp/usrp_e/usrp_e_impl.hpp | 6 ++-- host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp | 8 +++++ 3 files changed, 42 insertions(+), 15 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/io_impl.cpp b/host/lib/usrp/usrp_e/io_impl.cpp index 2802a6b87..406b7269f 100644 --- a/host/lib/usrp/usrp_e/io_impl.cpp +++ b/host/lib/usrp/usrp_e/io_impl.cpp @@ -91,7 +91,6 @@ void usrp_e_impl::io_impl::recv_pirate_loop( ){ set_thread_priority_safe(); recv_pirate_crew_raiding = true; - //size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(); @@ -143,6 +142,15 @@ void usrp_e_impl::io_impl::recv_pirate_loop( * Helper Functions **********************************************************************/ void usrp_e_impl::io_init(void){ + //setup otw types + _send_otw_type.width = 16; + _send_otw_type.shift = 0; + _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + + _recv_otw_type.width = 16; + _recv_otw_type.shift = 0; + _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + //setup rx data path _iface->poke32(UE_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); _iface->poke32(UE_REG_CTRL_RX_NCHANNELS, 1); @@ -197,21 +205,25 @@ bool get_send_buffs( return buffs[0].get() != NULL; } +size_t usrp_e_impl::get_max_send_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + size_t bpp = _io_impl->data_xport->get_send_frame_size() - hdr_size; + return bpp/_send_otw_type.get_sample_size(); +} + size_t usrp_e_impl::send( const std::vector &buffs, size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode, double timeout ){ - otw_type_t send_otw_type; - send_otw_type.width = 16; - send_otw_type.shift = 0; - send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - return vrt_packet_handler::send( _io_impl->packet_handler_send_state, //last state of the send handler buffs, num_samps, //buffer to fill metadata, send_mode, //samples metadata - io_type, send_otw_type, //input and output types to convert + io_type, _send_otw_type, //input and output types to convert MASTER_CLOCK_RATE, //master clock tick rate uhd::transport::vrt::if_hdr_pack_le, boost::bind(&get_send_buffs, _io_impl->data_xport, timeout, _1), @@ -222,21 +234,26 @@ size_t usrp_e_impl::send( /*********************************************************************** * Data Recv **********************************************************************/ +size_t usrp_e_impl::get_max_recv_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + size_t bpp = _io_impl->data_xport->get_recv_frame_size() - hdr_size; + return bpp/_recv_otw_type.get_sample_size(); +} + size_t usrp_e_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, double timeout ){ - otw_type_t recv_otw_type; - recv_otw_type.width = 16; - recv_otw_type.shift = 0; - recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - return vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler buffs, num_samps, //buffer to fill metadata, recv_mode, //samples metadata - io_type, recv_otw_type, //input and output types to convert + io_type, _recv_otw_type, //input and output types to convert MASTER_CLOCK_RATE, //master clock tick rate uhd::transport::vrt::if_hdr_unpack_le, boost::bind(&usrp_e_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout), diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp index 49912050e..95d80fed5 100644 --- a/host/lib/usrp/usrp_e/usrp_e_impl.hpp +++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -85,8 +86,8 @@ public: size_t send(const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); size_t recv(const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); bool recv_async_msg(uhd::async_metadata_t &, double); - size_t get_max_send_samps_per_packet(void) const{return 503;} - size_t get_max_recv_samps_per_packet(void) const{return 503;} + size_t get_max_send_samps_per_packet(void) const; + size_t get_max_recv_samps_per_packet(void) const; private: //interface to ioctls and file descriptor @@ -97,6 +98,7 @@ private: //handle io stuff UHD_PIMPL_DECL(io_impl) _io_impl; + uhd::otw_type_t _send_otw_type, _recv_otw_type; void io_init(void); void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); void handle_overrun(size_t); diff --git a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp index 4e10bcc48..bc18c490b 100644 --- a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp @@ -134,6 +134,10 @@ public: return _rb_size.num_rx_frames; } + size_t get_recv_frame_size(void) const{ + return _frame_size; + } + managed_send_buffer::sptr get_send_buff(double timeout){ if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl; @@ -166,6 +170,10 @@ public: return _rb_size.num_tx_frames; } + size_t get_send_frame_size(void) const{ + return _frame_size; + } + private: void release(ring_buffer_info *info){ -- cgit v1.2.3 From 0059e62ed067a4844edfb720da73fcdb8e69db6a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 7 Oct 2010 10:43:58 -0700 Subject: usrp2: moved samples per packet calculation into io_impl --- host/lib/usrp/usrp2/io_impl.cpp | 19 +++++++++++++++++++ host/lib/usrp/usrp2/usrp2_impl.hpp | 23 +++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 07eda08c3..eba704059 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -197,6 +197,15 @@ static bool get_send_buffs( return good; } +size_t usrp2_impl::get_max_send_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + const size_t bpp = _data_transports.front()->get_send_frame_size() - hdr_size; + return bpp/_tx_otw_type.get_sample_size(); +} + size_t usrp2_impl::send( const std::vector &buffs, size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, @@ -217,6 +226,16 @@ size_t usrp2_impl::send( /*********************************************************************** * Receive Data **********************************************************************/ +size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + const size_t bpp = _data_transports.front()->get_recv_frame_size() - hdr_size; + return bpp/_rx_otw_type.get_sample_size(); +} + size_t usrp2_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e12c4d6d4..558726a2b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -184,24 +184,18 @@ public: ~usrp2_impl(void); //the io interface - size_t get_max_send_samps_per_packet(void) const{ - const size_t bytes_per_packet = _data_transports.front()->get_send_frame_size() - _max_tx_header_bytes; - return bytes_per_packet/_tx_otw_type.get_sample_size(); - } size_t send( const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, uhd::device::send_mode_t, double ); - size_t get_max_recv_samps_per_packet(void) const{ - const size_t bytes_per_packet = _data_transports.front()->get_recv_frame_size() - _max_rx_header_bytes; - return bytes_per_packet/_rx_otw_type.get_sample_size(); - } size_t recv( const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, uhd::device::recv_mode_t, double ); + size_t get_max_send_samps_per_packet(void) const; + size_t get_max_recv_samps_per_packet(void) const; bool recv_async_msg(uhd::async_metadata_t &, double); private: @@ -215,20 +209,9 @@ private: //io impl methods and members std::vector _data_transports; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); - - //over-the-wire structs and constants - uhd::otw_type_t _rx_otw_type, _tx_otw_type; - static const size_t _max_rx_header_bytes = 0 - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t().tlr) //forced to have trailer - - sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used - ; - static const size_t _max_tx_header_bytes = 0 - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used - ; }; #endif /* INCLUDED_USRP2_IMPL_HPP */ -- cgit v1.2.3 From 5514e67c64551e8c1d9e706f63be487aa6912705 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 7 Oct 2010 11:06:37 -0700 Subject: usrp1: ensure that the current buffer was committed before getting a new one --- host/lib/usrp/usrp1/io_impl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 0a16f7a43..6728d9b15 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -63,6 +63,7 @@ struct usrp1_impl::io_impl{ data_transport(data_transport), underflow_poll_samp_count(0), overflow_poll_samp_count(0), + curr_buff_committed(true), curr_buff(offset_send_buffer::make(data_transport->get_send_buff())) { /* NOP */ @@ -86,6 +87,7 @@ struct usrp1_impl::io_impl{ //all of this to ensure only aligned lengths are committed //NOTE: you must commit before getting a new buffer //since the vrt packet handler obeys this, we are ok + bool curr_buff_committed; offset_send_buffer::sptr curr_buff; void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t); void flush_send_buff(void); @@ -121,6 +123,7 @@ void usrp1_impl::io_impl::commit_send_buff( //commit the current buffer curr->buff->commit(num_bytes_to_commit); + curr_buff_committed = true; } /*! @@ -145,7 +148,7 @@ void usrp1_impl::io_impl::flush_send_buff(void){ bool usrp1_impl::io_impl::get_send_buffs( vrt_packet_handler::managed_send_buffs_t &buffs, double timeout ){ - UHD_ASSERT_THROW(buffs.size() == 1); + UHD_ASSERT_THROW(curr_buff_committed and buffs.size() == 1); //try to get a new managed buffer with timeout offset_send_buffer::sptr next_buff(offset_send_buffer::make(data_transport->get_send_buff(timeout))); @@ -163,6 +166,7 @@ bool usrp1_impl::io_impl::get_send_buffs( //store the next buffer for the next call curr_buff = next_buff; + curr_buff_committed = false; return true; } -- cgit v1.2.3 From 4c3b5212b1b91b30b44af72365448ea6af66c408 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 7 Oct 2010 12:37:42 -0700 Subject: tvrx: converted floats to doubles to avoid msvc warnings --- host/lib/usrp/dboard/db_tvrx.cpp | 110 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 55 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 41c52fbf5..33507acaa 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -66,25 +66,25 @@ static const uhd::dict tvrx_freq_ranges = map_list_of ("UHF" , freq_range_t(454e6, 860e6)) ; -static const boost::array vhflo_gains_db = +static const boost::array vhflo_gains_db = {{-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, 50.30000, 50.30000}}; - -static const boost::array vhfhi_gains_db = + +static const boost::array vhfhi_gains_db = {{13.3000, -13.3000, -13.3000, -1.0000, 7.7000, 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, 48.2000, 48.2000}}; - -static const boost::array uhf_gains_db = + +static const boost::array uhf_gains_db = {{-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, 43.2000, 43.8000}}; - -static const boost::array tvrx_if_gains_db = + +static const boost::array tvrx_if_gains_db = {{-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, @@ -96,32 +96,32 @@ static const boost::array tvrx_if_gains_db = //need dang near as many coefficients as to just map it like this and interp. //these numbers are culled from the 4937DI5 datasheet and are probably totally inaccurate //but if it's better than the old linear fit i'm happy -static const uhd::dict > tvrx_rf_gains_db = map_list_of +static const uhd::dict > tvrx_rf_gains_db = map_list_of ("VHFLO", vhflo_gains_db) ("VHFHI", vhfhi_gains_db) ("UHF" , uhf_gains_db) ; //sample voltages for the above points -static const boost::array tvrx_gains_volts = +static const boost::array tvrx_gains_volts = {{0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0}}; static uhd::dict get_tvrx_gain_ranges(void) { - float rfmax = 0.0, rfmin = FLT_MAX; + double rfmax = 0.0, rfmin = FLT_MAX; BOOST_FOREACH(const std::string range, tvrx_rf_gains_db.keys()) { - float my_max = tvrx_rf_gains_db[range].back(); //we're assuming it's monotonic - float my_min = tvrx_rf_gains_db[range].front(); //if it's not this is wrong wrong wrong + double my_max = tvrx_rf_gains_db[range].back(); //we're assuming it's monotonic + double my_min = tvrx_rf_gains_db[range].front(); //if it's not this is wrong wrong wrong if(my_max > rfmax) rfmax = my_max; if(my_min < rfmin) rfmin = my_min; } - - float ifmin = tvrx_if_gains_db.front(); - float ifmax = tvrx_if_gains_db.back(); - + + double ifmin = tvrx_if_gains_db.front(); + double ifmax = tvrx_if_gains_db.back(); + return map_list_of - ("RF", gain_range_t(rfmin, rfmax, (rfmax-rfmin)/4096.0)) - ("IF", gain_range_t(ifmin, ifmax, (ifmax-ifmin)/4096.0)) - ; + ("RF", gain_range_t(float(rfmin), float(rfmax), float((rfmax-rfmin)/4096.0))) + ("IF", gain_range_t(float(ifmin), float(ifmax), float((ifmax-ifmin)/4096.0))) + ; } static const double opamp_gain = 1.22; //onboard DAC opamp gain @@ -136,7 +136,7 @@ class tvrx : public rx_dboard_base{ public: tvrx(ctor_args_t args); ~tvrx(void); - + void rx_get(const wax::obj &key, wax::obj &val); void rx_set(const wax::obj &key, const wax::obj &val); @@ -198,11 +198,11 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ } //send initial register settings if necessary - + //set default freq _lo_freq = tvrx_freq_range.min + tvrx_if_freq; //init _lo_freq to a sane default set_freq(tvrx_freq_range.min); - + //set default gains BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){ set_gain(get_tvrx_gain_ranges()[name].min, name); @@ -238,33 +238,33 @@ static std::string get_band(double freq) { * \return a voltage to feed the TVRX analog gain */ -static float gain_interp(float gain, boost::array db_vector, boost::array volts_vector) { - float volts; - gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here - +static double gain_interp(double gain, boost::array db_vector, boost::array volts_vector) { + double volts; + gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here + boost::uint8_t gain_step = 0; //find which bin we're in for(size_t i = 0; i < db_vector.size()-1; i++) { if(gain >= db_vector[i] && gain <= db_vector[i+1]) gain_step = i; } - + //find the current slope for linear interpolation - float slope = (volts_vector[gain_step + 1] - volts_vector[gain_step]) + double slope = (volts_vector[gain_step + 1] - volts_vector[gain_step]) / (db_vector[gain_step + 1] - db_vector[gain_step]); - + //the problem here is that for gains approaching the maximum, the voltage slope becomes infinite //i.e., a small change in gain requires an infinite change in voltage //to cope, we limit the slope - - if(slope == std::numeric_limits::infinity()) + + if(slope == std::numeric_limits::infinity()) return volts_vector[gain_step]; //use the volts per dB slope to find the final interpolated voltage volts = volts_vector[gain_step] + (slope * (gain - db_vector[gain_step])); - + if(tvrx_debug) std::cout << "Gain interp: gain: " << gain << ", gain_step: " << int(gain_step) << ", slope: " << slope << ", volts: " << volts << std::endl; - + return volts; } @@ -283,17 +283,17 @@ static float rf_gain_to_voltage(float gain, double lo_freq){ std::string band = get_band(lo_freq + tvrx_if_freq); //this is the voltage at the TVRX gain input - float gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts); + double gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts); //this is the voltage at the USRP DAC output - float dac_volts = gain_volts / opamp_gain; - - dac_volts = std::clip(dac_volts, 0.0, 3.3); + double dac_volts = gain_volts / opamp_gain; + + dac_volts = std::clip(dac_volts, 0.0, 3.3); if (tvrx_debug) std::cerr << boost::format( "tvrx RF AGC gain: %f dB, dac_volts: %f V" ) % gain % dac_volts << std::endl; - return dac_volts; + return float(dac_volts); } /*! @@ -306,17 +306,17 @@ static float rf_gain_to_voltage(float gain, double lo_freq){ static float if_gain_to_voltage(float gain){ //clip the input gain = std::clip(gain, get_tvrx_gain_ranges()["IF"].min, get_tvrx_gain_ranges()["IF"].max); - - float gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts); - float dac_volts = gain_volts / opamp_gain; - - dac_volts = std::clip(dac_volts, 0.0, 3.3); + + double gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts); + double dac_volts = gain_volts / opamp_gain; + + dac_volts = std::clip(dac_volts, 0.0, 3.3); if (tvrx_debug) std::cerr << boost::format( "tvrx IF AGC gain: %f dB, dac_volts: %f V" ) % gain % dac_volts << std::endl; - return dac_volts; + return float(dac_volts); } void tvrx::set_gain(float gain, const std::string &name){ @@ -337,27 +337,27 @@ void tvrx::set_gain(float gain, const std::string &name){ */ void tvrx::set_freq(double freq) { - freq = std::clip(freq, tvrx_freq_range.min, tvrx_freq_range.max); + freq = std::clip(freq, tvrx_freq_range.min, tvrx_freq_range.max); std::string prev_band = get_band(_lo_freq - tvrx_if_freq); std::string new_band = get_band(freq); - + double target_lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing double f_ref = reference_freq / double(reference_divider); //your tuning step size - + int divisor = int((target_lo_freq + (f_ref * 4.0)) / (f_ref * 8)); //the divisor we'll use double actual_lo_freq = (f_ref * 8 * divisor); //the LO freq we'll actually get - + if((divisor & ~0x7fff)) UHD_THROW_INVALID_CODE_PATH(); - + //now we update the registers _tuner_4937di5_regs.db1 = (divisor >> 8) & 0xff; _tuner_4937di5_regs.db2 = divisor & 0xff; - + if(new_band == "VHFLO") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFLO; else if(new_band == "VHFHI") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFHI; else if(new_band == "UHF") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_UHF; else UHD_THROW_INVALID_CODE_PATH(); - + _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_OFF; update_regs(); @@ -365,10 +365,10 @@ void tvrx::set_freq(double freq) { //we do this because the gains are different for different band settings //not FAR off, but we do this to be consistent if(prev_band != new_band) set_gain(_gains["RF"], "RF"); - - if(tvrx_debug) + + if(tvrx_debug) std::cout << boost::format("set_freq: target LO: %f f_ref: %f divisor: %i actual LO: %f") % target_lo_freq % f_ref % divisor % actual_lo_freq << std::endl; - + _lo_freq = actual_lo_freq; //for rx props } @@ -422,7 +422,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - /* + /* * so here we have to do some magic. because the TVRX uses a relatively high IF, * we have to watch the sample rate to see if the IF will be aliased * or if it will fall within Nyquist. -- cgit v1.2.3 From 4b5792d2a5c6d101f602b5854fb2e7cfb3acf602 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 8 Oct 2010 14:00:56 -0700 Subject: tvrx: added enabled prop to set and get --- host/lib/usrp/dboard/db_tvrx.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 33507acaa..b1fc2ea76 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -447,6 +447,10 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ val = SUBDEV_CONN_COMPLEX_IQ; return; + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; @@ -467,10 +471,14 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_GAIN: this->set_gain(val.as(), key.name); return; + case SUBDEV_PROP_FREQ: this->set_freq(val.as()); return; + case SUBDEV_PROP_ENABLED: + return; //always enabled + default: UHD_THROW_PROP_SET_ERROR(); } } -- cgit v1.2.3 From 1190bc5c1a7bd0946bc55373eca58ec60a100f63 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 8 Oct 2010 15:52:33 -0700 Subject: usrp: added calls to get subdev and mboard canonical names --- host/include/uhd/usrp/single_usrp.hpp | 16 +++++++++++++--- host/lib/usrp/single_usrp.cpp | 18 +++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp index 1b89a3620..bc6943478 100644 --- a/host/include/uhd/usrp/single_usrp.hpp +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -57,15 +57,21 @@ public: */ virtual device::sptr get_device(void) = 0; + /******************************************************************* + * Mboard methods + ******************************************************************/ /*! * Get a printable name for this usrp. * \return a printable string */ virtual std::string get_pp_string(void) = 0; - /******************************************************************* - * Misc - ******************************************************************/ + /*! + * Get canonical name for this USRP motherboard. + * \return a string representing the name + */ + virtual std::string get_mboard_name(void) = 0; + /*! * Gets the current time in the usrp time registers. * \return a timespec representing current usrp time @@ -113,6 +119,8 @@ public: virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0; + virtual std::string get_rx_subdev_name(size_t chan = 0) = 0; + virtual void set_rx_rate(double rate) = 0; virtual double get_rx_rate(void) = 0; @@ -146,6 +154,8 @@ public: virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0; + virtual std::string get_tx_subdev_name(size_t chan = 0) = 0; + virtual void set_tx_rate(double rate) = 0; virtual double get_tx_rate(void) = 0; diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index bb4af44b8..08dc3bb1d 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -54,6 +54,9 @@ public: return _dev; } + /******************************************************************* + * Mboard methods + ******************************************************************/ std::string get_pp_string(void){ std::string buff = str(boost::format( "Single USRP:\n" @@ -101,9 +104,10 @@ public: return buff; } - /******************************************************************* - * Misc - ******************************************************************/ + std::string get_mboard_name(void){ + return _mboard()[MBOARD_PROP_NAME].as(); + } + time_spec_t get_time_now(void){ return _mboard()[MBOARD_PROP_TIME_NOW].as(); } @@ -135,6 +139,10 @@ public: return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as(); } + std::string get_rx_subdev_name(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_NAME].as(); + } + void set_rx_rate(double rate){ _rx_dsp()[DSP_PROP_HOST_RATE] = rate; } @@ -206,6 +214,10 @@ public: return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as(); } + std::string get_tx_subdev_name(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_NAME].as(); + } + void set_tx_rate(double rate){ _tx_dsp()[DSP_PROP_HOST_RATE] = rate; } -- cgit v1.2.3 From 86d6bceb0d37197d0fd8ace19fdedc957c5dfb84 Mon Sep 17 00:00:00 2001 From: Jason Abele Date: Fri, 8 Oct 2010 17:03:27 -0700 Subject: Fixed Assertions to better document tuning failures --- host/lib/usrp/dboard/db_dbsrx.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 23cafea53..327cb5f75 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -277,15 +277,17 @@ void dbsrx::set_lo_freq(double target_freq){ } } - //Assert because we failed to find a suitable combination of ref_clock, R and N - UHD_ASSERT_THROW(ref_clock/(1 << m) < 1e6 or ref_clock/(1 << m) > 2.5e6); - UHD_ASSERT_THROW((pfd_freq < dbsrx_pfd_freq_range.min) or (pfd_freq > dbsrx_pfd_freq_range.max)); - UHD_ASSERT_THROW((N < 256) or (N > 32768)); done_loop: + //Assert because we failed to find a suitable combination of ref_clock, R and N + UHD_ASSERT_THROW(ref_clock < 27.0e6 and ref_clock > 0.0); + UHD_ASSERT_THROW(ref_clock/m > 1e6 and ref_clock/m < 2.5e6); + UHD_ASSERT_THROW((pfd_freq > dbsrx_pfd_freq_range.min) and (pfd_freq < dbsrx_pfd_freq_range.max)); + UHD_ASSERT_THROW((N > 256) and (N < 32768)); + if(dbsrx_debug) std::cerr << boost::format( - "DBSRX: choose ref_clock %f and m_divider %d" - ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl; + "DBSRX: choose ref_clock (current: %f, new: %f) and m_divider %d" + ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % ref_clock % m << std::endl; //if ref_clock or m divider changed, we need to update the filter settings if (ref_clock != this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) or m != _max2118_write_regs.m_divider) update_filter_settings = true; -- cgit v1.2.3 From 8aac27fa3e427e0ff09c111127da162356d2bac5 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Fri, 8 Oct 2010 17:54:01 -0700 Subject: TVRX documentation and a bugfix in the cal table. Named the antenna "RX". --- host/docs/dboards.rst | 9 +++++++++ host/lib/usrp/dboard/db_tvrx.cpp | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 738a0696d..4ad724c82 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -107,6 +107,15 @@ Transmit Gains: **PGA0**, Range: 0-25dB Recieve Gains: **PGA0**, Range: 0-31.5dB +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +TVRX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Receive Antennas: RX + +Receive Gains: + * **RF**, Range: -13.3-50.3dB (frequency-dependent) + * **IF**, Range: -1.5-32.5dB + ------------------------------------------------------------------------ Daughterboard Modifications ------------------------------------------------------------------------ diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index b1fc2ea76..10be8d1c3 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -58,7 +58,7 @@ static const bool tvrx_debug = false; static const freq_range_t tvrx_freq_range(50e6, 860e6); -static const prop_names_t tvrx_antennas = list_of(""); //only got one +static const prop_names_t tvrx_antennas = list_of("RX"); static const uhd::dict tvrx_freq_ranges = map_list_of ("VHFLO", freq_range_t(50e6, 158e6)) @@ -73,7 +73,7 @@ static const boost::array vhflo_gains_db = 50.30000, 50.30000}}; static const boost::array vhfhi_gains_db = - {{13.3000, -13.3000, -13.3000, -1.0000, 7.7000, + {{-13.3000, -13.3000, -13.3000, -1.0000, 7.7000, 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, 48.2000, 48.2000}}; @@ -436,7 +436,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_ANTENNA: - val = std::string(""); + val = tvrx_antennas.front(); //there's only one return; case SUBDEV_PROP_ANTENNA_NAMES: -- cgit v1.2.3 From 5898d378522905208bc49b2a4a30a5c04fba639b Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 11 Oct 2010 16:25:15 -0700 Subject: DBSRX: Fixed some ASSERT statements. --- host/lib/usrp/dboard/db_dbsrx.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 327cb5f75..99137dda3 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -239,7 +239,6 @@ void dbsrx::set_lo_freq(double target_freq){ double actual_freq=0.0, pfd_freq=0.0, ref_clock=0.0; int R=0, N=0, r=0, m=0; bool update_filter_settings = false; - //choose refclock std::vector clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX); BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){ @@ -251,7 +250,7 @@ void dbsrx::set_lo_freq(double target_freq){ if(dbsrx_debug) std::cerr << boost::format( "DBSRX: trying ref_clock %f and m_divider %d" - ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl; + ) % (ref_clock) % m << std::endl; if (m >= 32) continue; @@ -280,10 +279,10 @@ void dbsrx::set_lo_freq(double target_freq){ done_loop: //Assert because we failed to find a suitable combination of ref_clock, R and N - UHD_ASSERT_THROW(ref_clock < 27.0e6 and ref_clock > 0.0); - UHD_ASSERT_THROW(ref_clock/m > 1e6 and ref_clock/m < 2.5e6); - UHD_ASSERT_THROW((pfd_freq > dbsrx_pfd_freq_range.min) and (pfd_freq < dbsrx_pfd_freq_range.max)); - UHD_ASSERT_THROW((N > 256) and (N < 32768)); + UHD_ASSERT_THROW(ref_clock <= 27.0e6 and ref_clock >= 0.0); + UHD_ASSERT_THROW(ref_clock/m >= 1e6 and ref_clock/m <= 2.5e6); + UHD_ASSERT_THROW((pfd_freq >= dbsrx_pfd_freq_range.min) and (pfd_freq <= dbsrx_pfd_freq_range.max)); + UHD_ASSERT_THROW((N >= 256) and (N <= 32768)); if(dbsrx_debug) std::cerr << boost::format( "DBSRX: choose ref_clock (current: %f, new: %f) and m_divider %d" @@ -351,7 +350,7 @@ void dbsrx::set_lo_freq(double target_freq){ "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n" ) % int(_max2118_write_regs.osc_band)) ); - UHD_ASSERT_THROW(_max2118_read_regs.adc == 0); + UHD_ASSERT_THROW(_max2118_read_regs.adc != 0); //just to cause a throw } if (_max2118_write_regs.osc_band <= 0) break; _max2118_write_regs.osc_band -= 1; @@ -365,7 +364,7 @@ void dbsrx::set_lo_freq(double target_freq){ "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n" ) % int(_max2118_write_regs.osc_band)) ); - UHD_ASSERT_THROW(_max2118_read_regs.adc == 0); + UHD_ASSERT_THROW(_max2118_read_regs.adc != 7); //just to cause a throw } if (_max2118_write_regs.osc_band >= 7) break; _max2118_write_regs.osc_band += 1; @@ -403,6 +402,7 @@ void dbsrx::set_lo_freq(double target_freq){ << boost::format(" Ref Freq=%fMHz\n") % (ref_clock/1e6) << boost::format(" Target Freq=%fMHz\n") % (target_freq/1e6) << boost::format(" Actual Freq=%fMHz\n") % (_lo_freq/1e6) + << boost::format(" VCO Freq=%fMHz\n") % (vco_freq/1e6) << std::endl; if (update_filter_settings) set_bandwidth(_bandwidth); -- cgit v1.2.3 From f28c07db44694e3cce96502183c7570a386987f5 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 11 Oct 2010 18:21:11 -0700 Subject: UHD: Brought out set_rx_bandwidth for dboards with programmable rx filters. --- host/include/uhd/usrp/mimo_usrp.hpp | 2 ++ host/include/uhd/usrp/simple_usrp.hpp | 2 ++ host/include/uhd/usrp/single_usrp.hpp | 2 ++ host/lib/usrp/mimo_usrp.cpp | 4 ++++ host/lib/usrp/simple_usrp.cpp | 4 ++++ host/lib/usrp/single_usrp.cpp | 4 ++++ 6 files changed, 18 insertions(+) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 10a404059..ed40addb3 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -148,6 +148,8 @@ public: * \return the rssi in dB */ virtual float read_rssi(size_t chan) = 0; + + virtual void set_rx_bandwidth(float bandwidth, size_t chan) = 0; /******************************************************************* * TX methods diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 6149f739c..6f3597ed7 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -139,6 +139,8 @@ public: virtual float read_rssi(void) = 0; virtual dboard_iface::sptr get_rx_dboard_iface(void) = 0; + + virtual void set_rx_bandwidth(float) = 0; /******************************************************************* * TX methods diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp index 3cd263bce..fa6498d13 100644 --- a/host/include/uhd/usrp/single_usrp.hpp +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -152,6 +152,8 @@ public: virtual float read_rssi(size_t chan = 0) = 0; virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan = 0) = 0; + + virtual void set_rx_bandwidth(float bandwidth, size_t chan = 0) = 0; /******************************************************************* * TX methods diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 9331c7fbb..5437607a6 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -225,6 +225,10 @@ public: float read_rssi(size_t chan){ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); } + + void set_rx_bandwidth(float bandwidth, size_t chan){ + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } /******************************************************************* * TX methods diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index b89b76eed..b4f34287b 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -136,6 +136,10 @@ public: dboard_iface::sptr get_rx_dboard_iface(void){ return _sdev->get_rx_dboard_iface(); } + + void set_rx_bandwidth(float bandwidth) { + return _sdev->set_rx_bandwidth(bandwidth); + } /******************************************************************* * TX methods diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index 08dc3bb1d..7d053535e 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -202,6 +202,10 @@ public: dboard_iface::sptr get_rx_dboard_iface(size_t chan){ return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); } + + void set_rx_bandwidth(float bandwidth, size_t chan) { + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } /******************************************************************* * TX methods -- cgit v1.2.3 From 3b36c206e56b415974ed83a52a652b65f9de1add Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 11 Oct 2010 18:37:04 -0700 Subject: UHD: reordered MIMO set_rx_bandwidth arg order --- host/include/uhd/usrp/mimo_usrp.hpp | 2 +- host/lib/usrp/mimo_usrp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index ed40addb3..bdd84a148 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -149,7 +149,7 @@ public: */ virtual float read_rssi(size_t chan) = 0; - virtual void set_rx_bandwidth(float bandwidth, size_t chan) = 0; + virtual void set_rx_bandwidth(size_t chan, float bandwidth) = 0; /******************************************************************* * TX methods diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 5437607a6..08618c288 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -226,7 +226,7 @@ public: return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); } - void set_rx_bandwidth(float bandwidth, size_t chan){ + void set_rx_bandwidth(size_t chan, float bandwidth){ _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; } -- cgit v1.2.3 From 8c0ca70d24f87ccc617ce79f2eedcc272a895204 Mon Sep 17 00:00:00 2001 From: Jason Abele Date: Tue, 12 Oct 2010 12:57:30 -0700 Subject: Enhance XCVR2450 to clip for high/low band tuning and add bandwidth property --- host/docs/dboards.rst | 11 ++- host/lib/usrp/dboard/db_xcvr2450.cpp | 147 ++++++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 9 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 4ad724c82..f3d7d95b0 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -69,21 +69,20 @@ Recieve Gains: **PGA0**, Range: 0-70dB (except RFX400 range is 0-45dB) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ XCVR 2450 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The XCVR2450 has a non-contiguous tuning range consisting of a high band and a low band. -The high band consists of frequencies between...TODO +The XCVR2450 has a non-contiguous tuning range consisting of a +high band (4.9-6.0GHz) and a low band (2.4-2.5GHz). Transmit Antennas: **J1** or **J2** Receive Antennas: **J1** or **J2** -When using the XCVR2450 in full-duplex mode, -the user must set the receive antenna and the transmit antenna to be different; -not doing so will yeild undefined results. - The XCVR2450 uses a common LO for both receive and transmit. Even though the API allows the RX and TX LOs to be individually set, a change of one LO setting will be reflected in the other LO setting. +The XCVR2450 does not support full-duplex mode, attempting to operate +in full-duplex will result in transmit-only operation. + Transmit Gains: * **VGA**, Range: 0-30dB * **BB**, Range: 0-5dB diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 0ee133f3d..314c85a69 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ using namespace boost::assign; static const bool xcvr2450_debug = false; static const freq_range_t xcvr_freq_range(2.4e9, 6.0e9); +static const freq_range_t xcvr_freq_band_seperation(2.5e9, 4.9e9); static const prop_names_t xcvr_antennas = list_of("J1")("J2"); @@ -100,6 +102,7 @@ public: private: double _lo_freq; + float _rx_bandwidth, _tx_bandwidth; uhd::dict _tx_gains, _rx_gains; std::string _tx_ant, _rx_ant; int _ad9515div; @@ -110,6 +113,8 @@ private: void set_rx_ant(const std::string &ant); void set_tx_gain(float gain, const std::string &name); void set_rx_gain(float gain, const std::string &name); + void set_rx_bandwidth(float bandwidth); + void set_tx_bandwidth(float bandwidth); void update_atr(void); void spi_reset(void); @@ -176,6 +181,9 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){ spi_reset(); //prepare the spi + _rx_bandwidth = 9.5e6; + _tx_bandwidth = 12.0e6; + //setup the misc max2829 registers _max2829_regs.mimo_select = max2829_regs_t::MIMO_SELECT_MIMO; _max2829_regs.band_sel_mimo = max2829_regs_t::BAND_SEL_MIMO_MIMO; @@ -183,7 +191,7 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){ _max2829_regs.rssi_high_bw = max2829_regs_t::RSSI_HIGH_BW_6MHZ; _max2829_regs.tx_lpf_coarse_adj = max2829_regs_t::TX_LPF_COARSE_ADJ_12MHZ; _max2829_regs.rx_lpf_coarse_adj = max2829_regs_t::RX_LPF_COARSE_ADJ_9_5MHZ; - _max2829_regs.rx_lpf_fine_adj = max2829_regs_t::RX_LPF_FINE_ADJ_95; + _max2829_regs.rx_lpf_fine_adj = max2829_regs_t::RX_LPF_FINE_ADJ_100; _max2829_regs.rx_vga_gain_spi = max2829_regs_t::RX_VGA_GAIN_SPI_SPI; _max2829_regs.rssi_output_range = max2829_regs_t::RSSI_OUTPUT_RANGE_HIGH; _max2829_regs.rssi_op_mode = max2829_regs_t::RSSI_OP_MODE_ENABLED; @@ -244,15 +252,24 @@ void xcvr2450::update_atr(void){ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP_RXIO | RX_DIS_RXIO); this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP_RXIO | RX_ENB_RXIO); this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP_RXIO | RX_DIS_RXIO); - this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_ENB_RXIO); + this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_DIS_RXIO); } /*********************************************************************** * Tuning **********************************************************************/ void xcvr2450::set_lo_freq(double target_freq){ + //clip for highband and lowband + if((target_freq > xcvr_freq_band_seperation.min) and (target_freq < xcvr_freq_band_seperation.max)){ + if(target_freq - xcvr_freq_band_seperation.min < xcvr_freq_band_seperation.max - target_freq){ + target_freq = xcvr_freq_band_seperation.min; + }else{ + target_freq = xcvr_freq_band_seperation.max; + } + } + + //clip for max and min target_freq = std::clip(target_freq, xcvr_freq_range.min, xcvr_freq_range.max); - //TODO: clip for highband and lowband //variables used in the calculation below double scaler = xcvr2450::is_highband(target_freq)? (4.0/5.0) : (4.0/3.0); @@ -434,6 +451,114 @@ void xcvr2450::set_rx_gain(float gain, const std::string &name){ _rx_gains[name] = gain; } + +/*********************************************************************** + * Bandwidth Handling + **********************************************************************/ +static max2829_regs_t::tx_lpf_coarse_adj_t bandwidth_to_tx_lpf_coarse_reg(float &bandwidth){ + int reg = std::clip(boost::math::iround((bandwidth-6.0e6)/6.0e6), 1, 3); + + switch(reg){ + case 1: // bandwidth < 15MHz + bandwidth = 12e6; + return max2829_regs_t::TX_LPF_COARSE_ADJ_12MHZ; + case 2: // 15MHz < bandwidth < 21MHz + bandwidth = 18e6; + return max2829_regs_t::TX_LPF_COARSE_ADJ_18MHZ; + case 3: // bandwidth > 21MHz + bandwidth = 24e6; + return max2829_regs_t::TX_LPF_COARSE_ADJ_24MHZ; + } + UHD_THROW_INVALID_CODE_PATH(); +} + +static max2829_regs_t::rx_lpf_fine_adj_t bandwidth_to_rx_lpf_fine_reg(float &bandwidth, float requested_bandwidth){ + int reg = std::clip(boost::math::iround((requested_bandwidth/bandwidth)/0.05), 18, 22); + + switch(reg){ + case 18: // requested_bandwidth < 92.5% + bandwidth = 0.9 * bandwidth; + return max2829_regs_t::RX_LPF_FINE_ADJ_90; + case 19: // 92.5% < requested_bandwidth < 97.5% + bandwidth = 0.95 * bandwidth; + return max2829_regs_t::RX_LPF_FINE_ADJ_95; + case 20: // 97.5% < requested_bandwidth < 102.5% + bandwidth = 1.0 * bandwidth; + return max2829_regs_t::RX_LPF_FINE_ADJ_100; + case 21: // 102.5% < requested_bandwidth < 107.5% + bandwidth = 1.05 * bandwidth; + return max2829_regs_t::RX_LPF_FINE_ADJ_105; + case 22: // 107.5% < requested_bandwidth + bandwidth = 1.1 * bandwidth; + return max2829_regs_t::RX_LPF_FINE_ADJ_110; + } + UHD_THROW_INVALID_CODE_PATH(); +} + +static max2829_regs_t::rx_lpf_coarse_adj_t bandwidth_to_rx_lpf_coarse_reg(float &bandwidth){ + int reg = std::clip(boost::math::iround((bandwidth-7.0e6)/1.0e6), 0, 11); + + switch(reg){ + case 0: // bandwidth < 7.5MHz + case 1: // 7.5MHz < bandwidth < 8.5MHz + bandwidth = 7.5e6; + return max2829_regs_t::RX_LPF_COARSE_ADJ_7_5MHZ; + case 2: // 8.5MHz < bandwidth < 9.5MHz + case 3: // 9.5MHz < bandwidth < 10.5MHz + case 4: // 10.5MHz < bandwidth < 11.5MHz + bandwidth = 9.5e6; + return max2829_regs_t::RX_LPF_COARSE_ADJ_9_5MHZ; + case 5: // 11.5MHz < bandwidth < 12.5MHz + case 6: // 12.5MHz < bandwidth < 13.5MHz + case 7: // 13.5MHz < bandwidth < 14.5MHz + case 8: // 14.5MHz < bandwidth < 15.5MHz + bandwidth = 14e6; + return max2829_regs_t::RX_LPF_COARSE_ADJ_14MHZ; + case 9: // 15.5MHz < bandwidth < 16.5MHz + case 10: // 16.5MHz < bandwidth < 17.5MHz + case 11: // 17.5MHz < bandwidth + bandwidth = 18e6; + return max2829_regs_t::RX_LPF_COARSE_ADJ_18MHZ; + } + UHD_THROW_INVALID_CODE_PATH(); +} + +void xcvr2450::set_rx_bandwidth(float bandwidth){ + float requested_bandwidth = bandwidth; + + //compute coarse low pass cutoff frequency setting + _max2829_regs.rx_lpf_coarse_adj = bandwidth_to_rx_lpf_coarse_reg(bandwidth); + + //compute fine low pass cutoff frequency setting + _max2829_regs.rx_lpf_fine_adj = bandwidth_to_rx_lpf_fine_reg(bandwidth, requested_bandwidth); + + //shadow bandwidth setting + _rx_bandwidth = bandwidth; + + //update register + send_reg(0x7); + + if (xcvr2450_debug) std::cerr << boost::format( + "XCVR2450 RX Bandwidth (lp_fc): %f Hz, coarse reg: %d, fine reg: %d" + ) % _rx_bandwidth % (int(_max2829_regs.rx_lpf_coarse_adj)) % (int(_max2829_regs.rx_lpf_fine_adj)) << std::endl; +} + +void xcvr2450::set_tx_bandwidth(float bandwidth){ + //compute coarse low pass cutoff frequency setting + _max2829_regs.tx_lpf_coarse_adj = bandwidth_to_tx_lpf_coarse_reg(bandwidth); + + //shadow bandwidth setting + _tx_bandwidth = bandwidth; + + //update register + send_reg(0x7); + + if (xcvr2450_debug) std::cerr << boost::format( + "XCVR2450 TX Bandwidth (lp_fc): %f Hz, coarse reg: %d" + ) % _tx_bandwidth % (int(_max2829_regs.tx_lpf_coarse_adj)) << std::endl; +} + + /*********************************************************************** * RX Get and Set **********************************************************************/ @@ -500,6 +625,10 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){ val = this->get_rssi(); return; + case SUBDEV_PROP_BANDWIDTH: + val = _rx_bandwidth; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } @@ -522,6 +651,10 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){ this->set_rx_ant(val.as()); return; + case SUBDEV_PROP_BANDWIDTH: + this->set_rx_bandwidth(val.as()); + return; + case SUBDEV_PROP_ENABLED: return; //always enabled @@ -591,6 +724,10 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){ val = this->get_locked(); return; + case SUBDEV_PROP_BANDWIDTH: + val = _tx_bandwidth; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } @@ -609,6 +746,10 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){ this->set_tx_gain(val.as(), key.name); return; + case SUBDEV_PROP_BANDWIDTH: + this->set_tx_bandwidth(val.as()); + return; + case SUBDEV_PROP_ANTENNA: this->set_tx_ant(val.as()); return; -- cgit v1.2.3 From 9348c2764dbbdf01e34a3ec7b5c8e74964b355e0 Mon Sep 17 00:00:00 2001 From: Philip Balister Date: Thu, 14 Oct 2010 21:41:14 -0400 Subject: usrp_e: back out dynamic send/recv samples calculation. --- host/lib/usrp/usrp_e/io_impl.cpp | 6 +++++- host/lib/usrp/usrp_e/usrp_e_impl.hpp | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/io_impl.cpp b/host/lib/usrp/usrp_e/io_impl.cpp index 406b7269f..d89a7db07 100644 --- a/host/lib/usrp/usrp_e/io_impl.cpp +++ b/host/lib/usrp/usrp_e/io_impl.cpp @@ -37,7 +37,7 @@ zero_copy_if::sptr usrp_e_make_mmap_zero_copy(usrp_e_iface::sptr iface); **********************************************************************/ static const size_t tx_async_report_sid = 1; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; -static const bool recv_debug = true; +static const bool recv_debug = false; /*********************************************************************** * io impl details (internal to this file) @@ -205,6 +205,7 @@ bool get_send_buffs( return buffs[0].get() != NULL; } +#if 0 size_t usrp_e_impl::get_max_send_samps_per_packet(void) const{ static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) @@ -213,6 +214,7 @@ size_t usrp_e_impl::get_max_send_samps_per_packet(void) const{ size_t bpp = _io_impl->data_xport->get_send_frame_size() - hdr_size; return bpp/_send_otw_type.get_sample_size(); } +#endif size_t usrp_e_impl::send( const std::vector &buffs, size_t num_samps, @@ -234,6 +236,7 @@ size_t usrp_e_impl::send( /*********************************************************************** * Data Recv **********************************************************************/ +#if 0 size_t usrp_e_impl::get_max_recv_samps_per_packet(void) const{ static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) @@ -243,6 +246,7 @@ size_t usrp_e_impl::get_max_recv_samps_per_packet(void) const{ size_t bpp = _io_impl->data_xport->get_recv_frame_size() - hdr_size; return bpp/_recv_otw_type.get_sample_size(); } +#endif size_t usrp_e_impl::recv( const std::vector &buffs, size_t num_samps, diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp index 95d80fed5..9799cd645 100644 --- a/host/lib/usrp/usrp_e/usrp_e_impl.hpp +++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp @@ -86,8 +86,13 @@ public: size_t send(const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); size_t recv(const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); bool recv_async_msg(uhd::async_metadata_t &, double); +#if 0 size_t get_max_send_samps_per_packet(void) const; size_t get_max_recv_samps_per_packet(void) const; +#else + size_t get_max_send_samps_per_packet(void) const{return 503;} + size_t get_max_recv_samps_per_packet(void) const{return 503;} +#endif private: //interface to ioctls and file descriptor -- cgit v1.2.3 From 6b203950d9583ab882628311402e26cf40838aa0 Mon Sep 17 00:00:00 2001 From: Philip Balister Date: Thu, 14 Oct 2010 21:42:10 -0400 Subject: usrp_e: Disable debug. --- host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp index bc18c490b..274bb043e 100644 --- a/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_mmap_zero_copy.cpp @@ -29,8 +29,8 @@ using namespace uhd; using namespace uhd::transport; -static const bool fp_verbose = true; //fast-path verbose -static const bool sp_verbose = true; //slow-path verbose +static const bool fp_verbose = false; //fast-path verbose +static const bool sp_verbose = false; //slow-path verbose static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout /*********************************************************************** -- cgit v1.2.3 From 816a07bee54e998e4fb25beeb44b9ac3888189bf Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 16 Oct 2010 01:18:47 -0700 Subject: usrp2: make the booty smaller than the number of recv frames This may fix some of our woes when the host cannot keep up. That is, with a smaller booty, the managed buffers will get freed up and the call to get buffer will never block waiting for a buffer to become free. This has several side effects: 1) Overflows are more likely to occur in the pirate thread. Pirate-based overflows will overwrite old packets, whereas socket-based overflows will discard newer incoming packets. 2) The pirate thread will continue to pull in async packets rather than loosing them in a socket-based overflow. --- host/lib/usrp/usrp2/io_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index eba704059..bbe9c273f 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -46,7 +46,7 @@ struct usrp2_impl::io_impl{ io_impl(size_t num_frames, size_t width): packet_handler_recv_state(width), - recv_pirate_booty(alignment_buffer_type::make(num_frames, width)), + recv_pirate_booty(alignment_buffer_type::make(num_frames-3, width)), async_msg_fifo(bounded_buffer::make(100/*messages deep*/)) { /* NOP */ -- cgit v1.2.3 From c861f98c55c38250a0d87ed91f5c19b10192a4b8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 16 Oct 2010 18:07:10 -0700 Subject: usrp: created multi-usrp (multi chan, multi board), and deprecated mimo-usrp --- host/include/uhd/usrp/CMakeLists.txt | 1 + host/include/uhd/usrp/mimo_usrp.hpp | 4 +- host/include/uhd/usrp/multi_usrp.hpp | 259 +++++++++++++++++++++ host/include/uhd/usrp/single_usrp.hpp | 6 +- host/lib/usrp/CMakeLists.txt | 1 + host/lib/usrp/mimo_usrp.cpp | 6 + host/lib/usrp/multi_usrp.cpp | 422 ++++++++++++++++++++++++++++++++++ host/lib/usrp/single_usrp.cpp | 4 - 8 files changed, 694 insertions(+), 9 deletions(-) create mode 100644 host/include/uhd/usrp/multi_usrp.hpp create mode 100644 host/lib/usrp/multi_usrp.cpp (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index f973e401a..abddf3951 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -42,6 +42,7 @@ INSTALL(FILES simple_usrp.hpp single_usrp.hpp mimo_usrp.hpp + multi_usrp.hpp DESTINATION ${INCLUDE_DIR}/uhd/usrp ) diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index bdd84a148..7c250b2fd 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -32,12 +32,12 @@ namespace uhd{ namespace usrp{ /*! - * The MIMO USRP device class: + * The MIMO USRP device class (DEPRECATED): * A mimo usrp facilitates ease-of-use for multi-usrp scenarios. * The wrapper provides convenience functions to control the group * of underlying devices as if they consisted of a single device. */ -class UHD_API mimo_usrp : boost::noncopyable{ +class UHD_API UHD_DEPRECATED mimo_usrp : boost::noncopyable{ public: typedef boost::shared_ptr sptr; diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp new file mode 100644 index 000000000..65c7e9044 --- /dev/null +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -0,0 +1,259 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#ifndef INCLUDED_UHD_USRP_MULTI_USRP_HPP +#define INCLUDED_UHD_USRP_MULTI_USRP_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uhd{ namespace usrp{ + +/*! + * The multi-USRP device class: + * A multi-USRP facilitates ease-of-use for multiple USRP scenarios. + * The wrapper provides convenience functions to control the group + * of underlying devices as if they consisted of a single device. + * + * A few notes about a multi-USRP configuration: + * - All boards share a common RX sample rate + * - All boards share a common TX sample rate + * - All boards share a common RX subdevice specification size + * - All boards share a common TX subdevice specification size + * - All boards must have synchronized times (see the set_time_*() calls) + * + * Example to setup channel mapping: + *
+ *
+ * //create a multi_usrp with two boards in the configuration
+ * device_addr_t dev_addr;
+ * dev_addr["addr"] = "192.168.10.2 192.168.10.3";
+ * multi_usrp::sptr dev = multi_usrp::make(dev_addr);
+ *
+ * //set the board on 10.2 to use the A RX subdevice (RX channel 0)
+ * dev->set_rx_subdev_spec(":A", 0);
+ *
+ * //set the board on 10.3 to use the B RX subdevice (RX channel 1)
+ * dev->set_rx_subdev_spec(":B", 1);
+ *
+ * //set both boards to use the AB TX subdevice (TX channels 0 and 1)
+ * dev->set_tx_subdev_spec(":AB", multi_usrp::ALL_MBOARDS);
+ *
+ * //now that all the channels are mapped, continue with configuration...
+ *
+ * 
+ */ +class UHD_API multi_usrp : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + //! A wildcard motherboard index + static const size_t ALL_MBOARDS = size_t(~0); + + /*! + * Make a new multi usrp from the device address. + * \param dev_addr the device address + * \return a new single usrp object + */ + static sptr make(const device_addr_t &dev_addr); + + /*! + * Get the underlying device object. + * This is needed to get access to the streaming API and properties. + * \return the device object within this single usrp + */ + virtual device::sptr get_device(void) = 0; + + /******************************************************************* + * Mboard methods + ******************************************************************/ + /*! + * Get a printable summary for this USRP configuration. + * \return a printable string + */ + virtual std::string get_pp_string(void) = 0; + + /*! + * Get canonical name for this USRP motherboard. + * \param mboard which motherboard to query + * \return a string representing the name + */ + virtual std::string get_mboard_name(size_t mboard) = 0; + + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + + /*! + * Set the time registers on the usrp at the next pps tick. + * The values will not be latched in until the pulse occurs. + * It is recommended that the user sleep(1) after calling to ensure + * that the time registers will be in a known state prior to use. + * + * Note: Because this call sets the time on the "next" pps, + * the seconds in the time spec should be current seconds + 1. + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + + /*! + * Synchronize the times across all motherboards in this configuration. + * Use this method to sync the times when the edge of the PPS is unknown. + * + * Ex: Host machine is not attached to serial port of GPSDO + * and can therefore not query the GPSDO for the PPS edge. + * + * This is a 3-step process, and will take at most 3 seconds to complete. + * Upon completion, the times will be synchronized to the time provided. + * + * - Step1: set the time at the next pps (potential race condition) + * - Step2: wait for the seconds to rollover to catch the pps edge + * - Step3: set the time at the next pps (synchronous for all boards) + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_unknown_pps(const time_spec_t &time_spec) = 0; + + /*! + * Issue a stream command to the usrp device. + * This tells the usrp to send samples into the host. + * See the documentation for stream_cmd_t for more info. + * \param stream_cmd the stream command to issue + */ + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + + /*! + * Set the clock configuration for the usrp device. + * This tells the usrp how to get a 10Mhz reference and PPS clock. + * See the documentation for clock_config_t for more info. + * \param clock_config the clock configuration to set + * \param mboard which motherboard to set the config + */ + virtual void set_clock_config(const clock_config_t &clock_config, size_t mboard) = 0; + + /*! + * Get the number of USRP motherboards in this configuration. + */ + virtual size_t get_num_mboards(void) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + /*! + * Set the RX subdevice specification: + * The subdev spec maps a physical part of a daughter-board to a channel number. + * Set the subdev spec before calling into any methods with a channel number. + * The subdev spec must be the same size across all motherboards. + */ + virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec, size_t mboard) = 0; + virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(size_t mboard) = 0; + + /*! + * Get the number of RX channels in this configuration. + * This is the number of USRPs times the number of RX channels per board, + * where the number of RX channels per board is homogeneous among all USRPs. + */ + virtual size_t get_rx_num_channels(void) = 0; + + virtual std::string get_rx_subdev_name(size_t chan) = 0; + + virtual void set_rx_rate(double rate) = 0; + virtual double get_rx_rate(void) = 0; + + virtual tune_result_t set_rx_freq(double freq, size_t chan) = 0; + virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan) = 0; + virtual double get_rx_freq(size_t chan) = 0; + virtual freq_range_t get_rx_freq_range(size_t chan) = 0; + + virtual void set_rx_gain(float gain, size_t chan) = 0; + virtual float get_rx_gain(size_t chan) = 0; + virtual gain_range_t get_rx_gain_range(size_t chan) = 0; + + virtual void set_rx_antenna(const std::string &ant, size_t chan) = 0; + virtual std::string get_rx_antenna(size_t chan) = 0; + virtual std::vector get_rx_antennas(size_t chan) = 0; + + virtual bool get_rx_lo_locked(size_t chan) = 0; + + /*! + * Read the RSSI value from a usrp device. + * Or throw if the dboard does not support an RSSI readback. + * \return the rssi in dB + */ + virtual float read_rssi(size_t chan) = 0; + + virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan) = 0; + + virtual void set_rx_bandwidth(float bandwidth, size_t chan) = 0; + + /******************************************************************* + * TX methods + ******************************************************************/ + /*! + * Set the TX subdevice specification: + * The subdev spec maps a physical part of a daughter-board to a channel number. + * Set the subdev spec before calling into any methods with a channel number. + * The subdev spec must be the same size across all motherboards. + */ + virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec, size_t mboard) = 0; + virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(size_t mboard) = 0; + + /*! + * Get the number of TX channels in this configuration. + * This is the number of USRPs times the number of TX channels per board, + * where the number of TX channels per board is homogeneous among all USRPs. + */ + virtual size_t get_tx_num_channels(void) = 0; + + virtual std::string get_tx_subdev_name(size_t chan) = 0; + + virtual void set_tx_rate(double rate) = 0; + virtual double get_tx_rate(void) = 0; + + virtual tune_result_t set_tx_freq(double freq, size_t chan) = 0; + virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan) = 0; + virtual double get_tx_freq(size_t chan) = 0; + virtual freq_range_t get_tx_freq_range(size_t chan) = 0; + + virtual void set_tx_gain(float gain, size_t chan) = 0; + virtual float get_tx_gain(size_t chan) = 0; + virtual gain_range_t get_tx_gain_range(size_t chan) = 0; + + virtual void set_tx_antenna(const std::string &ant, size_t chan) = 0; + virtual std::string get_tx_antenna(size_t chan) = 0; + virtual std::vector get_tx_antennas(size_t chan) = 0; + + virtual bool get_tx_lo_locked(size_t chan) = 0; + + virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan) = 0; +}; + +}} + +#endif /* INCLUDED_UHD_USRP_MULTI_USRP_HPP */ diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp index fa6498d13..2266e7f2c 100644 --- a/host/include/uhd/usrp/single_usrp.hpp +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -33,8 +33,8 @@ namespace uhd{ namespace usrp{ /*! - * The single USRP device class: - * A single usrp facilitates ease-of-use for most use-case scenarios. + * The single-USRP device class: + * A single-USRP facilitates ease-of-use for most use-case scenarios. * The wrapper provides convenience functions to tune the devices * as well as to set the dboard gains, antennas, and other properties. * This wrapper supports multi-channel configurations per motherboard. @@ -61,7 +61,7 @@ public: * Mboard methods ******************************************************************/ /*! - * Get a printable name for this usrp. + * Get a printable summary for this USRP configuration. * \return a printable string */ virtual std::string get_pp_string(void) = 0; diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 69a190bfa..d8898caff 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -25,6 +25,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/multi_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 08618c288..f5a80a3e6 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -347,5 +347,11 @@ private: * The Make Function **********************************************************************/ mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){ + uhd::print_warning( + "The mimo USRP interface has been deprecated.\n" + "Please switch to the multi USRP interface.\n" + "#include \n" + "multi_usrp::sptr sdev = multi_usrp::make(args);\n" + ); return sptr(new mimo_usrp_impl(dev_addr)); } diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp new file mode 100644 index 000000000..d0fc5c0f6 --- /dev/null +++ b/host/lib/usrp/multi_usrp.cpp @@ -0,0 +1,422 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ + double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); + return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} + +/*********************************************************************** + * Simple USRP Implementation + **********************************************************************/ +class multi_usrp_impl : public multi_usrp{ +public: + multi_usrp_impl(const device_addr_t &addr){ + _dev = device::make(addr); + } + + device::sptr get_device(void){ + return _dev; + } + + /******************************************************************* + * Mboard methods + ******************************************************************/ + std::string get_pp_string(void){ + std::string buff = str(boost::format( + "Multi USRP:\n" + " Device: %s\n" + ) + % (*_dev)[DEVICE_PROP_NAME].as() + ); + for (size_t m = 0; m < get_num_mboards(); m++){ + buff += str(boost::format( + " Mboard %d: %s\n" + ) % m + % _mboard(m)[MBOARD_PROP_NAME].as() + ); + } + + //----------- rx side of life ---------------------------------- + for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){ + buff += str(boost::format( + " RX DSP %d: %s\n" + ) % m + % _rx_dsp(m)[DSP_PROP_NAME].as() + ); + for (; chan < (m + 1)*get_rx_subdev_spec(m).size(); chan++){ + buff += str(boost::format( + " RX Channel: %u\n" + " RX Dboard: %s\n" + " RX Subdev: %s\n" + ) % chan + % _rx_dboard(chan)[DBOARD_PROP_NAME].as() + % _rx_subdev(chan)[SUBDEV_PROP_NAME].as() + ); + } + } + + //----------- tx side of life ---------------------------------- + for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){ + buff += str(boost::format( + " TX DSP %d: %s\n" + ) % m + % _tx_dsp(m)[DSP_PROP_NAME].as() + ); + for (; chan < (m + 1)*get_tx_subdev_spec(m).size(); chan++){ + buff += str(boost::format( + " TX Channel: %u\n" + " TX Dboard: %s\n" + " TX Subdev: %s\n" + ) % chan + % _tx_dboard(chan)[DBOARD_PROP_NAME].as() + % _tx_subdev(chan)[SUBDEV_PROP_NAME].as() + ); + } + } + + return buff; + } + + std::string get_mboard_name(size_t mboard){ + return _mboard(mboard)[MBOARD_PROP_NAME].as(); + } + + time_spec_t get_time_now(void){ + return _mboard(0)[MBOARD_PROP_TIME_NOW].as(); + } + + void set_time_next_pps(const time_spec_t &time_spec){ + for (size_t m = 0; m < get_num_mboards(); m++){ + _mboard(m)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + } + + void set_time_unknown_pps(const time_spec_t &time_spec){ + std::cout << "Set time with unknown pps edge:" << std::endl; + std::cout << " 1) set times next pps (race condition)" << std::endl; + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + + std::cout << " 2) catch seconds rollover at pps edge" << std::endl; + time_t last_secs = 0, curr_secs = 0; + while(curr_secs == last_secs){ + last_secs = curr_secs; + curr_secs = get_time_now().get_full_secs(); + } + + std::cout << " 3) set times next pps (synchronously)" << std::endl; + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + + //verify that the time registers are read to be within a few RTT + for (size_t m = 1; m < get_num_mboards(); m++){ + time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as(); + time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as(); + if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big + uhd::print_warning(str(boost::format( + "Detected time deviation between board %d and board 0.\n" + "Board 0 time is %f seconds.\n" + "Board %d time is %f seconds.\n" + ) % m % time_0.get_real_secs() % m % time_i.get_real_secs())); + } + } + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + for (size_t m = 0; m < get_num_mboards(); m++){ + _mboard(m)[MBOARD_PROP_STREAM_CMD] = stream_cmd; + } + } + + void set_clock_config(const clock_config_t &clock_config, size_t mboard){ + if (mboard != ALL_MBOARDS){ + _mboard(mboard)[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + return; + } + for (size_t m = 0; m < get_num_mboards(); m++){ + set_clock_config(clock_config, m); + } + } + + size_t get_num_mboards(void){ + return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as().size(); + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_subdev_spec(const subdev_spec_t &spec, size_t mboard){ + if (mboard != ALL_MBOARDS){ + _mboard(mboard)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; + return; + } + for (size_t m = 0; m < get_num_mboards(); m++){ + set_rx_subdev_spec(spec, m); + } + } + + subdev_spec_t get_rx_subdev_spec(size_t mboard){ + return _mboard(mboard)[MBOARD_PROP_RX_SUBDEV_SPEC].as(); + } + + size_t get_rx_num_channels(void){ + size_t nchan = get_rx_subdev_spec(0).size(); + for (size_t m = 1; m < get_num_mboards(); m++){ + if (nchan != get_rx_subdev_spec(m).size()){ + throw std::runtime_error("rx subdev spec size inconsistent across all mboards"); + } + } + return nchan; + } + + std::string get_rx_subdev_name(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_NAME].as(); + } + + void set_rx_rate(double rate){ + for (size_t m = 0; m < get_num_mboards(); m++){ + _rx_dsp(m)[DSP_PROP_HOST_RATE] = rate; + } + } + + double get_rx_rate(void){ + return _rx_dsp(0)[DSP_PROP_HOST_RATE].as(); + } + + tune_result_t set_rx_freq(double target_freq, size_t chan){ + size_t nchan = get_rx_num_channels(); + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq); + } + + tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ + size_t nchan = get_rx_num_channels(); + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + } + + double get_rx_freq(size_t chan){ + size_t nchan = get_rx_num_channels(); + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan); + } + + freq_range_t get_rx_freq_range(size_t chan){ + size_t nchan = get_rx_num_channels(); + return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp(nchan/chan)); + } + + void set_rx_gain(float gain, size_t chan){ + return _rx_gain_group(chan)->set_value(gain); + } + + float get_rx_gain(size_t chan){ + return _rx_gain_group(chan)->get_value(); + } + + gain_range_t get_rx_gain_range(size_t chan){ + return _rx_gain_group(chan)->get_range(); + } + + void set_rx_antenna(const std::string &ant, size_t chan){ + _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_rx_antennas(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_rx_lo_locked(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + float read_rssi(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); + } + + dboard_iface::sptr get_rx_dboard_iface(size_t chan){ + return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); + } + + void set_rx_bandwidth(float bandwidth, size_t chan) { + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_subdev_spec(const subdev_spec_t &spec, size_t mboard){ + if (mboard != ALL_MBOARDS){ + _mboard(mboard)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; + return; + } + for (size_t m = 0; m < get_num_mboards(); m++){ + set_tx_subdev_spec(spec, m); + } + } + + subdev_spec_t get_tx_subdev_spec(size_t mboard){ + return _mboard(mboard)[MBOARD_PROP_TX_SUBDEV_SPEC].as(); + } + + std::string get_tx_subdev_name(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_NAME].as(); + } + + size_t get_tx_num_channels(void){ + size_t nchan = get_tx_subdev_spec(0).size(); + for (size_t m = 1; m < get_num_mboards(); m++){ + if (nchan != get_tx_subdev_spec(m).size()){ + throw std::runtime_error("tx subdev spec size inconsistent across all mboards"); + } + } + return nchan; + } + + void set_tx_rate(double rate){ + for (size_t m = 0; m < get_num_mboards(); m++){ + _tx_dsp(m)[DSP_PROP_HOST_RATE] = rate; + } + } + + double get_tx_rate(void){ + return _tx_dsp(0)[DSP_PROP_HOST_RATE].as(); + } + + tune_result_t set_tx_freq(double target_freq, size_t chan){ + size_t nchan = get_tx_num_channels(); + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq); + } + + tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ + size_t nchan = get_tx_num_channels(); + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + } + + double get_tx_freq(size_t chan){ + size_t nchan = get_tx_num_channels(); + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan); + } + + freq_range_t get_tx_freq_range(size_t chan){ + size_t nchan = get_tx_num_channels(); + return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp(nchan/chan)); + } + + void set_tx_gain(float gain, size_t chan){ + return _tx_gain_group(chan)->set_value(gain); + } + + float get_tx_gain(size_t chan){ + return _tx_gain_group(chan)->get_value(); + } + + gain_range_t get_tx_gain_range(size_t chan){ + return _tx_gain_group(chan)->get_range(); + } + + void set_tx_antenna(const std::string &ant, size_t chan){ + _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_tx_antennas(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_tx_lo_locked(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + dboard_iface::sptr get_tx_dboard_iface(size_t chan){ + return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); + } + +private: + device::sptr _dev; + wax::obj _mboard(size_t mboard){ + std::string mb_name = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as().at(mboard); + return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, mb_name)]; + } + wax::obj _rx_dsp(size_t mboard){ + return _mboard(mboard)[MBOARD_PROP_RX_DSP]; + } + wax::obj _tx_dsp(size_t mboard){ + return _mboard(mboard)[MBOARD_PROP_TX_DSP]; + } + wax::obj _rx_dboard(size_t chan){ + size_t nchan = get_rx_num_channels(); + std::string db_name = get_rx_subdev_spec(chan/nchan).at(chan%nchan).db_name; + return _mboard(chan/nchan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + } + wax::obj _tx_dboard(size_t chan){ + size_t nchan = get_tx_num_channels(); + std::string db_name = get_tx_subdev_spec(chan/nchan).at(chan%nchan).db_name; + return _mboard(chan/nchan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + } + wax::obj _rx_subdev(size_t chan){ + size_t nchan = get_rx_num_channels(); + std::string sd_name = get_rx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + wax::obj _tx_subdev(size_t chan){ + size_t nchan = get_tx_num_channels(); + std::string sd_name = get_tx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + gain_group::sptr _rx_gain_group(size_t chan){ + size_t nchan = get_rx_num_channels(); + std::string sd_name = get_rx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); + } + gain_group::sptr _tx_gain_group(size_t chan){ + size_t nchan = get_tx_num_channels(); + std::string sd_name = get_tx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); + } +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +multi_usrp::sptr multi_usrp::make(const device_addr_t &dev_addr){ + return sptr(new multi_usrp_impl(dev_addr)); +} diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index 7d053535e..fba04cd60 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -46,10 +46,6 @@ public: _dev = device::make(addr); } - ~single_usrp_impl(void){ - /* NOP */ - } - device::sptr get_device(void){ return _dev; } -- cgit v1.2.3 From a1e42e5d60be8fd74d3e93f86546343cb93c3a48 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 17 Oct 2010 23:37:52 -0700 Subject: usrp: moved warnings logic into wrappers --- host/lib/usrp/CMakeLists.txt | 1 + host/lib/usrp/multi_usrp.cpp | 24 +++++++++------ host/lib/usrp/single_usrp.cpp | 24 +++++++++------ host/lib/usrp/wrapper_utils.hpp | 66 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 host/lib/usrp/wrapper_utils.hpp (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index d8898caff..906a5ff29 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -30,6 +30,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/wrapper_utils.hpp ) INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/dboard/CMakeLists.txt) diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index d0fc5c0f6..7f7ea77b0 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include "wrapper_utils.hpp" #include #include #include @@ -34,11 +35,6 @@ using namespace uhd; using namespace uhd::usrp; -static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ - double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); - return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); -} - /*********************************************************************** * Simple USRP Implementation **********************************************************************/ @@ -211,6 +207,7 @@ public: for (size_t m = 0; m < get_num_mboards(); m++){ _rx_dsp(m)[DSP_PROP_HOST_RATE] = rate; } + do_samp_rate_warning_message(rate, get_rx_rate(), "RX"); } double get_rx_rate(void){ @@ -219,12 +216,16 @@ public: tune_result_t set_rx_freq(double target_freq, size_t chan){ size_t nchan = get_rx_num_channels(); - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq); + do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); + return r; } tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ size_t nchan = get_rx_num_channels(); - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); + return r; } double get_rx_freq(size_t chan){ @@ -312,6 +313,7 @@ public: for (size_t m = 0; m < get_num_mboards(); m++){ _tx_dsp(m)[DSP_PROP_HOST_RATE] = rate; } + do_samp_rate_warning_message(rate, get_tx_rate(), "TX"); } double get_tx_rate(void){ @@ -320,12 +322,16 @@ public: tune_result_t set_tx_freq(double target_freq, size_t chan){ size_t nchan = get_tx_num_channels(); - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq); + do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); + return r; } tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ size_t nchan = get_tx_num_channels(); - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); + return r; } double get_tx_freq(size_t chan){ diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index fba04cd60..7a4df3eb5 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include "wrapper_utils.hpp" #include #include #include @@ -32,11 +33,6 @@ using namespace uhd; using namespace uhd::usrp; -static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ - double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); - return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); -} - /*********************************************************************** * Simple USRP Implementation **********************************************************************/ @@ -141,6 +137,7 @@ public: void set_rx_rate(double rate){ _rx_dsp()[DSP_PROP_HOST_RATE] = rate; + do_samp_rate_warning_message(rate, get_rx_rate(), "RX"); } double get_rx_rate(void){ @@ -148,11 +145,15 @@ public: } tune_result_t set_rx_freq(double target_freq, size_t chan){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq); + do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); + return r; } tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off); + do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); + return r; } double get_rx_freq(size_t chan){ @@ -220,6 +221,7 @@ public: void set_tx_rate(double rate){ _tx_dsp()[DSP_PROP_HOST_RATE] = rate; + do_samp_rate_warning_message(rate, get_tx_rate(), "TX"); } double get_tx_rate(void){ @@ -227,11 +229,15 @@ public: } tune_result_t set_tx_freq(double target_freq, size_t chan){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq); + do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); + return r; } tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off); + do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); + return r; } double get_tx_freq(size_t chan){ diff --git a/host/lib/usrp/wrapper_utils.hpp b/host/lib/usrp/wrapper_utils.hpp new file mode 100644 index 000000000..aee230fc0 --- /dev/null +++ b/host/lib/usrp/wrapper_utils.hpp @@ -0,0 +1,66 @@ +// +// Copyright 2010 Ettus Research LLC +// +// 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, see . +// + +#ifndef INCLUDED_LIBUHD_USRP_WRAPPER_UTILS_HPP +#define INCLUDED_LIBUHD_USRP_WRAPPER_UTILS_HPP + +#include +#include +#include +#include +#include +#include + +static inline uhd::freq_range_t add_dsp_shift( + const uhd::freq_range_t &range, + wax::obj dsp +){ + double codec_rate = dsp[uhd::usrp::DSP_PROP_CODEC_RATE].as(); + return uhd::freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} + +static inline void do_samp_rate_warning_message( + double target_rate, + double actual_rate, + const std::string &xx +){ + static const double max_allowed_error = 1.0; //Sps + if (std::abs(target_rate - actual_rate) > max_allowed_error){ + uhd::print_warning(str(boost::format( + "The hardware does not support the requested %s sample rate:\n" + "Target sample rate: %f MSps\n" + "Actual sample rate: %f MSps\n" + ) % xx % (target_rate/1e6) % (actual_rate/1e6))); + } +} + +static inline void do_tune_freq_warning_message( + double target_freq, + double actual_freq, + const std::string &xx +){ + static const double max_allowed_error = 1.0; //Hz + if (std::abs(target_freq - actual_freq) > max_allowed_error){ + uhd::print_warning(str(boost::format( + "The hardware does not support the requested %s frequency:\n" + "Target frequency: %f MHz\n" + "Actual frequency: %f MHz\n" + ) % xx % (target_freq/1e6) % (actual_freq/1e6))); + } +} + +#endif /* INCLUDED_LIBUHD_USRP_WRAPPER_UTILS_HPP */ -- cgit v1.2.3 From 847512647f10241d9ba828c5c284176d11437cb8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 18 Oct 2010 17:39:34 -0700 Subject: usrp: deleted deprecated simple and mimo wrappers, moved implementations into headers --- host/include/uhd/usrp/mimo_usrp.hpp | 343 ++++++++++++++++++++++++++++++++ host/include/uhd/usrp/simple_usrp.hpp | 214 ++++++++++++++++++++ host/lib/usrp/CMakeLists.txt | 2 - host/lib/usrp/mimo_usrp.cpp | 357 ---------------------------------- host/lib/usrp/simple_usrp.cpp | 226 --------------------- 5 files changed, 557 insertions(+), 585 deletions(-) delete mode 100644 host/lib/usrp/mimo_usrp.cpp delete mode 100644 host/lib/usrp/simple_usrp.cpp (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 7c250b2fd..78833e24e 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -179,4 +179,347 @@ public: }} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uhd{ namespace usrp{ namespace /*anon*/{ + +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ + double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); + return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} + +/*********************************************************************** + * MIMO USRP Implementation + **********************************************************************/ +class mimo_usrp_impl : public mimo_usrp{ +public: + mimo_usrp_impl(const device_addr_t &addr){ + _dev = device::make(addr); + + //set the clock config across all mboards (TODO set through api) + clock_config_t clock_config; + clock_config.ref_source = clock_config_t::REF_SMA; + clock_config.pps_source = clock_config_t::PPS_SMA; + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _mboard(chan)[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + } + } + + ~mimo_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_pp_string(void){ + std::string buff = str(boost::format( + "MIMO USRP:\n" + " Device: %s\n" + ) + % (*_dev)[DEVICE_PROP_NAME].as() + ); + for (size_t chan = 0; chan < get_num_channels(); chan++){ + buff += str(boost::format( + " Channel: %u\n" + " Mboard: %s\n" + " RX DSP: %s\n" + " RX Dboard: %s\n" + " RX Subdev: %s\n" + " TX DSP: %s\n" + " TX Dboard: %s\n" + " TX Subdev: %s\n" + ) % chan + % _mboard(chan)[MBOARD_PROP_NAME].as() + % _rx_dsp(chan)[DSP_PROP_NAME].as() + % _rx_dboard(chan)[DBOARD_PROP_NAME].as() + % _rx_subdev(chan)[SUBDEV_PROP_NAME].as() + % _tx_dsp(chan)[DSP_PROP_NAME].as() + % _tx_dboard(chan)[DBOARD_PROP_NAME].as() + % _tx_subdev(chan)[SUBDEV_PROP_NAME].as() + ); + } + return buff; + } + + size_t get_num_channels(void){ + return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as().size(); + } + + /******************************************************************* + * Misc + ******************************************************************/ + time_spec_t get_time_now(void){ + //the time on the first mboard better be the same on all + return _mboard(0)[MBOARD_PROP_TIME_NOW].as(); + } + + void set_time_next_pps(const time_spec_t &time_spec){ + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _mboard(chan)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + } + + void set_time_unknown_pps(const time_spec_t &time_spec){ + std::cout << "Set time with unknown pps edge:" << std::endl; + std::cout << " 1) set times next pps (race condition)" << std::endl; + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + + std::cout << " 2) catch seconds rollover at pps edge" << std::endl; + time_t last_secs = 0, curr_secs = 0; + while(curr_secs == last_secs){ + last_secs = curr_secs; + curr_secs = get_time_now().get_full_secs(); + } + + std::cout << " 3) set times next pps (synchronously)" << std::endl; + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + + //verify that the time registers are read to be within a few RTT + for (size_t chan = 1; chan < get_num_channels(); chan++){ + time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as(); + time_spec_t time_i = _mboard(chan)[MBOARD_PROP_TIME_NOW].as(); + if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big + uhd::print_warning(str(boost::format( + "Detected time deviation between board %d and board 0.\n" + "Board 0 time is %f seconds.\n" + "Board %d time is %f seconds.\n" + ) % chan % time_0.get_real_secs() % chan % time_i.get_real_secs())); + } + } + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _mboard(chan)[MBOARD_PROP_STREAM_CMD] = stream_cmd; + } + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_subdev_spec(size_t chan, const subdev_spec_t &spec){ + UHD_ASSERT_THROW(spec.size() <= 1); + _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; + } + + subdev_spec_t get_rx_subdev_spec(size_t chan){ + return _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as(); + } + + void set_rx_rate_all(double rate){ + std::vector _actual_rates; + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(_rx_dsp(chan)[DSP_PROP_HOST_RATE].as()); + } + _rx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: rx rate inconsistent across mboards" + ); + } + + double get_rx_rate_all(void){ + return _rx_rate; + } + + tune_result_t set_rx_freq(size_t chan, double target_freq){ + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq); + } + + tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off); + } + + double get_rx_freq(size_t chan){ + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0); + } + + freq_range_t get_rx_freq_range(size_t chan){ + return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp(chan)); + } + + void set_rx_gain(size_t chan, float gain){ + return _rx_gain_group(chan)->set_value(gain); + } + + float get_rx_gain(size_t chan){ + return _rx_gain_group(chan)->get_value(); + } + + gain_range_t get_rx_gain_range(size_t chan){ + return _rx_gain_group(chan)->get_range(); + } + + void set_rx_antenna(size_t chan, const std::string &ant){ + _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_rx_antennas(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_rx_lo_locked(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + float read_rssi(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); + } + + void set_rx_bandwidth(size_t chan, float bandwidth){ + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_subdev_spec(size_t chan, const subdev_spec_t &spec){ + UHD_ASSERT_THROW(spec.size() <= 1); + _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; + } + + subdev_spec_t get_tx_subdev_spec(size_t chan){ + return _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as(); + } + + void set_tx_rate_all(double rate){ + std::vector _actual_rates; + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(_tx_dsp(chan)[DSP_PROP_HOST_RATE].as()); + } + _tx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: tx rate inconsistent across mboards" + ); + } + + double get_tx_rate_all(void){ + return _tx_rate; + } + + tune_result_t set_tx_freq(size_t chan, double target_freq){ + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq); + } + + tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off); + } + + double get_tx_freq(size_t chan){ + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0); + } + + freq_range_t get_tx_freq_range(size_t chan){ + return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp(chan)); + } + + void set_tx_gain(size_t chan, float gain){ + return _tx_gain_group(chan)->set_value(gain); + } + + float get_tx_gain(size_t chan){ + return _tx_gain_group(chan)->get_value(); + } + + gain_range_t get_tx_gain_range(size_t chan){ + return _tx_gain_group(chan)->get_range(); + } + + void set_tx_antenna(size_t chan, const std::string &ant){ + _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_tx_antennas(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_tx_lo_locked(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + +private: + device::sptr _dev; + wax::obj _mboard(size_t chan){ + prop_names_t names = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as(); + return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, names.at(chan))]; + } + wax::obj _rx_dsp(size_t chan){ + return _mboard(chan)[MBOARD_PROP_RX_DSP]; + } + wax::obj _tx_dsp(size_t chan){ + return _mboard(chan)[MBOARD_PROP_TX_DSP]; + } + wax::obj _rx_dboard(size_t chan){ + std::string db_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().db_name; + return _mboard(chan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + } + wax::obj _tx_dboard(size_t chan){ + std::string db_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().db_name; + return _mboard(chan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + } + wax::obj _rx_subdev(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + wax::obj _tx_subdev(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + gain_group::sptr _rx_gain_group(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); + } + gain_group::sptr _tx_gain_group(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); + } + + //shadows + double _rx_rate, _tx_rate; +}; +}}} + +namespace uhd{ namespace usrp{ +/*********************************************************************** + * The Make Function + **********************************************************************/ +inline mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){ + uhd::print_warning( + "The mimo USRP interface has been deprecated.\n" + "Please switch to the multi USRP interface.\n" + "#include \n" + "multi_usrp::sptr sdev = multi_usrp::make(args);\n" + ); + return sptr(new mimo_usrp_impl(dev_addr)); +} +}} + #endif /* INCLUDED_UHD_USRP_MIMO_USRP_HPP */ diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 6f3597ed7..22f4d64ba 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -171,4 +171,218 @@ public: }} +#include +#include + +namespace uhd{ namespace usrp{ namespace /*anon*/{ + +/*********************************************************************** + * Simple USRP Implementation + **********************************************************************/ +class simple_usrp_impl : public simple_usrp{ +public: + simple_usrp_impl(const device_addr_t &addr){ + _sdev = single_usrp::make(addr); + } + + ~simple_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _sdev->get_device(); + } + + std::string get_pp_string(void){ + return _sdev->get_pp_string(); + } + + /******************************************************************* + * Misc + ******************************************************************/ + time_spec_t get_time_now(void){ + return _sdev->get_time_now(); + } + + void set_time_now(const time_spec_t &time_spec){ + return _sdev->set_time_now(time_spec); + } + + void set_time_next_pps(const time_spec_t &time_spec){ + return _sdev->set_time_next_pps(time_spec); + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + return _sdev->issue_stream_cmd(stream_cmd); + } + + void set_clock_config(const clock_config_t &clock_config){ + return _sdev->set_clock_config(clock_config); + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_subdev_spec(const subdev_spec_t &spec){ + return _sdev->set_rx_subdev_spec(spec); + } + + subdev_spec_t get_rx_subdev_spec(void){ + return _sdev->get_rx_subdev_spec(); + } + + void set_rx_rate(double rate){ + return _sdev->set_rx_rate(rate); + } + + double get_rx_rate(void){ + return _sdev->get_rx_rate(); + } + + tune_result_t set_rx_freq(double target_freq){ + return _sdev->set_rx_freq(target_freq); + } + + tune_result_t set_rx_freq(double target_freq, double lo_off){ + return _sdev->set_rx_freq(target_freq, lo_off); + } + + double get_rx_freq(void){ + return _sdev->get_rx_freq(); + } + + freq_range_t get_rx_freq_range(void){ + return _sdev->get_rx_freq_range(); + } + + void set_rx_gain(float gain){ + return _sdev->set_rx_gain(gain); + } + + float get_rx_gain(void){ + return _sdev->get_rx_gain(); + } + + gain_range_t get_rx_gain_range(void){ + return _sdev->get_rx_gain_range(); + } + + void set_rx_antenna(const std::string &ant){ + return _sdev->set_rx_antenna(ant); + } + + std::string get_rx_antenna(void){ + return _sdev->get_rx_antenna(); + } + + std::vector get_rx_antennas(void){ + return _sdev->get_rx_antennas(); + } + + bool get_rx_lo_locked(void){ + return _sdev->get_rx_lo_locked(); + } + + float read_rssi(void){ + return _sdev->read_rssi(); + } + + dboard_iface::sptr get_rx_dboard_iface(void){ + return _sdev->get_rx_dboard_iface(); + } + + void set_rx_bandwidth(float bandwidth) { + return _sdev->set_rx_bandwidth(bandwidth); + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_subdev_spec(const subdev_spec_t &spec){ + return _sdev->set_tx_subdev_spec(spec); + } + + subdev_spec_t get_tx_subdev_spec(void){ + return _sdev->get_tx_subdev_spec(); + } + + void set_tx_rate(double rate){ + return _sdev->set_tx_rate(rate); + } + + double get_tx_rate(void){ + return _sdev->get_tx_rate(); + } + + tune_result_t set_tx_freq(double target_freq){ + return _sdev->set_tx_freq(target_freq); + } + + tune_result_t set_tx_freq(double target_freq, double lo_off){ + return _sdev->set_tx_freq(target_freq, lo_off); + } + + double get_tx_freq(void){ + return _sdev->get_tx_freq(); + } + + freq_range_t get_tx_freq_range(void){ + return _sdev->get_tx_freq_range(); + } + + void set_tx_gain(float gain){ + return _sdev->set_tx_gain(gain); + } + + float get_tx_gain(void){ + return _sdev->get_tx_gain(); + } + + gain_range_t get_tx_gain_range(void){ + return _sdev->get_tx_gain_range(); + } + + void set_tx_antenna(const std::string &ant){ + return _sdev->set_tx_antenna(ant); + } + + std::string get_tx_antenna(void){ + return _sdev->get_tx_antenna(); + } + + std::vector get_tx_antennas(void){ + return _sdev->get_tx_antennas(); + } + + bool get_tx_lo_locked(void){ + return _sdev->get_tx_lo_locked(); + } + + dboard_iface::sptr get_tx_dboard_iface(void){ + return _sdev->get_tx_dboard_iface(); + } + +private: + single_usrp::sptr _sdev; +}; + +}}} + +namespace uhd{ namespace usrp{ + +/*********************************************************************** + * The Make Function + **********************************************************************/ +inline simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ + uhd::print_warning( + "The simple USRP interface has been deprecated.\n" + "Please switch to the single USRP interface.\n" + "#include \n" + "single_usrp::sptr sdev = single_usrp::make(args);\n" + ); + return sptr(new simple_usrp_impl(dev_addr)); +} + +}} + #endif /* INCLUDED_UHD_USRP_SIMPLE_USRP_HPP */ diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 906a5ff29..eeb181e0b 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -23,10 +23,8 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/multi_usrp.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp deleted file mode 100644 index f5a80a3e6..000000000 --- a/host/lib/usrp/mimo_usrp.cpp +++ /dev/null @@ -1,357 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// 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, see . -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ - double codec_rate = dsp[DSP_PROP_CODEC_RATE].as(); - return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); -} - -/*********************************************************************** - * MIMO USRP Implementation - **********************************************************************/ -class mimo_usrp_impl : public mimo_usrp{ -public: - mimo_usrp_impl(const device_addr_t &addr){ - _dev = device::make(addr); - - //set the clock config across all mboards (TODO set through api) - clock_config_t clock_config; - clock_config.ref_source = clock_config_t::REF_SMA; - clock_config.pps_source = clock_config_t::PPS_SMA; - for (size_t chan = 0; chan < get_num_channels(); chan++){ - _mboard(chan)[MBOARD_PROP_CLOCK_CONFIG] = clock_config; - } - } - - ~mimo_usrp_impl(void){ - /* NOP */ - } - - device::sptr get_device(void){ - return _dev; - } - - std::string get_pp_string(void){ - std::string buff = str(boost::format( - "MIMO USRP:\n" - " Device: %s\n" - ) - % (*_dev)[DEVICE_PROP_NAME].as() - ); - for (size_t chan = 0; chan < get_num_channels(); chan++){ - buff += str(boost::format( - " Channel: %u\n" - " Mboard: %s\n" - " RX DSP: %s\n" - " RX Dboard: %s\n" - " RX Subdev: %s\n" - " TX DSP: %s\n" - " TX Dboard: %s\n" - " TX Subdev: %s\n" - ) % chan - % _mboard(chan)[MBOARD_PROP_NAME].as() - % _rx_dsp(chan)[DSP_PROP_NAME].as() - % _rx_dboard(chan)[DBOARD_PROP_NAME].as() - % _rx_subdev(chan)[SUBDEV_PROP_NAME].as() - % _tx_dsp(chan)[DSP_PROP_NAME].as() - % _tx_dboard(chan)[DBOARD_PROP_NAME].as() - % _tx_subdev(chan)[SUBDEV_PROP_NAME].as() - ); - } - return buff; - } - - size_t get_num_channels(void){ - return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as().size(); - } - - /******************************************************************* - * Misc - ******************************************************************/ - time_spec_t get_time_now(void){ - //the time on the first mboard better be the same on all - return _mboard(0)[MBOARD_PROP_TIME_NOW].as(); - } - - void set_time_next_pps(const time_spec_t &time_spec){ - for (size_t chan = 0; chan < get_num_channels(); chan++){ - _mboard(chan)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; - } - } - - void set_time_unknown_pps(const time_spec_t &time_spec){ - std::cout << "Set time with unknown pps edge:" << std::endl; - std::cout << " 1) set times next pps (race condition)" << std::endl; - set_time_next_pps(time_spec); - boost::this_thread::sleep(boost::posix_time::seconds(1)); - - std::cout << " 2) catch seconds rollover at pps edge" << std::endl; - time_t last_secs = 0, curr_secs = 0; - while(curr_secs == last_secs){ - last_secs = curr_secs; - curr_secs = get_time_now().get_full_secs(); - } - - std::cout << " 3) set times next pps (synchronously)" << std::endl; - set_time_next_pps(time_spec); - boost::this_thread::sleep(boost::posix_time::seconds(1)); - - //verify that the time registers are read to be within a few RTT - for (size_t chan = 1; chan < get_num_channels(); chan++){ - time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as(); - time_spec_t time_i = _mboard(chan)[MBOARD_PROP_TIME_NOW].as(); - if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big - uhd::print_warning(str(boost::format( - "Detected time deviation between board %d and board 0.\n" - "Board 0 time is %f seconds.\n" - "Board %d time is %f seconds.\n" - ) % chan % time_0.get_real_secs() % chan % time_i.get_real_secs())); - } - } - } - - void issue_stream_cmd(const stream_cmd_t &stream_cmd){ - for (size_t chan = 0; chan < get_num_channels(); chan++){ - _mboard(chan)[MBOARD_PROP_STREAM_CMD] = stream_cmd; - } - } - - /******************************************************************* - * RX methods - ******************************************************************/ - void set_rx_subdev_spec(size_t chan, const subdev_spec_t &spec){ - UHD_ASSERT_THROW(spec.size() <= 1); - _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; - } - - subdev_spec_t get_rx_subdev_spec(size_t chan){ - return _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as(); - } - - void set_rx_rate_all(double rate){ - std::vector _actual_rates; - for (size_t chan = 0; chan < get_num_channels(); chan++){ - _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; - _actual_rates.push_back(_rx_dsp(chan)[DSP_PROP_HOST_RATE].as()); - } - _rx_rate = _actual_rates.front(); - if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error( - "MIMO configuratio error: rx rate inconsistent across mboards" - ); - } - - double get_rx_rate_all(void){ - return _rx_rate; - } - - tune_result_t set_rx_freq(size_t chan, double target_freq){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq); - } - - tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ - return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off); - } - - double get_rx_freq(size_t chan){ - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0); - } - - freq_range_t get_rx_freq_range(size_t chan){ - return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp(chan)); - } - - void set_rx_gain(size_t chan, float gain){ - return _rx_gain_group(chan)->set_value(gain); - } - - float get_rx_gain(size_t chan){ - return _rx_gain_group(chan)->get_value(); - } - - gain_range_t get_rx_gain_range(size_t chan){ - return _rx_gain_group(chan)->get_range(); - } - - void set_rx_antenna(size_t chan, const std::string &ant){ - _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; - } - - std::string get_rx_antenna(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); - } - - std::vector get_rx_antennas(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); - } - - bool get_rx_lo_locked(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); - } - - float read_rssi(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); - } - - void set_rx_bandwidth(size_t chan, float bandwidth){ - _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; - } - - /******************************************************************* - * TX methods - ******************************************************************/ - void set_tx_subdev_spec(size_t chan, const subdev_spec_t &spec){ - UHD_ASSERT_THROW(spec.size() <= 1); - _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; - } - - subdev_spec_t get_tx_subdev_spec(size_t chan){ - return _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as(); - } - - void set_tx_rate_all(double rate){ - std::vector _actual_rates; - for (size_t chan = 0; chan < get_num_channels(); chan++){ - _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; - _actual_rates.push_back(_tx_dsp(chan)[DSP_PROP_HOST_RATE].as()); - } - _tx_rate = _actual_rates.front(); - if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error( - "MIMO configuratio error: tx rate inconsistent across mboards" - ); - } - - double get_tx_rate_all(void){ - return _tx_rate; - } - - tune_result_t set_tx_freq(size_t chan, double target_freq){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq); - } - - tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ - return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off); - } - - double get_tx_freq(size_t chan){ - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0); - } - - freq_range_t get_tx_freq_range(size_t chan){ - return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp(chan)); - } - - void set_tx_gain(size_t chan, float gain){ - return _tx_gain_group(chan)->set_value(gain); - } - - float get_tx_gain(size_t chan){ - return _tx_gain_group(chan)->get_value(); - } - - gain_range_t get_tx_gain_range(size_t chan){ - return _tx_gain_group(chan)->get_range(); - } - - void set_tx_antenna(size_t chan, const std::string &ant){ - _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; - } - - std::string get_tx_antenna(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as(); - } - - std::vector get_tx_antennas(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); - } - - bool get_tx_lo_locked(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); - } - -private: - device::sptr _dev; - wax::obj _mboard(size_t chan){ - prop_names_t names = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as(); - return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, names.at(chan))]; - } - wax::obj _rx_dsp(size_t chan){ - return _mboard(chan)[MBOARD_PROP_RX_DSP]; - } - wax::obj _tx_dsp(size_t chan){ - return _mboard(chan)[MBOARD_PROP_TX_DSP]; - } - wax::obj _rx_dboard(size_t chan){ - std::string db_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().db_name; - return _mboard(chan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; - } - wax::obj _tx_dboard(size_t chan){ - std::string db_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().db_name; - return _mboard(chan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; - } - wax::obj _rx_subdev(size_t chan){ - std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().sd_name; - return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; - } - wax::obj _tx_subdev(size_t chan){ - std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().sd_name; - return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; - } - gain_group::sptr _rx_gain_group(size_t chan){ - std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as().front().sd_name; - return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); - } - gain_group::sptr _tx_gain_group(size_t chan){ - std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as().front().sd_name; - return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); - } - - //shadows - double _rx_rate, _tx_rate; -}; - -/*********************************************************************** - * The Make Function - **********************************************************************/ -mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){ - uhd::print_warning( - "The mimo USRP interface has been deprecated.\n" - "Please switch to the multi USRP interface.\n" - "#include \n" - "multi_usrp::sptr sdev = multi_usrp::make(args);\n" - ); - return sptr(new mimo_usrp_impl(dev_addr)); -} diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp deleted file mode 100644 index b4f34287b..000000000 --- a/host/lib/usrp/simple_usrp.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// 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, see . -// - -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Simple USRP Implementation - **********************************************************************/ -class simple_usrp_impl : public simple_usrp{ -public: - simple_usrp_impl(const device_addr_t &addr){ - _sdev = single_usrp::make(addr); - } - - ~simple_usrp_impl(void){ - /* NOP */ - } - - device::sptr get_device(void){ - return _sdev->get_device(); - } - - std::string get_pp_string(void){ - return _sdev->get_pp_string(); - } - - /******************************************************************* - * Misc - ******************************************************************/ - time_spec_t get_time_now(void){ - return _sdev->get_time_now(); - } - - void set_time_now(const time_spec_t &time_spec){ - return _sdev->set_time_now(time_spec); - } - - void set_time_next_pps(const time_spec_t &time_spec){ - return _sdev->set_time_next_pps(time_spec); - } - - void issue_stream_cmd(const stream_cmd_t &stream_cmd){ - return _sdev->issue_stream_cmd(stream_cmd); - } - - void set_clock_config(const clock_config_t &clock_config){ - return _sdev->set_clock_config(clock_config); - } - - /******************************************************************* - * RX methods - ******************************************************************/ - void set_rx_subdev_spec(const subdev_spec_t &spec){ - return _sdev->set_rx_subdev_spec(spec); - } - - subdev_spec_t get_rx_subdev_spec(void){ - return _sdev->get_rx_subdev_spec(); - } - - void set_rx_rate(double rate){ - return _sdev->set_rx_rate(rate); - } - - double get_rx_rate(void){ - return _sdev->get_rx_rate(); - } - - tune_result_t set_rx_freq(double target_freq){ - return _sdev->set_rx_freq(target_freq); - } - - tune_result_t set_rx_freq(double target_freq, double lo_off){ - return _sdev->set_rx_freq(target_freq, lo_off); - } - - double get_rx_freq(void){ - return _sdev->get_rx_freq(); - } - - freq_range_t get_rx_freq_range(void){ - return _sdev->get_rx_freq_range(); - } - - void set_rx_gain(float gain){ - return _sdev->set_rx_gain(gain); - } - - float get_rx_gain(void){ - return _sdev->get_rx_gain(); - } - - gain_range_t get_rx_gain_range(void){ - return _sdev->get_rx_gain_range(); - } - - void set_rx_antenna(const std::string &ant){ - return _sdev->set_rx_antenna(ant); - } - - std::string get_rx_antenna(void){ - return _sdev->get_rx_antenna(); - } - - std::vector get_rx_antennas(void){ - return _sdev->get_rx_antennas(); - } - - bool get_rx_lo_locked(void){ - return _sdev->get_rx_lo_locked(); - } - - float read_rssi(void){ - return _sdev->read_rssi(); - } - - dboard_iface::sptr get_rx_dboard_iface(void){ - return _sdev->get_rx_dboard_iface(); - } - - void set_rx_bandwidth(float bandwidth) { - return _sdev->set_rx_bandwidth(bandwidth); - } - - /******************************************************************* - * TX methods - ******************************************************************/ - void set_tx_subdev_spec(const subdev_spec_t &spec){ - return _sdev->set_tx_subdev_spec(spec); - } - - subdev_spec_t get_tx_subdev_spec(void){ - return _sdev->get_tx_subdev_spec(); - } - - void set_tx_rate(double rate){ - return _sdev->set_tx_rate(rate); - } - - double get_tx_rate(void){ - return _sdev->get_tx_rate(); - } - - tune_result_t set_tx_freq(double target_freq){ - return _sdev->set_tx_freq(target_freq); - } - - tune_result_t set_tx_freq(double target_freq, double lo_off){ - return _sdev->set_tx_freq(target_freq, lo_off); - } - - double get_tx_freq(void){ - return _sdev->get_tx_freq(); - } - - freq_range_t get_tx_freq_range(void){ - return _sdev->get_tx_freq_range(); - } - - void set_tx_gain(float gain){ - return _sdev->set_tx_gain(gain); - } - - float get_tx_gain(void){ - return _sdev->get_tx_gain(); - } - - gain_range_t get_tx_gain_range(void){ - return _sdev->get_tx_gain_range(); - } - - void set_tx_antenna(const std::string &ant){ - return _sdev->set_tx_antenna(ant); - } - - std::string get_tx_antenna(void){ - return _sdev->get_tx_antenna(); - } - - std::vector get_tx_antennas(void){ - return _sdev->get_tx_antennas(); - } - - bool get_tx_lo_locked(void){ - return _sdev->get_tx_lo_locked(); - } - - dboard_iface::sptr get_tx_dboard_iface(void){ - return _sdev->get_tx_dboard_iface(); - } - -private: - single_usrp::sptr _sdev; -}; - -/*********************************************************************** - * The Make Function - **********************************************************************/ -simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ - uhd::print_warning( - "The simple USRP interface has been deprecated.\n" - "Please switch to the single USRP interface.\n" - "#include \n" - "single_usrp::sptr sdev = single_usrp::make(args);\n" - ); - return sptr(new simple_usrp_impl(dev_addr)); -} -- cgit v1.2.3 From 982ac435e99a7bb9de3838f5919643cfe5cb8851 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 18 Oct 2010 18:24:53 -0700 Subject: multi-usrp: corrected calculations for channel and mboard indexes --- host/lib/usrp/multi_usrp.cpp | 55 ++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 30 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 7f7ea77b0..cb44bc468 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -215,27 +215,23 @@ public: } tune_result_t set_rx_freq(double target_freq, size_t chan){ - size_t nchan = get_rx_num_channels(); - tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), target_freq); do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); return r; } tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ - size_t nchan = get_rx_num_channels(); - tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), target_freq, lo_off); do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); return r; } double get_rx_freq(size_t chan){ - size_t nchan = get_rx_num_channels(); - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(nchan/chan), nchan%chan); + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm()); } freq_range_t get_rx_freq_range(size_t chan){ - size_t nchan = get_rx_num_channels(); - return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp(nchan/chan)); + return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _rx_dsp(chan/rx_cpm())); } void set_rx_gain(float gain, size_t chan){ @@ -321,27 +317,23 @@ public: } tune_result_t set_tx_freq(double target_freq, size_t chan){ - size_t nchan = get_tx_num_channels(); - tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), target_freq); do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); return r; } tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ - size_t nchan = get_tx_num_channels(); - tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan, target_freq, lo_off); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), target_freq, lo_off); do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); return r; } double get_tx_freq(size_t chan){ - size_t nchan = get_tx_num_channels(); - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(nchan/chan), nchan%chan); + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm()); } freq_range_t get_tx_freq_range(size_t chan){ - size_t nchan = get_tx_num_channels(); - return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp(nchan/chan)); + return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as(), _tx_dsp(chan/tx_cpm())); } void set_tx_gain(float gain, size_t chan){ @@ -378,6 +370,15 @@ public: private: device::sptr _dev; + + size_t rx_cpm(void){ //channels per mboard + return get_rx_num_channels()/get_num_mboards(); + } + + size_t tx_cpm(void){ //channels per mboard + return get_tx_num_channels()/get_num_mboards(); + } + wax::obj _mboard(size_t mboard){ std::string mb_name = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as().at(mboard); return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, mb_name)]; @@ -389,33 +390,27 @@ private: return _mboard(mboard)[MBOARD_PROP_TX_DSP]; } wax::obj _rx_dboard(size_t chan){ - size_t nchan = get_rx_num_channels(); - std::string db_name = get_rx_subdev_spec(chan/nchan).at(chan%nchan).db_name; - return _mboard(chan/nchan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + std::string db_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).db_name; + return _mboard(chan/rx_cpm())[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; } wax::obj _tx_dboard(size_t chan){ - size_t nchan = get_tx_num_channels(); - std::string db_name = get_tx_subdev_spec(chan/nchan).at(chan%nchan).db_name; - return _mboard(chan/nchan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + std::string db_name = get_tx_subdev_spec(chan/tx_cpm()).at(chan%tx_cpm()).db_name; + return _mboard(chan/tx_cpm())[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; } wax::obj _rx_subdev(size_t chan){ - size_t nchan = get_rx_num_channels(); - std::string sd_name = get_rx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + std::string sd_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).sd_name; return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; } wax::obj _tx_subdev(size_t chan){ - size_t nchan = get_tx_num_channels(); - std::string sd_name = get_tx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + std::string sd_name = get_tx_subdev_spec(chan/tx_cpm()).at(chan%tx_cpm()).sd_name; return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; } gain_group::sptr _rx_gain_group(size_t chan){ - size_t nchan = get_rx_num_channels(); - std::string sd_name = get_rx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + std::string sd_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).sd_name; return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); } gain_group::sptr _tx_gain_group(size_t chan){ - size_t nchan = get_tx_num_channels(); - std::string sd_name = get_tx_subdev_spec(chan/nchan).at(chan%nchan).sd_name; + std::string sd_name = get_tx_subdev_spec(chan/tx_cpm()).at(chan%tx_cpm()).sd_name; return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as(); } }; -- cgit v1.2.3 From 083413de3dc67e34042ec4e3e77b0ebfaf19009b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 19 Oct 2010 13:04:07 -0700 Subject: multi-usrp: fixed num channel calculation, moved logic to cpm functions --- host/lib/usrp/multi_usrp.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index cb44bc468..6df3afbf8 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -190,13 +190,7 @@ public: } size_t get_rx_num_channels(void){ - size_t nchan = get_rx_subdev_spec(0).size(); - for (size_t m = 1; m < get_num_mboards(); m++){ - if (nchan != get_rx_subdev_spec(m).size()){ - throw std::runtime_error("rx subdev spec size inconsistent across all mboards"); - } - } - return nchan; + return rx_cpm()*get_num_mboards(); //total num channels } std::string get_rx_subdev_name(size_t chan){ @@ -296,13 +290,7 @@ public: } size_t get_tx_num_channels(void){ - size_t nchan = get_tx_subdev_spec(0).size(); - for (size_t m = 1; m < get_num_mboards(); m++){ - if (nchan != get_tx_subdev_spec(m).size()){ - throw std::runtime_error("tx subdev spec size inconsistent across all mboards"); - } - } - return nchan; + return tx_cpm()*get_num_mboards(); //total num channels } void set_tx_rate(double rate){ @@ -372,11 +360,23 @@ private: device::sptr _dev; size_t rx_cpm(void){ //channels per mboard - return get_rx_num_channels()/get_num_mboards(); + size_t nchan = get_rx_subdev_spec(0).size(); + for (size_t m = 1; m < get_num_mboards(); m++){ + if (nchan != get_rx_subdev_spec(m).size()){ + throw std::runtime_error("rx subdev spec size inconsistent across all mboards"); + } + } + return nchan; } size_t tx_cpm(void){ //channels per mboard - return get_tx_num_channels()/get_num_mboards(); + size_t nchan = get_tx_subdev_spec(0).size(); + for (size_t m = 1; m < get_num_mboards(); m++){ + if (nchan != get_tx_subdev_spec(m).size()){ + throw std::runtime_error("tx subdev spec size inconsistent across all mboards"); + } + } + return nchan; } wax::obj _mboard(size_t mboard){ -- cgit v1.2.3 From 799d5059bae77a24267cfc33b33c4af1c0de8c5b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 19 Oct 2010 15:42:21 -0700 Subject: usrp: change the bandwidth param to a double (its a frequency), add set and gets for BW in the wrappers --- host/include/uhd/usrp/multi_usrp.hpp | 8 ++++++-- host/include/uhd/usrp/single_usrp.hpp | 8 ++++++-- host/lib/usrp/dboard/db_dbsrx.cpp | 18 ++++++------------ host/lib/usrp/dboard/db_xcvr2450.cpp | 20 ++++++++++---------- host/lib/usrp/multi_usrp.cpp | 20 ++++++++++++++++---- host/lib/usrp/single_usrp.cpp | 20 ++++++++++++++++---- 6 files changed, 60 insertions(+), 34 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp index 65c7e9044..dcec0c515 100644 --- a/host/include/uhd/usrp/multi_usrp.hpp +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -201,6 +201,9 @@ public: virtual bool get_rx_lo_locked(size_t chan) = 0; + virtual void set_rx_bandwidth(double bandwidth, size_t chan) = 0; + virtual double get_rx_bandwidth(size_t chan) = 0; + /*! * Read the RSSI value from a usrp device. * Or throw if the dboard does not support an RSSI readback. @@ -209,8 +212,6 @@ public: virtual float read_rssi(size_t chan) = 0; virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan) = 0; - - virtual void set_rx_bandwidth(float bandwidth, size_t chan) = 0; /******************************************************************* * TX methods @@ -251,6 +252,9 @@ public: virtual bool get_tx_lo_locked(size_t chan) = 0; + virtual void set_tx_bandwidth(double bandwidth, size_t chan) = 0; + virtual double get_tx_bandwidth(size_t chan) = 0; + virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan) = 0; }; diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp index 2266e7f2c..9b2fd7ccf 100644 --- a/host/include/uhd/usrp/single_usrp.hpp +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -144,6 +144,9 @@ public: virtual bool get_rx_lo_locked(size_t chan = 0) = 0; + virtual void set_rx_bandwidth(double bandwidth, size_t chan = 0) = 0; + virtual double get_rx_bandwidth(size_t chan = 0) = 0; + /*! * Read the RSSI value from a usrp device. * Or throw if the dboard does not support an RSSI readback. @@ -152,8 +155,6 @@ public: virtual float read_rssi(size_t chan = 0) = 0; virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan = 0) = 0; - - virtual void set_rx_bandwidth(float bandwidth, size_t chan = 0) = 0; /******************************************************************* * TX methods @@ -186,6 +187,9 @@ public: virtual bool get_tx_lo_locked(size_t chan = 0) = 0; + virtual void set_tx_bandwidth(double bandwidth, size_t chan = 0) = 0; + virtual double get_tx_bandwidth(size_t chan = 0) = 0; + virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan = 0) = 0; }; diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 99137dda3..939a79e58 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -69,7 +69,7 @@ public: private: double _lo_freq; - float _bandwidth; + double _bandwidth; uhd::dict _gains; max2118_write_regs_t _max2118_write_regs; max2118_read_regs_t _max2118_read_regs; @@ -79,7 +79,7 @@ private: void set_lo_freq(double target_freq); void set_gain(float gain, const std::string &name); - void set_bandwidth(float bandwidth); + void set_bandwidth(double bandwidth); void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5)); @@ -482,9 +482,9 @@ void dbsrx::set_gain(float gain, const std::string &name){ /*********************************************************************** * Bandwidth Handling **********************************************************************/ -void dbsrx::set_bandwidth(float bandwidth){ +void dbsrx::set_bandwidth(double bandwidth){ //clip the input - bandwidth = std::clip(bandwidth, 4e6, 33e6); + bandwidth = std::clip(bandwidth, 4e6, 33e6); double ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); @@ -494,7 +494,7 @@ void dbsrx::set_bandwidth(float bandwidth){ _max2118_write_regs.f_dac = std::clip(int((((bandwidth*_max2118_write_regs.m_divider)/ref_clock) - 4)/0.145),0,127); //determine actual bandwidth - _bandwidth = float((ref_clock/(_max2118_write_regs.m_divider))*(4+0.145*_max2118_write_regs.f_dac)); + _bandwidth = double((ref_clock/(_max2118_write_regs.m_divider))*(4+0.145*_max2118_write_regs.f_dac)); if (dbsrx_debug) std::cerr << boost::format( "DBSRX Filter Bandwidth: %f MHz, m: %d, f_dac: %d\n" @@ -565,12 +565,6 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ val = this->get_locked(); return; -/* - case SUBDEV_PROP_RSSI: - val = this->get_rssi(); - return; -*/ - case SUBDEV_PROP_BANDWIDTH: val = _bandwidth; return; @@ -597,7 +591,7 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){ return; //always enabled case SUBDEV_PROP_BANDWIDTH: - this->set_bandwidth(val.as()); + this->set_bandwidth(val.as()); return; default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 314c85a69..99f2a231c 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -102,7 +102,7 @@ public: private: double _lo_freq; - float _rx_bandwidth, _tx_bandwidth; + double _rx_bandwidth, _tx_bandwidth; uhd::dict _tx_gains, _rx_gains; std::string _tx_ant, _rx_ant; int _ad9515div; @@ -113,8 +113,8 @@ private: void set_rx_ant(const std::string &ant); void set_tx_gain(float gain, const std::string &name); void set_rx_gain(float gain, const std::string &name); - void set_rx_bandwidth(float bandwidth); - void set_tx_bandwidth(float bandwidth); + void set_rx_bandwidth(double bandwidth); + void set_tx_bandwidth(double bandwidth); void update_atr(void); void spi_reset(void); @@ -455,7 +455,7 @@ void xcvr2450::set_rx_gain(float gain, const std::string &name){ /*********************************************************************** * Bandwidth Handling **********************************************************************/ -static max2829_regs_t::tx_lpf_coarse_adj_t bandwidth_to_tx_lpf_coarse_reg(float &bandwidth){ +static max2829_regs_t::tx_lpf_coarse_adj_t bandwidth_to_tx_lpf_coarse_reg(double &bandwidth){ int reg = std::clip(boost::math::iround((bandwidth-6.0e6)/6.0e6), 1, 3); switch(reg){ @@ -472,7 +472,7 @@ static max2829_regs_t::tx_lpf_coarse_adj_t bandwidth_to_tx_lpf_coarse_reg(float UHD_THROW_INVALID_CODE_PATH(); } -static max2829_regs_t::rx_lpf_fine_adj_t bandwidth_to_rx_lpf_fine_reg(float &bandwidth, float requested_bandwidth){ +static max2829_regs_t::rx_lpf_fine_adj_t bandwidth_to_rx_lpf_fine_reg(double &bandwidth, double requested_bandwidth){ int reg = std::clip(boost::math::iround((requested_bandwidth/bandwidth)/0.05), 18, 22); switch(reg){ @@ -495,7 +495,7 @@ static max2829_regs_t::rx_lpf_fine_adj_t bandwidth_to_rx_lpf_fine_reg(float &ban UHD_THROW_INVALID_CODE_PATH(); } -static max2829_regs_t::rx_lpf_coarse_adj_t bandwidth_to_rx_lpf_coarse_reg(float &bandwidth){ +static max2829_regs_t::rx_lpf_coarse_adj_t bandwidth_to_rx_lpf_coarse_reg(double &bandwidth){ int reg = std::clip(boost::math::iround((bandwidth-7.0e6)/1.0e6), 0, 11); switch(reg){ @@ -523,7 +523,7 @@ static max2829_regs_t::rx_lpf_coarse_adj_t bandwidth_to_rx_lpf_coarse_reg(float UHD_THROW_INVALID_CODE_PATH(); } -void xcvr2450::set_rx_bandwidth(float bandwidth){ +void xcvr2450::set_rx_bandwidth(double bandwidth){ float requested_bandwidth = bandwidth; //compute coarse low pass cutoff frequency setting @@ -543,7 +543,7 @@ void xcvr2450::set_rx_bandwidth(float bandwidth){ ) % _rx_bandwidth % (int(_max2829_regs.rx_lpf_coarse_adj)) % (int(_max2829_regs.rx_lpf_fine_adj)) << std::endl; } -void xcvr2450::set_tx_bandwidth(float bandwidth){ +void xcvr2450::set_tx_bandwidth(double bandwidth){ //compute coarse low pass cutoff frequency setting _max2829_regs.tx_lpf_coarse_adj = bandwidth_to_tx_lpf_coarse_reg(bandwidth); @@ -652,7 +652,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_BANDWIDTH: - this->set_rx_bandwidth(val.as()); + this->set_rx_bandwidth(val.as()); return; case SUBDEV_PROP_ENABLED: @@ -747,7 +747,7 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_BANDWIDTH: - this->set_tx_bandwidth(val.as()); + this->set_tx_bandwidth(val.as()); return; case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 6df3afbf8..027530f31 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -256,6 +256,14 @@ public: return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); } + void set_rx_bandwidth(double bandwidth, size_t chan){ + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + double get_rx_bandwidth(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as(); + } + float read_rssi(size_t chan){ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); } @@ -263,10 +271,6 @@ public: dboard_iface::sptr get_rx_dboard_iface(size_t chan){ return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); } - - void set_rx_bandwidth(float bandwidth, size_t chan) { - _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; - } /******************************************************************* * TX methods @@ -352,6 +356,14 @@ public: return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); } + void set_tx_bandwidth(double bandwidth, size_t chan){ + _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + double get_tx_bandwidth(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as(); + } + dboard_iface::sptr get_tx_dboard_iface(size_t chan){ return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); } diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index 7a4df3eb5..2faa1280c 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -192,6 +192,14 @@ public: return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); } + void set_rx_bandwidth(double bandwidth, size_t chan){ + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + double get_rx_bandwidth(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as(); + } + float read_rssi(size_t chan){ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as(); } @@ -199,10 +207,6 @@ public: dboard_iface::sptr get_rx_dboard_iface(size_t chan){ return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); } - - void set_rx_bandwidth(float bandwidth, size_t chan) { - _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; - } /******************************************************************* * TX methods @@ -276,6 +280,14 @@ public: return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as(); } + void set_tx_bandwidth(double bandwidth, size_t chan){ + _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + double get_tx_bandwidth(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as(); + } + dboard_iface::sptr get_tx_dboard_iface(size_t chan){ return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as(); } -- cgit v1.2.3 From b405abf883a5b37de1468cde679644927d89abce Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 19 Oct 2010 17:13:56 -0700 Subject: uhd: remove some warnings in MSVC and with typo in xcvr2450 --- host/include/uhd/config.hpp | 5 +++-- host/lib/usrp/dboard/db_xcvr2450.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index dacd3a96b..2918c2340 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -31,11 +31,12 @@ # pragma warning(disable: 4251) // class 'A' needs to have dll-interface to be used by clients of class 'B' //# pragma warning(disable: 4127) // conditional expression is constant //# pragma warning(disable: 4290) // C++ exception specification ignored except to ... -# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored +//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored # pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ... //# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data //# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated -# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance +//# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance +# pragma warning(disable: 4200) // nonstandard extension used : zero-sized array in struct/union #endif // define logical operators diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 99f2a231c..fb1367113 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -524,7 +524,7 @@ static max2829_regs_t::rx_lpf_coarse_adj_t bandwidth_to_rx_lpf_coarse_reg(double } void xcvr2450::set_rx_bandwidth(double bandwidth){ - float requested_bandwidth = bandwidth; + double requested_bandwidth = bandwidth; //compute coarse low pass cutoff frequency setting _max2829_regs.rx_lpf_coarse_adj = bandwidth_to_rx_lpf_coarse_reg(bandwidth); -- cgit v1.2.3