aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2012-02-17 18:18:26 -0800
committerJosh Blum <josh@joshknows.com>2012-02-17 18:18:26 -0800
commit3ddbcb6078593c39cb0e4bc8f9769f818a61466f (patch)
tree408e3f6a64e31b7d830b9f884ecebdaf100a5d2d /host
parent1fab7e9d477aa98e489400c25a08358952c69c90 (diff)
parentace4489066d1621a09e70650a00d736f0b03ed8c (diff)
downloaduhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.tar.gz
uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.tar.bz2
uhd-3ddbcb6078593c39cb0e4bc8f9769f818a61466f.zip
Merge branch 'next'
Diffstat (limited to 'host')
-rw-r--r--host/examples/benchmark_rate.cpp15
-rw-r--r--host/examples/test_messages.cpp3
-rw-r--r--host/examples/tx_waveforms.cpp5
-rw-r--r--host/include/uhd/stream.hpp8
-rw-r--r--host/include/uhd/types/metadata.hpp15
-rw-r--r--host/include/uhd/types/time_spec.hpp28
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp10
-rw-r--r--host/lib/convert/CMakeLists.txt4
-rw-r--r--host/lib/convert/convert_common.hpp50
-rw-r--r--host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp150
-rw-r--r--host/lib/convert/convert_fc32_with_sse2.cpp8
-rw-r--r--host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp156
-rw-r--r--host/lib/convert/convert_fc64_with_sse2.cpp8
-rw-r--r--host/lib/convert/convert_orc.orc17
-rw-r--r--host/lib/convert/convert_with_orc.cpp11
-rw-r--r--host/lib/convert/convert_with_tables.cpp100
-rw-r--r--host/lib/convert/gen_convert_general.py18
-rw-r--r--[-rwxr-xr-x]host/lib/transport/gen_vrt_if_packet.py2
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp17
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp12
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp14
-rw-r--r--host/lib/transport/usb_zero_copy_wrapper.cpp106
-rw-r--r--host/lib/types/time_spec.cpp58
-rw-r--r--host/lib/usrp/b100/b100_ctrl.cpp4
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp48
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp12
-rw-r--r--host/lib/usrp/b100/b100_regs.hpp36
-rw-r--r--host/lib/usrp/b100/io_impl.cpp61
-rw-r--r--host/lib/usrp/common/async_packet_handler.hpp71
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp13
-rw-r--r--host/lib/usrp/common/fx2_ctrl.hpp6
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt3
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp60
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.hpp3
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp34
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp62
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.hpp6
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.cpp43
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.hpp36
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp17
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp6
-rw-r--r--host/lib/usrp/e100/e100_regs.hpp32
-rw-r--r--host/lib/usrp/e100/io_impl.cpp46
-rw-r--r--host/lib/usrp/multi_usrp.cpp11
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp12
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.cpp4
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp1
-rw-r--r--host/lib/usrp/usrp2/fw_common.h4
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp44
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp13
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp17
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp12
-rw-r--r--host/tests/convert_test.cpp83
-rw-r--r--host/tests/sph_recv_test.cpp24
-rw-r--r--host/tests/sph_send_test.cpp6
-rw-r--r--host/tests/time_spec_test.cpp6
-rw-r--r--host/usrp_e_utils/usrp-e-loopback.cpp3
59 files changed, 1268 insertions, 394 deletions
diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp
index fce184514..8f00e25de 100644
--- a/host/examples/benchmark_rate.cpp
+++ b/host/examples/benchmark_rate.cpp
@@ -40,11 +40,11 @@ unsigned long long num_seq_errors = 0;
/***********************************************************************
* Benchmark RX Rate
**********************************************************************/
-void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp){
+void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_otw){
uhd::set_thread_priority_safe();
//create a receive streamer
- uhd::stream_args_t stream_args("fc32"); //complex floats
+ uhd::stream_args_t stream_args("fc32", rx_otw); //complex floats
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
//print pre-test summary
@@ -94,11 +94,11 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp){
/***********************************************************************
* Benchmark TX Rate
**********************************************************************/
-void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp){
+void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_otw){
uhd::set_thread_priority_safe();
//create a transmit streamer
- uhd::stream_args_t stream_args("fc32"); //complex floats
+ uhd::stream_args_t stream_args("fc32", tx_otw); //complex floats
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
//print pre-test summary
@@ -162,6 +162,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
double duration;
double rx_rate, tx_rate;
+ std::string rx_otw, tx_otw;
//setup the program options
po::options_description desc("Allowed options");
@@ -171,6 +172,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("duration", po::value<double>(&duration)->default_value(10.0), "duration for the test in seconds")
("rx_rate", po::value<double>(&rx_rate), "specify to perform a RX rate test (sps)")
("tx_rate", po::value<double>(&tx_rate), "specify to perform a TX rate test (sps)")
+ ("rx_otw", po::value<std::string>(&rx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for RX")
+ ("tx_otw", po::value<std::string>(&tx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for TX")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -203,13 +206,13 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//spawn the receive test thread
if (vm.count("rx_rate")){
usrp->set_rx_rate(rx_rate);
- thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp));
+ thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp, rx_otw));
}
//spawn the transmit test thread
if (vm.count("tx_rate")){
usrp->set_tx_rate(tx_rate);
- thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp));
+ thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp, tx_otw));
thread_group.create_thread(boost::bind(&benchmark_tx_rate_async_helper, usrp));
}
diff --git a/host/examples/test_messages.cpp b/host/examples/test_messages.cpp
index f24a172d1..afb092092 100644
--- a/host/examples/test_messages.cpp
+++ b/host/examples/test_messages.cpp
@@ -26,6 +26,7 @@
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <cstdlib>
+#include <ctime>
#include <complex>
#include <iostream>
@@ -326,7 +327,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
}
//run the tests, pick at random
- std::srand(uhd::time_spec_t::get_system_time().get_full_secs());
+ std::srand((unsigned int) time(NULL));
for (size_t n = 0; n < ntests; n++){
std::string key = tests.keys()[std::rand() % tests.size()];
bool pass = tests[key](usrp, rx_stream, tx_stream);
diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp
index 39f70aec6..6a377fdac 100644
--- a/host/examples/tx_waveforms.cpp
+++ b/host/examples/tx_waveforms.cpp
@@ -90,7 +90,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::set_thread_priority_safe();
//variables to be set by po
- std::string args, wave_type, ant, subdev, ref;
+ std::string args, wave_type, ant, subdev, ref, otw;
size_t spb;
double rate, freq, gain, wave_freq, bw;
float ampl;
@@ -111,6 +111,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("wave-type", po::value<std::string>(&wave_type)->default_value("CONST"), "waveform type (CONST, SQUARE, RAMP, SINE)")
("wave-freq", po::value<double>(&wave_freq)->default_value(0), "waveform frequency in Hz")
("ref", po::value<std::string>(&ref)->default_value("internal"), "clock reference (internal, external, mimo)")
+ ("otw", po::value<std::string>(&otw)->default_value("sc16"), "specify the over-the-wire sample mode")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -193,7 +194,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a transmit streamer
//linearly map channels (index0 = channel0, index1 = channel1, ...)
- uhd::stream_args_t stream_args("fc32");
+ uhd::stream_args_t stream_args("fc32", otw);
for (size_t chan = 0; chan < usrp->get_tx_num_channels(); chan++)
stream_args.channels.push_back(chan); //linear mapping
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
diff --git a/host/include/uhd/stream.hpp b/host/include/uhd/stream.hpp
index 352f63e4e..cec2eee79 100644
--- a/host/include/uhd/stream.hpp
+++ b/host/include/uhd/stream.hpp
@@ -79,9 +79,11 @@ struct UHD_API stream_args_t{
* The args parameter is used to pass arbitrary key/value pairs.
* Possible keys used by args (depends on implementation):
*
- * - scalar: an integer scaling factor used with the sc8 wire format.
- * The key/value pair scalar=1024 means that the sample in the DSP
- * was multiplied by 1024 before its upper 8 bits were harvested.
+ * - peak: specifies a fractional sample level to calculate scaling with the sc8 wire format.
+ * When using sc8 samples over the wire, the device must scale samples
+ * (both on the host and in the device) to satisfy the dynamic range needs.
+ * The peak value specifies a fraction of the maximum sample level (1.0 = 100%).
+ * Set peak to max_sample_level/full_scale_level to ensure optimum dynamic range.
*
* - underflow_policy: how the TX DSP should recover from underflow.
* Possible options are "next_burst" or "next_packet".
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 269c77c7c..788999900 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#include <uhd/config.hpp>
#include <uhd/types/time_spec.hpp>
+#include <boost/cstdint.hpp>
namespace uhd{
@@ -140,13 +141,21 @@ namespace uhd{
EVENT_CODE_UNDERFLOW = 0x2,
//! Packet loss between host and device.
EVENT_CODE_SEQ_ERROR = 0x4,
- //! Packet had time that was late (or too early).
+ //! Packet had time that was late.
EVENT_CODE_TIME_ERROR = 0x8,
//! Underflow occurred inside a packet.
EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10,
//! Packet loss within a burst.
- EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20
+ EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20,
+ //! Some kind of custom user payload
+ EVENT_CODE_USER_PAYLOAD = 0x40
} event_code;
+
+ /*!
+ * A special payload populated by custom FPGA fabric.
+ */
+ boost::uint32_t user_payload[4];
+
};
} //namespace uhd
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index 02de20ea1..e7d7d5ab4 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ namespace uhd{
time_spec_t(time_t full_secs, double frac_secs = 0);
/*!
- * Create a time_spec_t from whole and fractional seconds.
+ * Create a time_spec_t from whole seconds and fractional ticks.
* Translation from clock-domain specific units.
* \param full_secs the whole/integer seconds count
* \param tick_count the fractional seconds tick count
@@ -69,6 +69,14 @@ namespace uhd{
time_spec_t(time_t full_secs, long tick_count, double tick_rate);
/*!
+ * Create a time_spec_t from a 64-bit tick count.
+ * Translation from clock-domain specific units.
+ * \param ticks an integer count of ticks
+ * \param tick_rate the number of ticks per second
+ */
+ static time_spec_t from_ticks(long long ticks, double tick_rate);
+
+ /*!
* Convert the fractional seconds to clock ticks.
* Translation into clock-domain specific units.
* \param tick_rate the number of ticks per second
@@ -77,6 +85,14 @@ namespace uhd{
long get_tick_count(double tick_rate) const;
/*!
+ * Convert the time spec into a 64-bit tick count.
+ * Translation into clock-domain specific units.
+ * \param tick_rate the number of ticks per second
+ * \return an integer number of ticks
+ */
+ long long to_ticks(const double tick_rate) const;
+
+ /*!
* 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.
@@ -112,6 +128,14 @@ namespace uhd{
//! Implement less_than_comparable interface
UHD_API bool operator<(const time_spec_t &, const time_spec_t &);
+ UHD_INLINE time_t time_spec_t::get_full_secs(void) const{
+ return this->_full_secs;
+ }
+
+ UHD_INLINE double time_spec_t::get_frac_secs(void) const{
+ return this->_frac_secs;
+ }
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index 49354f1af..88affa40c 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -24,6 +24,7 @@
#define UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
#define UHD_USRP_MULTI_USRP_COMMAND_TIME_API
#define UHD_USRP_MULTI_USRP_BW_RANGE_API
+#define UHD_USRP_MULTI_USRP_USER_REGS_API
#include <uhd/config.hpp>
#include <uhd/device.hpp>
@@ -338,6 +339,15 @@ public:
*/
virtual std::vector<std::string> get_mboard_sensor_names(size_t mboard = 0) = 0;
+ /*!
+ * Perform write on the user configuration register bus. These only exist if
+ * the user has implemented custom setting registers in the device FPGA.
+ * \param addr 8-bit register address
+ * \param data 32-bit register value
+ * \param mboard which motherboard to set the user register
+ */
+ virtual void set_user_register(const boost::uint8_t addr, const boost::uint32_t data, size_t mboard = ALL_MBOARDS) = 0;
+
/*******************************************************************
* RX methods
******************************************************************/
diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt
index 98907dc29..c42a0a434 100644
--- a/host/lib/convert/CMakeLists.txt
+++ b/host/lib/convert/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2012 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -73,6 +73,8 @@ IF(HAVE_EMMINTRIN_H)
SET(convert_with_sse2_sources
${CMAKE_CURRENT_SOURCE_DIR}/convert_fc32_with_sse2.cpp
${CMAKE_CURRENT_SOURCE_DIR}/convert_fc64_with_sse2.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_fc32_to_sc8_with_sse2.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_fc64_to_sc8_with_sse2.cpp
)
SET_SOURCE_FILES_PROPERTIES(
${convert_with_sse2_sources}
diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp
index 699d6301b..55bc2e99d 100644
--- a/host/lib/convert/convert_common.hpp
+++ b/host/lib/convert/convert_common.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -190,4 +190,52 @@ static UHD_INLINE void item32_sc8_to_fc64(item32_t item, fc64_t &out0, fc64_t &o
);
}
+/***********************************************************************
+ * Convert complex char to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t sc8_to_item32_sc8(sc8_t in0, sc8_t in1, double){
+ return
+ (item32_t(boost::uint8_t(in0.real())) << 8) |
+ (item32_t(boost::uint8_t(in0.imag())) << 0) |
+ (item32_t(boost::uint8_t(in1.real())) << 24) |
+ (item32_t(boost::uint8_t(in1.imag())) << 16)
+ ;
+}
+
+/***********************************************************************
+ * Convert complex short to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t sc16_to_item32_sc8(sc16_t in0, sc16_t in1, double){
+ return
+ (item32_t(boost::uint8_t(in0.real())) << 8) |
+ (item32_t(boost::uint8_t(in0.imag())) << 0) |
+ (item32_t(boost::uint8_t(in1.real())) << 24) |
+ (item32_t(boost::uint8_t(in1.imag())) << 16)
+ ;
+}
+
+/***********************************************************************
+ * Convert complex float to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t fc32_to_item32_sc8(fc32_t in0, fc32_t in1, double scale_factor){
+ return
+ (item32_t(boost::uint8_t(in0.real()*float(scale_factor))) << 8) |
+ (item32_t(boost::uint8_t(in0.imag()*float(scale_factor))) << 0) |
+ (item32_t(boost::uint8_t(in1.real()*float(scale_factor))) << 24) |
+ (item32_t(boost::uint8_t(in1.imag()*float(scale_factor))) << 16)
+ ;
+}
+
+/***********************************************************************
+ * Convert complex double to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t fc64_to_item32_sc8(fc64_t in0, fc64_t in1, double scale_factor){
+ return
+ (item32_t(boost::uint8_t(in0.real()*(scale_factor))) << 8) |
+ (item32_t(boost::uint8_t(in0.imag()*(scale_factor))) << 0) |
+ (item32_t(boost::uint8_t(in1.real()*(scale_factor))) << 24) |
+ (item32_t(boost::uint8_t(in1.imag()*(scale_factor))) << 16)
+ ;
+}
+
#endif /* INCLUDED_LIBUHD_CONVERT_COMMON_HPP */
diff --git a/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp b/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp
new file mode 100644
index 000000000..b633f487c
--- /dev/null
+++ b/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp
@@ -0,0 +1,150 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "convert_common.hpp"
+#include <uhd/utils/byteswap.hpp>
+#include <emmintrin.h>
+
+using namespace uhd::convert;
+
+UHD_INLINE __m128i pack_sc32_4x_be(
+ const __m128 &in0, const __m128 &in1,
+ const __m128 &in2, const __m128 &in3,
+ const __m128 &scalar
+){
+ __m128i tmpi0 = _mm_cvtps_epi32(_mm_mul_ps(in0, scalar));
+ tmpi0 = _mm_shuffle_epi32(tmpi0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i tmpi1 = _mm_cvtps_epi32(_mm_mul_ps(in1, scalar));
+ tmpi1 = _mm_shuffle_epi32(tmpi1, _MM_SHUFFLE(1, 0, 3, 2));
+ const __m128i lo = _mm_packs_epi32(tmpi0, tmpi1);
+
+ __m128i tmpi2 = _mm_cvtps_epi32(_mm_mul_ps(in2, scalar));
+ tmpi2 = _mm_shuffle_epi32(tmpi2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i tmpi3 = _mm_cvtps_epi32(_mm_mul_ps(in3, scalar));
+ tmpi3 = _mm_shuffle_epi32(tmpi3, _MM_SHUFFLE(1, 0, 3, 2));
+ const __m128i hi = _mm_packs_epi32(tmpi2, tmpi3);
+
+ return _mm_packs_epi16(lo, hi);
+}
+
+UHD_INLINE __m128i pack_sc32_4x_le(
+ const __m128 &in0, const __m128 &in1,
+ const __m128 &in2, const __m128 &in3,
+ const __m128 &scalar
+){
+ __m128i tmpi0 = _mm_cvtps_epi32(_mm_mul_ps(in0, scalar));
+ tmpi0 = _mm_shuffle_epi32(tmpi0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i tmpi1 = _mm_cvtps_epi32(_mm_mul_ps(in1, scalar));
+ tmpi1 = _mm_shuffle_epi32(tmpi1, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i lo = _mm_packs_epi32(tmpi0, tmpi1);
+
+ __m128i tmpi2 = _mm_cvtps_epi32(_mm_mul_ps(in2, scalar));
+ tmpi2 = _mm_shuffle_epi32(tmpi2, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i tmpi3 = _mm_cvtps_epi32(_mm_mul_ps(in3, scalar));
+ tmpi3 = _mm_shuffle_epi32(tmpi3, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i hi = _mm_packs_epi32(tmpi2, tmpi3);
+
+ return _mm_packs_epi16(lo, hi);
+}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_SIMD){
+ const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128 scalar = _mm_set_ps1(float(scale_factor));
+
+ #define convert_fc32_1_to_sc8_item32_1_bswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128 tmp0 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
+ __m128 tmp1 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
+ __m128 tmp2 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+4)); \
+ __m128 tmp3 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+6)); \
+ \
+ /* convert */ \
+ const __m128i tmpi = pack_sc32_4x_be(tmp0, tmp1, tmp2, tmp3, scalar); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc32_1_to_sc8_item32_1_bswap_guts(_)
+ }
+ else{
+ convert_fc32_1_to_sc8_item32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc32_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = uhd::byteswap(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc32_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = uhd::byteswap(item);
+ }
+}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_SIMD){
+ const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128 scalar = _mm_set_ps1(float(scale_factor));
+
+ #define convert_fc32_1_to_sc8_item32_1_nswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128 tmp0 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
+ __m128 tmp1 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
+ __m128 tmp2 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+4)); \
+ __m128 tmp3 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+6)); \
+ \
+ /* convert */ \
+ const __m128i tmpi = pack_sc32_4x_le(tmp0, tmp1, tmp2, tmp3, scalar); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc32_1_to_sc8_item32_1_nswap_guts(_)
+ }
+ else{
+ convert_fc32_1_to_sc8_item32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc32_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = (item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc32_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = (item);
+ }
+}
diff --git a/host/lib/convert/convert_fc32_with_sse2.cpp b/host/lib/convert/convert_fc32_with_sse2.cpp
index 24a939d6c..97a3e8cdc 100644
--- a/host/lib/convert/convert_fc32_with_sse2.cpp
+++ b/host/lib/convert/convert_fc32_with_sse2.cpp
@@ -28,7 +28,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
#define convert_fc32_1_to_item32_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128 tmplo = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
__m128 tmphi = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
@@ -71,7 +71,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
#define convert_fc32_1_to_item32_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128 tmplo = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
__m128 tmphi = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
@@ -114,7 +114,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc32_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
@@ -159,7 +159,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc32_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
diff --git a/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp b/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp
new file mode 100644
index 000000000..405850601
--- /dev/null
+++ b/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp
@@ -0,0 +1,156 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "convert_common.hpp"
+#include <uhd/utils/byteswap.hpp>
+#include <emmintrin.h>
+
+using namespace uhd::convert;
+
+UHD_INLINE __m128i pack_sc8_item32_4x(
+ const __m128i &in0, const __m128i &in1,
+ const __m128i &in2, const __m128i &in3
+){
+ const __m128i lo = _mm_packs_epi32(in0, in1);
+ const __m128i hi = _mm_packs_epi32(in2, in3);
+ return _mm_packs_epi16(lo, hi);
+}
+
+UHD_INLINE __m128i pack_sc32_4x_be(
+ const __m128d &lo, const __m128d &hi,
+ const __m128d &scalar
+){
+ const __m128i tmpi_lo = _mm_cvttpd_epi32(_mm_mul_pd(hi, scalar));
+ const __m128i tmpi_hi = _mm_cvttpd_epi32(_mm_mul_pd(lo, scalar));
+ return _mm_unpacklo_epi64(tmpi_lo, tmpi_hi);
+}
+
+UHD_INLINE __m128i pack_sc32_4x_le(
+ const __m128d &lo, const __m128d &hi,
+ const __m128d &scalar
+){
+ const __m128i tmpi_lo = _mm_cvttpd_epi32(_mm_mul_pd(lo, scalar));
+ const __m128i tmpi_hi = _mm_cvttpd_epi32(_mm_mul_pd(hi, scalar));
+ const __m128i tmpi = _mm_unpacklo_epi64(tmpi_lo, tmpi_hi);
+ return _mm_shuffle_epi32(tmpi, _MM_SHUFFLE(2, 3, 0, 1));
+}
+
+DECLARE_CONVERTER(fc64, 1, sc8_item32_be, 1, PRIORITY_SIMD){
+ const fc64_t *input = reinterpret_cast<const fc64_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128d scalar = _mm_set1_pd(scale_factor);
+
+ #define convert_fc64_1_to_sc8_item32_1_bswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
+ __m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
+ __m128d tmp2 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+2)); \
+ __m128d tmp3 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+3)); \
+ __m128d tmp4 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+4)); \
+ __m128d tmp5 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+5)); \
+ __m128d tmp6 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+6)); \
+ __m128d tmp7 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+7)); \
+ \
+ /* interleave */ \
+ const __m128i tmpi = pack_sc8_item32_4x( \
+ pack_sc32_4x_be(tmp0, tmp1, scalar), \
+ pack_sc32_4x_be(tmp2, tmp3, scalar), \
+ pack_sc32_4x_be(tmp4, tmp5, scalar), \
+ pack_sc32_4x_be(tmp6, tmp7, scalar) \
+ ); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc64_1_to_sc8_item32_1_bswap_guts(_)
+ }
+ else{
+ convert_fc64_1_to_sc8_item32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc64_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = uhd::byteswap(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc64_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = uhd::byteswap(item);
+ }
+}
+
+DECLARE_CONVERTER(fc64, 1, sc8_item32_le, 1, PRIORITY_SIMD){
+ const fc64_t *input = reinterpret_cast<const fc64_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128d scalar = _mm_set1_pd(scale_factor);
+
+ #define convert_fc64_1_to_sc8_item32_1_nswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
+ __m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
+ __m128d tmp2 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+2)); \
+ __m128d tmp3 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+3)); \
+ __m128d tmp4 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+4)); \
+ __m128d tmp5 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+5)); \
+ __m128d tmp6 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+6)); \
+ __m128d tmp7 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+7)); \
+ \
+ /* interleave */ \
+ const __m128i tmpi = pack_sc8_item32_4x( \
+ pack_sc32_4x_le(tmp0, tmp1, scalar), \
+ pack_sc32_4x_le(tmp2, tmp3, scalar), \
+ pack_sc32_4x_le(tmp4, tmp5, scalar), \
+ pack_sc32_4x_le(tmp6, tmp7, scalar) \
+ ); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc64_1_to_sc8_item32_1_nswap_guts(_)
+ }
+ else{
+ convert_fc64_1_to_sc8_item32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc64_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = (item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc64_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = (item);
+ }
+}
diff --git a/host/lib/convert/convert_fc64_with_sse2.cpp b/host/lib/convert/convert_fc64_with_sse2.cpp
index 837bb584e..6e097e380 100644
--- a/host/lib/convert/convert_fc64_with_sse2.cpp
+++ b/host/lib/convert/convert_fc64_with_sse2.cpp
@@ -28,7 +28,7 @@ DECLARE_CONVERTER(fc64, 1, sc16_item32_le, 1, PRIORITY_SIMD){
const __m128d scalar = _mm_set1_pd(scale_factor);
#define convert_fc64_1_to_item32_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
__m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
@@ -75,7 +75,7 @@ DECLARE_CONVERTER(fc64, 1, sc16_item32_be, 1, PRIORITY_SIMD){
const __m128d scalar = _mm_set1_pd(scale_factor);
#define convert_fc64_1_to_item32_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
__m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
@@ -122,7 +122,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc64, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc64_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
@@ -171,7 +171,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc64, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc64_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
diff --git a/host/lib/convert/convert_orc.orc b/host/lib/convert/convert_orc.orc
index 5450bf4db..f7075606e 100644
--- a/host/lib/convert/convert_orc.orc
+++ b/host/lib/convert/convert_orc.orc
@@ -61,3 +61,20 @@ x2 swapw dst, tmp
.temp 4 tmp
x2 swapw tmp, src
swapl dst, tmp
+
+.function _convert_swap_byte_pairs_orc
+.source 4 src
+.dest 4 dst
+swapl dst, src
+
+.function _convert_fc32_1_to_sc8_1_nswap_orc
+.source 8 src
+.dest 2 dst
+.temp 8 tmp
+.temp 4 tmp2
+.floatparam 4 scalar
+x2 mulf tmp, src, scalar
+x2 convfl tmp, tmp
+swaplq tmp, tmp
+x2 convlw tmp2, tmp
+x2 convwb dst, tmp2
diff --git a/host/lib/convert/convert_with_orc.cpp b/host/lib/convert/convert_with_orc.cpp
index 0c46bcf1e..e44c8ca73 100644
--- a/host/lib/convert/convert_with_orc.cpp
+++ b/host/lib/convert/convert_with_orc.cpp
@@ -27,6 +27,8 @@ extern void _convert_item32_1_to_fc32_1_nswap_orc(void *, const void *, float, i
extern void _convert_item32_1_to_fc32_1_bswap_orc(void *, const void *, float, int);
extern void _convert_sc16_1_to_item32_1_nswap_orc(void *, const void *, float, int);
extern void _convert_item32_1_to_sc16_1_nswap_orc(void *, const void *, float, int);
+extern void _convert_fc32_1_to_sc8_1_nswap_orc(void *, const void *, float, int);
+extern void _convert_swap_byte_pairs_orc(void *, const void *, int);
}
DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_LIBORC){
@@ -52,3 +54,12 @@ DECLARE_CONVERTER(sc16, 1, sc16_item32_le, 1, PRIORITY_LIBORC){
DECLARE_CONVERTER(sc16_item32_le, 1, sc16, 1, PRIORITY_LIBORC){
_convert_item32_1_to_sc16_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps);
}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_LIBORC){
+ _convert_fc32_1_to_sc8_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps);
+ _convert_swap_byte_pairs_orc(outputs[0], outputs[0], (nsamps + 1)/2);
+}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_LIBORC){
+ _convert_fc32_1_to_sc8_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps);
+}
diff --git a/host/lib/convert/convert_with_tables.cpp b/host/lib/convert/convert_with_tables.cpp
index c45415d5d..4a3ce29b2 100644
--- a/host/lib/convert/convert_with_tables.cpp
+++ b/host/lib/convert/convert_with_tables.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
#include "convert_common.hpp"
#include <uhd/utils/byteswap.hpp>
+#include <boost/math/special_functions/round.hpp>
#include <vector>
using namespace uhd::convert;
@@ -26,6 +27,55 @@ static const size_t sc16_table_len = size_t(1 << 16);
typedef boost::uint16_t (*tohost16_type)(boost::uint16_t);
/***********************************************************************
+ * Implementation for sc16 to sc8 lookup table
+ * - Lookup the real and imaginary parts individually
+ **********************************************************************/
+template <bool swap>
+class convert_sc16_1_to_sc8_item32_1 : public converter{
+public:
+ convert_sc16_1_to_sc8_item32_1(void): _table(sc16_table_len){}
+
+ void set_scalar(const double scalar){
+ for (size_t i = 0; i < sc16_table_len; i++){
+ const boost::int16_t val = boost::uint16_t(i);
+ _table[i] = boost::int8_t(boost::math::iround(val * scalar / 32767.));
+ }
+ }
+
+ void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps){
+ const sc16_t *input = reinterpret_cast<const sc16_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const size_t num_pairs = nsamps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ output[i] = this->lookup(input[j], input[j+1]);
+ }
+
+ if (nsamps != num_pairs*2){
+ output[num_pairs] = this->lookup(input[nsamps-1], 0);;
+ }
+ }
+
+ item32_t lookup(const sc16_t &in0, const sc16_t &in1){
+ if (swap){ //hope this compiles out, its a template constant
+ return
+ (item32_t(_table[size_t(in0.real())]) << 16) |
+ (item32_t(_table[size_t(in0.imag())]) << 24) |
+ (item32_t(_table[size_t(in1.real())]) << 0) |
+ (item32_t(_table[size_t(in1.imag())]) << 8) ;
+ }
+ return
+ (item32_t(_table[size_t(in0.real())]) << 8) |
+ (item32_t(_table[size_t(in0.imag())]) << 0) |
+ (item32_t(_table[size_t(in1.real())]) << 24) |
+ (item32_t(_table[size_t(in1.imag())]) << 16) ;
+ }
+
+private:
+ std::vector<boost::uint8_t> _table;
+};
+
+/***********************************************************************
* Implementation for sc16 lookup table
* - Lookup the real and imaginary parts individually
**********************************************************************/
@@ -67,11 +117,19 @@ class convert_sc8_item32_1_to_fcxx_1 : public converter{
public:
convert_sc8_item32_1_to_fcxx_1(void): _table(sc16_table_len){}
+ //special case for sc16 type, 32767 undoes float normalization
+ static type conv(const boost::int8_t &num, const double scalar){
+ if (sizeof(type) == sizeof(s16_t)){
+ return type(boost::math::iround(num*scalar*32767));
+ }
+ return type(num*scalar);
+ }
+
void set_scalar(const double scalar){
for (size_t i = 0; i < sc16_table_len; i++){
const boost::uint16_t val = tohost(boost::uint16_t(i & 0xffff));
- const type real = type(boost::int8_t(val >> 8)*scalar);
- const type imag = type(boost::int8_t(val >> 0)*scalar);
+ const type real = conv(boost::int8_t(val >> 8), scalar);
+ const type imag = conv(boost::int8_t(val >> 0), scalar);
_table[i] = std::complex<type>(real, imag);
}
}
@@ -112,9 +170,13 @@ private:
#ifdef BOOST_BIG_ENDIAN
# define SHIFT_PAIR0 16, 0
# define SHIFT_PAIR1 0, 16
+# define BE_SWAP false
+# define LE_SWAP true
#else
# define SHIFT_PAIR0 0, 16
# define SHIFT_PAIR1 16, 0
+# define BE_SWAP true
+# define LE_SWAP false
#endif
static converter::sptr make_convert_sc16_item32_be_1_to_fc32_1(void){
@@ -149,6 +211,22 @@ static converter::sptr make_convert_sc8_item32_le_1_to_fc64_1(void){
return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<double, uhd::wtohx, SHIFT_PAIR0>());
}
+static converter::sptr make_convert_sc8_item32_be_1_to_sc16_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<s16_t, uhd::ntohx, SHIFT_PAIR1>());
+}
+
+static converter::sptr make_convert_sc8_item32_le_1_to_sc16_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<s16_t, uhd::wtohx, SHIFT_PAIR0>());
+}
+
+static converter::sptr make_convert_sc16_1_to_sc8_item32_be_1(void){
+ return converter::sptr(new convert_sc16_1_to_sc8_item32_1<BE_SWAP>());
+}
+
+static converter::sptr make_convert_sc16_1_to_sc8_item32_le_1(void){
+ return converter::sptr(new convert_sc16_1_to_sc8_item32_1<LE_SWAP>());
+}
+
UHD_STATIC_BLOCK(register_convert_sc16_item32_1_to_fcxx_1){
uhd::convert::id_type id;
id.num_inputs = 1;
@@ -185,4 +263,20 @@ UHD_STATIC_BLOCK(register_convert_sc16_item32_1_to_fcxx_1){
id.output_format = "fc64";
id.input_format = "sc8_item32_le";
uhd::convert::register_converter(id, &make_convert_sc8_item32_le_1_to_fc64_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_be_1_to_sc16_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_le_1_to_sc16_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc16_1_to_sc8_item32_be_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc16_1_to_sc8_item32_le_1, PRIORITY_TABLE);
}
diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py
index 46a0c8185..364c4bd1a 100644
--- a/host/lib/convert/gen_convert_general.py
+++ b/host/lib/convert/gen_convert_general.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2012 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -92,6 +92,22 @@ DECLARE_CONVERTER(sc8_item32_$(end), 1, $(cpu_type), 1, PRIORITY_GENERAL){
item32_sc8_to_$(cpu_type)(item_n, output[num_samps-1], dummy, scale_factor);
}
}
+
+DECLARE_CONVERTER($(cpu_type), 1, sc8_item32_$(end), 1, PRIORITY_GENERAL){
+ const $(cpu_type)_t *input = reinterpret_cast<const $(cpu_type)_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const size_t num_pairs = nsamps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ const item32_t item = $(cpu_type)_to_item32_sc8(input[j], input[j+1], scale_factor);
+ output[i] = $(to_wire)(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = $(cpu_type)_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = $(to_wire)(item);
+ }
+}
"""
TMPL_CONV_USRP1_COMPLEX = """
diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py
index 245a7ddbd..e28ce3aae 100755..100644
--- a/host/lib/transport/gen_vrt_if_packet.py
+++ b/host/lib/transport/gen_vrt_if_packet.py
@@ -137,7 +137,7 @@ void vrt::if_hdr_pack_$(suffix)(
#if $pred & $tlr_p
{
const size_t empty_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t) - if_packet_info.num_payload_bytes;
- if_packet_info.tlr |= (0x3 << 22) | (occ_table[empty_bytes & 0x3] << 10);
+ if_packet_info.tlr = (0x3 << 22) | (occ_table[empty_bytes & 0x3] << 10);
}
packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr);
#set $flags |= (0x1 << 26);
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 28d6cdd5b..3e67264cd 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -80,13 +80,14 @@ UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, b
**********************************************************************/
class libusb_zero_copy_mrb : public managed_recv_buffer{
public:
- libusb_zero_copy_mrb(libusb_transfer *lut):
+ libusb_zero_copy_mrb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false) { /* NOP */ }
+ _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
void release(void){
if (_expired) return;
completed = false;
+ _lut->length = _frame_size; //always reset length
UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
_expired = true;
}
@@ -109,6 +110,7 @@ private:
libusb_context *_ctx;
libusb_transfer *_lut;
bool _expired;
+ const size_t _frame_size;
};
/***********************************************************************
@@ -118,9 +120,9 @@ private:
**********************************************************************/
class libusb_zero_copy_msb : public managed_send_buffer{
public:
- libusb_zero_copy_msb(libusb_transfer *lut):
+ libusb_zero_copy_msb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false) { /* NOP */ }
+ _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
void commit(size_t len){
if (_expired) return;
@@ -144,11 +146,12 @@ public:
private:
void *get_buff(void) const{return _lut->buffer;}
- size_t get_size(void) const{return _lut->length;}
+ size_t get_size(void) const{return _frame_size;}
libusb_context *_ctx;
libusb_transfer *_lut;
bool _expired;
+ const size_t _frame_size;
};
/***********************************************************************
@@ -184,7 +187,7 @@ public:
libusb_transfer *lut = libusb_alloc_transfer(0);
UHD_ASSERT_THROW(lut != NULL);
- _mrb_pool.push_back(boost::shared_ptr<libusb_zero_copy_mrb>(new libusb_zero_copy_mrb(lut)));
+ _mrb_pool.push_back(boost::shared_ptr<libusb_zero_copy_mrb>(new libusb_zero_copy_mrb(lut, this->get_recv_frame_size())));
libusb_fill_bulk_transfer(
lut, // transfer
@@ -207,7 +210,7 @@ public:
libusb_transfer *lut = libusb_alloc_transfer(0);
UHD_ASSERT_THROW(lut != NULL);
- _msb_pool.push_back(boost::shared_ptr<libusb_zero_copy_msb>(new libusb_zero_copy_msb(lut)));
+ _msb_pool.push_back(boost::shared_ptr<libusb_zero_copy_msb>(new libusb_zero_copy_msb(lut, this->get_send_frame_size())));
libusb_fill_bulk_transfer(
lut, // transfer
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index a5876c8bf..74fbe82fb 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -283,7 +283,7 @@ private:
info.ifpi.num_packet_words32 = num_packet_words32 - _header_offset_words32;
info.vrt_hdr = buff->cast<const boost::uint32_t *>() + _header_offset_words32;
_vrt_unpacker(info.vrt_hdr, info.ifpi);
- info.time = time_spec_t(time_t(info.ifpi.tsi), size_t(info.ifpi.tsf), _tick_rate); //assumes has_tsi and has_tsf are true
+ info.time = time_spec_t::from_ticks(info.ifpi.tsf, _tick_rate); //assumes has_tsf is true
info.copy_buff = reinterpret_cast<const char *>(info.vrt_hdr + info.ifpi.num_header_words32);
//--------------------------------------------------------------
@@ -408,7 +408,7 @@ private:
case PACKET_INLINE_MESSAGE:
std::swap(curr_info, next_info); //save progress from curr -> next
- curr_info.metadata.has_time_spec = next_info[index].ifpi.has_tsi and next_info[index].ifpi.has_tsf;
+ curr_info.metadata.has_time_spec = next_info[index].ifpi.has_tsf;
curr_info.metadata.time_spec = next_info[index].time;
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -436,7 +436,7 @@ private:
alignment_check(index, curr_info);
std::swap(curr_info, next_info); //save progress from curr -> next
curr_info.metadata.has_time_spec = prev_info.metadata.has_time_spec;
- curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t(0,
+ curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t::from_ticks(
prev_info[index].ifpi.num_payload_words32*sizeof(boost::uint32_t)/_bytes_per_otw_item, _samp_rate);
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -469,7 +469,7 @@ private:
}
//set the metadata from the buffer information at index zero
- curr_info.metadata.has_time_spec = curr_info[0].ifpi.has_tsi and curr_info[0].ifpi.has_tsf;
+ curr_info.metadata.has_time_spec = curr_info[0].ifpi.has_tsf;
curr_info.metadata.time_spec = curr_info[0].time;
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -508,7 +508,7 @@ private:
metadata = info.metadata;
//interpolate the time spec (useful when this is a fragment)
- metadata.time_spec += time_spec_t(0, info.fragment_offset_in_samps, _samp_rate);
+ metadata.time_spec += time_spec_t::from_ticks(info.fragment_offset_in_samps, _samp_rate);
//extract the number of samples available to copy
const size_t nsamps_available = info.data_bytes_to_copy/_bytes_per_otw_item;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 5ed8e0143..3d68507ed 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -134,11 +134,10 @@ public:
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.has_tsi = metadata.has_time_spec;
+ if_packet_info.has_tlr = true;
+ if_packet_info.has_tsi = false;
if_packet_info.has_tsf = metadata.has_time_spec;
- 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_packet_info.tsf = metadata.time_spec.to_ticks(_tick_rate);
if_packet_info.sob = metadata.start_of_burst;
if_packet_info.eob = metadata.end_of_burst;
@@ -174,9 +173,8 @@ public:
if (num_samps_sent == 0) return total_num_samps_sent;
//setup metadata for the next fragment
- const time_spec_t time_spec = metadata.time_spec + time_spec_t(0, total_num_samps_sent, _samp_rate);
- if_packet_info.tsi = boost::uint32_t(time_spec.get_full_secs());
- if_packet_info.tsf = boost::uint64_t(time_spec.get_tick_count(_tick_rate));
+ const time_spec_t time_spec = metadata.time_spec + time_spec_t::from_ticks(total_num_samps_sent, _samp_rate);
+ if_packet_info.tsf = time_spec.to_ticks(_tick_rate);
if_packet_info.sob = false;
}
diff --git a/host/lib/transport/usb_zero_copy_wrapper.cpp b/host/lib/transport/usb_zero_copy_wrapper.cpp
index 227c4b392..690e5aaa2 100644
--- a/host/lib/transport/usb_zero_copy_wrapper.cpp
+++ b/host/lib/transport/usb_zero_copy_wrapper.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,17 +18,13 @@
#include <uhd/transport/usb_zero_copy.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/buffer_pool.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/msg.hpp>
#include <boost/foreach.hpp>
#include <vector>
#include <iostream>
using namespace uhd::transport;
-bool debug = true;
-
-static inline size_t next_boundary(size_t length, size_t boundary){
- //pad to the boundary, assumes boundary is a power of 2
- return (length + (boundary-1)) & ~(boundary-1);
-}
/***********************************************************************
* USB zero copy wrapper - managed receive buffer
@@ -45,7 +41,7 @@ public:
_mrb.reset();
}
- sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){
+ UHD_INLINE sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){
_mrb = mrb;
_mem = mem;
_len = len;
@@ -67,28 +63,46 @@ private:
**********************************************************************/
class usb_zero_copy_wrapper_msb : public managed_send_buffer{
public:
- usb_zero_copy_wrapper_msb(bounded_buffer<usb_zero_copy_wrapper_msb *> &queue, size_t boundary):
- _queue(queue), _boundary(boundary){/*NOP*/}
+ usb_zero_copy_wrapper_msb(const usb_zero_copy::sptr internal, const size_t fragmentation_size):
+ _internal(internal), _fragmentation_size(fragmentation_size){/*NOP*/}
void commit(size_t len){
- if (_msb.get() == NULL) return;
- _msb->commit(next_boundary(len, _boundary));
- _queue.push_with_haste(this);
- _msb.reset();
+ if (len == 0) return;
+
+ //get a reference to the VITA header before incrementing
+ const boost::uint32_t vita_header = reinterpret_cast<const boost::uint32_t *>(_mem_buffer_tip)[0];
+
+ _bytes_in_buffer += len;
+ _mem_buffer_tip += len;
+
+ //extract VITA end of packet flag, we must force flush under eof conditions
+ const bool eop = (uhd::wtohx(vita_header) & (0x1 << 24)) != 0;
+ const bool full = _bytes_in_buffer >= (_last_send_buff->size() - _fragmentation_size);
+ if (eop or full){
+ _last_send_buff->commit(_bytes_in_buffer);
+ _last_send_buff.reset();
+ }
}
- sptr get_new(managed_send_buffer::sptr msb){
- _msb = msb;
+ UHD_INLINE sptr get_new(const double timeout){
+ if (not _last_send_buff){
+ _last_send_buff = _internal->get_send_buff(timeout);
+ if (not _last_send_buff) return sptr();
+ _mem_buffer_tip = _last_send_buff->cast<char *>();
+ _bytes_in_buffer = 0;
+ }
return make_managed_buffer(this);
}
private:
- void *get_buff(void) const{return _msb->cast<void *>();}
- size_t get_size(void) const{return _msb->size();}
-
- bounded_buffer<usb_zero_copy_wrapper_msb *> &_queue;
- size_t _boundary;
- managed_send_buffer::sptr _msb;
+ void *get_buff(void) const{return reinterpret_cast<void *>(_mem_buffer_tip);}
+ size_t get_size(void) const{return _fragmentation_size;}
+
+ usb_zero_copy::sptr _internal;
+ const size_t _fragmentation_size;
+ managed_send_buffer::sptr _last_send_buff;
+ size_t _bytes_in_buffer;
+ char *_mem_buffer_tip;
};
/***********************************************************************
@@ -96,23 +110,16 @@ private:
**********************************************************************/
class usb_zero_copy_wrapper : public usb_zero_copy{
public:
- usb_zero_copy_wrapper(
- sptr usb_zc, size_t usb_frame_boundary
- ):
+ usb_zero_copy_wrapper(sptr usb_zc, const size_t frame_boundary):
_internal_zc(usb_zc),
- _usb_frame_boundary(usb_frame_boundary),
+ _frame_boundary(frame_boundary),
_available_recv_buffs(this->get_num_recv_frames()),
- _available_send_buffs(this->get_num_send_frames()),
_mrb_pool(this->get_num_recv_frames(), usb_zero_copy_wrapper_mrb(_available_recv_buffs)),
- _msb_pool(this->get_num_send_frames(), usb_zero_copy_wrapper_msb(_available_send_buffs, usb_frame_boundary))
+ _the_only_msb(usb_zero_copy_wrapper_msb(usb_zc, frame_boundary))
{
BOOST_FOREACH(usb_zero_copy_wrapper_mrb &mrb, _mrb_pool){
_available_recv_buffs.push_with_haste(&mrb);
}
-
- BOOST_FOREACH(usb_zero_copy_wrapper_msb &msb, _msb_pool){
- _available_send_buffs.push_with_haste(&msb);
- }
}
managed_recv_buffer::sptr get_recv_buff(double timeout){
@@ -128,18 +135,17 @@ public:
//extract this packet's memory address and length in bytes
const char *mem = _last_recv_buff->cast<const char *>() + _last_recv_offset;
const boost::uint32_t *mem32 = reinterpret_cast<const boost::uint32_t *>(mem);
- size_t len = (mem32[0] & 0xffff)*sizeof(boost::uint32_t); //length in bytes (from VRT header)
-
+ const size_t len = (uhd::wtohx(mem32[0]) & 0xffff)*sizeof(boost::uint32_t); //length in bytes (from VRT header)
+
managed_recv_buffer::sptr recv_buff; //the buffer to be returned to the user
-
recv_buff = wmrb->get_new(_last_recv_buff, mem, len);
- _last_recv_offset = next_boundary(_last_recv_offset + len, _usb_frame_boundary);
-
+ _last_recv_offset += len;
+
//check if this receive buffer has been exhausted
if (_last_recv_offset >= _last_recv_buff->size()) {
_last_recv_buff.reset();
}
-
+
return recv_buff;
}
@@ -152,20 +158,11 @@ public:
}
size_t get_recv_frame_size(void) const{
- return _internal_zc->get_recv_frame_size();
+ return std::min(_frame_boundary, _internal_zc->get_recv_frame_size());
}
managed_send_buffer::sptr get_send_buff(double timeout){
- managed_send_buffer::sptr send_buff = _internal_zc->get_send_buff(timeout);
-
- //attempt to get a wrapper for a managed send buffer
- usb_zero_copy_wrapper_msb *wmsb = NULL;
- if (send_buff.get() and _available_send_buffs.pop_with_haste(wmsb)){
- return wmsb->get_new(send_buff);
- }
-
- //otherwise return a null sptr for failure
- return managed_send_buffer::sptr();
+ return _the_only_msb.get_new(timeout);
}
size_t get_num_send_frames(void) const{
@@ -173,20 +170,19 @@ public:
}
size_t get_send_frame_size(void) const{
- return _internal_zc->get_send_frame_size();
+ return std::min(_frame_boundary, _internal_zc->get_send_frame_size());
}
private:
sptr _internal_zc;
- size_t _usb_frame_boundary;
+ size_t _frame_boundary;
bounded_buffer<usb_zero_copy_wrapper_mrb *> _available_recv_buffs;
- bounded_buffer<usb_zero_copy_wrapper_msb *> _available_send_buffs;
std::vector<usb_zero_copy_wrapper_mrb> _mrb_pool;
- std::vector<usb_zero_copy_wrapper_msb> _msb_pool;
-
+ usb_zero_copy_wrapper_msb _the_only_msb;
+
//buffer to store partially-received VRT packets in
buffer_pool::sptr _fragment_mem;
-
+
//state for last recv buffer to create multiple managed buffers
managed_recv_buffer::sptr _last_recv_buff;
size_t _last_recv_offset;
diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp
index 8e540c14c..14b9c988a 100644
--- a/host/lib/types/time_spec.cpp
+++ b/host/lib/types/time_spec.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
//
#include <uhd/types/time_spec.hpp>
+#include <inttypes.h> //imaxdiv, intmax_t
using namespace uhd;
@@ -23,18 +24,6 @@ using namespace uhd;
* Time spec system time
**********************************************************************/
-/*!
- * Creates a time spec from system counts:
- * TODO make part of API as a static factory function
- * The counts type is 64 bits and will overflow the ticks type of long.
- * Therefore, divmod the counts into seconds + sub-second counts first.
- */
-#include <inttypes.h> //imaxdiv, intmax_t
-static UHD_INLINE time_spec_t time_spec_t_from_counts(intmax_t counts, intmax_t freq){
- imaxdiv_t divres = imaxdiv(counts, freq);
- return time_spec_t(time_t(divres.quot), double(divres.rem)/freq);
-}
-
#ifdef HAVE_CLOCK_GETTIME
#include <time.h>
time_spec_t time_spec_t::get_system_time(void){
@@ -49,7 +38,7 @@ time_spec_t time_spec_t::get_system_time(void){
time_spec_t time_spec_t::get_system_time(void){
mach_timebase_info_data_t info; mach_timebase_info(&info);
intmax_t nanosecs = mach_absolute_time()*info.numer/info.denom;
- return time_spec_t_from_counts(nanosecs, intmax_t(1e9));
+ return time_spec_t::from_ticks(nanosecs, 1e9);
}
#endif /* HAVE_MACH_ABSOLUTE_TIME */
@@ -60,7 +49,7 @@ time_spec_t time_spec_t::get_system_time(void){
LARGE_INTEGER counts, freq;
QueryPerformanceCounter(&counts);
QueryPerformanceFrequency(&freq);
- return time_spec_t_from_counts(counts.QuadPart, freq.QuadPart);
+ return time_spec_t::from_ticks(counts.QuadPart, freq.QuadPart);
}
#endif /* HAVE_QUERY_PERFORMANCE_COUNTER */
@@ -83,14 +72,21 @@ time_spec_t time_spec_t::get_system_time(void){
* Time spec constructors
**********************************************************************/
#define time_spec_init(full, frac) { \
- _full_secs = full + time_t(frac); \
- _frac_secs = frac - time_t(frac); \
+ const time_t _full = time_t(full); \
+ const double _frac = double(frac); \
+ const int _frac_int = int(_frac); \
+ _full_secs = _full + _frac_int; \
+ _frac_secs = _frac - _frac_int; \
if (_frac_secs < 0) {\
_full_secs -= 1; \
_frac_secs += 1; \
} \
}
+UHD_INLINE long long fast_llround(const double x){
+ return (long long)(x + 0.5); // assumption of non-negativity
+}
+
time_spec_t::time_spec_t(double secs){
time_spec_init(0, secs);
}
@@ -104,23 +100,25 @@ time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate){
time_spec_init(full_secs, frac_secs);
}
+time_spec_t time_spec_t::from_ticks(long long ticks, double tick_rate){
+ const imaxdiv_t divres = imaxdiv(ticks, fast_llround(tick_rate));
+ return time_spec_t(time_t(divres.quot), double(divres.rem)/tick_rate);
+}
+
/***********************************************************************
* Time spec accessors
**********************************************************************/
long time_spec_t::get_tick_count(double tick_rate) const{
- return long(this->get_frac_secs()*tick_rate + 0.5);
-}
-
-double time_spec_t::get_real_secs(void) const{
- return this->_full_secs + this->_frac_secs;
+ return long(fast_llround(this->get_frac_secs()*tick_rate));
}
-time_t time_spec_t::get_full_secs(void) const{
- return this->_full_secs;
+long long time_spec_t::to_ticks(double tick_rate) const{
+ return fast_llround(this->get_frac_secs()*tick_rate) + \
+ (this->get_full_secs() * fast_llround(tick_rate));
}
-double time_spec_t::get_frac_secs(void) const{
- return this->_frac_secs;
+double time_spec_t::get_real_secs(void) const{
+ return this->get_full_secs() + this->get_frac_secs();
}
/***********************************************************************
@@ -128,16 +126,16 @@ double time_spec_t::get_frac_secs(void) const{
**********************************************************************/
time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){
time_spec_init(
- this->_full_secs + rhs.get_full_secs(),
- this->_frac_secs + rhs.get_frac_secs()
+ this->get_full_secs() + rhs.get_full_secs(),
+ this->get_frac_secs() + rhs.get_frac_secs()
);
return *this;
}
time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){
time_spec_init(
- this->_full_secs - rhs.get_full_secs(),
- this->_frac_secs - rhs.get_frac_secs()
+ this->get_full_secs() - rhs.get_full_secs(),
+ this->get_frac_secs() - rhs.get_frac_secs()
);
return *this;
}
diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp
index 7d40daa32..e6136c00e 100644
--- a/host/lib/usrp/b100/b100_ctrl.cpp
+++ b/host/lib/usrp/b100/b100_ctrl.cpp
@@ -165,7 +165,7 @@ int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) {
pkt.pkt_meta.seq = _seq++;
pkt.pkt_meta.len = pkt.data.size();
pkt.pkt_meta.addr = addr;
- boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)];
+ boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)] = {};
pack_ctrl_pkt(pkt_buff, pkt);
size_t result = send_pkt(pkt_buff);
@@ -181,7 +181,7 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) {
pkt.pkt_meta.seq = _seq++;
pkt.pkt_meta.len = len;
pkt.pkt_meta.addr = addr;
- boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)];
+ boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)] = {};
//flush anything that might be in the queue
while (get_ctrl_data(pkt.data, 0.0)){
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 61bc58bce..8b55494c5 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -150,6 +150,10 @@ UHD_STATIC_BLOCK(register_b100_device){
* Structors
**********************************************************************/
b100_impl::b100_impl(const device_addr_t &device_addr){
+ size_t initialization_count = 0;
+ b100_impl_constructor_begin:
+ initialization_count++;
+
_tree = property_tree::make();
//extract the FPGA path for the B100
@@ -181,6 +185,8 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
//load FPGA image, gpif is disabled while loading
this->enable_gpif(false);
_fx2_ctrl->usrp_load_fpga(b100_fpga_image);
+ _fx2_ctrl->usrp_fpga_reset(false); //active low reset
+ _fx2_ctrl->usrp_fpga_reset(true);
this->enable_gpif(true);
//create the control transport
@@ -196,13 +202,28 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
3, 4, //interface, endpoint
ctrl_xport_args
);
+ while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport
////////////////////////////////////////////////////////////////////
// Initialize FPGA wishbone communication
////////////////////////////////////////////////////////////////////
_fpga_ctrl = b100_ctrl::make(_ctrl_transport);
- this->reset_gpif(6); //always reset first to ensure communication
_fpga_ctrl->poke32(B100_REG_GLOBAL_RESET, 0); //global fpga reset
+ //perform a test peek operation
+ try{
+ _fpga_ctrl->peek32(0);
+ }
+ //try reset once in the case of failure
+ catch(const uhd::exception &e){
+ if (initialization_count > 1) throw;
+ UHD_MSG(warning) <<
+ "The control endpoint was left in a bad state.\n"
+ "Attempting endpoint re-enumeration...\n" << std::endl;
+ _fpga_ctrl.reset();
+ _ctrl_transport.reset();
+ _fx2_ctrl->usrp_fx2_reset();
+ goto b100_impl_constructor_begin;
+ }
this->check_fpga_compat(); //check after reset and making control
////////////////////////////////////////////////////////////////////
@@ -229,8 +250,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
2, 6, // IN interface, endpoint
1, 2, // OUT interface, endpoint
data_xport_args // param hints
- )
+ ),
+ B100_MAX_PKT_BYTE_LIMIT
);
+ while (_data_transport->get_recv_buff(0.0)){} //flush data xport
////////////////////////////////////////////////////////////////////
// Initialize the properties tree
@@ -361,10 +384,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
// create time control objects
////////////////////////////////////////////////////////////////////
time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_now = B100_REG_RB_TIME_NOW_SECS;
- time64_rb_bases.rb_ticks_now = B100_REG_RB_TIME_NOW_TICKS;
- time64_rb_bases.rb_secs_pps = B100_REG_RB_TIME_PPS_SECS;
- time64_rb_bases.rb_ticks_pps = B100_REG_RB_TIME_PPS_TICKS;
+ time64_rb_bases.rb_hi_now = B100_REG_RB_TIME_NOW_HI;
+ time64_rb_bases.rb_lo_now = B100_REG_RB_TIME_NOW_LO;
+ time64_rb_bases.rb_hi_pps = B100_REG_RB_TIME_PPS_HI;
+ time64_rb_bases.rb_lo_pps = B100_REG_RB_TIME_PPS_LO;
_time64 = time64_core_200::make(
_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases
);
@@ -388,6 +411,13 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
////////////////////////////////////////////////////////////////////
+ // create user-defined control objects
+ ////////////////////////////////////////////////////////////////////
+ _user = user_settings_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_USER_REGS));
+ _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")
+ .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1));
+
+ ////////////////////////////////////////////////////////////////////
// create dboard control objects
////////////////////////////////////////////////////////////////////
@@ -505,10 +535,6 @@ void b100_impl::update_clock_source(const std::string &source){
}
////////////////// some GPIF preparation related stuff /////////////////
-void b100_impl::reset_gpif(const boost::uint16_t ep) {
- _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0);
-}
-
void b100_impl::enable_gpif(const bool en) {
_fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0);
}
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index 96d90b14c..eab9c750b 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
#include "rx_dsp_core_200.hpp"
#include "tx_dsp_core_200.hpp"
#include "time64_core_200.hpp"
+#include "user_settings_core_200.hpp"
#include <uhd/device.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/utils/pimpl.hpp>
@@ -43,14 +44,15 @@
#include <uhd/transport/usb_zero_copy.hpp>
#include <boost/weak_ptr.hpp>
-static const double B100_LINK_RATE_BPS = 256e6/8; //pratical link rate (< 480 Mbps)
+static const double B100_LINK_RATE_BPS = 256e6/5; //pratical link rate (< 480 Mbps)
static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx";
static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin";
-static const boost::uint16_t B100_FW_COMPAT_NUM = 0x02;
-static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x08;
+static const boost::uint16_t B100_FW_COMPAT_NUM = 0x03;
+static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x09;
static const boost::uint32_t B100_RX_SID_BASE = 2;
static const boost::uint32_t B100_TX_ASYNC_SID = 1;
static const double B100_DEFAULT_TICK_RATE = 64e6;
+static const size_t B100_MAX_PKT_BYTE_LIMIT = 2048;
//! Make a b100 dboard interface
uhd::usrp::dboard_iface::sptr make_b100_dboard_iface(
@@ -84,6 +86,7 @@ private:
std::vector<rx_dsp_core_200::sptr> _rx_dsps;
tx_dsp_core_200::sptr _tx_dsp;
time64_core_200::sptr _time64;
+ user_settings_core_200::sptr _user;
b100_clock_ctrl::sptr _clock_ctrl;
b100_codec_ctrl::sptr _codec_ctrl;
b100_ctrl::sptr _fpga_ctrl;
@@ -120,7 +123,6 @@ private:
void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &);
void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &);
void update_clock_source(const std::string &);
- void reset_gpif(const boost::uint16_t);
void enable_gpif(const bool);
void clear_fpga_fifo(void);
void handle_async_message(uhd::transport::managed_recv_buffer::sptr);
diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp
index 491e16eef..987a09f03 100644
--- a/host/lib/usrp/b100/b100_regs.hpp
+++ b/host/lib/usrp/b100/b100_regs.hpp
@@ -1,4 +1,19 @@
-
+//
+// Copyright 2010-2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
////////////////////////////////////////////////////////////////
//
@@ -27,10 +42,6 @@
#define B100_REG_MISC_SW B100_REG_MISC_BASE + 2
#define B100_REG_MISC_CGEN_CTRL B100_REG_MISC_BASE + 4
#define B100_REG_MISC_CGEN_ST B100_REG_MISC_BASE + 6
-#define B100_REG_MISC_TEST B100_REG_MISC_BASE + 8
-#define B100_REG_MISC_RX_LEN B100_REG_MISC_BASE + 10
-#define B100_REG_MISC_TX_LEN B100_REG_MISC_BASE + 12
-#define B100_REG_MISC_XFER_RATE B100_REG_MISC_BASE + 14
/////////////////////////////////////////////////////
// Slave 1 -- UART
@@ -65,10 +76,10 @@
#define B100_REG_RB_MUX_32_BASE B100_REG_SLAVE(7)
-#define B100_REG_RB_TIME_NOW_SECS B100_REG_RB_MUX_32_BASE + 0
-#define B100_REG_RB_TIME_NOW_TICKS B100_REG_RB_MUX_32_BASE + 4
-#define B100_REG_RB_TIME_PPS_SECS B100_REG_RB_MUX_32_BASE + 8
-#define B100_REG_RB_TIME_PPS_TICKS B100_REG_RB_MUX_32_BASE + 12
+#define B100_REG_RB_TIME_NOW_HI B100_REG_RB_MUX_32_BASE + 0
+#define B100_REG_RB_TIME_NOW_LO B100_REG_RB_MUX_32_BASE + 4
+#define B100_REG_RB_TIME_PPS_HI B100_REG_RB_MUX_32_BASE + 8
+#define B100_REG_RB_TIME_PPS_LO B100_REG_RB_MUX_32_BASE + 12
#define B100_REG_RB_MISC_TEST32 B100_REG_RB_MUX_32_BASE + 16
#define B100_REG_RB_COMPAT B100_REG_RB_MUX_32_BASE + 24
#define B100_REG_RB_GPIO B100_REG_RB_MUX_32_BASE + 28
@@ -92,9 +103,9 @@
#define B100_SR_TX_FRONT 54 // 5 regs (+0 to +4)
#define B100_SR_REG_TEST32 60 // 1 reg
-#define B100_SR_CLEAR_RX_FIFO 61 // 1 reg
-#define B100_SR_CLEAR_TX_FIFO 62 // 1 reg
+#define B100_SR_CLEAR_FIFO 61 // 1 reg
#define B100_SR_GLOBAL_RESET 63 // 1 reg
+#define B100_SR_USER_REGS 64 // 2 regs
#define B100_SR_GPIO 128
@@ -105,8 +116,7 @@
/////////////////////////////////////////////////
// Magic reset regs
////////////////////////////////////////////////
-#define B100_REG_CLEAR_RX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO)
-#define B100_REG_CLEAR_TX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO)
+#define B100_REG_CLEAR_FIFO B100_REG_SR_ADDR(B100_SR_CLEAR_FIFO)
#define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET)
#endif
diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp
index 494d5d123..674380cca 100644
--- a/host/lib/usrp/b100/io_impl.cpp
+++ b/host/lib/usrp/b100/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
#include "recv_packet_demuxer.hpp"
#include "validate_subdev_spec.hpp"
+#include "async_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp_commands.h"
@@ -41,12 +42,13 @@ using namespace uhd::transport;
**********************************************************************/
struct b100_impl::io_impl{
io_impl(void):
- async_msg_fifo(100/*messages deep*/)
+ async_msg_fifo(1000/*messages deep*/)
{ /* NOP */ }
zero_copy_if::sptr data_transport;
bounded_buffer<async_metadata_t> async_msg_fifo;
recv_packet_demuxer::sptr demuxer;
+ double tick_rate;
};
/***********************************************************************
@@ -54,12 +56,8 @@ struct b100_impl::io_impl{
**********************************************************************/
void b100_impl::io_init(void){
- //clear state machines
- _fpga_ctrl->poke32(B100_REG_CLEAR_RX, 0);
- _fpga_ctrl->poke32(B100_REG_CLEAR_TX, 0);
-
- //set the expected packet size in USB frames
- _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4);
+ //clear fifo state machines
+ _fpga_ctrl->poke32(B100_REG_CLEAR_FIFO, 0);
//allocate streamer weak ptrs containers
_rx_streamers.resize(_rx_dsps.size());
@@ -85,26 +83,16 @@ void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){
}
if (if_packet_info.sid == B100_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+
//fill in the async metadata
async_metadata_t metadata;
- metadata.channel = 0;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), _clock_ctrl->get_fpga_clock_rate()
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
+ load_metadata_from_buff(uhd::wtohx<boost::uint32_t>, metadata, if_packet_info, vrt_hdr, _io_impl->tick_rate);
+
+ //push the message onto the queue
_io_impl->async_msg_fifo.push_with_pop_on_full(metadata);
- if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_UNDERFLOW
- | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
- ) UHD_MSG(fastpath) << "U";
- else if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_SEQ_ERROR
- | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
- ) UHD_MSG(fastpath) << "S";
- else if (metadata.event_code &
- async_metadata_t::EVENT_CODE_TIME_ERROR
- ) UHD_MSG(fastpath) << "L";
+
+ //print some fastpath messages
+ standard_async_msg_prints(metadata);
}
else UHD_MSG(error) << "Unknown async packet" << std::endl;
}
@@ -123,6 +111,8 @@ void b100_impl::update_rates(void){
}
void b100_impl::update_tick_rate(const double rate){
+ _io_impl->tick_rate = rate;
+
//update the tick rate on all existing streamers -> thread safe
for (size_t i = 0; i < _rx_streamers.size(); i++){
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
@@ -154,6 +144,8 @@ void b100_impl::update_tx_samp_rate(const size_t dspno, const double rate){
if (my_streamer.get() == NULL) return;
my_streamer->set_samp_rate(rate);
+ const double adj = _tx_dsp->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
}
void b100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
@@ -202,15 +194,15 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){
//setup defaults for unspecified values
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
- const size_t bpp = 2048 - hdr_size; //limited by FPGA pkt buffer size
+ const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi));
@@ -233,8 +225,7 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
_rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
- if (not args.args.has_key("noclear")) _rx_dsps[dsp]->clear();
- _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ _rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1
), true /*flush*/);
@@ -260,16 +251,15 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- if (args.otw_format != "sc16"){
- throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
- }
-
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
+ - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
- static const size_t bpp = 2048 - hdr_size;
+ static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
//make the new streamer given the samples per packet
@@ -291,8 +281,7 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
UHD_ASSERT_THROW(dsp == 0); //always 0
- if (not args.args.has_key("noclear")) _tx_dsp->clear();
- if (args.args.has_key("underflow_policy")) _tx_dsp->set_underflow_policy(args.args["underflow_policy"]);
+ _tx_dsp->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_send_buff, _data_transport, _1
));
diff --git a/host/lib/usrp/common/async_packet_handler.hpp b/host/lib/usrp/common/async_packet_handler.hpp
new file mode 100644
index 000000000..fef03483f
--- /dev/null
+++ b/host/lib/usrp/common/async_packet_handler.hpp
@@ -0,0 +1,71 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/vrt_if_packet.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/msg.hpp>
+
+namespace uhd{ namespace usrp{
+
+ template <typename to_host_type>
+ void load_metadata_from_buff(
+ const to_host_type &to_host,
+ async_metadata_t &metadata,
+ const transport::vrt::if_packet_info_t &if_packet_info,
+ const boost::uint32_t *vrt_hdr,
+ const double tick_rate,
+ const size_t channel = 0
+ ){
+ const boost::uint32_t *payload = vrt_hdr + if_packet_info.num_header_words32;
+
+ //load into metadata
+ metadata.channel = channel;
+ metadata.has_time_spec = if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate);
+ metadata.event_code = async_metadata_t::event_code_t(to_host(payload[0]) & 0xff);
+
+ //load user payload
+ for (size_t i = 1; i < if_packet_info.num_payload_words32; i++){
+ if (i-1 == 4) break; //limit of 4 words32
+ metadata.user_payload[i-1] = to_host(payload[i]);
+ }
+ }
+
+ UHD_INLINE void standard_async_msg_prints(const async_metadata_t &metadata)
+ {
+ if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_UNDERFLOW
+ | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
+ ) UHD_MSG(fastpath) << "U";
+ else if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_SEQ_ERROR
+ | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
+ ) UHD_MSG(fastpath) << "S";
+ else if (metadata.event_code &
+ async_metadata_t::EVENT_CODE_TIME_ERROR
+ ) UHD_MSG(fastpath) << "L";
+ }
+
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP */
diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
index 3c6df7079..7b8920eb1 100644
--- a/host/lib/usrp/common/fx2_ctrl.cpp
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -139,6 +139,15 @@ public:
_ctrl_transport = ctrl_transport;
}
+ void usrp_fx2_reset(void){
+ unsigned char reset_y = 1;
+ unsigned char reset_n = 0;
+ usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1);
+ usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1);
+ //wait for things to settle
+ boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
+ }
+
void usrp_load_firmware(std::string filestring, bool force)
{
const char *filename = filestring.c_str();
@@ -419,7 +428,7 @@ public:
{
UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes);
- unsigned char buff[max_i2c_data_bytes];
+ unsigned char buff[max_i2c_data_bytes] = {};
std::copy(bytes.begin(), bytes.end(), buff);
int ret = this->usrp_i2c_write(addr & 0xff,
@@ -434,7 +443,7 @@ public:
{
UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
- unsigned char buff[max_i2c_data_bytes];
+ unsigned char buff[max_i2c_data_bytes] = {};
int ret = this->usrp_i2c_read(addr & 0xff,
buff,
num_bytes);
diff --git a/host/lib/usrp/common/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp
index 691d64275..f2e060862 100644
--- a/host/lib/usrp/common/fx2_ctrl.hpp
+++ b/host/lib/usrp/common/fx2_ctrl.hpp
@@ -39,6 +39,9 @@ public:
//! Call init after the fpga is loaded
virtual void usrp_init(void) = 0;
+ //! For emergency situations
+ virtual void usrp_fx2_reset(void) = 0;
+
/*!
* Load firmware in Intel HEX Format onto device
* \param filename name of firmware file
@@ -116,6 +119,9 @@ public:
//! enable/disable the tx path
virtual void usrp_tx_enable(bool on) = 0;
+
+ //! reset the fpga
+ virtual void usrp_fpga_reset(bool on) = 0;
};
}} //namespace uhd::usrp
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
index 2aa8f6b99..aa5f0bcbb 100644
--- a/host/lib/usrp/cores/CMakeLists.txt
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2012 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -30,4 +30,5 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tx_frontend_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_core_200.cpp
)
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index 2e21cc895..0996952ff 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
#include "rx_dsp_core_200.hpp"
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread/thread.hpp> //thread sleep
@@ -27,7 +28,7 @@
#include <cmath>
#define REG_DSP_RX_FREQ _dsp_base + 0
-//skip one right here
+#define REG_DSP_RX_SCALE_IQ _dsp_base + 4
#define REG_DSP_RX_DECIM _dsp_base + 8
#define REG_DSP_RX_MUX _dsp_base + 12
@@ -35,15 +36,15 @@
#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
#define REG_RX_CTRL_STREAM_CMD _ctrl_base + 0
-#define REG_RX_CTRL_TIME_SECS _ctrl_base + 4
-#define REG_RX_CTRL_TIME_TICKS _ctrl_base + 8
+#define REG_RX_CTRL_TIME_HI _ctrl_base + 4
+#define REG_RX_CTRL_TIME_LO _ctrl_base + 8
#define REG_RX_CTRL_CLEAR _ctrl_base + 12
#define REG_RX_CTRL_VRT_HDR _ctrl_base + 16
#define REG_RX_CTRL_VRT_SID _ctrl_base + 20
#define REG_RX_CTRL_VRT_TLR _ctrl_base + 24
#define REG_RX_CTRL_NSAMPS_PP _ctrl_base + 28
#define REG_RX_CTRL_NCHANNELS _ctrl_base + 32
-#define REG_RX_CTRL_FORMAT _ctrl_base + 36
+#define REG_RX_CTRL_FORMAT REG_RX_CTRL_CLEAR //re-use clear address
template <class T> T ceil_log2(T num){
return std::ceil(std::log(num)/std::log(T(2)));
@@ -60,6 +61,10 @@ public:
):
_iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+
//This is a hack/fix for the lingering packet problem.
//The caller should also flush the recv transports
if (lingering_packet){
@@ -78,7 +83,6 @@ public:
_iface->poke32(REG_RX_CTRL_VRT_HDR, 0
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
- | (0x3 << 22) //integer time other
| (0x1 << 20) //fractional time sample count
);
_iface->poke32(REG_RX_CTRL_VRT_SID, _sid);
@@ -117,8 +121,9 @@ public:
//issue the stream command
_iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word);
- _iface->poke32(REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_tick_rate)); //latches the command
+ const boost::uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(_tick_rate);
+ _iface->poke32(REG_RX_CTRL_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_RX_CTRL_TIME_LO, boost::uint32_t(ticks >> 0)); //latches the command
}
void set_mux(const std::string &mode, const bool fe_swapped){
@@ -175,12 +180,20 @@ public:
// Calculate closest multiplier constant to reverse gain absent scale multipliers
const double rate_pow = std::pow(double(decim & 0xff), 4);
_scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
return _tick_rate/decim_rate;
}
+ void update_scalar(void){
+ const double target_scalar = (1 << 16)*_scaling_adjustment/_dsp_extra_scaling;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small
+ _iface->poke32(REG_DSP_RX_SCALE_IQ, actual_scalar);
+ }
+
double get_scaling_adjustment(void){
- return _scaling_adjustment/_fxpt_scale_adj;
+ return _fxpt_scalar_correction*_host_extra_scaling/32767.;
}
double set_freq(const double freq_){
@@ -210,22 +223,27 @@ public:
if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
}
- void set_format(const std::string &format, const unsigned scale){
+ void setup(const uhd::stream_args_t &stream_args){
+ if (not stream_args.args.has_key("noclear")) this->clear();
+
unsigned format_word = 0;
- if (format == "sc16"){
+ if (stream_args.otw_format == "sc16"){
format_word = 0;
- _fxpt_scale_adj = 32767.;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
}
- else if (format == "sc8"){
- format_word = (1 << 18);
- _fxpt_scale_adj = 127. * scale;
- _fxpt_scale_adj /= 256; //engine 16to8 drops lower 8 bits
- _fxpt_scale_adj /= 4; //scale operation 2-bit pad
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = peak*256;
+ _dsp_extra_scaling = peak*256;
}
- else throw uhd::value_error("USRP RX cannot handle requested wire format: " + format);
+ else throw uhd::value_error("USRP RX cannot handle requested wire format: " + stream_args.otw_format);
+
+ this->update_scalar();
- const unsigned scale_word = scale & 0x3ffff; //18 bits;
- _iface->poke32(REG_RX_CTRL_FORMAT, format_word | scale_word);
+ _iface->poke32(REG_RX_CTRL_FORMAT, format_word);
}
private:
@@ -233,7 +251,7 @@ private:
const size_t _dsp_base, _ctrl_base;
double _tick_rate, _link_rate;
bool _continuous_streaming;
- double _scaling_adjustment, _fxpt_scale_adj;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
const boost::uint32_t _sid;
};
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp
index 58be51eee..b01f751e9 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP
#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -60,7 +61,7 @@ public:
virtual void handle_overflow(void) = 0;
- virtual void set_format(const std::string &format, const unsigned scale) = 0;
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
};
#endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index 23d1bdea2..e460d1106 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -20,11 +20,10 @@
#include <uhd/utils/assert_has.hpp>
#include <boost/math/special_functions/round.hpp>
-#define REG_TIME64_SECS _base + 0
-#define REG_TIME64_TICKS _base + 4
+#define REG_TIME64_TICKS_HI _base + 0
+#define REG_TIME64_TICKS_LO _base + 4
#define REG_TIME64_FLAGS _base + 8
#define REG_TIME64_IMM _base + 12
-#define REG_TIME64_TPS _base + 16
#define REG_TIME64_MIMO_SYNC _base + 20 //lower byte is delay cycles
//pps flags (see above)
@@ -59,39 +58,42 @@ public:
void set_tick_rate(const double rate){
_tick_rate = rate;
- _iface->poke32(REG_TIME64_TPS, boost::math::iround(rate));
}
uhd::time_spec_t get_time_now(void){
for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
- const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_now);
- const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_now);
- if (secs != _iface->peek32(_readback_bases.rb_secs_now)) continue;
- return time_spec_t(secs, ticks, _tick_rate);
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_now);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_now);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_now)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(ticks, _tick_rate);
}
throw uhd::runtime_error("time64_core_200: get time now timeout");
}
uhd::time_spec_t get_time_last_pps(void){
for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
- const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_pps);
- const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_pps);
- if (secs != _iface->peek32(_readback_bases.rb_secs_pps)) continue;
- return time_spec_t(secs, ticks, _tick_rate);
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_pps);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_pps);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_pps)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(ticks, _tick_rate);
}
throw uhd::runtime_error("time64_core_200: get time last pps timeout");
}
void set_time_now(const uhd::time_spec_t &time){
- _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate));
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
_iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW);
- _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
}
void set_time_next_pps(const uhd::time_spec_t &time){
- _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate));
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
_iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS);
- _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
}
void set_time_source(const std::string &source){
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index ebd51a02f..7571573a5 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -31,8 +31,8 @@ public:
typedef boost::shared_ptr<time64_core_200> sptr;
struct readback_bases_type{
- size_t rb_secs_now, rb_ticks_now;
- size_t rb_secs_pps, rb_ticks_pps;
+ size_t rb_hi_now, rb_lo_now;
+ size_t rb_hi_pps, rb_lo_pps;
};
//! makes a new time64 core from iface and slave base
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
index c5de4e361..7f02d59ca 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,10 +18,12 @@
#include "tx_dsp_core_200.hpp"
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/sign.hpp>
+#include <boost/thread/thread.hpp> //sleep
#include <algorithm>
#include <cmath>
@@ -29,8 +31,8 @@
#define REG_DSP_TX_SCALE_IQ _dsp_base + 4
#define REG_DSP_TX_INTERP _dsp_base + 8
-#define REG_TX_CTRL_NUM_CHAN _ctrl_base + 0
-#define REG_TX_CTRL_CLEAR_STATE _ctrl_base + 4
+#define REG_TX_CTRL_CLEAR _ctrl_base + 0
+#define REG_TX_CTRL_FORMAT _ctrl_base + 4
#define REG_TX_CTRL_REPORT_SID _ctrl_base + 8
#define REG_TX_CTRL_POLICY _ctrl_base + 12
#define REG_TX_CTRL_CYCLES_PER_UP _ctrl_base + 16
@@ -58,14 +60,19 @@ public:
):
_iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+
//init the tx control registers
this->clear();
this->set_underflow_policy("next_packet");
}
void clear(void){
- _iface->poke32(REG_TX_CTRL_CLEAR_STATE, 1); //reset
- _iface->poke32(REG_TX_CTRL_NUM_CHAN, 0); //1 channel
+ _iface->poke32(REG_TX_CTRL_CLEAR, 1); //reset and flush technique
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+ _iface->poke32(REG_TX_CTRL_CLEAR, 0);
_iface->poke32(REG_TX_CTRL_REPORT_SID, _sid);
}
@@ -121,13 +128,24 @@ public:
// Calculate CIC interpolation (i.e., without halfband interpolators)
// Calculate closest multiplier constant to reverse gain absent scale multipliers
- double rate_cubed = std::pow(double(interp & 0xff), 3);
- const boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed));
- _iface->poke32(REG_DSP_TX_SCALE_IQ, (boost::uint32_t(scale) << 16) | (boost::uint32_t(scale) << 0));
+ const double rate_pow = std::pow(double(interp & 0xff), 3);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
return _tick_rate/interp_rate;
}
+ void update_scalar(void){
+ const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small
+ _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar);
+ }
+
+ double get_scaling_adjustment(void){
+ return _fxpt_scalar_correction*_host_extra_scaling*32767.;
+ }
+
double set_freq(const double freq_){
//correct for outside of rate (wrap around)
double freq = std::fmod(freq_, _tick_rate);
@@ -156,10 +174,38 @@ public:
_iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up));
}
+ void setup(const uhd::stream_args_t &stream_args){
+ if (not stream_args.args.has_key("noclear")) this->clear();
+
+ unsigned format_word = 0;
+ if (stream_args.otw_format == "sc16"){
+ format_word = 0;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
+ }
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = 1.0/peak/256;
+ _dsp_extra_scaling = 1.0/peak;
+ }
+ else throw uhd::value_error("USRP TX cannot handle requested wire format: " + stream_args.otw_format);
+
+ this->update_scalar();
+
+ _iface->poke32(REG_TX_CTRL_FORMAT, format_word);
+
+ if (stream_args.args.has_key("underflow_policy")){
+ this->set_underflow_policy(stream_args.args["underflow_policy"]);
+ }
+ }
+
private:
wb_iface::sptr _iface;
const size_t _dsp_base, _ctrl_base;
double _tick_rate, _link_rate;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
const boost::uint32_t _sid;
};
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp
index 4b39a5b07..0e1cfb6bc 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP
#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -44,14 +45,15 @@ public:
virtual uhd::meta_range_t get_host_rates(void) = 0;
+ virtual double get_scaling_adjustment(void) = 0;
+
virtual uhd::meta_range_t get_freq_range(void) = 0;
virtual double set_freq(const double freq) = 0;
virtual void set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0;
- virtual void set_underflow_policy(const std::string &policy) = 0;
-
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
};
#endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/user_settings_core_200.cpp b/host/lib/usrp/cores/user_settings_core_200.cpp
new file mode 100644
index 000000000..d262631b1
--- /dev/null
+++ b/host/lib/usrp/cores/user_settings_core_200.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "user_settings_core_200.hpp"
+
+#define REG_USER_ADDR _base + 0
+#define REG_USER_DATA _base + 4
+
+class user_settings_core_200_impl : public user_settings_core_200{
+public:
+ user_settings_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_reg(const user_reg_t &reg){
+ _iface->poke32(REG_USER_ADDR, reg.first);
+ _iface->poke32(REG_USER_DATA, reg.second);
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+user_settings_core_200::sptr user_settings_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new user_settings_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/user_settings_core_200.hpp b/host/lib/usrp/cores/user_settings_core_200.hpp
new file mode 100644
index 000000000..1f5d13de7
--- /dev/null
+++ b/host/lib/usrp/cores/user_settings_core_200.hpp
@@ -0,0 +1,36 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class user_settings_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<user_settings_core_200> sptr;
+ typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_reg(const user_reg_t &reg) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP */
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index f58138ae6..a01ce4a7b 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -326,10 +326,10 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
// create time control objects
////////////////////////////////////////////////////////////////////
time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_now = E100_REG_RB_TIME_NOW_SECS;
- time64_rb_bases.rb_ticks_now = E100_REG_RB_TIME_NOW_TICKS;
- time64_rb_bases.rb_secs_pps = E100_REG_RB_TIME_PPS_SECS;
- time64_rb_bases.rb_ticks_pps = E100_REG_RB_TIME_PPS_TICKS;
+ time64_rb_bases.rb_hi_now = E100_REG_RB_TIME_NOW_HI;
+ time64_rb_bases.rb_lo_now = E100_REG_RB_TIME_NOW_LO;
+ time64_rb_bases.rb_hi_pps = E100_REG_RB_TIME_PPS_HI;
+ time64_rb_bases.rb_lo_pps = E100_REG_RB_TIME_PPS_LO;
_time64 = time64_core_200::make(
_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases
);
@@ -353,6 +353,13 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
////////////////////////////////////////////////////////////////////
+ // create user-defined control objects
+ ////////////////////////////////////////////////////////////////////
+ _user = user_settings_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_USER_REGS));
+ _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")
+ .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1));
+
+ ////////////////////////////////////////////////////////////////////
// create dboard control objects
////////////////////////////////////////////////////////////////////
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 2ea890375..1d36cb2ac 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include "rx_dsp_core_200.hpp"
#include "tx_dsp_core_200.hpp"
#include "time64_core_200.hpp"
+#include "user_settings_core_200.hpp"
#include <uhd/device.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/utils/pimpl.hpp>
@@ -48,7 +49,7 @@ static const double E100_RX_LINK_RATE_BPS = 166e6/3/2*2;
static const double E100_TX_LINK_RATE_BPS = 166e6/3/1*2;
static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3";
static const std::string E100_UART_DEV_NODE = "/dev/ttyO0";
-static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x08;
+static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x09;
static const boost::uint32_t E100_RX_SID_BASE = 2;
static const boost::uint32_t E100_TX_ASYNC_SID = 1;
static const double E100_DEFAULT_CLOCK_RATE = 64e6;
@@ -92,6 +93,7 @@ private:
std::vector<rx_dsp_core_200::sptr> _rx_dsps;
tx_dsp_core_200::sptr _tx_dsp;
time64_core_200::sptr _time64;
+ user_settings_core_200::sptr _user;
e100_clock_ctrl::sptr _clock_ctrl;
e100_codec_ctrl::sptr _codec_ctrl;
e100_ctrl::sptr _fpga_ctrl;
diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp
index f24f5895b..75be2cfbe 100644
--- a/host/lib/usrp/e100/e100_regs.hpp
+++ b/host/lib/usrp/e100/e100_regs.hpp
@@ -1,4 +1,19 @@
-
+//
+// Copyright 2010-2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
////////////////////////////////////////////////////////////////
//
@@ -71,10 +86,10 @@
#define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7)
-#define E100_REG_RB_TIME_NOW_SECS E100_REG_RB_MUX_32_BASE + 0
-#define E100_REG_RB_TIME_NOW_TICKS E100_REG_RB_MUX_32_BASE + 4
-#define E100_REG_RB_TIME_PPS_SECS E100_REG_RB_MUX_32_BASE + 8
-#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12
+#define E100_REG_RB_TIME_NOW_HI E100_REG_RB_MUX_32_BASE + 0
+#define E100_REG_RB_TIME_NOW_LO E100_REG_RB_MUX_32_BASE + 4
+#define E100_REG_RB_TIME_PPS_HI E100_REG_RB_MUX_32_BASE + 8
+#define E100_REG_RB_TIME_PPS_LO E100_REG_RB_MUX_32_BASE + 12
#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16
#define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20
#define E100_REG_RB_COMPAT E100_REG_RB_MUX_32_BASE + 24
@@ -101,9 +116,9 @@
#define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4)
#define UE_SR_REG_TEST32 60 // 1 reg
-#define UE_SR_CLEAR_RX_FIFO 61 // 1 reg
-#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg
+#define UE_SR_CLEAR_FIFO 61 // 1 reg
#define UE_SR_GLOBAL_RESET 63 // 1 reg
+#define UE_SR_USER_REGS 64 // 2 regs
#define UE_SR_GPIO 128
@@ -115,8 +130,7 @@
/////////////////////////////////////////////////
// Magic reset regs
////////////////////////////////////////////////
-#define E100_REG_CLEAR_RX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO)
-#define E100_REG_CLEAR_TX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO)
+#define E100_REG_CLEAR_FIFO E100_REG_SR_ADDR(UE_SR_CLEAR_FIFO)
#define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET)
#endif
diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp
index 441e32a8d..e9608125f 100644
--- a/host/lib/usrp/e100/io_impl.cpp
+++ b/host/lib/usrp/e100/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
#include "recv_packet_demuxer.hpp"
#include "validate_subdev_spec.hpp"
+#include "async_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include <linux/usrp_e.h> //ioctl structures and constants
@@ -50,7 +51,7 @@ using namespace uhd::transport;
**********************************************************************/
struct e100_impl::io_impl{
io_impl(void):
- false_alarm(0), async_msg_fifo(100/*messages deep*/)
+ false_alarm(0), async_msg_fifo(1000/*messages deep*/)
{ /* NOP */ }
double tick_rate; //set by update tick rate method
@@ -123,28 +124,13 @@ void e100_impl::io_impl::handle_irq(void){
//fill in the async metadata
async_metadata_t metadata;
- metadata.channel = 0;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), long(if_packet_info.tsf), tick_rate
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(data.buf, if_packet_info));
+ load_metadata_from_buff(uhd::wtohx<boost::uint32_t>, metadata, if_packet_info, data.buf, tick_rate);
//push the message onto the queue
async_msg_fifo.push_with_pop_on_full(metadata);
//print some fastpath messages
- if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_UNDERFLOW
- | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
- ) UHD_MSG(fastpath) << "U";
- else if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_SEQ_ERROR
- | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
- ) UHD_MSG(fastpath) << "S";
- else if (metadata.event_code &
- async_metadata_t::EVENT_CODE_TIME_ERROR
- ) UHD_MSG(fastpath) << "L";
+ standard_async_msg_prints(metadata);
}
//prepare for the next round
@@ -164,9 +150,8 @@ void e100_impl::io_init(void){
_io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE);
_io_impl->iface = _fpga_ctrl;
- //clear state machines
- _fpga_ctrl->poke32(E100_REG_CLEAR_RX, 0);
- _fpga_ctrl->poke32(E100_REG_CLEAR_TX, 0);
+ //clear fifo state machines
+ _fpga_ctrl->poke32(E100_REG_CLEAR_FIFO, 0);
//allocate streamer weak ptrs containers
_rx_streamers.resize(_rx_dsps.size());
@@ -217,6 +202,8 @@ void e100_impl::update_tx_samp_rate(const size_t dspno, const double rate){
if (my_streamer.get() == NULL) return;
my_streamer->set_samp_rate(rate);
+ const double adj = _tx_dsp->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
}
void e100_impl::update_rates(void){
@@ -278,13 +265,13 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){
//setup defaults for unspecified values
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -309,8 +296,7 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
_rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
- if (not args.args.has_key("noclear")) _rx_dsps[dsp]->clear();
- _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ _rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1
), true /*flush*/);
@@ -336,14 +322,13 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- if (args.otw_format != "sc16"){
- throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
- }
-
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
+ - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
@@ -367,8 +352,7 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
UHD_ASSERT_THROW(dsp == 0); //always 0
- if (not args.args.has_key("noclear")) _tx_dsp->clear();
- if (args.args.has_key("underflow_policy")) _tx_dsp->set_underflow_policy(args.args["underflow_policy"]);
+ _tx_dsp->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_send_buff, _data_transport, _1
));
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 6cd9f95bb..d9be19b83 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -445,6 +445,17 @@ public:
return _tree->list(mb_root(mboard) / "sensors");
}
+ void set_user_register(const boost::uint8_t addr, const boost::uint32_t data, size_t mboard){
+ if (mboard != ALL_MBOARDS){
+ typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
+ _tree->access<user_reg_t>(mb_root(mboard) / "user/reg").set(user_reg_t(addr, data));
+ return;
+ }
+ for (size_t m = 0; m < get_num_mboards(); m++){
+ set_user_register(addr, data, m);
+ }
+ }
+
/*******************************************************************
* RX methods
******************************************************************/
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index e9d9b65c2..f27135562 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -221,17 +221,17 @@ void usrp1_impl::io_init(void){
_io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
- //create a new vandal thread to poll xerflow conditions
- _io_impl->vandal_task = task::make(boost::bind(
- &usrp1_impl::vandal_conquest_loop, this
- ));
-
//init as disabled, then call the real function (uses restore)
this->enable_rx(false);
this->enable_tx(false);
rx_stream_on_off(false);
tx_stream_on_off(false);
_io_impl->flush_send_buff();
+
+ //create a new vandal thread to poll xerflow conditions
+ _io_impl->vandal_task = task::make(boost::bind(
+ &usrp1_impl::vandal_conquest_loop, this
+ ));
}
void usrp1_impl::rx_stream_on_off(bool enb){
diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
index b8af8af06..90b3a92da 100644
--- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp
+++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
@@ -39,8 +39,8 @@ public:
_nsamps_remaining(0),
_stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),
_cmd_queue(2),
- _async_msg_queue(100),
- _inline_msg_queue(100),
+ _async_msg_queue(1000),
+ _inline_msg_queue(1000),
_stream_on_off(stream_on_off)
{
//synchronously spawn a new thread
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index ef8ae950d..430ea59c8 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -210,6 +210,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
// Initialize the properties tree
////////////////////////////////////////////////////////////////////
+ _rx_dc_offset_shadow = 0;
_tree = property_tree::make();
_tree->create<std::string>("/name").set("USRP1 Device");
const fs_path mb_path = "/mboards/0";
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 1af1db860..0babf7445 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -30,9 +30,9 @@ extern "C" {
#endif
//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 8
+#define USRP2_FPGA_COMPAT_NUM 9
#define USRP2_FW_COMPAT_NUM 11
-#define USRP2_FW_VER_MINOR 1
+#define USRP2_FW_VER_MINOR 2
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index e3fa46920..d32ffb62c 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
//
#include "validate_subdev_spec.hpp"
+#include "async_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp2_impl.hpp"
@@ -135,7 +136,8 @@ private:
struct usrp2_impl::io_impl{
io_impl(void):
- async_msg_fifo(100/*messages deep*/)
+ async_msg_fifo(1000/*messages deep*/),
+ tick_rate(1 /*non-zero default*/)
{
/* NOP */
}
@@ -201,12 +203,7 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//fill in the async metadata
async_metadata_t metadata;
- metadata.channel = index;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
+ load_metadata_from_buff(uhd::ntohx<boost::uint32_t>, metadata, if_packet_info, vrt_hdr, tick_rate, index);
//catch the flow control packets and react
if (metadata.event_code == 0){
@@ -217,17 +214,7 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//else UHD_MSG(often) << "metadata.event_code " << metadata.event_code << std::endl;
async_msg_fifo.push_with_pop_on_full(metadata);
- if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_UNDERFLOW
- | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
- ) UHD_MSG(fastpath) << "U";
- else if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_SEQ_ERROR
- | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
- ) UHD_MSG(fastpath) << "S";
- else if (metadata.event_code &
- async_metadata_t::EVENT_CODE_TIME_ERROR
- ) UHD_MSG(fastpath) << "L";
+ standard_async_msg_prints(metadata);
}
else{
//TODO unknown received packet, may want to print error...
@@ -307,6 +294,8 @@ void usrp2_impl::update_tx_samp_rate(const std::string &mb, const size_t dsp, co
if (my_streamer.get() == NULL) return;
my_streamer->set_samp_rate(rate);
+ const double adj = _mbc[mb].tx_dsp->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
}
void usrp2_impl::update_rates(void){
@@ -380,13 +369,13 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
//setup defaults for unspecified values
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -416,8 +405,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
if (chan < num_chan_so_far){
const size_t dsp = chan + _mbc[mb].rx_chan_occ - num_chan_so_far;
_mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
- if (not args.args.has_key("noclear")) _mbc[mb].rx_dsps[dsp]->clear();
- _mbc[mb].rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ _mbc[mb].rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1
), true /*flush*/);
@@ -447,15 +435,14 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- if (args.otw_format != "sc16"){
- throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
- }
-
//calculate packet size
static const size_t hdr_size = 0
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ vrt_send_header_offset_words32*sizeof(boost::uint32_t)
+ + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _mbc[_mbc.keys().front()].tx_dsp_xport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
@@ -485,10 +472,9 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){
if (chan < num_chan_so_far){
const size_t dsp = chan + _mbc[mb].tx_chan_occ - num_chan_so_far;
if (not args.args.has_key("noclear")){
- _mbc[mb].tx_dsp->clear();
_io_impl->fc_mons[abs]->clear();
}
- if (args.args.has_key("underflow_policy")) _mbc[mb].tx_dsp->set_underflow_policy(args.args["underflow_policy"]);
+ _mbc[mb].tx_dsp->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&usrp2_impl::io_impl::get_send_buff, _io_impl.get(), abs, _1
));
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 4830c10d9..eeba6756e 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -87,7 +87,7 @@ public:
//Obtain the firmware's compat number.
//Save the response compat number for communication.
//TODO can choose to reject certain older compat numbers
- usrp2_ctrl_data_t ctrl_data;
+ usrp2_ctrl_data_t ctrl_data = usrp2_ctrl_data_t();
ctrl_data.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
ctrl_data = ctrl_send_and_recv(ctrl_data, 0, ~0);
if (ntohl(ctrl_data.id) != USRP2_CTRL_ID_WAZZUP_DUDE)
@@ -126,10 +126,9 @@ public:
bool is_device_locked(void){
boost::uint32_t lock_secs = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_TIME);
boost::uint32_t lock_gpid = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_GPID);
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
//if the difference is larger, assume not locked anymore
- if (curr_secs - lock_secs >= 3) return false;
+ if (this->get_curr_secs() - lock_secs >= 3) return false;
//otherwise only lock if the device hash is different that ours
return lock_gpid != boost::uint32_t(get_gpid());
@@ -137,12 +136,16 @@ public:
void lock_task(void){
//re-lock in task
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs);
+ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, this->get_curr_secs());
//sleep for a bit
boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
}
+ boost::uint32_t get_curr_secs(void){
+ //may not be the right tick rate, but this is ok for locking purposes
+ return boost::uint32_t(this->peek32(U2_REG_TIME64_LO_RB_IMM)/100e6);
+ }
+
/***********************************************************************
* Peek and Poke
**********************************************************************/
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index ef7151cee..2077ab009 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -546,10 +546,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
// create time control objects
////////////////////////////////////////////////////////////////
time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_now = U2_REG_TIME64_SECS_RB_IMM;
- time64_rb_bases.rb_ticks_now = U2_REG_TIME64_TICKS_RB_IMM;
- time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS;
- time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS;
+ time64_rb_bases.rb_hi_now = U2_REG_TIME64_HI_RB_IMM;
+ time64_rb_bases.rb_lo_now = U2_REG_TIME64_LO_RB_IMM;
+ time64_rb_bases.rb_hi_pps = U2_REG_TIME64_HI_RB_PPS;
+ time64_rb_bases.rb_lo_pps = U2_REG_TIME64_LO_RB_PPS;
_mbc[mb].time64 = time64_core_200::make(
_mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles
);
@@ -572,6 +572,13 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
+ ////////////////////////////////////////////////////////////////////
+ // create user-defined control objects
+ ////////////////////////////////////////////////////////////////////
+ _mbc[mb].user = user_settings_core_200::make(_mbc[mb].iface, U2_REG_SR_ADDR(SR_USER_REGS));
+ _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")
+ .subscribe(boost::bind(&user_settings_core_200::set_reg, _mbc[mb].user, _1));
+
////////////////////////////////////////////////////////////////
// create dboard control objects
////////////////////////////////////////////////////////////////
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 278dc713e..882a61f80 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#include "rx_dsp_core_200.hpp"
#include "tx_dsp_core_200.hpp"
#include "time64_core_200.hpp"
+#include "user_settings_core_200.hpp"
#include <uhd/property_tree.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/device.hpp>
@@ -91,6 +92,7 @@ private:
std::vector<boost::weak_ptr<uhd::tx_streamer> > tx_streamers;
tx_dsp_core_200::sptr tx_dsp;
time64_core_200::sptr time64;
+ user_settings_core_200::sptr user;
std::vector<uhd::transport::zero_copy_if::sptr> rx_dsp_xports;
uhd::transport::zero_copy_if::sptr tx_dsp_xport;
uhd::usrp::dboard_manager::sptr dboard_manager;
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 179a930c6..e14798ecb 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@
#define SR_SIMTIMER 8 // 2
#define SR_TIME64 10 // 6
#define SR_BUF_POOL 16 // 4
-
+#define SR_USER_REGS 20 // 2
#define SR_RX_FRONT 24 // 5
#define SR_RX_CTRL0 32 // 9
#define SR_RX_DSP0 48 // 7
@@ -97,11 +97,11 @@
////////////////////////////////////////////////
#define U2_REG_STATUS READBACK_BASE + 4*8
#define U2_REG_GPIO_RB READBACK_BASE + 4*9
-#define U2_REG_TIME64_SECS_RB_IMM READBACK_BASE + 4*10
-#define U2_REG_TIME64_TICKS_RB_IMM READBACK_BASE + 4*11
+#define U2_REG_TIME64_HI_RB_IMM READBACK_BASE + 4*10
+#define U2_REG_TIME64_LO_RB_IMM READBACK_BASE + 4*11
#define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12
#define U2_REG_IRQ_RB READBACK_BASE + 4*13
-#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14
-#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15
+#define U2_REG_TIME64_HI_RB_PPS READBACK_BASE + 4*14
+#define U2_REG_TIME64_LO_RB_PPS READBACK_BASE + 4*15
#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp
index 1a5d30080..6b0ae53a9 100644
--- a/host/tests/convert_test.cpp
+++ b/host/tests/convert_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011-2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -31,8 +31,9 @@ typedef std::complex<boost::int16_t> sc16_t;
typedef std::complex<float> fc32_t;
typedef std::complex<double> fc64_t;
-#define MY_CHECK_CLOSE(a, b, f) if ((std::abs(a) > (f))) \
- BOOST_CHECK_CLOSE_FRACTION(a, b, f)
+#define MY_CHECK_CLOSE(a, b, f) { \
+ BOOST_CHECK_MESSAGE(std::abs((a)-(b)) < f, "\n\t" << #a << " (" << (a) << ") error " << #b << " (" << (b) << ")"); \
+}
/***********************************************************************
* Loopback runner:
@@ -67,13 +68,13 @@ template <typename Range> static void loopback(
* Test short conversion
**********************************************************************/
static void test_convert_types_sc16(
- size_t nsamps, convert::id_type &id
+ size_t nsamps, convert::id_type &id, const int extra_div = 1
){
//fill the input samples
std::vector<sc16_t> input(nsamps), output(nsamps);
BOOST_FOREACH(sc16_t &in, input) in = sc16_t(
- std::rand()-(RAND_MAX/2),
- std::rand()-(RAND_MAX/2)
+ short(((std::rand()/double(RAND_MAX/2)) - 1)*32767/extra_div),
+ short(((std::rand()/double(RAND_MAX/2)) - 1)*32767/extra_div)
);
//run the loopback and test
@@ -116,15 +117,15 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16){
**********************************************************************/
template <typename data_type>
static void test_convert_types_for_floats(
- size_t nsamps, convert::id_type &id
+ size_t nsamps, convert::id_type &id, const double extra_scale = 1.0
){
typedef typename data_type::value_type value_type;
//fill the input samples
std::vector<data_type> input(nsamps), output(nsamps);
BOOST_FOREACH(data_type &in, input) in = data_type(
- (std::rand()/value_type(RAND_MAX/2)) - 1,
- (std::rand()/value_type(RAND_MAX/2)) - 1
+ ((std::rand()/value_type(RAND_MAX/2)) - 1)*float(extra_scale),
+ ((std::rand()/value_type(RAND_MAX/2)) - 1)*float(extra_scale)
);
//run the loopback and test
@@ -134,8 +135,8 @@ static void test_convert_types_for_floats(
std::swap(out_id.num_inputs, out_id.num_outputs);
loopback(nsamps, in_id, out_id, input, output);
for (size_t i = 0; i < nsamps; i++){
- MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(0.01));
- MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(0.01));
+ MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(1./32767));
+ MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(1./32767));
}
}
@@ -280,3 +281,63 @@ BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32){
MY_CHECK_CLOSE(input[i].imag()/float(32767), output[i].imag(), float(0.01));
}
}
+
+/***********************************************************************
+ * Test sc8 conversions
+ **********************************************************************/
+BOOST_AUTO_TEST_CASE(test_convert_types_fc64_and_sc8){
+ convert::id_type id;
+ id.input_format = "fc64";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id, 1./256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id, 1./256);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_sc8){
+ convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id, 1./256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id, 1./256);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8){
+ convert::id_type id;
+ id.input_format = "sc16";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id, 256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id, 256);
+ }
+}
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp
index 85d06aa0d..9b45d7016 100644
--- a/host/tests/sph_recv_test.cpp
+++ b/host/tests/sph_recv_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_normal){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -232,14 +232,14 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_sequence_error){
if (i == NUM_PKTS_TO_TEST/2){
//must get the soft overflow here
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
num_accum_samps += 10 + i%10;
}
else{
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -323,7 +323,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
if (i == NUM_PKTS_TO_TEST/2){
@@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
);
std::cout << "metadata.error_code " << metadata.error_code << std::endl;
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(overflow_handler.num_overflow, size_t(1));
}
}
@@ -414,7 +414,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -500,14 +500,14 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_sequence_error){
if (i == NUM_PKTS_TO_TEST/2){
//must get the soft overflow here
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
num_accum_samps += 10 + i%10;
}
else{
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -593,7 +593,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_time_error){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
if (i == NUM_PKTS_TO_TEST/2){
@@ -677,7 +677,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
);
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10);
num_accum_samps += num_samps_ret;
@@ -690,7 +690,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK_EQUAL(metadata.fragment_offset, 10);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, i%10);
num_accum_samps += num_samps_ret;
}
diff --git a/host/tests/sph_send_test.cpp b/host/tests/sph_send_test.cpp
index 25a3f97ee..c31399d12 100644
--- a/host/tests/sph_send_test.cpp
+++ b/host/tests/sph_send_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -136,9 +136,7 @@ BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_one_packet_mode){
std::cout << "data check " << i << std::endl;
dummy_send_xport.pop_front_packet(ifpi);
BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 10+i%10);
- BOOST_CHECK(ifpi.has_tsi);
BOOST_CHECK(ifpi.has_tsf);
- BOOST_CHECK_EQUAL(ifpi.tsi, 0);
BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
@@ -191,9 +189,7 @@ BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_full_buffer_mode){
std::cout << "data check " << i << std::endl;
dummy_send_xport.pop_front_packet(ifpi);
BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 20);
- BOOST_CHECK(ifpi.has_tsi);
BOOST_CHECK(ifpi.has_tsf);
- BOOST_CHECK_EQUAL(ifpi.tsi, 0);
BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp
index 467da5c18..102b7cda3 100644
--- a/host/tests/time_spec_test.cpp
+++ b/host/tests/time_spec_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -54,11 +54,11 @@ BOOST_AUTO_TEST_CASE(test_time_spec_parts){
BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_full_secs(), 1);
BOOST_CHECK_CLOSE(uhd::time_spec_t(1.1).get_frac_secs(), 0.1, 0.001);
- BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_tick_count(100), 10);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).to_ticks(100), 110);
BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_full_secs(), -2);
BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), 0.9, 0.001);
- BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_tick_count(100), 90);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).to_ticks(100), -110);
}
BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){
diff --git a/host/usrp_e_utils/usrp-e-loopback.cpp b/host/usrp_e_utils/usrp-e-loopback.cpp
index 5b289c648..d4220adc3 100644
--- a/host/usrp_e_utils/usrp-e-loopback.cpp
+++ b/host/usrp_e_utils/usrp-e-loopback.cpp
@@ -261,8 +261,7 @@ int main(int argc, char *argv[]){
poke16(E100_REG_MISC_XFER_RATE, (1<<8) | (1<<9));
//clear FIFO state in FPGA and kernel
- poke32(E100_REG_CLEAR_RX, 0);
- poke32(E100_REG_CLEAR_TX, 0);
+ poke32(E100_REG_CLEAR_FIFO, 0);
::close(fp);
if ((fp = ::open("/dev/usrp_e0", O_RDWR)) < 0){
std::cerr << "Open failed" << std::endl;