From e74356ec5956d10d399969851fefd4a1f308ad7c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 22 Jun 2010 18:49:19 -0700 Subject: uhd: tweaks to ic regs maps common generator code --- host/lib/ic_reg_maps/common.py | 4 ++-- host/lib/ic_reg_maps/gen_ad9522_regs.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'host') diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py index 173186eb1..47325a7e3 100644 --- a/host/lib/ic_reg_maps/common.py +++ b/host/lib/ic_reg_maps/common.py @@ -59,7 +59,7 @@ public: delete _state; } -$body + $body void save_state(void){ if (_state == NULL) _state = new $(name)_t(); @@ -181,7 +181,7 @@ def generate(name, regs_tmpl, body_tmpl='', file=__file__): else: regs.append(reg(entry)) #evaluate the body template with the list of registers - body = parse_tmpl(body_tmpl, regs=regs).replace('\n', '\n ').strip() + body = '\n '.join(parse_tmpl(body_tmpl, regs=regs).splitlines()) #evaluate the code template with the parsed registers and arguments code = parse_tmpl(COMMON_TMPL, diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py index 9da51205b..ed6b5f48d 100755 --- a/host/lib/ic_reg_maps/gen_ad9522_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py @@ -32,9 +32,11 @@ cp_mode 0x010[3:2] 3 high_imp, force pll_power_down 0x010[1:0] 1 normal=0, async=1, sync=3 r_counter_lsb 0x011[7:0] 1 r_counter_msb 0x012[5:0] 0 +~r_counter r_counter_lsb, r_counter_msb a_counter 0x013[5:0] 0 b_counter_lsb 0x014[7:0] 3 b_counter_msb 0x015[4:0] 0 +~b_counter b_counter_lsb, b_counter_msb set_cp_pin_to_vcp_2 0x016[7] 0 normal, vcp_2 reset_r_counter 0x016[6] 0 reset_a_and_b_counters 0x016[5] 0 -- cgit v1.2.3 From fadd3a44a84e061412accd35c1c97db820190df8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 24 Jun 2010 18:55:08 -0700 Subject: uhd: created benchmark rx example app Made mods to time spec to support math operators. --- host/examples/CMakeLists.txt | 12 ++- host/examples/benchmark_rx_rate.cpp | 150 +++++++++++++++++++++++++++++++++++ host/examples/rx_timed_samples.cpp | 4 +- host/include/uhd/types/time_spec.hpp | 24 +++++- host/include/uhd/usrp/dboard_id.hpp | 2 +- host/lib/transport/gen_vrt.py | 13 ++- host/lib/types.cpp | 28 +++++++ 7 files changed, 220 insertions(+), 13 deletions(-) create mode 100644 host/examples/benchmark_rx_rate.cpp (limited to 'host') diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index a537c0901..5071b114f 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -15,10 +15,18 @@ # along with this program. If not, see . # +ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp) +TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd) + 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) + +INSTALL(TARGETS + benchmark_rx_rate + rx_timed_samples + tx_timed_samples + RUNTIME DESTINATION ${PKG_DATA_DIR}/examples +) diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp new file mode 100644 index 000000000..2ab98bc22 --- /dev/null +++ b/host/examples/benchmark_rx_rate.cpp @@ -0,0 +1,150 @@ +// +// 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 +#include +#include + +namespace po = boost::program_options; + +//TODO add time spec diff to API +static inline double time_spec_diff( + uhd::time_spec_t time_spec_begin, + uhd::time_spec_t time_spec_end +){ + return (time_spec_end.secs - time_spec_begin.secs) + \ + ((time_spec_end.nsecs - time_spec_begin.nsecs)*1e-9); +} + +static inline void test_device( + uhd::usrp::simple_usrp::sptr sdev, + double rx_rate_sps, + double duration_secs +){ + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Testing receive rate %f Msps (%f second run)") % (rx_rate_sps/1e6) % duration_secs << std::endl; + + //allocate recv buffer and metatdata + uhd::rx_metadata_t md; + std::vector > buff(dev->get_max_recv_samps_per_packet()); + + //declare status variables + bool got_first_packet = false; + size_t total_recv_packets = 0; + size_t total_lost_samples = 0; + size_t total_recv_samples = 0; + uhd::time_spec_t initial_time_spec; + uhd::time_spec_t next_expected_time_spec; + + sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + do { + size_t num_rx_samps = dev->recv( + boost::asio::buffer(buff), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET + ); + if (num_rx_samps == 0){ + std::cerr << "Unexpected timeout on recv, exit test..." << std::endl; + return; + } + if (not md.has_time_spec){ + std::cerr << "Metadata missing time spec, exit test..." << std::endl; + return; + } + + total_recv_samples += num_rx_samps; + total_recv_packets++; + + if (not got_first_packet){ + initial_time_spec = md.time_spec; + next_expected_time_spec = initial_time_spec; + got_first_packet = true; + } + + total_lost_samples += boost::math::iround(rx_rate_sps*time_spec_diff(next_expected_time_spec, md.time_spec)); + next_expected_time_spec = md.time_spec + uhd::time_spec_t(0, num_rx_samps, rx_rate_sps); + + } while(time_spec_diff(initial_time_spec, next_expected_time_spec) < duration_secs); + sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + + //flush the buffers + while(dev->recv( + boost::asio::buffer(buff), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET + )); + + //print a summary + std::cout << std::endl; //go to newline, recv may spew SXSYSZ... + std::cout << boost::format(" Received packets: %d") % total_recv_packets << std::endl; + std::cout << boost::format(" Received samples: %d") % total_recv_samples << std::endl; + std::cout << boost::format(" Lost samples: %d") % total_lost_samples << std::endl; + size_t packets_lost = boost::math::iround(double(total_lost_samples)/dev->get_max_recv_samps_per_packet()); + std::cout << boost::format(" Lost packets: %d (approximate)") % packets_lost << std::endl; + double actual_rx_rate_sps = (total_recv_samples*rx_rate_sps)/(total_recv_samples+total_lost_samples); + std::cout << boost::format(" Sustained receive rate: %f Msps") % (actual_rx_rate_sps/1e6) << std::endl; + std::cout << std::endl << std::endl; +} + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + //variables to be set by po + std::string args; + double duration; + + //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") + ("duration", po::value(&duration)->default_value(10.0), "duration for each test in seconds") + ; + 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 Benchmark RX Rate %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); + std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + + sdev->set_rx_rate(500e3); //initial rate + while(true){ + double rate = sdev->get_rx_rate(); + test_device(sdev, rate, duration); + sdev->set_rx_rate(rate*2); //double the rate + if (sdev->get_rx_rate() == rate) break; + } + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 6920b34d1..adc745024 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -85,8 +85,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::rx_metadata_t md; std::vector > buff(dev->get_max_recv_samps_per_packet()); size_t num_rx_samps = dev->recv( - boost::asio::buffer(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 and num_acc_samps > 0){ diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp index 25d9e41d0..7353c6e25 100644 --- a/host/include/uhd/types/time_spec.hpp +++ b/host/include/uhd/types/time_spec.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace uhd{ @@ -38,7 +39,10 @@ namespace uhd{ * This gives the fractional seconds enough precision to unambiguously * specify a clock-tick/sample-count up to rates of several petahertz. */ - struct UHD_API time_spec_t{ + struct UHD_API time_spec_t: + boost::addable, + boost::subtractable, + boost::equality_comparable{ //! whole/integer seconds count in seconds boost::uint32_t secs; @@ -69,8 +73,26 @@ namespace uhd{ */ time_spec_t(boost::uint32_t secs = 0, double nsecs = 0); + /*! + * Create a time_spec_t from whole and fractional seconds. + * Translation from clock-domain specific units. + * \param secs the whole/integer seconds count in seconds + * \param ticks the fractional seconds tick count + * \param tick_rate the number of ticks per second + */ + time_spec_t(boost::uint32_t secs, boost::uint32_t ticks, double tick_rate); + + //! Implement addable interface + time_spec_t &operator+=(const time_spec_t &); + + //! Implement subtractable interface + time_spec_t &operator-=(const time_spec_t &); + }; + //! Implement equality_comparable interface + UHD_API bool operator==(const time_spec_t &, const time_spec_t &); + } //namespace uhd #endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */ diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 8b6eaf6bd..4c45e4334 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -25,7 +25,7 @@ namespace uhd{ namespace usrp{ - class UHD_API dboard_id_t : boost::equality_comparable1{ + class UHD_API dboard_id_t : boost::equality_comparable{ public: /*! * Create a dboard id from an integer. diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 6cdd6645d..d1e553c41 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -169,7 +169,7 @@ void vrt::unpack_$(suffix)( switch(pred){ #for $pred in range(2**5) case $pred: - #set $set_has_time_spec = False + #set $has_time_spec = False #set $num_header_words = 1 ########## Stream ID ########## #if $pred & $sid_p @@ -184,21 +184,20 @@ void vrt::unpack_$(suffix)( #end if ########## Integer Time ########## #if $pred & $tsi_p - metadata.has_time_spec = true; - #set $set_has_time_spec = True + #set $has_time_spec = True metadata.time_spec.secs = $(XE_MACRO)(header_buff[$num_header_words]); #set $num_header_words += 1 #end if ########## Fractional Time ########## #if $pred & $tsf_p - #if not $set_has_time_spec - metadata.has_time_spec = true; - #set $set_has_time_spec = True - #end if + #set $has_time_spec = True #set $num_header_words += 1 metadata.time_spec.set_ticks($(XE_MACRO)(header_buff[$num_header_words]), tick_rate); #set $num_header_words += 1 #end if + #if $has_time_spec + metadata.has_time_spec = true; + #end if ########## Trailer ########## #if $pred & $tlr_p #set $num_trailer_words = 1; diff --git a/host/lib/types.cpp b/host/lib/types.cpp index daf3be7f7..78a3d22ce 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -120,6 +120,11 @@ tx_metadata_t::tx_metadata_t(void): /*********************************************************************** * time spec **********************************************************************/ +static inline void time_spec_normalize(time_spec_t &time_spec){ + time_spec.secs += boost::uint32_t(std::ceil(time_spec.nsecs/1e9)); + time_spec.nsecs = std::fmod(time_spec.nsecs, 1e9); +} + time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs): secs(secs), nsecs(nsecs) @@ -127,6 +132,13 @@ time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs): /* NOP */ } +time_spec_t::time_spec_t(boost::uint32_t secs, boost::uint32_t ticks, double tick_rate): + secs(secs), + nsecs(double(ticks)*1e9/tick_rate) +{ + /* NOP */ +} + boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ return boost::math::iround(nsecs*tick_rate*1e-9); } @@ -135,6 +147,22 @@ void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){ nsecs = double(ticks)*1e9/tick_rate; } +time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ + this->secs += rhs.secs; + this->nsecs += rhs.nsecs; + return *this; +} + +time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){ + this->secs -= rhs.secs; + this->nsecs -= rhs.nsecs; + return *this; +} + +bool uhd::operator==(const time_spec_t &lhs, const time_spec_t &rhs){ + return lhs.secs == rhs.secs and lhs.nsecs == rhs.nsecs; +} + /*********************************************************************** * device addr **********************************************************************/ -- cgit v1.2.3 From 51cb8da5837adacbc626ee20aa58264e1b4b7a78 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 24 Jun 2010 20:29:11 -0700 Subject: uhd: reworked time_spec_t to be more flexible: arithmetic, comparison operators... Replaced nsecs with fractional seconds in units of seconds. Replaced nsecs and secs members with public function members. time_spec_t has a more diverse set of constructors and methods. It can handle the cases where frac secs are greater than 1 second. --- host/examples/benchmark_rx_rate.cpp | 13 +----- host/examples/rx_timed_samples.cpp | 10 ++--- host/examples/tx_timed_samples.cpp | 6 +-- host/include/uhd/types/time_spec.hpp | 82 +++++++++++++++++++++--------------- host/lib/transport/gen_vrt.py | 10 +++-- host/lib/types.cpp | 52 +++++++++++++++-------- host/lib/usrp/usrp2/mboard_impl.cpp | 8 ++-- host/test/vrt_test.cpp | 10 ++--- 8 files changed, 105 insertions(+), 86 deletions(-) (limited to 'host') diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 2ab98bc22..53f4a3c68 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -26,15 +26,6 @@ namespace po = boost::program_options; -//TODO add time spec diff to API -static inline double time_spec_diff( - uhd::time_spec_t time_spec_begin, - uhd::time_spec_t time_spec_end -){ - return (time_spec_end.secs - time_spec_begin.secs) + \ - ((time_spec_end.nsecs - time_spec_begin.nsecs)*1e-9); -} - static inline void test_device( uhd::usrp::simple_usrp::sptr sdev, double rx_rate_sps, @@ -80,10 +71,10 @@ static inline void test_device( got_first_packet = true; } - total_lost_samples += boost::math::iround(rx_rate_sps*time_spec_diff(next_expected_time_spec, md.time_spec)); + total_lost_samples += boost::math::iround(rx_rate_sps*(md.time_spec - next_expected_time_spec).get_real_secs()); next_expected_time_spec = md.time_spec + uhd::time_spec_t(0, num_rx_samps, rx_rate_sps); - } while(time_spec_diff(initial_time_spec, next_expected_time_spec) < duration_secs); + } while((next_expected_time_spec - initial_time_spec) < uhd::time_spec_t(duration_secs)); sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //flush the buffers diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index adc745024..8db312690 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -30,7 +30,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //variables to be set by po std::string args; - int seconds_in_future; + time_t seconds_in_future; size_t total_num_samps; double rx_rate, freq; @@ -39,7 +39,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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 receive") + ("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") @@ -67,7 +67,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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)); + sdev->set_time_now(uhd::time_spec_t(0.0)); //setup streaming std::cout << std::endl; @@ -95,8 +95,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } if (num_rx_samps == 0) continue; //wait for packets with contents - std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs") - % num_rx_samps % md.time_spec.secs % md.time_spec.nsecs << std::endl; + std::cout << boost::format("Got packet: %u samples, %u full secs, %f frac secs") + % num_rx_samps % md.time_spec.get_full_secs() % md.time_spec.get_frac_secs() << std::endl; num_acc_samps += num_rx_samps; } diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 28fd2ee67..333f03fbe 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -30,7 +30,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //variables to be set by po std::string args; - int seconds_in_future; + time_t seconds_in_future; size_t total_num_samps; double tx_rate, freq; float ampl; @@ -40,7 +40,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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") + ("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") @@ -69,7 +69,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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)); + sdev->set_time_now(uhd::time_spec_t(0.0)); //data to send std::vector > buff(total_num_samps, std::complex(ampl, ampl)); diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp index 7353c6e25..59b85f4b7 100644 --- a/host/include/uhd/types/time_spec.hpp +++ b/host/include/uhd/types/time_spec.hpp @@ -19,68 +19,75 @@ #define INCLUDED_UHD_TYPES_TIME_SPEC_HPP #include -#include #include +#include namespace uhd{ /*! - * A time_spec_t holds a seconds and fractional seconds time value. - * The time_spec_t can be used when setting the time on devices, - * and for dealing with time stamped samples though the metadata. - * and for controlling the start of streaming for applicable dsps. + * A time_spec_t holds a seconds and a fractional seconds time value. + * Depending upon usage, the time_spec_t can represent absolute times, + * relative times, or time differences (between absolute times). * - * The fractional seconds are represented in units of nanoseconds, - * which provide a clock-domain independent unit of time storage. - * The methods "get_ticks" and "set_ticks" can be used to convert - * the fractional seconds to and from clock-domain specific units. + * The time_spec_t provides clock-domain independent time storage, + * but can convert fractional seconds to/from clock-domain specific units. * - * The nanoseconds count is stored as double precision floating point. + * The fractional seconds are stored as double precision floating point. * This gives the fractional seconds enough precision to unambiguously * specify a clock-tick/sample-count up to rates of several petahertz. */ - struct UHD_API time_spec_t: - boost::addable, - boost::subtractable, - boost::equality_comparable{ + class UHD_API time_spec_t : boost::additive, boost::totally_ordered{ + public: - //! whole/integer seconds count in seconds - boost::uint32_t secs; + /*! + * Create a time_spec_t from a real-valued seconds count. + * \param secs the real-valued seconds count (default = 0) + */ + time_spec_t(double secs = 0); - //! fractional seconds count in nano-seconds - double nsecs; + /*! + * Create a time_spec_t from whole and fractional seconds. + * \param full_secs the whole/integer seconds count + * \param frac_secs the fractional seconds count (default = 0) + */ + time_spec_t(time_t full_secs, double frac_secs = 0); + + /*! + * Create a time_spec_t from whole and fractional seconds. + * Translation from clock-domain specific units. + * \param full_secs the whole/integer seconds count + * \param tick_count the fractional seconds tick count + * \param tick_rate the number of ticks per second + */ + time_spec_t(time_t full_secs, size_t tick_count, double tick_rate); /*! - * Convert the fractional nsecs to clock ticks. + * Convert the fractional seconds to clock ticks. * Translation into clock-domain specific units. * \param tick_rate the number of ticks per second * \return the fractional seconds tick count */ - boost::uint32_t get_ticks(double tick_rate) const; + size_t get_tick_count(double tick_rate) const; /*! - * Set the fractional nsecs from clock ticks. - * Translation from clock-domain specific units. - * \param ticks the fractional seconds tick count - * \param tick_rate the number of ticks per second + * Get the time as a real-valued seconds count. + * Note: If this time_spec_t represents an absolute time, + * the precision of the fractional seconds may be lost. + * \return the real-valued seconds */ - void set_ticks(boost::uint32_t ticks, double tick_rate); + double get_real_secs(void) const; /*! - * Create a time_spec_t from whole and fractional seconds. - * \param secs the whole/integer seconds count in seconds (default = 0) - * \param nsecs the fractional seconds count in nanoseconds (default = 0) + * Get the whole/integer part of the time in seconds. + * \return the whole/integer seconds */ - time_spec_t(boost::uint32_t secs = 0, double nsecs = 0); + time_t get_full_secs(void) const; /*! - * Create a time_spec_t from whole and fractional seconds. - * Translation from clock-domain specific units. - * \param secs the whole/integer seconds count in seconds - * \param ticks the fractional seconds tick count - * \param tick_rate the number of ticks per second + * Get the fractional part of the time in seconds. + * \return the fractional seconds */ - time_spec_t(boost::uint32_t secs, boost::uint32_t ticks, double tick_rate); + double get_frac_secs(void) const; //! Implement addable interface time_spec_t &operator+=(const time_spec_t &); @@ -88,11 +95,16 @@ namespace uhd{ //! Implement subtractable interface time_spec_t &operator-=(const time_spec_t &); + //private time storage details + private: time_t _full_secs; double _frac_secs; }; //! Implement equality_comparable interface UHD_API bool operator==(const time_spec_t &, const time_spec_t &); + //! Implement less_than_comparable interface + UHD_API bool operator<(const time_spec_t &, const time_spec_t &); + } //namespace uhd #endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */ diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index d1e553c41..8e0fce9ff 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -97,7 +97,7 @@ void vrt::pack_$(suffix)( #end if ########## Integer Time ########## #if $pred & $tsi_p - header_buff[$num_header_words] = $(XE_MACRO)(metadata.time_spec.secs); + header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_full_secs())); #set $num_header_words += 1 #set $flags |= (0x3 << 22); #end if @@ -105,7 +105,7 @@ void vrt::pack_$(suffix)( #if $pred & $tsf_p header_buff[$num_header_words] = 0; #set $num_header_words += 1 - header_buff[$num_header_words] = $(XE_MACRO)(metadata.time_spec.get_ticks(tick_rate)); + header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_tick_count(tick_rate))); #set $num_header_words += 1 #set $flags |= (0x1 << 20); #end if @@ -147,6 +147,7 @@ void vrt::unpack_$(suffix)( ){ //clear the metadata metadata = rx_metadata_t(); + boost::uint32_t secs = 0, ticks = 0; //extract vrt header boost::uint32_t vrt_hdr_word = $(XE_MACRO)(header_buff[0]); @@ -185,18 +186,19 @@ void vrt::unpack_$(suffix)( ########## Integer Time ########## #if $pred & $tsi_p #set $has_time_spec = True - metadata.time_spec.secs = $(XE_MACRO)(header_buff[$num_header_words]); + secs = $(XE_MACRO)(header_buff[$num_header_words]); #set $num_header_words += 1 #end if ########## Fractional Time ########## #if $pred & $tsf_p #set $has_time_spec = True #set $num_header_words += 1 - metadata.time_spec.set_ticks($(XE_MACRO)(header_buff[$num_header_words]), tick_rate); + ticks = $(XE_MACRO)(header_buff[$num_header_words]); #set $num_header_words += 1 #end if #if $has_time_spec metadata.has_time_spec = true; + metadata.time_spec = time_spec_t(secs, ticks, tick_rate); #end if ########## Trailer ########## #if $pred & $tlr_p diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 78a3d22ce..6a9fcf5b5 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -120,47 +120,63 @@ tx_metadata_t::tx_metadata_t(void): /*********************************************************************** * time spec **********************************************************************/ -static inline void time_spec_normalize(time_spec_t &time_spec){ - time_spec.secs += boost::uint32_t(std::ceil(time_spec.nsecs/1e9)); - time_spec.nsecs = std::fmod(time_spec.nsecs, 1e9); +time_spec_t::time_spec_t(double secs): + _full_secs(0), + _frac_secs(secs) +{ + /* NOP */ } -time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs): - secs(secs), - nsecs(nsecs) +time_spec_t::time_spec_t(time_t full_secs, double frac_secs): + _full_secs(full_secs), + _frac_secs(frac_secs) { /* NOP */ } -time_spec_t::time_spec_t(boost::uint32_t secs, boost::uint32_t ticks, double tick_rate): - secs(secs), - nsecs(double(ticks)*1e9/tick_rate) +time_spec_t::time_spec_t(time_t full_secs, size_t tick_count, double tick_rate): + _full_secs(full_secs), + _frac_secs(double(tick_count)/tick_rate) { /* NOP */ } -boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ - return boost::math::iround(nsecs*tick_rate*1e-9); +size_t time_spec_t::get_tick_count(double tick_rate) const{ + return boost::math::iround(this->get_frac_secs()*tick_rate); +} + +double time_spec_t::get_real_secs(void) const{ + return this->_full_secs + this->_frac_secs; } -void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){ - nsecs = double(ticks)*1e9/tick_rate; +time_t time_spec_t::get_full_secs(void) const{ + return this->_full_secs + time_t(std::floor(this->_frac_secs)); +} + +double time_spec_t::get_frac_secs(void) const{ + return std::fmod(this->_frac_secs, 1.0); } time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ - this->secs += rhs.secs; - this->nsecs += rhs.nsecs; + this->_full_secs += rhs.get_full_secs(); + this->_frac_secs += rhs.get_frac_secs(); return *this; } time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){ - this->secs -= rhs.secs; - this->nsecs -= rhs.nsecs; + this->_full_secs -= rhs.get_full_secs(); + this->_frac_secs -= rhs.get_frac_secs(); return *this; } bool uhd::operator==(const time_spec_t &lhs, const time_spec_t &rhs){ - return lhs.secs == rhs.secs and lhs.nsecs == rhs.nsecs; + return lhs.get_full_secs() == rhs.get_full_secs() and lhs.get_frac_secs() == rhs.get_frac_secs(); +} + +bool uhd::operator<(const time_spec_t &lhs, const time_spec_t &rhs){ + if (lhs.get_full_secs() < rhs.get_full_secs()) return true; + if (lhs.get_full_secs() > rhs.get_full_secs()) return false; + return lhs.get_frac_secs() < rhs.get_frac_secs(); } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 78fc5dc23..1a0f9916b 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -84,14 +84,14 @@ void usrp2_impl::update_clock_config(void){ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ //set the ticks - _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq())); + _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); //set the flags register boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS; _iface->poke32(U2_REG_TIME64_IMM, imm_flags); //set the seconds (latches in all 3 registers) - _iface->poke32(U2_REG_TIME64_SECS, time_spec.secs); + _iface->poke32(U2_REG_TIME64_SECS, time_spec.get_full_secs()); } void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ @@ -118,8 +118,8 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 )); - _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs); - _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq())); + _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.get_full_secs()); + _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); } /*********************************************************************** diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 3e596164c..3776e33aa 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -66,8 +66,8 @@ static void pack_and_unpack( } BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec); if (metadata.has_time_spec and metadata_out.has_time_spec){ - BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs); - BOOST_CHECK_EQUAL(metadata.time_spec.nsecs, metadata_out.time_spec.nsecs); + BOOST_CHECK_EQUAL(metadata.time_spec.get_full_secs(), metadata_out.time_spec.get_full_secs()); + BOOST_CHECK_EQUAL(metadata.time_spec.get_frac_secs(), metadata_out.time_spec.get_frac_secs()); } } @@ -86,8 +86,7 @@ BOOST_AUTO_TEST_CASE(test_with_sid){ BOOST_AUTO_TEST_CASE(test_with_time_spec){ uhd::tx_metadata_t metadata; metadata.has_time_spec = true; - metadata.time_spec.secs = 7; - metadata.time_spec.nsecs = 2000; + metadata.time_spec = uhd::time_spec_t(7, 0.2); pack_and_unpack(metadata, 500, 3); } @@ -96,7 +95,6 @@ BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ metadata.has_stream_id = true; metadata.stream_id = 2; metadata.has_time_spec = true; - metadata.time_spec.secs = 5; - metadata.time_spec.nsecs = 1000; + metadata.time_spec = uhd::time_spec_t(5, 0.1); pack_and_unpack(metadata, 600, 4); } -- cgit v1.2.3 From 0a57031a8a2eee5c490350484b32ac3ccb000b2f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 25 Jun 2010 19:54:08 -0700 Subject: uhd: fix for windows warning, tweaks for msvc optimization flags --- host/CMakeLists.txt | 13 +++++++++---- host/lib/usrp/usrp2/mboard_impl.cpp | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'host') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index a8b89d6c5..2979b4279 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -55,7 +55,7 @@ MACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have) ENDIF(${have}) ENDMACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG) -IF(UNIX) +IF(CMAKE_COMPILER_IS_GNUCXX) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC) @@ -63,14 +63,19 @@ IF(UNIX) #only export symbols that are declared to be part of the uhd api: UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations -ENDIF(UNIX) +ENDIF(CMAKE_COMPILER_IS_GNUCXX) -IF(WIN32) +IF(MSVC) + #Set the predefined cxx debug flags to have only the debug flags + #because the default flags disable optimization which we want to have. + #Setting CMAKE_BUILD_TYPE to "release" does not seem to fix this issue. + SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd") #FIXME better way to do this? ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc -ENDIF(WIN32) + ADD_DEFINITIONS(/arch:SSE2 /G7 /O2 /fp:fast) #optimization flags +ENDIF(MSVC) ######################################################################## # Setup Boost diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 1a0f9916b..2c900b328 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -91,7 +91,7 @@ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ _iface->poke32(U2_REG_TIME64_IMM, imm_flags); //set the seconds (latches in all 3 registers) - _iface->poke32(U2_REG_TIME64_SECS, time_spec.get_full_secs()); + _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); } void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ @@ -118,7 +118,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 )); - _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.get_full_secs()); + _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); } -- cgit v1.2.3 From a34f930a79a0c626706a5f7532d8f692446d3c35 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 26 Jun 2010 23:06:47 -0700 Subject: uhd: removed hackery to set performance flags, use release mode. The correct optimization flags are added when the build type is set to release. Made a change to set built type to release if not specified, and added build guide notes. For MSVC, one must set release mode from the visual studio IDE. --- host/CMakeLists.txt | 13 +++++++------ host/docs/build.rst | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'host') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 2979b4279..c60372fb9 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -55,6 +55,12 @@ MACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have) ENDIF(${have}) ENDMACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG) +#select the release build type by default to get optimization flags +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release") + MESSAGE(STATUS "Build type not specified: defaulting to release.") +ENDIF(NOT CMAKE_BUILD_TYPE) + IF(CMAKE_COMPILER_IS_GNUCXX) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA) @@ -62,19 +68,14 @@ IF(CMAKE_COMPILER_IS_GNUCXX) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI) #only export symbols that are declared to be part of the uhd api: UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) - UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(MSVC) - #Set the predefined cxx debug flags to have only the debug flags - #because the default flags disable optimization which we want to have. - #Setting CMAKE_BUILD_TYPE to "release" does not seem to fix this issue. - SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd") #FIXME better way to do this? ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc - ADD_DEFINITIONS(/arch:SSE2 /G7 /O2 /fp:fast) #optimization flags + ADD_DEFINITIONS(/arch:SSE2 /G7) #processor optimization flags ENDIF(MSVC) ######################################################################## diff --git a/host/docs/build.rst b/host/docs/build.rst index f5a8dac8d..a00cefabd 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -138,6 +138,7 @@ Generate the project with cmake Build the project in MSVC ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Open the generated project file in MSVC. +* Change the build type from "Debug" to "Release". * Select the build all target, right click, and choose build. * Select the install target, right click, and choose build. -- cgit v1.2.3 From f0005a27c3c0ff3148bab53eefdafcad799f03cc Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 21 Jun 2010 15:51:33 -0700 Subject: uhd: replaced single sample converters with vector converters easy to conditionally compile in SIMD instrinsics etc.. --- host/lib/transport/gen_convert_types.py | 143 ++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 46 deletions(-) (limited to 'host') diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index af2bcc7cb..e81bf7330 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -28,53 +28,92 @@ TMPL_TEXT = """ \#include \#include \#include +\#include \#include -//define the endian macros to convert integers \#ifdef BOOST_BIG_ENDIAN - \#define BE_MACRO(x) x - \#define LE_MACRO(x) uhd::byteswap(x) static const bool is_big_endian = true; \#else - \#define BE_MACRO(x) uhd::byteswap(x) - \#define LE_MACRO(x) x static const bool is_big_endian = false; \#endif using namespace uhd; /*********************************************************************** - * Constants + * Typedefs **********************************************************************/ typedef std::complex fc32_t; typedef std::complex sc16_t; typedef boost::uint32_t item32_t; -static const float shorts_per_float = float(32767); -static const float floats_per_short = float(1.0/shorts_per_float); +/*********************************************************************** + * Convert complex short buffer to items32 + **********************************************************************/ +static UHD_INLINE void sc16_to_item32_nswap( + const sc16_t *input, item32_t *output, size_t nsamps +){ + std::memcpy(output, input, nsamps*sizeof(item32_t)); +} + +static UHD_INLINE void sc16_to_item32_bswap( + const sc16_t *input, item32_t *output, size_t nsamps +){ + const item32_t *item32_input = (const item32_t *)input; + for (size_t i = 0; i < nsamps; i++){ + output[i] = uhd::byteswap(item32_input[i]); + } +} /*********************************************************************** - * Single-sample converters + * Convert items32 buffer to complex short **********************************************************************/ -static UHD_INLINE item32_t sc16_to_item32(sc16_t num){ - boost::uint16_t real = boost::int16_t(num.real()); - boost::uint16_t imag = boost::int16_t(num.imag()); - return (item32_t(real) << 16) | (item32_t(imag) << 0); +static UHD_INLINE void item32_to_sc16_nswap( + const item32_t *input, sc16_t *output, size_t nsamps +){ + std::memcpy(output, input, nsamps*sizeof(item32_t)); } -static UHD_INLINE sc16_t item32_to_sc16(item32_t item){ - return sc16_t( - boost::uint16_t(item >> 16), - boost::uint16_t(item >> 0) - ); +static UHD_INLINE void item32_to_sc16_bswap( + const item32_t *input, sc16_t *output, size_t nsamps +){ + item32_t *item32_output = (item32_t *)output; + for (size_t i = 0; i < nsamps; i++){ + item32_output[i] = uhd::byteswap(input[i]); + } } +/*********************************************************************** + * Convert complex float buffer to items32 + **********************************************************************/ +static const float shorts_per_float = float(32767); + static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); return (item32_t(real) << 16) | (item32_t(imag) << 0); } +static UHD_INLINE void fc32_to_item32_nswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = fc32_to_item32(input[i]); + } +} + +static UHD_INLINE void fc32_to_item32_bswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = uhd::byteswap(fc32_to_item32(input[i])); + } +} + +/*********************************************************************** + * Convert items32 buffer to complex float + **********************************************************************/ +static const float floats_per_short = float(1.0/shorts_per_float); + static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ return fc32_t( float(boost::int16_t(item >> 16)*floats_per_short), @@ -82,6 +121,22 @@ static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ ); } +static UHD_INLINE void item32_to_fc32_nswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = item32_to_fc32(input[i]); + } +} + +static UHD_INLINE void item32_to_fc32_bswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = item32_to_fc32(uhd::byteswap(input[i])); + } +} + /*********************************************************************** * Sample-buffer converters **********************************************************************/ @@ -92,21 +147,20 @@ UHD_INLINE boost::uint8_t get_pred( boost::uint8_t pred = 0; switch(otw_type.byteorder){ - case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.be_p; break; - case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.le_p; break; - ##let the compiler determine the native byte order (we could use python sys.byteorder) - case otw_type_t::BO_NATIVE: pred |= (is_big_endian)? $ph.be_p : $ph.le_p; break; + case otw_type_t::BO_BIG_ENDIAN: pred |= (is_big_endian)? $ph.nswap_p : $ph.bswap_p; break; + case otw_type_t::BO_LITTLE_ENDIAN: pred |= (is_big_endian)? $ph.bswap_p : $ph.nswap_p; break; + case otw_type_t::BO_NATIVE: pred |= $ph.nswap_p; break; default: throw std::runtime_error("unhandled byteorder type"); } - switch(otw_type.width){ - case 16: pred |= $ph.w16_p; break; + switch(otw_type.get_sample_size()){ + case sizeof(boost::uint32_t): pred |= $ph.item32_p; break; default: throw std::runtime_error("unhandled bit width"); } switch(io_type.tid){ - case io_type_t::COMPLEX_INT16: pred |= $ph.sc16_p; break; case io_type_t::COMPLEX_FLOAT32: pred |= $ph.fc32_p; break; + case io_type_t::COMPLEX_INT16: pred |= $ph.sc16_p; break; default: throw std::runtime_error("unhandled io type id"); } @@ -123,11 +177,8 @@ void transport::convert_io_type_to_otw_type( case $pred: #set $out_type = $ph.get_dev_type($pred) #set $in_type = $ph.get_host_type($pred) - #set $converter = $in_type+"_to_"+$out_type - #set $xe_macro = $ph.get_xe_macro($pred) - for (size_t i = 0; i < num_samps; i++){ - (($(out_type)_t *)otw_buff)[i] = $(xe_macro)($(converter)(((const $(in_type)_t *)io_buff)[i])); - } + #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)]) + $(converter)((const $(in_type)_t *)io_buff, ($(out_type)_t *)otw_buff, num_samps); break; #end for } @@ -143,11 +194,8 @@ void transport::convert_otw_type_to_io_type( case $pred: #set $out_type = $ph.get_host_type($pred) #set $in_type = $ph.get_dev_type($pred) - #set $converter = $in_type+"_to_"+$out_type - #set $xe_macro = $ph.get_xe_macro($pred) - for (size_t i = 0; i < num_samps; i++){ - (($(out_type)_t *)io_buff)[i] = $(converter)($(xe_macro)(((const $(in_type)_t *)otw_buff)[i])); - } + #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)]) + $(converter)((const $(in_type)_t *)otw_buff, ($(out_type)_t *)io_buff, num_samps); break; #end for } @@ -160,29 +208,32 @@ def parse_tmpl(_tmpl_text, **kwargs): return str(Template(_tmpl_text, kwargs)) class ph: - be_p = 0b00001 - le_p = 0b00000 - w16_p = 0b00000 - sc16_p = 0b00010 - fc32_p = 0b00000 + bswap_p = 0b00001 + nswap_p = 0b00000 + item32_p = 0b00000 + sc16_p = 0b00010 + fc32_p = 0b00000 nbits = 2 #see above @staticmethod - def get_xe_macro(pred): - if (pred & ph.be_p) == ph.be_p: return 'BE_MACRO' - if (pred & ph.le_p) == ph.le_p: return 'LE_MACRO' + def has(pred, flag): return (pred & flag) == flag + + @staticmethod + def get_swap_type(pred): + if ph.has(pred, ph.bswap_p): return 'bswap' + if ph.has(pred, ph.nswap_p): return 'nswap' raise NotImplementedError @staticmethod def get_dev_type(pred): - if (pred & ph.w16_p) == ph.w16_p: return 'item32' + if ph.has(pred, ph.item32_p): return 'item32' raise NotImplementedError @staticmethod def get_host_type(pred): - if (pred & ph.sc16_p) == ph.sc16_p: return 'sc16' - if (pred & ph.fc32_p) == ph.fc32_p: return 'fc32' + if ph.has(pred, ph.sc16_p): return 'sc16' + if ph.has(pred, ph.fc32_p): return 'fc32' raise NotImplementedError if __name__ == '__main__': -- cgit v1.2.3 From 45dc078069798d14f33518033e58d9aa7ace99f1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 22 Jun 2010 15:41:59 -0700 Subject: uhd: implemented complex float <-> item32 conversion with sse2 --- host/lib/transport/CMakeLists.txt | 10 +++++ host/lib/transport/gen_convert_types.py | 74 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) (limited to 'host') diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 872865d6c..a2bd17b01 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -17,6 +17,16 @@ #This file will be included by cmake, use absolute paths! +######################################################################## +# Check for SIMD headers +######################################################################## +INCLUDE(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H) + +IF(HAVE_EMMINTRIN_H) + ADD_DEFINITIONS(-DHAVE_EMMINTRIN_H) +ENDIF(HAVE_EMMINTRIN_H) + ######################################################################## # Setup defines for interface address discovery ######################################################################## diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index e81bf7330..6b87bf134 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -30,6 +30,9 @@ TMPL_TEXT = """ \#include \#include \#include +\#include + +\#define USE_EMMINTRIN_H true \#ifdef BOOST_BIG_ENDIAN static const bool is_big_endian = true; @@ -101,6 +104,39 @@ static UHD_INLINE void fc32_to_item32_nswap( } } +\#if defined(HAVE_EMMINTRIN_H) && USE_EMMINTRIN_H +\#include + +static UHD_INLINE void fc32_to_item32_bswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(shorts_per_float); + + //convert samples with intrinsics pairs at a time + size_t i = 0; for (; i < nsamps/4; i+=4){ + //load from input + __m128 tmplo = _mm_loadu_ps(reinterpret_cast(input+i+0)); + __m128 tmphi = _mm_loadu_ps(reinterpret_cast(input+i+2)); + + //convert and scale + __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); + __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); + + //pack + byteswap -> byteswap 32 bit words + __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); + tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); + + //store to output + _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); + } + + //convert remainder + for (; i < nsamps; i++){ + output[i] = uhd::byteswap(fc32_to_item32(input[i])); + } +} + +\#else static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ @@ -109,6 +145,8 @@ static UHD_INLINE void fc32_to_item32_bswap( } } +\#endif + /*********************************************************************** * Convert items32 buffer to complex float **********************************************************************/ @@ -129,6 +167,40 @@ static UHD_INLINE void item32_to_fc32_nswap( } } +\#if defined(HAVE_EMMINTRIN_H) && USE_EMMINTRIN_H +\#include + +static UHD_INLINE void item32_to_fc32_bswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); + + //convert samples with intrinsics pairs at a time + size_t i = 0; for (; i < nsamps/4; i+=4){ + //load from input + __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); + + //byteswap + unpack -> byteswap 32 bit words + tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); + __m128i tmpilo = _mm_unpacklo_epi16(tmpi, tmpi); + __m128i tmpihi = _mm_unpackhi_epi16(tmpi, tmpi); + + //convert and scale + __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); + __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); + + //store to output + _mm_storeu_ps(reinterpret_cast(output+i+0), tmplo); + _mm_storeu_ps(reinterpret_cast(output+i+2), tmphi); + } + + //convert remainder + for (; i < nsamps; i++){ + output[i] = item32_to_fc32(uhd::byteswap(input[i])); + } +} + +\#else static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ @@ -137,6 +209,8 @@ static UHD_INLINE void item32_to_fc32_bswap( } } +\#endif + /*********************************************************************** * Sample-buffer converters **********************************************************************/ -- cgit v1.2.3 From b46f9f53c9252f69c0ab60a948373431da4fc54f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 22 Jun 2010 17:00:57 -0700 Subject: uhd: moved convert routines into implementation header file (out of python gen file) --- host/lib/transport/CMakeLists.txt | 10 ++ host/lib/transport/convert_types_impl.hpp | 200 ++++++++++++++++++++++++++++++ host/lib/transport/gen_convert_types.py | 184 ++------------------------- 3 files changed, 218 insertions(+), 176 deletions(-) create mode 100644 host/lib/transport/convert_types_impl.hpp (limited to 'host') diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index a2bd17b01..70cf6312d 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -59,6 +59,16 @@ LIBUHD_PYTHON_GEN_SOURCE( ${CMAKE_BINARY_DIR}/lib/transport/convert_types.cpp ) +# append this directory to the include path so the generated convert types +# can include the implementation convert types file in the source directory +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/transport) + +# make the generated convert types depend on the implementation header +SET_SOURCE_FILES_PROPERTIES( + ${CMAKE_BINARY_DIR}/lib/transport/convert_types.cpp PROPERTIES + OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/lib/transport/convert_types_impl.hpp +) + LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp new file mode 100644 index 000000000..58cc69eb0 --- /dev/null +++ b/host/lib/transport/convert_types_impl.hpp @@ -0,0 +1,200 @@ +// +// 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_CONVERT_TYPES_IMPL_HPP +#define INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP + +#include +#include +#include +#include +#include + +#ifdef HAVE_EMMINTRIN_H + #define USE_EMMINTRIN_H //use sse2 intrinsics +#endif + +/*********************************************************************** + * Typedefs + **********************************************************************/ +typedef std::complex fc32_t; +typedef std::complex sc16_t; +typedef boost::uint32_t item32_t; + +/*********************************************************************** + * Convert complex short buffer to items32 + **********************************************************************/ +static UHD_INLINE void sc16_to_item32_nswap( + const sc16_t *input, item32_t *output, size_t nsamps +){ + std::memcpy(output, input, nsamps*sizeof(item32_t)); +} + +static UHD_INLINE void sc16_to_item32_bswap( + const sc16_t *input, item32_t *output, size_t nsamps +){ + const item32_t *item32_input = (const item32_t *)input; + for (size_t i = 0; i < nsamps; i++){ + output[i] = uhd::byteswap(item32_input[i]); + } +} + +/*********************************************************************** + * Convert items32 buffer to complex short + **********************************************************************/ +static UHD_INLINE void item32_to_sc16_nswap( + const item32_t *input, sc16_t *output, size_t nsamps +){ + std::memcpy(output, input, nsamps*sizeof(item32_t)); +} + +static UHD_INLINE void item32_to_sc16_bswap( + const item32_t *input, sc16_t *output, size_t nsamps +){ + item32_t *item32_output = (item32_t *)output; + for (size_t i = 0; i < nsamps; i++){ + item32_output[i] = uhd::byteswap(input[i]); + } +} + +/*********************************************************************** + * Convert complex float buffer to items32 + **********************************************************************/ +static const float shorts_per_float = float(32767); + +static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ + boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); + boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); + return (item32_t(real) << 16) | (item32_t(imag) << 0); +} + +static UHD_INLINE void fc32_to_item32_nswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = fc32_to_item32(input[i]); + } +} + +#if defined(USE_EMMINTRIN_H) +#include + +static UHD_INLINE void fc32_to_item32_bswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(shorts_per_float); + + //convert blocks of samples with intrinsics + size_t i = 0; for (; i < nsamps/4; i+=4){ + //load from input + __m128 tmplo = _mm_loadu_ps(reinterpret_cast(input+i+0)); + __m128 tmphi = _mm_loadu_ps(reinterpret_cast(input+i+2)); + + //convert and scale + __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); + __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); + + //pack + byteswap -> byteswap 32 bit words + __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); + tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); + + //store to output + _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); + } + + //convert remainder + for (; i < nsamps; i++){ + output[i] = uhd::byteswap(fc32_to_item32(input[i])); + } +} + +#else +static UHD_INLINE void fc32_to_item32_bswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = uhd::byteswap(fc32_to_item32(input[i])); + } +} + +#endif + +/*********************************************************************** + * Convert items32 buffer to complex float + **********************************************************************/ +static const float floats_per_short = float(1.0/shorts_per_float); + +static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ + return fc32_t( + float(boost::int16_t(item >> 16)*floats_per_short), + float(boost::int16_t(item >> 0)*floats_per_short) + ); +} + +static UHD_INLINE void item32_to_fc32_nswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = item32_to_fc32(input[i]); + } +} + +#if defined(USE_EMMINTRIN_H) +#include + +static UHD_INLINE void item32_to_fc32_bswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); + + //convert blocks of samples with intrinsics + size_t i = 0; for (; i < nsamps/4; i+=4){ + //load from input + __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); + + //byteswap + unpack -> byteswap 32 bit words + tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); + __m128i tmpilo = _mm_unpacklo_epi16(tmpi, tmpi); + __m128i tmpihi = _mm_unpackhi_epi16(tmpi, tmpi); + + //convert and scale + __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); + __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); + + //store to output + _mm_storeu_ps(reinterpret_cast(output+i+0), tmplo); + _mm_storeu_ps(reinterpret_cast(output+i+2), tmphi); + } + + //convert remainder + for (; i < nsamps; i++){ + output[i] = item32_to_fc32(uhd::byteswap(input[i])); + } +} + +#else +static UHD_INLINE void item32_to_fc32_bswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + for (size_t i = 0; i < nsamps; i++){ + output[i] = item32_to_fc32(uhd::byteswap(input[i])); + } +} + +#endif + +#endif /* INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP */ diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index 6b87bf134..b37fe242b 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -24,15 +24,10 @@ TMPL_TEXT = """ \#include \#include -\#include \#include \#include \#include -\#include -\#include -\#include - -\#define USE_EMMINTRIN_H true +\#include "convert_types_impl.hpp" \#ifdef BOOST_BIG_ENDIAN static const bool is_big_endian = true; @@ -43,176 +38,7 @@ TMPL_TEXT = """ using namespace uhd; /*********************************************************************** - * Typedefs - **********************************************************************/ -typedef std::complex fc32_t; -typedef std::complex sc16_t; -typedef boost::uint32_t item32_t; - -/*********************************************************************** - * Convert complex short buffer to items32 - **********************************************************************/ -static UHD_INLINE void sc16_to_item32_nswap( - const sc16_t *input, item32_t *output, size_t nsamps -){ - std::memcpy(output, input, nsamps*sizeof(item32_t)); -} - -static UHD_INLINE void sc16_to_item32_bswap( - const sc16_t *input, item32_t *output, size_t nsamps -){ - const item32_t *item32_input = (const item32_t *)input; - for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(item32_input[i]); - } -} - -/*********************************************************************** - * Convert items32 buffer to complex short - **********************************************************************/ -static UHD_INLINE void item32_to_sc16_nswap( - const item32_t *input, sc16_t *output, size_t nsamps -){ - std::memcpy(output, input, nsamps*sizeof(item32_t)); -} - -static UHD_INLINE void item32_to_sc16_bswap( - const item32_t *input, sc16_t *output, size_t nsamps -){ - item32_t *item32_output = (item32_t *)output; - for (size_t i = 0; i < nsamps; i++){ - item32_output[i] = uhd::byteswap(input[i]); - } -} - -/*********************************************************************** - * Convert complex float buffer to items32 - **********************************************************************/ -static const float shorts_per_float = float(32767); - -static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ - boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); - boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); - return (item32_t(real) << 16) | (item32_t(imag) << 0); -} - -static UHD_INLINE void fc32_to_item32_nswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = fc32_to_item32(input[i]); - } -} - -\#if defined(HAVE_EMMINTRIN_H) && USE_EMMINTRIN_H -\#include - -static UHD_INLINE void fc32_to_item32_bswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - __m128 scalar = _mm_set_ps1(shorts_per_float); - - //convert samples with intrinsics pairs at a time - size_t i = 0; for (; i < nsamps/4; i+=4){ - //load from input - __m128 tmplo = _mm_loadu_ps(reinterpret_cast(input+i+0)); - __m128 tmphi = _mm_loadu_ps(reinterpret_cast(input+i+2)); - - //convert and scale - __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); - __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - - //pack + byteswap -> byteswap 32 bit words - __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); - tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); - - //store to output - _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); - } - - //convert remainder - for (; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); - } -} - -\#else -static UHD_INLINE void fc32_to_item32_bswap( - const fc32_t *input, item32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); - } -} - -\#endif - -/*********************************************************************** - * Convert items32 buffer to complex float - **********************************************************************/ -static const float floats_per_short = float(1.0/shorts_per_float); - -static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ - return fc32_t( - float(boost::int16_t(item >> 16)*floats_per_short), - float(boost::int16_t(item >> 0)*floats_per_short) - ); -} - -static UHD_INLINE void item32_to_fc32_nswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(input[i]); - } -} - -\#if defined(HAVE_EMMINTRIN_H) && USE_EMMINTRIN_H -\#include - -static UHD_INLINE void item32_to_fc32_bswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); - - //convert samples with intrinsics pairs at a time - size_t i = 0; for (; i < nsamps/4; i+=4){ - //load from input - __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); - - //byteswap + unpack -> byteswap 32 bit words - tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); - __m128i tmpilo = _mm_unpacklo_epi16(tmpi, tmpi); - __m128i tmpihi = _mm_unpackhi_epi16(tmpi, tmpi); - - //convert and scale - __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); - __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); - - //store to output - _mm_storeu_ps(reinterpret_cast(output+i+0), tmplo); - _mm_storeu_ps(reinterpret_cast(output+i+2), tmphi); - } - - //convert remainder - for (; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); - } -} - -\#else -static UHD_INLINE void item32_to_fc32_bswap( - const item32_t *input, fc32_t *output, size_t nsamps -){ - for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); - } -} - -\#endif - -/*********************************************************************** - * Sample-buffer converters + * Generate predicate for jump table **********************************************************************/ UHD_INLINE boost::uint8_t get_pred( const io_type_t &io_type, @@ -241,6 +67,9 @@ UHD_INLINE boost::uint8_t get_pred( return pred; } +/*********************************************************************** + * Convert host type to device type + **********************************************************************/ void transport::convert_io_type_to_otw_type( const void *io_buff, const io_type_t &io_type, void *otw_buff, const otw_type_t &otw_type, @@ -258,6 +87,9 @@ void transport::convert_io_type_to_otw_type( } } +/*********************************************************************** + * Convert device type to host type + **********************************************************************/ void transport::convert_otw_type_to_io_type( const void *otw_buff, const otw_type_t &otw_type, void *io_buff, const io_type_t &io_type, -- cgit v1.2.3 From a9a47d0a69419e862657567a4228e8de0f4b8342 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 25 Jun 2010 15:57:08 -0700 Subject: uhd: convert types simd, unpack with zero constant for lower half --- host/lib/transport/convert_types_impl.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'host') diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index 58cc69eb0..ca1be175c 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -160,6 +160,7 @@ static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); + __m128i zeroi = _mm_setzero_si128(); //convert blocks of samples with intrinsics size_t i = 0; for (; i < nsamps/4; i+=4){ @@ -168,8 +169,8 @@ static UHD_INLINE void item32_to_fc32_bswap( //byteswap + unpack -> byteswap 32 bit words tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); - __m128i tmpilo = _mm_unpacklo_epi16(tmpi, tmpi); - __m128i tmpihi = _mm_unpackhi_epi16(tmpi, tmpi); + __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits + __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); //convert and scale __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); -- cgit v1.2.3 From a094f2a6373552c74657c73d048a938bcdeb6907 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 26 Jun 2010 00:33:37 -0700 Subject: uhd: moron alert, used incorrect bounds in simd loop, the remainder loop was doing 3/4 the work --- host/lib/transport/convert_types_impl.hpp | 4 ++-- host/lib/transport/gen_convert_types.py | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'host') diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index ca1be175c..5958b08cb 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -99,7 +99,7 @@ static UHD_INLINE void fc32_to_item32_bswap( __m128 scalar = _mm_set_ps1(shorts_per_float); //convert blocks of samples with intrinsics - size_t i = 0; for (; i < nsamps/4; i+=4){ + size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ //load from input __m128 tmplo = _mm_loadu_ps(reinterpret_cast(input+i+0)); __m128 tmphi = _mm_loadu_ps(reinterpret_cast(input+i+2)); @@ -163,7 +163,7 @@ static UHD_INLINE void item32_to_fc32_bswap( __m128i zeroi = _mm_setzero_si128(); //convert blocks of samples with intrinsics - size_t i = 0; for (; i < nsamps/4; i+=4){ + size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ //load from input __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index b37fe242b..951b634d9 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -29,12 +29,6 @@ TMPL_TEXT = """ \#include \#include "convert_types_impl.hpp" -\#ifdef BOOST_BIG_ENDIAN - static const bool is_big_endian = true; -\#else - static const bool is_big_endian = false; -\#endif - using namespace uhd; /*********************************************************************** @@ -47,15 +41,20 @@ UHD_INLINE boost::uint8_t get_pred( boost::uint8_t pred = 0; switch(otw_type.byteorder){ - case otw_type_t::BO_BIG_ENDIAN: pred |= (is_big_endian)? $ph.nswap_p : $ph.bswap_p; break; - case otw_type_t::BO_LITTLE_ENDIAN: pred |= (is_big_endian)? $ph.bswap_p : $ph.nswap_p; break; + \#ifdef BOOST_BIG_ENDIAN + case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.nswap_p; break; + case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.bswap_p; break; + \#else + case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.bswap_p; break; + case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.nswap_p; break; + \#endif case otw_type_t::BO_NATIVE: pred |= $ph.nswap_p; break; - default: throw std::runtime_error("unhandled byteorder type"); + default: throw std::runtime_error("unhandled otw byteorder type"); } switch(otw_type.get_sample_size()){ case sizeof(boost::uint32_t): pred |= $ph.item32_p; break; - default: throw std::runtime_error("unhandled bit width"); + default: throw std::runtime_error("unhandled otw sample size"); } switch(io_type.tid){ -- cgit v1.2.3 From e057e6afde4b4be21f0e30ee6071599288b0e8a8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 28 Jun 2010 15:15:14 -0700 Subject: uhd: added build notes for fedora 64 boost not found --- host/docs/build.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'host') diff --git a/host/docs/build.rst b/host/docs/build.rst index a00cefabd..108d8dc8b 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -97,7 +97,10 @@ Generate Makefiles with cmake cd build cmake ../ -For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX= ../ +**Notes:** + +* For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX= ../ +* On some Fedora 64-bit systems, cmake has trouble finding boost, use: cmake -DBOOST_LIBRARYDIR=/usr/lib64 ../ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Build and install -- cgit v1.2.3 From 01e5f592d62e2193cc88081bd88765cae4708148 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 12:29:31 -0700 Subject: usrp2: increased transport buffer minimum size, and added warning added more notes on buffer size to the manual pulled in some firmware fixes from the mimo work, just to have them in here --- firmware/microblaze/apps/txrx_uhd.c | 8 ++++---- host/docs/usrp2.rst | 28 ++++++++++++++++------------ host/lib/transport/udp_zero_copy_asio.cpp | 9 ++++++++- host/lib/usrp/usrp2/usrp2_iface.cpp | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) (limited to 'host') diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 45e5ff5fe..21803b199 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -177,7 +177,7 @@ void handle_udp_ctrl_packet( unsigned char *payload, int payload_len ){ //printf("Got ctrl packet #words: %d\n", (int)payload_len); - usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; + const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; uint32_t ctrl_data_in_id = ctrl_data_in->id; //ensure that the protocol versions match @@ -288,15 +288,15 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: switch(ctrl_data_in->data.poke_args.num_bytes){ case sizeof(uint32_t): - ctrl_data_in->data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); + ctrl_data_out.data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); break; case sizeof(uint16_t): - ctrl_data_in->data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr); + ctrl_data_out.data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr); break; case sizeof(uint8_t): - ctrl_data_in->data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr); + ctrl_data_out.data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr); break; } diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 09987b3fa..aff0d0454 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -158,10 +158,25 @@ buffer incoming samples faster than they can be processed. However, if you application cannot process samples fast enough, no amount of buffering can save you. +By default, the UHD will try to request a reasonably large buffer size for both send and receive. +A warning will be printed on instantiation if the actual buffer size is insufficient. +See the OS specific notes below: + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +OS specific notes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On linux, the maximum buffer sizes are capped by the sysctl values +**net.core.rmem_max** and **net.core.wmem_max**. +To change the maximum values, run the following commands: +:: + + sudo sysctl -w net.core.rmem_max= + sudo sysctl -w net.core.wmem_max= + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Device address params ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To set the size of the buffers, +To manually set the size of the buffers, the usrp2 will accept two optional parameters in the device address. Each parameter will accept a numeric value for the number of bytes. @@ -172,14 +187,3 @@ Example, set the args string to the following: :: addr=192.168.10.2, recv_buff_size=100e6 - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -OS specific notes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -On linux, the maximum buffer sizes are capped by the sysctl values -**net.core.rmem_max** and **net.core.wmem_max**. -To change the maximum values, run the following commands: -:: - - sudo sysctl -w net.core.rmem_max= - sudo sysctl -w net.core.wmem_max= diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index c3c02707e..7f9292d24 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -27,7 +27,8 @@ using namespace uhd::transport; /*********************************************************************** * Constants **********************************************************************/ -static const size_t MIN_SOCK_BUFF_SIZE = size_t(100e3); +//enough buffering for half a second of samples at full rate on usrp2 +static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; //100 ms @@ -159,6 +160,12 @@ template static void resize_buff_helper( //otherwise, ensure that the buffer is at least the minimum size else if (udp_trans->get_buff_size() < MIN_SOCK_BUFF_SIZE){ resize_buff_helper(udp_trans, MIN_SOCK_BUFF_SIZE, name); + if (udp_trans->get_buff_size() < MIN_SOCK_BUFF_SIZE){ + std::cerr << boost::format( + "Warning: the %s buffer size is smaller than the recommended size of %d bytes.\n" + " See the USRP2 application notes on buffer resizing." + ) % name % MIN_SOCK_BUFF_SIZE << std::endl; + } } } diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 83e98904e..66a1a57f6 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -200,7 +200,7 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); - return T(ntohl(out_data.data.poke_args.data)); + return T(ntohl(in_data.data.poke_args.data)); } }; -- cgit v1.2.3 From 08fad28f209a2f6c79d939ad54ca3a1d4e270b0b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 29 Jun 2010 22:55:45 -0700 Subject: uhd: work vectorizing the vrt packet handler, reworked vrt packet stuff, needs testing --- host/include/uhd/device.hpp | 51 ++++-- host/include/uhd/transport/vrt.hpp | 110 ++++++------- host/include/uhd/types/metadata.hpp | 14 -- host/lib/transport/gen_vrt.py | 117 +++++++------- host/lib/transport/vrt_packet_handler.hpp | 252 ++++++++++++++++-------------- host/lib/types.cpp | 4 - host/lib/usrp/usrp2/io_impl.cpp | 32 ++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 9 +- host/test/vrt_test.cpp | 147 ++++++++++------- 9 files changed, 401 insertions(+), 335 deletions(-) (limited to 'host') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index d3e9015c4..f04a5b4fb 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace uhd{ @@ -96,8 +97,22 @@ public: RECV_MODE_ONE_PACKET = 1 }; + //! wrapper call for single buffer recv //TODO put somewhere + size_t send( + const boost::asio::const_buffer &buff, + const tx_metadata_t &metadata, + const io_type_t &io_type, + send_mode_t send_mode + ){ + return send( + std::vector(1, boost::asio::buffer_cast(buff)), + boost::asio::buffer_size(buff)/io_type.size, + metadata, io_type, send_mode + ); + } + /*! - * Send a buffer containing IF data with its metadata. + * Send buffers containing IF data described by the metadata. * * Send handles fragmentation as follows: * If the buffer has more samples than the maximum per packet, @@ -108,23 +123,39 @@ public: * 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. + * of samples returned have been read out of each buffer. * - * \param buff a buffer pointing to some read-only memory + * \param buffs a vector of read-only memory containing IF data + * \param nsamps_per_buff the number of samples to send, per buffer * \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 std::vector &buffs, + size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode ) = 0; + //! wrapper call for single buffer recv //TODO put somewhere + size_t recv( + const boost::asio::mutable_buffer &buff, + rx_metadata_t &metadata, + const io_type_t &io_type, + recv_mode_t recv_mode + ){ + return recv( + std::vector(1, boost::asio::buffer_cast(buff)), + boost::asio::buffer_size(buff)/io_type.size, + metadata, io_type, recv_mode + ); + } + /*! - * Receive a buffer containing IF data and its metadata. + * Receive buffers containing IF data described by the metadata. * * Receive handles fragmentation as follows: * If the buffer has insufficient space to hold all samples @@ -138,7 +169,7 @@ public: * See the rx metadata fragment flags and offset fields for details. * * This is a blocking call and will not return until the number - * of samples returned have been written into the buffer. + * of samples returned have been written into each buffer. * However, a call to receive may timeout and return zero samples. * The timeout duration is decided by the underlying transport layer. * The caller should assume that the call to receive will not return @@ -146,17 +177,19 @@ public: * 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. + * to the first packet received and written into the recv buffers. * Use the one packet recv mode to get per packet metadata. * - * \param buff the buffer to fill with IF data + * \param buffs a vector of writable memory to fill with IF data + * \param nsamps_per_buff the size of each buffer in number of samples * \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, + const std::vector &buffs, + size_t nsamps_per_buff, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index fb6efc99c..17da2d540 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -19,93 +19,77 @@ #define INCLUDED_UHD_TRANSPORT_VRT_HPP #include -#include -#include +#include +#include //size_t namespace uhd{ namespace transport{ namespace vrt{ - static const size_t max_header_words32 = 5; //hdr+sid+tsi+tsf (no class id supported) + //! The maximum number of 32-bit words in a vrt if packet header + static const size_t max_if_hdr_words32 = 7; //hdr+sid+cid+tsi+tsf + + /*! + * Definition for fields that can be packed into a vrt if header. + * The size fields are used for input and output depending upon + * the operation used (ie the pack or unpack function call). + */ + struct UHD_API if_packet_info_t{ + //size fields + size_t num_payload_words32; //required in pack, derived in unpack + size_t num_header_words32; //derived in pack, derived in unpack + size_t num_packet_words32; //derived in pack, required in unpack + + //header fields + size_t packet_count; + bool sob, eob; + + //optional fields + bool has_sid; boost::uint32_t sid; + bool has_cid; boost::uint64_t cid; + bool has_tsi; boost::uint32_t tsi; + bool has_tsf; boost::uint64_t tsf; + bool has_tlr; boost::uint32_t tlr; + }; /*! * Pack a vrt header from metadata (big endian format). - * \param metadata the tx metadata with flags and timestamps - * \param header_buff memory to write the packed vrt header - * \param num_header_words32 number of words in the vrt header - * \param num_payload_words32 the length of the payload - * \param num_packet_words32 the length of the packet - * \param packet_count the packet count sequence number - * \param tick_rate ticks per second used in time conversion + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) */ - UHD_API void pack_be( - const tx_metadata_t &metadata, //input - boost::uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count, //input - double tick_rate //input + UHD_API void if_hdr_pack_be( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info ); /*! * Unpack a vrt header to metadata (big endian format). - * \param metadata the rx metadata with flags and timestamps - * \param header_buff memory to read the packed vrt header - * \param num_header_words32 number of words in the vrt header - * \param num_payload_words32 the length of the payload - * \param num_packet_words32 the length of the packet - * \param packet_count the packet count sequence number - * \param tick_rate ticks per second used in time conversion + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) */ - UHD_API void unpack_be( - rx_metadata_t &metadata, //output - const boost::uint32_t *header_buff, //input - size_t &num_header_words32, //output - size_t &num_payload_words32, //output - size_t num_packet_words32, //input - size_t &packet_count, //output - double tick_rate //input + UHD_API void if_hdr_unpack_be( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info ); /*! * Pack a vrt header from metadata (little endian format). - * \param metadata the tx metadata with flags and timestamps - * \param header_buff memory to write the packed vrt header - * \param num_header_words32 number of words in the vrt header - * \param num_payload_words32 the length of the payload - * \param num_packet_words32 the length of the packet - * \param packet_count the packet count sequence number - * \param tick_rate ticks per second used in time conversion + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) */ - UHD_API void pack_le( - const tx_metadata_t &metadata, //input - boost::uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count, //input - double tick_rate //input + UHD_API void if_hdr_pack_le( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info ); /*! * Unpack a vrt header to metadata (little endian format). - * \param metadata the rx metadata with flags and timestamps - * \param header_buff memory to read the packed vrt header - * \param num_header_words32 number of words in the vrt header - * \param num_payload_words32 the length of the payload - * \param num_packet_words32 the length of the packet - * \param packet_count the packet count sequence number - * \param tick_rate ticks per second used in time conversion + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) */ - UHD_API void unpack_le( - rx_metadata_t &metadata, //output - const boost::uint32_t *header_buff, //input - size_t &num_header_words32, //output - size_t &num_payload_words32, //output - size_t num_packet_words32, //input - size_t &packet_count, //output - double tick_rate //input + UHD_API void if_hdr_unpack_le( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info ); } //namespace vrt diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp index 55add71cc..f4c962ff7 100644 --- a/host/include/uhd/types/metadata.hpp +++ b/host/include/uhd/types/metadata.hpp @@ -30,13 +30,6 @@ namespace uhd{ * The receive routines will convert IF data headers into metadata. */ struct UHD_API rx_metadata_t{ - /*! - * Stream IDs may be used to identify source DSP units. - * --Not currently used in any known device implementation.-- - */ - bool has_stream_id; - boost::uint32_t stream_id; - /*! * Time specification: * Set from timestamps on incoming data when provided. @@ -83,13 +76,6 @@ namespace uhd{ * The send routines will convert the metadata to IF data headers. */ struct UHD_API tx_metadata_t{ - /*! - * Stream IDs may be used to identify destination DSP units. - * --Not currently used in any known device implementation.-- - */ - bool has_stream_id; - boost::uint32_t stream_id; - /*! * Time specification: * Set has time spec to false to perform a send "now". diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 8e0fce9ff..ad87b9972 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -61,20 +61,22 @@ using namespace uhd::transport; #set $tsf_p = 0b01000 #set $tlr_p = 0b10000 -void vrt::pack_$(suffix)( - const tx_metadata_t &metadata, //input - boost::uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count, //input - double tick_rate //input +static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ + *(reinterpret_cast(mem)) = $(XE_MACRO)(num); +} + +void vrt::if_hdr_pack_$(suffix)( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info ){ boost::uint32_t vrt_hdr_flags = 0; boost::uint8_t pred = 0; - if (metadata.has_stream_id) pred |= $hex($sid_p); - if (metadata.has_time_spec) pred |= $hex($tsi_p | $tsf_p); + if (if_packet_info.has_sid) pred |= $hex($sid_p); + if (if_packet_info.has_cid) pred |= $hex($cid_p); + if (if_packet_info.has_tsi) pred |= $hex($tsi_p); + if (if_packet_info.has_tsf) pred |= $hex($tsf_p); + if (if_packet_info.has_tlr) pred |= $hex($tlr_p); switch(pred){ #for $pred in range(2**5) @@ -83,79 +85,71 @@ void vrt::pack_$(suffix)( #set $flags = 0 ########## Stream ID ########## #if $pred & $sid_p - header_buff[$num_header_words] = $(XE_MACRO)(metadata.stream_id); + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); #set $num_header_words += 1 #set $flags |= (0x1 << 28); #end if ########## Class ID ########## #if $pred & $cid_p - header_buff[$num_header_words] = 0; - #set $num_header_words += 1 - header_buff[$num_header_words] = 0; - #set $num_header_words += 1 + pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 #set $flags |= (0x1 << 27); #end if ########## Integer Time ########## #if $pred & $tsi_p - header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_full_secs())); + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); #set $num_header_words += 1 #set $flags |= (0x3 << 22); #end if ########## Fractional Time ########## #if $pred & $tsf_p - header_buff[$num_header_words] = 0; - #set $num_header_words += 1 - header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_tick_count(tick_rate))); - #set $num_header_words += 1 + pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 #set $flags |= (0x1 << 20); #end if ########## Trailer ########## #if $pred & $tlr_p + packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); #set $flags |= (0x1 << 26); #set $num_trailer_words = 1; #else #set $num_trailer_words = 0; #end if ########## Variables ########## - num_header_words32 = $num_header_words; - num_packet_words32 = $($num_header_words + $num_trailer_words) + num_payload_words32; + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; vrt_hdr_flags = $hex($flags); break; #end for } //set the burst flags - if (metadata.start_of_burst) vrt_hdr_flags |= $hex(0x1 << 25); - if (metadata.end_of_burst) vrt_hdr_flags |= $hex(0x1 << 24); + if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); + if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24); //fill in complete header word - header_buff[0] = $(XE_MACRO)(boost::uint32_t(0 + packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0 | vrt_hdr_flags - | ((packet_count & 0xf) << 16) - | (num_packet_words32 & 0xffff) + | ((if_packet_info.packet_count & 0xf) << 16) + | (if_packet_info.num_packet_words32 & 0xffff) )); } -void vrt::unpack_$(suffix)( - rx_metadata_t &metadata, //output - const boost::uint32_t *header_buff, //input - size_t &num_header_words32, //output - size_t &num_payload_words32, //output - size_t num_packet_words32, //input - size_t &packet_count, //output - double tick_rate //input -){ - //clear the metadata - metadata = rx_metadata_t(); - boost::uint32_t secs = 0, ticks = 0; +static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ + num = $(XE_MACRO)(*reinterpret_cast(mem)); +} +void vrt::if_hdr_unpack_$(suffix)( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +){ //extract vrt header - boost::uint32_t vrt_hdr_word = $(XE_MACRO)(header_buff[0]); + boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); size_t packet_words32 = vrt_hdr_word & 0xffff; - packet_count = (vrt_hdr_word >> 16) & 0xf; + if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0 or num_packet_words32 < packet_words32) + if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) throw std::runtime_error("unsupported vrt packet type"); @@ -174,41 +168,48 @@ void vrt::unpack_$(suffix)( #set $num_header_words = 1 ########## Stream ID ########## #if $pred & $sid_p - metadata.has_stream_id = true; - metadata.stream_id = $(XE_MACRO)(header_buff[$num_header_words]); + if_packet_info.has_sid = true; + if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); #set $num_header_words += 1 + #else + if_packet_info.has_sid = false; #end if ########## Class ID ########## #if $pred & $cid_p - #set $num_header_words += 1 - #set $num_header_words += 1 + if_packet_info.has_cid = true; + unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_cid = false; #end if ########## Integer Time ########## #if $pred & $tsi_p - #set $has_time_spec = True - secs = $(XE_MACRO)(header_buff[$num_header_words]); + if_packet_info.has_tsi = true; + if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); #set $num_header_words += 1 + #else + if_packet_info.has_tsi = false; #end if ########## Fractional Time ########## #if $pred & $tsf_p - #set $has_time_spec = True - #set $num_header_words += 1 - ticks = $(XE_MACRO)(header_buff[$num_header_words]); - #set $num_header_words += 1 - #end if - #if $has_time_spec - metadata.has_time_spec = true; - metadata.time_spec = time_spec_t(secs, ticks, tick_rate); + if_packet_info.has_tsf = true; + unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_tsf = false; #end if ########## Trailer ########## #if $pred & $tlr_p + if_packet_info.has_tlr = true; + if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); #set $num_trailer_words = 1; #else + if_packet_info.has_tlr = false; #set $num_trailer_words = 0; #end if ########## Variables ########## - num_header_words32 = $num_header_words; - num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); break; #end for } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 8dfc7b3d0..01cccd81e 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -30,37 +31,43 @@ #include #include #include +#include namespace vrt_packet_handler{ /*********************************************************************** * vrt packet handler for recv **********************************************************************/ + typedef std::vector managed_recv_buffs_t; + struct recv_state{ + //width of the receiver in channels + size_t width; + //init the expected seq number - size_t next_packet_seq; + std::vector next_packet_seq; //state variables to handle fragments - uhd::transport::managed_recv_buffer::sptr managed_buff; - boost::asio::const_buffer copy_buff; + managed_recv_buffs_t managed_buffs; + std::vector copy_buffs; + size_t size_of_copy_buffs; 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); + recv_state(size_t width): + width(width), + next_packet_seq(width, 0), + managed_buffs(width), + copy_buffs(width, NULL), + size_of_copy_buffs(0), + fragment_offset_in_samps(0) + { + /* NOP */ } }; - typedef boost::function get_recv_buff_t; - - typedef boost::function recv_cb_t; + typedef boost::function get_recv_buffs_t; - static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ - /* NOP */ - } + typedef boost::function recv_cb_t; /******************************************************************* * Unpack a received vrt header and set the copy buffer. @@ -74,33 +81,41 @@ namespace vrt_packet_handler{ vrt_unpacker_type vrt_unpacker, size_t vrt_header_offset_words32 ){ - size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + size_t num_packet_words32 = state.managed_buffs[0]->size()/sizeof(boost::uint32_t); if (num_packet_words32 <= vrt_header_offset_words32){ - state.copy_buff = boost::asio::buffer("", 0); + state.size_of_copy_buffs = 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; - vrt_unpacker( - 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; + //vrt unpack each managed buffer + uhd::transport::vrt::if_packet_info_t if_packet_info; + for (size_t i = 0; i < state.width; i++){ + const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast() + vrt_header_offset_words32; + if_packet_info.num_packet_words32 = num_packet_words32; + vrt_unpacker(vrt_hdr, if_packet_info); + + //handle the packet count / sequence number + if (if_packet_info.packet_count != state.next_packet_seq[i]){ + std::cerr << "S" << (if_packet_info.packet_count - state.next_packet_seq[i])%16; + } + state.next_packet_seq[i] = (if_packet_info.packet_count+1)%16; + + //setup the buffer to point to the data + state.copy_buffs[i] = reinterpret_cast(vrt_hdr + if_packet_info.num_header_words32); + + //store the minimum payload length into the copy buffer length + size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t); + if (i == 0 or state.size_of_copy_buffs > num_payload_bytes){ + state.size_of_copy_buffs = num_payload_bytes; + } } - 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) + //store the last vrt info into the metadata + metadata.has_time_spec = if_packet_info.has_tsi or if_packet_info.has_tsf; + metadata.time_spec = uhd::time_spec_t( + time_t((if_packet_info.has_tsi)? if_packet_info.tsi : 0), + size_t((if_packet_info.has_tsf)? if_packet_info.tsf : 0), + tick_rate ); } @@ -111,24 +126,22 @@ namespace vrt_packet_handler{ template static UHD_INLINE size_t _recv1( recv_state &state, - void *recv_mem, + const std::vector &buffs, + size_t offset_bytes, 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, vrt_unpacker_type vrt_unpacker, - const get_recv_buff_t &get_recv_buff, + const get_recv_buffs_t &get_recv_buffs, //use these two params to handle a layer above vrt - size_t vrt_header_offset_words32, - const recv_cb_t &recv_cb + size_t vrt_header_offset_words32 ){ //perform a receive if no rx data is waiting to be copied - if (boost::asio::buffer_size(state.copy_buff) == 0){ + if (state.size_of_copy_buffs == 0){ state.fragment_offset_in_samps = 0; - state.managed_buff = get_recv_buff(); - if (state.managed_buff.get() == NULL) return 0; - recv_cb(state.managed_buff); //callback before vrt unpack + if (not get_recv_buffs(state.managed_buffs)) return 0; try{ _recv1_helper( state, metadata, tick_rate, vrt_unpacker, vrt_header_offset_words32 @@ -141,26 +154,28 @@ 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 bytes_available = state.size_of_copy_buffs; size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); + size_t bytes_to_copy = num_samps*bytes_per_item; //setup the fragment flags and offset 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, - recv_mem, io_type, num_samps - ); + for (size_t i = 0; i < state.width; i++){ + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + state.copy_buffs[i], otw_type, + reinterpret_cast(buffs[i]) + offset_bytes, + 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 - ); + //update the rx copy buffer to reflect the bytes copied + state.copy_buffs[i] = reinterpret_cast(state.copy_buffs[i]) + bytes_to_copy; + } + //update the copy buffer's availability + state.size_of_copy_buffs -= bytes_to_copy; return num_samps; } @@ -171,20 +186,19 @@ namespace vrt_packet_handler{ template static UHD_INLINE size_t recv( recv_state &state, - const boost::asio::mutable_buffer &buff, + const std::vector &buffs, + const size_t total_num_samps, 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, vrt_unpacker_type vrt_unpacker, - const get_recv_buff_t &get_recv_buff, + const get_recv_buffs_t &get_recv_buffs, //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 = 0 ){ 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){ @@ -193,15 +207,14 @@ namespace vrt_packet_handler{ //////////////////////////////////////////////////////////////// return _recv1( state, - boost::asio::buffer_cast(buff), + buffs, 0, total_num_samps, metadata, io_type, otw_type, tick_rate, vrt_unpacker, - get_recv_buff, - vrt_header_offset_words32, - recv_cb + get_recv_buffs, + vrt_header_offset_words32 ); } @@ -213,15 +226,14 @@ namespace vrt_packet_handler{ while(accum_num_samps < total_num_samps){ size_t num_samps = _recv1( state, - boost::asio::buffer_cast(buff) + (accum_num_samps*io_type.size), + buffs, accum_num_samps*io_type.size, total_num_samps - accum_num_samps, (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept io_type, otw_type, tick_rate, vrt_unpacker, - get_recv_buff, - vrt_header_offset_words32, - recv_cb + get_recv_buffs, + vrt_header_offset_words32 ); if (num_samps == 0) break; //had a recv timeout or error, break loop accum_num_samps += num_samps; @@ -236,6 +248,8 @@ namespace vrt_packet_handler{ /*********************************************************************** * vrt packet handler for send **********************************************************************/ + typedef std::vector managed_send_buffs_t; + struct send_state{ //init the expected seq number size_t next_packet_seq; @@ -245,13 +259,9 @@ namespace vrt_packet_handler{ } }; - typedef boost::function get_send_buff_t; - - typedef boost::function send_cb_t; + typedef boost::function get_send_buffs_t; - static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ - /* NOP */ - } + typedef boost::function send_cb_t; /******************************************************************* * Pack a vrt header, copy-convert the data, and send it. @@ -260,46 +270,51 @@ namespace vrt_packet_handler{ template static UHD_INLINE void _send1( send_state &state, - const void *send_mem, + const std::vector &buffs, + size_t offset_bytes, 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, vrt_packer_type vrt_packer, - const get_send_buff_t &get_send_buff, - size_t vrt_header_offset_words32, - const send_cb_t& send_cb + const get_send_buffs_t &get_send_buffs, + size_t vrt_header_offset_words32 ){ - //get a new managed send buffer - uhd::transport::managed_send_buffer::sptr send_buff = 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++; - - //pack metadata into a vrt header - vrt_packer( - 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 + //translate the metadata to vrt if packet info + uhd::transport::vrt::if_packet_info_t if_packet_info; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tsi = metadata.has_time_spec; + if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); + if_packet_info.has_tsf = metadata.has_time_spec; + if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); + if_packet_info.has_tlr = false; + if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); + if_packet_info.packet_count = state.next_packet_seq++; + + //get send buffers for each channel + managed_send_buffs_t send_buffs(buffs.size()); + UHD_ASSERT_THROW(get_send_buffs(send_buffs)); + + for (size_t i = 0; i < buffs.size(); i++){ + //calculate pointers with offsets to io and otw memory + const boost::uint8_t *io_mem = reinterpret_cast(buffs[i]) + offset_bytes; + boost::uint32_t *otw_mem = send_buffs[i]->cast() + vrt_header_offset_words32; + + //pack metadata into a vrt header + vrt_packer(otw_mem, if_packet_info); + + //copy-convert the samples into the send buffer + uhd::transport::convert_io_type_to_otw_type( + io_mem, io_type, + otw_mem + if_packet_info.num_header_words32, otw_type, + num_samps + ); - //commit the samples to the zero-copy interface - send_buff->commit(num_packet_words32*sizeof(boost::uint32_t)); + //commit the samples to the zero-copy interface + send_buffs[i]->commit(if_packet_info.num_packet_words32*sizeof(boost::uint32_t)); + } } /******************************************************************* @@ -308,20 +323,19 @@ namespace vrt_packet_handler{ template static UHD_INLINE size_t send( send_state &state, - const boost::asio::const_buffer &buff, + const std::vector &buffs, + const size_t total_num_samps, 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, vrt_packer_type vrt_packer, - const get_send_buff_t &get_send_buff, + const get_send_buffs_t &get_send_buffs, 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 vrt_header_offset_words32 = 0 ){ - const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET; switch(send_mode){ @@ -331,15 +345,14 @@ namespace vrt_packet_handler{ size_t num_samps = std::min(total_num_samps, max_samples_per_packet); _send1( state, - boost::asio::buffer_cast(buff), + buffs, 0, num_samps, metadata, io_type, otw_type, tick_rate, vrt_packer, - get_send_buff, - vrt_header_offset_words32, - send_cb + get_send_buffs, + vrt_header_offset_words32 ); return num_samps; } @@ -366,15 +379,14 @@ namespace vrt_packet_handler{ //send the fragment with the helper function _send1( state, - boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), + buffs, n*max_samples_per_packet*io_type.size, (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, md, io_type, otw_type, tick_rate, vrt_packer, - get_send_buff, - vrt_header_offset_words32, - send_cb + get_send_buffs, + vrt_header_offset_words32 ); } return total_num_samps; diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 6a9fcf5b5..9cf2a2220 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -96,8 +96,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): * metadata **********************************************************************/ rx_metadata_t::rx_metadata_t(void): - has_stream_id(false), - stream_id(0), has_time_spec(false), time_spec(time_spec_t()), more_fragments(false), @@ -107,8 +105,6 @@ rx_metadata_t::rx_metadata_t(void): } tx_metadata_t::tx_metadata_t(void): - has_stream_id(false), - stream_id(0), has_time_spec(false), time_spec(time_spec_t()), start_of_burst(false), diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index aa0f63321..e3a3a3b17 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -52,7 +52,7 @@ struct usrp2_impl::io_impl{ bounded_buffer::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if){ +usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if): packet_handler_recv_state(1){ //create a large enough booty size_t num_frames = zc_if->get_num_recv_frames(); std::cout << "Recv pirate num frames: " << num_frames << std::endl; @@ -130,19 +130,26 @@ void usrp2_impl::io_init(void){ /*********************************************************************** * Send Data **********************************************************************/ +bool tmp_todo_fixme_remove_get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs, const zero_copy_if::sptr &zc_if){ + buffs[0] = zc_if->get_send_buff(); + return buffs[0].get() != NULL; +} + size_t usrp2_impl::send( - const asio::const_buffer &buff, + const std::vector &buffs, + size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode ){ return vrt_packet_handler::send( _io_impl->packet_handler_send_state, //last state of the send handler - buff, metadata, send_mode, //buffer to empty and samples metadata + buffs, nsamps_per_buff, //buffer to empty + metadata, send_mode, //samples metadata io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate - uhd::transport::vrt::pack_be, - boost::bind(&zero_copy_if::get_send_buff, _data_transport), + uhd::transport::vrt::if_hdr_pack_be, + boost::bind(&tmp_todo_fixme_remove_get_send_buffs, _1, _data_transport), get_max_send_samps_per_packet() ); } @@ -150,18 +157,25 @@ size_t usrp2_impl::send( /*********************************************************************** * Receive Data **********************************************************************/ +bool tmp_todo_fixme_remove_get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, boost::shared_ptr impl){ + buffs[0] = impl->get_recv_buff(); + return buffs[0].get() != NULL; +} + size_t usrp2_impl::recv( - const asio::mutable_buffer &buff, + const std::vector &buffs, + size_t nsamps_per_buff, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode ){ return vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler - buff, metadata, recv_mode, //buffer to fill and samples metadata + buffs, nsamps_per_buff, //buffer to empty + metadata, recv_mode, //samples metadata io_type, _rx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate - uhd::transport::vrt::unpack_be, - boost::bind(&usrp2_impl::io_impl::get_recv_buff, _io_impl) + uhd::transport::vrt::if_hdr_unpack_be, + boost::bind(&tmp_todo_fixme_remove_get_recv_buffs, _1, _io_impl) ); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2126b9565..70735173e 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -108,7 +108,7 @@ public: return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); } size_t send( - const boost::asio::const_buffer &, + const std::vector &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, uhd::device::send_mode_t @@ -117,12 +117,14 @@ public: return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); } size_t recv( - const boost::asio::mutable_buffer &, + const std::vector &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, uhd::device::recv_mode_t ); + UHD_PIMPL_DECL(io_impl) _io_impl; + private: inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); @@ -148,11 +150,10 @@ private: ; static const size_t _max_tx_bytes_per_packet = USRP2_UDP_BYTES - - uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) ; uhd::otw_type_t _rx_otw_type, _tx_otw_type; - UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); //udp transports for control and data diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 3776e33aa..3f74a836e 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -17,84 +17,123 @@ #include #include +#include using namespace uhd::transport; static void pack_and_unpack( - const uhd::tx_metadata_t &metadata, - size_t num_payload_words32, - size_t packet_count + vrt::if_packet_info_t &if_packet_info_in ){ - boost::uint32_t header_buff[vrt::max_header_words32]; - size_t num_header_words32; - size_t num_packet_words32; + boost::uint32_t header_buff[vrt::max_if_hdr_words32]; //pack metadata into a vrt header - vrt::pack_be( - metadata, //input - header_buff, //output - num_header_words32, //output - num_payload_words32, //input - num_packet_words32, //output - packet_count, //input - 100e6 + vrt::if_hdr_pack_be( + header_buff, if_packet_info_in ); - uhd::rx_metadata_t metadata_out; - size_t num_header_words32_out; - size_t num_payload_words32_out; - size_t packet_count_out; + vrt::if_packet_info_t if_packet_info_out; + if_packet_info_out.num_packet_words32 = if_packet_info_in.num_packet_words32; //unpack the vrt header back into metadata - vrt::unpack_be( - metadata_out, //output - header_buff, //input - num_header_words32_out, //output - num_payload_words32_out, //output - num_packet_words32, //input - packet_count_out, //output - 100e6 + vrt::if_hdr_unpack_be( + header_buff, if_packet_info_out ); //check the the unpacked metadata is the same - BOOST_CHECK_EQUAL(packet_count, packet_count_out); - BOOST_CHECK_EQUAL(num_header_words32, num_header_words32_out); - BOOST_CHECK_EQUAL(num_payload_words32, num_payload_words32_out); - BOOST_CHECK_EQUAL(metadata.has_stream_id, metadata_out.has_stream_id); - if (metadata.has_stream_id and metadata_out.has_stream_id){ - BOOST_CHECK_EQUAL(metadata.stream_id, metadata_out.stream_id); + BOOST_CHECK_EQUAL(if_packet_info_in.packet_count, if_packet_info_out.packet_count); + BOOST_CHECK_EQUAL(if_packet_info_in.num_header_words32, if_packet_info_out.num_header_words32); + BOOST_CHECK_EQUAL(if_packet_info_in.num_payload_words32, if_packet_info_out.num_payload_words32); + BOOST_CHECK_EQUAL(if_packet_info_in.has_sid, if_packet_info_out.has_sid); + if (if_packet_info_in.has_sid and if_packet_info_out.has_sid){ + BOOST_CHECK_EQUAL(if_packet_info_in.sid, if_packet_info_out.sid); } - BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec); - if (metadata.has_time_spec and metadata_out.has_time_spec){ - BOOST_CHECK_EQUAL(metadata.time_spec.get_full_secs(), metadata_out.time_spec.get_full_secs()); - BOOST_CHECK_EQUAL(metadata.time_spec.get_frac_secs(), metadata_out.time_spec.get_frac_secs()); + BOOST_CHECK_EQUAL(if_packet_info_in.has_cid, if_packet_info_out.has_cid); + if (if_packet_info_in.has_cid and if_packet_info_out.has_cid){ + BOOST_CHECK_EQUAL(if_packet_info_in.cid, if_packet_info_out.cid); + } + BOOST_CHECK_EQUAL(if_packet_info_in.has_tsi, if_packet_info_out.has_tsi); + if (if_packet_info_in.has_tsi and if_packet_info_out.has_tsi){ + BOOST_CHECK_EQUAL(if_packet_info_in.tsi, if_packet_info_out.tsi); + } + BOOST_CHECK_EQUAL(if_packet_info_in.has_tsf, if_packet_info_out.has_tsf); + if (if_packet_info_in.has_tsf and if_packet_info_out.has_tsf){ + BOOST_CHECK_EQUAL(if_packet_info_in.tsf, if_packet_info_out.tsf); + } + BOOST_CHECK_EQUAL(if_packet_info_in.has_tlr, if_packet_info_out.has_tlr); + if (if_packet_info_in.has_tlr and if_packet_info_out.has_tlr){ + BOOST_CHECK_EQUAL(if_packet_info_in.tlr, if_packet_info_out.tlr); } } +/*********************************************************************** + * Loopback test the vrt packer/unpacker with various packet info combos + * The trailer is not tested as it is not convenient to do so. + **********************************************************************/ + BOOST_AUTO_TEST_CASE(test_with_none){ - uhd::tx_metadata_t metadata; - pack_and_unpack(metadata, 300, 1); + vrt::if_packet_info_t if_packet_info; + if_packet_info.packet_count = 0; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tsi = false; + if_packet_info.has_tsf = false; + if_packet_info.has_tlr = false; + if_packet_info.num_payload_words32 = 0; + pack_and_unpack(if_packet_info); } BOOST_AUTO_TEST_CASE(test_with_sid){ - uhd::tx_metadata_t metadata; - metadata.has_stream_id = true; - metadata.stream_id = 6; - pack_and_unpack(metadata, 400, 2); + vrt::if_packet_info_t if_packet_info; + if_packet_info.packet_count = 1; + if_packet_info.has_sid = true; + if_packet_info.has_cid = false; + if_packet_info.has_tsi = false; + if_packet_info.has_tsf = false; + if_packet_info.has_tlr = false; + if_packet_info.sid = std::rand(); + if_packet_info.num_payload_words32 = 1111; + pack_and_unpack(if_packet_info); +} + +BOOST_AUTO_TEST_CASE(test_with_cid){ + vrt::if_packet_info_t if_packet_info; + if_packet_info.packet_count = 2; + if_packet_info.has_sid = false; + if_packet_info.has_cid = true; + if_packet_info.has_tsi = false; + if_packet_info.has_tsf = false; + if_packet_info.has_tlr = false; + if_packet_info.cid = std::rand(); + if_packet_info.num_payload_words32 = 2222; + pack_and_unpack(if_packet_info); } -BOOST_AUTO_TEST_CASE(test_with_time_spec){ - uhd::tx_metadata_t metadata; - metadata.has_time_spec = true; - metadata.time_spec = uhd::time_spec_t(7, 0.2); - pack_and_unpack(metadata, 500, 3); +BOOST_AUTO_TEST_CASE(test_with_time){ + vrt::if_packet_info_t if_packet_info; + if_packet_info.packet_count = 3; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tsi = true; + if_packet_info.has_tsf = true; + if_packet_info.has_tlr = false; + if_packet_info.tsi = std::rand(); + if_packet_info.tsf = std::rand(); + if_packet_info.num_payload_words32 = 33333; + pack_and_unpack(if_packet_info); } -BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ - uhd::tx_metadata_t metadata; - metadata.has_stream_id = true; - metadata.stream_id = 2; - metadata.has_time_spec = true; - metadata.time_spec = uhd::time_spec_t(5, 0.1); - pack_and_unpack(metadata, 600, 4); +BOOST_AUTO_TEST_CASE(test_with_all){ + vrt::if_packet_info_t if_packet_info; + if_packet_info.packet_count = 4; + if_packet_info.has_sid = true; + if_packet_info.has_cid = true; + if_packet_info.has_tsi = true; + if_packet_info.has_tsf = true; + if_packet_info.has_tlr = false; + if_packet_info.sid = std::rand(); + if_packet_info.cid = std::rand(); + if_packet_info.tsi = std::rand(); + if_packet_info.tsf = std::rand(); + if_packet_info.num_payload_words32 = 44444; + pack_and_unpack(if_packet_info); } -- cgit v1.2.3 From 9183ca62eb8fba96cf527d3cefa0a48f67397a57 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 11:13:24 -0700 Subject: uhd: forgot burst flags, tweaks to vrt info -> metadata --- host/lib/transport/gen_vrt.py | 3 ++- host/lib/transport/vrt_packet_handler.hpp | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'host') diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index ad87b9972..06182bd39 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -109,10 +109,11 @@ void vrt::if_hdr_pack_$(suffix)( #end if ########## Trailer ########## #if $pred & $tlr_p - packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); #set $flags |= (0x1 << 26); #set $num_trailer_words = 1; #else + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; #set $num_trailer_words = 0; #end if ########## Variables ########## diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 01cccd81e..63bf95204 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -111,11 +111,9 @@ namespace vrt_packet_handler{ } //store the last vrt info into the metadata - metadata.has_time_spec = if_packet_info.has_tsi or if_packet_info.has_tsf; + metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; metadata.time_spec = uhd::time_spec_t( - time_t((if_packet_info.has_tsi)? if_packet_info.tsi : 0), - size_t((if_packet_info.has_tsf)? if_packet_info.tsf : 0), - tick_rate + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate ); } @@ -292,6 +290,8 @@ namespace vrt_packet_handler{ if_packet_info.has_tlr = false; if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); if_packet_info.packet_count = state.next_packet_seq++; + if_packet_info.sob = metadata.start_of_burst; + if_packet_info.eob = metadata.end_of_burst; //get send buffers for each channel managed_send_buffs_t send_buffs(buffs.size()); -- cgit v1.2.3 From a38a0943490d10da733a529156a7650c056028e6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 12:08:45 -0700 Subject: uhd: vrt packet handler fix and tweaks --- host/lib/transport/vrt_packet_handler.hpp | 66 ++++++++++++++----------------- 1 file changed, 30 insertions(+), 36 deletions(-) (limited to 'host') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 63bf95204..8cbc71008 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -39,6 +39,7 @@ namespace vrt_packet_handler{ * vrt packet handler for recv **********************************************************************/ typedef std::vector managed_recv_buffs_t; + typedef boost::function get_recv_buffs_t; struct recv_state{ //width of the receiver in channels @@ -65,10 +66,6 @@ namespace vrt_packet_handler{ } }; - typedef boost::function get_recv_buffs_t; - - typedef boost::function recv_cb_t; - /******************************************************************* * Unpack a received vrt header and set the copy buffer. * - helper function for vrt_packet_handler::_recv1 @@ -136,6 +133,8 @@ namespace vrt_packet_handler{ //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 ){ + metadata.has_time_spec = false; //false unless set in the helper + //perform a receive if no rx data is waiting to be copied if (state.size_of_copy_buffs == 0){ state.fragment_offset_in_samps = 0; @@ -196,8 +195,6 @@ namespace vrt_packet_handler{ //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0 ){ - metadata = uhd::rx_metadata_t(); //init the metadata - switch(recv_mode){ //////////////////////////////////////////////////////////////// @@ -247,20 +244,17 @@ namespace vrt_packet_handler{ * vrt packet handler for send **********************************************************************/ typedef std::vector managed_send_buffs_t; + typedef boost::function get_send_buffs_t; struct send_state{ //init the expected seq number size_t next_packet_seq; - send_state(void){ - next_packet_seq = 0; + send_state(void) : next_packet_seq(0){ + /* NOP */ } }; - typedef boost::function get_send_buffs_t; - - typedef boost::function send_cb_t; - /******************************************************************* * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send @@ -271,27 +265,16 @@ namespace vrt_packet_handler{ const std::vector &buffs, size_t offset_bytes, size_t num_samps, - const uhd::tx_metadata_t &metadata, + uhd::transport::vrt::if_packet_info_t &if_packet_info, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, - double tick_rate, vrt_packer_type vrt_packer, const get_send_buffs_t &get_send_buffs, size_t vrt_header_offset_words32 ){ - //translate the metadata to vrt if packet info - uhd::transport::vrt::if_packet_info_t if_packet_info; - if_packet_info.has_sid = false; - if_packet_info.has_cid = false; - if_packet_info.has_tsi = metadata.has_time_spec; - if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); - if_packet_info.has_tsf = metadata.has_time_spec; - if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); - if_packet_info.has_tlr = false; - if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); + //load the rest of the if_packet_info in here + if_packet_info.num_payload_words32 = (num_samps*otw_type.get_sample_size())/sizeof(boost::uint32_t); if_packet_info.packet_count = state.next_packet_seq++; - if_packet_info.sob = metadata.start_of_burst; - if_packet_info.eob = metadata.end_of_burst; //get send buffers for each channel managed_send_buffs_t send_buffs(buffs.size()); @@ -336,6 +319,14 @@ namespace vrt_packet_handler{ //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0 ){ + //translate the metadata to vrt if packet info + uhd::transport::vrt::if_packet_info_t if_packet_info; + if_packet_info.has_sid = false; + if_packet_info.has_cid = false; + if_packet_info.has_tlr = false; + if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); + if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); + if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET; switch(send_mode){ @@ -343,13 +334,19 @@ namespace vrt_packet_handler{ case uhd::device::SEND_MODE_ONE_PACKET:{ //////////////////////////////////////////////////////////////// size_t num_samps = std::min(total_num_samps, max_samples_per_packet); + + //fill in parts of the packet info overwrote in full buff mode + if_packet_info.has_tsi = metadata.has_time_spec; + if_packet_info.has_tsf = metadata.has_time_spec; + if_packet_info.sob = metadata.start_of_burst; + if_packet_info.eob = metadata.end_of_burst; + _send1( state, buffs, 0, num_samps, - metadata, + if_packet_info, io_type, otw_type, - tick_rate, vrt_packer, get_send_buffs, vrt_header_offset_words32 @@ -365,25 +362,22 @@ namespace vrt_packet_handler{ 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 = metadata.has_time_spec and (n == first_fragment_index); - md.start_of_burst = metadata.start_of_burst and (n == first_fragment_index); - md.end_of_burst = metadata.end_of_burst and (n == final_fragment_index); + if_packet_info.has_tsi = metadata.has_time_spec and (n == first_fragment_index); + if_packet_info.has_tsf = metadata.has_time_spec and (n == first_fragment_index); + if_packet_info.sob = metadata.start_of_burst and (n == first_fragment_index); + if_packet_info.eob = metadata.end_of_burst and (n == final_fragment_index); //send the fragment with the helper function _send1( state, buffs, n*max_samples_per_packet*io_type.size, (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, - md, + if_packet_info, io_type, otw_type, - tick_rate, vrt_packer, get_send_buffs, vrt_header_offset_words32 -- cgit v1.2.3 From 905f5b3b249a60401e181856ac6b3f2cae88d166 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 16:21:46 -0700 Subject: usrp2: split mboard impl into its own class, usrp2 device can instantiate N mboard impls for mimo setup (works with 1 for now) --- host/lib/usrp/usrp2/dboard_impl.cpp | 18 ++-- host/lib/usrp/usrp2/dsp_impl.cpp | 20 ++--- host/lib/usrp/usrp2/io_impl.cpp | 113 ++++++++++++----------- host/lib/usrp/usrp2/mboard_impl.cpp | 78 +++++++++++++--- host/lib/usrp/usrp2/usrp2_impl.cpp | 102 ++++++++++----------- host/lib/usrp/usrp2/usrp2_impl.hpp | 175 +++++++++++++++++++----------------- 6 files changed, 282 insertions(+), 224 deletions(-) (limited to 'host') diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index fef486771..fa8d1a674 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -33,7 +33,7 @@ using namespace uhd::usrp; /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_impl::dboard_init(void){ +void usrp2_mboard_impl::dboard_init(void){ //read the dboard eeprom to extract the dboard ids _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); @@ -46,12 +46,12 @@ void usrp2_impl::dboard_init(void){ //load dboards _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2) ); _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2) ); //init the subdevs in use (use the first subdevice) @@ -62,7 +62,7 @@ void usrp2_impl::dboard_init(void){ /*********************************************************************** * RX DBoard Properties **********************************************************************/ -void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -96,7 +96,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ } } -void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DBOARD_PROP_USED_SUBDEVS:{ _rx_subdevs_in_use = val.as(); @@ -122,7 +122,7 @@ void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ /*********************************************************************** * TX DBoard Properties **********************************************************************/ -void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -156,7 +156,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ } } -void usrp2_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DBOARD_PROP_USED_SUBDEVS:{ _tx_subdevs_in_use = val.as(); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 367cde2e1..c315a2eec 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -41,11 +41,11 @@ pick_closest_rate(double exact_rate, const std::vector &rates){ return closest_match; } -void usrp2_impl::init_ddc_config(void){ +void usrp2_mboard_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict _rx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::ddc_get, this, _1, _2), - boost::bind(&usrp2_impl::ddc_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2) ); //initial config and update @@ -56,7 +56,7 @@ void usrp2_impl::init_ddc_config(void){ /*********************************************************************** * DDC Properties **********************************************************************/ -void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 ddc0"); @@ -82,7 +82,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ @@ -116,11 +116,11 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ /*********************************************************************** * DUC Helper Methods **********************************************************************/ -void usrp2_impl::init_duc_config(void){ +void usrp2_mboard_impl::init_duc_config(void){ //create the duc in the tx dsp dict _tx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::duc_get, this, _1, _2), - boost::bind(&usrp2_impl::duc_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2) ); //initial config and update @@ -131,7 +131,7 @@ void usrp2_impl::init_duc_config(void){ /*********************************************************************** * DUC Properties **********************************************************************/ -void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 duc0"); @@ -157,7 +157,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ switch(key.as()){ case DSP_PROP_FREQ_SHIFT:{ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index e3a3a3b17..8b1864e2d 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -20,7 +20,7 @@ #include "usrp2_regs.hpp" #include #include -#include +#include #include #include //htonl and ntohl #include @@ -36,54 +36,58 @@ namespace asio = boost::asio; * io impl details (internal to this file) **********************************************************************/ struct usrp2_impl::io_impl{ + typedef alignment_buffer alignment_buffer_type; - io_impl(zero_copy_if::sptr zc_if); + io_impl(std::vector &zc_ifs); ~io_impl(void); - managed_recv_buffer::sptr get_recv_buff(void); + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs); //state management for the vrt packet handler code vrt_packet_handler::recv_state packet_handler_recv_state; vrt_packet_handler::send_state packet_handler_send_state; //methods and variables for the recv pirate - void recv_pirate_loop(zero_copy_if::sptr zc_if); - boost::thread *recv_pirate_thread; bool recv_pirate_running; - bounded_buffer::sptr recv_pirate_booty; + void recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index); + boost::thread_group recv_pirate_crew; + bool recv_pirate_crew_running; + alignment_buffer_type::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if): packet_handler_recv_state(1){ +usrp2_impl::io_impl::io_impl(std::vector &zc_ifs): + packet_handler_recv_state(zc_ifs.size()) +{ //create a large enough booty - size_t num_frames = zc_if->get_num_recv_frames(); + size_t num_frames = zc_ifs.at(0)->get_num_recv_frames(); std::cout << "Recv pirate num frames: " << num_frames << std::endl; - recv_pirate_booty = bounded_buffer::make(num_frames); + recv_pirate_booty = alignment_buffer_type::make(num_frames, zc_ifs.size()); - //create a new pirate thread (yarr!!) - recv_pirate_thread = new boost::thread( - boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_if) - ); + //create a new pirate thread for each zc if (yarr!!) + for (size_t i = 0; i < zc_ifs.size(); i++){ + recv_pirate_crew.create_thread( + boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_ifs.at(i), i) + ); + } } usrp2_impl::io_impl::~io_impl(void){ - recv_pirate_running = false; - recv_pirate_thread->interrupt(); - recv_pirate_thread->join(); - delete recv_pirate_thread; + recv_pirate_crew_running = false; + recv_pirate_crew.interrupt_all(); + recv_pirate_crew.join_all(); } -managed_recv_buffer::sptr usrp2_impl::io_impl::get_recv_buff(void){ - managed_recv_buffer::sptr buff; +bool usrp2_impl::io_impl::get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ boost::this_thread::disable_interruption di; //disable because the wait can throw - recv_pirate_booty->pop_with_timed_wait(buff, boost::posix_time::milliseconds(100)); - return buff; //a timeout means that we return a null sptr... + return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); } -void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ +void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index){ set_thread_priority_safe(); - recv_pirate_running = true; - while(recv_pirate_running){ + recv_pirate_crew_running = true; + while(recv_pirate_crew_running){ managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); - if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff); + //TODO unpack vrt, get time spec, round to nearest packet bound, use below: + if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff, time_spec_t(/*todoseq*/), index); } } @@ -102,54 +106,54 @@ void usrp2_impl::io_init(void){ _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; //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); - memcpy(send_buff->cast(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); + for(size_t i = 0; i < _data_transports.size(); i++){ + managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff(); + boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); + memcpy(send_buff->cast(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); + } - //setup RX DSP regs - std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); - _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); - _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset - _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 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(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); - _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); + //setup VRT RX DSP regs + for(size_t i = 0; i < _mboards.size(); i++){ + _mboards[i]->setup_vrt_recv_regs(get_max_recv_samps_per_packet()); + } + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transports)); } /*********************************************************************** * Send Data **********************************************************************/ -bool tmp_todo_fixme_remove_get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs, const zero_copy_if::sptr &zc_if){ - buffs[0] = zc_if->get_send_buff(); - return buffs[0].get() != NULL; +bool get_send_buffs( + const std::vector &trans, + vrt_packet_handler::managed_send_buffs_t &buffs +){ + UHD_ASSERT_THROW(trans.size() == buffs.size()); + for (size_t i = 0; i < buffs.size(); i++){ + buffs[i] = trans[i]->get_send_buff(); + } + return true; } size_t usrp2_impl::send( const std::vector &buffs, - size_t nsamps_per_buff, + size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode ){ return vrt_packet_handler::send( _io_impl->packet_handler_send_state, //last state of the send handler - buffs, nsamps_per_buff, //buffer to empty + buffs, num_samps, //buffer to fill metadata, send_mode, //samples metadata io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_pack_be, - boost::bind(&tmp_todo_fixme_remove_get_send_buffs, _1, _data_transport), + boost::bind(&get_send_buffs, _data_transports, _1), get_max_send_samps_per_packet() ); } @@ -157,25 +161,20 @@ size_t usrp2_impl::send( /*********************************************************************** * Receive Data **********************************************************************/ -bool tmp_todo_fixme_remove_get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, boost::shared_ptr impl){ - buffs[0] = impl->get_recv_buff(); - return buffs[0].get() != NULL; -} - size_t usrp2_impl::recv( const std::vector &buffs, - size_t nsamps_per_buff, + size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode ){ return vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler - buffs, nsamps_per_buff, //buffer to empty + buffs, num_samps, //buffer to fill metadata, recv_mode, //samples metadata io_type, _rx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_unpack_be, - boost::bind(&tmp_todo_fixme_remove_get_recv_buffs, _1, _io_impl) + boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl, _1) ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 2c900b328..903d5da86 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -29,17 +29,71 @@ using namespace uhd; using namespace uhd::usrp; +/*********************************************************************** + * Structors + **********************************************************************/ +usrp2_mboard_impl::usrp2_mboard_impl( + size_t index, transport::udp_simple::sptr ctrl_transport +): + _index(index) +{ + //make a new interface for usrp2 stuff + _iface = usrp2_iface::make(ctrl_transport); + _clock_ctrl = usrp2_clock_ctrl::make(_iface); + _codec_ctrl = usrp2_codec_ctrl::make(_iface); + _serdes_ctrl = usrp2_serdes_ctrl::make(_iface); + + //TODO move to dsp impl... + //load the allowed decim/interp rates + //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) + _allowed_decim_and_interp_rates.clear(); + for (size_t i = 4; i <= 128; i+=1){ + _allowed_decim_and_interp_rates.push_back(i); + } + for (size_t i = 130; i <= 256; i+=2){ + _allowed_decim_and_interp_rates.push_back(i); + } + for (size_t i = 260; i <= 512; i+=4){ + _allowed_decim_and_interp_rates.push_back(i); + } + + //init the ddc + init_ddc_config(); + + //init the duc + init_duc_config(); + + //initialize the clock configuration + init_clock_config(); + + //init the tx and rx dboards (do last) + dboard_init(); +} + +usrp2_mboard_impl::~usrp2_mboard_impl(void){ + /* NOP */ +} + /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_impl::mboard_init(void){ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::mboard_get, this, _1, _2), - boost::bind(&usrp2_impl::mboard_set, this, _1, _2) +void usrp2_mboard_impl::setup_vrt_recv_regs(size_t num_samps){ + _max_recv_samps_per_packet = num_samps; + + _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _max_recv_samps_per_packet); + _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); + _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset + _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 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(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); + _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); } -void usrp2_impl::init_clock_config(void){ +void usrp2_mboard_impl::init_clock_config(void){ //setup the clock configuration settings _clock_config.ref_source = clock_config_t::REF_INT; _clock_config.pps_source = clock_config_t::PPS_SMA; @@ -49,7 +103,7 @@ void usrp2_impl::init_clock_config(void){ update_clock_config(); } -void usrp2_impl::update_clock_config(void){ +void usrp2_mboard_impl::update_clock_config(void){ boost::uint32_t pps_flags = 0; //translate pps source enums @@ -82,7 +136,7 @@ void usrp2_impl::update_clock_config(void){ _clock_ctrl->enable_external_ref(use_external); } -void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ +void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ //set the ticks _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); @@ -94,7 +148,7 @@ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); } -void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ +void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ UHD_ASSERT_THROW(stream_cmd.num_samps <= U2_REG_RX_CTRL_MAX_SAMPS_PER_CMD); //setup the mode to instruction flags @@ -113,7 +167,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, U2_REG_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_recv_samps_per_packet : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 @@ -125,7 +179,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ /*********************************************************************** * MBoard Get Properties **********************************************************************/ -void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -148,7 +202,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as()){ case MBOARD_PROP_NAME: - val = std::string("usrp2 mboard"); + val = str(boost::format("usrp2 mboard %d") % _index); return; case MBOARD_PROP_OTHERS:{ @@ -207,7 +261,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ /*********************************************************************** * MBoard Set Properties **********************************************************************/ -void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as() == "mac-addr"){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 36c264c3c..af496bf69 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,15 @@ UHD_STATIC_BLOCK(register_usrp2_device){ device::register_device(&usrp2::find, &usrp2::make); } +/*********************************************************************** + * Helper Functions + **********************************************************************/ +std::vector split_addrs(const std::string &addrs_str){ + std::vector addrs; + boost::split(addrs, addrs_str, boost::is_any_of("\t ")); + return addrs; +} + /*********************************************************************** * Discovery over the udp transport **********************************************************************/ @@ -66,6 +76,16 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ return usrp2_addrs; } + //if there are multiple addresses, just return good, dont test + std::vector addrs = split_addrs(hint["addr"]); + if (addrs.size() > 1){ + device_addr_t new_addr; + new_addr["type"] = "usrp2"; + new_addr["addr"] = hint["addr"]; + usrp2_addrs.push_back(new_addr); + return usrp2_addrs; + } + //create a udp transport to communicate std::string ctrl_port = boost::lexical_cast(USRP2_UDP_CTRL_PORT); udp_simple::sptr udp_transport = udp_simple::make_broadcast( @@ -112,11 +132,6 @@ template std::string num2str(T num){ } device::sptr usrp2::make(const device_addr_t &device_addr){ - //create a control transport - udp_simple::sptr ctrl_transport = udp_simple::make_connected( - device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) - ); - //extract the receive and send buffer sizes size_t recv_buff_size = 0, send_buff_size= 0 ; if (device_addr.has_key("recv_buff_size")){ @@ -126,17 +141,23 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ send_buff_size = size_t(boost::lexical_cast(device_addr["send_buff_size"])); } - //create a data transport - udp_zero_copy::sptr data_transport = udp_zero_copy::make( - device_addr["addr"], - num2str(USRP2_UDP_DATA_PORT), - recv_buff_size, - send_buff_size - ); + //create a ctrl and data transport for each address + std::vector ctrl_transports; + std::vector data_transports; + + BOOST_FOREACH(const std::string &addr, split_addrs(device_addr["addr"])){ + ctrl_transports.push_back(udp_simple::make_connected( + addr, num2str(USRP2_UDP_CTRL_PORT) + )); + data_transports.push_back(udp_zero_copy::make( + addr, num2str(USRP2_UDP_DATA_PORT), + recv_buff_size, send_buff_size + )); + } //create the usrp2 implementation guts return device::sptr( - new usrp2_impl(ctrl_transport, data_transport) + new usrp2_impl(ctrl_transports, data_transports) ); } @@ -144,44 +165,20 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - udp_simple::sptr ctrl_transport, - udp_zero_copy::sptr data_transport -){ - _data_transport = data_transport; - - //make a new interface for usrp2 stuff - _iface = usrp2_iface::make(ctrl_transport); - _clock_ctrl = usrp2_clock_ctrl::make(_iface); - _codec_ctrl = usrp2_codec_ctrl::make(_iface); - _serdes_ctrl = usrp2_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) - _allowed_decim_and_interp_rates.clear(); - for (size_t i = 4; i <= 128; i+=1){ - _allowed_decim_and_interp_rates.push_back(i); - } - for (size_t i = 130; i <= 256; i+=2){ - _allowed_decim_and_interp_rates.push_back(i); + std::vector ctrl_transports, + std::vector data_transports +): + _data_transports(data_transports) +{ + //create a new mboard handler for each control transport + for(size_t i = 0; i < ctrl_transports.size(); i++){ + _mboards.push_back(usrp2_mboard_impl::sptr( + new usrp2_mboard_impl(i, ctrl_transports[i]) + )); + //use an empty name when there is only one mboard + std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast(i) : ""; + _mboard_dict[name] = _mboards.back(); } - for (size_t i = 260; i <= 512; i+=4){ - _allowed_decim_and_interp_rates.push_back(i); - } - - //init the mboard - mboard_init(); - - //init the ddc - init_ddc_config(); - - //init the duc - init_duc_config(); - - //initialize the clock configuration - init_clock_config(); - - //init the tx and rx dboards (do last) - dboard_init(); //init the send and recv io io_init(); @@ -206,12 +203,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(name == ""); - val = _mboard_proxy->get_link(); + val = _mboard_dict[name]->get_link(); return; case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); + val = prop_names_t(_mboard_dict.keys()); 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 70735173e..ccda5e3d8 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -62,102 +62,50 @@ public: return sptr(new wax_obj_proxy(get, set)); } - ~wax_obj_proxy(void){ - /* NOP */ - } - private: - get_t _get; - set_t _set; - - wax_obj_proxy(const get_t &get, const set_t &set){ - _get = get; - _set = set; - }; - - void get(const wax::obj &key, wax::obj &val){ - return _get(key, val); - } - - void set(const wax::obj &key, const wax::obj &val){ - return _set(key, val); - } + get_t _get; set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; + void get(const wax::obj &key, wax::obj &val){return _get(key, val);} + void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} }; /*! - * USRP2 implementation guts: + * USRP2 mboard implementation guts: * The implementation details are encapsulated here. * Handles properties on the mboard, dboard, dsps... */ -class usrp2_impl : public uhd::device{ +class usrp2_mboard_impl : public wax::obj{ public: - /*! - * Create a new usrp2 impl base. - * \param ctrl_transport the udp transport for control - * \param data_transport the udp transport for data - */ - usrp2_impl( - uhd::transport::udp_simple::sptr ctrl_transport, - uhd::transport::udp_zero_copy::sptr data_transport - ); + typedef boost::shared_ptr sptr; - ~usrp2_impl(void); + //structors + usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr); + ~usrp2_mboard_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 std::vector &, size_t, - 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 std::vector &, size_t, - uhd::rx_metadata_t &, - const uhd::io_type_t &, - uhd::device::recv_mode_t - ); - - UHD_PIMPL_DECL(io_impl) _io_impl; + void setup_vrt_recv_regs(size_t num_samps); -private: inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); } - //device properties interface + //properties for this mboard void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); +private: + size_t _index; + size_t _max_recv_samps_per_packet; + //interfaces usrp2_iface::sptr _iface; usrp2_clock_ctrl::sptr _clock_ctrl; usrp2_codec_ctrl::sptr _codec_ctrl; usrp2_serdes_ctrl::sptr _serdes_ctrl; - /******************************************************************* - * Deal with the rx and tx packet sizes - ******************************************************************/ - static const size_t _max_rx_bytes_per_packet = - USRP2_UDP_BYTES - - 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_bytes_per_packet = - USRP2_UDP_BYTES - - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - ; - - uhd::otw_type_t _rx_otw_type, _tx_otw_type; - void io_init(void); - - //udp transports for control and data - uhd::transport::udp_zero_copy::sptr _data_transport; + //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); //methods and shadows for clock configuration uhd::clock_config_t _clock_config; @@ -165,17 +113,6 @@ private: void update_clock_config(void); void set_time_spec(const uhd::time_spec_t &time_spec, bool now); - //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 - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _mboard_proxy; - //properties interface for rx dboard void rx_dboard_get(const wax::obj &, wax::obj &); void rx_dboard_set(const wax::obj &, const wax::obj &); @@ -214,4 +151,76 @@ private: }; +/*! + * USRP2 implementation guts: + * The implementation details are encapsulated here. + * Handles device properties and streaming... + */ +class usrp2_impl : public uhd::device{ +public: + /*! + * Create a new usrp2 impl base. + * \param ctrl_transports the udp transports for control + * \param data_transports the udp transports for data + */ + usrp2_impl( + std::vector ctrl_transports, + std::vector data_transports + ); + + ~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 std::vector &, size_t, + 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 std::vector &, size_t, + uhd::rx_metadata_t &, + const uhd::io_type_t &, + uhd::device::recv_mode_t + ); + +private: + inline double get_master_clock_freq(void){ + return _mboards.front()->get_master_clock_freq(); + } + + //device properties interface + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + + //pointers to mboards on this device (think mimo setup) + std::vector _mboards; + uhd::dict _mboard_dict; + + /******************************************************************* + * Deal with the rx and tx packet sizes + ******************************************************************/ + static const size_t _max_rx_bytes_per_packet = + USRP2_UDP_BYTES - + 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_bytes_per_packet = + USRP2_UDP_BYTES - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used + ; + + std::vector _data_transports; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); +}; + #endif /* INCLUDED_USRP2_IMPL_HPP */ -- cgit v1.2.3 From 158bf440d2884b981a86121990be16decedaa733 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 17:34:35 -0700 Subject: usrp2: moved calculations for max packet size and otw types into shared object between device and mboards --- host/lib/usrp/usrp2/io_impl.cpp | 35 +++++---------- host/lib/usrp/usrp2/mboard_impl.cpp | 38 ++++++++-------- host/lib/usrp/usrp2/usrp2_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 86 +++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 73 deletions(-) (limited to 'host') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 8b1864e2d..0c92c33b2 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -95,16 +95,6 @@ void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if, size_t inde * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //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; - //send a small data packet so the usrp2 knows the udp source port for(size_t i = 0; i < _data_transports.size(); i++){ managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff(); @@ -113,11 +103,6 @@ void usrp2_impl::io_init(void){ send_buff->commit(sizeof(data)); } - //setup VRT RX DSP regs - for(size_t i = 0; i < _mboards.size(); i++){ - _mboards[i]->setup_vrt_recv_regs(get_max_recv_samps_per_packet()); - } - std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; @@ -147,11 +132,11 @@ size_t usrp2_impl::send( send_mode_t send_mode ){ return vrt_packet_handler::send( - _io_impl->packet_handler_send_state, //last state of the send handler - buffs, num_samps, //buffer to fill - metadata, send_mode, //samples metadata - io_type, _tx_otw_type, //input and output types to convert - get_master_clock_freq(), //master clock tick rate + _io_impl->packet_handler_send_state, //last state of the send handler + buffs, num_samps, //buffer to fill + metadata, send_mode, //samples metadata + io_type, _io_helper.get_tx_otw_type(), //input and output types to convert + _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_pack_be, boost::bind(&get_send_buffs, _data_transports, _1), get_max_send_samps_per_packet() @@ -169,11 +154,11 @@ size_t usrp2_impl::recv( recv_mode_t recv_mode ){ return vrt_packet_handler::recv( - _io_impl->packet_handler_recv_state, //last state of the recv handler - buffs, num_samps, //buffer to fill - metadata, recv_mode, //samples metadata - io_type, _rx_otw_type, //input and output types to convert - get_master_clock_freq(), //master clock tick rate + _io_impl->packet_handler_recv_state, //last state of the recv handler + buffs, num_samps, //buffer to fill + metadata, recv_mode, //samples metadata + io_type, _io_helper.get_rx_otw_type(), //input and output types to convert + _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_unpack_be, boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl, _1) ); diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 903d5da86..28a346be7 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -33,9 +33,12 @@ using namespace uhd::usrp; * Structors **********************************************************************/ usrp2_mboard_impl::usrp2_mboard_impl( - size_t index, transport::udp_simple::sptr ctrl_transport + size_t index, + transport::udp_simple::sptr ctrl_transport, + const usrp2_io_helper &io_helper ): - _index(index) + _index(index), + _io_helper(io_helper) { //make a new interface for usrp2 stuff _iface = usrp2_iface::make(ctrl_transport); @@ -57,6 +60,19 @@ usrp2_mboard_impl::usrp2_mboard_impl( _allowed_decim_and_interp_rates.push_back(i); } + //setup the vrt rx registers + _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet()); + _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); + _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset + _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 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(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); + _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); + //init the ddc init_ddc_config(); @@ -77,22 +93,6 @@ usrp2_mboard_impl::~usrp2_mboard_impl(void){ /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_mboard_impl::setup_vrt_recv_regs(size_t num_samps){ - _max_recv_samps_per_packet = num_samps; - - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _max_recv_samps_per_packet); - _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); - _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset - _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 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(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); - _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); -} - void usrp2_mboard_impl::init_clock_config(void){ //setup the clock configuration settings _clock_config.ref_source = clock_config_t::REF_INT; @@ -167,7 +167,7 @@ void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, U2_REG_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_recv_samps_per_packet : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _io_helper.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 af496bf69..436146a48 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -173,7 +173,7 @@ usrp2_impl::usrp2_impl( //create a new mboard handler for each control transport for(size_t i = 0; i < ctrl_transports.size(); i++){ _mboards.push_back(usrp2_mboard_impl::sptr( - new usrp2_mboard_impl(i, ctrl_transports[i]) + new usrp2_mboard_impl(i, ctrl_transports[i], _io_helper) )); //use an empty name when there is only one mboard std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast(i) : ""; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ccda5e3d8..719cf3f16 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -69,6 +69,55 @@ private: void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} }; +/*! + * The io helper class encapculates the max packet sizes and otw types. + * The otw types are read-only for now, this will be reimplemented + * when it becomes possible to change the otw type in the usrp2. + */ +class usrp2_io_helper{ +public: + usrp2_io_helper(void){ + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + } + + inline size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } + + inline size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } + + inline const uhd::otw_type_t &get_rx_otw_type(void) const{ + return _rx_otw_type; + } + + inline const uhd::otw_type_t &get_tx_otw_type(void) const{ + return _tx_otw_type; + } + +private: + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + static const size_t _max_rx_bytes_per_packet = + USRP2_UDP_BYTES - + 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_bytes_per_packet = + USRP2_UDP_BYTES - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used + ; +}; + /*! * USRP2 mboard implementation guts: * The implementation details are encapsulated here. @@ -79,23 +128,21 @@ public: typedef boost::shared_ptr sptr; //structors - usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr); + usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr, const usrp2_io_helper &); ~usrp2_mboard_impl(void); - void setup_vrt_recv_regs(size_t num_samps); - inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); } +private: + size_t _index; + const usrp2_io_helper &_io_helper; + //properties for this mboard void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); -private: - size_t _index; - size_t _max_recv_samps_per_packet; - //interfaces usrp2_iface::sptr _iface; usrp2_clock_ctrl::sptr _clock_ctrl; @@ -172,7 +219,7 @@ public: //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(); + return _io_helper.get_max_send_samps_per_packet(); } size_t send( const std::vector &, size_t, @@ -181,7 +228,7 @@ public: 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(); + return _io_helper.get_max_recv_samps_per_packet(); } size_t recv( const std::vector &, size_t, @@ -191,10 +238,6 @@ public: ); private: - inline double get_master_clock_freq(void){ - return _mboards.front()->get_master_clock_freq(); - } - //device properties interface void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); @@ -203,22 +246,9 @@ private: std::vector _mboards; uhd::dict _mboard_dict; - /******************************************************************* - * Deal with the rx and tx packet sizes - ******************************************************************/ - static const size_t _max_rx_bytes_per_packet = - USRP2_UDP_BYTES - - 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_bytes_per_packet = - USRP2_UDP_BYTES - - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used - ; - + //io impl methods and members std::vector _data_transports; - uhd::otw_type_t _rx_otw_type, _tx_otw_type; + const usrp2_io_helper _io_helper; UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); }; -- cgit v1.2.3 From deaade7bd0ae4dd9cab7f304fb69eea153ce592a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 30 Jun 2010 17:44:47 -0700 Subject: uhd: renamed the vrt header to vrt_if_packet header --- host/include/uhd/transport/CMakeLists.txt | 2 +- host/include/uhd/transport/vrt.hpp | 99 ------------ host/include/uhd/transport/vrt_if_packet.hpp | 99 ++++++++++++ host/lib/transport/CMakeLists.txt | 4 +- host/lib/transport/gen_vrt.py | 233 --------------------------- host/lib/transport/gen_vrt_if_packet.py | 233 +++++++++++++++++++++++++++ host/lib/transport/vrt_packet_handler.hpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 2 +- host/test/vrt_test.cpp | 2 +- 9 files changed, 338 insertions(+), 338 deletions(-) delete mode 100644 host/include/uhd/transport/vrt.hpp create mode 100644 host/include/uhd/transport/vrt_if_packet.hpp delete mode 100755 host/lib/transport/gen_vrt.py create mode 100755 host/lib/transport/gen_vrt_if_packet.py (limited to 'host') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 23a4aae94..4e1f7aca5 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -23,7 +23,7 @@ INSTALL(FILES if_addrs.hpp udp_simple.hpp udp_zero_copy.hpp - vrt.hpp + vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport ) diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp deleted file mode 100644 index 17da2d540..000000000 --- a/host/include/uhd/transport/vrt.hpp +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_UHD_TRANSPORT_VRT_HPP -#define INCLUDED_UHD_TRANSPORT_VRT_HPP - -#include -#include -#include //size_t - -namespace uhd{ namespace transport{ - -namespace vrt{ - - //! The maximum number of 32-bit words in a vrt if packet header - static const size_t max_if_hdr_words32 = 7; //hdr+sid+cid+tsi+tsf - - /*! - * Definition for fields that can be packed into a vrt if header. - * The size fields are used for input and output depending upon - * the operation used (ie the pack or unpack function call). - */ - struct UHD_API if_packet_info_t{ - //size fields - size_t num_payload_words32; //required in pack, derived in unpack - size_t num_header_words32; //derived in pack, derived in unpack - size_t num_packet_words32; //derived in pack, required in unpack - - //header fields - size_t packet_count; - bool sob, eob; - - //optional fields - bool has_sid; boost::uint32_t sid; - bool has_cid; boost::uint64_t cid; - bool has_tsi; boost::uint32_t tsi; - bool has_tsf; boost::uint64_t tsf; - bool has_tlr; boost::uint32_t tlr; - }; - - /*! - * Pack a vrt header from metadata (big endian format). - * \param packet_buff memory to write the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_pack_be( - boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - - /*! - * Unpack a vrt header to metadata (big endian format). - * \param packet_buff memory to read the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_unpack_be( - const boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - - /*! - * Pack a vrt header from metadata (little endian format). - * \param packet_buff memory to write the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_pack_le( - boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - - /*! - * Unpack a vrt header to metadata (little endian format). - * \param packet_buff memory to read the packed vrt header - * \param if_packet_info the if packet info (read/write) - */ - UHD_API void if_hdr_unpack_le( - const boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info - ); - -} //namespace vrt - -}} //namespace - -#endif /* INCLUDED_UHD_TRANSPORT_VRT_HPP */ diff --git a/host/include/uhd/transport/vrt_if_packet.hpp b/host/include/uhd/transport/vrt_if_packet.hpp new file mode 100644 index 000000000..ccefe14ea --- /dev/null +++ b/host/include/uhd/transport/vrt_if_packet.hpp @@ -0,0 +1,99 @@ +// +// 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_UHD_TRANSPORT_VRT_IF_PACKET_HPP +#define INCLUDED_UHD_TRANSPORT_VRT_IF_PACKET_HPP + +#include +#include +#include //size_t + +namespace uhd{ namespace transport{ + +namespace vrt{ + + //! The maximum number of 32-bit words in a vrt if packet header + static const size_t max_if_hdr_words32 = 7; //hdr+sid+cid+tsi+tsf + + /*! + * Definition for fields that can be packed into a vrt if header. + * The size fields are used for input and output depending upon + * the operation used (ie the pack or unpack function call). + */ + struct UHD_API if_packet_info_t{ + //size fields + size_t num_payload_words32; //required in pack, derived in unpack + size_t num_header_words32; //derived in pack, derived in unpack + size_t num_packet_words32; //derived in pack, required in unpack + + //header fields + size_t packet_count; + bool sob, eob; + + //optional fields + bool has_sid; boost::uint32_t sid; + bool has_cid; boost::uint64_t cid; + bool has_tsi; boost::uint32_t tsi; + bool has_tsf; boost::uint64_t tsf; + bool has_tlr; boost::uint32_t tlr; + }; + + /*! + * Pack a vrt header from metadata (big endian format). + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_pack_be( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Unpack a vrt header to metadata (big endian format). + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_unpack_be( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Pack a vrt header from metadata (little endian format). + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_pack_le( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Unpack a vrt header to metadata (little endian format). + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_unpack_le( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + +} //namespace vrt + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_VRT_IF_PACKET_HPP */ diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 70cf6312d..bde2b72b9 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -50,8 +50,8 @@ ENDIF(HAVE_IFADDRS_H) # Append to the list of sources for lib uhd ######################################################################## LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_SOURCE_DIR}/lib/transport/gen_vrt.py - ${CMAKE_BINARY_DIR}/lib/transport/vrt.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/gen_vrt_if_packet.py + ${CMAKE_BINARY_DIR}/lib/transport/vrt_if_packet.cpp ) LIBUHD_PYTHON_GEN_SOURCE( diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py deleted file mode 100755 index 06182bd39..000000000 --- a/host/lib/transport/gen_vrt.py +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env python -# -# 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 . -# - -""" -The vrt packer/unpacker code generator: - -This script will generate the pack and unpack routines that convert -metatdata into vrt headers and vrt headers into metadata. - -The generated code infers jump tables to speed-up the parsing time. -""" - -TMPL_TEXT = """ -#import time -/*********************************************************************** - * This file was generated by $file on $time.strftime("%c") - **********************************************************************/ - -\#include -\#include -\#include -\#include - -//define the endian macros to convert integers -\#ifdef BOOST_BIG_ENDIAN - \#define BE_MACRO(x) (x) - \#define LE_MACRO(x) uhd::byteswap(x) -\#else - \#define BE_MACRO(x) uhd::byteswap(x) - \#define LE_MACRO(x) (x) -\#endif - -using namespace uhd; -using namespace uhd::transport; - -######################################################################## -#def gen_code($XE_MACRO, $suffix) -######################################################################## - -######################################################################## -## setup predicates -######################################################################## -#set $sid_p = 0b00001 -#set $cid_p = 0b00010 -#set $tsi_p = 0b00100 -#set $tsf_p = 0b01000 -#set $tlr_p = 0b10000 - -static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ - *(reinterpret_cast(mem)) = $(XE_MACRO)(num); -} - -void vrt::if_hdr_pack_$(suffix)( - boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info -){ - boost::uint32_t vrt_hdr_flags = 0; - - boost::uint8_t pred = 0; - if (if_packet_info.has_sid) pred |= $hex($sid_p); - if (if_packet_info.has_cid) pred |= $hex($cid_p); - if (if_packet_info.has_tsi) pred |= $hex($tsi_p); - if (if_packet_info.has_tsf) pred |= $hex($tsf_p); - if (if_packet_info.has_tlr) pred |= $hex($tlr_p); - - switch(pred){ - #for $pred in range(2**5) - case $pred: - #set $num_header_words = 1 - #set $flags = 0 - ########## Stream ID ########## - #if $pred & $sid_p - packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); - #set $num_header_words += 1 - #set $flags |= (0x1 << 28); - #end if - ########## Class ID ########## - #if $pred & $cid_p - pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); - #set $num_header_words += 2 - #set $flags |= (0x1 << 27); - #end if - ########## Integer Time ########## - #if $pred & $tsi_p - packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); - #set $num_header_words += 1 - #set $flags |= (0x3 << 22); - #end if - ########## Fractional Time ########## - #if $pred & $tsf_p - pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); - #set $num_header_words += 2 - #set $flags |= (0x1 << 20); - #end if - ########## Trailer ########## - #if $pred & $tlr_p - //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); - #set $flags |= (0x1 << 26); - #set $num_trailer_words = 1; - #else - //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; - #set $num_trailer_words = 0; - #end if - ########## Variables ########## - if_packet_info.num_header_words32 = $num_header_words; - if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; - vrt_hdr_flags = $hex($flags); - break; - #end for - } - - //set the burst flags - if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); - if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24); - - //fill in complete header word - packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0 - | vrt_hdr_flags - | ((if_packet_info.packet_count & 0xf) << 16) - | (if_packet_info.num_packet_words32 & 0xffff) - )); -} - -static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ - num = $(XE_MACRO)(*reinterpret_cast(mem)); -} - -void vrt::if_hdr_unpack_$(suffix)( - const boost::uint32_t *packet_buff, - if_packet_info_t &if_packet_info -){ - //extract vrt header - boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); - size_t packet_words32 = vrt_hdr_word & 0xffff; - if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; - - //failure cases - if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) - throw std::runtime_error("bad vrt header or packet fragment"); - if (vrt_hdr_word & (0x7 << 29)) - throw std::runtime_error("unsupported vrt packet type"); - - boost::uint8_t pred = 0; - if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); - if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p); - if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p); - if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p); - if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p); - - switch(pred){ - #for $pred in range(2**5) - case $pred: - #set $has_time_spec = False - #set $num_header_words = 1 - ########## Stream ID ########## - #if $pred & $sid_p - if_packet_info.has_sid = true; - if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); - #set $num_header_words += 1 - #else - if_packet_info.has_sid = false; - #end if - ########## Class ID ########## - #if $pred & $cid_p - if_packet_info.has_cid = true; - unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); - #set $num_header_words += 2 - #else - if_packet_info.has_cid = false; - #end if - ########## Integer Time ########## - #if $pred & $tsi_p - if_packet_info.has_tsi = true; - if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); - #set $num_header_words += 1 - #else - if_packet_info.has_tsi = false; - #end if - ########## Fractional Time ########## - #if $pred & $tsf_p - if_packet_info.has_tsf = true; - unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); - #set $num_header_words += 2 - #else - if_packet_info.has_tsf = false; - #end if - ########## Trailer ########## - #if $pred & $tlr_p - if_packet_info.has_tlr = true; - if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); - #set $num_trailer_words = 1; - #else - if_packet_info.has_tlr = false; - #set $num_trailer_words = 0; - #end if - ########## Variables ########## - if_packet_info.num_header_words32 = $num_header_words; - if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); - break; - #end for - } -} - -######################################################################## -#end def -######################################################################## - -$gen_code("BE_MACRO", "be") -$gen_code("LE_MACRO", "le") -""" - -def parse_tmpl(_tmpl_text, **kwargs): - from Cheetah.Template import Template - return str(Template(_tmpl_text, kwargs)) - -if __name__ == '__main__': - import sys - open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__)) diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py new file mode 100755 index 000000000..536409b2e --- /dev/null +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python +# +# 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 . +# + +""" +The vrt packer/unpacker code generator: + +This script will generate the pack and unpack routines that convert +metatdata into vrt headers and vrt headers into metadata. + +The generated code infers jump tables to speed-up the parsing time. +""" + +TMPL_TEXT = """ +#import time +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#include +\#include +\#include +\#include + +//define the endian macros to convert integers +\#ifdef BOOST_BIG_ENDIAN + \#define BE_MACRO(x) (x) + \#define LE_MACRO(x) uhd::byteswap(x) +\#else + \#define BE_MACRO(x) uhd::byteswap(x) + \#define LE_MACRO(x) (x) +\#endif + +using namespace uhd; +using namespace uhd::transport; + +######################################################################## +#def gen_code($XE_MACRO, $suffix) +######################################################################## + +######################################################################## +## setup predicates +######################################################################## +#set $sid_p = 0b00001 +#set $cid_p = 0b00010 +#set $tsi_p = 0b00100 +#set $tsf_p = 0b01000 +#set $tlr_p = 0b10000 + +static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ + *(reinterpret_cast(mem)) = $(XE_MACRO)(num); +} + +void vrt::if_hdr_pack_$(suffix)( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +){ + boost::uint32_t vrt_hdr_flags = 0; + + boost::uint8_t pred = 0; + if (if_packet_info.has_sid) pred |= $hex($sid_p); + if (if_packet_info.has_cid) pred |= $hex($cid_p); + if (if_packet_info.has_tsi) pred |= $hex($tsi_p); + if (if_packet_info.has_tsf) pred |= $hex($tsf_p); + if (if_packet_info.has_tlr) pred |= $hex($tlr_p); + + switch(pred){ + #for $pred in range(2**5) + case $pred: + #set $num_header_words = 1 + #set $flags = 0 + ########## Stream ID ########## + #if $pred & $sid_p + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid); + #set $num_header_words += 1 + #set $flags |= (0x1 << 28); + #end if + ########## Class ID ########## + #if $pred & $cid_p + pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 + #set $flags |= (0x1 << 27); + #end if + ########## Integer Time ########## + #if $pred & $tsi_p + packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi); + #set $num_header_words += 1 + #set $flags |= (0x3 << 22); + #end if + ########## Fractional Time ########## + #if $pred & $tsf_p + pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 + #set $flags |= (0x1 << 20); + #end if + ########## Trailer ########## + #if $pred & $tlr_p + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr); + #set $flags |= (0x1 << 26); + #set $num_trailer_words = 1; + #else + //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; + #set $num_trailer_words = 0; + #end if + ########## Variables ########## + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32; + vrt_hdr_flags = $hex($flags); + break; + #end for + } + + //set the burst flags + if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); + if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24); + + //fill in complete header word + packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0 + | vrt_hdr_flags + | ((if_packet_info.packet_count & 0xf) << 16) + | (if_packet_info.num_packet_words32 & 0xffff) + )); +} + +static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ + num = $(XE_MACRO)(*reinterpret_cast(mem)); +} + +void vrt::if_hdr_unpack_$(suffix)( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info +){ + //extract vrt header + boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); + size_t packet_words32 = vrt_hdr_word & 0xffff; + if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; + + //failure cases + if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) + throw std::runtime_error("bad vrt header or packet fragment"); + if (vrt_hdr_word & (0x7 << 29)) + throw std::runtime_error("unsupported vrt packet type"); + + boost::uint8_t pred = 0; + if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); + if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p); + if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p); + if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p); + if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p); + + switch(pred){ + #for $pred in range(2**5) + case $pred: + #set $has_time_spec = False + #set $num_header_words = 1 + ########## Stream ID ########## + #if $pred & $sid_p + if_packet_info.has_sid = true; + if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]); + #set $num_header_words += 1 + #else + if_packet_info.has_sid = false; + #end if + ########## Class ID ########## + #if $pred & $cid_p + if_packet_info.has_cid = true; + unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_cid = false; + #end if + ########## Integer Time ########## + #if $pred & $tsi_p + if_packet_info.has_tsi = true; + if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]); + #set $num_header_words += 1 + #else + if_packet_info.has_tsi = false; + #end if + ########## Fractional Time ########## + #if $pred & $tsf_p + if_packet_info.has_tsf = true; + unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); + #set $num_header_words += 2 + #else + if_packet_info.has_tsf = false; + #end if + ########## Trailer ########## + #if $pred & $tlr_p + if_packet_info.has_tlr = true; + if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); + #set $num_trailer_words = 1; + #else + if_packet_info.has_tlr = false; + #set $num_trailer_words = 0; + #end if + ########## Variables ########## + if_packet_info.num_header_words32 = $num_header_words; + if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); + break; + #end for + } +} + +######################################################################## +#end def +######################################################################## + +$gen_code("BE_MACRO", "be") +$gen_code("LE_MACRO", "le") +""" + +def parse_tmpl(_tmpl_text, **kwargs): + from Cheetah.Template import Template + return str(Template(_tmpl_text, kwargs)) + +if __name__ == '__main__': + import sys + open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__)) diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 8cbc71008..31b7e6614 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 719cf3f16..df1dba663 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 3f74a836e..b90b2fc15 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -16,7 +16,7 @@ // #include -#include +#include #include using namespace uhd::transport; -- cgit v1.2.3 From 82790f3da8afe646f255da428c5936045f0e2434 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Jul 2010 15:38:06 -0700 Subject: usrp2: some cleanup and tweaks in io impl --- host/lib/usrp/usrp2/io_impl.cpp | 117 ++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 41 deletions(-) (limited to 'host') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 0c92c33b2..c96528694 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -34,60 +34,81 @@ namespace asio = boost::asio; /*********************************************************************** * io impl details (internal to this file) + * - pirate crew + * - alignment buffer + * - thread loop + * - vrt packet handler states **********************************************************************/ struct usrp2_impl::io_impl{ typedef alignment_buffer alignment_buffer_type; - io_impl(std::vector &zc_ifs); - ~io_impl(void); + io_impl(size_t num_frames, size_t width): + packet_handler_recv_state(width), + recv_pirate_booty(alignment_buffer_type::make(num_frames, width)) + { + /* NOP */ + } + + ~io_impl(void){ + recv_pirate_crew_raiding = false; + recv_pirate_crew.interrupt_all(); + recv_pirate_crew.join_all(); + } - bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs); + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); + } //state management for the vrt packet handler code vrt_packet_handler::recv_state packet_handler_recv_state; vrt_packet_handler::send_state packet_handler_send_state; - //methods and variables for the recv pirate - void recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index); + //methods and variables for the pirate crew + void recv_pirate_loop(zero_copy_if::sptr, usrp2_mboard_impl::sptr, size_t); boost::thread_group recv_pirate_crew; - bool recv_pirate_crew_running; + bool recv_pirate_crew_raiding; alignment_buffer_type::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(std::vector &zc_ifs): - packet_handler_recv_state(zc_ifs.size()) -{ - //create a large enough booty - size_t num_frames = zc_ifs.at(0)->get_num_recv_frames(); - std::cout << "Recv pirate num frames: " << num_frames << std::endl; - recv_pirate_booty = alignment_buffer_type::make(num_frames, zc_ifs.size()); - - //create a new pirate thread for each zc if (yarr!!) - for (size_t i = 0; i < zc_ifs.size(); i++){ - recv_pirate_crew.create_thread( - boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_ifs.at(i), i) - ); - } -} - -usrp2_impl::io_impl::~io_impl(void){ - recv_pirate_crew_running = false; - recv_pirate_crew.interrupt_all(); - recv_pirate_crew.join_all(); -} - -bool usrp2_impl::io_impl::get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); -} - -void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if, size_t index){ +/*********************************************************************** + * Receive Pirate Loop + * - while raiding, loot for recv buffers + * - put booty into the alignment buffer + **********************************************************************/ +void usrp2_impl::io_impl::recv_pirate_loop( + zero_copy_if::sptr zc_if, + usrp2_mboard_impl::sptr mboard, + size_t index +){ set_thread_priority_safe(); - recv_pirate_crew_running = true; - while(recv_pirate_crew_running){ + recv_pirate_crew_raiding = true; + while(recv_pirate_crew_raiding){ managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); - //TODO unpack vrt, get time spec, round to nearest packet bound, use below: - if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff, time_spec_t(/*todoseq*/), index); + if (buff->size() == 0) continue; //ignore timeout buffers + + try{ + //extract the vrt header packet info + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); + vrt::if_hdr_unpack_be(buff->cast(), if_packet_info); + + //extract the timespec and round to the nearest packet + UHD_ASSERT_THROW(if_packet_info.has_tsi and if_packet_info.has_tsf); + + //size_t pkt_dur_ticks = mboard->get_master_clock_freq() * 1; //TODO FIXME + //size_t(if_packet_info.tsf) - size_t(if_packet_info.tsf)%pkt_dur_ticks + //the idea is to round the time specs to packet boundaries to avoid the issue + //of never getting alignment when things are not locked properly + time_spec_t time( + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq() + ); + + //push the packet into the buffer with the new time + recv_pirate_booty->push_with_pop_on_full(buff, time, index); + }catch(const std::exception &e){ + std::cerr << "Error (usrp2 recv pirate loop): " << e.what() << std::endl; + } } } @@ -103,11 +124,25 @@ void usrp2_impl::io_init(void){ send_buff->commit(sizeof(data)); } - std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; - std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; + //the number of recv frames is the number for the first transport + //the assumption is that all data transports should be identical + size_t num_frames = _data_transports.front()->get_num_recv_frames(); //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transports)); + _io_impl = UHD_PIMPL_MAKE(io_impl, (num_frames, _data_transports.size())); + + //create a new pirate thread for each zc if (yarr!!) + for (size_t i = 0; i < _data_transports.size(); i++){ + _io_impl->recv_pirate_crew.create_thread(boost::bind( + &usrp2_impl::io_impl::recv_pirate_loop, + _io_impl, _data_transports.at(i), + _mboards.at(i), i + )); + } + + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; + std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; + std::cout << "Recv pirate num frames: " << num_frames << std::endl; } /*********************************************************************** -- cgit v1.2.3 From 3b1473d5a3fbfb89e9ddc5575e855644707718d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Jul 2010 16:08:33 -0700 Subject: usrp2: removed usrp2.hpp header, its not needed, just use the discovery/factory system uhd: added usrp_mimo skeleton code/header --- host/include/uhd/usrp/CMakeLists.txt | 6 ++-- host/include/uhd/usrp/mimo_usrp.hpp | 69 ++++++++++++++++++++++++++++++++++++ host/include/uhd/usrp/usrp2.hpp | 62 -------------------------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 22 ++++++------ host/lib/usrp/usrp2/usrp2_impl.hpp | 2 +- host/utils/usrp2_addr_burner.cpp | 5 +-- 6 files changed, 87 insertions(+), 79 deletions(-) create mode 100644 host/include/uhd/usrp/mimo_usrp.hpp delete mode 100644 host/include/uhd/usrp/usrp2.hpp (limited to 'host') diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index bbd124ed8..6f8c1a2d8 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -31,12 +31,12 @@ INSTALL(FILES dboard_iface.hpp dboard_manager.hpp - ### usrp headers ### - usrp2.hpp - ### utilities ### tune_helper.hpp + + ### interfaces ### simple_usrp.hpp + mimo_usrp.hpp DESTINATION ${INCLUDE_DIR}/uhd/usrp ) diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp new file mode 100644 index 000000000..2262b324e --- /dev/null +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -0,0 +1,69 @@ +// +// 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_UHD_USRP_MIMO_USRP_HPP +#define INCLUDED_UHD_USRP_MIMO_USRP_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uhd{ namespace usrp{ + +/*! + * The MIMO USRP device class: + * A mimo usrp facilitates ease-of-use for multi-usrp scenarios. + * The wrapper provides convenience functions to control the group + * of underlying devices as if they consisted of a single device. + */ +class UHD_API mimo_usrp : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new mimo usrp from the device address. + * \param dev_addr the device address + * \return a new mimo usrp object + */ + static sptr make(const device_addr_t &dev_addr); + + /*! + * Get the underlying device object. + * This is needed to get access to the streaming API and properties. + * \return the device object within this simple usrp + */ + virtual device::sptr get_device(void) = 0; + + /*! + * Get a printable name for this mimo usrp. + * \return a printable string + */ + virtual std::string get_name(void) = 0; + + //TODO + +}; + +}} + +#endif /* INCLUDED_UHD_USRP_MIMO_USRP_HPP */ diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp deleted file mode 100644 index 7387e5dd4..000000000 --- a/host/include/uhd/usrp/usrp2.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_UHD_USRP_USRP2_HPP -#define INCLUDED_UHD_USRP_USRP2_HPP - -#include -#include - -namespace uhd{ namespace usrp{ - -/*! - * The usrp2 device class. - */ -class UHD_API usrp2 : public device{ -public: - /*! - * Find usrp2 devices over the ethernet. - * - * Recommended key/value pairs for the device hint address: - * hint["addr"] = address, where address is a resolvable address - * or ip address, which may or may not be a broadcast address. - * - * Other optional device address keys: - * recv_buff_size: resizes the recv buffer on the data socket - * send_buff_size: resizes the send buffer on the data socket - * - * \param hint a device addr with the usrp2 address filled in - * \return a vector of device addresses for all usrp2s found - */ - static device_addrs_t find(const device_addr_t &hint); - - /*! - * Make a usrp2 from a device address. - * - * Required key/value pairs for the device address: - * hint["addr"] = address, where address is a resolvable address - * or ip address, which must be the specific address of a usrp2. - * - * \param addr the device address - * \return a device sptr to a new usrp2 - */ - static device::sptr make(const device_addr_t &addr); -}; - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_USRP2_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 436146a48..cdba19f50 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -35,10 +35,6 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -UHD_STATIC_BLOCK(register_usrp2_device){ - device::register_device(&usrp2::find, &usrp2::make); -} - /*********************************************************************** * Helper Functions **********************************************************************/ @@ -48,10 +44,14 @@ std::vector split_addrs(const std::string &addrs_str){ return addrs; } +template std::string num2str(T num){ + return boost::lexical_cast(num); +} + /*********************************************************************** * Discovery over the udp transport **********************************************************************/ -uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ +static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){ device_addrs_t usrp2_addrs; //return an empty list of addresses when type is set to non-usrp2 @@ -68,7 +68,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ new_hint["addr"] = if_addrs.bcast; //call discover with the new hint and append results - device_addrs_t new_usrp2_addrs = usrp2::find(new_hint); + device_addrs_t new_usrp2_addrs = usrp2_find(new_hint); usrp2_addrs.insert(usrp2_addrs.begin(), new_usrp2_addrs.begin(), new_usrp2_addrs.end() ); @@ -127,11 +127,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -template std::string num2str(T num){ - return boost::lexical_cast(num); -} - -device::sptr usrp2::make(const device_addr_t &device_addr){ +static device::sptr usrp2_make(const device_addr_t &device_addr){ //extract the receive and send buffer sizes size_t recv_buff_size = 0, send_buff_size= 0 ; if (device_addr.has_key("recv_buff_size")){ @@ -161,6 +157,10 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ ); } +UHD_STATIC_BLOCK(register_usrp2_device){ + device::register_device(&usrp2_find, &usrp2_make); +} + /*********************************************************************** * Structors **********************************************************************/ diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index df1dba663..07e29eadd 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,7 +22,7 @@ #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include "serdes_ctrl.hpp" -#include +#include #include #include #include diff --git a/host/utils/usrp2_addr_burner.cpp b/host/utils/usrp2_addr_burner.cpp index 08fc1e218..f0e3434b7 100644 --- a/host/utils/usrp2_addr_burner.cpp +++ b/host/utils/usrp2_addr_burner.cpp @@ -16,7 +16,7 @@ // #include -#include +#include #include #include #include @@ -45,6 +45,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //load the options into the address uhd::device_addr_t device_addr; + device_addr["type"] = "usrp2"; if (vm.count("addr")){ device_addr["addr"] = vm["addr"].as(); } @@ -54,7 +55,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } //create a usrp2 device - uhd::device::sptr u2_dev = uhd::usrp::usrp2::make(device_addr); + uhd::device::sptr u2_dev = uhd::device::make(device_addr); //FIXME usees the default mboard for now (until the mimo link is supported) wax::obj u2_mb = (*u2_dev)[uhd::usrp::DEVICE_PROP_MBOARD]; std::cout << std::endl; -- cgit v1.2.3 From 6469d2419f8564c37f8fd6870aedbc990f06e108 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 1 Jul 2010 18:32:37 -0700 Subject: uhd: filling in mimo usrp implementation, renamed get_name to get_pp_string for simple and mimo usrp --- host/examples/benchmark_rx_rate.cpp | 2 +- host/examples/rx_timed_samples.cpp | 2 +- host/examples/tx_timed_samples.cpp | 2 +- host/include/uhd/usrp/mimo_usrp.hpp | 41 +++++++++- host/include/uhd/usrp/simple_usrp.hpp | 16 ++-- host/lib/usrp/CMakeLists.txt | 1 + host/lib/usrp/mimo_usrp.cpp | 149 ++++++++++++++++++++++++++++++++++ host/lib/usrp/simple_usrp.cpp | 12 +-- host/lib/usrp/usrp2/usrp2_impl.cpp | 3 +- 9 files changed, 208 insertions(+), 20 deletions(-) create mode 100644 host/lib/usrp/mimo_usrp.cpp (limited to 'host') diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 53f4a3c68..e7e358e4c 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -124,7 +124,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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); - std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; sdev->set_rx_rate(500e3); //initial rate while(true){ diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 8db312690..3c3c3fdc6 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -59,7 +59,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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; + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; //set properties on the device std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl; diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 333f03fbe..846d9b6f4 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -61,7 +61,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ 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; + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; //set properties on the device std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 2262b324e..8820c91c1 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -58,9 +58,46 @@ public: * Get a printable name for this mimo usrp. * \return a printable string */ - virtual std::string get_name(void) = 0; + virtual std::string get_pp_string(void) = 0; - //TODO + /*! + * Get the number of channels in this mimo configuration. + * The number of rx channels == the number of tx channels. + * \return the number of channels + */ + virtual size_t get_num_channels(void) = 0; + + /******************************************************************* + * Misc + ******************************************************************/ + /*! + * Set the time registers on the usrp at the next pps tick. + * The values will not be latched in until the pulse occurs. + * It is recommended that the user sleep(1) after calling to ensure + * that the time registers will be in a known state prior to use. + * + * Note: Because this call sets the time on the "next" pps, + * the seconds in the time spec should be current seconds + 1. + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + + /*! + * Issue a stream command to the usrp device. + * This tells the usrp to send samples into the host. + * See the documentation for stream_cmd_t for more info. + * \param stream_cmd the stream command to issue + */ + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + + /******************************************************************* + * TX methods + ******************************************************************/ }; diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 6ba1b90dd..1d817e030 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -58,7 +58,7 @@ public: * Get a printable name for this simple usrp. * \return a printable string */ - virtual std::string get_name(void) = 0; + virtual std::string get_pp_string(void) = 0; /******************************************************************* * Misc @@ -98,13 +98,6 @@ public: */ virtual void set_clock_config(const clock_config_t &clock_config) = 0; - /*! - * Read the RSSI value from a usrp device. - * Or throw if the dboard does not support an RSSI readback. - * \return the rssi in dB - */ - virtual float read_rssi(void) = 0; - /******************************************************************* * RX methods ******************************************************************/ @@ -125,6 +118,13 @@ public: virtual bool get_rx_lo_locked(void) = 0; + /*! + * Read the RSSI value from a usrp device. + * Or throw if the dboard does not support an RSSI readback. + * \return the rssi in dB + */ + virtual float read_rssi(void) = 0; + /******************************************************************* * TX methods ******************************************************************/ diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 3e12c087e..814affdd0 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -23,6 +23,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp ) diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp new file mode 100644 index 000000000..54c921ac7 --- /dev/null +++ b/host/lib/usrp/mimo_usrp.cpp @@ -0,0 +1,149 @@ +// +// 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 +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * MIMO USRP Implementation + **********************************************************************/ +class mimo_usrp_impl : public mimo_usrp{ +public: + mimo_usrp_impl(const device_addr_t &addr){ + _dev = device::make(addr); + + //extract each mboard and its sub-devices + BOOST_FOREACH(const std::string &name, (*_dev)[DEVICE_PROP_MBOARD_NAMES].as()){ + _mboards.push_back((*_dev)[named_prop_t(DEVICE_PROP_MBOARD, name)]); + _rx_dsps.push_back(_mboards.back()[MBOARD_PROP_RX_DSP]); + _tx_dsps.push_back(_mboards.back()[MBOARD_PROP_TX_DSP]); + + //extract rx subdevice + _rx_dboards.push_back(_mboards.back()[MBOARD_PROP_RX_DBOARD]); + std::string rx_subdev_in_use = _rx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as().at(0); + _rx_subdevs.push_back(_rx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]); + + //extract tx subdevice + _tx_dboards.push_back(_mboards.back()[MBOARD_PROP_TX_DBOARD]); + std::string tx_subdev_in_use = _tx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as().at(0); + _tx_subdevs.push_back(_tx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)]); + } + + //set the clock config across all mboards (TODO set through api) + clock_config_t clock_config; + clock_config.ref_source = clock_config_t::REF_SMA; + clock_config.pps_source = clock_config_t::PPS_SMA; + BOOST_FOREACH(wax::obj mboard, _mboards){ + mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + } + + } + + ~mimo_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_pp_string(void){ + std::string buff = str(boost::format( + "MIMO USRP:\n" + " Device: %s\n" + ) + % (*_dev)[DEVICE_PROP_NAME].as() + ); + for (size_t i = 0; i < get_num_channels(); i++){ + buff += str(boost::format( + " Channel: %u\n" + " Mboard: %s\n" + " RX DSP: %s\n" + " RX Dboard: %s\n" + " RX Subdev: %s\n" + " TX DSP: %s\n" + " TX Dboard: %s\n" + " TX Subdev: %s\n" + ) % i + % _mboards.at(i)[MBOARD_PROP_NAME].as() + % _rx_dsps.at(i)[DSP_PROP_NAME].as() + % _rx_dboards.at(i)[DBOARD_PROP_NAME].as() + % _rx_subdevs.at(i)[SUBDEV_PROP_NAME].as() + % _tx_dsps.at(i)[DSP_PROP_NAME].as() + % _tx_dboards.at(i)[DBOARD_PROP_NAME].as() + % _tx_subdevs.at(i)[SUBDEV_PROP_NAME].as() + ); + } + return buff; + } + + size_t get_num_channels(void){ + return _mboards.size(); + } + + /******************************************************************* + * Misc + ******************************************************************/ + void set_time_next_pps(const time_spec_t &time_spec){ + BOOST_FOREACH(wax::obj mboard, _mboards){ + mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + BOOST_FOREACH(wax::obj mboard, _mboards){ + mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd; + } + } + + /******************************************************************* + * RX methods + ******************************************************************/ + + /******************************************************************* + * TX methods + ******************************************************************/ + +private: + device::sptr _dev; + std::vector _mboards; + std::vector _rx_dsps; + std::vector _tx_dsps; + std::vector _rx_dboards; + std::vector _tx_dboards; + std::vector _rx_subdevs; + std::vector _tx_subdevs; +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){ + return sptr(new mimo_usrp_impl(dev_addr)); +} diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index f4aa82669..4a5171cf7 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -31,7 +31,7 @@ using namespace uhd; using namespace uhd::usrp; /*********************************************************************** - * Simple Device Implementation + * Simple USRP Implementation **********************************************************************/ class simple_usrp_impl : public simple_usrp{ public: @@ -60,7 +60,7 @@ public: return _dev; } - std::string get_name(void){ + std::string get_pp_string(void){ return str(boost::format( "Simple USRP:\n" " Device: %s\n" @@ -102,10 +102,6 @@ public: _mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; } - float read_rssi(void){ - return _rx_subdev[SUBDEV_PROP_RSSI].as(); - } - /******************************************************************* * RX methods ******************************************************************/ @@ -157,6 +153,10 @@ public: return _rx_subdev[SUBDEV_PROP_LO_LOCKED].as(); } + float read_rssi(void){ + return _rx_subdev[SUBDEV_PROP_RSSI].as(); + } + /******************************************************************* * TX methods ******************************************************************/ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index cdba19f50..3402c26b1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -199,7 +199,8 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as()){ case DEVICE_PROP_NAME: - val = std::string("usrp2 device"); + if (_mboards.size() > 1) val = std::string("usrp2 mimo device"); + else val = std::string("usrp2 device"); return; case DEVICE_PROP_MBOARD: -- cgit v1.2.3 From 09ad8e1337c76ae9ca8bbf18791519fa786a286a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 2 Jul 2010 10:48:43 -0700 Subject: uhd: filled in mimo usrp rx and tx methods --- host/include/uhd/usrp/mimo_usrp.hpp | 40 ++++++++++++ host/include/uhd/utils/algorithm.hpp | 29 +++++++++ host/lib/usrp/mimo_usrp.cpp | 118 +++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) (limited to 'host') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 8820c91c1..483feca29 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -94,10 +94,50 @@ public: /******************************************************************* * RX methods ******************************************************************/ + virtual void set_rx_rate_all(double rate) = 0; + virtual double get_rx_rate_all(void) = 0; + + virtual tune_result_t set_rx_freq(size_t chan, double freq) = 0; + virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0; + virtual freq_range_t get_rx_freq_range(size_t chan) = 0; + + virtual void set_rx_gain(size_t chan, float gain) = 0; + virtual float get_rx_gain(size_t chan) = 0; + virtual gain_range_t get_rx_gain_range(size_t chan) = 0; + + virtual void set_rx_antenna(size_t chan, const std::string &ant) = 0; + virtual std::string get_rx_antenna(size_t chan) = 0; + virtual std::vector get_rx_antennas(size_t chan) = 0; + + virtual bool get_rx_lo_locked(size_t chan) = 0; + + /*! + * Read the RSSI value from a usrp device. + * Or throw if the dboard does not support an RSSI readback. + * \param chan which mimo channel 0 to N-1 + * \return the rssi in dB + */ + virtual float read_rssi(size_t chan) = 0; /******************************************************************* * TX methods ******************************************************************/ + virtual void set_tx_rate_all(double rate) = 0; + virtual double get_tx_rate_all(void) = 0; + + virtual tune_result_t set_tx_freq(size_t chan, double freq) = 0; + virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0; + virtual freq_range_t get_tx_freq_range(size_t chan) = 0; + + virtual void set_tx_gain(size_t chan, float gain) = 0; + virtual float get_tx_gain(size_t chan) = 0; + virtual gain_range_t get_tx_gain_range(size_t chan) = 0; + + virtual void set_tx_antenna(size_t chan, const std::string &ant) = 0; + virtual std::string get_tx_antenna(size_t chan) = 0; + virtual std::vector get_tx_antennas(size_t chan) = 0; + + virtual bool get_tx_lo_locked(size_t chan) = 0; }; diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp index 08977a69f..b52edc6b5 100644 --- a/host/include/uhd/utils/algorithm.hpp +++ b/host/include/uhd/utils/algorithm.hpp @@ -82,6 +82,35 @@ namespace std{ return boost::end(range) != std::find(boost::begin(range), boost::end(range), value); } + /*! + * Count the number of appearances of a value in a range. + * + * Uses std::count to count the appearances in the range. + * + * \param range the elements to iterate through + * \param value the value to count in the range + * \return the number of appearances of the value + */ + template inline + size_t count(const Range &range, const T &value){ + return std::count(boost::begin(range), boost::end(range), value); + } + + /*! + * Are the ranges equal (are their elements equivalent)? + * + * Uses std::equal to search the iterable for an element. + * + * \param range1 the first range of elements + * \param range2 the second range of elements + * \return true when the elements are equivalent + */ + template inline + bool equal(const Range &range1, const Range &range2){ + return (boost::size(range1) == boost::size(range2)) and + std::equal(boost::begin(range1), boost::end(range1), boost::begin(range2)); + } + /*! * A templated signum implementation. * \param n the comparable to process diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 54c921ac7..3c9788388 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -125,10 +126,124 @@ public: /******************************************************************* * RX methods ******************************************************************/ + void set_rx_rate_all(double rate){ + std::vector _actual_rates; + BOOST_FOREACH(wax::obj rx_dsp, _rx_dsps){ + rx_dsp[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(rx_dsp[DSP_PROP_HOST_RATE].as()); + } + _rx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: rx rate inconsistent across mboards" + ); + } + + double get_rx_rate_all(void){ + return _rx_rate; + } + + tune_result_t set_rx_freq(size_t chan, double target_freq){ + return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq); + } + + tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ + return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq, lo_off); + } + + freq_range_t get_rx_freq_range(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as(); + } + + void set_rx_gain(size_t chan, float gain){ + _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain; + } + + float get_rx_gain(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as(); + } + + gain_range_t get_rx_gain_range(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as(); + } + + void set_rx_antenna(size_t chan, const std::string &ant){ + _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_rx_antennas(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_rx_lo_locked(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } + + float read_rssi(size_t chan){ + return _rx_subdevs.at(chan)[SUBDEV_PROP_RSSI].as(); + } /******************************************************************* * TX methods ******************************************************************/ + void set_tx_rate_all(double rate){ + std::vector _actual_rates; + BOOST_FOREACH(wax::obj tx_dsp, _tx_dsps){ + tx_dsp[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(tx_dsp[DSP_PROP_HOST_RATE].as()); + } + _tx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: tx rate inconsistent across mboards" + ); + } + + double get_tx_rate_all(void){ + return _rx_rate; + } + + tune_result_t set_tx_freq(size_t chan, double target_freq){ + return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq); + } + + tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ + return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq, lo_off); + } + + freq_range_t get_tx_freq_range(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as(); + } + + void set_tx_gain(size_t chan, float gain){ + _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain; + } + + float get_tx_gain(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as(); + } + + gain_range_t get_tx_gain_range(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as(); + } + + void set_tx_antenna(size_t chan, const std::string &ant){ + _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as(); + } + + std::vector get_tx_antennas(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as(); + } + + bool get_tx_lo_locked(size_t chan){ + return _tx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as(); + } private: device::sptr _dev; @@ -139,6 +254,9 @@ private: std::vector _tx_dboards; std::vector _rx_subdevs; std::vector _tx_subdevs; + + //shadows + double _rx_rate, _tx_rate; }; /*********************************************************************** -- cgit v1.2.3 From 37bc860d52c937fb35925af3590d9bca1ecad559 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 2 Jul 2010 18:29:19 -0700 Subject: mimo: added call to set time to zero at next pps on init --- host/include/uhd/usrp/mimo_usrp.hpp | 1 + host/lib/usrp/mimo_usrp.cpp | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'host') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 483feca29..a3cbde483 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -75,6 +75,7 @@ public: * The values will not be latched in until the pulse occurs. * It is recommended that the user sleep(1) after calling to ensure * that the time registers will be in a known state prior to use. + * This call works across all mboards in the mimo configuration. * * Note: Because this call sets the time on the "next" pps, * the seconds in the time spec should be current seconds + 1. diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 3c9788388..bd7753d09 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -64,6 +64,10 @@ public: mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; } + //set the times to zero at the next pps and sleep + this->set_time_next_pps(time_spec_t(0, 0)); + sleep(1); + } ~mimo_usrp_impl(void){ -- cgit v1.2.3 From 52ea9b8f90c56c12e978387aee670b45d93d74a5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 3 Jul 2010 11:19:14 -0700 Subject: uhd: added mimo notes, misc spellcheck and tweaks --- host/docs/coding.rst | 37 +++++++++++++++++++++++++++++-------- host/docs/dboards.rst | 8 ++++---- host/docs/general.rst | 2 +- host/docs/usrp2.rst | 39 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 15 deletions(-) (limited to 'host') diff --git a/host/docs/coding.rst b/host/docs/coding.rst index 689667f30..84f9abf3e 100644 --- a/host/docs/coding.rst +++ b/host/docs/coding.rst @@ -5,8 +5,11 @@ UHD - Coding to the API .. contents:: Table of Contents ------------------------------------------------------------------------ -Low-Level: The device API +Various API interfaces ------------------------------------------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Low-Level: The device API +^^^^^^^^^^^^^^^^^^^^^^^^^^^ A device is an abstraction for hardware that is connected to the host system. For a USRP, this means that the motherboard and everything on it would be considered to be a "device". The device API provides ways to: @@ -17,12 +20,12 @@ The device API provides ways to: * Streaming samples with metadata into and out of the device. * Set and get properties on the device object. -See the documentation in device.hpp for reference. +See the documentation in *device.hpp* for reference. ------------------------------------------------------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^ High-Level: The simple usrp ------------------------------------------------------------------------- -The goal of the simple usrp is to wrap high level functions around the device properties. +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The goal of the simple usrp API is to wrap high level functions around the device properties. The simple usrp provides a fat interface to access the most common properties. The simple usrp provides ways to: @@ -35,14 +38,32 @@ The simple usrp provides ways to: * Set the usrp time registers. * Get the underlying device (as discussed above). -It is recommended that users code to the simple_usrp api when possible. -See the documentation in usrp/simple_usrp.hpp for reference. +See the documentation in *usrp/simple_usrp.hpp* for reference. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +High-Level: The mimo usrp +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The mimo usrp API provides a wrapper around a device that represents several motherboards. +This API provides convenience calls just like the simple usrp, +however the calls either work across all channels in the configuration, +or take a channel argument to specify which channel to configure. +The mimo usrp provides ways to: + +* Set and get the sample rate across all channels. +* Issue a stream command across all channels. +* Set the time registers across all channels. +* Set and get individual daughterboard gains. +* Set and get individual daughterboard antennas. +* Tune individual DSPs and daughterboards. +* Get the underlying device (as discussed above). + +See the documentation in *usrp/mimo_usrp.hpp* for reference. ------------------------------------------------------------------------ Integrating custom hardware ------------------------------------------------------------------------ Creators of custom hardware can create drivers that use the UHD API. -These drivers can be built as dynamically lodable modules that the UHD will load at runtime. +These drivers can be built as dynamically loadable modules that the UHD will load at runtime. For a module to be loaded at runtime, it must be found in the UHD_MODULE_PATH environment variable. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index e14f49933..9c496ebee 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -23,7 +23,7 @@ The Basic RX and LFRX boards have 3 subdevices: The boards have no tunable elements or programmable gains. Though the magic of aliasing, you can down-convert signals -greater than the nyquist rate of the ADC. +greater than the Nyquist rate of the ADC. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Basic TX and and LFTX @@ -50,7 +50,7 @@ Recieve Gains: **PGA0**, Range: 0-45dB ^^^^^^^^^^^^^^^^^^^^^^^^^^^ XCVR 2450 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The XCVR2450 has a non-contiguous tuning range consiting of a high band and a low band. +The XCVR2450 has a non-contiguous tuning range consisting of a high band and a low band. The high band consists of frequencies between...TODO Transmit Antennas: **J1** or **J2** @@ -65,11 +65,11 @@ The XCVR2450 uses a common LO for both receive and transmit. Even though the API allows the RX and TX LOs to be individually set, a change of one LO setting will be reflected in the other LO setting. -Transmit Gains: +Transmit Gains: * **VGA**, Range: 0-30dB * **BB**, Range: 0-5dB -Recieve Gains: +Receive Gains: * **LNA**, Range: 0-30.5dB * **VGA**, Range: 0-62dB diff --git a/host/docs/general.rst b/host/docs/general.rst index 6b309cba0..90a880c2e 100644 --- a/host/docs/general.rst +++ b/host/docs/general.rst @@ -45,7 +45,7 @@ The list of discovered devices can be narrowed down by specifying device address Device properties ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Properties of devices attached to your system can be probed with the "uhd_usrp_probe" program. -The usrp probe program contructs an instance of the device and prints out its properties; +The usrp probe program constructs an instance of the device and prints out its properties; properties such as detected daughter-boards, frequency range, gain ranges, etc... **Usage:** diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index aff0d0454..d3ae1dec7 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -11,8 +11,7 @@ Building firmware and FPGA images ^^^^^^^^^^^^^^^^^^ FPGA Image ^^^^^^^^^^^^^^^^^^ -Xilinx ISE 10.1 is required to build the FPGA image for the USRP2 -(newer version of ISE are known to build buggy images). +Xilinx ISE 10.1 and up is required to build the FPGA image for the USRP2. The build requires that you have a unix-like environment with make. Make sure that xtclsh from the Xilinx ISE bin directory is in your $PATH. @@ -149,6 +148,40 @@ MAC addresses, control packets, and fast-path settings. **Monitor the host network traffic:** Use wireshark to monitor packets sent to and received from the USRP2. +------------------------------------------------------------------------ +Addressing the device +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Single device configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +A USRP2 can be identified though its IPv4 address or resolvable hostname. +The USRP2 device is referenced through the "addr" key in the device address. +Use this addressing scheme with the *simple_usrp* interface. + +The device address string representation for a USRP2 with IPv4 address 192.168.10.2 + +:: + + addr=192.168.10.2 + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Soft-MIMO configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In a soft-mimo configuration, each USRP2 must have a unique IPv4 address (per computer) +and be attached to its own dedicated network port. +The value for the addr key is a white-space separated list +of IPv4 addresses or resolvable hostnames. +The first address in the list will represent channel 0, +the second channel 1, and so on... +Use this addressing scheme with the *mimo_usrp* interface. + +The device address string representation for 2 USRP2s with IPv4 addresses 192.168.10.2 and 192.168.20.2 +:: + + addr=192.168.10.2 192.168.20.2 + + ------------------------------------------------------------------------ Resize the send and receive buffers ------------------------------------------------------------------------ @@ -173,6 +206,8 @@ To change the maximum values, run the following commands: sudo sysctl -w net.core.rmem_max= sudo sysctl -w net.core.wmem_max= +Set the values permanently by editing */etc/sysctl.conf* + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Device address params ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit v1.2.3 From 11f2aa1ea0fd6c28a20c6d85f94e41a06b3a6770 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 3 Jul 2010 16:50:45 -0700 Subject: uhd: replaced old send and recv with inline wrappers that take a single buffer and look more like the vectored send/recv --- host/examples/benchmark_rx_rate.cpp | 4 +-- host/examples/rx_timed_samples.cpp | 2 +- host/examples/tx_timed_samples.cpp | 4 +-- host/include/uhd/device.hpp | 53 +++++++++++++++++-------------- host/lib/transport/vrt_packet_handler.hpp | 1 - 5 files changed, 34 insertions(+), 30 deletions(-) (limited to 'host') diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index e7e358e4c..6984d7eff 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -49,7 +49,7 @@ static inline void test_device( sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); do { size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff), md, + &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET ); @@ -79,7 +79,7 @@ static inline void test_device( //flush the buffers while(dev->recv( - boost::asio::buffer(buff), md, + &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET )); diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 3c3c3fdc6..9ff8772bc 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -85,7 +85,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::rx_metadata_t md; std::vector > buff(dev->get_max_recv_samps_per_packet()); size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff), md, + &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET ); diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 846d9b6f4..4226aa4c8 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -81,8 +81,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //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, + &buff.front(), buff.size(), 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; diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index f04a5b4fb..e5ef1181f 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include namespace uhd{ @@ -97,20 +96,6 @@ public: RECV_MODE_ONE_PACKET = 1 }; - //! wrapper call for single buffer recv //TODO put somewhere - size_t send( - const boost::asio::const_buffer &buff, - const tx_metadata_t &metadata, - const io_type_t &io_type, - send_mode_t send_mode - ){ - return send( - std::vector(1, boost::asio::buffer_cast(buff)), - boost::asio::buffer_size(buff)/io_type.size, - metadata, io_type, send_mode - ); - } - /*! * Send buffers containing IF data described by the metadata. * @@ -140,17 +125,20 @@ public: send_mode_t send_mode ) = 0; - //! wrapper call for single buffer recv //TODO put somewhere - size_t recv( - const boost::asio::mutable_buffer &buff, - rx_metadata_t &metadata, + /*! + * Convenience wrapper for send that takes a single buffer. + */ + inline size_t send( + const void *buff, + size_t nsamps_per_buff, + const tx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode + send_mode_t send_mode ){ - return recv( - std::vector(1, boost::asio::buffer_cast(buff)), - boost::asio::buffer_size(buff)/io_type.size, - metadata, io_type, recv_mode + return send( + std::vector(1, buff), + nsamps_per_buff, metadata, + io_type, send_mode ); } @@ -195,6 +183,23 @@ public: recv_mode_t recv_mode ) = 0; + /*! + * Convenience wrapper for recv that takes a single buffer. + */ + inline size_t recv( + void *buff, + size_t nsamps_per_buff, + rx_metadata_t &metadata, + const io_type_t &io_type, + recv_mode_t recv_mode + ){ + return recv( + std::vector(1, buff), + nsamps_per_buff, metadata, + io_type, recv_mode + ); + } + /*! * Get the maximum number of samples per packet on send. * \return the number of samples diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 31b7e6614..42cbb7e5a 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 5e14653f241070791d46893e68e341357e040add Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 4 Jul 2010 19:13:59 -0700 Subject: usrp2: bug fix for readback registers added readback for time64 fixed bug for fragment flag in vrt packet handler --- host/include/uhd/transport/zero_copy.hpp | 8 ++++---- host/include/uhd/usrp/mboard_props.hpp | 2 +- host/lib/transport/vrt_packet_handler.hpp | 18 +++++++++--------- host/lib/usrp/usrp2/fw_common.h | 2 +- host/lib/usrp/usrp2/mboard_impl.cpp | 10 ++++++++++ host/lib/usrp/usrp2/usrp2_regs.hpp | 10 ++++++---- 6 files changed, 31 insertions(+), 19 deletions(-) (limited to 'host') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 2815e3189..da10bfbe2 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -47,7 +47,7 @@ namespace uhd{ namespace transport{ * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void) const{ + inline size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -55,7 +55,7 @@ namespace uhd{ namespace transport{ * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void) const{ + template inline T cast(void) const{ return boost::asio::buffer_cast(this->get()); } @@ -89,7 +89,7 @@ namespace uhd{ namespace transport{ * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void) const{ + inline size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -97,7 +97,7 @@ namespace uhd{ namespace transport{ * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void) const{ + template inline T cast(void) const{ return boost::asio::buffer_cast(this->get()); } diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp index 7ff454472..a432ce50c 100644 --- a/host/include/uhd/usrp/mboard_props.hpp +++ b/host/include/uhd/usrp/mboard_props.hpp @@ -40,7 +40,7 @@ namespace uhd{ namespace usrp{ MBOARD_PROP_TX_DBOARD = 'v', //ro, wax::obj MBOARD_PROP_TX_DBOARD_NAMES = 'V', //ro, prop_names_t MBOARD_PROP_CLOCK_CONFIG = 'C', //rw, clock_config_t - MBOARD_PROP_TIME_NOW = 't', //wo, time_spec_t + MBOARD_PROP_TIME_NOW = 't', //rw, time_spec_t MBOARD_PROP_TIME_NEXT_PPS = 'T', //wo, time_spec_t MBOARD_PROP_STREAM_CMD = 's' //wo, stream_cmd_t }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 42cbb7e5a..177239509 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -151,20 +151,15 @@ 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 = state.size_of_copy_buffs; - size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); - size_t bytes_to_copy = num_samps*bytes_per_item; - - //setup the fragment flags and offset - 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 + size_t nsamps_to_copy = std::min(total_samps, bytes_available/bytes_per_item); + size_t bytes_to_copy = nsamps_to_copy*bytes_per_item; for (size_t i = 0; i < state.width; i++){ //copy-convert the samples from the recv buffer uhd::transport::convert_otw_type_to_io_type( state.copy_buffs[i], otw_type, reinterpret_cast(buffs[i]) + offset_bytes, - io_type, num_samps + io_type, nsamps_to_copy ); //update the rx copy buffer to reflect the bytes copied @@ -173,7 +168,12 @@ namespace vrt_packet_handler{ //update the copy buffer's availability state.size_of_copy_buffs -= bytes_to_copy; - return num_samps; + //setup the fragment flags and offset + metadata.more_fragments = state.size_of_copy_buffs != 0; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += nsamps_to_copy; //set for next call + + return nsamps_to_copy; } /******************************************************************* diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 242d268ec..12daa6286 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -38,7 +38,7 @@ extern "C" { //defines the protocol version in this shared header //increment this value when the protocol is changed -#define USRP2_PROTO_VERSION 4 +#define USRP2_PROTO_VERSION 5 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 28a346be7..36ac6275f 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -72,6 +73,7 @@ usrp2_mboard_impl::usrp2_mboard_impl( ); _iface->poke32(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); + _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); //init the ddc init_ddc_config(); @@ -254,6 +256,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ val = _clock_config; return; + case MBOARD_PROP_TIME_NOW: + val = time_spec_t( + _iface->peek32(U2_REG_TIME64_SECS_RB), + _iface->peek32(U2_REG_TIME64_TICKS_RB), + get_master_clock_freq() + ); + return; + default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 589fa71a3..c859d3603 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -18,8 +18,6 @@ #ifndef INCLUDED_USRP2_REGS_HPP #define INCLUDED_USRP2_REGS_HPP -#include - //////////////////////////////////////////////////// // Settings Bus, Slave #7, Not Byte Addressable! // @@ -46,7 +44,7 @@ #define SR_SIMTIMER 198 #define SR_LAST 255 -#define _SR_ADDR(sr) (MISC_OUTPUT_BASE + (sr) * sizeof(boost::uint32_t)) +#define _SR_ADDR(sr) ((MISC_OUTPUT_BASE) + (4*(sr))) ///////////////////////////////////////////////// // SPI Slave Constants @@ -104,7 +102,11 @@ #define U2_REG_TIME64_SECS _SR_ADDR(SR_TIME64 + 0) // value to set absolute secs to on next PPS #define U2_REG_TIME64_TICKS _SR_ADDR(SR_TIME64 + 1) // value to set absolute ticks to on next PPS #define U2_REG_TIME64_FLAGS _SR_ADDR(SR_TIME64 + 2) // flags - see chart above -#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define U2_REG_TIME64_TPS _SR_ADDR(SR_TIME64 + 4) // the ticks per second rollover count + +#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10) +#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11) //pps flags (see above) #define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -- cgit v1.2.3 From 549a0170a409904f123a4eef975362978ca62bf3 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 4 Jul 2010 20:21:09 -0700 Subject: uhd: added get time now call to simple and mimo usrp --- host/include/uhd/usrp/mimo_usrp.hpp | 6 ++++++ host/include/uhd/usrp/simple_usrp.hpp | 6 ++++++ host/lib/usrp/mimo_usrp.cpp | 10 +++++----- host/lib/usrp/simple_usrp.cpp | 4 ++++ 4 files changed, 21 insertions(+), 5 deletions(-) (limited to 'host') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index a3cbde483..e85c06046 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -70,6 +70,12 @@ public: /******************************************************************* * Misc ******************************************************************/ + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + /*! * Set the time registers on the usrp at the next pps tick. * The values will not be latched in until the pulse occurs. diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 1d817e030..1d9136f08 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -63,6 +63,12 @@ public: /******************************************************************* * Misc ******************************************************************/ + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + /*! * Sets the time registers on the usrp immediately. * \param time_spec the time to latch into the usrp device diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index bd7753d09..440aaf9f6 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -63,11 +63,6 @@ public: BOOST_FOREACH(wax::obj mboard, _mboards){ mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; } - - //set the times to zero at the next pps and sleep - this->set_time_next_pps(time_spec_t(0, 0)); - sleep(1); - } ~mimo_usrp_impl(void){ @@ -115,6 +110,11 @@ public: /******************************************************************* * Misc ******************************************************************/ + time_spec_t get_time_now(void){ + //the time on the first mboard better be the same on all + return _mboards.front()[MBOARD_PROP_TIME_NOW].as(); + } + void set_time_next_pps(const time_spec_t &time_spec){ BOOST_FOREACH(wax::obj mboard, _mboards){ mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index 4a5171cf7..56e82d7ee 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -86,6 +86,10 @@ public: /******************************************************************* * Misc ******************************************************************/ + time_spec_t get_time_now(void){ + return _mboard[MBOARD_PROP_TIME_NOW].as(); + } + void set_time_now(const time_spec_t &time_spec){ _mboard[MBOARD_PROP_TIME_NOW] = time_spec; } -- cgit v1.2.3 From 8047f25c601c43d6941cd0d094360a56917917c8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 12:02:21 -0700 Subject: uhd: added clear capability to alignment buffer (fixes case when next seq is less than prev) --- host/include/uhd/transport/alignment_buffer.hpp | 22 +++++++++++++++++++++- host/include/uhd/transport/bounded_buffer.hpp | 10 ++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'host') diff --git a/host/include/uhd/transport/alignment_buffer.hpp b/host/include/uhd/transport/alignment_buffer.hpp index dc6ccc3ed..5766c2284 100644 --- a/host/include/uhd/transport/alignment_buffer.hpp +++ b/host/include/uhd/transport/alignment_buffer.hpp @@ -56,6 +56,11 @@ namespace uhd{ namespace transport{ const seq_type &seq, size_t index ){ + //clear the buffer for this index if the seqs are mis-ordered + if (seq < _last_seqs[index]){ + _buffs[index]->clear(); + _there_was_a_clear = true; + } _last_seqs[index] = seq; return _buffs[index]->push_with_pop_on_full(buff_contents_type(elem, seq)); } @@ -79,6 +84,18 @@ namespace uhd{ namespace transport{ //get an aligned set of elements from the buffers: while(indexes_to_do.size() != 0){ + + //respond to a clear by starting from scratch + if(_there_was_a_clear){ + _there_was_a_clear = false; + indexes_to_do = _all_indexes; + index = indexes_to_do.front(); + if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; + elems[index] = buff_contents_tmp.first; + expected_seq_id = buff_contents_tmp.second; + indexes_to_do.pop_front(); + } + //pop an element off for this index index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; @@ -118,14 +135,17 @@ namespace uhd{ namespace transport{ typedef bounded_buffer bounded_buffer_type; typedef boost::shared_ptr bounded_buffer_sptr; std::vector _buffs; + std::vector _last_seqs; std::list _all_indexes; + bool _there_was_a_clear; //private constructor - alignment_buffer(size_t capacity, size_t width){ + alignment_buffer(size_t capacity, size_t width) : _last_seqs(width){ for (size_t i = 0; i < width; i++){ _buffs.push_back(bounded_buffer_type::make(capacity)); _all_indexes.push_back(i); } + _there_was_a_clear = false; } }; diff --git a/host/include/uhd/transport/bounded_buffer.hpp b/host/include/uhd/transport/bounded_buffer.hpp index baecd6382..94c360fba 100644 --- a/host/include/uhd/transport/bounded_buffer.hpp +++ b/host/include/uhd/transport/bounded_buffer.hpp @@ -129,6 +129,16 @@ namespace uhd{ namespace transport{ return true; } + /*! + * Clear all elements from the bounded_buffer. + */ + UHD_INLINE void clear(void){ + boost::unique_lock lock(_mutex); + while (not_empty()) _buffer.pop_back(); + lock.unlock(); + _full_cond.notify_one(); + } + private: boost::mutex _mutex; boost::condition _empty_cond, _full_cond; -- cgit v1.2.3 From c2039a8c92561fa5532d87cb9d875a3ad7b875c1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 16:35:44 -0700 Subject: uhd: code tweaks, extra error condition for vrt unpack --- host/lib/transport/gen_vrt_if_packet.py | 7 +++++-- host/lib/transport/udp_zero_copy_asio.cpp | 2 +- host/lib/transport/vrt_packet_handler.hpp | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'host') diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py index 536409b2e..7910ff60d 100755 --- a/host/lib/transport/gen_vrt_if_packet.py +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -150,10 +150,10 @@ void vrt::if_hdr_unpack_$(suffix)( if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0 or if_packet_info.num_packet_words32 < packet_words32) + if (if_packet_info.num_packet_words32 < packet_words32) throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) - throw std::runtime_error("unsupported vrt packet type"); + throw std::runtime_error("bad vrt header or unsupported packet type"); boost::uint8_t pred = 0; if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); @@ -209,6 +209,9 @@ void vrt::if_hdr_unpack_$(suffix)( #set $num_trailer_words = 0; #end if ########## Variables ########## + //another failure case + if (packet_words32 < $($num_header_words + $num_trailer_words)) + throw std::runtime_error("bad vrt header or invalid packet length"); if_packet_info.num_header_words32 = $num_header_words; if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); break; diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 7f9292d24..a91be25af 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -28,7 +28,7 @@ using namespace uhd::transport; * Constants **********************************************************************/ //enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); +static const size_t MIN_SOCK_BUFF_SIZE(sizeof(boost::uint32_t) * 25e6 * 0.5); static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; //100 ms diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 177239509..68edeb1e1 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -87,7 +87,7 @@ namespace vrt_packet_handler{ uhd::transport::vrt::if_packet_info_t if_packet_info; for (size_t i = 0; i < state.width; i++){ const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast() + vrt_header_offset_words32; - if_packet_info.num_packet_words32 = num_packet_words32; + if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32; vrt_unpacker(vrt_hdr, if_packet_info); //handle the packet count / sequence number @@ -163,7 +163,7 @@ namespace vrt_packet_handler{ ); //update the rx copy buffer to reflect the bytes copied - state.copy_buffs[i] = reinterpret_cast(state.copy_buffs[i]) + bytes_to_copy; + state.copy_buffs[i] += bytes_to_copy; } //update the copy buffer's availability state.size_of_copy_buffs -= bytes_to_copy; -- cgit v1.2.3 From a95eaac42f6cc85fd2ad3f32dc29eeab38ef5194 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 19:12:01 -0700 Subject: usrp2: Added a peek64 to read pairs of 32 bit numbers such as time64 also added a templated host to/from network conversion in byteswap.hpp (didnt use it though) --- firmware/microblaze/apps/txrx_uhd.c | 8 ++++++++ host/include/uhd/utils/byteswap.hpp | 27 +++++++++++++++++++++++++++ host/lib/usrp/usrp2/fw_common.h | 4 +++- host/lib/usrp/usrp2/mboard_impl.cpp | 14 ++++++++------ host/lib/usrp/usrp2/usrp2_iface.cpp | 24 +++++++++++++++++++----- host/lib/usrp/usrp2/usrp2_iface.hpp | 10 ++++++++++ 6 files changed, 75 insertions(+), 12 deletions(-) (limited to 'host') diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 21803b199..99c149d45 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -269,6 +269,10 @@ void handle_udp_ctrl_packet( printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr); } else switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint64_t): + *((uint32_t *) ctrl_data_in->data.poke_args.addrhi) = (uint32_t)ctrl_data_in->data.poke_args.datahi; + //continue to uint32_t for low addr: + case sizeof(uint32_t): *((uint32_t *) ctrl_data_in->data.poke_args.addr) = (uint32_t)ctrl_data_in->data.poke_args.data; break; @@ -287,6 +291,10 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint64_t): + ctrl_data_out.data.poke_args.datahi = *((uint32_t *) ctrl_data_in->data.poke_args.addrhi); + //continue to uint32_t for low addr: + case sizeof(uint32_t): ctrl_data_out.data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); break; diff --git a/host/include/uhd/utils/byteswap.hpp b/host/include/uhd/utils/byteswap.hpp index dd5dcbc09..26d60c2ab 100644 --- a/host/include/uhd/utils/byteswap.hpp +++ b/host/include/uhd/utils/byteswap.hpp @@ -37,6 +37,12 @@ namespace uhd{ //! perform a byteswap on a 64 bit integer boost::uint64_t byteswap(boost::uint64_t); + //! network to host: short, long, or long-long + template T ntohx(T); + + //! host to network: short, long, or long-long + template T htonx(T); + } //namespace uhd /*********************************************************************** @@ -117,4 +123,25 @@ namespace uhd{ #endif +/*********************************************************************** + * Define the templated network to/from host conversions + **********************************************************************/ +#include + +template UHD_INLINE T uhd::ntohx(T num){ + #ifdef BOOST_BIG_ENDIAN + return num; + #else + return uhd::byteswap(num); + #endif +} + +template UHD_INLINE T uhd::htonx(T num){ + #ifdef BOOST_BIG_ENDIAN + return num; + #else + return uhd::byteswap(num); + #endif +} + #endif /* INCLUDED_UHD_UTILS_BYTESWAP_HPP */ diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 12daa6286..4c66aa41e 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -111,7 +111,9 @@ typedef struct{ struct { _SINS_ uint32_t addr; _SINS_ uint32_t data; - _SINS_ uint8_t num_bytes; //1, 2, 4 + _SINS_ uint32_t addrhi; + _SINS_ uint32_t datahi; + _SINS_ uint8_t num_bytes; //1, 2, 4, 8 } poke_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 36ac6275f..952954286 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -256,12 +256,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ val = _clock_config; return; - case MBOARD_PROP_TIME_NOW: - val = time_spec_t( - _iface->peek32(U2_REG_TIME64_SECS_RB), - _iface->peek32(U2_REG_TIME64_TICKS_RB), - get_master_clock_freq() - ); + case MBOARD_PROP_TIME_NOW:{ + usrp2_iface::pair64 time64( + _iface->peek64(U2_REG_TIME64_SECS_RB, U2_REG_TIME64_TICKS_RB) + ); + val = time_spec_t( + time64.first, time64.second, get_master_clock_freq() + ); + } return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 66a1a57f6..faf4a5c7e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -59,6 +59,20 @@ public: return this->peek(addr); } + pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO); + out_data.data.poke_args.addr = htonl(addrlo); + out_data.data.poke_args.addrhi = htonl(addrhi); + out_data.data.poke_args.num_bytes = sizeof(boost::uint64_t); + + //send and recv + usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); + return pair64(ntohl(in_data.data.poke_args.data), ntohl(in_data.data.poke_args.datahi)); + } + /*********************************************************************** * SPI **********************************************************************/ @@ -86,7 +100,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); return ntohl(in_data.data.spi_args.data); } @@ -109,7 +123,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); } byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ @@ -124,7 +138,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); //copy out the data @@ -187,7 +201,7 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); } template T peek(boost::uint32_t addr){ @@ -199,7 +213,7 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); return T(ntohl(in_data.data.poke_args.data)); } diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 7b2a3a89d..9cc32104e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "fw_common.h" //////////////////////////////////////////////////////////////////////// @@ -49,6 +50,7 @@ class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{ public: typedef boost::shared_ptr sptr; + typedef std::pair pair64; /*! * Make a new usrp2 interface with the control transport. @@ -64,6 +66,14 @@ public: */ virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0; + /*! + * Read a dual register (64 bits) + * \param addrlo the address for the low-32 bits + * \param addrhi the address for the high-32 bits + * \return a pair of 32 bit integers lo, hi + */ + virtual pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi) = 0; + /*! * Write a register (32 bits) * \param addr the address -- cgit v1.2.3 From 4840c5bc95771e8f2485e002da0d81521cb4a16c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 21:17:49 -0700 Subject: uhd: moved header file implementation code into ipp files byteswap, bounded_buffer, and alignment_buffer --- host/include/uhd/transport/CMakeLists.txt | 2 + host/include/uhd/transport/alignment_buffer.hpp | 104 ++---------------- host/include/uhd/transport/alignment_buffer.ipp | 140 ++++++++++++++++++++++++ host/include/uhd/transport/bounded_buffer.hpp | 86 +++------------ host/include/uhd/transport/bounded_buffer.ipp | 112 +++++++++++++++++++ host/include/uhd/utils/CMakeLists.txt | 1 + host/include/uhd/utils/byteswap.hpp | 99 +---------------- host/include/uhd/utils/byteswap.ipp | 120 ++++++++++++++++++++ 8 files changed, 401 insertions(+), 263 deletions(-) create mode 100644 host/include/uhd/transport/alignment_buffer.ipp create mode 100644 host/include/uhd/transport/bounded_buffer.ipp create mode 100644 host/include/uhd/utils/byteswap.ipp (limited to 'host') diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 4e1f7aca5..93e9a6485 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -18,7 +18,9 @@ INSTALL(FILES alignment_buffer.hpp + alignment_buffer.ipp bounded_buffer.hpp + bounded_buffer.ipp convert_types.hpp if_addrs.hpp udp_simple.hpp diff --git a/host/include/uhd/transport/alignment_buffer.hpp b/host/include/uhd/transport/alignment_buffer.hpp index 5766c2284..29ba74efc 100644 --- a/host/include/uhd/transport/alignment_buffer.hpp +++ b/host/include/uhd/transport/alignment_buffer.hpp @@ -19,16 +19,14 @@ #define INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP #include -#include -#include +#include //time_duration_t #include -#include #include namespace uhd{ namespace transport{ /*! - * Imlement a templated alignment buffer: + * Implement a templated alignment buffer: * Used for aligning asynchronously pushed elements with matching ids. */ template class alignment_buffer{ @@ -40,9 +38,7 @@ namespace uhd{ namespace transport{ * \param capacity the maximum elements per index * \param width the number of elements to align */ - static sptr make(size_t capacity, size_t width){ - return sptr(new alignment_buffer(capacity, width)); - } + static sptr make(size_t capacity, size_t width); /*! * Push an element with sequence id into the buffer at index. @@ -51,18 +47,11 @@ namespace uhd{ namespace transport{ * \param index the buffer index * \return true if the element fit without popping for space */ - UHD_INLINE bool push_with_pop_on_full( + virtual bool push_with_pop_on_full( const elem_type &elem, const seq_type &seq, size_t index - ){ - //clear the buffer for this index if the seqs are mis-ordered - if (seq < _last_seqs[index]){ - _buffs[index]->clear(); - _there_was_a_clear = true; - } _last_seqs[index] = seq; - return _buffs[index]->push_with_pop_on_full(buff_contents_type(elem, seq)); - } + ) = 0; /*! * Pop an aligned set of elements from this alignment buffer. @@ -70,85 +59,14 @@ namespace uhd{ namespace transport{ * \param time the timeout time * \return false when the operation times out */ - template - bool pop_elems_with_timed_wait(elems_type &elems, const time_type &time){ - buff_contents_type buff_contents_tmp; - std::list indexes_to_do(_all_indexes); - - //do an initial pop to load an initial sequence id - size_t index = indexes_to_do.front(); - if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; - elems[index] = buff_contents_tmp.first; - seq_type expected_seq_id = buff_contents_tmp.second; - indexes_to_do.pop_front(); - - //get an aligned set of elements from the buffers: - while(indexes_to_do.size() != 0){ - - //respond to a clear by starting from scratch - if(_there_was_a_clear){ - _there_was_a_clear = false; - indexes_to_do = _all_indexes; - index = indexes_to_do.front(); - if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; - elems[index] = buff_contents_tmp.first; - expected_seq_id = buff_contents_tmp.second; - indexes_to_do.pop_front(); - } - - //pop an element off for this index - index = indexes_to_do.front(); - if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; - - //if the sequence id matches: - // store the popped element into the output, - // remove this index from the list and continue - if (buff_contents_tmp.second == expected_seq_id){ - elems[index] = buff_contents_tmp.first; - indexes_to_do.pop_front(); - continue; - } - - //if the sequence id is older: - // continue with the same index to try again - if (buff_contents_tmp.second < expected_seq_id){ - continue; - } - - //if the sequence id is newer: - // store the popped element into the output, - // add all other indexes back into the list - if (buff_contents_tmp.second > expected_seq_id){ - elems[index] = buff_contents_tmp.first; - expected_seq_id = buff_contents_tmp.second; - indexes_to_do = _all_indexes; - indexes_to_do.remove(index); - continue; - } - } - return true; - } - - private: - //a vector of bounded buffers for each index - typedef std::pair buff_contents_type; - typedef bounded_buffer bounded_buffer_type; - typedef boost::shared_ptr bounded_buffer_sptr; - std::vector _buffs; - std::vector _last_seqs; - std::list _all_indexes; - bool _there_was_a_clear; - - //private constructor - alignment_buffer(size_t capacity, size_t width) : _last_seqs(width){ - for (size_t i = 0; i < width; i++){ - _buffs.push_back(bounded_buffer_type::make(capacity)); - _all_indexes.push_back(i); - } - _there_was_a_clear = false; - } + virtual bool pop_elems_with_timed_wait( + std::vector &elems, + const time_duration_t &time + ) = 0; }; }} //namespace +#include + #endif /* INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP */ diff --git a/host/include/uhd/transport/alignment_buffer.ipp b/host/include/uhd/transport/alignment_buffer.ipp new file mode 100644 index 000000000..f89f2886e --- /dev/null +++ b/host/include/uhd/transport/alignment_buffer.ipp @@ -0,0 +1,140 @@ +// +// 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_UHD_TRANSPORT_ALIGNMENT_BUFFER_IPP +#define INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_IPP + +#include +#include +#include + +namespace uhd{ namespace transport{ namespace{ /*anon*/ + + /*! + * Imlement a templated alignment buffer: + * Used for aligning asynchronously pushed elements with matching ids. + */ + template + class alignment_buffer_impl : public alignment_buffer{ + public: + + alignment_buffer_impl(size_t capacity, size_t width) : _last_seqs(width){ + for (size_t i = 0; i < width; i++){ + _buffs.push_back(bounded_buffer::make(capacity)); + _all_indexes.push_back(i); + } + _there_was_a_clear = false; + } + + UHD_INLINE bool push_with_pop_on_full( + const elem_type &elem, + const seq_type &seq, + size_t index + ){ + //clear the buffer for this index if the seqs are mis-ordered + if (seq < _last_seqs[index]){ + _buffs[index]->clear(); + _there_was_a_clear = true; + } _last_seqs[index] = seq; + return _buffs[index]->push_with_pop_on_full(buff_contents_type(elem, seq)); + } + + UHD_INLINE bool pop_elems_with_timed_wait( + std::vector &elems, + const time_duration_t &time + ){ + buff_contents_type buff_contents_tmp; + std::list indexes_to_do(_all_indexes); + + //do an initial pop to load an initial sequence id + size_t index = indexes_to_do.front(); + if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; + elems[index] = buff_contents_tmp.first; + seq_type expected_seq_id = buff_contents_tmp.second; + indexes_to_do.pop_front(); + + //get an aligned set of elements from the buffers: + while(indexes_to_do.size() != 0){ + + //respond to a clear by starting from scratch + if(_there_was_a_clear){ + _there_was_a_clear = false; + indexes_to_do = _all_indexes; + index = indexes_to_do.front(); + if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; + elems[index] = buff_contents_tmp.first; + expected_seq_id = buff_contents_tmp.second; + indexes_to_do.pop_front(); + } + + //pop an element off for this index + index = indexes_to_do.front(); + if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; + + //if the sequence id matches: + // store the popped element into the output, + // remove this index from the list and continue + if (buff_contents_tmp.second == expected_seq_id){ + elems[index] = buff_contents_tmp.first; + indexes_to_do.pop_front(); + continue; + } + + //if the sequence id is older: + // continue with the same index to try again + if (buff_contents_tmp.second < expected_seq_id){ + continue; + } + + //if the sequence id is newer: + // store the popped element into the output, + // add all other indexes back into the list + if (buff_contents_tmp.second > expected_seq_id){ + elems[index] = buff_contents_tmp.first; + expected_seq_id = buff_contents_tmp.second; + indexes_to_do = _all_indexes; + indexes_to_do.remove(index); + continue; + } + } + return true; + } + + private: + //a vector of bounded buffers for each index + typedef std::pair buff_contents_type; + std::vector::sptr> _buffs; + std::vector _last_seqs; + std::list _all_indexes; + bool _there_was_a_clear; + }; + +}}} //namespace + +namespace uhd{ namespace transport{ + + template + typename alignment_buffer::sptr + alignment_buffer::make(size_t capacity, size_t width){ + return alignment_buffer::sptr( + new alignment_buffer_impl(capacity, width) + ); + } + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_IPP */ diff --git a/host/include/uhd/transport/bounded_buffer.hpp b/host/include/uhd/transport/bounded_buffer.hpp index 94c360fba..d1deece96 100644 --- a/host/include/uhd/transport/bounded_buffer.hpp +++ b/host/include/uhd/transport/bounded_buffer.hpp @@ -19,15 +19,16 @@ #define INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP #include -#include #include -#include -#include +#include namespace uhd{ namespace transport{ + //! typedef for the time duration type for wait operations + typedef boost::posix_time::time_duration time_duration_t; + /*! - * Imlement a templated bounded buffer: + * Implement a templated bounded buffer: * Used for passing elements between threads in a producer-consumer model. * The bounded buffer implemented waits and timed waits with condition variables. * The pop operation blocks on the bounded_buffer to become non empty. @@ -41,9 +42,7 @@ namespace uhd{ namespace transport{ * Make a new bounded buffer object. * \param capacity the bounded_buffer capacity */ - static sptr make(size_t capacity){ - return sptr(new bounded_buffer(capacity)); - } + static sptr make(size_t capacity); /*! * Push a new element into the bounded buffer. @@ -52,35 +51,14 @@ namespace uhd{ namespace transport{ * \param elem the new element to push * \return true if the element fit without popping for space */ - UHD_INLINE bool push_with_pop_on_full(const elem_type &elem){ - boost::unique_lock lock(_mutex); - if(_buffer.full()){ - _buffer.pop_back(); - _buffer.push_front(elem); - lock.unlock(); - _empty_cond.notify_one(); - return false; - } - else{ - _buffer.push_front(elem); - lock.unlock(); - _empty_cond.notify_one(); - return true; - } - } + virtual bool push_with_pop_on_full(const elem_type &elem) = 0; /*! * Push a new element into the bounded_buffer. * Wait until the bounded_buffer becomes non-full. * \param elem the new element to push */ - UHD_INLINE void push_with_wait(const elem_type &elem){ - boost::unique_lock lock(_mutex); - _full_cond.wait(lock, boost::bind(&bounded_buffer::not_full, this)); - _buffer.push_front(elem); - lock.unlock(); - _empty_cond.notify_one(); - } + virtual void push_with_wait(const elem_type &elem) = 0; /*! * Push a new element into the bounded_buffer. @@ -89,28 +67,14 @@ namespace uhd{ namespace transport{ * \param time the timeout time * \return false when the operation times out */ - template UHD_INLINE - bool push_with_timed_wait(const elem_type &elem, const time_type &time){ - boost::unique_lock lock(_mutex); - if (not _full_cond.timed_wait(lock, time, boost::bind(&bounded_buffer::not_full, this))) return false; - _buffer.push_front(elem); - lock.unlock(); - _empty_cond.notify_one(); - return true; - } + virtual bool push_with_timed_wait(const elem_type &elem, const time_duration_t &time) = 0; /*! * Pop an element from the bounded_buffer. * Wait until the bounded_buffer becomes non-empty. * \param elem the element reference pop to */ - UHD_INLINE void pop_with_wait(elem_type &elem){ - boost::unique_lock lock(_mutex); - _empty_cond.wait(lock, boost::bind(&bounded_buffer::not_empty, this)); - elem = _buffer.back(); _buffer.pop_back(); - lock.unlock(); - _full_cond.notify_one(); - } + virtual void pop_with_wait(elem_type &elem) = 0; /*! * Pop an element from the bounded_buffer. @@ -119,38 +83,16 @@ namespace uhd{ namespace transport{ * \param time the timeout time * \return false when the operation times out */ - template UHD_INLINE - bool pop_with_timed_wait(elem_type &elem, const time_type &time){ - boost::unique_lock lock(_mutex); - if (not _empty_cond.timed_wait(lock, time, boost::bind(&bounded_buffer::not_empty, this))) return false; - elem = _buffer.back(); _buffer.pop_back(); - lock.unlock(); - _full_cond.notify_one(); - return true; - } + virtual bool pop_with_timed_wait(elem_type &elem, const time_duration_t &time) = 0; /*! * Clear all elements from the bounded_buffer. */ - UHD_INLINE void clear(void){ - boost::unique_lock lock(_mutex); - while (not_empty()) _buffer.pop_back(); - lock.unlock(); - _full_cond.notify_one(); - } - - private: - boost::mutex _mutex; - boost::condition _empty_cond, _full_cond; - boost::circular_buffer _buffer; - - bool not_full(void) const{return not _buffer.full();} - bool not_empty(void) const{return not _buffer.empty();} - - //private constructor - bounded_buffer(size_t capacity) : _buffer(capacity){} + virtual void clear(void) = 0; }; }} //namespace +#include + #endif /* INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP */ diff --git a/host/include/uhd/transport/bounded_buffer.ipp b/host/include/uhd/transport/bounded_buffer.ipp new file mode 100644 index 000000000..6885b357d --- /dev/null +++ b/host/include/uhd/transport/bounded_buffer.ipp @@ -0,0 +1,112 @@ +// +// 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_UHD_TRANSPORT_BOUNDED_BUFFER_IPP +#define INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_IPP + +#include +#include +#include + +namespace uhd{ namespace transport{ namespace{ /*anon*/ + + template + class bounded_buffer_impl : public bounded_buffer{ + public: + + bounded_buffer_impl(size_t capacity) : _buffer(capacity){ + /* NOP */ + } + + UHD_INLINE bool push_with_pop_on_full(const elem_type &elem){ + boost::unique_lock lock(_mutex); + if(_buffer.full()){ + _buffer.pop_back(); + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + return false; + } + else{ + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + return true; + } + } + + UHD_INLINE void push_with_wait(const elem_type &elem){ + boost::unique_lock lock(_mutex); + _full_cond.wait(lock, boost::bind(&bounded_buffer_impl::not_full, this)); + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + } + + bool push_with_timed_wait(const elem_type &elem, const time_duration_t &time){ + boost::unique_lock lock(_mutex); + if (not _full_cond.timed_wait(lock, time, boost::bind(&bounded_buffer_impl::not_full, this))) return false; + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + return true; + } + + UHD_INLINE void pop_with_wait(elem_type &elem){ + boost::unique_lock lock(_mutex); + _empty_cond.wait(lock, boost::bind(&bounded_buffer_impl::not_empty, this)); + elem = _buffer.back(); _buffer.pop_back(); + lock.unlock(); + _full_cond.notify_one(); + } + + bool pop_with_timed_wait(elem_type &elem, const time_duration_t &time){ + boost::unique_lock lock(_mutex); + if (not _empty_cond.timed_wait(lock, time, boost::bind(&bounded_buffer_impl::not_empty, this))) return false; + elem = _buffer.back(); _buffer.pop_back(); + lock.unlock(); + _full_cond.notify_one(); + return true; + } + + UHD_INLINE void clear(void){ + boost::unique_lock lock(_mutex); + while (not_empty()) _buffer.pop_back(); + lock.unlock(); + _full_cond.notify_one(); + } + + private: + boost::mutex _mutex; + boost::condition _empty_cond, _full_cond; + boost::circular_buffer _buffer; + + bool not_full(void) const{return not _buffer.full();} + bool not_empty(void) const{return not _buffer.empty();} + }; +}}} //namespace + +namespace uhd{ namespace transport{ + + template typename bounded_buffer::sptr + bounded_buffer::make(size_t capacity){ + return bounded_buffer::sptr(new bounded_buffer_impl(capacity)); + } + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_IPP */ diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index c98eec639..36f86054a 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -19,6 +19,7 @@ INSTALL(FILES algorithm.hpp assert.hpp byteswap.hpp + byteswap.ipp exception.hpp gain_handler.hpp pimpl.hpp diff --git a/host/include/uhd/utils/byteswap.hpp b/host/include/uhd/utils/byteswap.hpp index 26d60c2ab..9a1871210 100644 --- a/host/include/uhd/utils/byteswap.hpp +++ b/host/include/uhd/utils/byteswap.hpp @@ -45,103 +45,6 @@ namespace uhd{ } //namespace uhd -/*********************************************************************** - * Platform-specific implementation details for byteswap below: - **********************************************************************/ -#ifdef BOOST_MSVC //http://msdn.microsoft.com/en-us/library/a3140177%28VS.80%29.aspx - #include - - UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ - return _byteswap_ushort(x); - } - - UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ - return _byteswap_ulong(x); - } - - UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ - return _byteswap_uint64(x); - } - -#elif defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 - - UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ - return (x>>8) | (x<<8); //DNE return __builtin_bswap16(x); - } - - UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ - return __builtin_bswap32(x); - } - - UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ - return __builtin_bswap64(x); - } - -#elif defined(__FreeBSD__) || defined(__MACOSX__) || defined(__APPLE__) - #include - - UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ - return OSSwapInt16(x); - } - - UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ - return OSSwapInt32(x); - } - - UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ - return OSSwapInt64(x); - } - -#elif defined(linux) || defined(__linux) - #include - - UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ - return bswap_16(x); - } - - UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ - return bswap_32(x); - } - - UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ - return bswap_64(x); - } - -#else //http://www.koders.com/c/fidB93B34CD44F0ECF724F1A4EAE3854BA2FE692F59.aspx - - UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ - return (x>>8) | (x<<8); - } - - UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ - return (boost::uint32_t(uhd::byteswap(boost::uint16_t(x&0xfffful)))<<16) | (uhd::byteswap(boost::uint16_t(x>>16))); - } - - UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ - return (boost::uint64_t(uhd::byteswap(boost::uint32_t(x&0xffffffffull)))<<32) | (uhd::byteswap(boost::uint32_t(x>>32))); - } - -#endif - -/*********************************************************************** - * Define the templated network to/from host conversions - **********************************************************************/ -#include - -template UHD_INLINE T uhd::ntohx(T num){ - #ifdef BOOST_BIG_ENDIAN - return num; - #else - return uhd::byteswap(num); - #endif -} - -template UHD_INLINE T uhd::htonx(T num){ - #ifdef BOOST_BIG_ENDIAN - return num; - #else - return uhd::byteswap(num); - #endif -} +#include #endif /* INCLUDED_UHD_UTILS_BYTESWAP_HPP */ diff --git a/host/include/uhd/utils/byteswap.ipp b/host/include/uhd/utils/byteswap.ipp new file mode 100644 index 000000000..11c82a4ec --- /dev/null +++ b/host/include/uhd/utils/byteswap.ipp @@ -0,0 +1,120 @@ +// +// 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_UHD_UTILS_BYTESWAP_IPP +#define INCLUDED_UHD_UTILS_BYTESWAP_IPP + +/*********************************************************************** + * Platform-specific implementation details for byteswap below: + **********************************************************************/ +#ifdef BOOST_MSVC //http://msdn.microsoft.com/en-us/library/a3140177%28VS.80%29.aspx + #include + + UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ + return _byteswap_ushort(x); + } + + UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ + return _byteswap_ulong(x); + } + + UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ + return _byteswap_uint64(x); + } + +#elif defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 + + UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ + return (x>>8) | (x<<8); //DNE return __builtin_bswap16(x); + } + + UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ + return __builtin_bswap32(x); + } + + UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ + return __builtin_bswap64(x); + } + +#elif defined(__FreeBSD__) || defined(__MACOSX__) || defined(__APPLE__) + #include + + UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ + return OSSwapInt16(x); + } + + UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ + return OSSwapInt32(x); + } + + UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ + return OSSwapInt64(x); + } + +#elif defined(linux) || defined(__linux) + #include + + UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ + return bswap_16(x); + } + + UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ + return bswap_32(x); + } + + UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ + return bswap_64(x); + } + +#else //http://www.koders.com/c/fidB93B34CD44F0ECF724F1A4EAE3854BA2FE692F59.aspx + + UHD_INLINE boost::uint16_t uhd::byteswap(boost::uint16_t x){ + return (x>>8) | (x<<8); + } + + UHD_INLINE boost::uint32_t uhd::byteswap(boost::uint32_t x){ + return (boost::uint32_t(uhd::byteswap(boost::uint16_t(x&0xfffful)))<<16) | (uhd::byteswap(boost::uint16_t(x>>16))); + } + + UHD_INLINE boost::uint64_t uhd::byteswap(boost::uint64_t x){ + return (boost::uint64_t(uhd::byteswap(boost::uint32_t(x&0xffffffffull)))<<32) | (uhd::byteswap(boost::uint32_t(x>>32))); + } + +#endif + +/*********************************************************************** + * Define the templated network to/from host conversions + **********************************************************************/ +#include + +template UHD_INLINE T uhd::ntohx(T num){ + #ifdef BOOST_BIG_ENDIAN + return num; + #else + return uhd::byteswap(num); + #endif +} + +template UHD_INLINE T uhd::htonx(T num){ + #ifdef BOOST_BIG_ENDIAN + return num; + #else + return uhd::byteswap(num); + #endif +} + +#endif /* INCLUDED_UHD_UTILS_BYTESWAP_IPP */ -- cgit v1.2.3 From 189c4c96fc0b40aa98c28f6bd4b95753bdaec970 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 5 Jul 2010 21:51:48 -0700 Subject: uhd: remove windows warnings (minor tweaks) --- host/lib/transport/udp_zero_copy_asio.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'host') diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index a91be25af..7f9292d24 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -28,7 +28,7 @@ using namespace uhd::transport; * Constants **********************************************************************/ //enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_SOCK_BUFF_SIZE(sizeof(boost::uint32_t) * 25e6 * 0.5); +static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; //100 ms diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 07e29eadd..42630a3e4 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -114,7 +114,7 @@ private: static const size_t _max_tx_bytes_per_packet = USRP2_UDP_BYTES - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(uhd::transport::vrt::if_packet_info_t::cid) //no class id ever used + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used ; }; -- cgit v1.2.3 From 1ca30a49030da2ef248048e17a46738bb3823c4c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 15:44:15 -0700 Subject: uhd: added set time w/ unknown pps to mimo usrp, get tx rate bug fix --- host/include/uhd/usrp/mimo_usrp.hpp | 18 ++++++++++++++++++ host/lib/usrp/mimo_usrp.cpp | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'host') diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index e85c06046..68a42cad8 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -90,6 +90,24 @@ public: */ virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + /*! + * Synchronize the times across all motherboards in this configuration. + * Use this method to sync the times when the edge of the PPS is unknown. + * + * Ex: Host machine is not attached to serial port of GPSDO + * and can therefore not query the GPSDO for the PPS edge. + * + * This is a 3-step process, and will take at most 3 seconds to complete. + * Upon completion, the times will be synchronized to the time provided. + * + * - Step1: set the time at the next pps (potential race condition) + * - Step2: wait for the seconds to rollover to catch the pps edge + * - Step3: set the time at the next pps (synchronous for all boards) + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_unknown_pps(const time_spec_t &time_spec) = 0; + /*! * Issue a stream command to the usrp device. * This tells the usrp to send samples into the host. diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 440aaf9f6..f5441e19d 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -121,6 +122,22 @@ public: } } + void set_time_unknown_pps(const time_spec_t &time_spec){ + std::cout << "Set time with unknown pps edge:" << std::endl; + std::cout << " 1) set times next pps (race condition)" << std::endl; + set_time_next_pps(time_spec); sleep(1); + + std::cout << " 2) catch seconds rollover at pps edge" << std::endl; + time_t last_secs = 0, curr_secs = 0; + while(curr_secs == last_secs){ + last_secs = curr_secs; + curr_secs = get_time_now().get_full_secs(); + } + + std::cout << " 3) set times next pps (synchronously)" << std::endl; + set_time_next_pps(time_spec); sleep(1); + } + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ BOOST_FOREACH(wax::obj mboard, _mboards){ mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd; @@ -206,7 +223,7 @@ public: } double get_tx_rate_all(void){ - return _rx_rate; + return _tx_rate; } tune_result_t set_tx_freq(size_t chan, double target_freq){ -- cgit v1.2.3 From e771e157f6d210fe2e66294c60581c5953006ba1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 16:15:49 -0700 Subject: uhd: added back into old send/recv but with deprecation attributes, moved inline device stuff into device.ipp --- host/include/uhd/CMakeLists.txt | 1 + host/include/uhd/config.hpp | 11 +++++- host/include/uhd/device.hpp | 35 +++++++++--------- host/include/uhd/device.ipp | 79 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 host/include/uhd/device.ipp (limited to 'host') diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index d63062032..c0339dbd3 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -24,6 +24,7 @@ ADD_SUBDIRECTORY(utils) INSTALL(FILES config.hpp device.hpp + device.ipp wax.hpp DESTINATION ${INCLUDE_DIR}/uhd ) diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index b23a4dc00..013354d33 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -78,7 +78,7 @@ #endif // UHD_DLL // Define force inline macro -#ifdef BOOST_MSVC +#if defined(BOOST_MSVC) #define UHD_INLINE __forceinline #elif defined(__GNUG__) && __GNUG__ >= 4 #define UHD_INLINE inline __attribute__((always_inline)) @@ -86,4 +86,13 @@ #define UHD_INLINE inline #endif +// Define deprecated attribute macro +#if defined(BOOST_MSVC) + #define UHD_DEPRECATED __declspec(deprecated) +#elif defined(__GNUG__) && __GNUG__ >= 4 + #define UHD_DEPRECATED __attribute__ ((deprecated)) +#else + #define UHD_DEPRECATED +#endif + #endif /* INCLUDED_UHD_CONFIG_HPP */ diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index e5ef1181f..a0c29f2e6 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace uhd{ @@ -128,19 +129,19 @@ public: /*! * Convenience wrapper for send that takes a single buffer. */ - inline size_t send( + size_t send( const void *buff, size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode - ){ - return send( - std::vector(1, buff), - nsamps_per_buff, metadata, - io_type, send_mode - ); - } + ); + + //! Deprecated + size_t send( + const boost::asio::const_buffer &, const tx_metadata_t &, + const io_type_t &, send_mode_t send_mode + ); /*! * Receive buffers containing IF data described by the metadata. @@ -186,19 +187,19 @@ public: /*! * Convenience wrapper for recv that takes a single buffer. */ - inline size_t recv( + size_t recv( void *buff, size_t nsamps_per_buff, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode - ){ - return recv( - std::vector(1, buff), - nsamps_per_buff, metadata, - io_type, recv_mode - ); - } + ); + + //! Deprecated + size_t recv( + const boost::asio::mutable_buffer &, rx_metadata_t &, + const io_type_t &, recv_mode_t + ); /*! * Get the maximum number of samples per packet on send. @@ -216,4 +217,6 @@ public: } //namespace uhd +#include + #endif /* INCLUDED_UHD_DEVICE_HPP */ diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp new file mode 100644 index 000000000..c38a2e43e --- /dev/null +++ b/host/include/uhd/device.ipp @@ -0,0 +1,79 @@ +// +// 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_UHD_DEVICE_IPP +#define INCLUDED_UHD_DEVICE_IPP + +namespace uhd{ + + UHD_INLINE size_t device::send( + const void *buff, + size_t nsamps_per_buff, + const tx_metadata_t &metadata, + const io_type_t &io_type, + send_mode_t send_mode + ){ + return this->send( + std::vector(1, buff), + nsamps_per_buff, metadata, + io_type, send_mode + ); + } + + UHD_DEPRECATED UHD_INLINE size_t device::send( + const boost::asio::const_buffer &buff, + const tx_metadata_t &metadata, + const io_type_t &io_type, + send_mode_t send_mode + ){ + return this->send( + boost::asio::buffer_cast(buff), + boost::asio::buffer_size(buff)/io_type.size, + metadata, io_type, send_mode + ); + } + + UHD_INLINE size_t device::recv( + void *buff, + size_t nsamps_per_buff, + rx_metadata_t &metadata, + const io_type_t &io_type, + recv_mode_t recv_mode + ){ + return this->recv( + std::vector(1, buff), + nsamps_per_buff, metadata, + io_type, recv_mode + ); + } + + UHD_DEPRECATED UHD_INLINE size_t device::recv( + const boost::asio::mutable_buffer &buff, + rx_metadata_t &metadata, + const io_type_t &io_type, + recv_mode_t recv_mode + ){ + return this->recv( + boost::asio::buffer_cast(buff), + boost::asio::buffer_size(buff)/io_type.size, + metadata, io_type, recv_mode + ); + } + +} //namespace uhd + +#endif /* INCLUDED_UHD_DEVICE_IPP */ -- cgit v1.2.3 From 7f3c4791f7d19d02b7d4515c763b9c2044e96170 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 16:55:59 -0700 Subject: uhd: mimo usrp replace sleep with boost thread sleep (windows fix) --- host/lib/usrp/mimo_usrp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'host') diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index f5441e19d..fd8225074 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -125,7 +126,8 @@ public: void set_time_unknown_pps(const time_spec_t &time_spec){ std::cout << "Set time with unknown pps edge:" << std::endl; std::cout << " 1) set times next pps (race condition)" << std::endl; - set_time_next_pps(time_spec); sleep(1); + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); std::cout << " 2) catch seconds rollover at pps edge" << std::endl; time_t last_secs = 0, curr_secs = 0; @@ -135,7 +137,8 @@ public: } std::cout << " 3) set times next pps (synchronously)" << std::endl; - set_time_next_pps(time_spec); sleep(1); + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); } void issue_stream_cmd(const stream_cmd_t &stream_cmd){ -- cgit v1.2.3 From cfdc9e7776acd1f2c8100ac3593482753c0dbca5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 17:59:11 -0700 Subject: uhd: removed some errors and warnings under macosx gcc build --- host/examples/benchmark_rx_rate.cpp | 4 +++- host/include/uhd/transport/alignment_buffer.ipp | 2 +- host/include/uhd/transport/bounded_buffer.ipp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'host') diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 6984d7eff..a913261eb 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -82,7 +82,9 @@ static inline void test_device( &buff.front(), buff.size(), md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET - )); + )){ + /* NOP */ + }; //print a summary std::cout << std::endl; //go to newline, recv may spew SXSYSZ... diff --git a/host/include/uhd/transport/alignment_buffer.ipp b/host/include/uhd/transport/alignment_buffer.ipp index f89f2886e..ed7cfd26c 100644 --- a/host/include/uhd/transport/alignment_buffer.ipp +++ b/host/include/uhd/transport/alignment_buffer.ipp @@ -130,7 +130,7 @@ namespace uhd{ namespace transport{ template typename alignment_buffer::sptr alignment_buffer::make(size_t capacity, size_t width){ - return alignment_buffer::sptr( + return typename alignment_buffer::sptr( new alignment_buffer_impl(capacity, width) ); } diff --git a/host/include/uhd/transport/bounded_buffer.ipp b/host/include/uhd/transport/bounded_buffer.ipp index 6885b357d..e106e229e 100644 --- a/host/include/uhd/transport/bounded_buffer.ipp +++ b/host/include/uhd/transport/bounded_buffer.ipp @@ -104,7 +104,7 @@ namespace uhd{ namespace transport{ template typename bounded_buffer::sptr bounded_buffer::make(size_t capacity){ - return bounded_buffer::sptr(new bounded_buffer_impl(capacity)); + return typename bounded_buffer::sptr(new bounded_buffer_impl(capacity)); } }} //namespace -- cgit v1.2.3 From 5c2cccfe8c4a9c6c912a4d18dc1e7a6f84c79609 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Jul 2010 18:06:15 -0700 Subject: uhd: renamed prefix on usrp burn eeprom utility --- host/utils/CMakeLists.txt | 26 ++++++++--- host/utils/uhd_burn_db_eeprom.cpp | 93 -------------------------------------- host/utils/usrp_burn_db_eeprom.cpp | 93 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 99 deletions(-) delete mode 100644 host/utils/uhd_burn_db_eeprom.cpp create mode 100644 host/utils/usrp_burn_db_eeprom.cpp (limited to 'host') diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 8d260c06c..c349a9018 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -15,21 +15,35 @@ # along with this program. If not, see . # +######################################################################## +# Utilities that get installed into the runtime path +######################################################################## ADD_EXECUTABLE(uhd_find_devices uhd_find_devices.cpp) TARGET_LINK_LIBRARIES(uhd_find_devices uhd) -INSTALL(TARGETS uhd_find_devices RUNTIME DESTINATION ${RUNTIME_DIR}) ADD_EXECUTABLE(uhd_usrp_probe uhd_usrp_probe.cpp) TARGET_LINK_LIBRARIES(uhd_usrp_probe uhd) -INSTALL(TARGETS uhd_usrp_probe RUNTIME DESTINATION ${RUNTIME_DIR}) +INSTALL(TARGETS + uhd_find_devices + uhd_usrp_probe + RUNTIME DESTINATION ${RUNTIME_DIR} +) + +######################################################################## +# Utilities that get installed into the share path +######################################################################## ADD_EXECUTABLE(usrp2_addr_burner usrp2_addr_burner.cpp) TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd) -INSTALL(TARGETS usrp2_addr_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) -ADD_EXECUTABLE(uhd_burn_db_eeprom uhd_burn_db_eeprom.cpp) -TARGET_LINK_LIBRARIES(uhd_burn_db_eeprom uhd) -INSTALL(TARGETS uhd_burn_db_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) +ADD_EXECUTABLE(usrp_burn_db_eeprom usrp_burn_db_eeprom.cpp) +TARGET_LINK_LIBRARIES(usrp_burn_db_eeprom uhd) + +INSTALL(TARGETS + usrp2_addr_burner + usrp_burn_db_eeprom + RUNTIME DESTINATION ${PKG_DATA_DIR}/utils +) INSTALL(PROGRAMS usrp2_recovery.py diff --git a/host/utils/uhd_burn_db_eeprom.cpp b/host/utils/uhd_burn_db_eeprom.cpp deleted file mode 100644 index ba7aa6cec..000000000 --- a/host/utils/uhd_burn_db_eeprom.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; -namespace po = boost::program_options; - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - //command line variables - std::string args, db_name, unit; - static const uhd::dict unit_to_db_prop = boost::assign::map_list_of - ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) - ; - - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("args", po::value(&args)->default_value(""), "device address args [default = \"\"]") - ("db", po::value(&db_name)->default_value(""), "dboard name [default = \"\"]") - ("unit", po::value(&unit)->default_value(""), "which unit [RX or TX]") - ("id", po::value(), "dboard id to burn, omit for readback") - ; - - 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 Burn DB EEPROM %s") % desc << std::endl; - std::cout << boost::format( - "Omit the id argument to perform readback,\n" - "Or specify a new id to burn into the eeprom.\n" - ) << std::endl; - return ~0; - } - - //check inputs - if (not unit_to_db_prop.has_key(unit)){ - std::cout << "Error: specify RX or TX for unit" << std::endl; - return ~0; - } - - //make the device and extract the dboard w/ property - device::sptr dev = device::make(args); - wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], db_name)]; - std::string prefix = (db_name == "")? unit : (unit + ":" + db_name); - - //read the current dboard id from eeprom - if (vm.count("id") == 0){ - std::cout << boost::format("Getting dbid on %s dboard...") % prefix << std::endl; - dboard_id_t id = dboard[DBOARD_PROP_DBOARD_ID].as(); - std::cout << boost::format(" Current dbid: %s") % id.to_pp_string() << std::endl; - } - - //write a new dboard id to eeprom - else{ - dboard_id_t id = dboard_id_t::from_string(vm["id"].as()); - std::cout << boost::format("Setting dbid on %s dboard...") % prefix << std::endl; - std::cout << boost::format(" New dbid: %s") % id.to_pp_string() << std::endl; - dboard[DBOARD_PROP_DBOARD_ID] = id; - } - - std::cout << " Done" << std::endl << std::endl; - return 0; -} diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp new file mode 100644 index 000000000..db2981e87 --- /dev/null +++ b/host/utils/usrp_burn_db_eeprom.cpp @@ -0,0 +1,93 @@ +// +// 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 +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + //command line variables + std::string args, db_name, unit; + static const uhd::dict unit_to_db_prop = boost::assign::map_list_of + ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) + ; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "device address args [default = \"\"]") + ("db", po::value(&db_name)->default_value(""), "dboard name [default = \"\"]") + ("unit", po::value(&unit)->default_value(""), "which unit [RX or TX]") + ("id", po::value(), "dboard id to burn, omit for readback") + ; + + 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("USRP Burn DB EEPROM %s") % desc << std::endl; + std::cout << boost::format( + "Omit the id argument to perform readback,\n" + "Or specify a new id to burn into the eeprom.\n" + ) << std::endl; + return ~0; + } + + //check inputs + if (not unit_to_db_prop.has_key(unit)){ + std::cout << "Error: specify RX or TX for unit" << std::endl; + return ~0; + } + + //make the device and extract the dboard w/ property + device::sptr dev = device::make(args); + wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], db_name)]; + std::string prefix = (db_name == "")? unit : (unit + ":" + db_name); + + //read the current dboard id from eeprom + if (vm.count("id") == 0){ + std::cout << boost::format("Getting dbid on %s dboard...") % prefix << std::endl; + dboard_id_t id = dboard[DBOARD_PROP_DBOARD_ID].as(); + std::cout << boost::format(" Current dbid: %s") % id.to_pp_string() << std::endl; + } + + //write a new dboard id to eeprom + else{ + dboard_id_t id = dboard_id_t::from_string(vm["id"].as()); + std::cout << boost::format("Setting dbid on %s dboard...") % prefix << std::endl; + std::cout << boost::format(" New dbid: %s") % id.to_pp_string() << std::endl; + dboard[DBOARD_PROP_DBOARD_ID] = id; + } + + std::cout << " Done" << std::endl << std::endl; + return 0; +} -- cgit v1.2.3