diff options
Diffstat (limited to 'host/lib/usrp')
-rw-r--r-- | host/lib/usrp/dboard/db_basic_and_lf.cpp | 16 | ||||
-rw-r--r-- | host/lib/usrp/dboard/db_rfx.cpp | 319 | ||||
-rw-r--r-- | host/lib/usrp/dboard_interface.cpp | 53 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dboard_impl.cpp | 1 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dboard_interface.cpp | 99 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 7 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 153 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 8 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 32 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 13 |
10 files changed, 448 insertions, 253 deletions
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 3c14e473e..5a992339b 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -75,7 +75,7 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){ return dboard_base::sptr(new basic_tx(args, 32e6)); } -UHD_STATIC_BLOCK(reg_dboards){ +UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){ dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX"); dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("ab")("a")("b")); dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX"); @@ -138,10 +138,6 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; - case SUBDEV_PROP_ENABLED: - val = true; //always enabled - return; - case SUBDEV_PROP_QUADRATURE: val = (get_subdev_name() == "ab"); //only quadrature in ab mode return; @@ -175,9 +171,6 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ ASSERT_THROW(val.as<std::string>() == std::string("")); return; - case SUBDEV_PROP_ENABLED: - return; // it wont do you much good, but you can set it - case SUBDEV_PROP_FREQ: return; // it wont do you much good, but you can set it @@ -240,10 +233,6 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; - case SUBDEV_PROP_ENABLED: - val = true; //always enabled - return; - case SUBDEV_PROP_QUADRATURE: val = true; return; @@ -277,9 +266,6 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ ASSERT_THROW(val.as<std::string>() == std::string("")); return; - case SUBDEV_PROP_ENABLED: - return; // it wont do you much good, but you can set it - case SUBDEV_PROP_FREQ: return; // it wont do you much good, but you can set it diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp new file mode 100644 index 000000000..4bf931660 --- /dev/null +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -0,0 +1,319 @@ +// +// 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 "adf4360_regs.hpp" +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/usrp/dboard_base.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The RFX series of dboards + **********************************************************************/ +class rfx_xcvr : public xcvr_dboard_base{ +public: + rfx_xcvr(ctor_args_t const& args, const freq_range_t &freq_range); + ~rfx_xcvr(void); + + void rx_get(const wax::obj &key, wax::obj &val); + void rx_set(const wax::obj &key, const wax::obj &val); + + void tx_get(const wax::obj &key, wax::obj &val); + void tx_set(const wax::obj &key, const wax::obj &val); + +private: + freq_range_t _freq_range; + double _lo_freq; + std::string _rx_ant; + float _rx_pga0_gain; + adf4360_regs_t _adf4360_regs; + + void set_lo_freq(double freq); + void set_rx_ant(const std::string &ant); + void set_rx_pga0_gain(float gain); + void reload_adf4360_regs(void); +}; + +/*********************************************************************** + * Register the RFX dboards + **********************************************************************/ +static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6))); +} + +static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(750e6, 1050e6))); +} + +static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6))); +} + +static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1500e6, 2100e6))); +} + +static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6))); +} + +UHD_STATIC_BLOCK(reg_rfx_dboards){ + dboard_manager::register_dboard(0x0024, &make_rfx_flex400, "Flex 400 Rx MIMO B"); + dboard_manager::register_dboard(0x0028, &make_rfx_flex400, "Flex 400 Tx MIMO B"); + + dboard_manager::register_dboard(0x0025, &make_rfx_flex900, "Flex 900 Rx MIMO B"); + dboard_manager::register_dboard(0x0029, &make_rfx_flex900, "Flex 900 Tx MIMO B"); + + dboard_manager::register_dboard(0x0026, &make_rfx_flex1200, "Flex 1200 Rx MIMO B"); + dboard_manager::register_dboard(0x002a, &make_rfx_flex1200, "Flex 1200 Tx MIMO B"); + + dboard_manager::register_dboard(0x0034, &make_rfx_flex1800, "Flex 1800 Rx MIMO B"); + dboard_manager::register_dboard(0x0035, &make_rfx_flex1800, "Flex 1800 Tx MIMO B"); + + dboard_manager::register_dboard(0x0027, &make_rfx_flex2400, "Flex 2400 Rx MIMO B"); + dboard_manager::register_dboard(0x002b, &make_rfx_flex2400, "Flex 2400 Tx MIMO B"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +rfx_xcvr::rfx_xcvr( + ctor_args_t const& args, + const freq_range_t &freq_range +) : xcvr_dboard_base(args){ + _freq_range = freq_range; + set_lo_freq((_freq_range.min + _freq_range.max)/2.0); + set_rx_ant("rx2"); + set_rx_pga0_gain(0); +} + +rfx_xcvr::~rfx_xcvr(void){ + /* NOP */ +} + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void rfx_xcvr::set_lo_freq(double freq){ + /* NOP */ + reload_adf4360_regs(); +} + +void rfx_xcvr::set_rx_ant(const std::string &ant){ + /* NOP */ +} + +void rfx_xcvr::set_rx_pga0_gain(float gain){ + /* NOP */ +} + +void rfx_xcvr::reload_adf4360_regs(void){ + std::vector<adf4360_regs_t::addr_t> addrs = list_of + (adf4360_regs_t::ADDR_CONTROL) + (adf4360_regs_t::ADDR_NCOUNTER) + (adf4360_regs_t::ADDR_RCOUNTER) + ; + BOOST_FOREACH(adf4360_regs_t::addr_t addr, addrs){ + this->get_interface()->write_spi( + dboard_interface::UNIT_TYPE_TX, + spi_config_t::EDGE_RISE, + _adf4360_regs.get_reg(addr), 24 + ); + } +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as<subdev_prop_t>()){ + case SUBDEV_PROP_NAME: + val = dboard_id::to_string(get_rx_id()); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + val = _rx_pga0_gain; + return; + + case SUBDEV_PROP_GAIN_RANGE: + val = gain_range_t(0, 45, float(0.022)); + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(1, "pga0"); + return; + + case SUBDEV_PROP_FREQ: + val = _lo_freq; + return; + + case SUBDEV_PROP_FREQ_RANGE: + val = _freq_range; + return; + + case SUBDEV_PROP_ANTENNA: + val = _rx_ant; + return; + + case SUBDEV_PROP_ANTENNA_NAMES:{ + prop_names_t ants = list_of("tx/rx")("rx2"); + val = ants; + } + return; + + case SUBDEV_PROP_QUADRATURE: + val = true; + return; + + case SUBDEV_PROP_IQ_SWAPPED: + val = true; + return; + + case SUBDEV_PROP_SPECTRUM_INVERTED: + val = false; + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = false; + return; + } +} + +void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as<subdev_prop_t>()){ + + case SUBDEV_PROP_GAIN: + ASSERT_THROW(name == "pga0"); + set_rx_pga0_gain(val.as<float>()); + return; + + case SUBDEV_PROP_ANTENNA: + set_rx_ant(val.as<std::string>()); + return; + + default: + throw std::runtime_error(str(boost::format( + "Error: trying to set read-only property on %s subdev" + ) % dboard_id::to_string(get_rx_id()))); + } +} + +/*********************************************************************** + * TX Get and Set + **********************************************************************/ +void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as<subdev_prop_t>()){ + case SUBDEV_PROP_NAME: + val = dboard_id::to_string(get_tx_id()); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + val = float(0); + return; + + case SUBDEV_PROP_GAIN_RANGE: + val = gain_range_t(0, 0, 0); + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_FREQ: + val = _lo_freq; + return; + + case SUBDEV_PROP_FREQ_RANGE: + val = _freq_range; + return; + + case SUBDEV_PROP_ANTENNA: + val = std::string("tx/rx"); + return; + + case SUBDEV_PROP_ANTENNA_NAMES: + val = prop_names_t(1, "tx/rx"); + return; + + case SUBDEV_PROP_QUADRATURE: + val = true; + return; + + case SUBDEV_PROP_IQ_SWAPPED: + val = false; + return; + + case SUBDEV_PROP_SPECTRUM_INVERTED: + val = false; + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = true; + return; + } +} + +void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as<subdev_prop_t>()){ + + case SUBDEV_PROP_GAIN: + //no gains to set! + return; + + case SUBDEV_PROP_ANTENNA: + //its always set to tx/rx, so we only allow this value + ASSERT_THROW(val.as<std::string>() == "tx/rx"); + return; + + default: + throw std::runtime_error(str(boost::format( + "Error: trying to set read-only property on %s subdev" + ) % dboard_id::to_string(get_tx_id()))); + } +} diff --git a/host/lib/usrp/dboard_interface.cpp b/host/lib/usrp/dboard_interface.cpp deleted file mode 100644 index c40c9b398..000000000 --- a/host/lib/usrp/dboard_interface.cpp +++ /dev/null @@ -1,53 +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> - -using namespace uhd::usrp; - -dboard_interface::dboard_interface(void){ - /* NOP */ -} - -dboard_interface::~dboard_interface(void){ - /* NOP */ -} - -void dboard_interface::write_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf -){ - transact_spi(dev, edge, buf, false); //dont readback -} - -dboard_interface::byte_vector_t dboard_interface::read_spi( - spi_dev_t dev, - spi_edge_t edge, - size_t num_bytes -){ - byte_vector_t buf(num_bytes, 0x00); //dummy data - return transact_spi(dev, edge, buf, true); //readback -} - -dboard_interface::byte_vector_t dboard_interface::read_write_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf -){ - return transact_spi(dev, edge, buf, true); //readback -} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index d1515f2d5..3ac805421 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -22,6 +22,7 @@ #include <uhd/usrp/dboard_props.hpp> #include <uhd/utils/assert.hpp> #include <boost/format.hpp> +#include <iostream> using namespace uhd; using namespace uhd::usrp; diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp index 6dd756420..d10cfa37e 100644 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ b/host/lib/usrp/usrp2/dboard_interface.cpp @@ -42,11 +42,21 @@ public: double get_rx_clock_rate(void); double get_tx_clock_rate(void); -private: - byte_vector_t transact_spi( - spi_dev_t, spi_edge_t, const byte_vector_t &, bool + void write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ); + + boost::uint32_t read_write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits ); +private: usrp2_impl *_impl; boost::uint32_t _ddr_shadow; }; @@ -136,62 +146,35 @@ void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, atr_reg_t atr, boost: * SPI **********************************************************************/ /*! - * Static function to convert a spi dev enum - * to an over-the-wire value for the usrp2 control. - * \param dev the dboard interface spi dev enum + * Static function to convert a unit type enum + * to an over-the-wire value for the spi device. + * \param unit the dboard interface unit type enum * \return an over the wire representation */ -static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ - switch(dev){ - case uhd::usrp::dboard_interface::SPI_DEV_TX: return SPI_SS_TX_DB; - case uhd::usrp::dboard_interface::SPI_DEV_RX: return SPI_SS_RX_DB; +static boost::uint8_t unit_to_otw_dev(dboard_interface::unit_type_t unit){ + switch(unit){ + case dboard_interface::UNIT_TYPE_TX: return SPI_SS_TX_DB; + case dboard_interface::UNIT_TYPE_RX: return SPI_SS_RX_DB; } - throw std::invalid_argument("unknown spi device type"); + throw std::invalid_argument("unknown unit type type"); } -/*! - * Static function to convert a spi edge enum - * to an over-the-wire value for the usrp2 control. - * \param edge the dboard interface spi edge enum - * \return an over the wire representation - */ -static boost::uint8_t spi_edge_to_otw(dboard_interface::spi_edge_t edge){ - switch(edge){ - case uhd::usrp::dboard_interface::SPI_EDGE_RISE: return USRP2_CLK_EDGE_RISE; - case uhd::usrp::dboard_interface::SPI_EDGE_FALL: return USRP2_CLK_EDGE_FALL; - } - throw std::invalid_argument("unknown spi edge type"); +void usrp2_dboard_interface::write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits +){ + _impl->transact_spi(unit_to_otw_dev(unit), config, data, num_bits, false /*no rb*/); } -dboard_interface::byte_vector_t usrp2_dboard_interface::transact_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf, - bool readback +boost::uint32_t usrp2_dboard_interface::read_write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits ){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); - out_data.data.spi_args.dev = spi_dev_to_otw(dev); - out_data.data.spi_args.edge = spi_edge_to_otw(edge); - out_data.data.spi_args.readback = (readback)? 1 : 0; - out_data.data.spi_args.bytes = buf.size(); - - //limitation of spi transaction size - ASSERT_THROW(buf.size() <= sizeof(out_data.data.spi_args.data)); - - //copy in the data - std::copy(buf.begin(), buf.end(), out_data.data.spi_args.data); - - //send and recv - usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); - ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); - ASSERT_THROW(in_data.data.spi_args.bytes == buf.size()); - - //copy out the data - byte_vector_t result(buf.size()); - std::copy(in_data.data.spi_args.data, in_data.data.spi_args.data + buf.size(), result.begin()); - return result; + return _impl->transact_spi(unit_to_otw_dev(unit), config, data, num_bits, true /*rb*/); } /*********************************************************************** @@ -245,19 +228,19 @@ 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 boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ +static boost::uint8_t unit_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; + case dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX; + case dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX; } throw std::invalid_argument("unknown unit type type"); } -void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, int which, int value){ +void usrp2_dboard_interface::write_aux_dac(unit_type_t unit, int which, int value){ //setup the out data usrp2_ctrl_data_t out_data; 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.dir = unit_to_otw(unit); out_data.data.aux_args.which = which; out_data.data.aux_args.value = htonl(value); @@ -266,11 +249,11 @@ void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, i ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE); } -int usrp2_dboard_interface::read_aux_adc(dboard_interface::unit_type_t unit, int which){ +int usrp2_dboard_interface::read_aux_adc(unit_type_t unit, int which){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO); - out_data.data.aux_args.dir = spi_dev_to_otw(unit); + out_data.data.aux_args.dir = unit_to_otw(unit); out_data.data.aux_args.which = which; //send and recv diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 019f3b931..b600a2a70 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -110,10 +110,11 @@ typedef struct{ } dboard_ids; struct { _SINS_ uint8_t dev; - _SINS_ uint8_t edge; + _SINS_ uint8_t miso_edge; + _SINS_ uint8_t mosi_edge; _SINS_ uint8_t readback; - _SINS_ uint8_t bytes; - _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; + _SINS_ uint32_t data; + _SINS_ uint8_t num_bits; } spi_args; struct { _SINS_ uint8_t addr; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index a58e32619..a760cbe3d 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -15,9 +15,11 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <complex> -#include <boost/format.hpp> #include "usrp2_impl.hpp" +#include <uhd/transport/convert_types.hpp> +#include <boost/format.hpp> +#include <complex> +#include <iostream> using namespace uhd; using namespace uhd::usrp; @@ -25,101 +27,26 @@ 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){ + //setup otw type + _otw_type.width = 16; + _otw_type.shift = 0; + _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //initially empty copy buffer _rx_copy_buff = asio::buffer("", 0); //send a small data packet so the usrp2 knows the udp source port //and the maximum number of lines (32 bit words) per packet + managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data[2] = { htonl(USRP2_INVALID_VRT_HEADER), htonl(_max_rx_samples_per_packet) }; - _data_transport->send(asio::buffer(&data, sizeof(data))); -} - -#define unrolled_loop(__inst, __len){ \ - size_t __i = 0; \ - for(; __i < (__len & ~0x3); __i+= 4){ \ - __inst(__i+0); __inst(__i+1); \ - __inst(__i+2); __inst(__i+3); \ - } \ - for(; __i < __len; __i++){ \ - __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 -){ - #define host_floats_to_usrp2_items_i(i){ \ - 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)); \ - } - unrolled_loop(host_floats_to_usrp2_items_i, num_samps); -} - -static inline void usrp2_items_to_host_floats( - fc32_t *host_floats, - const boost::uint32_t *usrp2_items, - size_t num_samps -){ - #define usrp2_items_to_host_floats_i(i){ \ - 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)); \ - } - unrolled_loop(usrp2_items_to_host_floats_i, num_samps); -} - -static inline void host_items_to_usrp2_items( - boost::uint32_t *usrp2_items, - const boost::uint32_t *host_items, - size_t num_samps -){ - #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i]) - if (is_big_endian){ - std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); - } - else{ - unrolled_loop(host_items_to_usrp2_items_i, num_samps); - } -} - -static inline void usrp2_items_to_host_items( - boost::uint32_t *host_items, - const boost::uint32_t *usrp2_items, - size_t num_samps -){ - #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i]) - if (is_big_endian){ - std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); - } - else{ - unrolled_loop(usrp2_items_to_host_items_i, num_samps); - } + memcpy(send_buff->cast<void*>(), data, sizeof(data)); + send_buff->done(sizeof(data)); } /*********************************************************************** @@ -127,15 +54,15 @@ static inline void usrp2_items_to_host_items( **********************************************************************/ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ //do a receive - _rx_smart_buff = _data_transport->recv(); + _rx_smart_buff = _data_transport->get_recv_buff(); //unpack the vrt header - size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(boost::uint32_t); + size_t num_packet_words32 = _rx_smart_buff->size()/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()); + const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>(); size_t num_header_words32_out, num_payload_words32_out, packet_count_out; try{ vrt::unpack( @@ -144,7 +71,8 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ num_header_words32_out, //output num_payload_words32_out, //output num_packet_words32, //input - packet_count_out //output + packet_count_out, //output + get_master_clock_freq() ); }catch(const std::exception &e){ std::cerr << "bad vrt header: " << e.what() << std::endl; @@ -176,10 +104,12 @@ size_t usrp2_impl::send( ){ tx_metadata_t metadata = metadata_; //rw copy to change later - boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; - size_t num_samps = std::min( + transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); + boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>(); + size_t num_samps = std::min(std::min( asio::buffer_size(buff)/io_type.size, - size_t(_max_tx_samples_per_packet) + size_t(_max_tx_samples_per_packet)), + send_buff->size()/io_type.size ); //kill the end of burst flag if this is a fragment @@ -196,25 +126,21 @@ size_t usrp2_impl::send( num_header_words32, //output num_samps, //input num_packet_words32, //output - packet_count //input + packet_count, //input + get_master_clock_freq() ); boost::uint32_t *items = tx_mem + num_header_words32; //offset for data - //copy the samples into the send buffer - switch(io_type.tid){ - case io_type_t::COMPLEX_FLOAT32: - host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); - break; - case io_type_t::COMPLEX_INT16: - host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); - break; - default: - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid)); - } + //copy-convert the samples into the send buffer + convert_io_type_to_otw_type( + asio::buffer_cast<const void*>(buff), io_type, + (void*)items, _otw_type, + num_samps + ); //send and return number of samples - _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t))); + send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); return num_samps; } @@ -251,17 +177,12 @@ size_t usrp2_impl::recv( metadata.fragment_offset = _fragment_offset_in_samps; _fragment_offset_in_samps += num_samps; //set for next time - //copy the samples from the recv buffer - switch(io_type.tid){ - case io_type_t::COMPLEX_FLOAT32: - usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps); - break; - case io_type_t::COMPLEX_INT16: - usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps); - break; - default: - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid)); - } + //copy-convert the samples from the recv buffer + convert_otw_type_to_io_type( + (const void*)items, _otw_type, + asio::buffer_cast<void*>(buff), io_type, + num_samps + ); //update the rx copy buffer to reflect the bytes copied _rx_copy_buff = asio::buffer( diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 94ab88a6b..2fa2e5211 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -33,10 +33,6 @@ 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){ @@ -75,7 +71,7 @@ void usrp2_impl::update_clock_config(void){ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ //set ticks and seconds this->poke32(FR_TIME64_SECS, time_spec.secs); - this->poke32(FR_TIME64_TICKS, time_spec.ticks); + this->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq())); //set the register to latch it all in boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS; @@ -88,7 +84,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO); out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0; out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs); - out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.ticks); + out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq())); //set these to defaults, then change in the switch statement out_data.data.stream_cmd.continuous = 0; diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index a7be2da8c..6d8c1a86c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -15,15 +15,16 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "usrp2_impl.hpp" #include <uhd/transport/if_addrs.hpp> #include <uhd/usrp/device_props.hpp> #include <uhd/utils/assert.hpp> #include <uhd/utils/static.hpp> +#include <boost/assign/list_of.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <boost/bind.hpp> #include <iostream> -#include "usrp2_impl.hpp" using namespace uhd; using namespace uhd::usrp; @@ -217,6 +218,35 @@ boost::uint16_t usrp2_impl::peek16(boost::uint32_t addr){ return impl_peek<boost::uint16_t>(this, addr); } +boost::uint32_t usrp2_impl::transact_spi( + int which_slave, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback +){ + static const uhd::dict<spi_config_t::edge_t, int> spi_edge_to_otw = boost::assign::map_list_of + (spi_config_t::EDGE_RISE, USRP2_CLK_EDGE_RISE) + (spi_config_t::EDGE_FALL, USRP2_CLK_EDGE_FALL) + ; + + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); + out_data.data.spi_args.dev = which_slave; + out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge]; + out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge]; + out_data.data.spi_args.readback = (readback)? 1 : 0; + out_data.data.spi_args.num_bits = num_bits; + out_data.data.spi_args.data = htonl(data); + + //send and recv + usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); + + return ntohl(out_data.data.spi_args.data); +} + /*********************************************************************** * Control Send/Recv **********************************************************************/ diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index baa6530b8..5a02b33dc 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -20,6 +20,7 @@ #include <uhd/usrp/usrp2.hpp> #include <uhd/types/dict.hpp> +#include <uhd/types/otw_type.hpp> #include <uhd/types/stream_cmd.hpp> #include <uhd/types/clock_config.hpp> #include <boost/asio.hpp> @@ -109,6 +110,15 @@ public: void poke16(boost::uint32_t addr, boost::uint16_t data); boost::uint16_t peek16(boost::uint32_t addr); + //spi read and write + boost::uint32_t transact_spi( + int which_slave, + const uhd::usrp::spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback + ); + //misc access methods double get_master_clock_freq(void); @@ -136,9 +146,10 @@ private: (_mtu - _hdrs)/sizeof(boost::uint32_t) - uhd::transport::vrt::max_header_words32 ; - uhd::transport::smart_buffer::sptr _rx_smart_buff; + uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; size_t _fragment_offset_in_samps; + uhd::otw_type_t _otw_type; void io_init(void); //udp transports for control and data |