diff options
author | Josh Blum <josh@joshknows.com> | 2012-02-17 18:18:26 -0800 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2012-02-17 18:18:26 -0800 |
commit | 3ddbcb6078593c39cb0e4bc8f9769f818a61466f (patch) | |
tree | 408e3f6a64e31b7d830b9f884ecebdaf100a5d2d /host/lib/usrp | |
parent | 1fab7e9d477aa98e489400c25a08358952c69c90 (diff) | |
parent | ace4489066d1621a09e70650a00d736f0b03ed8c (diff) | |
download | uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.tar.gz uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.tar.bz2 uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.zip |
Merge branch 'next'
Diffstat (limited to 'host/lib/usrp')
31 files changed, 502 insertions, 223 deletions
diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp index 7d40daa32..e6136c00e 100644 --- a/host/lib/usrp/b100/b100_ctrl.cpp +++ b/host/lib/usrp/b100/b100_ctrl.cpp @@ -165,7 +165,7 @@ int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) { pkt.pkt_meta.seq = _seq++; pkt.pkt_meta.len = pkt.data.size(); pkt.pkt_meta.addr = addr; - boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)]; + boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)] = {}; pack_ctrl_pkt(pkt_buff, pkt); size_t result = send_pkt(pkt_buff); @@ -181,7 +181,7 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) { pkt.pkt_meta.seq = _seq++; pkt.pkt_meta.len = len; pkt.pkt_meta.addr = addr; - boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)]; + boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)] = {}; //flush anything that might be in the queue while (get_ctrl_data(pkt.data, 0.0)){ diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index 61bc58bce..8b55494c5 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2012 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 @@ -150,6 +150,10 @@ UHD_STATIC_BLOCK(register_b100_device){ * Structors **********************************************************************/ b100_impl::b100_impl(const device_addr_t &device_addr){ + size_t initialization_count = 0; + b100_impl_constructor_begin: + initialization_count++; + _tree = property_tree::make(); //extract the FPGA path for the B100 @@ -181,6 +185,8 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //load FPGA image, gpif is disabled while loading this->enable_gpif(false); _fx2_ctrl->usrp_load_fpga(b100_fpga_image); + _fx2_ctrl->usrp_fpga_reset(false); //active low reset + _fx2_ctrl->usrp_fpga_reset(true); this->enable_gpif(true); //create the control transport @@ -196,13 +202,28 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ 3, 4, //interface, endpoint ctrl_xport_args ); + while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport //////////////////////////////////////////////////////////////////// // Initialize FPGA wishbone communication //////////////////////////////////////////////////////////////////// _fpga_ctrl = b100_ctrl::make(_ctrl_transport); - this->reset_gpif(6); //always reset first to ensure communication _fpga_ctrl->poke32(B100_REG_GLOBAL_RESET, 0); //global fpga reset + //perform a test peek operation + try{ + _fpga_ctrl->peek32(0); + } + //try reset once in the case of failure + catch(const uhd::exception &e){ + if (initialization_count > 1) throw; + UHD_MSG(warning) << + "The control endpoint was left in a bad state.\n" + "Attempting endpoint re-enumeration...\n" << std::endl; + _fpga_ctrl.reset(); + _ctrl_transport.reset(); + _fx2_ctrl->usrp_fx2_reset(); + goto b100_impl_constructor_begin; + } this->check_fpga_compat(); //check after reset and making control //////////////////////////////////////////////////////////////////// @@ -229,8 +250,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ 2, 6, // IN interface, endpoint 1, 2, // OUT interface, endpoint data_xport_args // param hints - ) + ), + B100_MAX_PKT_BYTE_LIMIT ); + while (_data_transport->get_recv_buff(0.0)){} //flush data xport //////////////////////////////////////////////////////////////////// // Initialize the properties tree @@ -361,10 +384,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ // create time control objects //////////////////////////////////////////////////////////////////// time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_secs_now = B100_REG_RB_TIME_NOW_SECS; - time64_rb_bases.rb_ticks_now = B100_REG_RB_TIME_NOW_TICKS; - time64_rb_bases.rb_secs_pps = B100_REG_RB_TIME_PPS_SECS; - time64_rb_bases.rb_ticks_pps = B100_REG_RB_TIME_PPS_TICKS; + time64_rb_bases.rb_hi_now = B100_REG_RB_TIME_NOW_HI; + time64_rb_bases.rb_lo_now = B100_REG_RB_TIME_NOW_LO; + time64_rb_bases.rb_hi_pps = B100_REG_RB_TIME_PPS_HI; + time64_rb_bases.rb_lo_pps = B100_REG_RB_TIME_PPS_LO; _time64 = time64_core_200::make( _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases ); @@ -388,6 +411,13 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); //////////////////////////////////////////////////////////////////// + // create user-defined control objects + //////////////////////////////////////////////////////////////////// + _user = user_settings_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_USER_REGS)); + _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs") + .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1)); + + //////////////////////////////////////////////////////////////////// // create dboard control objects //////////////////////////////////////////////////////////////////// @@ -505,10 +535,6 @@ void b100_impl::update_clock_source(const std::string &source){ } ////////////////// some GPIF preparation related stuff ///////////////// -void b100_impl::reset_gpif(const boost::uint16_t ep) { - _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0); -} - void b100_impl::enable_gpif(const bool en) { _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0); } diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp index 96d90b14c..eab9c750b 100644 --- a/host/lib/usrp/b100/b100_impl.hpp +++ b/host/lib/usrp/b100/b100_impl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 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 @@ -29,6 +29,7 @@ #include "rx_dsp_core_200.hpp" #include "tx_dsp_core_200.hpp" #include "time64_core_200.hpp" +#include "user_settings_core_200.hpp" #include <uhd/device.hpp> #include <uhd/property_tree.hpp> #include <uhd/utils/pimpl.hpp> @@ -43,14 +44,15 @@ #include <uhd/transport/usb_zero_copy.hpp> #include <boost/weak_ptr.hpp> -static const double B100_LINK_RATE_BPS = 256e6/8; //pratical link rate (< 480 Mbps) +static const double B100_LINK_RATE_BPS = 256e6/5; //pratical link rate (< 480 Mbps) static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx"; static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin"; -static const boost::uint16_t B100_FW_COMPAT_NUM = 0x02; -static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x08; +static const boost::uint16_t B100_FW_COMPAT_NUM = 0x03; +static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x09; static const boost::uint32_t B100_RX_SID_BASE = 2; static const boost::uint32_t B100_TX_ASYNC_SID = 1; static const double B100_DEFAULT_TICK_RATE = 64e6; +static const size_t B100_MAX_PKT_BYTE_LIMIT = 2048; //! Make a b100 dboard interface uhd::usrp::dboard_iface::sptr make_b100_dboard_iface( @@ -84,6 +86,7 @@ private: std::vector<rx_dsp_core_200::sptr> _rx_dsps; tx_dsp_core_200::sptr _tx_dsp; time64_core_200::sptr _time64; + user_settings_core_200::sptr _user; b100_clock_ctrl::sptr _clock_ctrl; b100_codec_ctrl::sptr _codec_ctrl; b100_ctrl::sptr _fpga_ctrl; @@ -120,7 +123,6 @@ private: void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &); void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &); void update_clock_source(const std::string &); - void reset_gpif(const boost::uint16_t); void enable_gpif(const bool); void clear_fpga_fifo(void); void handle_async_message(uhd::transport::managed_recv_buffer::sptr); diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp index 491e16eef..987a09f03 100644 --- a/host/lib/usrp/b100/b100_regs.hpp +++ b/host/lib/usrp/b100/b100_regs.hpp @@ -1,4 +1,19 @@ - +// +// Copyright 2010-2012 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/>. +// //////////////////////////////////////////////////////////////// // @@ -27,10 +42,6 @@ #define B100_REG_MISC_SW B100_REG_MISC_BASE + 2 #define B100_REG_MISC_CGEN_CTRL B100_REG_MISC_BASE + 4 #define B100_REG_MISC_CGEN_ST B100_REG_MISC_BASE + 6 -#define B100_REG_MISC_TEST B100_REG_MISC_BASE + 8 -#define B100_REG_MISC_RX_LEN B100_REG_MISC_BASE + 10 -#define B100_REG_MISC_TX_LEN B100_REG_MISC_BASE + 12 -#define B100_REG_MISC_XFER_RATE B100_REG_MISC_BASE + 14 ///////////////////////////////////////////////////// // Slave 1 -- UART @@ -65,10 +76,10 @@ #define B100_REG_RB_MUX_32_BASE B100_REG_SLAVE(7) -#define B100_REG_RB_TIME_NOW_SECS B100_REG_RB_MUX_32_BASE + 0 -#define B100_REG_RB_TIME_NOW_TICKS B100_REG_RB_MUX_32_BASE + 4 -#define B100_REG_RB_TIME_PPS_SECS B100_REG_RB_MUX_32_BASE + 8 -#define B100_REG_RB_TIME_PPS_TICKS B100_REG_RB_MUX_32_BASE + 12 +#define B100_REG_RB_TIME_NOW_HI B100_REG_RB_MUX_32_BASE + 0 +#define B100_REG_RB_TIME_NOW_LO B100_REG_RB_MUX_32_BASE + 4 +#define B100_REG_RB_TIME_PPS_HI B100_REG_RB_MUX_32_BASE + 8 +#define B100_REG_RB_TIME_PPS_LO B100_REG_RB_MUX_32_BASE + 12 #define B100_REG_RB_MISC_TEST32 B100_REG_RB_MUX_32_BASE + 16 #define B100_REG_RB_COMPAT B100_REG_RB_MUX_32_BASE + 24 #define B100_REG_RB_GPIO B100_REG_RB_MUX_32_BASE + 28 @@ -92,9 +103,9 @@ #define B100_SR_TX_FRONT 54 // 5 regs (+0 to +4) #define B100_SR_REG_TEST32 60 // 1 reg -#define B100_SR_CLEAR_RX_FIFO 61 // 1 reg -#define B100_SR_CLEAR_TX_FIFO 62 // 1 reg +#define B100_SR_CLEAR_FIFO 61 // 1 reg #define B100_SR_GLOBAL_RESET 63 // 1 reg +#define B100_SR_USER_REGS 64 // 2 regs #define B100_SR_GPIO 128 @@ -105,8 +116,7 @@ ///////////////////////////////////////////////// // Magic reset regs //////////////////////////////////////////////// -#define B100_REG_CLEAR_RX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO) -#define B100_REG_CLEAR_TX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO) +#define B100_REG_CLEAR_FIFO B100_REG_SR_ADDR(B100_SR_CLEAR_FIFO) #define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET) #endif diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp index 494d5d123..674380cca 100644 --- a/host/lib/usrp/b100/io_impl.cpp +++ b/host/lib/usrp/b100/io_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 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 @@ -17,6 +17,7 @@ #include "recv_packet_demuxer.hpp" #include "validate_subdev_spec.hpp" +#include "async_packet_handler.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include "usrp_commands.h" @@ -41,12 +42,13 @@ using namespace uhd::transport; **********************************************************************/ struct b100_impl::io_impl{ io_impl(void): - async_msg_fifo(100/*messages deep*/) + async_msg_fifo(1000/*messages deep*/) { /* NOP */ } zero_copy_if::sptr data_transport; bounded_buffer<async_metadata_t> async_msg_fifo; recv_packet_demuxer::sptr demuxer; + double tick_rate; }; /*********************************************************************** @@ -54,12 +56,8 @@ struct b100_impl::io_impl{ **********************************************************************/ void b100_impl::io_init(void){ - //clear state machines - _fpga_ctrl->poke32(B100_REG_CLEAR_RX, 0); - _fpga_ctrl->poke32(B100_REG_CLEAR_TX, 0); - - //set the expected packet size in USB frames - _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4); + //clear fifo state machines + _fpga_ctrl->poke32(B100_REG_CLEAR_FIFO, 0); //allocate streamer weak ptrs containers _rx_streamers.resize(_rx_dsps.size()); @@ -85,26 +83,16 @@ void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){ } if (if_packet_info.sid == B100_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + //fill in the async metadata async_metadata_t metadata; - metadata.channel = 0; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), _clock_ctrl->get_fpga_clock_rate() - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); + load_metadata_from_buff(uhd::wtohx<boost::uint32_t>, metadata, if_packet_info, vrt_hdr, _io_impl->tick_rate); + + //push the message onto the queue _io_impl->async_msg_fifo.push_with_pop_on_full(metadata); - if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) - ) UHD_MSG(fastpath) << "U"; - else if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_SEQ_ERROR - | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) - ) UHD_MSG(fastpath) << "S"; - else if (metadata.event_code & - async_metadata_t::EVENT_CODE_TIME_ERROR - ) UHD_MSG(fastpath) << "L"; + + //print some fastpath messages + standard_async_msg_prints(metadata); } else UHD_MSG(error) << "Unknown async packet" << std::endl; } @@ -123,6 +111,8 @@ void b100_impl::update_rates(void){ } void b100_impl::update_tick_rate(const double rate){ + _io_impl->tick_rate = rate; + //update the tick rate on all existing streamers -> thread safe for (size_t i = 0; i < _rx_streamers.size(); i++){ boost::shared_ptr<sph::recv_packet_streamer> my_streamer = @@ -154,6 +144,8 @@ void b100_impl::update_tx_samp_rate(const size_t dspno, const double rate){ if (my_streamer.get() == NULL) return; my_streamer->set_samp_rate(rate); + const double adj = _tx_dsp->get_scaling_adjustment(); + my_streamer->set_scale_factor(adj); } void b100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ @@ -202,15 +194,15 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){ //setup defaults for unspecified values args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400)); //calculate packet size static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; - const size_t bpp = 2048 - hdr_size; //limited by FPGA pkt buffer size + const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size; const size_t bpi = convert::get_bytes_per_item(args.otw_format); const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); @@ -233,8 +225,7 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){ for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){ const size_t dsp = args.channels[chan_i]; _rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this - if (not args.args.has_key("noclear")) _rx_dsps[dsp]->clear(); - _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar); + _rx_dsps[dsp]->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1 ), true /*flush*/); @@ -260,16 +251,15 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){ args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - if (args.otw_format != "sc16"){ - throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format); - } - //calculate packet size static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; - static const size_t bpp = 2048 - hdr_size; + static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size; const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format); //make the new streamer given the samples per packet @@ -291,8 +281,7 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){ for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){ const size_t dsp = args.channels[chan_i]; UHD_ASSERT_THROW(dsp == 0); //always 0 - if (not args.args.has_key("noclear")) _tx_dsp->clear(); - if (args.args.has_key("underflow_policy")) _tx_dsp->set_underflow_policy(args.args["underflow_policy"]); + _tx_dsp->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( &zero_copy_if::get_send_buff, _data_transport, _1 )); diff --git a/host/lib/usrp/common/async_packet_handler.hpp b/host/lib/usrp/common/async_packet_handler.hpp new file mode 100644 index 000000000..fef03483f --- /dev/null +++ b/host/lib/usrp/common/async_packet_handler.hpp @@ -0,0 +1,71 @@ +// +// Copyright 2012 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/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP + +#include <uhd/config.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/msg.hpp> + +namespace uhd{ namespace usrp{ + + template <typename to_host_type> + void load_metadata_from_buff( + const to_host_type &to_host, + async_metadata_t &metadata, + const transport::vrt::if_packet_info_t &if_packet_info, + const boost::uint32_t *vrt_hdr, + const double tick_rate, + const size_t channel = 0 + ){ + const boost::uint32_t *payload = vrt_hdr + if_packet_info.num_header_words32; + + //load into metadata + metadata.channel = channel; + metadata.has_time_spec = if_packet_info.has_tsf; + metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate); + metadata.event_code = async_metadata_t::event_code_t(to_host(payload[0]) & 0xff); + + //load user payload + for (size_t i = 1; i < if_packet_info.num_payload_words32; i++){ + if (i-1 == 4) break; //limit of 4 words32 + metadata.user_payload[i-1] = to_host(payload[i]); + } + } + + UHD_INLINE void standard_async_msg_prints(const async_metadata_t &metadata) + { + if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_UNDERFLOW + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_SEQ_ERROR + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; + else if (metadata.event_code & + async_metadata_t::EVENT_CODE_TIME_ERROR + ) UHD_MSG(fastpath) << "L"; + } + + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP */ diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp index 3c6df7079..7b8920eb1 100644 --- a/host/lib/usrp/common/fx2_ctrl.cpp +++ b/host/lib/usrp/common/fx2_ctrl.cpp @@ -139,6 +139,15 @@ public: _ctrl_transport = ctrl_transport; } + void usrp_fx2_reset(void){ + unsigned char reset_y = 1; + unsigned char reset_n = 0; + usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); + usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); + //wait for things to settle + boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); + } + void usrp_load_firmware(std::string filestring, bool force) { const char *filename = filestring.c_str(); @@ -419,7 +428,7 @@ public: { UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); - unsigned char buff[max_i2c_data_bytes]; + unsigned char buff[max_i2c_data_bytes] = {}; std::copy(bytes.begin(), bytes.end(), buff); int ret = this->usrp_i2c_write(addr & 0xff, @@ -434,7 +443,7 @@ public: { UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); - unsigned char buff[max_i2c_data_bytes]; + unsigned char buff[max_i2c_data_bytes] = {}; int ret = this->usrp_i2c_read(addr & 0xff, buff, num_bytes); diff --git a/host/lib/usrp/common/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp index 691d64275..f2e060862 100644 --- a/host/lib/usrp/common/fx2_ctrl.hpp +++ b/host/lib/usrp/common/fx2_ctrl.hpp @@ -39,6 +39,9 @@ public: //! Call init after the fpga is loaded virtual void usrp_init(void) = 0; + //! For emergency situations + virtual void usrp_fx2_reset(void) = 0; + /*! * Load firmware in Intel HEX Format onto device * \param filename name of firmware file @@ -116,6 +119,9 @@ public: //! enable/disable the tx path virtual void usrp_tx_enable(bool on) = 0; + + //! reset the fpga + virtual void usrp_fpga_reset(bool on) = 0; }; }} //namespace uhd::usrp diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt index 2aa8f6b99..aa5f0bcbb 100644 --- a/host/lib/usrp/cores/CMakeLists.txt +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2011 Ettus Research LLC +# Copyright 2011-2012 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 @@ -30,4 +30,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_200.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_200.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tx_frontend_core_200.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_core_200.cpp ) diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp index 2e21cc895..0996952ff 100644 --- a/host/lib/usrp/cores/rx_dsp_core_200.cpp +++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 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 @@ -18,6 +18,7 @@ #include "rx_dsp_core_200.hpp" #include <uhd/types/dict.hpp> #include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> #include <uhd/utils/algorithm.hpp> #include <boost/assign/list_of.hpp> #include <boost/thread/thread.hpp> //thread sleep @@ -27,7 +28,7 @@ #include <cmath> #define REG_DSP_RX_FREQ _dsp_base + 0 -//skip one right here +#define REG_DSP_RX_SCALE_IQ _dsp_base + 4 #define REG_DSP_RX_DECIM _dsp_base + 8 #define REG_DSP_RX_MUX _dsp_base + 12 @@ -35,15 +36,15 @@ #define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) #define REG_RX_CTRL_STREAM_CMD _ctrl_base + 0 -#define REG_RX_CTRL_TIME_SECS _ctrl_base + 4 -#define REG_RX_CTRL_TIME_TICKS _ctrl_base + 8 +#define REG_RX_CTRL_TIME_HI _ctrl_base + 4 +#define REG_RX_CTRL_TIME_LO _ctrl_base + 8 #define REG_RX_CTRL_CLEAR _ctrl_base + 12 #define REG_RX_CTRL_VRT_HDR _ctrl_base + 16 #define REG_RX_CTRL_VRT_SID _ctrl_base + 20 #define REG_RX_CTRL_VRT_TLR _ctrl_base + 24 #define REG_RX_CTRL_NSAMPS_PP _ctrl_base + 28 #define REG_RX_CTRL_NCHANNELS _ctrl_base + 32 -#define REG_RX_CTRL_FORMAT _ctrl_base + 36 +#define REG_RX_CTRL_FORMAT REG_RX_CTRL_CLEAR //re-use clear address template <class T> T ceil_log2(T num){ return std::ceil(std::log(num)/std::log(T(2))); @@ -60,6 +61,10 @@ public: ): _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid) { + //init to something so update method has reasonable defaults + _scaling_adjustment = 1.0; + _dsp_extra_scaling = 1.0; + //This is a hack/fix for the lingering packet problem. //The caller should also flush the recv transports if (lingering_packet){ @@ -78,7 +83,6 @@ public: _iface->poke32(REG_RX_CTRL_VRT_HDR, 0 | (0x1 << 28) //if data with stream id | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other | (0x1 << 20) //fractional time sample count ); _iface->poke32(REG_RX_CTRL_VRT_SID, _sid); @@ -117,8 +121,9 @@ public: //issue the stream command _iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word); - _iface->poke32(REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_tick_rate)); //latches the command + const boost::uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(_tick_rate); + _iface->poke32(REG_RX_CTRL_TIME_HI, boost::uint32_t(ticks >> 32)); + _iface->poke32(REG_RX_CTRL_TIME_LO, boost::uint32_t(ticks >> 0)); //latches the command } void set_mux(const std::string &mode, const bool fe_swapped){ @@ -175,12 +180,20 @@ public: // Calculate closest multiplier constant to reverse gain absent scale multipliers const double rate_pow = std::pow(double(decim & 0xff), 4); _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow); + this->update_scalar(); return _tick_rate/decim_rate; } + void update_scalar(void){ + const double target_scalar = (1 << 16)*_scaling_adjustment/_dsp_extra_scaling; + const boost::int32_t actual_scalar = boost::math::iround(target_scalar); + _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small + _iface->poke32(REG_DSP_RX_SCALE_IQ, actual_scalar); + } + double get_scaling_adjustment(void){ - return _scaling_adjustment/_fxpt_scale_adj; + return _fxpt_scalar_correction*_host_extra_scaling/32767.; } double set_freq(const double freq_){ @@ -210,22 +223,27 @@ public: if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); } - void set_format(const std::string &format, const unsigned scale){ + void setup(const uhd::stream_args_t &stream_args){ + if (not stream_args.args.has_key("noclear")) this->clear(); + unsigned format_word = 0; - if (format == "sc16"){ + if (stream_args.otw_format == "sc16"){ format_word = 0; - _fxpt_scale_adj = 32767.; + _dsp_extra_scaling = 1.0; + _host_extra_scaling = 1.0; } - else if (format == "sc8"){ - format_word = (1 << 18); - _fxpt_scale_adj = 127. * scale; - _fxpt_scale_adj /= 256; //engine 16to8 drops lower 8 bits - _fxpt_scale_adj /= 4; //scale operation 2-bit pad + else if (stream_args.otw_format == "sc8"){ + format_word = (1 << 0); + double peak = stream_args.args.cast<double>("peak", 1.0); + peak = std::max(peak, 1.0/256); + _host_extra_scaling = peak*256; + _dsp_extra_scaling = peak*256; } - else throw uhd::value_error("USRP RX cannot handle requested wire format: " + format); + else throw uhd::value_error("USRP RX cannot handle requested wire format: " + stream_args.otw_format); + + this->update_scalar(); - const unsigned scale_word = scale & 0x3ffff; //18 bits; - _iface->poke32(REG_RX_CTRL_FORMAT, format_word | scale_word); + _iface->poke32(REG_RX_CTRL_FORMAT, format_word); } private: @@ -233,7 +251,7 @@ private: const size_t _dsp_base, _ctrl_base; double _tick_rate, _link_rate; bool _continuous_streaming; - double _scaling_adjustment, _fxpt_scale_adj; + double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction; const boost::uint32_t _sid; }; diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp index 58be51eee..b01f751e9 100644 --- a/host/lib/usrp/cores/rx_dsp_core_200.hpp +++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp @@ -19,6 +19,7 @@ #define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP #include <uhd/config.hpp> +#include <uhd/stream.hpp> #include <uhd/types/ranges.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> @@ -60,7 +61,7 @@ public: virtual void handle_overflow(void) = 0; - virtual void set_format(const std::string &format, const unsigned scale) = 0; + virtual void setup(const uhd::stream_args_t &stream_args) = 0; }; #endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp index 23d1bdea2..e460d1106 100644 --- a/host/lib/usrp/cores/time64_core_200.cpp +++ b/host/lib/usrp/cores/time64_core_200.cpp @@ -20,11 +20,10 @@ #include <uhd/utils/assert_has.hpp> #include <boost/math/special_functions/round.hpp> -#define REG_TIME64_SECS _base + 0 -#define REG_TIME64_TICKS _base + 4 +#define REG_TIME64_TICKS_HI _base + 0 +#define REG_TIME64_TICKS_LO _base + 4 #define REG_TIME64_FLAGS _base + 8 #define REG_TIME64_IMM _base + 12 -#define REG_TIME64_TPS _base + 16 #define REG_TIME64_MIMO_SYNC _base + 20 //lower byte is delay cycles //pps flags (see above) @@ -59,39 +58,42 @@ public: void set_tick_rate(const double rate){ _tick_rate = rate; - _iface->poke32(REG_TIME64_TPS, boost::math::iround(rate)); } uhd::time_spec_t get_time_now(void){ for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously - const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_now); - const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_now); - if (secs != _iface->peek32(_readback_bases.rb_secs_now)) continue; - return time_spec_t(secs, ticks, _tick_rate); + const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_now); + const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_now); + if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_now)) continue; + const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo; + return time_spec_t::from_ticks(ticks, _tick_rate); } throw uhd::runtime_error("time64_core_200: get time now timeout"); } uhd::time_spec_t get_time_last_pps(void){ for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously - const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_pps); - const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_pps); - if (secs != _iface->peek32(_readback_bases.rb_secs_pps)) continue; - return time_spec_t(secs, ticks, _tick_rate); + const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_pps); + const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_pps); + if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_pps)) continue; + const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo; + return time_spec_t::from_ticks(ticks, _tick_rate); } throw uhd::runtime_error("time64_core_200: get time last pps timeout"); } void set_time_now(const uhd::time_spec_t &time){ - _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate)); + const boost::uint64_t ticks = time.to_ticks(_tick_rate); + _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0)); _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW); - _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3 + _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3 } void set_time_next_pps(const uhd::time_spec_t &time){ - _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate)); + const boost::uint64_t ticks = time.to_ticks(_tick_rate); + _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0)); _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS); - _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3 + _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3 } void set_time_source(const std::string &source){ diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp index ebd51a02f..7571573a5 100644 --- a/host/lib/usrp/cores/time64_core_200.hpp +++ b/host/lib/usrp/cores/time64_core_200.hpp @@ -31,8 +31,8 @@ public: typedef boost::shared_ptr<time64_core_200> sptr; struct readback_bases_type{ - size_t rb_secs_now, rb_ticks_now; - size_t rb_secs_pps, rb_ticks_pps; + size_t rb_hi_now, rb_lo_now; + size_t rb_hi_pps, rb_lo_pps; }; //! makes a new time64 core from iface and slave base diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp index c5de4e361..7f02d59ca 100644 --- a/host/lib/usrp/cores/tx_dsp_core_200.cpp +++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 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 @@ -18,10 +18,12 @@ #include "tx_dsp_core_200.hpp" #include <uhd/types/dict.hpp> #include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> #include <uhd/utils/algorithm.hpp> #include <boost/assign/list_of.hpp> #include <boost/math/special_functions/round.hpp> #include <boost/math/special_functions/sign.hpp> +#include <boost/thread/thread.hpp> //sleep #include <algorithm> #include <cmath> @@ -29,8 +31,8 @@ #define REG_DSP_TX_SCALE_IQ _dsp_base + 4 #define REG_DSP_TX_INTERP _dsp_base + 8 -#define REG_TX_CTRL_NUM_CHAN _ctrl_base + 0 -#define REG_TX_CTRL_CLEAR_STATE _ctrl_base + 4 +#define REG_TX_CTRL_CLEAR _ctrl_base + 0 +#define REG_TX_CTRL_FORMAT _ctrl_base + 4 #define REG_TX_CTRL_REPORT_SID _ctrl_base + 8 #define REG_TX_CTRL_POLICY _ctrl_base + 12 #define REG_TX_CTRL_CYCLES_PER_UP _ctrl_base + 16 @@ -58,14 +60,19 @@ public: ): _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid) { + //init to something so update method has reasonable defaults + _scaling_adjustment = 1.0; + _dsp_extra_scaling = 1.0; + //init the tx control registers this->clear(); this->set_underflow_policy("next_packet"); } void clear(void){ - _iface->poke32(REG_TX_CTRL_CLEAR_STATE, 1); //reset - _iface->poke32(REG_TX_CTRL_NUM_CHAN, 0); //1 channel + _iface->poke32(REG_TX_CTRL_CLEAR, 1); //reset and flush technique + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + _iface->poke32(REG_TX_CTRL_CLEAR, 0); _iface->poke32(REG_TX_CTRL_REPORT_SID, _sid); } @@ -121,13 +128,24 @@ public: // Calculate CIC interpolation (i.e., without halfband interpolators) // Calculate closest multiplier constant to reverse gain absent scale multipliers - double rate_cubed = std::pow(double(interp & 0xff), 3); - const boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed)); - _iface->poke32(REG_DSP_TX_SCALE_IQ, (boost::uint32_t(scale) << 16) | (boost::uint32_t(scale) << 0)); + const double rate_pow = std::pow(double(interp & 0xff), 3); + _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow); + this->update_scalar(); return _tick_rate/interp_rate; } + void update_scalar(void){ + const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling; + const boost::int32_t actual_scalar = boost::math::iround(target_scalar); + _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small + _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar); + } + + double get_scaling_adjustment(void){ + return _fxpt_scalar_correction*_host_extra_scaling*32767.; + } + double set_freq(const double freq_){ //correct for outside of rate (wrap around) double freq = std::fmod(freq_, _tick_rate); @@ -156,10 +174,38 @@ public: _iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up)); } + void setup(const uhd::stream_args_t &stream_args){ + if (not stream_args.args.has_key("noclear")) this->clear(); + + unsigned format_word = 0; + if (stream_args.otw_format == "sc16"){ + format_word = 0; + _dsp_extra_scaling = 1.0; + _host_extra_scaling = 1.0; + } + else if (stream_args.otw_format == "sc8"){ + format_word = (1 << 0); + double peak = stream_args.args.cast<double>("peak", 1.0); + peak = std::max(peak, 1.0/256); + _host_extra_scaling = 1.0/peak/256; + _dsp_extra_scaling = 1.0/peak; + } + else throw uhd::value_error("USRP TX cannot handle requested wire format: " + stream_args.otw_format); + + this->update_scalar(); + + _iface->poke32(REG_TX_CTRL_FORMAT, format_word); + + if (stream_args.args.has_key("underflow_policy")){ + this->set_underflow_policy(stream_args.args["underflow_policy"]); + } + } + private: wb_iface::sptr _iface; const size_t _dsp_base, _ctrl_base; double _tick_rate, _link_rate; + double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction; const boost::uint32_t _sid; }; diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp index 4b39a5b07..0e1cfb6bc 100644 --- a/host/lib/usrp/cores/tx_dsp_core_200.hpp +++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp @@ -19,6 +19,7 @@ #define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP #include <uhd/config.hpp> +#include <uhd/stream.hpp> #include <uhd/types/ranges.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> @@ -44,14 +45,15 @@ public: virtual uhd::meta_range_t get_host_rates(void) = 0; + virtual double get_scaling_adjustment(void) = 0; + virtual uhd::meta_range_t get_freq_range(void) = 0; virtual double set_freq(const double freq) = 0; virtual void set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0; - virtual void set_underflow_policy(const std::string &policy) = 0; - + virtual void setup(const uhd::stream_args_t &stream_args) = 0; }; #endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/user_settings_core_200.cpp b/host/lib/usrp/cores/user_settings_core_200.cpp new file mode 100644 index 000000000..d262631b1 --- /dev/null +++ b/host/lib/usrp/cores/user_settings_core_200.cpp @@ -0,0 +1,43 @@ +// +// Copyright 2012 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 "user_settings_core_200.hpp" + +#define REG_USER_ADDR _base + 0 +#define REG_USER_DATA _base + 4 + +class user_settings_core_200_impl : public user_settings_core_200{ +public: + user_settings_core_200_impl(wb_iface::sptr iface, const size_t base): + _iface(iface), _base(base) + { + //NOP + } + + void set_reg(const user_reg_t ®){ + _iface->poke32(REG_USER_ADDR, reg.first); + _iface->poke32(REG_USER_DATA, reg.second); + } + +private: + wb_iface::sptr _iface; + const size_t _base; +}; + +user_settings_core_200::sptr user_settings_core_200::make(wb_iface::sptr iface, const size_t base){ + return sptr(new user_settings_core_200_impl(iface, base)); +} diff --git a/host/lib/usrp/cores/user_settings_core_200.hpp b/host/lib/usrp/cores/user_settings_core_200.hpp new file mode 100644 index 000000000..1f5d13de7 --- /dev/null +++ b/host/lib/usrp/cores/user_settings_core_200.hpp @@ -0,0 +1,36 @@ +// +// Copyright 2012 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/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP +#define INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP + +#include <uhd/config.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" + +class user_settings_core_200 : boost::noncopyable{ +public: + typedef boost::shared_ptr<user_settings_core_200> sptr; + typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t; + + static sptr make(wb_iface::sptr iface, const size_t base); + + virtual void set_reg(const user_reg_t ®) = 0; +}; + +#endif /* INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP */ diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index f58138ae6..a01ce4a7b 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -326,10 +326,10 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ // create time control objects //////////////////////////////////////////////////////////////////// time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_secs_now = E100_REG_RB_TIME_NOW_SECS; - time64_rb_bases.rb_ticks_now = E100_REG_RB_TIME_NOW_TICKS; - time64_rb_bases.rb_secs_pps = E100_REG_RB_TIME_PPS_SECS; - time64_rb_bases.rb_ticks_pps = E100_REG_RB_TIME_PPS_TICKS; + time64_rb_bases.rb_hi_now = E100_REG_RB_TIME_NOW_HI; + time64_rb_bases.rb_lo_now = E100_REG_RB_TIME_NOW_LO; + time64_rb_bases.rb_hi_pps = E100_REG_RB_TIME_PPS_HI; + time64_rb_bases.rb_lo_pps = E100_REG_RB_TIME_PPS_LO; _time64 = time64_core_200::make( _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases ); @@ -353,6 +353,13 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); //////////////////////////////////////////////////////////////////// + // create user-defined control objects + //////////////////////////////////////////////////////////////////// + _user = user_settings_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_USER_REGS)); + _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs") + .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1)); + + //////////////////////////////////////////////////////////////////// // create dboard control objects //////////////////////////////////////////////////////////////////// diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp index 2ea890375..1d36cb2ac 100644 --- a/host/lib/usrp/e100/e100_impl.hpp +++ b/host/lib/usrp/e100/e100_impl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -25,6 +25,7 @@ #include "rx_dsp_core_200.hpp" #include "tx_dsp_core_200.hpp" #include "time64_core_200.hpp" +#include "user_settings_core_200.hpp" #include <uhd/device.hpp> #include <uhd/property_tree.hpp> #include <uhd/utils/pimpl.hpp> @@ -48,7 +49,7 @@ static const double E100_RX_LINK_RATE_BPS = 166e6/3/2*2; static const double E100_TX_LINK_RATE_BPS = 166e6/3/1*2; static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3"; static const std::string E100_UART_DEV_NODE = "/dev/ttyO0"; -static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x08; +static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x09; static const boost::uint32_t E100_RX_SID_BASE = 2; static const boost::uint32_t E100_TX_ASYNC_SID = 1; static const double E100_DEFAULT_CLOCK_RATE = 64e6; @@ -92,6 +93,7 @@ private: std::vector<rx_dsp_core_200::sptr> _rx_dsps; tx_dsp_core_200::sptr _tx_dsp; time64_core_200::sptr _time64; + user_settings_core_200::sptr _user; e100_clock_ctrl::sptr _clock_ctrl; e100_codec_ctrl::sptr _codec_ctrl; e100_ctrl::sptr _fpga_ctrl; diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp index f24f5895b..75be2cfbe 100644 --- a/host/lib/usrp/e100/e100_regs.hpp +++ b/host/lib/usrp/e100/e100_regs.hpp @@ -1,4 +1,19 @@ - +// +// Copyright 2010-2012 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/>. +// //////////////////////////////////////////////////////////////// // @@ -71,10 +86,10 @@ #define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7) -#define E100_REG_RB_TIME_NOW_SECS E100_REG_RB_MUX_32_BASE + 0 -#define E100_REG_RB_TIME_NOW_TICKS E100_REG_RB_MUX_32_BASE + 4 -#define E100_REG_RB_TIME_PPS_SECS E100_REG_RB_MUX_32_BASE + 8 -#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12 +#define E100_REG_RB_TIME_NOW_HI E100_REG_RB_MUX_32_BASE + 0 +#define E100_REG_RB_TIME_NOW_LO E100_REG_RB_MUX_32_BASE + 4 +#define E100_REG_RB_TIME_PPS_HI E100_REG_RB_MUX_32_BASE + 8 +#define E100_REG_RB_TIME_PPS_LO E100_REG_RB_MUX_32_BASE + 12 #define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16 #define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20 #define E100_REG_RB_COMPAT E100_REG_RB_MUX_32_BASE + 24 @@ -101,9 +116,9 @@ #define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4) #define UE_SR_REG_TEST32 60 // 1 reg -#define UE_SR_CLEAR_RX_FIFO 61 // 1 reg -#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg +#define UE_SR_CLEAR_FIFO 61 // 1 reg #define UE_SR_GLOBAL_RESET 63 // 1 reg +#define UE_SR_USER_REGS 64 // 2 regs #define UE_SR_GPIO 128 @@ -115,8 +130,7 @@ ///////////////////////////////////////////////// // Magic reset regs //////////////////////////////////////////////// -#define E100_REG_CLEAR_RX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) -#define E100_REG_CLEAR_TX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) +#define E100_REG_CLEAR_FIFO E100_REG_SR_ADDR(UE_SR_CLEAR_FIFO) #define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET) #endif diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp index 441e32a8d..e9608125f 100644 --- a/host/lib/usrp/e100/io_impl.cpp +++ b/host/lib/usrp/e100/io_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -17,6 +17,7 @@ #include "recv_packet_demuxer.hpp" #include "validate_subdev_spec.hpp" +#include "async_packet_handler.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include <linux/usrp_e.h> //ioctl structures and constants @@ -50,7 +51,7 @@ using namespace uhd::transport; **********************************************************************/ struct e100_impl::io_impl{ io_impl(void): - false_alarm(0), async_msg_fifo(100/*messages deep*/) + false_alarm(0), async_msg_fifo(1000/*messages deep*/) { /* NOP */ } double tick_rate; //set by update tick rate method @@ -123,28 +124,13 @@ void e100_impl::io_impl::handle_irq(void){ //fill in the async metadata async_metadata_t metadata; - metadata.channel = 0; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), long(if_packet_info.tsf), tick_rate - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(data.buf, if_packet_info)); + load_metadata_from_buff(uhd::wtohx<boost::uint32_t>, metadata, if_packet_info, data.buf, tick_rate); //push the message onto the queue async_msg_fifo.push_with_pop_on_full(metadata); //print some fastpath messages - if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) - ) UHD_MSG(fastpath) << "U"; - else if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_SEQ_ERROR - | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) - ) UHD_MSG(fastpath) << "S"; - else if (metadata.event_code & - async_metadata_t::EVENT_CODE_TIME_ERROR - ) UHD_MSG(fastpath) << "L"; + standard_async_msg_prints(metadata); } //prepare for the next round @@ -164,9 +150,8 @@ void e100_impl::io_init(void){ _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE); _io_impl->iface = _fpga_ctrl; - //clear state machines - _fpga_ctrl->poke32(E100_REG_CLEAR_RX, 0); - _fpga_ctrl->poke32(E100_REG_CLEAR_TX, 0); + //clear fifo state machines + _fpga_ctrl->poke32(E100_REG_CLEAR_FIFO, 0); //allocate streamer weak ptrs containers _rx_streamers.resize(_rx_dsps.size()); @@ -217,6 +202,8 @@ void e100_impl::update_tx_samp_rate(const size_t dspno, const double rate){ if (my_streamer.get() == NULL) return; my_streamer->set_samp_rate(rate); + const double adj = _tx_dsp->get_scaling_adjustment(); + my_streamer->set_scale_factor(adj); } void e100_impl::update_rates(void){ @@ -278,13 +265,13 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){ //setup defaults for unspecified values args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400)); //calculate packet size static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size; const size_t bpi = convert::get_bytes_per_item(args.otw_format); @@ -309,8 +296,7 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){ for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){ const size_t dsp = args.channels[chan_i]; _rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this - if (not args.args.has_key("noclear")) _rx_dsps[dsp]->clear(); - _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar); + _rx_dsps[dsp]->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1 ), true /*flush*/); @@ -336,14 +322,13 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){ args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - if (args.otw_format != "sc16"){ - throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format); - } - //calculate packet size static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size; const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format); @@ -367,8 +352,7 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){ for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){ const size_t dsp = args.channels[chan_i]; UHD_ASSERT_THROW(dsp == 0); //always 0 - if (not args.args.has_key("noclear")) _tx_dsp->clear(); - if (args.args.has_key("underflow_policy")) _tx_dsp->set_underflow_policy(args.args["underflow_policy"]); + _tx_dsp->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( &zero_copy_if::get_send_buff, _data_transport, _1 )); diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 6cd9f95bb..d9be19b83 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -445,6 +445,17 @@ public: return _tree->list(mb_root(mboard) / "sensors"); } + void set_user_register(const boost::uint8_t addr, const boost::uint32_t data, size_t mboard){ + if (mboard != ALL_MBOARDS){ + typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t; + _tree->access<user_reg_t>(mb_root(mboard) / "user/reg").set(user_reg_t(addr, data)); + return; + } + for (size_t m = 0; m < get_num_mboards(); m++){ + set_user_register(addr, data, m); + } + } + /******************************************************************* * RX methods ******************************************************************/ diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index e9d9b65c2..f27135562 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -221,17 +221,17 @@ void usrp1_impl::io_init(void){ _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); - //create a new vandal thread to poll xerflow conditions - _io_impl->vandal_task = task::make(boost::bind( - &usrp1_impl::vandal_conquest_loop, this - )); - //init as disabled, then call the real function (uses restore) this->enable_rx(false); this->enable_tx(false); rx_stream_on_off(false); tx_stream_on_off(false); _io_impl->flush_send_buff(); + + //create a new vandal thread to poll xerflow conditions + _io_impl->vandal_task = task::make(boost::bind( + &usrp1_impl::vandal_conquest_loop, this + )); } void usrp1_impl::rx_stream_on_off(bool enb){ diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp index b8af8af06..90b3a92da 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp @@ -39,8 +39,8 @@ public: _nsamps_remaining(0), _stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS), _cmd_queue(2), - _async_msg_queue(100), - _inline_msg_queue(100), + _async_msg_queue(1000), + _inline_msg_queue(1000), _stream_on_off(stream_on_off) { //synchronously spawn a new thread diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index ef8ae950d..430ea59c8 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -210,6 +210,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // Initialize the properties tree //////////////////////////////////////////////////////////////////// + _rx_dc_offset_shadow = 0; _tree = property_tree::make(); _tree->create<std::string>("/name").set("USRP1 Device"); const fs_path mb_path = "/mboards/0"; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 1af1db860..0babf7445 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -30,9 +30,9 @@ extern "C" { #endif //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 8 +#define USRP2_FPGA_COMPAT_NUM 9 #define USRP2_FW_COMPAT_NUM 11 -#define USRP2_FW_VER_MINOR 1 +#define USRP2_FW_VER_MINOR 2 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index e3fa46920..d32ffb62c 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -16,6 +16,7 @@ // #include "validate_subdev_spec.hpp" +#include "async_packet_handler.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include "usrp2_impl.hpp" @@ -135,7 +136,8 @@ private: struct usrp2_impl::io_impl{ io_impl(void): - async_msg_fifo(100/*messages deep*/) + async_msg_fifo(1000/*messages deep*/), + tick_rate(1 /*non-zero default*/) { /* NOP */ } @@ -201,12 +203,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( //fill in the async metadata async_metadata_t metadata; - metadata.channel = index; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); + load_metadata_from_buff(uhd::ntohx<boost::uint32_t>, metadata, if_packet_info, vrt_hdr, tick_rate, index); //catch the flow control packets and react if (metadata.event_code == 0){ @@ -217,17 +214,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( //else UHD_MSG(often) << "metadata.event_code " << metadata.event_code << std::endl; async_msg_fifo.push_with_pop_on_full(metadata); - if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) - ) UHD_MSG(fastpath) << "U"; - else if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_SEQ_ERROR - | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) - ) UHD_MSG(fastpath) << "S"; - else if (metadata.event_code & - async_metadata_t::EVENT_CODE_TIME_ERROR - ) UHD_MSG(fastpath) << "L"; + standard_async_msg_prints(metadata); } else{ //TODO unknown received packet, may want to print error... @@ -307,6 +294,8 @@ void usrp2_impl::update_tx_samp_rate(const std::string &mb, const size_t dsp, co if (my_streamer.get() == NULL) return; my_streamer->set_samp_rate(rate); + const double adj = _mbc[mb].tx_dsp->get_scaling_adjustment(); + my_streamer->set_scale_factor(adj); } void usrp2_impl::update_rates(void){ @@ -380,13 +369,13 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){ //setup defaults for unspecified values args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400)); //calculate packet size static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; const size_t bpp = _mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size() - hdr_size; const size_t bpi = convert::get_bytes_per_item(args.otw_format); @@ -416,8 +405,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){ if (chan < num_chan_so_far){ const size_t dsp = chan + _mbc[mb].rx_chan_occ - num_chan_so_far; _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this - if (not args.args.has_key("noclear")) _mbc[mb].rx_dsps[dsp]->clear(); - _mbc[mb].rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar); + _mbc[mb].rx_dsps[dsp]->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( &zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1 ), true /*flush*/); @@ -447,15 +435,14 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){ args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - if (args.otw_format != "sc16"){ - throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format); - } - //calculate packet size static const size_t hdr_size = 0 - + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + vrt_send_header_offset_words32*sizeof(boost::uint32_t) + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used + - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used ; const size_t bpp = _mbc[_mbc.keys().front()].tx_dsp_xport->get_send_frame_size() - hdr_size; const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format); @@ -485,10 +472,9 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){ if (chan < num_chan_so_far){ const size_t dsp = chan + _mbc[mb].tx_chan_occ - num_chan_so_far; if (not args.args.has_key("noclear")){ - _mbc[mb].tx_dsp->clear(); _io_impl->fc_mons[abs]->clear(); } - if (args.args.has_key("underflow_policy")) _mbc[mb].tx_dsp->set_underflow_policy(args.args["underflow_policy"]); + _mbc[mb].tx_dsp->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), abs, _1 )); diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 4830c10d9..eeba6756e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -87,7 +87,7 @@ public: //Obtain the firmware's compat number. //Save the response compat number for communication. //TODO can choose to reject certain older compat numbers - usrp2_ctrl_data_t ctrl_data; + usrp2_ctrl_data_t ctrl_data = usrp2_ctrl_data_t(); ctrl_data.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO); ctrl_data = ctrl_send_and_recv(ctrl_data, 0, ~0); if (ntohl(ctrl_data.id) != USRP2_CTRL_ID_WAZZUP_DUDE) @@ -126,10 +126,9 @@ public: bool is_device_locked(void){ boost::uint32_t lock_secs = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_TIME); boost::uint32_t lock_gpid = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_GPID); - boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM); //if the difference is larger, assume not locked anymore - if (curr_secs - lock_secs >= 3) return false; + if (this->get_curr_secs() - lock_secs >= 3) return false; //otherwise only lock if the device hash is different that ours return lock_gpid != boost::uint32_t(get_gpid()); @@ -137,12 +136,16 @@ public: void lock_task(void){ //re-lock in task - boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM); - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs); + this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, this->get_curr_secs()); //sleep for a bit boost::this_thread::sleep(boost::posix_time::milliseconds(1500)); } + boost::uint32_t get_curr_secs(void){ + //may not be the right tick rate, but this is ok for locking purposes + return boost::uint32_t(this->peek32(U2_REG_TIME64_LO_RB_IMM)/100e6); + } + /*********************************************************************** * Peek and Poke **********************************************************************/ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index ef7151cee..2077ab009 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -546,10 +546,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ // create time control objects //////////////////////////////////////////////////////////////// time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_secs_now = U2_REG_TIME64_SECS_RB_IMM; - time64_rb_bases.rb_ticks_now = U2_REG_TIME64_TICKS_RB_IMM; - time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS; - time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS; + time64_rb_bases.rb_hi_now = U2_REG_TIME64_HI_RB_IMM; + time64_rb_bases.rb_lo_now = U2_REG_TIME64_LO_RB_IMM; + time64_rb_bases.rb_hi_pps = U2_REG_TIME64_HI_RB_PPS; + time64_rb_bases.rb_lo_pps = U2_REG_TIME64_LO_RB_PPS; _mbc[mb].time64 = time64_core_200::make( _mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles ); @@ -572,6 +572,13 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo"); _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); + //////////////////////////////////////////////////////////////////// + // create user-defined control objects + //////////////////////////////////////////////////////////////////// + _mbc[mb].user = user_settings_core_200::make(_mbc[mb].iface, U2_REG_SR_ADDR(SR_USER_REGS)); + _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs") + .subscribe(boost::bind(&user_settings_core_200::set_reg, _mbc[mb].user, _1)); + //////////////////////////////////////////////////////////////// // create dboard control objects //////////////////////////////////////////////////////////////// diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 278dc713e..882a61f80 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -26,6 +26,7 @@ #include "rx_dsp_core_200.hpp" #include "tx_dsp_core_200.hpp" #include "time64_core_200.hpp" +#include "user_settings_core_200.hpp" #include <uhd/property_tree.hpp> #include <uhd/usrp/gps_ctrl.hpp> #include <uhd/device.hpp> @@ -91,6 +92,7 @@ private: std::vector<boost::weak_ptr<uhd::tx_streamer> > tx_streamers; tx_dsp_core_200::sptr tx_dsp; time64_core_200::sptr time64; + user_settings_core_200::sptr user; std::vector<uhd::transport::zero_copy_if::sptr> rx_dsp_xports; uhd::transport::zero_copy_if::sptr tx_dsp_xport; uhd::usrp::dboard_manager::sptr dboard_manager; diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 179a930c6..e14798ecb 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 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 @@ -39,7 +39,7 @@ #define SR_SIMTIMER 8 // 2 #define SR_TIME64 10 // 6 #define SR_BUF_POOL 16 // 4 - +#define SR_USER_REGS 20 // 2 #define SR_RX_FRONT 24 // 5 #define SR_RX_CTRL0 32 // 9 #define SR_RX_DSP0 48 // 7 @@ -97,11 +97,11 @@ //////////////////////////////////////////////// #define U2_REG_STATUS READBACK_BASE + 4*8 #define U2_REG_GPIO_RB READBACK_BASE + 4*9 -#define U2_REG_TIME64_SECS_RB_IMM READBACK_BASE + 4*10 -#define U2_REG_TIME64_TICKS_RB_IMM READBACK_BASE + 4*11 +#define U2_REG_TIME64_HI_RB_IMM READBACK_BASE + 4*10 +#define U2_REG_TIME64_LO_RB_IMM READBACK_BASE + 4*11 #define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12 #define U2_REG_IRQ_RB READBACK_BASE + 4*13 -#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14 -#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15 +#define U2_REG_TIME64_HI_RB_PPS READBACK_BASE + 4*14 +#define U2_REG_TIME64_LO_RB_PPS READBACK_BASE + 4*15 #endif /* INCLUDED_USRP2_REGS_HPP */ |