From bf7ef6aeb502839797894cac4d7518029a0d04c4 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 15:14:48 -0700 Subject: Moved adc and dac control into codec control source file. The codec control powers down the chips on destruction. --- host/lib/usrp/usrp2/usrp2_impl.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 1c9387744..871050356 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -19,7 +19,8 @@ #define INCLUDED_USRP2_IMPL_HPP #include "usrp2_iface.hpp" -#include "clock_control.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" #include #include #include @@ -40,7 +41,7 @@ */ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( usrp2_iface::sptr iface, - clock_control::sptr clk_ctrl + clock_ctrl::sptr clk_ctrl ); /*! @@ -114,7 +115,8 @@ private: void set(const wax::obj &, const wax::obj &); //interfaces - clock_control::sptr _clk_ctrl; + clock_ctrl::sptr _clock_ctrl; + codec_ctrl::sptr _codec_ctrl; usrp2_iface::sptr _iface; //the raw io interface (samples are in the usrp2 native format) -- cgit v1.2.3 From 7c7b0d0a0dc8dd0cb4f0229fbc55978d6f2e253c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 16:37:12 -0700 Subject: Added a place for serdes control on the host. Fix bug in codec control. Comment out some clock control in fw code. --- firmware/microblaze/lib/clocks.c | 30 ++++++++++++------------ firmware/microblaze/lib/clocks.h | 10 ++++---- host/lib/usrp/usrp2/CMakeLists.txt | 1 + host/lib/usrp/usrp2/clock_ctrl.hpp | 6 ++--- host/lib/usrp/usrp2/codec_ctrl.cpp | 6 ++--- host/lib/usrp/usrp2/codec_ctrl.hpp | 6 ++--- host/lib/usrp/usrp2/mboard_impl.cpp | 4 ---- host/lib/usrp/usrp2/serdes_ctrl.cpp | 46 +++++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/serdes_ctrl.hpp | 40 ++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 1 + host/lib/usrp/usrp2/usrp2_impl.hpp | 4 +++- 11 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 host/lib/usrp/usrp2/serdes_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/serdes_ctrl.hpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c index d9d4fcd3c..ccc4a7cc7 100644 --- a/firmware/microblaze/lib/clocks.c +++ b/firmware/microblaze/lib/clocks.c @@ -48,14 +48,14 @@ clocks_init(void) clocks_mimo_config(MC_WE_DONT_LOCK); // Set up other clocks - clocks_enable_test_clk(false, 0); - clocks_enable_tx_dboard(false, 0); - clocks_enable_rx_dboard(false, 0); + //clocks_enable_test_clk(false, 0); + //clocks_enable_tx_dboard(false, 0); + //clocks_enable_rx_dboard(false, 0); clocks_enable_eth_phyclk(false, 0); // Enable clock to ADCs and DACs - clocks_enable_dac_clk(true, 1); - clocks_enable_adc_clk(true, 1); + //clocks_enable_dac_clk(true, 1); + //clocks_enable_adc_clk(true, 1); } @@ -168,11 +168,11 @@ clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mod } // Clock 0 -void +/*void clocks_enable_test_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); -} +}*/ // Clock 1 void @@ -211,29 +211,29 @@ clocks_enable_eth_phyclk(bool enable, int divisor) } // Clock 3 -void +/*void clocks_enable_dac_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); -} +}*/ // Clock 4 -void +/*void clocks_enable_adc_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); -} +}*/ // Clock 6 -void +/*void clocks_enable_tx_dboard(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); -} +}*/ // Clock 7 -void +/*void clocks_enable_rx_dboard(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); -} +}*/ diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h index 141fc61e0..43d5a05c2 100644 --- a/firmware/microblaze/lib/clocks.h +++ b/firmware/microblaze/lib/clocks.h @@ -53,7 +53,7 @@ bool clocks_lock_detect(); /*! * \brief Enable or disable test clock (extra clock signal) */ -void clocks_enable_test_clk(bool enable, int divisor); +//void clocks_enable_test_clk(bool enable, int divisor); /*! * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle. @@ -73,23 +73,23 @@ void clocks_enable_eth_phyclk(bool enable, int divisor); /*! * \brief Enable or disable clock to DAC */ -void clocks_enable_dac_clk(bool enable, int divisor); +//void clocks_enable_dac_clk(bool enable, int divisor); /*! * \brief Enable or disable clock to ADC */ -void clocks_enable_adc_clk(bool enable, int divisor); +//void clocks_enable_adc_clk(bool enable, int divisor); /*! * \brief Enable or disable clock to Rx daughterboard */ -void clocks_enable_rx_dboard(bool enable, int divisor); +//void clocks_enable_rx_dboard(bool enable, int divisor); /*! * \brief Enable or disable clock to Tx daughterboard */ -void clocks_enable_tx_dboard(bool enable, int divisor); +//void clocks_enable_tx_dboard(bool enable, int divisor); #endif /* INCLUDED_CLOCKS_H */ diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 6c7881861..fee67dff9 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -25,6 +25,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp ) diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 3208008a9..706bf4246 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_CLOCK_CONTROL_HPP -#define INCLUDED_CLOCK_CONTROL_HPP +#ifndef INCLUDED_CLOCK_CTRL_HPP +#define INCLUDED_CLOCK_CTRL_HPP #include "usrp2_iface.hpp" #include @@ -57,4 +57,4 @@ public: }; -#endif /* INCLUDED_CLOCK_CONTROL_HPP */ +#endif /* INCLUDED_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 452aa39b1..d1e16881b 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -53,7 +53,7 @@ public: _ad9777_regs.qdac_offset_adjust_msb = 0; //write all regs for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ - send_ad9777_reg(addr); + this->send_ad9777_reg(addr); } //power-up adc @@ -63,7 +63,7 @@ public: ~codec_ctrl_impl(void){ //power-down dac _ad9777_regs.power_down_mode = 1; - send_ad9777_reg(0); + this->send_ad9777_reg(0); //power-down adc _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF); @@ -78,7 +78,7 @@ private: if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl; _iface->transact_spi( SPI_SS_AD9777, spi_config_t::EDGE_RISE, - reg, 6, false /*no rb*/ + reg, 16, false /*no rb*/ ); } }; diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index c34fb8159..0ee52f476 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_CODEC_CONTROL_HPP -#define INCLUDED_CODEC_CONTROL_HPP +#ifndef INCLUDED_CODEC_CTRL_HPP +#define INCLUDED_CODEC_CTRL_HPP #include "usrp2_iface.hpp" #include @@ -35,4 +35,4 @@ public: }; -#endif /* INCLUDED_CODEC_CONTROL_HPP */ +#endif /* INCLUDED_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 892e45f49..7e62bedf0 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -36,10 +36,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 up serdes - _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); - } void usrp2_impl::init_clock_config(void){ diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp new file mode 100644 index 000000000..dde22b499 --- /dev/null +++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp @@ -0,0 +1,46 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "serdes_ctrl.hpp" +#include "usrp2_regs.hpp" + +using namespace uhd; + +/*! + * A usrp2 serdes control implementation + */ +class serdes_ctrl_impl : public serdes_ctrl{ +public: + serdes_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); + } + + ~serdes_ctrl_impl(void){ + _iface->poke32(FR_MISC_CTRL_SERDES, 0); //power-down + } + +private: + usrp2_iface::sptr _iface; +}; + +/*********************************************************************** + * Public make function for the usrp2 serdes control + **********************************************************************/ +serdes_ctrl::sptr serdes_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new serdes_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp new file mode 100644 index 000000000..586238739 --- /dev/null +++ b/host/lib/usrp/usrp2/serdes_ctrl.hpp @@ -0,0 +1,40 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_SERDES_CTRL_HPP +#define INCLUDED_SERDES_CTRL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class serdes_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a serdes control object for the usrp2 serdes port. + * \param _iface a pointer to the usrp2 interface object + * \return a new serdes control object + */ + static sptr make(usrp2_iface::sptr iface); + + //TODO fill me in with virtual methods + +}; + +#endif /* INCLUDED_SERDES_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index ef7754c33..5c1d7f9e3 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -149,6 +149,7 @@ usrp2_impl::usrp2_impl( _iface = usrp2_iface::make(ctrl_transport); _clock_ctrl = clock_ctrl::make(_iface); _codec_ctrl = codec_ctrl::make(_iface); + _serdes_ctrl = serdes_ctrl::make(_iface); //load the allowed decim/interp rates //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 871050356..c5b6af810 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -21,6 +21,7 @@ #include "usrp2_iface.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" +#include "serdes_ctrl.hpp" #include #include #include @@ -115,9 +116,10 @@ private: void set(const wax::obj &, const wax::obj &); //interfaces + usrp2_iface::sptr _iface; clock_ctrl::sptr _clock_ctrl; codec_ctrl::sptr _codec_ctrl; - usrp2_iface::sptr _iface; + serdes_ctrl::sptr _serdes_ctrl; //the raw io interface (samples are in the usrp2 native format) void recv_raw(uhd::rx_metadata_t &); -- cgit v1.2.3 From d20595a3fe9ba864d824c160c3db39fc7a3d1e7c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 09:52:43 -0700 Subject: calculate max samples per packet using otw type --- host/lib/usrp/usrp2/io_impl.cpp | 23 +++++++++++++++-------- host/lib/usrp/usrp2/mboard_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 ++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 27 +++++++++++++++++++-------- 4 files changed, 37 insertions(+), 19 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 7c9d003ce..de0c76eb1 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -31,10 +31,16 @@ namespace asio = boost::asio; * 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; + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //initially empty copy buffer _rx_copy_buff = asio::buffer("", 0); @@ -49,7 +55,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet); + std::cout << "RX samples per packet: " << max_rx_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, max_rx_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -121,7 +128,7 @@ size_t usrp2_impl::send( boost::uint32_t *tx_mem = send_buff->cast(); 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_samps_per_packet())), send_buff->size()/io_type.size ); @@ -148,7 +155,7 @@ size_t usrp2_impl::send( //copy-convert the samples into the send buffer convert_io_type_to_otw_type( asio::buffer_cast(buff), io_type, - (void*)items, _otw_type, + (void*)items, _tx_otw_type, num_samps ); @@ -192,7 +199,7 @@ size_t usrp2_impl::recv( //copy-convert the samples from the recv buffer convert_otw_type_to_io_type( - (const void*)items, _otw_type, + (const void*)items, _rx_otw_type, asio::buffer_cast(buff), io_type, num_samps ); diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 9ae68d158..a10529102 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? max_rx_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b7bdeea2..3b7156802 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -211,11 +211,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_rx_samples_per_packet); + val = max_rx_samps_per_packet(); return; case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_tx_samples_per_packet); + val = max_tx_samps_per_packet(); return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index c5b6af810..e2d37e512 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -125,21 +125,32 @@ private: void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; + + /******************************************************************* + * Deal with the rx and tx packet sizes + ******************************************************************/ 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_rx_bytes_per_packet = + _mtu - _hdrs - + USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) ; - static const size_t _max_tx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - uhd::transport::vrt::max_header_words32 + static const size_t _max_tx_bytes_per_packet = + _mtu - _hdrs - + uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; + size_t max_rx_samps_per_packet(void){ + return _max_rx_bytes_per_packet/(_rx_otw_type.width*2/8); + } + size_t max_tx_samps_per_packet(void){ + return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); + } + 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; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); //udp transports for control and data -- cgit v1.2.3 From d9cc352ed14dbab04523f53e21f855b05c30eb3f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 13:22:26 -0700 Subject: work on generic packet handler (got rx working) --- host/lib/transport/vrt_packet_handler.hpp | 161 ++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/io_impl.cpp | 95 ++---------------- host/lib/usrp/usrp2/usrp2_impl.hpp | 8 +- 3 files changed, 169 insertions(+), 95 deletions(-) create mode 100644 host/lib/transport/vrt_packet_handler.hpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp new file mode 100644 index 000000000..a6161ef55 --- /dev/null +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -0,0 +1,161 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vrt_packet_handler{ + +/*********************************************************************** + * vrt packet handler for recv + **********************************************************************/ + struct recv_state{ + //init the expected seq number + size_t next_packet_seq; + + //state variables to handle fragments + uhd::transport::managed_recv_buffer::sptr managed_buff; + boost::asio::const_buffer copy_buff; + size_t fragment_offset_in_samps; + + recv_state(void){ + //first expected seq is zero + next_packet_seq = 0; + + //initially empty copy buffer + copy_buff = boost::asio::buffer("", 0); + } + }; + + typedef boost::function recv_cb_t; + + static inline void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ + /* NOP */ + } + + static inline size_t recv( + recv_state &state, + const boost::asio::mutable_buffer &buff, + uhd::rx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t vrt_header_offset_words32 = 0, + const recv_cb_t& recv_cb = &recv_cb_nop + ){ + //////////////////////////////////////////////////////////////// + // Perform the recv + //////////////////////////////////////////////////////////////// + { + //perform a receive if no rx data is waiting to be copied + if (boost::asio::buffer_size(state.copy_buff) == 0){ + state.fragment_offset_in_samps = 0; + state.managed_buff = zc_iface->get_recv_buff(); + recv_cb(state.managed_buff); + } + //otherwise flag the metadata to show that is is a fragment + else{ + metadata = uhd::rx_metadata_t(); + goto vrt_recv_copy_convert; + } + } + + //////////////////////////////////////////////////////////////// + // Unpack the vrt header + //////////////////////////////////////////////////////////////// + { + size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + if (num_packet_words32 <= vrt_header_offset_words32){ + state.copy_buff = boost::asio::buffer("", 0); + goto vrt_recv_copy_convert; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + uhd::transport::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 + tick_rate + ); + + //handle the packet count / sequence number + if (packet_count_out != state.next_packet_seq){ + std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; + } + state.next_packet_seq = (packet_count_out+1)%16; + + //setup the buffer to point to the data + state.copy_buff = boost::asio::buffer( + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(boost::uint32_t) + ); + } + + //////////////////////////////////////////////////////////////// + // Perform copy-convert into buffer + //////////////////////////////////////////////////////////////// + vrt_recv_copy_convert:{ + size_t bytes_per_item = (otw_type.width * 2) / 8; + + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t num_samps = std::min( + boost::asio::buffer_size(buff)/io_type.size, + bytes_available/bytes_per_item + ); + + //setup the fragment flags and offset + metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += num_samps; //set for next time + + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + boost::asio::buffer_cast(state.copy_buff), otw_type, + boost::asio::buffer_cast(buff), io_type, + num_samps + ); + + //update the rx copy buffer to reflect the bytes copied + size_t bytes_copied = num_samps*bytes_per_item; + state.copy_buff = boost::asio::buffer( + boost::asio::buffer_cast(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + } + +} //namespace vrt_packet_handler + +#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index de0c76eb1..389460fe8 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -41,13 +41,6 @@ void usrp2_impl::io_init(void){ _tx_otw_type.shift = 0; _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; - - //initially empty copy buffer - _rx_copy_buff = asio::buffer("", 0); - - //init the expected rx seq number - _rx_stream_id_to_packet_seq[0] = 0; - //send a small data packet so the usrp2 knows the udp source port managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); @@ -69,51 +62,6 @@ void usrp2_impl::io_init(void){ _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0); } -/*********************************************************************** - * Receive Raw Data - **********************************************************************/ -void usrp2_impl::recv_raw(rx_metadata_t &metadata){ - //do a receive - _rx_smart_buff = _data_transport->get_recv_buff(); - - //unpack the vrt header - 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 = _rx_smart_buff->cast(); - 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 - get_master_clock_freq() - ); - }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 **********************************************************************/ @@ -172,42 +120,11 @@ size_t usrp2_impl::recv( rx_metadata_t &metadata, const io_type_t &io_type ){ - //perform a receive if no rx data is waiting to be copied - if (asio::buffer_size(_rx_copy_buff) == 0){ - _fragment_offset_in_samps = 0; - recv_raw(metadata); - } - //otherwise flag the metadata to show that is is a fragment - else{ - metadata = rx_metadata_t(); - } - - //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 = std::min( - asio::buffer_size(buff)/io_type.size, - bytes_to_copy/sizeof(boost::uint32_t) - ); - const boost::uint32_t *items = asio::buffer_cast(_rx_copy_buff); - - //setup the fragment flags and offset - metadata.more_fragments = asio::buffer_size(buff)/io_type.size < num_samps; - metadata.fragment_offset = _fragment_offset_in_samps; - _fragment_offset_in_samps += num_samps; //set for next time - - //copy-convert the samples from the recv buffer - convert_otw_type_to_io_type( - (const void*)items, _rx_otw_type, - asio::buffer_cast(buff), io_type, - num_samps - ); - - //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 vrt_packet_handler::recv( + _packet_handler_recv_state, //last state of the recv handler + buff, metadata, //buffer to fill and samples metadata + io_type, _rx_otw_type, //input and output types to convert + get_master_clock_freq(), //master clock tick rate + _data_transport //zero copy interface ); - - return num_samps; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e2d37e512..6958fc8ea 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -33,6 +33,7 @@ #include #include #include +#include "../../transport/vrt_packet_handler.hpp" /*! * Make a usrp2 dboard interface. @@ -121,10 +122,7 @@ private: codec_ctrl::sptr _codec_ctrl; serdes_ctrl::sptr _serdes_ctrl; - //the raw io interface (samples are in the usrp2 native format) - void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; - uhd::dict _rx_stream_id_to_packet_seq; /******************************************************************* * Deal with the rx and tx packet sizes @@ -147,9 +145,7 @@ private: return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); } - uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; - boost::asio::const_buffer _rx_copy_buff; - size_t _fragment_offset_in_samps; + vrt_packet_handler::recv_state _packet_handler_recv_state; uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); -- cgit v1.2.3 From 101afd526de722b6d30381340a7ca8148aa9a6d7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 18:47:33 -0700 Subject: Created inline send vrt packer function that also handles fragmentation. --- host/include/uhd/device.hpp | 11 +- host/include/uhd/types/otw_type.hpp | 6 + host/lib/transport/vrt_packet_handler.hpp | 280 ++++++++++++++++++++++-------- host/lib/types.cpp | 4 + host/lib/usrp/usrp2/io_impl.cpp | 48 +---- host/lib/usrp/usrp2/usrp2_impl.hpp | 7 +- 6 files changed, 232 insertions(+), 124 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ae75e6dc8..ecbe8c95c 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -80,12 +80,11 @@ public: * Send a buffer containing IF data with its metadata. * * Send handles fragmentation as follows: - * If the buffer has more samples than the maximum supported, - * the send method will send the maximum number of samples - * as supported by the transport and return the number sent. - * In this case, the end of burst flag will be forced to false. - * It is up to the caller to call send again on the un-sent - * portions of the buffer, until the buffer is exhausted. + * If the buffer has more samples than the maximum per packet, + * the send method will fragment the samples across several packets. + * Send will respect the burst flags when fragmenting to ensure + * that start of burst can only be set on the first fragment and + * that end of burst can only be set on the final fragment. * * This is a blocking call and will not return until the number * of samples returned have been read out of the buffer. diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp index f10664584..8e3e65d78 100644 --- a/host/include/uhd/types/otw_type.hpp +++ b/host/include/uhd/types/otw_type.hpp @@ -55,6 +55,12 @@ namespace uhd{ BO_NOT_APPLICABLE = '|' } byteorder; + /*! + * Get the sample size of this otw type. + * \return the size of a sample in bytes + */ + size_t get_sample_size(void) const; + otw_type_t(void); }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index a6161ef55..cd0c89b05 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -57,6 +57,49 @@ namespace vrt_packet_handler{ /* NOP */ } + /******************************************************************* + * Unpack a received vrt header and set the copy buffer. + * - helper function for vrt_packet_handler::recv + ******************************************************************/ + static inline void _recv_helper( + recv_state &state, + uhd::rx_metadata_t &metadata, + double tick_rate, + size_t vrt_header_offset_words32 + ){ + size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + if (num_packet_words32 <= vrt_header_offset_words32){ + state.copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + uhd::transport::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 + tick_rate + ); + + //handle the packet count / sequence number + if (packet_count_out != state.next_packet_seq){ + std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; + } + state.next_packet_seq = (packet_count_out+1)%16; + + //setup the buffer to point to the data + state.copy_buff = boost::asio::buffer( + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(boost::uint32_t) + ); + } + + /******************************************************************* + * Recv vrt packets and copy convert the samples into the buffer. + ******************************************************************/ static inline size_t recv( recv_state &state, const boost::asio::mutable_buffer &buff, @@ -65,95 +108,184 @@ namespace vrt_packet_handler{ const uhd::otw_type_t &otw_type, double tick_rate, uhd::transport::zero_copy_if::sptr zc_iface, + //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0, const recv_cb_t& recv_cb = &recv_cb_nop ){ - //////////////////////////////////////////////////////////////// - // Perform the recv - //////////////////////////////////////////////////////////////// - { - //perform a receive if no rx data is waiting to be copied - if (boost::asio::buffer_size(state.copy_buff) == 0){ - state.fragment_offset_in_samps = 0; - state.managed_buff = zc_iface->get_recv_buff(); - recv_cb(state.managed_buff); - } - //otherwise flag the metadata to show that is is a fragment - else{ - metadata = uhd::rx_metadata_t(); - goto vrt_recv_copy_convert; - } - } + metadata = uhd::rx_metadata_t(); //init the metadata - //////////////////////////////////////////////////////////////// - // Unpack the vrt header - //////////////////////////////////////////////////////////////// - { - size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); - if (num_packet_words32 <= vrt_header_offset_words32){ - state.copy_buff = boost::asio::buffer("", 0); - goto vrt_recv_copy_convert; //must exit here after setting the buffer - } - const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; - size_t num_header_words32_out, num_payload_words32_out, packet_count_out; - uhd::transport::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 - tick_rate + //perform a receive if no rx data is waiting to be copied + if (boost::asio::buffer_size(state.copy_buff) == 0){ + state.fragment_offset_in_samps = 0; + state.managed_buff = zc_iface->get_recv_buff(); + recv_cb(state.managed_buff); //callback before vrt unpack + _recv_helper( + state, metadata, tick_rate, vrt_header_offset_words32 ); + } - //handle the packet count / sequence number - if (packet_count_out != state.next_packet_seq){ - std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; - } - state.next_packet_seq = (packet_count_out+1)%16; + //extract the number of samples available to copy + size_t bytes_per_item = otw_type.get_sample_size(); + size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t num_samps = std::min( + boost::asio::buffer_size(buff)/io_type.size, + bytes_available/bytes_per_item + ); - //setup the buffer to point to the data - state.copy_buff = boost::asio::buffer( - vrt_hdr + num_header_words32_out, - num_payload_words32_out*sizeof(boost::uint32_t) - ); + //setup the fragment flags and offset + metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += num_samps; //set for next call + + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + boost::asio::buffer_cast(state.copy_buff), otw_type, + boost::asio::buffer_cast(buff), io_type, + num_samps + ); + + //update the rx copy buffer to reflect the bytes copied + size_t bytes_copied = num_samps*bytes_per_item; + state.copy_buff = boost::asio::buffer( + boost::asio::buffer_cast(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + +/*********************************************************************** + * vrt packet handler for send + **********************************************************************/ + struct send_state{ + //init the expected seq number + size_t next_packet_seq; + + send_state(void){ + next_packet_seq = 0; } + }; - //////////////////////////////////////////////////////////////// - // Perform copy-convert into buffer - //////////////////////////////////////////////////////////////// - vrt_recv_copy_convert:{ - size_t bytes_per_item = (otw_type.width * 2) / 8; - - //extract the number of samples available to copy - //and a pointer into the usrp2 received items memory - size_t bytes_available = boost::asio::buffer_size(state.copy_buff); - size_t num_samps = std::min( - boost::asio::buffer_size(buff)/io_type.size, - bytes_available/bytes_per_item - ); + typedef boost::function send_cb_t; - //setup the fragment flags and offset - metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; - metadata.fragment_offset = state.fragment_offset_in_samps; - state.fragment_offset_in_samps += num_samps; //set for next time + static inline void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ + /* NOP */ + } - //copy-convert the samples from the recv buffer - uhd::transport::convert_otw_type_to_io_type( - boost::asio::buffer_cast(state.copy_buff), otw_type, - boost::asio::buffer_cast(buff), io_type, - num_samps - ); + /******************************************************************* + * Pack a vrt header, copy-convert the data, and send it. + * - helper function for vrt_packet_handler::send + ******************************************************************/ + static inline void _send_helper( + send_state &state, + const void *send_mem, + size_t num_samps, + const uhd::tx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t vrt_header_offset_words32, + const send_cb_t& send_cb + ){ + //get a new managed send buffer + uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff(); + boost::uint32_t *tx_mem = send_buff->cast() + vrt_header_offset_words32; + + size_t num_header_words32, num_packet_words32; + size_t packet_count = state.next_packet_seq++; - //update the rx copy buffer to reflect the bytes copied - size_t bytes_copied = num_samps*bytes_per_item; - state.copy_buff = boost::asio::buffer( - boost::asio::buffer_cast(state.copy_buff) + bytes_copied, - bytes_available - bytes_copied + //pack metadata into a vrt header + uhd::transport::vrt::pack( + metadata, //input + tx_mem, //output + num_header_words32, //output + num_samps, //input + num_packet_words32, //output + packet_count, //input + tick_rate + ); + + //copy-convert the samples into the send buffer + uhd::transport::convert_io_type_to_otw_type( + send_mem, io_type, + tx_mem + num_header_words32, otw_type, + num_samps + ); + + send_cb(send_buff); //callback after memory filled + + //commit the samples to the zero-copy interface + send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); + } + + /******************************************************************* + * Send vrt packets and copy convert the samples into the buffer. + ******************************************************************/ + static inline size_t send( + send_state &state, + const boost::asio::const_buffer &buff, + const uhd::tx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t max_samples_per_packet, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32 = 0, + const send_cb_t& send_cb = &send_cb_nop + ){ + + size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + + //special case: no fragmentation needed + if (total_num_samps <= max_samples_per_packet){ + _send_helper( + state, + boost::asio::buffer_cast(buff), + total_num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb ); + return total_num_samps; + } - return num_samps; + //calculate constants for fragmentation + const size_t final_packet_samps = total_num_samps%max_samples_per_packet; + const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; + static const size_t first_fragment_index = 0; + const size_t final_fragment_index = num_fragments-1; + + //make a rw copy of the metadata to re-flag below + uhd::tx_metadata_t md(metadata); + + //loop through the following fragment indexes + for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + + //calculate new flags for the fragments + md.has_time_spec = md.has_time_spec and (n == first_fragment_index); + md.start_of_burst = md.start_of_burst and (n == first_fragment_index); + md.end_of_burst = md.end_of_burst and (n == final_fragment_index); + + //send the fragment with the helper function + _send_helper( + state, + boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), + (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + md, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb + ); } + + return total_num_samps; } } //namespace vrt_packet_handler diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 33eb550a1..87a2ad4ab 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -220,6 +220,10 @@ std::string mac_addr_t::to_string(void) const{ /*********************************************************************** * otw type **********************************************************************/ +size_t otw_type_t::get_sample_size(void) const{ + return (this->width * 2) / 8; +} + otw_type_t::otw_type_t(void){ width = 0; shift = 0; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 389460fe8..b26dbb8bd 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -67,49 +67,17 @@ void usrp2_impl::io_init(void){ **********************************************************************/ size_t usrp2_impl::send( const asio::const_buffer &buff, - const tx_metadata_t &metadata_, + const tx_metadata_t &metadata, const io_type_t &io_type ){ - tx_metadata_t metadata = metadata_; //rw copy to change later - - transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); - boost::uint32_t *tx_mem = send_buff->cast(); - size_t num_samps = std::min(std::min( - asio::buffer_size(buff)/io_type.size, - size_t(max_tx_samps_per_packet())), - send_buff->size()/io_type.size - ); - - //kill the end of burst flag if this is a fragment - if (asio::buffer_size(buff)/io_type.size < num_samps) - metadata.end_of_burst = false; - - 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 - tx_mem, //output - num_header_words32, //output - num_samps, //input - num_packet_words32, //output - packet_count, //input - get_master_clock_freq() - ); - - boost::uint32_t *items = tx_mem + num_header_words32; //offset for data - - //copy-convert the samples into the send buffer - convert_io_type_to_otw_type( - asio::buffer_cast(buff), io_type, - (void*)items, _tx_otw_type, - num_samps + return vrt_packet_handler::send( + _packet_handler_send_state, //last state of the send handler + buff, metadata, //buffer to empty and samples metadata + io_type, _tx_otw_type, //input and output types to convert + get_master_clock_freq(), //master clock tick rate + _data_transport, //zero copy interface + max_tx_samps_per_packet() ); - - //send and return number of samples - send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); - return num_samps; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 6958fc8ea..f98aa1938 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -122,8 +122,6 @@ private: codec_ctrl::sptr _codec_ctrl; serdes_ctrl::sptr _serdes_ctrl; - uhd::dict _tx_stream_id_to_packet_seq; - /******************************************************************* * Deal with the rx and tx packet sizes ******************************************************************/ @@ -139,13 +137,14 @@ private: uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; size_t max_rx_samps_per_packet(void){ - return _max_rx_bytes_per_packet/(_rx_otw_type.width*2/8); + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); } size_t max_tx_samps_per_packet(void){ - return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); } vrt_packet_handler::recv_state _packet_handler_recv_state; + vrt_packet_handler::send_state _packet_handler_send_state; uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); -- cgit v1.2.3 From eaa1508dcf6ff32496838f593ba4eb9eb1aee2ff Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 12:34:04 -0700 Subject: Added send and recv modes to the device class and packet handler implementation. --- host/include/uhd/device.hpp | 33 +++++- host/lib/transport/vrt_packet_handler.hpp | 178 ++++++++++++++++++++---------- host/lib/usrp/usrp2/io_impl.cpp | 10 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 14 ++- 4 files changed, 170 insertions(+), 65 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ecbe8c95c..a76b34ee2 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -76,6 +76,16 @@ public: */ static sptr make(const device_addr_t &hint, size_t which = 0); + /*! + * Send modes for the device send routine. + */ + enum send_mode_t{ + //! Tells the send routine to send the entire buffer + SEND_MODE_FULL_BUFF = 0, + //! Tells the send routine to return after one packet + SEND_MODE_ONE_PACKET = 1 + }; + /*! * Send a buffer containing IF data with its metadata. * @@ -85,6 +95,7 @@ public: * Send will respect the burst flags when fragmenting to ensure * that start of burst can only be set on the first fragment and * that end of burst can only be set on the final fragment. + * Fragmentation only applies in the full buffer send mode. * * This is a blocking call and will not return until the number * of samples returned have been read out of the buffer. @@ -92,14 +103,26 @@ public: * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param io_type the type of data loaded in the buffer + * \param send_mode tells send how to unload the buffer * \return the number of samples sent */ virtual size_t send( const boost::asio::const_buffer &buff, const tx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + send_mode_t send_mode = SEND_MODE_ONE_PACKET ) = 0; + /*! + * Recv modes for the device recv routine. + */ + enum recv_mode_t{ + //! Tells the recv routine to recv the entire buffer + RECV_MODE_FULL_BUFF = 0, + //! Tells the recv routine to return after one packet + RECV_MODE_ONE_PACKET = 1 + }; + /*! * Receive a buffer containing IF data and its metadata. * @@ -122,15 +145,21 @@ public: * immediately when no packets are available to the transport layer, * and that the timeout duration is reasonably tuned for performance. * + * When using the full buffer recv mode, the metadata only applies + * to the first packet received and written into the recv buffer. + * Use the one packet recv mode to get per packet metadata. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param io_type the type of data to fill into the buffer + * \param recv_mode tells recv how to load the buffer * \return the number of samples received */ virtual size_t recv( const boost::asio::mutable_buffer &buff, rx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + recv_mode_t recv_mode = RECV_MODE_ONE_PACKET ) = 0; }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index f6353ef99..c857db1c4 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -19,6 +19,7 @@ #define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP #include +#include #include #include #include @@ -60,9 +61,9 @@ namespace vrt_packet_handler{ /******************************************************************* * Unpack a received vrt header and set the copy buffer. - * - helper function for vrt_packet_handler::recv + * - helper function for vrt_packet_handler::_recv1 ******************************************************************/ - static UHD_INLINE void _recv_helper( + static UHD_INLINE void _recv1_helper( recv_state &state, uhd::rx_metadata_t &metadata, double tick_rate, @@ -99,28 +100,28 @@ namespace vrt_packet_handler{ } /******************************************************************* - * Recv vrt packets and copy convert the samples into the buffer. + * Recv data, unpack a vrt header, and copy-convert the data. + * - helper function for vrt_packet_handler::recv ******************************************************************/ - static UHD_INLINE size_t recv( + static UHD_INLINE size_t _recv1( recv_state &state, - const boost::asio::mutable_buffer &buff, + void *recv_mem, + size_t total_samps, uhd::rx_metadata_t &metadata, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, uhd::transport::zero_copy_if::sptr zc_iface, //use these two params to handle a layer above vrt - size_t vrt_header_offset_words32 = 0, - const recv_cb_t& recv_cb = &recv_cb_nop + size_t vrt_header_offset_words32, + const recv_cb_t& recv_cb ){ - metadata = uhd::rx_metadata_t(); //init the metadata - //perform a receive if no rx data is waiting to be copied if (boost::asio::buffer_size(state.copy_buff) == 0){ state.fragment_offset_in_samps = 0; state.managed_buff = zc_iface->get_recv_buff(); recv_cb(state.managed_buff); //callback before vrt unpack - _recv_helper( + _recv1_helper( state, metadata, tick_rate, vrt_header_offset_words32 ); } @@ -128,21 +129,17 @@ namespace vrt_packet_handler{ //extract the number of samples available to copy size_t bytes_per_item = otw_type.get_sample_size(); size_t bytes_available = boost::asio::buffer_size(state.copy_buff); - size_t num_samps = std::min( - boost::asio::buffer_size(buff)/io_type.size, - bytes_available/bytes_per_item - ); + size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); //setup the fragment flags and offset - metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.more_fragments = total_samps < num_samps; metadata.fragment_offset = state.fragment_offset_in_samps; state.fragment_offset_in_samps += num_samps; //set for next call //copy-convert the samples from the recv buffer uhd::transport::convert_otw_type_to_io_type( boost::asio::buffer_cast(state.copy_buff), otw_type, - boost::asio::buffer_cast(buff), io_type, - num_samps + recv_mem, io_type, num_samps ); //update the rx copy buffer to reflect the bytes copied @@ -155,6 +152,66 @@ namespace vrt_packet_handler{ return num_samps; } + /******************************************************************* + * Recv vrt packets and copy convert the samples into the buffer. + ******************************************************************/ + static UHD_INLINE size_t recv( + recv_state &state, + const boost::asio::mutable_buffer &buff, + uhd::rx_metadata_t &metadata, + uhd::device::recv_mode_t recv_mode, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32 = 0, + const recv_cb_t& recv_cb = &recv_cb_nop + ){ + metadata = uhd::rx_metadata_t(); //init the metadata + const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + + switch(recv_mode){ + + //////////////////////////////////////////////////////////////// + case uhd::device::RECV_MODE_ONE_PACKET:{ + //////////////////////////////////////////////////////////////// + return _recv1( + state, + boost::asio::buffer_cast(buff), + total_num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + recv_cb + ); + } + + //////////////////////////////////////////////////////////////// + case uhd::device::RECV_MODE_FULL_BUFF:{ + //////////////////////////////////////////////////////////////// + size_t num_samps = 0; + uhd::rx_metadata_t tmp_md; + while(num_samps < total_num_samps){ + num_samps += _recv1( + state, + boost::asio::buffer_cast(buff) + (num_samps*io_type.size), + total_num_samps - num_samps, + (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + recv_cb + ); + } + return total_num_samps; + } + }//switch(recv_mode) + } + /*********************************************************************** * vrt packet handler for send **********************************************************************/ @@ -177,7 +234,7 @@ namespace vrt_packet_handler{ * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send ******************************************************************/ - static UHD_INLINE void _send_helper( + static UHD_INLINE void _send1( send_state &state, const void *send_mem, size_t num_samps, @@ -227,6 +284,7 @@ namespace vrt_packet_handler{ send_state &state, const boost::asio::const_buffer &buff, const uhd::tx_metadata_t &metadata, + uhd::device::send_mode_t send_mode, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, @@ -236,15 +294,17 @@ namespace vrt_packet_handler{ size_t vrt_header_offset_words32 = 0, const send_cb_t& send_cb = &send_cb_nop ){ - - size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; - - //special case: no fragmentation needed - if (total_num_samps <= max_samples_per_packet){ - _send_helper( + const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + switch(send_mode){ + + //////////////////////////////////////////////////////////////// + case uhd::device::SEND_MODE_ONE_PACKET:{ + //////////////////////////////////////////////////////////////// + size_t num_samps = std::min(total_num_samps, max_samples_per_packet); + _send1( state, boost::asio::buffer_cast(buff), - total_num_samps, + num_samps, metadata, io_type, otw_type, tick_rate, @@ -252,41 +312,45 @@ namespace vrt_packet_handler{ vrt_header_offset_words32, send_cb ); - return total_num_samps; + return num_samps; } - //calculate constants for fragmentation - const size_t final_packet_samps = total_num_samps%max_samples_per_packet; - const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; - static const size_t first_fragment_index = 0; - const size_t final_fragment_index = num_fragments-1; - - //make a rw copy of the metadata to re-flag below - uhd::tx_metadata_t md(metadata); - - //loop through the following fragment indexes - for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ - - //calculate new flags for the fragments - md.has_time_spec = md.has_time_spec and (n == first_fragment_index); - md.start_of_burst = md.start_of_burst and (n == first_fragment_index); - md.end_of_burst = md.end_of_burst and (n == final_fragment_index); - - //send the fragment with the helper function - _send_helper( - state, - boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), - (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, - md, - io_type, otw_type, - tick_rate, - zc_iface, - vrt_header_offset_words32, - send_cb - ); + //////////////////////////////////////////////////////////////// + case uhd::device::SEND_MODE_FULL_BUFF:{ + //////////////////////////////////////////////////////////////// + //calculate constants for fragmentation + const size_t final_packet_samps = total_num_samps%max_samples_per_packet; + const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; + static const size_t first_fragment_index = 0; + const size_t final_fragment_index = num_fragments-1; + + //make a rw copy of the metadata to re-flag below + uhd::tx_metadata_t md(metadata); + + //loop through the following fragment indexes + for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + + //calculate new flags for the fragments + md.has_time_spec = md.has_time_spec and (n == first_fragment_index); + md.start_of_burst = md.start_of_burst and (n == first_fragment_index); + md.end_of_burst = md.end_of_burst and (n == final_fragment_index); + + //send the fragment with the helper function + _send1( + state, + boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), + (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + md, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb + ); + } + return total_num_samps; } - - return total_num_samps; + }//switch(send_mode) } } //namespace vrt_packet_handler diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b26dbb8bd..485cc2bd9 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -68,11 +68,12 @@ void usrp2_impl::io_init(void){ size_t usrp2_impl::send( const asio::const_buffer &buff, const tx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + send_mode_t send_mode ){ return vrt_packet_handler::send( _packet_handler_send_state, //last state of the send handler - buff, metadata, //buffer to empty and samples metadata + buff, metadata, send_mode, //buffer to empty and samples metadata io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport, //zero copy interface @@ -86,11 +87,12 @@ size_t usrp2_impl::send( size_t usrp2_impl::recv( const asio::mutable_buffer &buff, rx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + recv_mode_t recv_mode ){ return vrt_packet_handler::recv( _packet_handler_recv_state, //last state of the recv handler - buff, metadata, //buffer to fill and samples metadata + buff, metadata, recv_mode, //buffer to fill and samples metadata io_type, _rx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport //zero copy interface diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f98aa1938..ad674f594 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -104,8 +104,18 @@ public: ~usrp2_impl(void); //the io interface - size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &); - size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &); + size_t send( + const boost::asio::const_buffer &, + const uhd::tx_metadata_t &, + const uhd::io_type_t &, + uhd::device::send_mode_t + ); + size_t recv( + const boost::asio::mutable_buffer &, + uhd::rx_metadata_t &, + const uhd::io_type_t &, + uhd::device::recv_mode_t + ); private: double get_master_clock_freq(void){ -- cgit v1.2.3 From 17c494b79a99d947a150cdbc582ba331aeb57786 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 14:26:43 -0700 Subject: Added tx timed samples example. Added called to device to get max samples per packet. Removed device props that gave max samples per packet. --- host/examples/CMakeLists.txt | 4 ++ host/examples/rx_timed_samples.cpp | 13 +++-- host/examples/tx_timed_samples.cpp | 92 ++++++++++++++++++++++++++++++++++ host/include/uhd/device.hpp | 33 ++++++++---- host/include/uhd/usrp/device_props.hpp | 4 +- host/lib/usrp/usrp2/io_impl.cpp | 6 +-- host/lib/usrp/usrp2/mboard_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 8 --- host/lib/usrp/usrp2/usrp2_impl.hpp | 12 ++--- 9 files changed, 138 insertions(+), 36 deletions(-) create mode 100644 host/examples/tx_timed_samples.cpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 242857625..a537c0901 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -18,3 +18,7 @@ ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp) TARGET_LINK_LIBRARIES(rx_timed_samples uhd) INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) + +ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp) +TARGET_LINK_LIBRARIES(tx_timed_samples uhd) +INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 4b8774036..d2306c7c4 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -29,7 +29,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::string args; int seconds_in_future; size_t total_num_samps; - double rx_rate; + double rx_rate, freq; //setup the program options po::options_description desc("Allowed options"); @@ -39,10 +39,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to receive") ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to receive") ("rxrate", po::value(&rx_rate)->default_value(100e6/16), "rate of incoming samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); + po::notify(vm); //print the help message if (vm.count("help")){ @@ -62,6 +63,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ sdev->set_rx_rate(rx_rate); std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl; std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_rx_freq(freq); sdev->set_time_now(uhd::time_spec_t(0)); //setup streaming @@ -78,10 +80,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ size_t num_acc_samps = 0; //number of accumulated samples while(num_acc_samps < total_num_samps){ uhd::rx_metadata_t md; - std::complex buff[1000]; + std::vector > buff(dev->get_max_recv_samps_per_packet()); size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff, sizeof(buff)), - md, uhd::io_type_t::COMPLEX_FLOAT32 + boost::asio::buffer(buff), + md, uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET ); if (num_rx_samps == 0) continue; //wait for packets with contents diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp new file mode 100644 index 000000000..6dee69cd5 --- /dev/null +++ b/host/examples/tx_timed_samples.cpp @@ -0,0 +1,92 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + //variables to be set by po + std::string args; + int seconds_in_future; + size_t total_num_samps; + double tx_rate, freq; + float ampl; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit") + ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to transmit") + ("txrate", po::value(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") + ("ampl", po::value(&l)->default_value(0.3), "amplitude of each sample") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + + //set properties on the device + std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; + sdev->set_tx_rate(tx_rate); + std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl; + std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_tx_freq(freq); + sdev->set_time_now(uhd::time_spec_t(0)); + + //data to send + std::vector > buff(total_num_samps, std::complex(ampl, ampl)); + uhd::tx_metadata_t md; + md.start_of_burst = true; + md.end_of_burst = true; + md.has_time_spec = true; + md.time_spec = uhd::time_spec_t(seconds_in_future); + + //send the entire buffer, let the driver handle fragmentation + size_t num_tx_samps = dev->send( + boost::asio::buffer(buff), + md, uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; + + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index a76b34ee2..27b461184 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -86,6 +86,16 @@ public: SEND_MODE_ONE_PACKET = 1 }; + /*! + * Recv modes for the device recv routine. + */ + enum recv_mode_t{ + //! Tells the recv routine to recv the entire buffer + RECV_MODE_FULL_BUFF = 0, + //! Tells the recv routine to return after one packet + RECV_MODE_ONE_PACKET = 1 + }; + /*! * Send a buffer containing IF data with its metadata. * @@ -113,16 +123,6 @@ public: send_mode_t send_mode = SEND_MODE_ONE_PACKET ) = 0; - /*! - * Recv modes for the device recv routine. - */ - enum recv_mode_t{ - //! Tells the recv routine to recv the entire buffer - RECV_MODE_FULL_BUFF = 0, - //! Tells the recv routine to return after one packet - RECV_MODE_ONE_PACKET = 1 - }; - /*! * Receive a buffer containing IF data and its metadata. * @@ -161,6 +161,19 @@ public: const io_type_t &io_type, recv_mode_t recv_mode = RECV_MODE_ONE_PACKET ) = 0; + + /*! + * Get the maximum number of samples per packet on send. + * \return the number of samples + */ + virtual size_t get_max_send_samps_per_packet(void) const = 0; + + /*! + * Get the maximum number of samples per packet on recv. + * \return the number of samples + */ + virtual size_t get_max_recv_samps_per_packet(void) const = 0; + }; } //namespace uhd diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp index b8f6f5cd4..983bcb672 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/include/uhd/usrp/device_props.hpp @@ -31,9 +31,7 @@ namespace uhd{ namespace usrp{ enum device_prop_t{ DEVICE_PROP_NAME = 'n', //ro, std::string DEVICE_PROP_MBOARD = 'm', //ro, wax::obj - DEVICE_PROP_MBOARD_NAMES = 'M', //ro, prop_names_t - DEVICE_PROP_MAX_RX_SAMPLES = 'r', //ro, size_t - DEVICE_PROP_MAX_TX_SAMPLES = 't' //ro, size_t + DEVICE_PROP_MBOARD_NAMES = 'M' //ro, prop_names_t }; //////////////////////////////////////////////////////////////////////// diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 485cc2bd9..b6ab919e7 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -48,8 +48,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - std::cout << "RX samples per packet: " << max_rx_samps_per_packet() << std::endl; - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, max_rx_samps_per_packet()); + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -77,7 +77,7 @@ size_t usrp2_impl::send( io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport, //zero copy interface - max_tx_samps_per_packet() + get_max_send_samps_per_packet() ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index a10529102..f17efd88e 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? max_rx_samps_per_packet() : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 3b7156802..af3ec216a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -210,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); return; - case DEVICE_PROP_MAX_RX_SAMPLES: - val = max_rx_samps_per_packet(); - return; - - case DEVICE_PROP_MAX_TX_SAMPLES: - val = max_tx_samps_per_packet(); - return; - default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ad674f594..afea9683c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -104,12 +104,18 @@ public: ~usrp2_impl(void); //the io interface + size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } size_t send( const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &, uhd::device::send_mode_t ); + size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } size_t recv( const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, @@ -146,12 +152,6 @@ private: _mtu - _hdrs - uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; - size_t max_rx_samps_per_packet(void){ - return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); - } - size_t max_tx_samps_per_packet(void){ - return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); - } vrt_packet_handler::recv_state _packet_handler_recv_state; vrt_packet_handler::send_state _packet_handler_send_state; -- cgit v1.2.3 From 39943a5b0c3c210babfd6e62711ea4bf3133866b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 24 May 2010 16:31:23 -0700 Subject: Added support to set GPIO pins from dboard interface: write gpio and set pin control (atr or gpio) Added property to get dboard interface from the dboard obj. --- host/include/uhd/usrp/dboard_iface.hpp | 22 ++++++++++++++++++++-- host/include/uhd/usrp/dboard_props.hpp | 3 ++- host/lib/usrp/dboard/db_rfx.cpp | 4 +++- host/lib/usrp/dboard/db_wbx.cpp | 4 +++- host/lib/usrp/dboard/db_xcvr2450.cpp | 4 +++- host/lib/usrp/dboard_manager.cpp | 3 ++- host/lib/usrp/usrp2/dboard_iface.cpp | 34 ++++++++++++++++++++++++++-------- host/lib/usrp/usrp2/dboard_impl.cpp | 12 +++++++++--- host/lib/usrp/usrp2/usrp2_impl.hpp | 1 + host/lib/usrp/usrp2/usrp2_regs.hpp | 2 +- 10 files changed, 70 insertions(+), 19 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.hpp') diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index 1214a1a2f..7ecfcd3c0 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -67,23 +67,41 @@ public: */ virtual float read_aux_adc(unit_t unit, int which_adc) = 0; + /*! + * Set a daughterboard output pin control source. + * By default, the outputs are all GPIO controlled. + * + * \param unit which unit rx or tx + * \param value 16-bits, 0=GPIO controlled, 1=ATR controlled + */ + virtual void set_pin_ctrl(unit_t unit, boost::uint16_t value) = 0; + /*! * Set a daughterboard ATR register. * * \param unit which unit rx or tx * \param reg which ATR register to set - * \param value 16-bits, 0=FPGA output low, 1=FPGA output high + * \param value 16-bits, 0=ATR output low, 1=ATR output high */ virtual void set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint16_t value) = 0; /*! * Set daughterboard GPIO data direction register. + * By default, the GPIO pins are all inputs. * * \param unit which unit rx or tx - * \param value 16-bits, 0=FPGA input, 1=FPGA output + * \param value 16-bits, 0=GPIO input, 1=GPIO output */ virtual void set_gpio_ddr(unit_t unit, boost::uint16_t value) = 0; + /*! + * Read daughterboard GPIO pin values. + * + * \param unit which unit rx or tx + * \param value 16-bits, 0=GPIO output low, 1=GPIO output high + */ + virtual void write_gpio(unit_t unit, boost::uint16_t value) = 0; + /*! * Read daughterboard GPIO pin values. * diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp index 0208a6c2c..4d5c5efbd 100644 --- a/host/include/uhd/usrp/dboard_props.hpp +++ b/host/include/uhd/usrp/dboard_props.hpp @@ -30,7 +30,8 @@ namespace uhd{ namespace usrp{ DBOARD_PROP_SUBDEV = 's', //ro, wax::obj DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t DBOARD_PROP_USED_SUBDEVS = 'u', //ro, prop_names_t - DBOARD_PROP_DBOARD_ID = 'i' //rw, dboard_id_t + DBOARD_PROP_DBOARD_ID = 'i', //rw, dboard_id_t + DBOARD_PROP_DBOARD_IFACE = 'f' //ro, dboard_iface::sptr //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet }; diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 7bfd14943..89e707718 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -176,8 +176,10 @@ rfx_xcvr::rfx_xcvr( this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); - //set the gpio directions + //set the gpio directions and atr controls (identically) boost::uint16_t output_enables = POWER_IO | ANTSW_IO | MIXER_IO; + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, output_enables); + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, output_enables); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, output_enables); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables); diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 81edf7a11..23654860f 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -164,7 +164,9 @@ wbx_xcvr::wbx_xcvr( this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); - //set the gpio directions + //set the gpio directions and atr controls (identically) + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK); + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK); if (wbx_debug) std::cerr << boost::format( diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 3472229f4..d4d5f184e 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -169,7 +169,9 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){ //enable only the clocks we need this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); - //set the gpio directions + //set the gpio directions and atr controls (identically) + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK); + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK); diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 8161727e5..01352039e 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -298,7 +298,8 @@ void dboard_manager_impl::set_nice_dboard_if(void){ //set nice settings on each unit BOOST_FOREACH(dboard_iface::unit_t unit, units){ _iface->set_gpio_ddr(unit, 0x0000); //all inputs - _iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, 0x0000); //all low + _iface->write_gpio(unit, 0x0000); //all low + _iface->set_pin_ctrl(unit, 0x0000); //all gpio _iface->set_clock_enabled(unit, false); //clock off } } diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index d33a11fd6..0a2e4b550 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -39,8 +39,10 @@ public: void write_aux_dac(unit_t, int, float); float read_aux_adc(unit_t, int); + void set_pin_ctrl(unit_t, boost::uint16_t); void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); void set_gpio_ddr(unit_t, boost::uint16_t); + void write_gpio(unit_t, boost::uint16_t); boost::uint16_t read_gpio(unit_t); void write_i2c(boost::uint8_t, const byte_vector_t &); @@ -68,6 +70,7 @@ private: usrp2_iface::sptr _iface; clock_ctrl::sptr _clock_ctrl; boost::uint32_t _ddr_shadow; + boost::uint32_t _gpio_shadow; uhd::dict _dac_regs; void _write_aux_dac(unit_t); @@ -90,14 +93,7 @@ usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr _iface = iface; _clock_ctrl = clock_ctrl; _ddr_shadow = 0; - - //set the selection mux to use atr - boost::uint32_t new_sels = 0x0; - for(size_t i = 0; i < 16; i++){ - new_sels |= FRF_GPIO_SEL_ATR << (i*2); - } - _iface->poke32(FR_GPIO_TX_SEL, new_sels); - _iface->poke32(FR_GPIO_RX_SEL, new_sels); + _gpio_shadow = 0; //reset the aux dacs _dac_regs[UNIT_RX] = ad5624_regs_t(); @@ -136,6 +132,21 @@ static const uhd::dict unit_to_shift = map_list_of (dboard_iface::UNIT_TX, 16) ; +void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){ + //calculate the new selection mux setting + boost::uint32_t new_sels = 0x0; + for(size_t i = 0; i < 16; i++){ + bool is_bit_set = bool(value & (0x1 << i)); + new_sels |= ((is_bit_set)? FRF_GPIO_SEL_ATR : FRF_GPIO_SEL_GPIO) << (i*2); + } + + //write the selection mux value to register + switch(unit){ + case UNIT_RX: _iface->poke32(FR_GPIO_RX_SEL, new_sels); return; + case UNIT_TX: _iface->poke32(FR_GPIO_TX_SEL, new_sels); return; + } +} + void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){ _ddr_shadow = \ (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) | @@ -143,6 +154,13 @@ void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){ _iface->poke32(FR_GPIO_DDR, _ddr_shadow); } +void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){ + _gpio_shadow = \ + (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) | + (boost::uint32_t(value) << unit_to_shift[unit]); + _iface->poke32(FR_GPIO_IO, _gpio_shadow); +} + boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){ return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift[unit]); } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 0f8a739f2..0ac39d2a3 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -38,9 +38,7 @@ void usrp2_impl::dboard_init(void){ _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); //create a new dboard interface and manager - dboard_iface::sptr _dboard_iface( - make_usrp2_dboard_iface(_iface, _clock_ctrl) - ); + _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl); _dboard_manager = dboard_manager::make( _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface ); @@ -123,6 +121,10 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _rx_db_eeprom.id; return; + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } @@ -172,6 +174,10 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _tx_db_eeprom.id; return; + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index afea9683c..7948a2069 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -169,6 +169,7 @@ private: //rx and tx dboard methods and objects uhd::usrp::dboard_manager::sptr _dboard_manager; + uhd::usrp::dboard_iface::sptr _dboard_iface; void dboard_init(void); //properties for the mboard diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index feeccaa34..0f675357b 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -204,7 +204,7 @@ #define FR_GPIO_RX_SEL FR_GPIO_BASE + 12 // 16 2-bit fields select which source goes to RX DB // each 2-bit sel field is layed out this way -#define FRF_GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg +#define FRF_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register #define FRF_GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic #define FRF_GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric #define FRF_GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric -- cgit v1.2.3