diff options
-rw-r--r-- | firmware/microblaze/apps/txrx.c | 10 | ||||
-rw-r--r-- | host/apps/discover_usrps.cpp | 2 | ||||
-rw-r--r-- | host/include/uhd/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/props.hpp | 20 | ||||
-rw-r--r-- | host/include/uhd/simple_device.hpp | 111 | ||||
-rw-r--r-- | host/include/uhd/time_spec.hpp | 19 | ||||
-rw-r--r-- | host/include/uhd/utils.hpp | 105 | ||||
-rw-r--r-- | host/lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/lib/simple_device.cpp | 303 | ||||
-rw-r--r-- | host/lib/time_spec.cpp | 40 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dboard_impl.cpp | 9 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dsp_impl.cpp | 21 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 8 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 35 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 1 |
15 files changed, 591 insertions, 96 deletions
diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 1b3299150..18bbdd23d 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -489,6 +489,16 @@ void handle_udp_ctrl_packet( ctrl_data_out.id = USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE; break; + /******************************************************************* + * Time Config + ******************************************************************/ + case USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO: + sr_time64->imm = (ctrl_data_in->data.time_args.now == 0)? 0 : 1; + sr_time64->ticks = ctrl_data_in->data.time_args.ticks; + sr_time64->secs = ctrl_data_in->data.time_args.secs; //set this last to latch the regs + ctrl_data_out.id = USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE; + break; + default: ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 448095726..d670d1651 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,7 +63,7 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; - //uhd::device::make(device_addrs[i]); //test make + uhd::device::make(device_addrs[i]); //test make } return 0; diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index f4fb96786..522f43afd 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES gain_handler.hpp metadata.hpp props.hpp + simple_device.hpp time_spec.hpp utils.hpp wax.hpp diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index cf301d4bd..dea2baf52 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -116,16 +116,16 @@ namespace uhd{ enum dboard_prop_t{ DBOARD_PROP_NAME, //ro, std::string DBOARD_PROP_SUBDEV, //ro, wax::obj - DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t - DBOARD_PROP_CODEC //ro, wax::obj - }; + DBOARD_PROP_SUBDEV_NAMES //ro, prop_names_t + //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet + }; - /*! + /*! ------ not dealing with yet, commented out ------------ * Possible device codec properties: * A codec is expected to have a rate and gain elements. * Other properties can be discovered through the others prop. */ - enum codec_prop_t{ + /*enum codec_prop_t{ CODEC_PROP_NAME, //ro, std::string CODEC_PROP_OTHERS, //ro, prop_names_t CODEC_PROP_GAIN, //rw, gain_t @@ -133,8 +133,8 @@ namespace uhd{ CODEC_PROP_GAIN_MIN, //ro, gain_t CODEC_PROP_GAIN_STEP, //ro, gain_t CODEC_PROP_GAIN_NAMES, //ro, prop_names_t - CODEC_PROP_CLOCK_RATE //ro, freq_t - }; + //CODEC_PROP_CLOCK_RATE //ro, freq_t //----> not sure we care to know + };*/ /*! * Possible device subdev properties @@ -156,9 +156,9 @@ namespace uhd{ SUBDEV_PROP_QUADRATURE, //ro, bool SUBDEV_PROP_IQ_SWAPPED, //ro, bool SUBDEV_PROP_SPECTRUM_INVERTED, //ro, bool - SUBDEV_PROP_IS_TX, //ro, bool - SUBDEV_PROP_RSSI, //ro, gain_t - SUBDEV_PROP_BANDWIDTH //rw, freq_t + SUBDEV_PROP_LO_INTERFERES //ro, bool + //SUBDEV_PROP_RSSI, //ro, gain_t //----> not on all boards, use named prop + //SUBDEV_PROP_BANDWIDTH //rw, freq_t //----> not on all boards, use named prop }; } //namespace uhd diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp new file mode 100644 index 000000000..64ec85a5c --- /dev/null +++ b/host/include/uhd/simple_device.hpp @@ -0,0 +1,111 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <uhd/device.hpp> +#include <vector> + +#ifndef INCLUDED_UHD_SIMPLE_DEVICE_HPP +#define INCLUDED_UHD_SIMPLE_DEVICE_HPP + +namespace uhd{ + +/*! + * The tune result struct holds result of a 2-phase tuning: + * The struct hold the result of tuning the dboard as + * the target and actual intermediate frequency. + * The struct hold the result of tuning the DDC/DUC as + * the target and actual digital converter frequency. + * It also tell us weather or not the spectrum is inverted. + */ +struct tune_result_t{ + double target_inter_freq; + double actual_inter_freq; + double target_dxc_freq; + double actual_dxc_freq; + bool spectrum_inverted; + tune_result_t(void); +}; + +/*! + * The simple UHD device class: + * A simple device 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. + */ +class simple_device : boost::noncopyable{ +public: + typedef boost::shared_ptr<simple_device> sptr; + static sptr make(const std::string &args); + + virtual device::sptr get_device(void) = 0; + + virtual std::string get_name(void) = 0; + + /******************************************************************* + * Streaming + ******************************************************************/ + virtual void set_streaming(bool enb) = 0; + virtual bool get_streaming(void) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + virtual void set_rx_rate(double rate) = 0; + virtual double get_rx_rate(void) = 0; + virtual std::vector<double> get_rx_rates(void) = 0; + + virtual tune_result_t set_rx_freq(double target_freq, double lo_offset) = 0; + virtual double get_rx_freq_min(void) = 0; + virtual double get_rx_freq_max(void) = 0; + + virtual void set_rx_gain(float gain) = 0; + virtual float get_rx_gain(void) = 0; + virtual float get_rx_gain_min(void) = 0; + virtual float get_rx_gain_max(void) = 0; + virtual float get_rx_gain_step(void) = 0; + + virtual void set_rx_antenna(const std::string &ant) = 0; + virtual std::string get_rx_antenna(void) = 0; + virtual std::vector<std::string> get_rx_antennas(void) = 0; + + /******************************************************************* + * TX methods + ******************************************************************/ + virtual void set_tx_rate(double rate) = 0; + virtual double get_tx_rate(void) = 0; + virtual std::vector<double> get_tx_rates(void) = 0; + + virtual tune_result_t set_tx_freq(double target_freq, double lo_offset) = 0; + virtual double get_tx_freq_min(void) = 0; + virtual double get_tx_freq_max(void) = 0; + + virtual void set_tx_gain(float gain) = 0; + virtual float get_tx_gain(void) = 0; + virtual float get_tx_gain_min(void) = 0; + virtual float get_tx_gain_max(void) = 0; + virtual float get_tx_gain_step(void) = 0; + + virtual void set_tx_antenna(const std::string &ant) = 0; + virtual std::string get_tx_antenna(void) = 0; + virtual std::vector<std::string> get_tx_antennas(void) = 0; +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_SIMPLE_DEVICE_HPP */ diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/time_spec.hpp index e5657e555..7e182236b 100644 --- a/host/include/uhd/time_spec.hpp +++ b/host/include/uhd/time_spec.hpp @@ -15,6 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <boost/date_time/posix_time/posix_time.hpp> #include <stdint.h> #ifndef INCLUDED_UHD_TIME_SPEC_HPP @@ -36,20 +37,22 @@ namespace uhd{ * Create a time_spec_t that holds a wildcard time. * This will have implementation-specific meaning. */ - time_spec_t(void){ - secs = ~0; - ticks = ~0; - } + time_spec_t(void); /*! * Create a time_spec_t from seconds and ticks. * \param new_secs the new seconds * \param new_ticks the new ticks (default = 0) */ - time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0){ - secs = new_secs; - ticks = new_ticks; - } + time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0); + + /*! + * Create a time_spec_t from boost posix time. + * \param time fine-grained boost posix time + * \param tick_rate the rate of ticks per second + */ + time_spec_t(boost::posix_time::ptime time, double tick_rate); + }; } //namespace uhd diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 9bbdc83c9..25a7b5abd 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -15,18 +15,14 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/wax.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <boost/function.hpp> -#include <stdexcept> -#include <algorithm> -#include <vector> -#include <map> - #ifndef INCLUDED_UHD_UTILS_HPP #define INCLUDED_UHD_UTILS_HPP +#include <stdexcept> +#include <algorithm> +#include <boost/format.hpp> +#include <boost/current_function.hpp> + /*! * Useful templated functions and classes that I like to pretend are part of stl */ @@ -40,7 +36,9 @@ namespace std{ }; #define ASSERT_THROW(_x) if (not (_x)) { \ - throw std::assert_error("Assertion Failed: " + std::string(#_x)); \ + throw std::assert_error(str(boost::format( \ + "Assertion Failed:\n %s:%d\n %s\n __/ %s __/" \ + ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \ } template<class T, class InputIterator, class Function> @@ -57,9 +55,9 @@ namespace std{ return last != std::find(first, last, elem); } - template<class T, class V> - bool has(const V &vector, const T &elem){ - return has(vector.begin(), vector.end(), elem); + template<class T, class Iterable> + bool has(const Iterable &iterable, const T &elem){ + return has(iterable.begin(), iterable.end(), elem); } template<class T> @@ -75,52 +73,43 @@ namespace std{ }//namespace std -/*namespace uhd{ - -inline void tune( - freq_t target_freq, - freq_t lo_offset, - wax::obj subdev_freq_proxy, - bool subdev_quadrature, - bool subdev_spectrum_inverted, - bool subdev_is_tx, - wax::obj dsp_freq_proxy, - freq_t dsp_sample_rate -){ - // Ask the d'board to tune as closely as it can to target_freq+lo_offset - subdev_freq_proxy = target_freq + lo_offset; - freq_t inter_freq = wax::cast<freq_t>(subdev_freq_proxy); - - // Calculate the DDC setting that will downconvert the baseband from the - // daughterboard to our target frequency. - freq_t delta_freq = target_freq - inter_freq; - freq_t delta_sign = std::signum(delta_freq); - delta_freq *= delta_sign; - delta_freq = fmod(delta_freq, dsp_sample_rate); - bool inverted = delta_freq > dsp_sample_rate/2.0; - freq_t dxc_freq = inverted? (delta_freq - dsp_sample_rate) : (-delta_freq); - dxc_freq *= delta_sign; - - // If the spectrum is inverted, and the daughterboard doesn't do - // quadrature downconversion, we can fix the inversion by flipping the - // sign of the dxc_freq... (This only happens using the basic_rx board) - if (subdev_spectrum_inverted){ - inverted = not inverted; - } - if (inverted and not subdev_quadrature){ - dxc_freq = -dxc_freq; - inverted = not inverted; - } - if (subdev_is_tx){ - dxc_freq = -dxc_freq; // down conversion versus up conversion +#include <boost/format.hpp> +#include <boost/foreach.hpp> +#include <boost/lexical_cast.hpp> + +namespace uhd{ + + /*! + * Check that an element is found in a container. + * If not, throw a meaningful assertion error. + * The "what" in the error will show what is + * being set and a list of known good values. + * + * \param iterable a list of possible settings + * \param elem an element that may be in the list + * \param what a description of what is being set + * \throw assertion_error when elem not in list + */ + template<class T, class Iterable> void assert_has( + const Iterable &iterable, + const T &elem, + const std::string &what = "unknown" + ){ + if (std::has(iterable, elem)) return; + std::string possible_values = ""; + BOOST_FOREACH(T e, iterable){ + if (e != iterable.begin()[0]) possible_values += ", "; + possible_values += boost::lexical_cast<std::string>(e); + } + throw std::assert_error(str(boost::format( + "Error: %s is not a valid %s. " + "Possible values are: [%s]." + ) + % boost::lexical_cast<std::string>(elem) + % what % possible_values + )); } - dsp_freq_proxy = dxc_freq; - //freq_t actual_dxc_freq = wax::cast<freq_t>(dsp_freq_proxy); - - //return some kind of tune result tuple/struct -} - -} //namespace uhd*/ +}//namespace uhd #endif /* INCLUDED_UHD_UTILS_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index b1daf22d1..b141d67bb 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -23,6 +23,8 @@ SET(libuhd_sources device_addr.cpp gain_handler.cpp metadata.cpp + simple_device.cpp + time_spec.cpp wax.cpp transport/udp_simple.cpp transport/vrt.cpp diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp new file mode 100644 index 000000000..63a17c52d --- /dev/null +++ b/host/lib/simple_device.cpp @@ -0,0 +1,303 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#include <uhd/simple_device.hpp> +#include <uhd/device.hpp> +#include <uhd/utils.hpp> +#include <uhd/props.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/algorithm/string/trim.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <stdexcept> + +using namespace uhd; + +tune_result_t::tune_result_t(void){ + /* NOP */ +} + +/*********************************************************************** + * Tune Helper Function + **********************************************************************/ +static tune_result_t tune( + double target_freq, + double lo_offset, + wax::obj subdev, + wax::obj dxc, + bool is_tx +){ + wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; + bool subdev_quadrature = wax::cast<bool>(subdev[SUBDEV_PROP_QUADRATURE]); + bool subdev_spectrum_inverted = wax::cast<bool>(subdev[SUBDEV_PROP_SPECTRUM_INVERTED]); + wax::obj dxc_freq_proxy = dxc[std::string("freq")]; + double dxc_sample_rate = wax::cast<double>(dxc[std::string("rate")]); + + // Ask the d'board to tune as closely as it can to target_freq+lo_offset + double target_inter_freq = target_freq + lo_offset; + subdev_freq_proxy = target_inter_freq; + double actual_inter_freq = wax::cast<double>(subdev_freq_proxy); + + // Calculate the DDC setting that will downconvert the baseband from the + // daughterboard to our target frequency. + double delta_freq = target_freq - actual_inter_freq; + double delta_sign = std::signum(delta_freq); + delta_freq *= delta_sign; + delta_freq = fmod(delta_freq, dxc_sample_rate); + bool inverted = delta_freq > dxc_sample_rate/2.0; + double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); + target_dxc_freq *= delta_sign; + + // If the spectrum is inverted, and the daughterboard doesn't do + // quadrature downconversion, we can fix the inversion by flipping the + // sign of the dxc_freq... (This only happens using the basic_rx board) + if (subdev_spectrum_inverted){ + inverted = not inverted; + } + if (inverted and not subdev_quadrature){ + target_dxc_freq *= -1.0; + inverted = not inverted; + } + // down conversion versus up conversion, fight! + // your mother is ugly and your going down... + target_dxc_freq *= (is_tx)? -1.0 : +1.0; + + dxc_freq_proxy = target_dxc_freq; + double actual_dxc_freq = wax::cast<double>(dxc_freq_proxy); + + //return some kind of tune result tuple/struct + tune_result_t tune_result; + tune_result.target_inter_freq = target_inter_freq; + tune_result.actual_inter_freq = actual_inter_freq; + tune_result.target_dxc_freq = target_dxc_freq; + tune_result.actual_dxc_freq = actual_dxc_freq; + tune_result.spectrum_inverted = inverted; + return tune_result; +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static std::string trim(const std::string &in){ + return boost::algorithm::trim_copy(in); +} + +device_addr_t args_to_device_addr(const std::string &args){ + device_addr_t addr; + + //split the args at the semi-colons + std::vector<std::string> pairs; + boost::split(pairs, args, boost::is_any_of(";")); + BOOST_FOREACH(std::string pair, pairs){ + if (trim(pair) == "") continue; + + //split the key value pairs at the equals + std::vector<std::string> key_val; + boost::split(key_val, pair, boost::is_any_of("=")); + if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); + addr[trim(key_val[0])] = trim(key_val[1]); + } + + return addr; +} + +static std::vector<double> get_xx_rates(wax::obj decerps, wax::obj rate){ + std::vector<double> rates; + BOOST_FOREACH(size_t decerp, wax::cast<std::vector<size_t> >(decerps)){ + rates.push_back(wax::cast<double>(rate)/decerp); + } + return rates; +} + +/*********************************************************************** + * Simple Device Implementation + **********************************************************************/ +class simple_device_impl : public simple_device{ +public: + simple_device_impl(const device_addr_t &addr){ + _dev = device::make(addr); + _mboard = (*_dev)[DEVICE_PROP_MBOARD]; + _rx_ddc = _mboard[named_prop_t(MBOARD_PROP_RX_DSP, "ddc0")]; + _tx_duc = _mboard[named_prop_t(MBOARD_PROP_TX_DSP, "duc0")]; + _rx_subdev = _mboard[MBOARD_PROP_RX_DBOARD][DBOARD_PROP_SUBDEV]; + _tx_subdev = _mboard[MBOARD_PROP_TX_DBOARD][DBOARD_PROP_SUBDEV]; + } + + ~simple_device_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_name(void){ + return wax::cast<std::string>(_mboard[MBOARD_PROP_NAME]); + } + + /******************************************************************* + * Streaming + ******************************************************************/ + void set_streaming(bool enb){ + _rx_ddc[std::string("enabled")] = enb; + } + + bool get_streaming(void){ + return wax::cast<bool>(_rx_ddc[std::string("enabled")]); + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_rate(double rate){ + double samp_rate = wax::cast<double>(_rx_ddc[std::string("rate")]); + assert_has(get_rx_rates(), rate, "simple device rx rate"); + _rx_ddc[std::string("decim")] = size_t(samp_rate/rate); + } + + double get_rx_rate(void){ + double samp_rate = wax::cast<double>(_rx_ddc[std::string("rate")]); + size_t decim = wax::cast<size_t>(_rx_ddc[std::string("decim")]); + return samp_rate/decim; + } + + std::vector<double> get_rx_rates(void){ + return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); + } + + tune_result_t set_rx_freq(double target_freq, double lo_offset){ + return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); + } + + double get_rx_freq_min(void){ + return wax::cast<double>(_rx_subdev[SUBDEV_PROP_FREQ_MIN]); + } + + double get_rx_freq_max(void){ + return wax::cast<double>(_rx_subdev[SUBDEV_PROP_FREQ_MAX]); + } + + void set_rx_gain(float gain){ + _rx_subdev[SUBDEV_PROP_GAIN] = gain; + } + + float get_rx_gain(void){ + return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN]); + } + + float get_rx_gain_min(void){ + return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_MIN]); + } + + float get_rx_gain_max(void){ + return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_MAX]); + } + + float get_rx_gain_step(void){ + return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_STEP]); + } + + void set_rx_antenna(const std::string &ant){ + _rx_subdev[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(void){ + return wax::cast<std::string>(_rx_subdev[SUBDEV_PROP_ANTENNA]); + } + + std::vector<std::string> get_rx_antennas(void){ + return wax::cast<std::vector<std::string> >(_rx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_rate(double rate){ + double samp_rate = wax::cast<double>(_tx_duc[std::string("rate")]); + assert_has(get_tx_rates(), rate, "simple device tx rate"); + _tx_duc[std::string("interp")] = size_t(samp_rate/rate); + } + + double get_tx_rate(void){ + double samp_rate = wax::cast<double>(_tx_duc[std::string("rate")]); + size_t interp = wax::cast<size_t>(_tx_duc[std::string("interp")]); + return samp_rate/interp; + } + + std::vector<double> get_tx_rates(void){ + return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); + } + + tune_result_t set_tx_freq(double target_freq, double lo_offset){ + return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); + } + + double get_tx_freq_min(void){ + return wax::cast<double>(_tx_subdev[SUBDEV_PROP_FREQ_MIN]); + } + + double get_tx_freq_max(void){ + return wax::cast<double>(_tx_subdev[SUBDEV_PROP_FREQ_MAX]); + } + + void set_tx_gain(float gain){ + _tx_subdev[SUBDEV_PROP_GAIN] = gain; + } + + float get_tx_gain(void){ + return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN]); + } + + float get_tx_gain_min(void){ + return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_MIN]); + } + + float get_tx_gain_max(void){ + return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_MAX]); + } + + float get_tx_gain_step(void){ + return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_STEP]); + } + + void set_tx_antenna(const std::string &ant){ + _tx_subdev[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(void){ + return wax::cast<std::string>(_tx_subdev[SUBDEV_PROP_ANTENNA]); + } + + std::vector<std::string> get_tx_antennas(void){ + return wax::cast<std::vector<std::string> >(_tx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + } + +private: + device::sptr _dev; + wax::obj _mboard; + wax::obj _rx_ddc; + wax::obj _tx_duc; + wax::obj _rx_subdev; + wax::obj _tx_subdev; +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +simple_device::sptr simple_device::make(const std::string &args){ + return sptr(new simple_device_impl(args_to_device_addr(args))); +} diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp new file mode 100644 index 000000000..193441342 --- /dev/null +++ b/host/lib/time_spec.cpp @@ -0,0 +1,40 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#include <uhd/time_spec.hpp> + +using namespace uhd; + +time_spec_t::time_spec_t(void){ + secs = ~0; + ticks = ~0; +} + +time_spec_t::time_spec_t(uint32_t new_secs, uint32_t new_ticks){ + secs = new_secs; + ticks = new_ticks; +} + +static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); +static double time_tick_rate(boost::posix_time::time_duration::ticks_per_second()); + +time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ + boost::posix_time::time_duration td = time - epoch; + secs = td.total_seconds(); + double time_ticks_per_device_ticks = time_tick_rate/tick_rate; + ticks = td.fractional_seconds()/time_ticks_per_device_ticks; +} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 32c64f541..da05c3241 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -16,6 +16,7 @@ // #include <uhd/utils.hpp> +#include <boost/format.hpp> #include "usrp2_impl.hpp" #include "dboard_interface.hpp" @@ -83,8 +84,8 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _dboard_manager->get_rx_subdev_names(); return; - case DBOARD_PROP_CODEC: - throw std::runtime_error("unhandled prop in usrp2 dboard"); + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } @@ -113,8 +114,8 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _dboard_manager->get_tx_subdev_names(); return; - case DBOARD_PROP_CODEC: - throw std::runtime_error("unhandled prop in usrp2 dboard"); + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 7831b7667..cb7f58ec8 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -16,6 +16,7 @@ // #include <uhd/utils.hpp> +#include <boost/format.hpp> #include <boost/assign/list_of.hpp> #include "usrp2_impl.hpp" @@ -110,7 +111,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ prop_names_t others = boost::assign::list_of ("rate") ("decim") - ("decim_rates") + ("decims") ("freq") ("enabled") ("stream_at") @@ -131,7 +132,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ val = _ddc_decim; return; } - else if (key_name == "decim_rates"){ + else if (key_name == "decims"){ val = _allowed_decim_and_interp_rates; return; } @@ -154,10 +155,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ std::string key_name = wax::cast<std::string>(key); if (key_name == "decim"){ size_t new_decim = wax::cast<size_t>(val); - ASSERT_THROW(std::has( + assert_has( _allowed_decim_and_interp_rates, - new_decim - )); + new_decim, "usrp2 decimation" + ); _ddc_decim = new_decim; //shadow update_ddc_config(); return; @@ -244,7 +245,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ prop_names_t others = boost::assign::list_of ("rate") ("interp") - ("interp_rates") + ("interps") ("freq") ; val = others; @@ -263,7 +264,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ val = _duc_interp; return; } - else if (key_name == "interp_rates"){ + else if (key_name == "interps"){ val = _allowed_decim_and_interp_rates; return; } @@ -282,10 +283,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ std::string key_name = wax::cast<std::string>(key); if (key_name == "interp"){ size_t new_interp = wax::cast<size_t>(val); - ASSERT_THROW(std::has( + assert_has( _allowed_decim_and_interp_rates, - new_interp - )); + new_interp, "usrp2 interpolation" + ); _duc_interp = new_interp; //shadow update_duc_config(); return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 8e4b2ba35..10c1ef8cf 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -91,6 +91,9 @@ typedef enum{ USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO, USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE, + USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO, + USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE, + USRP2_CTRL_ID_PEACE_OUT } usrp2_ctrl_id_t; @@ -186,6 +189,11 @@ typedef struct{ uint32_t interp; uint32_t scale_iq; } duc_args; + struct { + uint32_t secs; + uint32_t ticks; + uint8_t now; + } time_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 8e682a675..47e22c473 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -28,6 +28,10 @@ void usrp2_impl::mboard_init(void){ boost::bind(&usrp2_impl::mboard_get, this, _1, _2), boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); + + //set the time on the usrp2 as close as possible to the system utc time + boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time()); + set_time_spec(time_spec_t(now, get_master_clock_freq()), true); } void usrp2_impl::init_clock_config(void){ @@ -64,6 +68,19 @@ void usrp2_impl::update_clock_config(void){ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_NEW_CLOCK_CONFIG_DUDE); } +void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO); + out_data.data.time_args.secs = htonl(time_spec.secs); + out_data.data.time_args.ticks = htonl(time_spec.ticks); + out_data.data.time_args.now = (now)? 1 : 0; + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE); +} + /*********************************************************************** * MBoard Get Properties **********************************************************************/ @@ -157,7 +174,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_PPS_SOURCE:{ std::string name = wax::cast<std::string>(val); - ASSERT_THROW(_pps_source_dict.has_key(name)); + assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source"); _pps_source = name; //shadow update_clock_config(); } @@ -165,7 +182,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_PPS_POLARITY:{ std::string name = wax::cast<std::string>(val); - ASSERT_THROW(_pps_polarity_dict.has_key(name)); + assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity"); _pps_polarity = name; //shadow update_clock_config(); } @@ -173,12 +190,22 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_REF_SOURCE:{ std::string name = wax::cast<std::string>(val); - ASSERT_THROW(_ref_source_dict.has_key(name)); + assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source"); _ref_source = name; //shadow update_clock_config(); } return; + case MBOARD_PROP_TIME_NOW:{ + set_time_spec(wax::cast<time_spec_t>(val), true); + return; + } + + case MBOARD_PROP_TIME_NEXT_PPS:{ + set_time_spec(wax::cast<time_spec_t>(val), false); + return; + } + case MBOARD_PROP_NAME: case MBOARD_PROP_OTHERS: case MBOARD_PROP_CLOCK_RATE: @@ -192,8 +219,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_TX_DBOARD_NAMES: case MBOARD_PROP_PPS_SOURCE_NAMES: case MBOARD_PROP_REF_SOURCE_NAMES: - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_NEXT_PPS: throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard"); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f4e6054bd..fc713c2bf 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -135,6 +135,7 @@ private: std::string _pps_source, _pps_polarity, _ref_source; void init_clock_config(void); void update_clock_config(void); + void set_time_spec(const uhd::time_spec_t &time_spec, bool now); //mappings from clock config strings to over the wire enums uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict; |