diff options
author | root <root@usrp1-e.(none)> | 2010-03-23 13:35:36 +0000 |
---|---|---|
committer | root <root@usrp1-e.(none)> | 2010-03-23 13:35:36 +0000 |
commit | c329da8f953c3981e23791c688f350b27541554a (patch) | |
tree | 3447dd657bf7221e3b4b1a9147ce1bd2ffa430b9 /host/lib/usrp/usrp2 | |
parent | f6ec1e45117f5794facd1cd8e11cbfacabdeb166 (diff) | |
parent | 09a21dd6d4bc5b7f032e07cfabcba9f55d25b0f6 (diff) | |
download | uhd-c329da8f953c3981e23791c688f350b27541554a.tar.gz uhd-c329da8f953c3981e23791c688f350b27541554a.tar.bz2 uhd-c329da8f953c3981e23791c688f350b27541554a.zip |
Merge branch 'u1e_uhd' of git@ettus.sourcerepo.com:ettus/uhd into u1e_uhd
Diffstat (limited to 'host/lib/usrp/usrp2')
-rw-r--r-- | host/lib/usrp/usrp2/dboard_impl.cpp | 99 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dboard_interface.cpp | 59 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dboard_interface.hpp | 63 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dsp_impl.cpp | 92 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 108 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 258 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 187 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 117 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 104 |
9 files changed, 761 insertions, 326 deletions
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 32c64f541..66e02d469 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -16,8 +16,8 @@ // #include <uhd/utils.hpp> +#include <boost/format.hpp> #include "usrp2_impl.hpp" -#include "dboard_interface.hpp" using namespace uhd; using namespace uhd::usrp; @@ -31,35 +31,68 @@ void usrp2_impl::dboard_init(void){ out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO); usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE); - std::cout << boost::format("rx id 0x%.2x, tx id 0x%.2x") - % ntohs(in_data.data.dboard_ids.rx_id) - % ntohs(in_data.data.dboard_ids.tx_id) << std::endl; - //extract the dboard ids an convert them to enums - dboard_id_t rx_dboard_id = static_cast<dboard_id_t>( - ntohs(in_data.data.dboard_ids.rx_id) - ); - dboard_id_t tx_dboard_id = static_cast<dboard_id_t>( - ntohs(in_data.data.dboard_ids.tx_id) - ); + //extract the dboard ids an convert them + dboard_id_t rx_dboard_id = ntohs(in_data.data.dboard_ids.rx_id); + dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id); //create a new dboard interface and manager dboard_interface::sptr _dboard_interface( - new usrp2_dboard_interface(this) + make_usrp2_dboard_interface(this) ); - dboard_manager::sptr _dboard_manager = dboard_manager::make( + _dboard_manager = dboard_manager::make( rx_dboard_id, tx_dboard_id, _dboard_interface ); //load dboards - _rx_dboards[""] = wax_obj_proxy( + _rx_dboards[""] = wax_obj_proxy::make( boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2), boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2) ); - _tx_dboards[""] = wax_obj_proxy( + _tx_dboards[""] = wax_obj_proxy::make( boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2), boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2) ); + + //init the subdevs in use (use the first subdevice) + _rx_subdevs_in_use = prop_names_t(1, _dboard_manager->get_rx_subdev_names().at(0)); + _tx_subdevs_in_use = prop_names_t(1, _dboard_manager->get_tx_subdev_names().at(0)); + update_mux_config(); +} + +void usrp2_impl::update_mux_config(void){ + //calculate the rx mux + boost::uint32_t rx_mux = 0; + ASSERT_THROW(_rx_subdevs_in_use.size() == 1); + wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0)); + std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl; + if (rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>()){ + rx_mux = (0x01 << 2) | (0x00 << 0); //Q=ADC1, I=ADC0 + }else{ + rx_mux = 0x00; //ADC0 + } + if (rx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){ + rx_mux = (((rx_mux >> 0) & 0x3) << 2) | (((rx_mux >> 2) & 0x3) << 0); + } + + //calculate the tx mux + boost::uint32_t tx_mux = 0x10; + ASSERT_THROW(_tx_subdevs_in_use.size() == 1); + wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0)); + std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl; + if (tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){ + tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0); + } + + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_UPDATE_THOSE_MUX_SETTINGS_BRO); + out_data.data.mux_args.rx_mux = htonl(rx_mux); + out_data.data.mux_args.tx_mux = htonl(tx_mux); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_UPDATED_THE_MUX_SETTINGS_DUDE); } /*********************************************************************** @@ -70,7 +103,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast<dboard_prop_t>(key)){ + switch(key.as<dboard_prop_t>()){ case DBOARD_PROP_NAME: val = std::string("usrp2 dboard (rx unit)"); return; @@ -83,12 +116,22 @@ 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_USED_SUBDEVS: + val = _rx_subdevs_in_use; + return; + + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } -void usrp2_impl::rx_dboard_set(const wax::obj &, const wax::obj &){ +void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ + if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){ + _rx_subdevs_in_use = val.as<prop_names_t>(); + update_mux_config(); //if the val is bad, this will throw + return; + } + throw std::runtime_error("Cannot set on usrp2 dboard"); } @@ -100,7 +143,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast<dboard_prop_t>(key)){ + switch(key.as<dboard_prop_t>()){ case DBOARD_PROP_NAME: val = std::string("usrp2 dboard (tx unit)"); return; @@ -113,11 +156,21 @@ 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_USED_SUBDEVS: + val = _tx_subdevs_in_use; + return; + + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } -void usrp2_impl::tx_dboard_set(const wax::obj &, const wax::obj &){ +void usrp2_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ + if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){ + _tx_subdevs_in_use = val.as<prop_names_t>(); + update_mux_config(); //if the val is bad, this will throw + return; + } + throw std::runtime_error("Cannot set on usrp2 dboard"); } diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp index f12b101f3..d20465147 100644 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ b/host/lib/usrp/usrp2/dboard_interface.cpp @@ -16,11 +16,48 @@ // #include <uhd/utils.hpp> -#include "dboard_interface.hpp" #include "usrp2_impl.hpp" using namespace uhd::usrp; +class usrp2_dboard_interface : public dboard_interface{ +public: + usrp2_dboard_interface(usrp2_impl *impl); + ~usrp2_dboard_interface(void); + + void write_aux_dac(unit_type_t, int, int); + int read_aux_adc(unit_type_t, int); + + void set_atr_reg(gpio_bank_t, boost::uint16_t, boost::uint16_t, boost::uint16_t); + void set_gpio_ddr(gpio_bank_t, boost::uint16_t, boost::uint16_t); + void write_gpio(gpio_bank_t, boost::uint16_t, boost::uint16_t); + boost::uint16_t read_gpio(gpio_bank_t); + + void write_i2c(int, const byte_vector_t &); + byte_vector_t read_i2c(int, size_t); + + double get_rx_clock_rate(void); + double get_tx_clock_rate(void); + +private: + byte_vector_t transact_spi( + spi_dev_t dev, + spi_latch_t latch, + spi_push_t push, + const byte_vector_t &buf, + bool readback + ); + + usrp2_impl *_impl; +}; + +/*********************************************************************** + * Make Function + **********************************************************************/ +dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl){ + return dboard_interface::sptr(new usrp2_dboard_interface(impl)); +} + /*********************************************************************** * Structors **********************************************************************/ @@ -52,7 +89,7 @@ double usrp2_dboard_interface::get_tx_clock_rate(void){ * \param bank the dboard interface gpio bank enum * \return an over the wire representation */ -static uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){ +static boost::uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){ switch(bank){ case uhd::usrp::dboard_interface::GPIO_TX_BANK: return USRP2_DIR_TX; case uhd::usrp::dboard_interface::GPIO_RX_BANK: return USRP2_DIR_RX; @@ -60,7 +97,7 @@ static uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){ throw std::invalid_argument("unknown gpio bank type"); } -void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint16_t mask){ +void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_USE_THESE_GPIO_DDR_SETTINGS_BRO); @@ -73,7 +110,7 @@ void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_GPIO_DDR_SETTINGS_DUDE); } -void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, uint16_t value, uint16_t mask){ +void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_SET_YOUR_GPIO_PIN_OUTS_BRO); @@ -86,7 +123,7 @@ void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, uint16_t value, uint16 ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_I_SET_THE_GPIO_PIN_OUTS_DUDE); } -uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ +boost::uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_GPIO_PIN_VALS_BRO); @@ -98,7 +135,7 @@ uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){ return ntohs(in_data.data.gpio_config.value); } -void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, uint16_t tx_value, uint16_t rx_value, uint16_t mask){ +void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, boost::uint16_t tx_value, boost::uint16_t rx_value, boost::uint16_t mask){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_USE_THESE_ATR_SETTINGS_BRO); @@ -121,7 +158,7 @@ void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, uint16_t tx_value, ui * \param dev the dboard interface spi dev enum * \return an over the wire representation */ -static uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ +static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ switch(dev){ case uhd::usrp::dboard_interface::SPI_TX_DEV: return USRP2_DIR_TX; case uhd::usrp::dboard_interface::SPI_RX_DEV: return USRP2_DIR_RX; @@ -135,7 +172,7 @@ static uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ * \param latch the dboard interface spi latch enum * \return an over the wire representation */ -static uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){ +static boost::uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){ switch(latch){ case uhd::usrp::dboard_interface::SPI_LATCH_RISE: return USRP2_CLK_EDGE_RISE; case uhd::usrp::dboard_interface::SPI_LATCH_FALL: return USRP2_CLK_EDGE_FALL; @@ -149,7 +186,7 @@ static uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){ * \param push the dboard interface spi push enum * \return an over the wire representation */ -static uint8_t spi_push_to_otw(dboard_interface::spi_push_t push){ +static boost::uint8_t spi_push_to_otw(dboard_interface::spi_push_t push){ switch(push){ case uhd::usrp::dboard_interface::SPI_PUSH_RISE: return USRP2_CLK_EDGE_RISE; case uhd::usrp::dboard_interface::SPI_PUSH_FALL: return USRP2_CLK_EDGE_FALL; @@ -249,7 +286,7 @@ dboard_interface::byte_vector_t usrp2_dboard_interface::read_i2c(int i2c_addr, s * \param unit the dboard interface unit type enum * \return an over the wire representation */ -static uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ +static boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ switch(unit){ case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX; case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX; @@ -263,7 +300,7 @@ void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, i out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO); out_data.data.aux_args.dir = spi_dev_to_otw(unit); out_data.data.aux_args.which = which; - out_data.data.aux_args.dir = htonl(value); + out_data.data.aux_args.value = htonl(value); //send and recv usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/dboard_interface.hpp b/host/lib/usrp/usrp2/dboard_interface.hpp deleted file mode 100644 index a06359e5e..000000000 --- a/host/lib/usrp/usrp2/dboard_interface.hpp +++ /dev/null @@ -1,63 +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 <http://www.gnu.org/licenses/>. -// - -#include <uhd/usrp/dboard_interface.hpp> - -#ifndef INCLUDED_DBOARD_INTERFACE_HPP -#define INCLUDED_DBOARD_INTERFACE_HPP - -class usrp2_impl; //dummy class declaration - -class usrp2_dboard_interface : public uhd::usrp::dboard_interface{ -public: - usrp2_dboard_interface(usrp2_impl *impl); - - ~usrp2_dboard_interface(void); - - void write_aux_dac(unit_type_t, int, int); - - int read_aux_adc(unit_type_t, int); - - void set_atr_reg(gpio_bank_t, uint16_t, uint16_t, uint16_t); - - void set_gpio_ddr(gpio_bank_t, uint16_t, uint16_t); - - void write_gpio(gpio_bank_t, uint16_t, uint16_t); - - uint16_t read_gpio(gpio_bank_t); - - void write_i2c(int, const byte_vector_t &); - - byte_vector_t read_i2c(int, size_t); - - double get_rx_clock_rate(void); - - double get_tx_clock_rate(void); - -private: - byte_vector_t transact_spi( - spi_dev_t dev, - spi_latch_t latch, - spi_push_t push, - const byte_vector_t &buf, - bool readback - ); - - usrp2_impl *_impl; -}; - -#endif /* INCLUDED_DBOARD_INTERFACE_HPP */ diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 22c00d99a..34cce0afb 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -16,19 +16,30 @@ // #include <uhd/utils.hpp> +#include <boost/format.hpp> #include <boost/assign/list_of.hpp> +#include <boost/math/special_functions/round.hpp> #include "usrp2_impl.hpp" using namespace uhd; +static const size_t default_decim = 16; +static const size_t default_interp = 16; + +#define rint boost::math::iround + +template <class T> T log2(T num){ + return std::log(num)/std::log(T(2)); +} + /*********************************************************************** * DDC Helper Methods **********************************************************************/ -static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){ - double scale_factor = pow(2.0, 32); +static boost::uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){ + double scale_factor = std::pow(2.0, 32); //calculate the freq register word - uint32_t freq_word = rint((freq / clock_freq) * scale_factor); + boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor); //update the actual frequency freq = (double(freq_word) / scale_factor) * clock_freq; @@ -36,15 +47,19 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t return freq_word; } +static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t q){ + return (boost::uint16_t(i) << 16) | (boost::uint16_t(q) << 0); +} + void usrp2_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict - _rx_dsps["ddc0"] = wax_obj_proxy( + _rx_dsps["ddc0"] = wax_obj_proxy::make( boost::bind(&usrp2_impl::ddc_get, this, _1, _2), boost::bind(&usrp2_impl::ddc_set, this, _1, _2) ); //initial config and update - _ddc_decim = 16; + _ddc_decim = default_decim; _ddc_freq = 0; update_ddc_config(); @@ -61,6 +76,10 @@ void usrp2_impl::update_ddc_config(void){ calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq()) ); out_data.data.ddc_args.decim = htonl(_ddc_decim); + static const boost::int16_t default_rx_scale_iq = 1024; + out_data.data.ddc_args.scale_iq = htonl( + calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -74,6 +93,7 @@ void usrp2_impl::update_ddc_enabled(void){ out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); + out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -89,7 +109,7 @@ void usrp2_impl::update_ddc_enabled(void){ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ //handle the case where the key is an expected dsp property if (key.type() == typeid(dsp_prop_t)){ - switch(wax::cast<dsp_prop_t>(key)){ + switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: val = std::string("usrp2 ddc0"); return; @@ -98,7 +118,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") @@ -110,7 +130,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ } //handle string-based properties specific to this dsp - std::string key_name = wax::cast<std::string>(key); + std::string key_name = key.as<std::string>(); if (key_name == "rate"){ val = get_master_clock_freq(); return; @@ -119,7 +139,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; } @@ -139,20 +159,19 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ //handle string-based properties specific to this dsp - std::string key_name = wax::cast<std::string>(key); + std::string key_name = key.as<std::string>(); if (key_name == "decim"){ - size_t new_decim = wax::cast<size_t>(val); - ASSERT_THROW(std::has( - _allowed_decim_and_interp_rates.begin(), - _allowed_decim_and_interp_rates.end(), - new_decim - )); + size_t new_decim = val.as<size_t>(); + assert_has( + _allowed_decim_and_interp_rates, + new_decim, "usrp2 decimation" + ); _ddc_decim = new_decim; //shadow update_ddc_config(); return; } else if (key_name == "freq"){ - freq_t new_freq = wax::cast<freq_t>(val); + freq_t new_freq = val.as<freq_t>(); ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); _ddc_freq = new_freq; //shadow @@ -160,13 +179,13 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ return; } else if (key_name == "enabled"){ - bool new_enabled = wax::cast<bool>(val); + bool new_enabled = val.as<bool>(); _ddc_enabled = new_enabled; //shadow update_ddc_enabled(); return; } else if (key_name == "stream_at"){ - time_spec_t new_stream_at = wax::cast<time_spec_t>(val); + time_spec_t new_stream_at = val.as<time_spec_t>(); _ddc_stream_at = new_stream_at; //shadow //update_ddc_enabled(); //dont update from here return; @@ -182,13 +201,13 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ **********************************************************************/ void usrp2_impl::init_duc_config(void){ //create the duc in the tx dsp dict - _tx_dsps["duc0"] = wax_obj_proxy( + _tx_dsps["duc0"] = wax_obj_proxy::make( boost::bind(&usrp2_impl::duc_get, this, _1, _2), boost::bind(&usrp2_impl::duc_set, this, _1, _2) ); //initial config and update - _duc_interp = 16; + _duc_interp = default_interp; _duc_freq = 0; update_duc_config(); } @@ -199,8 +218,8 @@ void usrp2_impl::update_duc_config(void){ while(tmp_interp > 128) tmp_interp /= 2; // Calculate closest multiplier constant to reverse gain absent scale multipliers - size_t interp_cubed = pow(tmp_interp, 3); - size_t scale = rint((4096*pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed)); + double interp_cubed = std::pow(double(tmp_interp), 3); + boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed)); //setup the out data usrp2_ctrl_data_t out_data; @@ -209,7 +228,9 @@ void usrp2_impl::update_duc_config(void){ calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq()) ); out_data.data.duc_args.interp = htonl(_duc_interp); - out_data.data.duc_args.scale_iq = htonl(scale); + out_data.data.duc_args.scale_iq = htonl( + calculate_iq_scale_word(scale, scale) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -222,7 +243,7 @@ void usrp2_impl::update_duc_config(void){ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ //handle the case where the key is an expected dsp property if (key.type() == typeid(dsp_prop_t)){ - switch(wax::cast<dsp_prop_t>(key)){ + switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: val = std::string("usrp2 duc0"); return; @@ -231,7 +252,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; @@ -241,7 +262,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ } //handle string-based properties specific to this dsp - std::string key_name = wax::cast<std::string>(key); + std::string key_name = key.as<std::string>(); if (key_name == "rate"){ val = get_master_clock_freq(); return; @@ -250,7 +271,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; } @@ -266,20 +287,19 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ //handle string-based properties specific to this dsp - std::string key_name = wax::cast<std::string>(key); + std::string key_name = key.as<std::string>(); if (key_name == "interp"){ - size_t new_interp = wax::cast<size_t>(val); - ASSERT_THROW(std::has( - _allowed_decim_and_interp_rates.begin(), - _allowed_decim_and_interp_rates.end(), - new_interp - )); + size_t new_interp = val.as<size_t>(); + assert_has( + _allowed_decim_and_interp_rates, + new_interp, "usrp2 interpolation" + ); _duc_interp = new_interp; //shadow update_duc_config(); return; } else if (key_name == "freq"){ - freq_t new_freq = wax::cast<freq_t>(val); + freq_t new_freq = val.as<freq_t>(); ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); _duc_freq = new_freq; //shadow diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 3def8ddaa..7fcae6fb2 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -24,9 +24,18 @@ * Therefore, this header may only contain valid C code. */ #ifdef __cplusplus +#include <boost/cstdint.hpp> +#define _SINS_ boost:://stdint namespace when in c++ extern "C" { +#else +#include <stdint.h> +#define _SINS_ #endif +// size of the vrt header and trailer to the host +#define USRP2_HOST_RX_VRT_HEADER_WORDS32 5 +#define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present + // udp ports for the usrp2 communication // Dynamic and/or private ports: 49152-65535 #define USRP2_UDP_CTRL_PORT 49152 @@ -87,6 +96,12 @@ 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_UPDATE_THOSE_MUX_SETTINGS_BRO, + USRP2_CTRL_ID_UPDATED_THE_MUX_SETTINGS_DUDE, + USRP2_CTRL_ID_PEACE_OUT } usrp2_ctrl_id_t; @@ -118,68 +133,79 @@ typedef enum{ } usrp2_clk_edge_t; typedef struct{ - uint32_t id; - uint32_t seq; + _SINS_ uint32_t id; + _SINS_ uint32_t seq; union{ - uint32_t ip_addr; - uint8_t mac_addr[6]; + _SINS_ uint32_t ip_addr; + _SINS_ uint8_t mac_addr[6]; struct { - uint16_t rx_id; - uint16_t tx_id; + _SINS_ uint16_t rx_id; + _SINS_ uint16_t tx_id; } dboard_ids; struct { - uint8_t pps_source; - uint8_t pps_polarity; - uint8_t ref_source; - uint8_t _pad; + _SINS_ uint8_t pps_source; + _SINS_ uint8_t pps_polarity; + _SINS_ uint8_t ref_source; + _SINS_ uint8_t _pad; } clock_config; struct { - uint8_t bank; - uint8_t _pad[3]; - uint16_t value; - uint16_t mask; + _SINS_ uint8_t bank; + _SINS_ uint8_t _pad[3]; + _SINS_ uint16_t value; + _SINS_ uint16_t mask; } gpio_config; struct { - uint8_t bank; - uint8_t _pad[3]; - uint16_t tx_value; - uint16_t rx_value; - uint16_t mask; + _SINS_ uint8_t bank; + _SINS_ uint8_t _pad[3]; + _SINS_ uint16_t tx_value; + _SINS_ uint16_t rx_value; + _SINS_ uint16_t mask; } atr_config; struct { - uint8_t dev; - uint8_t latch; - uint8_t push; - uint8_t readback; - uint8_t bytes; - uint8_t data[sizeof(uint32_t)]; + _SINS_ uint8_t dev; + _SINS_ uint8_t latch; + _SINS_ uint8_t push; + _SINS_ uint8_t readback; + _SINS_ uint8_t bytes; + _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; } spi_args; struct { - uint8_t addr; - uint8_t bytes; - uint8_t data[sizeof(uint32_t)]; + _SINS_ uint8_t addr; + _SINS_ uint8_t bytes; + _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; } i2c_args; struct { - uint8_t dir; - uint8_t which; - uint8_t _pad[2]; - uint32_t value; + _SINS_ uint8_t dir; + _SINS_ uint8_t which; + _SINS_ uint8_t _pad[2]; + _SINS_ uint32_t value; } aux_args; struct { - uint32_t freq_word; - uint32_t decim; + _SINS_ uint32_t freq_word; + _SINS_ uint32_t decim; + _SINS_ uint32_t scale_iq; } ddc_args; struct { - uint8_t enabled; - uint8_t _pad[3]; - uint32_t secs; - uint32_t ticks; + _SINS_ uint8_t enabled; + _SINS_ uint8_t _pad[3]; + _SINS_ uint32_t secs; + _SINS_ uint32_t ticks; + _SINS_ uint32_t samples; } streaming; struct { - uint32_t freq_word; - uint32_t interp; - uint32_t scale_iq; + _SINS_ uint32_t freq_word; + _SINS_ uint32_t interp; + _SINS_ uint32_t scale_iq; } duc_args; + struct { + _SINS_ uint32_t secs; + _SINS_ uint32_t ticks; + _SINS_ uint8_t now; + } time_args; + struct { + _SINS_ uint32_t rx_mux; + _SINS_ uint32_t tx_mux; + } mux_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp new file mode 100644 index 000000000..dc8eea243 --- /dev/null +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -0,0 +1,258 @@ +// +// 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 <complex> +#include <algorithm> +#include <boost/format.hpp> +#include "usrp2_impl.hpp" + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; +namespace asio = boost::asio; + +/*********************************************************************** + * Constants + **********************************************************************/ +typedef std::complex<float> fc32_t; +typedef std::complex<boost::int16_t> sc16_t; + +static const float shorts_per_float = float(1 << 15); +static const float floats_per_short = float(1.0/shorts_per_float); + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +void usrp2_impl::io_init(void){ + //initially empty copy buffer + _rx_copy_buff = asio::buffer("", 0); + + //send a small data packet so the usrp2 knows the udp source port + boost::uint32_t zero_data = 0; + _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data))); +} + +#define unrolled_loop(__i, __len, __inst) {\ + size_t __i = 0; \ + while(__i < (__len & ~0x7)){ \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + } \ + while(__i < __len){ \ + __inst; __i++;\ + } \ +} + +// set a boolean flag that indicates the endianess +#ifdef HAVE_BIG_ENDIAN +static const bool is_big_endian = true; +#else +static const bool is_big_endian = false; +#endif + +static inline void host_floats_to_usrp2_items( + boost::uint32_t *usrp2_items, + const fc32_t *host_floats, + size_t num_samps +){ + unrolled_loop(i, num_samps,{ + boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); + boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); + usrp2_items[i] = htonl((real << 16) | (imag << 0)); + }); +} + +static inline void usrp2_items_to_host_floats( + fc32_t *host_floats, + const boost::uint32_t *usrp2_items, + size_t num_samps +){ + unrolled_loop(i, num_samps,{ + boost::uint32_t item = ntohl(usrp2_items[i]); + boost::int16_t real = boost::uint16_t(item >> 16); + boost::int16_t imag = boost::uint16_t(item >> 0); + host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); + }); +} + +static inline void host_items_to_usrp2_items( + boost::uint32_t *usrp2_items, + const boost::uint32_t *host_items, + size_t num_samps +){ + if (is_big_endian){ + std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); + } + else{ + unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i])); + } +} + +static inline void usrp2_items_to_host_items( + boost::uint32_t *host_items, + const boost::uint32_t *usrp2_items, + size_t num_samps +){ + if (is_big_endian){ + std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); + } + else{ + unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); + } +} + +/*********************************************************************** + * Receive Raw Data + **********************************************************************/ +void usrp2_impl::recv_raw(rx_metadata_t &metadata){ + //do a receive + _rx_smart_buff = _data_transport->recv(); + + //unpack the vrt header + size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(boost::uint32_t); + if (num_packet_words32 == 0){ + _rx_copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = asio::buffer_cast<const boost::uint32_t *>(_rx_smart_buff->get()); + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + try{ + vrt::unpack( + metadata, //output + vrt_hdr, //input + num_header_words32_out, //output + num_payload_words32_out, //output + num_packet_words32, //input + packet_count_out //output + ); + }catch(const std::exception &e){ + std::cerr << "bad vrt header: " << e.what() << std::endl; + _rx_copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } + + //handle the packet count / sequence number + size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; + if (packet_count_out != expected_packet_count){ + std::cerr << "S" << (packet_count_out - expected_packet_count)%16; + } + _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16; + + //setup the rx buffer to point to the data + _rx_copy_buff = asio::buffer( + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(boost::uint32_t) + ); +} + +/*********************************************************************** + * Send Data + **********************************************************************/ +size_t usrp2_impl::send( + const asio::const_buffer &buff, + const tx_metadata_t &metadata, + const std::string &type +){ + boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; + boost::uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data + size_t num_samps = _max_tx_samples_per_packet; + + //calculate the number of samples to be copied + //and copy the samples into the send buffer + if (type == "32fc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); + } + else if (type == "16sc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); + } + + boost::uint32_t vrt_hdr[vrt::max_header_words32]; + size_t num_header_words32, num_packet_words32; + size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++; + + //pack metadata into a vrt header + vrt::pack( + metadata, //input + vrt_hdr, //output + num_header_words32, //output + num_samps, //input + num_packet_words32, //output + packet_count //input + ); + + //copy in the vrt header (yes we left space) + items -= num_header_words32; + std::memcpy(items, vrt_hdr, num_header_words32*sizeof(boost::uint32_t)); + + //send and return number of samples + _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(boost::uint32_t))); + return num_samps; +} + +/*********************************************************************** + * Receive Data + **********************************************************************/ +size_t usrp2_impl::recv( + const asio::mutable_buffer &buff, + rx_metadata_t &metadata, + const std::string &type +){ + //perform a receive if no rx data is waiting to be copied + if (asio::buffer_size(_rx_copy_buff) == 0){ + recv_raw(metadata); + } + //otherwise flag the metadata to show that is is a fragment + else{ + metadata = rx_metadata_t(); + metadata.is_fragment = true; + } + + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff); + if (bytes_to_copy == 0) return 0; //nothing to receive + size_t num_samps = bytes_to_copy/sizeof(boost::uint32_t); + const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff); + + //calculate the number of samples to be copied + //and copy the samples from the recv buffer + if (type == "32fc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps); + } + else if (type == "16sc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); + } + + //update the rx copy buffer to reflect the bytes copied + _rx_copy_buff = asio::buffer( + items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t) + ); + + return num_samps; +} diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index cc73b229c..cbca8eec7 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -24,28 +24,38 @@ using namespace uhd; * Helper Methods **********************************************************************/ void usrp2_impl::mboard_init(void){ - _mboards[""] = wax_obj_proxy( + _mboards[""] = wax_obj_proxy::make( 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){ + //init the ref source clock config + _ref_source_dict = boost::assign::map_list_of + ("int", USRP2_REF_SOURCE_INT) + ("sma", USRP2_REF_SOURCE_SMA) + ("mimo", USRP2_REF_SOURCE_MIMO) + ; + _clock_config.ref_source = "int"; + //init the pps source clock config - _pps_source_dict["sma"] = USRP2_PPS_SOURCE_SMA; - _pps_source_dict["mimo"] = USRP2_PPS_SOURCE_MIMO; - _pps_source = "sma"; + _pps_source_dict = boost::assign::map_list_of + ("sma", USRP2_PPS_SOURCE_SMA) + ("mimo", USRP2_PPS_SOURCE_MIMO) + ; + _clock_config.pps_source = "sma"; //init the pps polarity clock config - _pps_polarity_dict["pos"] = USRP2_PPS_POLARITY_POS; - _pps_polarity_dict["neg"] = USRP2_PPS_POLARITY_NEG; - _pps_polarity = "neg"; - - //init the ref source clock config - _ref_source_dict["int"] = USRP2_REF_SOURCE_INT; - _ref_source_dict["sma"] = USRP2_REF_SOURCE_SMA; - _ref_source_dict["mimo"] = USRP2_REF_SOURCE_MIMO; - _ref_source = "int"; + _pps_polarity_dict = boost::assign::map_list_of + (clock_config_t::POLARITY_POS, USRP2_PPS_POLARITY_POS) + (clock_config_t::POLARITY_NEG, USRP2_PPS_POLARITY_NEG) + ; + _clock_config.pps_polarity = clock_config_t::POLARITY_NEG; //update the clock config (sends a control packet) update_clock_config(); @@ -55,15 +65,28 @@ void usrp2_impl::update_clock_config(void){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_HERES_A_NEW_CLOCK_CONFIG_BRO); - out_data.data.clock_config.pps_source = _pps_source_dict [_pps_source]; - out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_pps_polarity]; - out_data.data.clock_config.ref_source = _ref_source_dict [_ref_source]; + out_data.data.clock_config.ref_source = _ref_source_dict [_clock_config.ref_source]; + out_data.data.clock_config.pps_source = _pps_source_dict [_clock_config.pps_source]; + out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_clock_config.pps_polarity]; //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); 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 **********************************************************************/ @@ -71,18 +94,55 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); + //handle the other props + if (key.type() == typeid(std::string)){ + if (key.as<std::string>() == "mac-addr"){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); + + //extract the address + val = reinterpret_cast<mac_addr_t*>(in_data.data.mac_addr)->to_string(); + return; + } + + if (key.as<std::string>() == "ip-addr"){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); + + //extract the address + val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string(); + return; + } + } + //handle the get request conditioned on the key - switch(wax::cast<mboard_prop_t>(key)){ + switch(key.as<mboard_prop_t>()){ case MBOARD_PROP_NAME: val = std::string("usrp2 mboard"); return; - case MBOARD_PROP_OTHERS: - val = prop_names_t(); //empty other props + case MBOARD_PROP_OTHERS:{ + prop_names_t others = boost::assign::list_of + ("mac-addr") + ("ip-addr") + ; + val = others; + } return; case MBOARD_PROP_RX_DBOARD: - val = _rx_dboards[name].get_link(); + ASSERT_THROW(_rx_dboards.has_key(name)); + val = _rx_dboards[name]->get_link(); return; case MBOARD_PROP_RX_DBOARD_NAMES: @@ -90,25 +150,21 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_TX_DBOARD: - val = _tx_dboards[name].get_link(); + ASSERT_THROW(_tx_dboards.has_key(name)); + val = _tx_dboards[name]->get_link(); return; case MBOARD_PROP_TX_DBOARD_NAMES: val = prop_names_t(_tx_dboards.get_keys()); return; - case MBOARD_PROP_MTU: - // FIXME we dont know the real MTU... - // give them something to fragment about - val = size_t(1500); - return; - case MBOARD_PROP_CLOCK_RATE: val = freq_t(get_master_clock_freq()); return; case MBOARD_PROP_RX_DSP: - val = _rx_dsps[name].get_link(); + ASSERT_THROW(_rx_dsps.has_key(name)); + val = _rx_dsps[name]->get_link(); return; case MBOARD_PROP_RX_DSP_NAMES: @@ -116,29 +172,22 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_TX_DSP: - val = _tx_dsps[name].get_link(); + ASSERT_THROW(_tx_dsps.has_key(name)); + val = _tx_dsps[name]->get_link(); return; case MBOARD_PROP_TX_DSP_NAMES: val = prop_names_t(_tx_dsps.get_keys()); return; - case MBOARD_PROP_PPS_SOURCE: - val = _pps_source; + case MBOARD_PROP_CLOCK_CONFIG: + val = _clock_config; return; case MBOARD_PROP_PPS_SOURCE_NAMES: val = prop_names_t(_pps_source_dict.get_keys()); return; - case MBOARD_PROP_PPS_POLARITY: - val = _pps_polarity; - return; - - case MBOARD_PROP_REF_SOURCE: - val = _ref_source; - return; - case MBOARD_PROP_REF_SOURCE_NAMES: val = prop_names_t(_ref_source_dict.get_keys()); return; @@ -154,36 +203,58 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ * MBoard Set Properties **********************************************************************/ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ + //handle the other props + if (key.type() == typeid(std::string)){ + if (key.as<std::string>() == "mac-addr"){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO); + mac_addr_t mac_addr(val.as<std::string>()); + std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t)); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); + return; + } + + if (key.as<std::string>() == "ip-addr"){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO); + out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_ulong()); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); + return; + } + } + //handle the get request conditioned on the key - switch(wax::cast<mboard_prop_t>(key)){ + switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_PPS_SOURCE:{ - std::string name = wax::cast<std::string>(val); - ASSERT_THROW(_pps_source_dict.has_key(name)); - _pps_source = name; //shadow + case MBOARD_PROP_CLOCK_CONFIG:{ + clock_config_t clock_config = val.as<clock_config_t>(); + assert_has(_pps_source_dict.get_keys(), clock_config.pps_source, "usrp2 pps source"); + assert_has(_ref_source_dict.get_keys(), clock_config.ref_source, "usrp2 ref source"); + _clock_config = clock_config; //shadow update_clock_config(); } return; - case MBOARD_PROP_PPS_POLARITY:{ - std::string name = wax::cast<std::string>(val); - ASSERT_THROW(_pps_polarity_dict.has_key(name)); - _pps_polarity = name; //shadow - update_clock_config(); - } + case MBOARD_PROP_TIME_NOW:{ + set_time_spec(val.as<time_spec_t>(), true); return; + } - case MBOARD_PROP_REF_SOURCE:{ - std::string name = wax::cast<std::string>(val); - ASSERT_THROW(_ref_source_dict.has_key(name)); - _ref_source = name; //shadow - update_clock_config(); - } + case MBOARD_PROP_TIME_NEXT_PPS:{ + set_time_spec(val.as<time_spec_t>(), false); return; + } case MBOARD_PROP_NAME: case MBOARD_PROP_OTHERS: - case MBOARD_PROP_MTU: case MBOARD_PROP_CLOCK_RATE: case MBOARD_PROP_RX_DSP: case MBOARD_PROP_RX_DSP_NAMES: @@ -195,8 +266,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.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b4e8fe39..85d73e83a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -23,6 +23,12 @@ using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; +namespace asio = boost::asio; + +STATIC_BLOCK(register_usrp2_device){ + device::register_device(&usrp2::discover, &usrp2::make); +} /*********************************************************************** * Discovery over the udp transport @@ -30,40 +36,41 @@ using namespace uhd::usrp; uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ device_addrs_t usrp2_addrs; + if (not hint.has_key("addr")) return usrp2_addrs; + //create a udp transport to communicate //TODO if an addr is not provided, search all interfaces? std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT); - uhd::transport::udp udp_transport(hint["addr"], ctrl_port, true); + udp_simple::sptr udp_transport = udp_simple::make_broadcast( + hint["addr"], ctrl_port + ); //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); - udp_transport.send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); + udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); - //loop and recieve until the time is up - size_t num_timeouts = 0; + //loop and recieve until the timeout while(true){ - uhd::shared_iovec iov = udp_transport.recv(); - //std::cout << boost::asio::buffer_size(buff) << "\n"; - if (iov.len < sizeof(usrp2_ctrl_data_t)){ - //sleep a little so we dont burn cpu - if (num_timeouts++ > 50) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - }else{ + usrp2_ctrl_data_t ctrl_data_in; + size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in))); + //std::cout << len << "\n"; + if (len >= sizeof(usrp2_ctrl_data_t)){ //handle the received data - const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(iov.base); - switch(ntohl(ctrl_data_in->id)){ + switch(ntohl(ctrl_data_in.id)){ case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE: //make a boost asio ipv4 with the raw addr in host byte order - boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr)); + boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; new_addr["name"] = "USRP2"; - new_addr["type"] = "udp"; + new_addr["transport"] = "udp"; new_addr["addr"] = ip_addr.to_string(); usrp2_addrs.push_back(new_addr); - break; + //dont break here, it will exit the while loop + //just continue on to the next loop iteration } } + if (len == 0) break; //timeout } return usrp2_addrs; @@ -72,21 +79,19 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ +template <class T> std::string num2str(T num){ + return boost::lexical_cast<std::string>(num); +} + device::sptr usrp2::make(const device_addr_t &device_addr){ //create a control transport - uhd::transport::udp::sptr ctrl_transport( - new uhd::transport::udp( - device_addr["addr"], - boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT) - ) + udp_simple::sptr ctrl_transport = udp_simple::make_connected( + device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) ); //create a data transport - uhd::transport::udp::sptr data_transport( - new uhd::transport::udp( - device_addr["addr"], - boost::lexical_cast<std::string>(USRP2_UDP_DATA_PORT) - ) + udp_zero_copy::sptr data_transport = udp_zero_copy::make( + device_addr["addr"], num2str(USRP2_UDP_DATA_PORT) ); //create the usrp2 implementation guts @@ -99,8 +104,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - uhd::transport::udp::sptr ctrl_transport, - uhd::transport::udp::sptr data_transport + udp_simple::sptr ctrl_transport, + udp_zero_copy::sptr data_transport ){ _ctrl_transport = ctrl_transport; _data_transport = data_transport; @@ -121,9 +126,6 @@ usrp2_impl::usrp2_impl( //init the mboard mboard_init(); - //init the tx and rx dboards - dboard_init(); - //init the ddc init_ddc_config(); @@ -132,6 +134,13 @@ usrp2_impl::usrp2_impl( //initialize the clock configuration init_clock_config(); + + //init the tx and rx dboards (do last) + dboard_init(); + + //init the send and recv io + io_init(); + } usrp2_impl::~usrp2_impl(void){ @@ -156,22 +165,15 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da out_copy.seq = htonl(++_ctrl_seq_num); _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); - //loop and recieve until the time is up - size_t num_timeouts = 0; + //loop until we get the packet or timeout while(true){ - uhd::shared_iovec iov = _ctrl_transport->recv(); - if (iov.len < sizeof(usrp2_ctrl_data_t)){ - //sleep a little so we dont burn cpu - if (num_timeouts++ > 50) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - }else{ - //handle the received data - usrp2_ctrl_data_t in_data = *reinterpret_cast<const usrp2_ctrl_data_t *>(iov.base); - if (ntohl(in_data.seq) == _ctrl_seq_num){ - return in_data; - } - //didnt get seq, continue on... + usrp2_ctrl_data_t in_data; + size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data))); + if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){ + return in_data; } + if (len == 0) break; //timeout + //didnt get seq or bad packet, continue looking... } throw std::runtime_error("usrp2 no control response"); } @@ -184,32 +186,31 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast<device_prop_t>(key)){ + switch(key.as<device_prop_t>()){ case DEVICE_PROP_NAME: val = std::string("usrp2 device"); return; case DEVICE_PROP_MBOARD: - val = _mboards[name].get_link(); + ASSERT_THROW(_mboards.has_key(name)); + val = _mboards[name]->get_link(); return; case DEVICE_PROP_MBOARD_NAMES: val = prop_names_t(_mboards.get_keys()); return; + + case DEVICE_PROP_MAX_RX_SAMPLES: + val = size_t(_max_rx_samples_per_packet); + return; + + case DEVICE_PROP_MAX_TX_SAMPLES: + val = size_t(_max_tx_samples_per_packet); + return; + } } void usrp2_impl::set(const wax::obj &, const wax::obj &){ throw std::runtime_error("Cannot set in usrp2 device"); } - -/*********************************************************************** - * IO Interface - **********************************************************************/ -void usrp2_impl::send_raw(const std::vector<boost::asio::const_buffer> &){ - return; -} - -uhd::shared_iovec usrp2_impl::recv_raw(void){ - throw std::runtime_error("not implemented"); -} diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2545efd58..55ac0b192 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -15,19 +15,31 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#ifndef INCLUDED_USRP2_IMPL_HPP +#define INCLUDED_USRP2_IMPL_HPP + #include <uhd/usrp/usrp2.hpp> #include <uhd/dict.hpp> -#include <uhd/props.hpp> +#include <uhd/types.hpp> #include <uhd/time_spec.hpp> #include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> -#include <uhd/transport/udp.hpp> +#include <boost/assign/list_of.hpp> +#include <uhd/transport/vrt.hpp> +#include <uhd/transport/udp_simple.hpp> +#include <uhd/transport/udp_zero_copy.hpp> #include <uhd/usrp/dboard_manager.hpp> #include "fw_common.h" -#ifndef INCLUDED_USRP2_IMPL_HPP -#define INCLUDED_USRP2_IMPL_HPP +class usrp2_impl; //dummy class declaration + +/*! + * Make a usrp2 dboard interface. + * \param impl a pointer to the usrp2 impl object + * \return a sptr to a new dboard interface + */ +uhd::usrp::dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl); /*! * Simple wax obj proxy class: @@ -39,20 +51,25 @@ class wax_obj_proxy : public wax::obj{ public: typedef boost::function<void(const wax::obj &, wax::obj &)> get_t; typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; + typedef boost::shared_ptr<wax_obj_proxy> sptr; - wax_obj_proxy(void){ + static sptr make(const get_t &get, const set_t &set){ + return sptr(new wax_obj_proxy(get, set)); + } + + ~wax_obj_proxy(void){ /* NOP */ } +private: + get_t _get; + set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set){ _get = get; _set = set; }; - ~wax_obj_proxy(void){ - /* NOP */ - } - void get(const wax::obj &key, wax::obj &val){ return _get(key, val); } @@ -60,10 +77,6 @@ public: void set(const wax::obj &key, const wax::obj &val){ return _set(key, val); } - -private: - get_t _get; - set_t _set; }; /*! @@ -73,24 +86,18 @@ private: */ class usrp2_impl : public uhd::device{ public: - typedef boost::shared_ptr<usrp2_impl> sptr; - /*! * Create a new usrp2 impl base. * \param ctrl_transport the udp transport for control * \param data_transport the udp transport for data */ usrp2_impl( - uhd::transport::udp::sptr ctrl_transport, - uhd::transport::udp::sptr data_transport + uhd::transport::udp_simple::sptr ctrl_transport, + uhd::transport::udp_zero_copy::sptr data_transport ); ~usrp2_impl(void); - //properties interface - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - //performs a control transaction usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &); @@ -98,27 +105,51 @@ public: double get_master_clock_freq(void); //the io interface - void send_raw(const std::vector<boost::asio::const_buffer> &); - uhd::shared_iovec recv_raw(void); + size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &); + size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &); private: + //device properties interface + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + + //the raw io interface (samples are in the usrp2 native format) + void recv_raw(uhd::rx_metadata_t &); + uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq; + uhd::dict<boost::uint32_t, size_t> _rx_stream_id_to_packet_seq; + static const size_t _mtu = 1500; //FIXME we have no idea + static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp) + static const size_t _max_rx_samples_per_packet = + (_mtu - _hdrs)/sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_HEADER_WORDS32 - + USRP2_HOST_RX_VRT_TRAILER_WORDS32 + ; + static const size_t _max_tx_samples_per_packet = + (_mtu - _hdrs)/sizeof(boost::uint32_t) - + uhd::transport::vrt::max_header_words32 + ; + uhd::transport::smart_buffer::sptr _rx_smart_buff; + boost::asio::const_buffer _rx_copy_buff; + void io_init(void); + //udp transports for control and data - uhd::transport::udp::sptr _ctrl_transport; - uhd::transport::udp::sptr _data_transport; + uhd::transport::udp_simple::sptr _ctrl_transport; + uhd::transport::udp_zero_copy::sptr _data_transport; //private vars for dealing with send/recv control - uint32_t _ctrl_seq_num; + boost::uint32_t _ctrl_seq_num; boost::mutex _ctrl_mutex; //methods and shadows for clock configuration - std::string _pps_source, _pps_polarity, _ref_source; + uhd::clock_config_t _clock_config; 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; - uhd::dict<std::string, usrp2_pps_polarity_t> _pps_polarity_dict; - uhd::dict<std::string, usrp2_ref_source_t> _ref_source_dict; + uhd::dict<std::string, usrp2_ref_source_t> _ref_source_dict; + uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict; + uhd::dict<uhd::clock_config_t::polarity_t, usrp2_pps_polarity_t> _pps_polarity_dict; //rx and tx dboard methods and objects uhd::usrp::dboard_manager::sptr _dboard_manager; @@ -128,17 +159,20 @@ private: void mboard_init(void); void mboard_get(const wax::obj &, wax::obj &); void mboard_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, wax_obj_proxy> _mboards; + uhd::dict<std::string, wax_obj_proxy::sptr> _mboards; //properties interface for rx dboard void rx_dboard_get(const wax::obj &, wax::obj &); void rx_dboard_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, wax_obj_proxy> _rx_dboards; + uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dboards; + uhd::prop_names_t _rx_subdevs_in_use; //properties interface for tx dboard void tx_dboard_get(const wax::obj &, wax::obj &); void tx_dboard_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, wax_obj_proxy> _tx_dboards; + uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dboards; + uhd::prop_names_t _tx_subdevs_in_use; + void update_mux_config(void); //methods and shadows for the ddc dsp std::vector<size_t> _allowed_decim_and_interp_rates; @@ -159,12 +193,12 @@ private: //properties interface for ddc void ddc_get(const wax::obj &, wax::obj &); void ddc_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, wax_obj_proxy> _rx_dsps; + uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsps; //properties interface for duc void duc_get(const wax::obj &, wax::obj &); void duc_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, wax_obj_proxy> _tx_dsps; + uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsps; }; |