summaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/convert/CMakeLists.txt13
-rw-r--r--host/lib/convert/convert_common.hpp270
-rw-r--r--host/lib/convert/convert_impl.cpp43
-rw-r--r--host/lib/convert/convert_item32.cpp44
-rw-r--r--host/lib/convert/convert_with_neon.cpp9
-rw-r--r--host/lib/convert/gen_convert_general.py72
-rw-r--r--host/lib/convert/sse2_fc32_to_sc16.cpp103
-rw-r--r--host/lib/convert/sse2_fc32_to_sc8.cpp (renamed from host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp)59
-rw-r--r--host/lib/convert/sse2_fc64_to_sc16.cpp111
-rw-r--r--host/lib/convert/sse2_fc64_to_sc8.cpp (renamed from host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp)53
-rw-r--r--host/lib/convert/sse2_sc16_to_fc32.cpp (renamed from host/lib/convert/convert_fc32_with_sse2.cpp)99
-rw-r--r--host/lib/convert/sse2_sc16_to_fc64.cpp (renamed from host/lib/convert/convert_fc64_with_sse2.cpp)103
-rw-r--r--host/lib/convert/sse2_sc8_to_fc32.cpp132
-rw-r--r--host/lib/convert/sse2_sc8_to_fc64.cpp151
-rw-r--r--host/lib/transport/CMakeLists.txt7
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp47
-rw-r--r--host/lib/transport/simple_claimer.hpp64
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp14
-rw-r--r--host/lib/transport/udp_wsa_zero_copy.cpp300
-rw-r--r--host/lib/transport/udp_zero_copy.cpp139
-rw-r--r--host/lib/transport/usb_zero_copy_wrapper.cpp153
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp25
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp3
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp39
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt1
-rw-r--r--host/lib/usrp/cores/gpio_core_200.cpp8
-rw-r--r--host/lib/usrp/cores/i2c_core_200.cpp158
-rw-r--r--host/lib/usrp/cores/i2c_core_200.hpp35
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp12
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp6
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp30
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp2
-rw-r--r--host/lib/usrp/dboard/db_dbsrx2.cpp4
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp24
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.cpp33
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.hpp3
-rw-r--r--host/lib/usrp/dboard/db_sbx_version3.cpp20
-rw-r--r--host/lib/usrp/dboard/db_sbx_version4.cpp18
-rw-r--r--host/lib/usrp/dboard/db_tvrx.cpp4
-rw-r--r--host/lib/usrp/dboard/db_tvrx2.cpp4
-rw-r--r--host/lib/usrp/dboard/db_wbx_simple.cpp9
-rw-r--r--host/lib/usrp/dboard/db_wbx_version2.cpp29
-rw-r--r--host/lib/usrp/dboard/db_wbx_version3.cpp29
-rw-r--r--host/lib/usrp/dboard/db_wbx_version4.cpp27
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp6
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp20
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp3
-rw-r--r--host/lib/usrp/e100/e100_mmap_zero_copy.cpp45
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp101
-rw-r--r--host/lib/usrp/multi_usrp.cpp83
-rw-r--r--host/lib/usrp/usrp1/codec_ctrl.cpp9
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp12
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp16
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp2
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt3
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp13
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.hpp7
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp14
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp7
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp48
-rw-r--r--host/lib/usrp/usrp2/fw_common.h19
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp57
-rw-r--r--host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp244
-rw-r--r--host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp47
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp101
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp11
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp128
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp19
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp4
-rw-r--r--host/lib/utils/images.cpp18
-rw-r--r--host/lib/utils/log.cpp47
-rw-r--r--host/lib/utils/paths.cpp39
73 files changed, 2599 insertions, 1037 deletions
diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt
index c42a0a434..0d9d0983f 100644
--- a/host/lib/convert/CMakeLists.txt
+++ b/host/lib/convert/CMakeLists.txt
@@ -71,10 +71,14 @@ UNSET(CMAKE_REQUIRED_FLAGS)
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
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_sc16_to_fc64.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_sc16_to_fc32.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_sc8_to_fc64.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_sc8_to_fc32.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_fc64_to_sc16.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_fc32_to_sc16.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_fc64_to_sc8.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sse2_fc32_to_sc8.cpp
)
SET_SOURCE_FILES_PROPERTIES(
${convert_with_sse2_sources}
@@ -117,4 +121,5 @@ LIBUHD_PYTHON_GEN_SOURCE(
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/convert_with_tables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/convert_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_item32.cpp
)
diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp
index 7626e4d87..933978a8f 100644
--- a/host/lib/convert/convert_common.hpp
+++ b/host/lib/convert/convert_common.hpp
@@ -53,12 +53,12 @@ static const int PRIORITY_EMPTY = -1;
#ifdef __ARM_NEON__
static const int PRIORITY_LIBORC = 3;
-static const int PRIORITY_SIMD = 1; //neon conversions could be implemented better, orc wins
-static const int PRIORITY_TABLE = 2; //tables require large cache, so they are slower on arm
+static const int PRIORITY_SIMD = 2; //neon conversions could be implemented better, orc wins
+static const int PRIORITY_TABLE = 1; //tables require large cache, so they are slower on arm
#else
-static const int PRIORITY_LIBORC = 1;
+static const int PRIORITY_LIBORC = 2;
static const int PRIORITY_SIMD = 3;
-static const int PRIORITY_TABLE = 2;
+static const int PRIORITY_TABLE = 1;
#endif
/***********************************************************************
@@ -77,123 +77,92 @@ typedef boost::int8_t s8_t;
typedef boost::uint32_t item32_t;
-/***********************************************************************
- * Convert complex short buffer to items32 sc16
- **********************************************************************/
-static UHD_INLINE item32_t sc16_to_item32_sc16(sc16_t num, double){
- boost::uint16_t real = num.real();
- boost::uint16_t imag = num.imag();
- return (item32_t(real) << 16) | (item32_t(imag) << 0);
-}
+typedef item32_t (*xtox_t)(item32_t);
/***********************************************************************
- * Convert items32 sc16 buffer to complex short
+ * Convert xx to items32 sc16 buffer
**********************************************************************/
-static UHD_INLINE sc16_t item32_sc16_to_sc16(item32_t item, double){
- return sc16_t(
- boost::int16_t(item >> 16),
- boost::int16_t(item >> 0)
- );
-}
-
-/***********************************************************************
- * Convert complex float buffer to items32 sc16
- **********************************************************************/
-static UHD_INLINE item32_t fc32_to_item32_sc16(fc32_t num, double scale_factor){
+template <typename T> UHD_INLINE item32_t xx_to_item32_sc16_x1(
+ const std::complex<T> &num, const double scale_factor
+){
boost::uint16_t real = boost::int16_t(num.real()*float(scale_factor));
boost::uint16_t imag = boost::int16_t(num.imag()*float(scale_factor));
return (item32_t(real) << 16) | (item32_t(imag) << 0);
}
-/***********************************************************************
- * Convert items32 sc16 buffer to complex float
- **********************************************************************/
-static UHD_INLINE fc32_t item32_sc16_to_fc32(item32_t item, double scale_factor){
- return fc32_t(
- float(boost::int16_t(item >> 16)*float(scale_factor)),
- float(boost::int16_t(item >> 0)*float(scale_factor))
- );
-}
-
-/***********************************************************************
- * Convert complex double buffer to items32 sc16
- **********************************************************************/
-static UHD_INLINE item32_t fc64_to_item32_sc16(fc64_t num, double scale_factor){
- boost::uint16_t real = boost::int16_t(num.real()*scale_factor);
- boost::uint16_t imag = boost::int16_t(num.imag()*scale_factor);
+template <> UHD_INLINE item32_t xx_to_item32_sc16_x1(
+ const sc16_t &num, const double
+){
+ boost::uint16_t real = boost::int16_t(num.real());
+ boost::uint16_t imag = boost::int16_t(num.imag());
return (item32_t(real) << 16) | (item32_t(imag) << 0);
}
-/***********************************************************************
- * Convert items32 sc16 buffer to complex double
- **********************************************************************/
-static UHD_INLINE fc64_t item32_sc16_to_fc64(item32_t item, double scale_factor){
- return fc64_t(
- float(boost::int16_t(item >> 16)*scale_factor),
- float(boost::int16_t(item >> 0)*scale_factor)
- );
+template <xtox_t to_wire, typename T>
+UHD_INLINE void xx_to_item32_sc16(
+ const std::complex<T> *input,
+ item32_t *output,
+ const size_t nsamps,
+ const double scale_factor
+){
+ for (size_t i = 0; i < nsamps; i++){
+ const item32_t item = xx_to_item32_sc16_x1(input[i], scale_factor);
+ output[i] = to_wire(item);
+ }
}
/***********************************************************************
- * Convert items32 sc8 buffer to complex char
+ * Convert items32 sc16 buffer to xx
**********************************************************************/
-static UHD_INLINE void item32_sc8_to_sc8(item32_t item, sc8_t &out0, sc8_t &out1, double){
- out0 = sc8_t(
- boost::int8_t(item >> 8),
- boost::int8_t(item >> 0)
- );
- out1 = sc8_t(
- boost::int8_t(item >> 24),
- boost::int8_t(item >> 16)
+template <typename T> UHD_INLINE std::complex<T> item32_sc16_x1_to_xx(
+ const item32_t item, const double scale_factor
+){
+ return std::complex<T>(
+ T(boost::int16_t(item >> 16)*float(scale_factor)),
+ T(boost::int16_t(item >> 0)*float(scale_factor))
);
}
-/***********************************************************************
- * Convert items32 sc8 buffer to complex short
- **********************************************************************/
-static UHD_INLINE void item32_sc8_to_sc16(item32_t item, sc16_t &out0, sc16_t &out1, double){
- out0 = sc16_t(
- boost::int8_t(item >> 8),
- boost::int8_t(item >> 0)
- );
- out1 = sc16_t(
- boost::int8_t(item >> 24),
- boost::int8_t(item >> 16)
+template <> UHD_INLINE sc16_t item32_sc16_x1_to_xx(
+ const item32_t item, const double
+){
+ return sc16_t(
+ boost::int16_t(item >> 16), boost::int16_t(item >> 0)
);
}
-/***********************************************************************
- * Convert items32 sc8 buffer to complex float
- **********************************************************************/
-static UHD_INLINE void item32_sc8_to_fc32(item32_t item, fc32_t &out0, fc32_t &out1, double scale_factor){
- out0 = fc32_t(
- float(boost::int8_t(item >> 8)*float(scale_factor)),
- float(boost::int8_t(item >> 0)*float(scale_factor))
- );
- out1 = fc32_t(
- float(boost::int8_t(item >> 24)*float(scale_factor)),
- float(boost::int8_t(item >> 16)*float(scale_factor))
- );
+template <xtox_t to_host, typename T>
+UHD_INLINE void item32_sc16_to_xx(
+ const item32_t *input,
+ std::complex<T> *output,
+ const size_t nsamps,
+ const double scale_factor
+){
+ for (size_t i = 0; i < nsamps; i++){
+ const item32_t item_i = to_host(input[i]);
+ output[i] = item32_sc16_x1_to_xx<T>(item_i, scale_factor);
+ }
}
/***********************************************************************
- * Convert items32 sc8 buffer to complex double
+ * Convert xx to items32 sc8 buffer
**********************************************************************/
-static UHD_INLINE void item32_sc8_to_fc64(item32_t item, fc64_t &out0, fc64_t &out1, double scale_factor){
- out0 = fc64_t(
- float(boost::int8_t(item >> 8)*scale_factor),
- float(boost::int8_t(item >> 0)*scale_factor)
- );
- out1 = fc64_t(
- float(boost::int8_t(item >> 24)*scale_factor),
- float(boost::int8_t(item >> 16)*scale_factor)
- );
+template <typename T> UHD_INLINE item32_t xx_to_item32_sc8_x1(
+ const std::complex<T> &in0, const std::complex<T> &in1, const double scale_factor
+){
+ boost::uint8_t real0 = boost::int8_t(in0.real()*float(scale_factor));
+ boost::uint8_t imag0 = boost::int8_t(in0.imag()*float(scale_factor));
+ boost::uint8_t real1 = boost::int8_t(in1.real()*float(scale_factor));
+ boost::uint8_t imag1 = boost::int8_t(in1.imag()*float(scale_factor));
+ return
+ (item32_t(real0) << 8) | (item32_t(imag0) << 0) |
+ (item32_t(real1) << 24) | (item32_t(imag1) << 16)
+ ;
}
-/***********************************************************************
- * Convert complex char to items32 sc8 buffer
- **********************************************************************/
-static UHD_INLINE item32_t sc8_to_item32_sc8(sc8_t in0, sc8_t in1, double){
+template <> UHD_INLINE item32_t xx_to_item32_sc8_x1(
+ const sc16_t &in0, const sc16_t &in1, const double
+){
boost::uint8_t real0 = boost::int8_t(in0.real());
boost::uint8_t imag0 = boost::int8_t(in0.imag());
boost::uint8_t real1 = boost::int8_t(in1.real());
@@ -204,10 +173,9 @@ static UHD_INLINE item32_t sc8_to_item32_sc8(sc8_t in0, sc8_t in1, double){
;
}
-/***********************************************************************
- * Convert complex short to items32 sc8 buffer
- **********************************************************************/
-static UHD_INLINE item32_t sc16_to_item32_sc8(sc16_t in0, sc16_t in1, double){
+template <> UHD_INLINE item32_t xx_to_item32_sc8_x1(
+ const sc8_t &in0, const sc8_t &in1, const double
+){
boost::uint8_t real0 = boost::int8_t(in0.real());
boost::uint8_t imag0 = boost::int8_t(in0.imag());
boost::uint8_t real1 = boost::int8_t(in1.real());
@@ -218,32 +186,94 @@ static UHD_INLINE item32_t sc16_to_item32_sc8(sc16_t in0, sc16_t in1, double){
;
}
-/***********************************************************************
- * 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){
- boost::uint8_t real0 = boost::int8_t(in0.real()*float(scale_factor));
- boost::uint8_t imag0 = boost::int8_t(in0.imag()*float(scale_factor));
- boost::uint8_t real1 = boost::int8_t(in1.real()*float(scale_factor));
- boost::uint8_t imag1 = boost::int8_t(in1.imag()*float(scale_factor));
- return
- (item32_t(real0) << 8) | (item32_t(imag0) << 0) |
- (item32_t(real1) << 24) | (item32_t(imag1) << 16)
- ;
+template <xtox_t to_wire, typename T>
+UHD_INLINE void xx_to_item32_sc8(
+ const std::complex<T> *input,
+ item32_t *output,
+ const size_t nsamps,
+ const double scale_factor
+){
+ const size_t num_pairs = nsamps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ const item32_t item = xx_to_item32_sc8_x1(input[j], input[j+1], scale_factor);
+ output[i] = to_wire(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = xx_to_item32_sc8_x1(input[nsamps-1], std::complex<T>(0), scale_factor);
+ output[num_pairs] = to_wire(item);
+ }
}
/***********************************************************************
- * Convert complex double to items32 sc8 buffer
+ * Convert items32 sc8 buffer to xx
**********************************************************************/
-static UHD_INLINE item32_t fc64_to_item32_sc8(fc64_t in0, fc64_t in1, double scale_factor){
- boost::uint8_t real0 = boost::int8_t(in0.real()*(scale_factor));
- boost::uint8_t imag0 = boost::int8_t(in0.imag()*(scale_factor));
- boost::uint8_t real1 = boost::int8_t(in1.real()*(scale_factor));
- boost::uint8_t imag1 = boost::int8_t(in1.imag()*(scale_factor));
- return
- (item32_t(real0) << 8) | (item32_t(imag0) << 0) |
- (item32_t(real1) << 24) | (item32_t(imag1) << 16)
- ;
+template <typename T> UHD_INLINE void item32_sc8_x1_to_xx(
+ const item32_t item, std::complex<T> &out0, std::complex<T> &out1, const double scale_factor
+){
+ out0 = std::complex<T>(
+ T(boost::int8_t(item >> 8)*float(scale_factor)),
+ T(boost::int8_t(item >> 0)*float(scale_factor))
+ );
+ out1 = std::complex<T>(
+ T(boost::int8_t(item >> 24)*float(scale_factor)),
+ T(boost::int8_t(item >> 16)*float(scale_factor))
+ );
+}
+
+template <> UHD_INLINE void item32_sc8_x1_to_xx(
+ const item32_t item, sc16_t &out0, sc16_t &out1, const double
+){
+ out0 = sc16_t(
+ boost::int16_t(boost::int8_t(item >> 8)),
+ boost::int16_t(boost::int8_t(item >> 0))
+ );
+ out1 = sc16_t(
+ boost::int16_t(boost::int8_t(item >> 24)),
+ boost::int16_t(boost::int8_t(item >> 16))
+ );
+}
+
+template <> UHD_INLINE void item32_sc8_x1_to_xx(
+ const item32_t item, sc8_t &out0, sc8_t &out1, const double
+){
+ out0 = sc8_t(
+ boost::int8_t(boost::int8_t(item >> 8)),
+ boost::int8_t(boost::int8_t(item >> 0))
+ );
+ out1 = sc8_t(
+ boost::int8_t(boost::int8_t(item >> 24)),
+ boost::int8_t(boost::int8_t(item >> 16))
+ );
+}
+
+template <xtox_t to_host, typename T>
+UHD_INLINE void item32_sc8_to_xx(
+ const item32_t *input,
+ std::complex<T> *output,
+ const size_t nsamps,
+ const double scale_factor
+){
+ input = reinterpret_cast<const item32_t *>(size_t(input) & ~0x3);
+ std::complex<T> dummy;
+ size_t num_samps = nsamps;
+
+ if ((size_t(input) & 0x3) != 0){
+ const item32_t item0 = to_host(*input++);
+ item32_sc8_x1_to_xx(item0, dummy, *output++, scale_factor);
+ num_samps--;
+ }
+
+ const size_t num_pairs = num_samps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ const item32_t item_i = to_host(input[i]);
+ item32_sc8_x1_to_xx(item_i, output[j], output[j+1], scale_factor);
+ }
+
+ if (num_samps != num_pairs*2){
+ const item32_t item_n = to_host(input[num_pairs]);
+ item32_sc8_x1_to_xx(item_n, output[num_samps-1], dummy, scale_factor);
+ }
}
#endif /* INCLUDED_LIBUHD_CONVERT_COMMON_HPP */
diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp
index 12ad54486..dc7f8f9dc 100644
--- a/host/lib/convert/convert_impl.cpp
+++ b/host/lib/convert/convert_impl.cpp
@@ -22,6 +22,7 @@
#include <uhd/exception.hpp>
#include <boost/cstdint.hpp>
#include <boost/format.hpp>
+#include <boost/foreach.hpp>
#include <complex>
using namespace uhd;
@@ -51,17 +52,9 @@ std::string convert::id_type::to_pp_string(void) const{
}
/***********************************************************************
- * Define types for the function tables
- **********************************************************************/
-struct fcn_table_entry_type{
- convert::priority_type prio;
- convert::function_type fcn;
-};
-
-/***********************************************************************
* Setup the table registry
**********************************************************************/
-typedef uhd::dict<convert::id_type, fcn_table_entry_type> fcn_table_type;
+typedef uhd::dict<convert::id_type, uhd::dict<convert::priority_type, convert::function_type> > fcn_table_type;
UHD_SINGLETON_FCN(fcn_table_type, get_table);
/***********************************************************************
@@ -72,14 +65,7 @@ void uhd::convert::register_converter(
const function_type &fcn,
const priority_type prio
){
- //get a reference to the function table
- fcn_table_type &table = get_table();
-
- //register the function if higher priority
- if (not table.has_key(id) or table[id].prio < prio){
- table[id].fcn = fcn;
- table[id].prio = prio;
- }
+ get_table()[id][prio] = fcn;
//----------------------------------------------------------------//
UHD_LOGV(always) << "register_converter: " << id.to_pp_string() << std::endl
@@ -92,9 +78,26 @@ void uhd::convert::register_converter(
/***********************************************************************
* The converter functions
**********************************************************************/
-convert::function_type convert::get_converter(const id_type &id){
- if (get_table().has_key(id)) return get_table()[id].fcn;
- throw uhd::key_error("Cannot find a conversion routine for " + id.to_pp_string());
+convert::function_type convert::get_converter(
+ const id_type &id,
+ const priority_type prio
+){
+ if (not get_table().has_key(id)) throw uhd::key_error(
+ "Cannot find a conversion routine for " + id.to_pp_string());
+
+ //find a matching priority
+ priority_type best_prio = -1;
+ BOOST_FOREACH(priority_type prio_i, get_table()[id].keys()){
+ if (prio_i == prio) return get_table()[id][prio];
+ best_prio = std::max(best_prio, prio_i);
+ }
+
+ //wanted a specific prio, didnt find
+ if (prio != -1) throw uhd::key_error(
+ "Cannot find a conversion routine [with prio] for " + id.to_pp_string());
+
+ //otherwise, return best prio
+ return get_table()[id][best_prio];
}
/***********************************************************************
diff --git a/host/lib/convert/convert_item32.cpp b/host/lib/convert/convert_item32.cpp
new file mode 100644
index 000000000..57bd64860
--- /dev/null
+++ b/host/lib/convert/convert_item32.cpp
@@ -0,0 +1,44 @@
+//
+// 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>
+
+#define __DECLARE_ITEM32_CONVERTER(cpu_type, wire_type, xe, htoxx, xxtoh) \
+ DECLARE_CONVERTER(cpu_type, 1, wire_type ## _item32_ ## xe, 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]); \
+ xx_to_item32_ ## wire_type<htoxx>(input, output, nsamps, scale_factor); \
+ } \
+ DECLARE_CONVERTER(wire_type ## _item32_ ## xe, 1, cpu_type, 1, PRIORITY_GENERAL){ \
+ const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); \
+ cpu_type ## _t *output = reinterpret_cast<cpu_type ## _t *>(outputs[0]); \
+ item32_ ## wire_type ## _to_xx<xxtoh>(input, output, nsamps, scale_factor); \
+ }
+
+#define _DECLARE_ITEM32_CONVERTER(cpu_type, wire_type) \
+ __DECLARE_ITEM32_CONVERTER(cpu_type, wire_type, be, uhd::htonx, uhd::ntohx) \
+ __DECLARE_ITEM32_CONVERTER(cpu_type, wire_type, le, uhd::htowx, uhd::wtohx)
+
+#define DECLARE_ITEM32_CONVERTER(cpu_type) \
+ _DECLARE_ITEM32_CONVERTER(cpu_type, sc8) \
+ _DECLARE_ITEM32_CONVERTER(cpu_type, sc16)
+
+DECLARE_ITEM32_CONVERTER(sc16)
+DECLARE_ITEM32_CONVERTER(fc32)
+DECLARE_ITEM32_CONVERTER(fc64)
+_DECLARE_ITEM32_CONVERTER(sc8, sc8)
diff --git a/host/lib/convert/convert_with_neon.cpp b/host/lib/convert/convert_with_neon.cpp
index c7ad62104..e994d97a6 100644
--- a/host/lib/convert/convert_with_neon.cpp
+++ b/host/lib/convert/convert_with_neon.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
@@ -16,6 +16,7 @@
//
#include "convert_common.hpp"
+#include <uhd/utils/byteswap.hpp>
#include <arm_neon.h>
using namespace uhd::convert;
@@ -36,8 +37,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
vst1_s16((reinterpret_cast<int16_t *>(&output[i])), D9);
}
- for (; i < nsamps; i++)
- output[i] = fc32_to_item32_sc16(input[i], scale_factor);
+ xx_to_item32_sc16<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
@@ -56,6 +56,5 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
vst1q_f32((reinterpret_cast<float *>(&output[i])), Q4);
}
- for (; i < nsamps; i++)
- output[i] = item32_sc16_to_fc32(input[i], scale_factor);
+ item32_sc16_to_xx<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py
index 364c4bd1a..b0790755a 100644
--- a/host/lib/convert/gen_convert_general.py
+++ b/host/lib/convert/gen_convert_general.py
@@ -48,68 +48,6 @@ DECLARE_CONVERTER(sc16_item32_$(end), 1, item32, 1, PRIORITY_GENERAL){
}
"""
-TMPL_CONV_GEN2_SC16 = """
-DECLARE_CONVERTER($(cpu_type), 1, sc16_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]);
-
- for (size_t i = 0; i < nsamps; i++){
- output[i] = $(to_wire)($(cpu_type)_to_item32_sc16(input[i], scale_factor));
- }
-}
-
-DECLARE_CONVERTER(sc16_item32_$(end), 1, $(cpu_type), 1, PRIORITY_GENERAL){
- const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);
- $(cpu_type)_t *output = reinterpret_cast<$(cpu_type)_t *>(outputs[0]);
-
- for (size_t i = 0; i < nsamps; i++){
- output[i] = item32_sc16_to_$(cpu_type)($(to_host)(input[i]), scale_factor);
- }
-}
-"""
-
-TMPL_CONV_GEN2_SC8 = """
-DECLARE_CONVERTER(sc8_item32_$(end), 1, $(cpu_type), 1, PRIORITY_GENERAL){
- const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
- $(cpu_type)_t *output = reinterpret_cast<$(cpu_type)_t *>(outputs[0]);
- $(cpu_type)_t dummy;
- size_t num_samps = nsamps;
-
- if ((size_t(inputs[0]) & 0x3) != 0){
- const item32_t item0 = $(to_host)(*input++);
- item32_sc8_to_$(cpu_type)(item0, dummy, *output++, scale_factor);
- num_samps--;
- }
-
- const size_t num_pairs = num_samps/2;
- for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
- const item32_t item_i = $(to_host)(input[i]);
- item32_sc8_to_$(cpu_type)(item_i, output[j], output[j+1], scale_factor);
- }
-
- if (num_samps != num_pairs*2){
- const item32_t item_n = $(to_host)(input[num_pairs]);
- 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 = """
DECLARE_CONVERTER($(cpu_type), $(width), sc16_item16_usrp1, 1, PRIORITY_GENERAL){
#for $w in range($width)
@@ -176,16 +114,6 @@ if __name__ == '__main__':
('be', 'uhd::ntohx', 'uhd::htonx'),
('le', 'uhd::wtohx', 'uhd::htowx'),
):
- for cpu_type in 'fc64', 'fc32', 'sc16':
- output += parse_tmpl(
- TMPL_CONV_GEN2_SC16,
- end=end, to_host=to_host, to_wire=to_wire, cpu_type=cpu_type
- )
- for cpu_type in 'fc64', 'fc32', 'sc16', 'sc8':
- output += parse_tmpl(
- TMPL_CONV_GEN2_SC8,
- end=end, to_host=to_host, to_wire=to_wire, cpu_type=cpu_type
- )
output += parse_tmpl(
TMPL_CONV_GEN2_ITEM32,
end=end, to_host=to_host, to_wire=to_wire
diff --git a/host/lib/convert/sse2_fc32_to_sc16.cpp b/host/lib/convert/sse2_fc32_to_sc16.cpp
new file mode 100644
index 000000000..90bf0ed04
--- /dev/null
+++ b/host/lib/convert/sse2_fc32_to_sc16.cpp
@@ -0,0 +1,103 @@
+//
+// 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
+// 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;
+
+DECLARE_CONVERTER(fc32, 1, sc16_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_item32_1_nswap_guts(_al_) \
+ 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)); \
+ \
+ /* convert and scale */ \
+ __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); \
+ __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); \
+ \
+ /* pack + swap 16-bit pairs */ \
+ __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
+ tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
+ tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ switch (size_t(input) & 0xf){
+ case 0x8:
+ xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor); i++;
+ case 0x0:
+ convert_fc32_1_to_item32_1_nswap_guts(_)
+ break;
+ default: convert_fc32_1_to_item32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ xx_to_item32_sc16<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
+}
+
+DECLARE_CONVERTER(fc32, 1, sc16_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_item32_1_bswap_guts(_al_) \
+ 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)); \
+ \
+ /* convert and scale */ \
+ __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); \
+ __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); \
+ \
+ /* pack + byteswap -> byteswap 16 bit words */ \
+ __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
+ tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ switch (size_t(input) & 0xf){
+ case 0x8:
+ xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor); i++;
+ case 0x0:
+ convert_fc32_1_to_item32_1_bswap_guts(_)
+ break;
+ default: convert_fc32_1_to_item32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ xx_to_item32_sc16<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
+}
diff --git a/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp b/host/lib/convert/sse2_fc32_to_sc8.cpp
index b633f487c..dd884640d 100644
--- a/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp
+++ b/host/lib/convert/sse2_fc32_to_sc8.cpp
@@ -21,41 +21,22 @@
using namespace uhd::convert;
-UHD_INLINE __m128i pack_sc32_4x_be(
+template <const int shuf>
+UHD_INLINE __m128i pack_sc32_4x(
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));
+ tmpi0 = _mm_shuffle_epi32(tmpi0, shuf);
__m128i tmpi1 = _mm_cvtps_epi32(_mm_mul_ps(in1, scalar));
- tmpi1 = _mm_shuffle_epi32(tmpi1, _MM_SHUFFLE(1, 0, 3, 2));
+ tmpi1 = _mm_shuffle_epi32(tmpi1, shuf);
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));
+ tmpi2 = _mm_shuffle_epi32(tmpi2, shuf);
__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));
+ tmpi3 = _mm_shuffle_epi32(tmpi3, shuf);
const __m128i hi = _mm_packs_epi32(tmpi2, tmpi3);
return _mm_packs_epi16(lo, hi);
@@ -66,6 +47,7 @@ DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_SIMD){
item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
const __m128 scalar = _mm_set_ps1(float(scale_factor));
+ const int shuf = _MM_SHUFFLE(1, 0, 3, 2);
#define convert_fc32_1_to_sc8_item32_1_bswap_guts(_al_) \
for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
@@ -76,7 +58,7 @@ DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_SIMD){
__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); \
+ const __m128i tmpi = pack_sc32_4x<shuf>(tmp0, tmp1, tmp2, tmp3, scalar); \
\
/* store to output */ \
_mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
@@ -93,16 +75,7 @@ DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_SIMD){
}
//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);
- }
+ xx_to_item32_sc8<uhd::htonx>(input+i, output+(i/2), nsamps-i, scale_factor);
}
DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_SIMD){
@@ -110,6 +83,7 @@ DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_SIMD){
item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
const __m128 scalar = _mm_set_ps1(float(scale_factor));
+ const int shuf = _MM_SHUFFLE(2, 3, 0, 1);
#define convert_fc32_1_to_sc8_item32_1_nswap_guts(_al_) \
for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
@@ -120,7 +94,7 @@ DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_SIMD){
__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); \
+ const __m128i tmpi = pack_sc32_4x<shuf>(tmp0, tmp1, tmp2, tmp3, scalar); \
\
/* store to output */ \
_mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
@@ -137,14 +111,5 @@ DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_SIMD){
}
//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);
- }
+ xx_to_item32_sc8<uhd::htowx>(input+i, output+(i/2), nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/sse2_fc64_to_sc16.cpp b/host/lib/convert/sse2_fc64_to_sc16.cpp
new file mode 100644
index 000000000..f030e9168
--- /dev/null
+++ b/host/lib/convert/sse2_fc64_to_sc16.cpp
@@ -0,0 +1,111 @@
+//
+// 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
+// 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;
+
+DECLARE_CONVERTER(fc64, 1, sc16_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_item32_1_nswap_guts(_al_) \
+ 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)); \
+ __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)); \
+ \
+ /* convert and scale */ \
+ __m128i tmpi0 = _mm_cvttpd_epi32(_mm_mul_pd(tmp0, scalar)); \
+ __m128i tmpi1 = _mm_cvttpd_epi32(_mm_mul_pd(tmp1, scalar)); \
+ __m128i tmpilo = _mm_unpacklo_epi64(tmpi0, tmpi1); \
+ __m128i tmpi2 = _mm_cvttpd_epi32(_mm_mul_pd(tmp2, scalar)); \
+ __m128i tmpi3 = _mm_cvttpd_epi32(_mm_mul_pd(tmp3, scalar)); \
+ __m128i tmpihi = _mm_unpacklo_epi64(tmpi2, tmpi3); \
+ \
+ /* pack + swap 16-bit pairs */ \
+ __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
+ tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
+ tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc64_1_to_item32_1_nswap_guts(_)
+ }
+ else{
+ convert_fc64_1_to_item32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ xx_to_item32_sc16<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
+}
+
+DECLARE_CONVERTER(fc64, 1, sc16_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_item32_1_bswap_guts(_al_) \
+ 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)); \
+ __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)); \
+ \
+ /* convert and scale */ \
+ __m128i tmpi0 = _mm_cvttpd_epi32(_mm_mul_pd(tmp0, scalar)); \
+ __m128i tmpi1 = _mm_cvttpd_epi32(_mm_mul_pd(tmp1, scalar)); \
+ __m128i tmpilo = _mm_unpacklo_epi64(tmpi0, tmpi1); \
+ __m128i tmpi2 = _mm_cvttpd_epi32(_mm_mul_pd(tmp2, scalar)); \
+ __m128i tmpi3 = _mm_cvttpd_epi32(_mm_mul_pd(tmp3, scalar)); \
+ __m128i tmpihi = _mm_unpacklo_epi64(tmpi2, tmpi3); \
+ \
+ /* pack + byteswap -> byteswap 16 bit words */ \
+ __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
+ tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc64_1_to_item32_1_bswap_guts(_)
+ }
+ else{
+ convert_fc64_1_to_item32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ xx_to_item32_sc16<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
+}
diff --git a/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp b/host/lib/convert/sse2_fc64_to_sc8.cpp
index 405850601..bf3719e13 100644
--- a/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp
+++ b/host/lib/convert/sse2_fc64_to_sc8.cpp
@@ -30,7 +30,7 @@ UHD_INLINE __m128i pack_sc8_item32_4x(
return _mm_packs_epi16(lo, hi);
}
-UHD_INLINE __m128i pack_sc32_4x_be(
+UHD_INLINE __m128i pack_sc32_4x(
const __m128d &lo, const __m128d &hi,
const __m128d &scalar
){
@@ -39,16 +39,6 @@ UHD_INLINE __m128i pack_sc32_4x_be(
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]);
@@ -69,10 +59,10 @@ DECLARE_CONVERTER(fc64, 1, sc8_item32_be, 1, PRIORITY_SIMD){
\
/* 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) \
+ pack_sc32_4x(tmp0, tmp1, scalar), \
+ pack_sc32_4x(tmp2, tmp3, scalar), \
+ pack_sc32_4x(tmp4, tmp5, scalar), \
+ pack_sc32_4x(tmp6, tmp7, scalar) \
); \
\
/* store to output */ \
@@ -90,16 +80,7 @@ DECLARE_CONVERTER(fc64, 1, sc8_item32_be, 1, PRIORITY_SIMD){
}
//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);
- }
+ xx_to_item32_sc8<uhd::htonx>(input+i, output+(i/2), nsamps-i, scale_factor);
}
DECLARE_CONVERTER(fc64, 1, sc8_item32_le, 1, PRIORITY_SIMD){
@@ -121,12 +102,13 @@ DECLARE_CONVERTER(fc64, 1, sc8_item32_le, 1, PRIORITY_SIMD){
__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) \
+ __m128i tmpi = pack_sc8_item32_4x( \
+ pack_sc32_4x(tmp1, tmp0, scalar), \
+ pack_sc32_4x(tmp3, tmp2, scalar), \
+ pack_sc32_4x(tmp5, tmp4, scalar), \
+ pack_sc32_4x(tmp7, tmp6, scalar) \
); \
+ tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); /*byteswap*/\
\
/* store to output */ \
_mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
@@ -143,14 +125,5 @@ DECLARE_CONVERTER(fc64, 1, sc8_item32_le, 1, PRIORITY_SIMD){
}
//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);
- }
+ xx_to_item32_sc8<uhd::htowx>(input+i, output+(i/2), nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/convert_fc32_with_sse2.cpp b/host/lib/convert/sse2_sc16_to_fc32.cpp
index 97a3e8cdc..c03e41585 100644
--- a/host/lib/convert/convert_fc32_with_sse2.cpp
+++ b/host/lib/convert/sse2_sc16_to_fc32.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
@@ -21,91 +21,6 @@
using namespace uhd::convert;
-DECLARE_CONVERTER(fc32, 1, sc16_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_item32_1_nswap_guts(_al_) \
- 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)); \
- \
- /* convert and scale */ \
- __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); \
- __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); \
- \
- /* pack + swap 16-bit pairs */ \
- __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
- tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
- tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
- \
- /* store to output */ \
- _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
- } \
-
- size_t i = 0;
-
- //dispatch according to alignment
- switch (size_t(input) & 0xf){
- case 0x8:
- output[i] = fc32_to_item32_sc16(input[i], float(scale_factor)); i++;
- case 0x0:
- convert_fc32_1_to_item32_1_nswap_guts(_)
- break;
- default: convert_fc32_1_to_item32_1_nswap_guts(u_)
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = fc32_to_item32_sc16(input[i], float(scale_factor));
- }
-}
-
-DECLARE_CONVERTER(fc32, 1, sc16_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_item32_1_bswap_guts(_al_) \
- 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)); \
- \
- /* convert and scale */ \
- __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); \
- __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); \
- \
- /* pack + byteswap -> byteswap 16 bit words */ \
- __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
- tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); \
- \
- /* store to output */ \
- _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
- } \
-
- size_t i = 0;
-
- //dispatch according to alignment
- switch (size_t(input) & 0xf){
- case 0x8:
- output[i] = uhd::byteswap(fc32_to_item32_sc16(input[i], float(scale_factor))); i++;
- case 0x0:
- convert_fc32_1_to_item32_1_bswap_guts(_)
- break;
- default: convert_fc32_1_to_item32_1_bswap_guts(u_)
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = uhd::byteswap(fc32_to_item32_sc16(input[i], float(scale_factor)));
- }
-}
-
DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);
fc32_t *output = reinterpret_cast<fc32_t *>(outputs[0]);
@@ -138,7 +53,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
//dispatch according to alignment
switch (size_t(output) & 0xf){
case 0x8:
- output[i] = item32_sc16_to_fc32(input[i], float(scale_factor)); i++;
+ item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor); i++;
case 0x0:
convert_item32_1_to_fc32_1_nswap_guts(_)
break;
@@ -146,9 +61,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
}
//convert remainder
- for (; i < nsamps; i++){
- output[i] = item32_sc16_to_fc32(input[i], float(scale_factor));
- }
+ item32_sc16_to_xx<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
@@ -182,7 +95,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
//dispatch according to alignment
switch (size_t(output) & 0xf){
case 0x8:
- output[i] = item32_sc16_to_fc32(uhd::byteswap(input[i]), float(scale_factor)); i++;
+ item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor); i++;
case 0x0:
convert_item32_1_to_fc32_1_bswap_guts(_)
break;
@@ -190,7 +103,5 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
}
//convert remainder
- for (; i < nsamps; i++){
- output[i] = item32_sc16_to_fc32(uhd::byteswap(input[i]), float(scale_factor));
- }
+ item32_sc16_to_xx<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/convert_fc64_with_sse2.cpp b/host/lib/convert/sse2_sc16_to_fc64.cpp
index 6e097e380..66068cad9 100644
--- a/host/lib/convert/convert_fc64_with_sse2.cpp
+++ b/host/lib/convert/sse2_sc16_to_fc64.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
@@ -21,99 +21,6 @@
using namespace uhd::convert;
-DECLARE_CONVERTER(fc64, 1, sc16_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_item32_1_nswap_guts(_al_) \
- 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)); \
- __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)); \
- \
- /* convert and scale */ \
- __m128i tmpi0 = _mm_cvttpd_epi32(_mm_mul_pd(tmp0, scalar)); \
- __m128i tmpi1 = _mm_cvttpd_epi32(_mm_mul_pd(tmp1, scalar)); \
- __m128i tmpilo = _mm_unpacklo_epi64(tmpi0, tmpi1); \
- __m128i tmpi2 = _mm_cvttpd_epi32(_mm_mul_pd(tmp2, scalar)); \
- __m128i tmpi3 = _mm_cvttpd_epi32(_mm_mul_pd(tmp3, scalar)); \
- __m128i tmpihi = _mm_unpacklo_epi64(tmpi2, tmpi3); \
- \
- /* pack + swap 16-bit pairs */ \
- __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
- tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
- tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); \
- \
- /* store to output */ \
- _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
- } \
-
- size_t i = 0;
-
- //dispatch according to alignment
- if ((size_t(input) & 0xf) == 0){
- convert_fc64_1_to_item32_1_nswap_guts(_)
- }
- else{
- convert_fc64_1_to_item32_1_nswap_guts(u_)
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = fc64_to_item32_sc16(input[i], scale_factor);
- }
-}
-
-DECLARE_CONVERTER(fc64, 1, sc16_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_item32_1_bswap_guts(_al_) \
- 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)); \
- __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)); \
- \
- /* convert and scale */ \
- __m128i tmpi0 = _mm_cvttpd_epi32(_mm_mul_pd(tmp0, scalar)); \
- __m128i tmpi1 = _mm_cvttpd_epi32(_mm_mul_pd(tmp1, scalar)); \
- __m128i tmpilo = _mm_unpacklo_epi64(tmpi0, tmpi1); \
- __m128i tmpi2 = _mm_cvttpd_epi32(_mm_mul_pd(tmp2, scalar)); \
- __m128i tmpi3 = _mm_cvttpd_epi32(_mm_mul_pd(tmp3, scalar)); \
- __m128i tmpihi = _mm_unpacklo_epi64(tmpi2, tmpi3); \
- \
- /* pack + byteswap -> byteswap 16 bit words */ \
- __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); \
- tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); \
- \
- /* store to output */ \
- _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); \
- } \
-
- size_t i = 0;
-
- //dispatch according to alignment
- if ((size_t(input) & 0xf) == 0){
- convert_fc64_1_to_item32_1_bswap_guts(_)
- }
- else{
- convert_fc64_1_to_item32_1_bswap_guts(u_)
- }
-
- //convert remainder
- for (; i < nsamps; i++){
- output[i] = uhd::byteswap(fc64_to_item32_sc16(input[i], scale_factor));
- }
-}
-
DECLARE_CONVERTER(sc16_item32_le, 1, fc64, 1, PRIORITY_SIMD){
const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);
fc64_t *output = reinterpret_cast<fc64_t *>(outputs[0]);
@@ -158,9 +65,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc64, 1, PRIORITY_SIMD){
}
//convert remainder
- for (; i < nsamps; i++){
- output[i] = item32_sc16_to_fc64(input[i], scale_factor);
- }
+ item32_sc16_to_xx<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
DECLARE_CONVERTER(sc16_item32_be, 1, fc64, 1, PRIORITY_SIMD){
@@ -206,7 +111,5 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc64, 1, PRIORITY_SIMD){
}
//convert remainder
- for (; i < nsamps; i++){
- output[i] = item32_sc16_to_fc64(uhd::byteswap(input[i]), scale_factor);
- }
+ item32_sc16_to_xx<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/sse2_sc8_to_fc32.cpp b/host/lib/convert/sse2_sc8_to_fc32.cpp
new file mode 100644
index 000000000..c0e561814
--- /dev/null
+++ b/host/lib/convert/sse2_sc8_to_fc32.cpp
@@ -0,0 +1,132 @@
+//
+// 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;
+
+static const __m128i zeroi = _mm_setzero_si128();
+
+template <const int shuf>
+UHD_INLINE void unpack_sc32_4x(
+ const __m128i &in,
+ __m128 &out0, __m128 &out1,
+ __m128 &out2, __m128 &out3,
+ const __m128 &scalar
+){
+ const __m128i tmplo = _mm_unpacklo_epi8(zeroi, in); /* value in upper 8 bits */
+ __m128i tmp0 = _mm_shuffle_epi32(_mm_unpacklo_epi16(zeroi, tmplo), shuf); /* value in upper 16 bits */
+ __m128i tmp1 = _mm_shuffle_epi32(_mm_unpackhi_epi16(zeroi, tmplo), shuf);
+ out0 = _mm_mul_ps(_mm_cvtepi32_ps(tmp0), scalar);
+ out1 = _mm_mul_ps(_mm_cvtepi32_ps(tmp1), scalar);
+
+ const __m128i tmphi = _mm_unpackhi_epi8(zeroi, in);
+ __m128i tmp2 = _mm_shuffle_epi32(_mm_unpacklo_epi16(zeroi, tmphi), shuf);
+ __m128i tmp3 = _mm_shuffle_epi32(_mm_unpackhi_epi16(zeroi, tmphi), shuf);
+ out2 = _mm_mul_ps(_mm_cvtepi32_ps(tmp2), scalar);
+ out3 = _mm_mul_ps(_mm_cvtepi32_ps(tmp3), scalar);
+}
+
+DECLARE_CONVERTER(sc8_item32_be, 1, fc32, 1, PRIORITY_SIMD){
+ const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
+ fc32_t *output = reinterpret_cast<fc32_t *>(outputs[0]);
+
+ const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 24));
+ const int shuf = _MM_SHUFFLE(1, 0, 3, 2);
+
+ size_t i = 0, j = 0;
+ fc32_t dummy;
+ size_t num_samps = nsamps;
+
+ if ((size_t(inputs[0]) & 0x3) != 0){
+ item32_sc8_to_xx<uhd::ntohx>(input++, output++, 1, scale_factor);
+ num_samps--;
+ }
+
+ #define convert_sc8_item32_1_to_fc32_1_bswap_guts(_al_) \
+ for (; j+7 < num_samps; j+=8, i+=4){ \
+ /* load from input */ \
+ __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
+ \
+ /* unpack + swap 8-bit pairs */ \
+ __m128 tmp0, tmp1, tmp2, tmp3; \
+ unpack_sc32_4x<shuf>(tmpi, tmp0, tmp1, tmp2, tmp3, scalar); \
+ \
+ /* store to output */ \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+0), tmp0); \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+2), tmp1); \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+4), tmp2); \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+6), tmp3); \
+ }
+
+ //dispatch according to alignment
+ if ((size_t(output) & 0xf) == 0){
+ convert_sc8_item32_1_to_fc32_1_bswap_guts(_)
+ }
+ else{
+ convert_sc8_item32_1_to_fc32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ item32_sc8_to_xx<uhd::ntohx>(input+i, output+j, num_samps-j, scale_factor);
+}
+
+DECLARE_CONVERTER(sc8_item32_le, 1, fc32, 1, PRIORITY_SIMD){
+ const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
+ fc32_t *output = reinterpret_cast<fc32_t *>(outputs[0]);
+
+ const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 24));
+ const int shuf = _MM_SHUFFLE(2, 3, 0, 1);
+
+ size_t i = 0, j = 0;
+ fc32_t dummy;
+ size_t num_samps = nsamps;
+
+ if ((size_t(inputs[0]) & 0x3) != 0){
+ item32_sc8_to_xx<uhd::wtohx>(input++, output++, 1, scale_factor);
+ num_samps--;
+ }
+
+ #define convert_sc8_item32_1_to_fc32_1_nswap_guts(_al_) \
+ for (; j+7 < num_samps; j+=8, i+=4){ \
+ /* load from input */ \
+ __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
+ \
+ /* unpack + swap 8-bit pairs */ \
+ __m128 tmp0, tmp1, tmp2, tmp3; \
+ unpack_sc32_4x<shuf>(tmpi, tmp0, tmp1, tmp2, tmp3, scalar); \
+ \
+ /* store to output */ \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+0), tmp0); \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+2), tmp1); \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+4), tmp2); \
+ _mm_store ## _al_ ## ps(reinterpret_cast<float *>(output+j+6), tmp3); \
+ }
+
+ //dispatch according to alignment
+ if ((size_t(output) & 0xf) == 0){
+ convert_sc8_item32_1_to_fc32_1_nswap_guts(_)
+ }
+ else{
+ convert_sc8_item32_1_to_fc32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ item32_sc8_to_xx<uhd::wtohx>(input+i, output+j, num_samps-j, scale_factor);
+}
diff --git a/host/lib/convert/sse2_sc8_to_fc64.cpp b/host/lib/convert/sse2_sc8_to_fc64.cpp
new file mode 100644
index 000000000..ef9c0fdb4
--- /dev/null
+++ b/host/lib/convert/sse2_sc8_to_fc64.cpp
@@ -0,0 +1,151 @@
+//
+// 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;
+
+static const __m128i zeroi = _mm_setzero_si128();
+
+UHD_INLINE void unpack_sc32_8x(
+ const __m128i &in,
+ __m128d &out0, __m128d &out1,
+ __m128d &out2, __m128d &out3,
+ __m128d &out4, __m128d &out5,
+ __m128d &out6, __m128d &out7,
+ const __m128d &scalar
+){
+ const int shuf = _MM_SHUFFLE(1, 0, 3, 2);
+ __m128i tmp;
+
+ const __m128i tmplo = _mm_unpacklo_epi8(zeroi, in); /* value in upper 8 bits */
+ tmp = _mm_unpacklo_epi16(zeroi, tmplo); /* value in upper 16 bits */
+ out0 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+ tmp = _mm_shuffle_epi32(tmp, shuf);
+ out1 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+ tmp = _mm_unpackhi_epi16(zeroi, tmplo);
+ out2 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+ tmp = _mm_shuffle_epi32(tmp, shuf);
+ out3 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+
+ const __m128i tmphi = _mm_unpackhi_epi8(zeroi, in);
+ tmp = _mm_unpacklo_epi16(zeroi, tmphi);
+ out4 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+ tmp = _mm_shuffle_epi32(tmp, shuf);
+ out5 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+ tmp = _mm_unpackhi_epi16(zeroi, tmphi);
+ out6 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+ tmp = _mm_shuffle_epi32(tmp, shuf);
+ out7 = _mm_mul_pd(_mm_cvtepi32_pd(tmp), scalar);
+}
+
+DECLARE_CONVERTER(sc8_item32_be, 1, fc64, 1, PRIORITY_SIMD){
+ const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
+ fc64_t *output = reinterpret_cast<fc64_t *>(outputs[0]);
+
+ const __m128d scalar = _mm_set1_pd(scale_factor/(1 << 24));
+
+ size_t i = 0, j = 0;
+ fc32_t dummy;
+ size_t num_samps = nsamps;
+
+ if ((size_t(inputs[0]) & 0x3) != 0){
+ item32_sc8_to_xx<uhd::ntohx>(input++, output++, 1, scale_factor);
+ num_samps--;
+ }
+
+ #define convert_sc8_item32_1_to_fc64_1_bswap_guts(_al_) \
+ for (; j+7 < num_samps; j+=8, i+=4){ \
+ /* load from input */ \
+ __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
+ \
+ /* unpack */ \
+ __m128d tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; \
+ unpack_sc32_8x(tmpi, tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, scalar); \
+ \
+ /* store to output */ \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+0), tmp0); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+1), tmp1); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+2), tmp2); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+3), tmp3); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+4), tmp4); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+5), tmp5); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+6), tmp6); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+7), tmp7); \
+ }
+
+ //dispatch according to alignment
+ if ((size_t(output) & 0xf) == 0){
+ convert_sc8_item32_1_to_fc64_1_bswap_guts(_)
+ }
+ else{
+ convert_sc8_item32_1_to_fc64_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ item32_sc8_to_xx<uhd::ntohx>(input+i, output+j, num_samps-j, scale_factor);
+}
+
+DECLARE_CONVERTER(sc8_item32_le, 1, fc64, 1, PRIORITY_SIMD){
+ const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
+ fc64_t *output = reinterpret_cast<fc64_t *>(outputs[0]);
+
+ const __m128d scalar = _mm_set1_pd(scale_factor/(1 << 24));
+
+ size_t i = 0, j = 0;
+ fc32_t dummy;
+ size_t num_samps = nsamps;
+
+ if ((size_t(inputs[0]) & 0x3) != 0){
+ item32_sc8_to_xx<uhd::wtohx>(input++, output++, 1, scale_factor);
+ num_samps--;
+ }
+
+ #define convert_sc8_item32_1_to_fc64_1_nswap_guts(_al_) \
+ for (; j+7 < num_samps; j+=8, i+=4){ \
+ /* load from input */ \
+ __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
+ \
+ /* unpack */ \
+ __m128d tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; \
+ tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); /*byteswap*/\
+ unpack_sc32_8x(tmpi, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, scalar); \
+ \
+ /* store to output */ \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+0), tmp0); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+1), tmp1); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+2), tmp2); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+3), tmp3); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+4), tmp4); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+5), tmp5); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+6), tmp6); \
+ _mm_store ## _al_ ## pd(reinterpret_cast<double *>(output+j+7), tmp7); \
+ }
+
+ //dispatch according to alignment
+ if ((size_t(output) & 0xf) == 0){
+ convert_sc8_item32_1_to_fc64_1_nswap_guts(_)
+ }
+ else{
+ convert_sc8_item32_1_to_fc64_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ item32_sc8_to_xx<uhd::wtohx>(input+i, output+j, num_samps-j, scale_factor);
+}
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 8e8ea5ea8..6524a8412 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -82,7 +82,11 @@ SET_SOURCE_FILES_PROPERTIES(
########################################################################
# Setup UDP
########################################################################
-LIBUHD_APPEND_SOURCES(${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy.cpp)
+IF(WIN32)
+ LIBUHD_APPEND_SOURCES(${CMAKE_CURRENT_SOURCE_DIR}/udp_wsa_zero_copy.cpp)
+ELSE()
+ LIBUHD_APPEND_SOURCES(${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy.cpp)
+ENDIF()
#On windows, the boost asio implementation uses the winsock2 library.
#Note: we exclude the .lib extension for cygwin and mingw platforms.
@@ -97,6 +101,7 @@ CHECK_INCLUDE_FILE_CXX(atlbase.h HAVE_ATLBASE_H)
IF(HAVE_ATLBASE_H)
SET_SOURCE_FILES_PROPERTIES(
${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/udp_wsa_zero_copy.cpp
PROPERTIES COMPILE_DEFINITIONS "HAVE_ATLBASE_H"
)
ENDIF(HAVE_ATLBASE_H)
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 3e67264cd..c13384eec 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -21,6 +21,7 @@
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <boost/foreach.hpp>
+#include <boost/make_shared.hpp>
#include <boost/thread/thread.hpp>
#include <list>
@@ -61,8 +62,18 @@ static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut){
* \return true for completion, false for timeout
*/
UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, bool &completed){
- const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000));
+ //already completed by a previous call?
+ if (completed) return true;
+
+ //perform a non-blocking event handle
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ libusb_handle_events_timeout(ctx, &tv);
+ if (completed) return true;
+ //finish the rest with a timeout loop
+ const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000));
while (not completed and (boost::get_system_time() < timeout_time)){
timeval tv;
tv.tv_sec = 0;
@@ -82,21 +93,18 @@ class libusb_zero_copy_mrb : public managed_recv_buffer{
public:
libusb_zero_copy_mrb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
+ _lut(lut), _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;
}
sptr get_new(const double timeout, size_t &index){
if (wait_for_completion(_ctx, timeout, completed)){
index++;
- _expired = false;
- return make_managed_buffer(this);
+ return make(this, _lut->buffer, _lut->actual_length);
}
return managed_recv_buffer::sptr();
}
@@ -104,12 +112,8 @@ public:
bool completed;
private:
- const void *get_buff(void) const{return _lut->buffer;}
- size_t get_size(void) const{return _lut->actual_length;}
-
libusb_context *_ctx;
libusb_transfer *_lut;
- bool _expired;
const size_t _frame_size;
};
@@ -122,22 +126,18 @@ class libusb_zero_copy_msb : public managed_send_buffer{
public:
libusb_zero_copy_msb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
+ _lut(lut), _frame_size(frame_size) { completed = true; }
- void commit(size_t len){
- if (_expired) return;
+ void release(void){
completed = false;
- _lut->length = len;
- if (len == 0) libusb_async_cb(_lut);
- else UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
- _expired = true;
+ _lut->length = size();
+ UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
}
sptr get_new(const double timeout, size_t &index){
if (wait_for_completion(_ctx, timeout, completed)){
index++;
- _expired = false;
- return make_managed_buffer(this);
+ return make(this, _lut->buffer, _frame_size);
}
return managed_send_buffer::sptr();
}
@@ -145,12 +145,8 @@ public:
bool completed;
private:
- void *get_buff(void) const{return _lut->buffer;}
- size_t get_size(void) const{return _frame_size;}
-
libusb_context *_ctx;
libusb_transfer *_lut;
- bool _expired;
const size_t _frame_size;
};
@@ -187,7 +183,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, this->get_recv_frame_size())));
+ _mrb_pool.push_back(boost::make_shared<libusb_zero_copy_mrb>(lut, this->get_recv_frame_size()));
libusb_fill_bulk_transfer(
lut, // transfer
@@ -210,7 +206,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, this->get_send_frame_size())));
+ _msb_pool.push_back(boost::make_shared<libusb_zero_copy_msb>(lut, this->get_send_frame_size()));
libusb_fill_bulk_transfer(
lut, // transfer
@@ -224,7 +220,6 @@ public:
);
_all_luts.push_back(lut);
- _msb_pool.back()->commit(0);
}
}
diff --git a/host/lib/transport/simple_claimer.hpp b/host/lib/transport/simple_claimer.hpp
new file mode 100644
index 000000000..3bbc49a05
--- /dev/null
+++ b/host/lib/transport/simple_claimer.hpp
@@ -0,0 +1,64 @@
+//
+// 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_TRANSPORT_SIMPLE_CLAIMER_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_SIMPLE_CLAIMER_HPP
+
+#include <uhd/config.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/mutex.hpp>
+
+namespace uhd{ namespace transport{
+
+/***********************************************************************
+ * Claimer class to provide synchronization for multi-thread access.
+ * Claiming enables buffer classes to be used with a buffer queue.
+ **********************************************************************/
+class simple_claimer{
+public:
+ simple_claimer(void){
+ this->release();
+ }
+
+ UHD_INLINE void release(void){
+ boost::mutex::scoped_lock lock(_mutex);
+ _locked = false;
+ lock.unlock();
+ _cond.notify_one();
+ }
+
+ UHD_INLINE bool claim_with_wait(const double timeout){
+ boost::mutex::scoped_lock lock(_mutex);
+ while (_locked){
+ if (not _cond.timed_wait(lock, boost::posix_time::microseconds(long(timeout*1e6)))){
+ break;
+ }
+ }
+ const bool ret = not _locked;
+ _locked = true;
+ return ret;
+ }
+
+private:
+ bool _locked;
+ boost::mutex _mutex;
+ boost::condition_variable _cond;
+};
+
+}} //namespace uhd::transport
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_SIMPLE_CLAIMER_HPP */
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 46c98afea..02cfad80f 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -77,6 +77,12 @@ public:
_header_offset_words32 = header_offset_words32;
}
+ //! Set the stream ID for a specific channel (or no SID)
+ void set_xport_chan_sid(const size_t xport_chan, const bool has_sid, const boost::uint32_t sid = 0){
+ _props.at(xport_chan).has_sid = has_sid;
+ _props.at(xport_chan).sid = sid;
+ }
+
//! Set the rate of ticks per second
void set_tick_rate(const double rate){
_tick_rate = rate;
@@ -133,7 +139,7 @@ public:
//translate the metadata to vrt if packet info
vrt::if_packet_info_t if_packet_info;
if_packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA;
- if_packet_info.has_sid = false;
+ //if_packet_info.has_sid = false; //set per channel
if_packet_info.has_cid = false;
if_packet_info.has_tlr = true;
if_packet_info.has_tsi = false;
@@ -195,7 +201,10 @@ private:
size_t _header_offset_words32;
double _tick_rate, _samp_rate;
struct xport_chan_props_type{
+ xport_chan_props_type(void):has_sid(false){}
get_buff_type get_buff;
+ bool has_sid;
+ boost::uint32_t sid;
};
std::vector<xport_chan_props_type> _props;
std::vector<const void *> _io_buffs; //used in conversion
@@ -233,6 +242,8 @@ private:
boost::uint32_t *otw_mem = buff->cast<boost::uint32_t *>() + _header_offset_words32;
//pack metadata into a vrt header
+ if_packet_info.has_sid = props.has_sid;
+ if_packet_info.sid = props.sid;
_vrt_packer(otw_mem, if_packet_info);
otw_mem += if_packet_info.num_header_words32;
@@ -242,6 +253,7 @@ private:
//commit the samples to the zero-copy interface
size_t num_bytes_total = (_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t);
buff->commit(num_bytes_total);
+ buff.reset(); //effectively a release
}
_next_packet_seq++; //increment sequence after commits
diff --git a/host/lib/transport/udp_wsa_zero_copy.cpp b/host/lib/transport/udp_wsa_zero_copy.cpp
new file mode 100644
index 000000000..6fe4e3cad
--- /dev/null
+++ b/host/lib/transport/udp_wsa_zero_copy.cpp
@@ -0,0 +1,300 @@
+//
+// Copyright 2010-2011 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 "udp_common.hpp"
+#include <uhd/transport/udp_zero_copy.hpp>
+#include <uhd/transport/udp_simple.hpp> //mtu
+#include <uhd/transport/buffer_pool.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/log.hpp>
+#include <boost/format.hpp>
+#include <vector>
+
+using namespace uhd;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+//A reasonable number of frames for send/recv and async/sync
+static const size_t DEFAULT_NUM_FRAMES = 32;
+
+/***********************************************************************
+ * Check registry for correct fast-path setting (windows only)
+ **********************************************************************/
+#ifdef HAVE_ATLBASE_H
+#define CHECK_REG_SEND_THRESH
+#include <atlbase.h> //CRegKey
+static void check_registry_for_fast_send_threshold(const size_t mtu){
+ static bool warned = false;
+ if (warned) return; //only allow one printed warning per process
+
+ CRegKey reg_key;
+ DWORD threshold = 1024; //system default when threshold is not specified
+ if (
+ reg_key.Open(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\AFD\\Parameters", KEY_READ) != ERROR_SUCCESS or
+ reg_key.QueryDWORDValue("FastSendDatagramThreshold", threshold) != ERROR_SUCCESS or threshold < mtu
+ ){
+ UHD_MSG(warning) << boost::format(
+ "The MTU (%d) is larger than the FastSendDatagramThreshold (%d)!\n"
+ "This will negatively affect the transmit performance.\n"
+ "See the transport application notes for more detail.\n"
+ ) % mtu % threshold << std::endl;
+ warned = true;
+ }
+ reg_key.Close();
+}
+#endif /*HAVE_ATLBASE_H*/
+
+/***********************************************************************
+ * Static initialization to take care of WSA init and cleanup
+ **********************************************************************/
+struct uhd_wsa_control{
+ uhd_wsa_control(void){
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(2, 2), &wsaData); /*windows socket startup */
+ }
+
+ ~uhd_wsa_control(void){
+ WSACleanup();
+ }
+};
+
+/***********************************************************************
+ * Reusable managed receiver buffer:
+ * - Initialize with memory and a release callback.
+ * - Call get new with a length in bytes to re-use.
+ **********************************************************************/
+class udp_zero_copy_asio_mrb : public managed_recv_buffer{
+public:
+ udp_zero_copy_asio_mrb(void *mem, int sock_fd, const size_t frame_size):
+ _sock_fd(sock_fd), _frame_size(frame_size)
+ {
+ _wsa_buff.buf = reinterpret_cast<char *>(mem);
+ ZeroMemory(&_overlapped, sizeof(_overlapped));
+ _overlapped.hEvent = WSACreateEvent();
+ UHD_ASSERT_THROW(_overlapped.hEvent != WSA_INVALID_EVENT);
+ this->release(); //makes buffer available via get_new
+ }
+
+ ~udp_zero_copy_asio_mrb(void){
+ WSACloseEvent(_overlapped.hEvent);
+ }
+
+ void release(void){
+ _wsa_buff.len = _frame_size;
+ _flags = 0;
+ WSARecv(_sock_fd, &_wsa_buff, 1, &_wsa_buff.len, &_flags, &_overlapped, NULL);
+ }
+
+ UHD_INLINE sptr get_new(const double timeout, size_t &index){
+ const DWORD result = WSAWaitForMultipleEvents(
+ 1, &_overlapped.hEvent, true, DWORD(timeout*1000), true
+ );
+ if (result == WSA_WAIT_TIMEOUT) return managed_recv_buffer::sptr();
+ index++; //advances the caller's buffer
+
+ WSAGetOverlappedResult(_sock_fd, &_overlapped, &_wsa_buff.len, true, &_flags);
+
+ WSAResetEvent(_overlapped.hEvent);
+ return make(this, _wsa_buff.buf, _wsa_buff.len);
+ }
+
+private:
+ int _sock_fd;
+ const size_t _frame_size;
+ WSAOVERLAPPED _overlapped;
+ WSABUF _wsa_buff;
+ DWORD _flags;
+};
+
+/***********************************************************************
+ * Reusable managed send buffer:
+ * - committing the buffer calls the asynchronous socket send
+ * - getting a new buffer performs the blocking wait for completion
+ **********************************************************************/
+class udp_zero_copy_asio_msb : public managed_send_buffer{
+public:
+ udp_zero_copy_asio_msb(void *mem, int sock_fd, const size_t frame_size):
+ _sock_fd(sock_fd), _frame_size(frame_size)
+ {
+ _wsa_buff.buf = reinterpret_cast<char *>(mem);
+ ZeroMemory(&_overlapped, sizeof(_overlapped));
+ _overlapped.hEvent = WSACreateEvent();
+ UHD_ASSERT_THROW(_overlapped.hEvent != WSA_INVALID_EVENT);
+ WSASetEvent(_overlapped.hEvent); //makes buffer available via get_new
+ }
+
+ ~udp_zero_copy_asio_msb(void){
+ WSACloseEvent(_overlapped.hEvent);
+ }
+
+ void release(void){
+ _wsa_buff.len = size();
+ WSASend(_sock_fd, &_wsa_buff, 1, NULL, 0, &_overlapped, NULL);
+ }
+
+ UHD_INLINE sptr get_new(const double timeout, size_t &index){
+ const DWORD result = WSAWaitForMultipleEvents(
+ 1, &_overlapped.hEvent, true, DWORD(timeout*1000), true
+ );
+ if (result == WSA_WAIT_TIMEOUT) return managed_send_buffer::sptr();
+ index++; //advances the caller's buffer
+
+ WSAResetEvent(_overlapped.hEvent);
+ _wsa_buff.len = _frame_size;
+ return make(this, _wsa_buff.buf, _wsa_buff.len);
+ }
+
+private:
+ int _sock_fd;
+ const size_t _frame_size;
+ WSAOVERLAPPED _overlapped;
+ WSABUF _wsa_buff;
+};
+
+/***********************************************************************
+ * Zero Copy UDP implementation with WSA:
+ *
+ * This is not a true zero copy implementation as each
+ * send and recv requires a copy operation to/from userspace.
+ *
+ * For receive, use a blocking recv() call on the socket.
+ * This has better performance than the overlapped IO.
+ * For send, use overlapped IO to submit async sends.
+ **********************************************************************/
+class udp_zero_copy_wsa_impl : public udp_zero_copy{
+public:
+ typedef boost::shared_ptr<udp_zero_copy_wsa_impl> sptr;
+
+ udp_zero_copy_wsa_impl(
+ const std::string &addr,
+ const std::string &port,
+ const device_addr_t &hints
+ ):
+ _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", udp_simple::mtu))),
+ _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_FRAMES))),
+ _send_frame_size(size_t(hints.cast<double>("send_frame_size", udp_simple::mtu))),
+ _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES))),
+ _recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)),
+ _send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)),
+ _next_recv_buff_index(0), _next_send_buff_index(0)
+ {
+ #ifdef CHECK_REG_SEND_THRESH
+ check_registry_for_fast_send_threshold(this->get_send_frame_size());
+ #endif /*CHECK_REG_SEND_THRESH*/
+
+ UHD_MSG(status) << boost::format("Creating WSA UDP transport for %s:%s") % addr % port << std::endl;
+ static uhd_wsa_control uhd_wsa; //makes wsa start happen via lazy initialization
+
+ UHD_ASSERT_THROW(_num_send_frames <= WSA_MAXIMUM_WAIT_EVENTS);
+
+ //resolve the address
+ asio::io_service io_service;
+ asio::ip::udp::resolver resolver(io_service);
+ asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port);
+ asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ //create the socket
+ _sock_fd = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
+ if (_sock_fd == INVALID_SOCKET){
+ const DWORD error = WSAGetLastError();
+ throw uhd::os_error(str(boost::format("WSASocket() failed with error %d") % error));
+ }
+
+ //set the socket non-blocking for recv
+ //u_long mode = 1;
+ //ioctlsocket(_sock_fd, FIONBIO, &mode);
+
+ //resize the socket buffers
+ const int recv_buff_size = int(hints.cast<double>("recv_buff_size", 0.0));
+ const int send_buff_size = int(hints.cast<double>("send_buff_size", 0.0));
+ if (recv_buff_size > 0) setsockopt(_sock_fd, SOL_SOCKET, SO_RCVBUF, (const char *)&recv_buff_size, sizeof(recv_buff_size));
+ if (send_buff_size > 0) setsockopt(_sock_fd, SOL_SOCKET, SO_SNDBUF, (const char *)&send_buff_size, sizeof(send_buff_size));
+
+ //connect the socket so we can send/recv
+ const asio::ip::udp::endpoint::data_type &servaddr = *receiver_endpoint.data();
+ if (WSAConnect(_sock_fd, (const struct sockaddr *)&servaddr, sizeof(servaddr), NULL, NULL, NULL, NULL) != 0){
+ const DWORD error = WSAGetLastError();
+ closesocket(_sock_fd);
+ throw uhd::os_error(str(boost::format("WSAConnect() failed with error %d") % error));
+ }
+
+ //allocate re-usable managed receive buffers
+ for (size_t i = 0; i < get_num_recv_frames(); i++){
+ _mrb_pool.push_back(boost::shared_ptr<udp_zero_copy_asio_mrb>(
+ new udp_zero_copy_asio_mrb(_recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size())
+ ));
+ }
+
+ //allocate re-usable managed send buffers
+ for (size_t i = 0; i < get_num_send_frames(); i++){
+ _msb_pool.push_back(boost::shared_ptr<udp_zero_copy_asio_msb>(
+ new udp_zero_copy_asio_msb(_send_buffer_pool->at(i), _sock_fd, get_send_frame_size())
+ ));
+ }
+ }
+
+ ~udp_zero_copy_wsa_impl(void){
+ closesocket(_sock_fd);
+ }
+
+ /*******************************************************************
+ * Receive implementation:
+ * Block on the managed buffer's get call and advance the index.
+ ******************************************************************/
+ managed_recv_buffer::sptr get_recv_buff(double timeout){
+ if (_next_recv_buff_index == _num_recv_frames) _next_recv_buff_index = 0;
+ return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index);
+ }
+
+ size_t get_num_recv_frames(void) const {return _num_recv_frames;}
+ size_t get_recv_frame_size(void) const {return _recv_frame_size;}
+
+ /*******************************************************************
+ * Send implementation:
+ * Block on the managed buffer's get call and advance the index.
+ ******************************************************************/
+ managed_send_buffer::sptr get_send_buff(double timeout){
+ if (_next_send_buff_index == _num_send_frames) _next_send_buff_index = 0;
+ return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index);
+ }
+
+ size_t get_num_send_frames(void) const {return _num_send_frames;}
+ size_t get_send_frame_size(void) const {return _send_frame_size;}
+
+private:
+ //memory management -> buffers and fifos
+ const size_t _recv_frame_size, _num_recv_frames;
+ const size_t _send_frame_size, _num_send_frames;
+ buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool;
+ std::vector<boost::shared_ptr<udp_zero_copy_asio_msb> > _msb_pool;
+ std::vector<boost::shared_ptr<udp_zero_copy_asio_mrb> > _mrb_pool;
+ size_t _next_recv_buff_index, _next_send_buff_index;
+
+ //socket guts
+ SOCKET _sock_fd;
+};
+
+/***********************************************************************
+ * UDP zero copy make function
+ **********************************************************************/
+udp_zero_copy::sptr udp_zero_copy::make(
+ const std::string &addr,
+ const std::string &port,
+ const device_addr_t &hints
+){
+ return sptr(new udp_zero_copy_wsa_impl(addr, port, hints));
+}
diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp
index 0ccc92b82..9765c19c0 100644
--- a/host/lib/transport/udp_zero_copy.cpp
+++ b/host/lib/transport/udp_zero_copy.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,14 +16,15 @@
//
#include "udp_common.hpp"
+#include "simple_claimer.hpp"
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/transport/udp_simple.hpp> //mtu
-#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/buffer_pool.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/log.hpp>
#include <boost/format.hpp>
-#include <list>
+#include <boost/make_shared.hpp>
+#include <vector>
using namespace uhd;
using namespace uhd::transport;
@@ -61,66 +62,71 @@ static void check_registry_for_fast_send_threshold(const size_t mtu){
/***********************************************************************
* Reusable managed receiver buffer:
- * - Initialize with memory and a release callback.
- * - Call get new with a length in bytes to re-use.
+ * - get_new performs the recv operation
**********************************************************************/
class udp_zero_copy_asio_mrb : public managed_recv_buffer{
public:
- udp_zero_copy_asio_mrb(void *mem, bounded_buffer<udp_zero_copy_asio_mrb *> &pending):
- _mem(mem), _len(0), _pending(pending){/* NOP */}
+ udp_zero_copy_asio_mrb(void *mem, int sock_fd, const size_t frame_size):
+ _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ }
void release(void){
- if (_len == 0) return;
- _pending.push_with_haste(this);
- _len = 0;
+ _claimer.release();
}
- sptr get_new(size_t len){
- _len = len;
- return make_managed_buffer(this);
- }
+ UHD_INLINE sptr get_new(const double timeout, size_t &index){
+ if (not _claimer.claim_with_wait(timeout)) return sptr();
- template <class T> T cast(void) const{return static_cast<T>(_mem);}
+ #ifdef MSG_DONTWAIT //try a non-blocking recv() if supported
+ _len = ::recv(_sock_fd, (char *)_mem, _frame_size, MSG_DONTWAIT);
+ if (_len > 0){
+ index++; //advances the caller's buffer
+ return make(this, _mem, size_t(_len));
+ }
+ #endif
-private:
- const void *get_buff(void) const{return _mem;}
- size_t get_size(void) const{return _len;}
+ if (wait_for_recv_ready(_sock_fd, timeout)){
+ _len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0);
+ index++; //advances the caller's buffer
+ return make(this, _mem, size_t(_len));
+ }
+ _claimer.release(); //undo claim
+ return sptr(); //null for timeout
+ }
+
+private:
void *_mem;
- size_t _len;
- bounded_buffer<udp_zero_copy_asio_mrb *> &_pending;
+ int _sock_fd;
+ size_t _frame_size;
+ ssize_t _len;
+ simple_claimer _claimer;
};
/***********************************************************************
* Reusable managed send buffer:
- * - Initialize with memory and a commit callback.
- * - Call get new with a length in bytes to re-use.
+ * - commit performs the send operation
**********************************************************************/
class udp_zero_copy_asio_msb : public managed_send_buffer{
public:
- udp_zero_copy_asio_msb(void *mem, bounded_buffer<udp_zero_copy_asio_msb *> &pending, int sock_fd):
- _mem(mem), _len(0), _pending(pending), _sock_fd(sock_fd){/* NOP */}
-
- void commit(size_t len){
- if (_len == 0) return;
- ::send(_sock_fd, this->cast<const char *>(), len, 0);
- _pending.push_with_haste(this);
- _len = 0;
+ udp_zero_copy_asio_msb(void *mem, int sock_fd, const size_t frame_size):
+ _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ }
+
+ void release(void){
+ UHD_ASSERT_THROW(::send(_sock_fd, (const char *)_mem, size(), 0) == ssize_t(size()));
+ _claimer.release();
}
- sptr get_new(size_t len){
- _len = len;
- return make_managed_buffer(this);
+ UHD_INLINE sptr get_new(const double timeout, size_t &index){
+ if (not _claimer.claim_with_wait(timeout)) return sptr();
+ index++; //advances the caller's buffer
+ return make(this, _mem, _frame_size);
}
private:
- void *get_buff(void) const{return _mem;}
- size_t get_size(void) const{return _len;}
-
void *_mem;
- size_t _len;
- bounded_buffer<udp_zero_copy_asio_msb *> &_pending;
int _sock_fd;
+ size_t _frame_size;
+ simple_claimer _claimer;
};
/***********************************************************************
@@ -145,8 +151,7 @@ public:
_num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES))),
_recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)),
_send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)),
- _pending_recv_buffs(_num_recv_frames),
- _pending_send_buffs(_num_send_frames)
+ _next_recv_buff_index(0), _next_send_buff_index(0)
{
UHD_LOG << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
@@ -167,18 +172,16 @@ public:
//allocate re-usable managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _mrb_pool.push_back(udp_zero_copy_asio_mrb(
- _recv_buffer_pool->at(i), _pending_recv_buffs
+ _mrb_pool.push_back(boost::make_shared<udp_zero_copy_asio_mrb>(
+ _recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size()
));
- _pending_recv_buffs.push_with_haste(&_mrb_pool.back());
}
//allocate re-usable managed send buffers
for (size_t i = 0; i < get_num_send_frames(); i++){
- _msb_pool.push_back(udp_zero_copy_asio_msb(
- _send_buffer_pool->at(i), _pending_send_buffs, _sock_fd
+ _msb_pool.push_back(boost::make_shared<udp_zero_copy_asio_msb>(
+ _send_buffer_pool->at(i), _sock_fd, get_send_frame_size()
));
- _pending_send_buffs.push_with_haste(&_msb_pool.back());
}
}
@@ -198,29 +201,11 @@ public:
/*******************************************************************
* Receive implementation:
- *
- * Perform a non-blocking receive for performance,
- * and then fall back to a blocking receive with timeout.
- * Return the managed receive buffer with the new length.
- * When the caller is finished with the managed buffer,
- * the managed receive buffer is released back into the queue.
+ * Block on the managed buffer's get call and advance the index.
******************************************************************/
managed_recv_buffer::sptr get_recv_buff(double timeout){
- udp_zero_copy_asio_mrb *mrb = NULL;
- if (_pending_recv_buffs.pop_with_timed_wait(mrb, timeout)){
-
- #ifdef MSG_DONTWAIT //try a non-blocking recv() if supported
- ssize_t ret = ::recv(_sock_fd, mrb->cast<char *>(), _recv_frame_size, MSG_DONTWAIT);
- if (ret > 0) return mrb->get_new(ret);
- #endif
-
- if (wait_for_recv_ready(_sock_fd, timeout)) return mrb->get_new(
- ::recv(_sock_fd, mrb->cast<char *>(), _recv_frame_size, 0)
- );
-
- _pending_recv_buffs.push_with_haste(mrb); //timeout: return the managed buffer to the queue
- }
- return managed_recv_buffer::sptr();
+ if (_next_recv_buff_index == _num_recv_frames) _next_recv_buff_index = 0;
+ return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index);
}
size_t get_num_recv_frames(void) const {return _num_recv_frames;}
@@ -228,18 +213,11 @@ public:
/*******************************************************************
* Send implementation:
- *
- * Get a managed receive buffer immediately with max length set.
- * The caller will fill the buffer and commit it when finished.
- * The commit routine will perform a blocking send operation,
- * and push the managed send buffer back into the queue.
+ * Block on the managed buffer's get call and advance the index.
******************************************************************/
managed_send_buffer::sptr get_send_buff(double timeout){
- udp_zero_copy_asio_msb *msb = NULL;
- if (_pending_send_buffs.pop_with_timed_wait(msb, timeout)){
- return msb->get_new(_send_frame_size);
- }
- return managed_send_buffer::sptr();
+ if (_next_send_buff_index == _num_send_frames) _next_send_buff_index = 0;
+ return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index);
}
size_t get_num_send_frames(void) const {return _num_send_frames;}
@@ -250,10 +228,9 @@ private:
const size_t _recv_frame_size, _num_recv_frames;
const size_t _send_frame_size, _num_send_frames;
buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool;
- bounded_buffer<udp_zero_copy_asio_mrb *> _pending_recv_buffs;
- bounded_buffer<udp_zero_copy_asio_msb *> _pending_send_buffs;
- std::list<udp_zero_copy_asio_msb> _msb_pool;
- std::list<udp_zero_copy_asio_mrb> _mrb_pool;
+ std::vector<boost::shared_ptr<udp_zero_copy_asio_msb> > _msb_pool;
+ std::vector<boost::shared_ptr<udp_zero_copy_asio_mrb> > _mrb_pool;
+ size_t _next_recv_buff_index, _next_send_buff_index;
//asio guts -> socket and service
asio::io_service _io_service;
diff --git a/host/lib/transport/usb_zero_copy_wrapper.cpp b/host/lib/transport/usb_zero_copy_wrapper.cpp
index 3571ed856..d59ea36ff 100644
--- a/host/lib/transport/usb_zero_copy_wrapper.cpp
+++ b/host/lib/transport/usb_zero_copy_wrapper.cpp
@@ -15,46 +15,64 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "simple_claimer.hpp"
#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 <uhd/utils/tasks.hpp>
#include <boost/foreach.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/bind.hpp>
#include <vector>
#include <iostream>
using namespace uhd::transport;
+static const boost::posix_time::time_duration AUTOFLUSH_TIMEOUT(boost::posix_time::milliseconds(1));
+
/***********************************************************************
* USB zero copy wrapper - managed receive buffer
**********************************************************************/
class usb_zero_copy_wrapper_mrb : public managed_recv_buffer{
public:
- usb_zero_copy_wrapper_mrb(bounded_buffer<usb_zero_copy_wrapper_mrb *> &queue):
- _queue(queue){/*NOP*/}
+ usb_zero_copy_wrapper_mrb(void){/*NOP*/}
void release(void){
- if (not _mrb) return;
_mrb.reset(); //decrement ref count, other MRB's may hold a ref
- _queue.push_with_haste(this);
+ _claimer.release();
}
- UHD_INLINE sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){
+ UHD_INLINE sptr get_new(
+ managed_recv_buffer::sptr &mrb, size_t &offset_bytes,
+ const double timeout, size_t &index
+ ){
+ if (not mrb or not _claimer.claim_with_wait(timeout)) return sptr();
+
+ index++; //advances the caller's buffer
+
+ //hold a copy of the buffer shared pointer
_mrb = mrb;
- _mem = mem;
- _len = len;
- return make_managed_buffer(this);
+
+ //extract this packet's memory address and length in bytes
+ char *mem = mrb->cast<char *>() + offset_bytes;
+ const boost::uint32_t *mem32 = reinterpret_cast<const boost::uint32_t *>(mem);
+ const size_t words32 = (uhd::wtohx(mem32[0]) & 0xffff); //length in words32 (from VRT header)
+ const size_t len = words32*sizeof(boost::uint32_t); //length in bytes
+
+ //check if this receive buffer has been exhausted
+ offset_bytes += len;
+ if (offset_bytes >= mrb->size()) mrb.reset(); //drop caller's ref
+ else if (uhd::wtohx(mem32[words32]) == 0) mrb.reset();
+
+ return make(this, mem, len);
}
private:
- const void *get_buff(void) const{return _mem;}
- size_t get_size(void) const{return _len;}
-
- bounded_buffer<usb_zero_copy_wrapper_mrb *> &_queue;
- const void *_mem;
- size_t _len;
managed_recv_buffer::sptr _mrb;
+ simple_claimer _claimer;
};
/***********************************************************************
@@ -63,16 +81,27 @@ private:
class usb_zero_copy_wrapper_msb : public managed_send_buffer{
public:
usb_zero_copy_wrapper_msb(const usb_zero_copy::sptr internal, const size_t fragmentation_size):
- _internal(internal), _fragmentation_size(fragmentation_size){/*NOP*/}
+ _internal(internal), _fragmentation_size(fragmentation_size)
+ {
+ _ok_to_auto_flush = false;
+ _task = uhd::task::make(boost::bind(&usb_zero_copy_wrapper_msb::auto_flush, this));
+ }
- void commit(size_t len){
- if (len == 0) return;
+ ~usb_zero_copy_wrapper_msb(void)
+ {
+ //ensure the task has exited before anything auto deconstructs
+ _task.reset();
+ }
+
+ void release(void){
+ boost::mutex::scoped_lock lock(_mutex);
+ _ok_to_auto_flush = true;
//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;
+ _bytes_in_buffer += size();
+ _mem_buffer_tip += size();
//extract VITA end of packet flag, we must force flush under eof conditions
const bool eop = (uhd::wtohx(vita_header) & (0x1 << 24)) != 0;
@@ -80,28 +109,53 @@ public:
if (eop or full){
_last_send_buff->commit(_bytes_in_buffer);
_last_send_buff.reset();
+
+ //notify the auto-flusher to restart its timed_wait
+ lock.unlock(); _cond.notify_one();
}
}
UHD_INLINE sptr get_new(const double timeout){
+ boost::mutex::scoped_lock lock(_mutex);
+ _ok_to_auto_flush = false;
+
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);
+
+ return make(this, _mem_buffer_tip, _fragmentation_size);
}
private:
- 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;
+
+ //private variables for auto flusher
+ boost::mutex _mutex;
+ boost::condition_variable _cond;
+ uhd::task::sptr _task;
+ bool _ok_to_auto_flush;
+
+ /*!
+ * The auto flusher ensures that buffers are force committed when
+ * the user has not called get_new() within a certain time window.
+ */
+ void auto_flush(void)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ const bool timeout = not _cond.timed_wait(lock, AUTOFLUSH_TIMEOUT);
+ if (timeout and _ok_to_auto_flush and _last_send_buff and _bytes_in_buffer != 0)
+ {
+ _last_send_buff->commit(_bytes_in_buffer);
+ _last_send_buff.reset();
+ }
+ }
};
/***********************************************************************
@@ -112,44 +166,26 @@ public:
usb_zero_copy_wrapper(sptr usb_zc, const size_t frame_boundary):
_internal_zc(usb_zc),
_frame_boundary(frame_boundary),
- _available_recv_buffs(this->get_num_recv_frames()),
- _mrb_pool(this->get_num_recv_frames(), usb_zero_copy_wrapper_mrb(_available_recv_buffs)),
- _the_only_msb(usb_zero_copy_wrapper_msb(usb_zc, frame_boundary))
+ _next_recv_buff_index(0)
{
- BOOST_FOREACH(usb_zero_copy_wrapper_mrb &mrb, _mrb_pool){
- _available_recv_buffs.push_with_haste(&mrb);
+ for (size_t i = 0; i < this->get_num_recv_frames(); i++){
+ _mrb_pool.push_back(boost::make_shared<usb_zero_copy_wrapper_mrb>());
}
+ _the_only_msb = boost::make_shared<usb_zero_copy_wrapper_msb>(usb_zc, frame_boundary);
}
managed_recv_buffer::sptr get_recv_buff(double timeout){
//attempt to get a managed recv buffer
- if (not _last_recv_buff.get()){
+ if (not _last_recv_buff){
_last_recv_buff = _internal_zc->get_recv_buff(timeout);
- _last_recv_offset = 0;
+ _last_recv_offset = 0; //reset offset into buffer
}
- //attempt to get a wrapper for a managed recv buffer
- usb_zero_copy_wrapper_mrb *wmrb = NULL;
- if (_last_recv_buff.get() and _available_recv_buffs.pop_with_timed_wait(wmrb, timeout)){
- //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);
- 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 += len;
-
- //check if this receive buffer has been exhausted
- if (_last_recv_offset >= _last_recv_buff->size()) {
- _last_recv_buff.reset();
- }
-
- return recv_buff;
- }
-
- //otherwise return a null sptr for failure
- return managed_recv_buffer::sptr();
+ //get the buffer to be returned to the user
+ if (_next_recv_buff_index == _mrb_pool.size()) _next_recv_buff_index = 0;
+ return _mrb_pool[_next_recv_buff_index]->get_new(
+ _last_recv_buff, _last_recv_offset, timeout, _next_recv_buff_index
+ );
}
size_t get_num_recv_frames(void) const{
@@ -161,7 +197,7 @@ public:
}
managed_send_buffer::sptr get_send_buff(double timeout){
- return _the_only_msb.get_new(timeout);
+ return _the_only_msb->get_new(timeout);
}
size_t get_num_send_frames(void) const{
@@ -175,16 +211,13 @@ public:
private:
sptr _internal_zc;
size_t _frame_boundary;
- bounded_buffer<usb_zero_copy_wrapper_mrb *> _available_recv_buffs;
- std::vector<usb_zero_copy_wrapper_mrb> _mrb_pool;
- usb_zero_copy_wrapper_msb _the_only_msb;
-
- //buffer to store partially-received VRT packets in
- buffer_pool::sptr _fragment_mem;
+ std::vector<boost::shared_ptr<usb_zero_copy_wrapper_mrb> > _mrb_pool;
+ boost::shared_ptr<usb_zero_copy_wrapper_msb> _the_only_msb;
//state for last recv buffer to create multiple managed buffers
managed_recv_buffer::sptr _last_recv_buff;
size_t _last_recv_offset;
+ size_t _next_recv_buff_index;
};
/***********************************************************************
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 991e6efd3..eec777842 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -35,6 +35,7 @@
#include <boost/lexical_cast.hpp>
#include "b100_regs.hpp"
#include <cstdio>
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
@@ -85,13 +86,10 @@ static device_addrs_t b100_find(const device_addr_t &hint)
b100_fw_image = find_image_path(hint.get("fw", B100_FW_FILE_NAME));
}
catch(...){
- UHD_MSG(warning) << boost::format(
- "Could not locate B100 firmware.\n"
- "Please install the images package.\n"
- );
+ UHD_MSG(warning) << boost::format("Could not locate B100 firmware. %s\n") % print_images_error();
return b100_addrs;
}
- UHD_LOG << "the firmware image: " << b100_fw_image << std::endl;
+ UHD_LOG << "the firmware image: " << b100_fw_image << std::endl;
usb_control::sptr control;
try{control = usb_control::make(handle, 0);}
@@ -117,7 +115,7 @@ static device_addrs_t b100_find(const device_addr_t &hint)
catch(const uhd::exception &){continue;} //ignore claimed
fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control);
- const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*fx2_ctrl, mboard_eeprom_t::MAP_B100);
+ const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*fx2_ctrl, B100_EEPROM_MAP_KEY);
device_addr_t new_addr;
new_addr["type"] = "b100";
new_addr["name"] = mb_eeprom["name"];
@@ -260,14 +258,15 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
_tree->create<std::string>("/name").set("B-Series Device");
const fs_path mb_path = "/mboards/0";
- _tree->create<std::string>(mb_path / "name").set("B100 (B-Hundo)");
+ _tree->create<std::string>(mb_path / "name").set("B100");
+ _tree->create<std::string>(mb_path / "codename").set("B-Hundo");
_tree->create<std::string>(mb_path / "load_eeprom")
.subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1));
////////////////////////////////////////////////////////////////////
// setup the mboard eeprom
////////////////////////////////////////////////////////////////////
- const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B100);
+ const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, B100_EEPROM_MAP_KEY);
_tree->create<mboard_eeprom_t>(mb_path / "eeprom")
.set(mb_eeprom)
.subscribe(boost::bind(&b100_impl::set_mb_eeprom, this, _1));
@@ -496,8 +495,9 @@ void b100_impl::check_fw_compat(void){
if (fw_compat_num != B100_FW_COMPAT_NUM){
throw uhd::runtime_error(str(boost::format(
"Expected firmware compatibility number 0x%x, but got 0x%x:\n"
- "The firmware build is not compatible with the host code build."
- ) % B100_FW_COMPAT_NUM % fw_compat_num));
+ "The firmware build is not compatible with the host code build.\n"
+ "%s"
+ ) % B100_FW_COMPAT_NUM % fw_compat_num % print_images_error()));
}
}
@@ -512,7 +512,8 @@ void b100_impl::check_fpga_compat(void){
throw uhd::runtime_error(str(boost::format(
"Expected FPGA compatibility number %d, but got %d:\n"
"The FPGA build is not compatible with the host code build."
- ) % int(B100_FPGA_COMPAT_NUM) % fpga_major));
+ "%s"
+ ) % int(B100_FPGA_COMPAT_NUM) % fpga_major % print_images_error()));
}
_tree->create<std::string>("/mboards/0/fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor));
}
@@ -526,7 +527,7 @@ double b100_impl::update_rx_codec_gain(const double gain){
}
void b100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){
- mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B100);
+ mb_eeprom.commit(*_fx2_ctrl, B100_EEPROM_MAP_KEY);
}
void b100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index eab9c750b..22e22bcff 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -48,11 +48,12 @@ static const double B100_LINK_RATE_BPS = 256e6/5; //pratical link rate
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 = 0x03;
-static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x09;
+static const boost::uint16_t B100_FPGA_COMPAT_NUM = 10;
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;
+static const std::string B100_EEPROM_MAP_KEY = "B100";
//! Make a b100 dboard interface
uhd::usrp::dboard_iface::sptr make_b100_dboard_iface(
diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
index 7b8920eb1..5cc701eb0 100644
--- a/host/lib/usrp/common/fx2_ctrl.cpp
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -411,6 +411,26 @@ public:
return usrp_control_write(request, value, index, 0, 0);
}
+ void write_eeprom(
+ boost::uint8_t addr,
+ boost::uint8_t offset,
+ const byte_vector_t &bytes
+ ){
+ byte_vector_t bytes_with_cmd(bytes.size() + 1);
+ bytes_with_cmd[0] = offset;
+ std::copy(bytes.begin(), bytes.end(), &bytes_with_cmd[1]);
+ this->write_i2c(addr, bytes_with_cmd);
+ }
+
+ byte_vector_t read_eeprom(
+ boost::uint8_t addr,
+ boost::uint8_t offset,
+ size_t num_bytes
+ ){
+ this->write_i2c(addr, byte_vector_t(1, offset));
+ return this->read_i2c(addr, num_bytes);
+ }
+
int usrp_i2c_write(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len)
{
return usrp_control_write(VRQ_I2C_WRITE, i2c_addr, 0, buf, len);
@@ -428,12 +448,7 @@ public:
{
UHD_ASSERT_THROW(bytes.size() < 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,
- buff,
- bytes.size());
+ int ret = this->usrp_i2c_write(addr, (unsigned char *)&bytes.front(), bytes.size());
if (iface_debug && (ret < 0))
uhd::runtime_error("USRP: failed i2c write");
@@ -443,19 +458,13 @@ public:
{
UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
- unsigned char buff[max_i2c_data_bytes] = {};
- int ret = this->usrp_i2c_read(addr & 0xff,
- buff,
- num_bytes);
+ byte_vector_t bytes(num_bytes);
+ int ret = this->usrp_i2c_read(addr, (unsigned char *)&bytes.front(), num_bytes);
if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes)))
uhd::runtime_error("USRP: failed i2c read");
- byte_vector_t out_bytes;
- for (size_t i = 0; i < num_bytes; i++)
- out_bytes.push_back(buff[i]);
-
- return out_bytes;
+ return bytes;
}
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
index aa5f0bcbb..3192b0774 100644
--- a/host/lib/usrp/cores/CMakeLists.txt
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -24,6 +24,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/gpio_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spi_core_100.cpp
${CMAKE_CURRENT_SOURCE_DIR}/time64_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_200.cpp
diff --git a/host/lib/usrp/cores/gpio_core_200.cpp b/host/lib/usrp/cores/gpio_core_200.cpp
index d756097ff..cdab70b8d 100644
--- a/host/lib/usrp/cores/gpio_core_200.cpp
+++ b/host/lib/usrp/cores/gpio_core_200.cpp
@@ -63,6 +63,7 @@ private:
wb_iface::sptr _iface;
const size_t _base;
const size_t _rb_addr;
+ uhd::dict<size_t, boost::uint32_t> _update_cache;
uhd::dict<unit_t, boost::uint16_t> _pin_ctrl, _gpio_out, _gpio_ddr;
uhd::dict<unit_t, uhd::dict<atr_reg_t, boost::uint16_t> > _atr_regs;
@@ -90,7 +91,12 @@ private:
const boost::uint32_t ctrl =
(boost::uint32_t(_pin_ctrl[dboard_iface::UNIT_RX]) << unit2shit(dboard_iface::UNIT_RX)) |
(boost::uint32_t(_pin_ctrl[dboard_iface::UNIT_TX]) << unit2shit(dboard_iface::UNIT_TX));
- _iface->poke32(addr, (ctrl & atr_val) | ((~ctrl) & gpio_val));
+ const boost::uint32_t val = (ctrl & atr_val) | ((~ctrl) & gpio_val);
+ if (not _update_cache.has_key(addr) or _update_cache[addr] != val)
+ {
+ _iface->poke32(addr, val);
+ }
+ _update_cache[addr] = val;
}
};
diff --git a/host/lib/usrp/cores/i2c_core_200.cpp b/host/lib/usrp/cores/i2c_core_200.cpp
new file mode 100644
index 000000000..1b882c54a
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_200.cpp
@@ -0,0 +1,158 @@
+//
+// 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
+// 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 "i2c_core_200.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+#include <boost/thread/mutex.hpp>
+
+#define REG_I2C_WR_PRESCALER_LO (1 << 3) | 0
+#define REG_I2C_WR_PRESCALER_HI (1 << 3) | 1
+#define REG_I2C_WR_CTRL (1 << 3) | 2
+#define REG_I2C_WR_DATA (1 << 3) | 3
+#define REG_I2C_WR_CMD (1 << 3) | 4
+#define REG_I2C_RD_DATA (0 << 3) | 3
+#define REG_I2C_RD_ST (0 << 3) | 4
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+using namespace uhd;
+
+class i2c_core_200_impl : public i2c_core_200{
+public:
+ i2c_core_200_impl(wb_iface::sptr iface, const size_t base, const size_t readback):
+ _iface(iface), _base(base), _readback(readback)
+ {
+ //init I2C FPGA interface.
+ this->poke(REG_I2C_WR_CTRL, 0x0000);
+ //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
+ static const boost::uint32_t i2c_datarate = 400000;
+ static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
+ boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
+ this->poke(REG_I2C_WR_PRESCALER_LO, prescaler & 0xFF);
+ this->poke(REG_I2C_WR_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+ this->poke(REG_I2C_WR_CTRL, I2C_CTRL_EN); //enable I2C core
+ }
+
+ void write_i2c(
+ boost::uint8_t addr,
+ const byte_vector_t &bytes
+ ){
+ this->poke(REG_I2C_WR_DATA, (addr << 1) | 0); //addr and read bit (0)
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
+
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ return;
+ }
+
+ for (size_t i = 0; i < bytes.size(); i++) {
+ this->poke(REG_I2C_WR_DATA, bytes[i]);
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+ if(!wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ return;
+ }
+ }
+ }
+
+ byte_vector_t read_i2c(
+ boost::uint8_t addr,
+ size_t num_bytes
+ ){
+ byte_vector_t bytes;
+ if (num_bytes == 0) return bytes;
+
+ while (this->peek(REG_I2C_RD_ST) & I2C_ST_BUSY){
+ /* NOP */
+ }
+
+ this->poke(REG_I2C_WR_DATA, (addr << 1) | 1); //addr and read bit (1)
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | I2C_CMD_START);
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ }
+ for (size_t i = 0; i < num_bytes; i++) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+ i2c_wait();
+ bytes.push_back(this->peek(REG_I2C_RD_DATA));
+ }
+ return bytes;
+ }
+
+private:
+ void i2c_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((this->peek(REG_I2C_RD_ST) & I2C_ST_TIP) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "i2c_core_200: i2c_wait timeout" << std::endl;
+ }
+
+ bool wait_chk_ack(void){
+ i2c_wait();
+ return (this->peek(REG_I2C_RD_ST) & I2C_ST_RXACK) == 0;
+ }
+
+ void poke(const size_t what, const boost::uint8_t cmd)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _iface->poke32(_base, (what << 8) | cmd);
+ }
+
+ boost::uint8_t peek(const size_t what)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _iface->poke32(_base, what << 8);
+ return boost::uint8_t(_iface->peek32(_readback));
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const size_t _readback;
+ boost::mutex _mutex;
+};
+
+i2c_core_200::sptr i2c_core_200::make(wb_iface::sptr iface, const size_t base, const size_t readback){
+ return sptr(new i2c_core_200_impl(iface, base, readback));
+}
diff --git a/host/lib/usrp/cores/i2c_core_200.hpp b/host/lib/usrp/cores/i2c_core_200.hpp
new file mode 100644
index 000000000..508855985
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_200.hpp
@@ -0,0 +1,35 @@
+//
+// 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
+// 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_I2C_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class i2c_core_200 : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<i2c_core_200> sptr;
+
+ //! makes a new i2c core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index cf8db1927..a89405039 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -19,6 +19,7 @@
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/safe_call.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread/thread.hpp> //thread sleep
@@ -76,8 +77,17 @@ public:
this->clear();
}
+ ~rx_dsp_core_200_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ //shutdown any possible streaming
+ this->clear();
+ )
+ }
+
void clear(void){
- _iface->poke32(REG_RX_CTRL_NCHANNELS, 1); //also reset
+ _iface->poke32(REG_RX_CTRL_NCHANNELS, 0); //also reset
_iface->poke32(REG_RX_CTRL_VRT_HDR, 0
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index e460d1106..11b310362 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -56,6 +56,10 @@ public:
if (_mimo_delay_cycles != 0) _sources.push_back("mimo");
}
+ void enable_gpsdo(void){
+ _sources.push_back("gpsdo");
+ }
+
void set_tick_rate(const double rate){
_tick_rate = rate;
}
@@ -100,7 +104,7 @@ public:
assert_has(_sources, source, "time source");
//setup pps flags
- if (source == "external"){
+ if (source == "external" or source == "gpsdo"){
_iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_POSEDGE);
}
else if (source == "_external_"){
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index 7571573a5..315f2ba67 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.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
@@ -42,6 +42,8 @@ public:
const size_t mimo_delay_cycles = 0 // 0 means no-mimo
);
+ virtual void enable_gpsdo(void) = 0;
+
virtual void set_tick_rate(const double rate) = 0;
virtual uhd::time_spec_t get_time_now(void) = 0;
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index fc42a73d5..2b30dab52 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.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
@@ -108,11 +108,17 @@ basic_rx::basic_rx(ctor_args_t args, double max_freq) : rx_dboard_base(args){
////////////////////////////////////////////////////////////////////
// Register properties
////////////////////////////////////////////////////////////////////
- this->get_rx_subtree()->create<std::string>("name").set(
- std::string(str(boost::format("%s - %s")
- % get_rx_id().to_pp_string()
- % get_subdev_name()
+ if(get_rx_id() == 0x0001){
+ this->get_rx_subtree()->create<std::string>("name").set(
+ std::string(str(boost::format("BasicRX (%s)") % get_subdev_name()
)));
+ }
+ else{
+ this->get_rx_subtree()->create<std::string>("name").set(
+ std::string(str(boost::format("LFRX (%s)") % get_subdev_name()
+ )));
+ }
+
this->get_rx_subtree()->create<int>("gains"); //phony property so this dir exists
this->get_rx_subtree()->create<double>("freq/value")
.publish(&always_zero_freq);
@@ -157,11 +163,17 @@ basic_tx::basic_tx(ctor_args_t args, double max_freq) : tx_dboard_base(args){
////////////////////////////////////////////////////////////////////
// Register properties
////////////////////////////////////////////////////////////////////
- this->get_tx_subtree()->create<std::string>("name").set(
- std::string(str(boost::format("%s - %s")
- % get_tx_id().to_pp_string()
- % get_subdev_name()
+ if(get_tx_id() == 0x0000){
+ this->get_tx_subtree()->create<std::string>("name").set(
+ std::string(str(boost::format("BasicTX (%s)") % get_subdev_name()
)));
+ }
+ else{
+ this->get_tx_subtree()->create<std::string>("name").set(
+ std::string(str(boost::format("LFTX (%s)") % get_subdev_name()
+ )));
+ }
+
this->get_tx_subtree()->create<int>("gains"); //phony property so this dir exists
this->get_tx_subtree()->create<double>("freq/value")
.publish(&always_zero_freq);
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index 95c5c5d4d..b1cee4aa7 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -202,7 +202,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
// Register properties
////////////////////////////////////////////////////////////////////
this->get_rx_subtree()->create<std::string>("name")
- .set(get_rx_id().to_pp_string());
+ .set("DBSRX");
this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&dbsrx::get_locked, this));
BOOST_FOREACH(const std::string &name, dbsrx_gain_ranges.keys()){
diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp
index 517b7b183..013f3178a 100644
--- a/host/lib/usrp/dboard/db_dbsrx2.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx2.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
@@ -189,7 +189,7 @@ dbsrx2::dbsrx2(ctor_args_t args) : rx_dboard_base(args){
// Register properties
////////////////////////////////////////////////////////////////////
this->get_rx_subtree()->create<std::string>("name")
- .set(get_rx_id().to_pp_string());
+ .set("DBSRX2");
this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&dbsrx2::get_locked, this));
BOOST_FOREACH(const std::string &name, dbsrx2_gain_ranges.keys()){
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 32aa3fe04..cf3b29ddc 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.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
@@ -174,7 +174,14 @@ rfx_xcvr::rfx_xcvr(
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
- this->get_rx_subtree()->create<std::string>("name").set("RFX RX");
+ if(get_rx_id() == 0x0024) this->get_rx_subtree()->create<std::string>("name").set("RFX400 RX");
+ else if(get_rx_id() == 0x0025) this->get_rx_subtree()->create<std::string>("name").set("RFX900 RX");
+ else if(get_rx_id() == 0x0034) this->get_rx_subtree()->create<std::string>("name").set("RFX1800 RX");
+ else if(get_rx_id() == 0x0026) this->get_rx_subtree()->create<std::string>("name").set("RFX1200 RX");
+ else if(get_rx_id() == 0x002c) this->get_rx_subtree()->create<std::string>("name").set("RFX2200 RX");
+ else if(get_rx_id() == 0x0027) this->get_rx_subtree()->create<std::string>("name").set("RFX2400 RX");
+ else this->get_rx_subtree()->create<std::string>("name").set("RFX RX");
+
this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&rfx_xcvr::get_locked, this, dboard_iface::UNIT_RX));
BOOST_FOREACH(const std::string &name, _rx_gain_ranges.keys()){
@@ -203,7 +210,14 @@ rfx_xcvr::rfx_xcvr(
////////////////////////////////////////////////////////////////////
// Register TX properties
////////////////////////////////////////////////////////////////////
- this->get_tx_subtree()->create<std::string>("name").set("RFX TX");
+ if(get_tx_id() == 0x0028) this->get_tx_subtree()->create<std::string>("name").set("RFX400 TX");
+ else if(get_tx_id() == 0x0029) this->get_tx_subtree()->create<std::string>("name").set("RFX900 TX");
+ else if(get_tx_id() == 0x0035) this->get_tx_subtree()->create<std::string>("name").set("RFX1800 TX");
+ else if(get_tx_id() == 0x002a) this->get_tx_subtree()->create<std::string>("name").set("RFX1200 TX");
+ else if(get_tx_id() == 0x002d) this->get_tx_subtree()->create<std::string>("name").set("RFX2200 TX");
+ else if(get_tx_id() == 0x002b) this->get_tx_subtree()->create<std::string>("name").set("RFX2400 TX");
+ else this->get_tx_subtree()->create<std::string>("name").set("RFX TX");
+
this->get_tx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&rfx_xcvr::get_locked, this, dboard_iface::UNIT_TX));
this->get_tx_subtree()->create<int>("gains"); //phony property so this dir exists
@@ -258,7 +272,7 @@ void rfx_xcvr::set_rx_ant(const std::string &ant){
//set the rx atr regs that change with antenna setting
if (ant == "CAL") {
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, _power_up | ANT_TXRX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, _power_up | ANT_TXRX | MIXER_ENB);
this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_TXRX | MIXER_ENB);
this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, _power_up | MIXER_ENB | ANT_TXRX );
}
@@ -358,7 +372,7 @@ double rfx_xcvr::set_lo_freq(
* The goal here to to loop though possible R dividers,
* band select clock dividers, and prescaler values.
* Calculate the A and B counters for each set of values.
- * The loop exists when it meets all of the constraints.
+ * The loop exits when it meets all of the constraints.
* The resulting loop values are loaded into the registers.
*
* fvco = [P*B + A] * fref/R
diff --git a/host/lib/usrp/dboard/db_sbx_common.cpp b/host/lib/usrp/dboard/db_sbx_common.cpp
index d1cd5b373..a51dee361 100644
--- a/host/lib/usrp/dboard/db_sbx_common.cpp
+++ b/host/lib/usrp/dboard/db_sbx_common.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
@@ -127,7 +127,10 @@ sbx_xcvr::sbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
- this->get_rx_subtree()->create<std::string>("name").set("SBX RX");
+ if(get_rx_id() == 0x054) this->get_rx_subtree()->create<std::string>("name").set("SBXv3 RX");
+ else if(get_rx_id() == 0x065) this->get_rx_subtree()->create<std::string>("name").set("SBXv4 RX");
+ else this->get_rx_subtree()->create<std::string>("name").set("SBX RX");
+
this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&sbx_xcvr::get_locked, this, dboard_iface::UNIT_RX));
BOOST_FOREACH(const std::string &name, sbx_rx_gain_ranges.keys()){
@@ -156,7 +159,10 @@ sbx_xcvr::sbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){
////////////////////////////////////////////////////////////////////
// Register TX properties
////////////////////////////////////////////////////////////////////
- this->get_tx_subtree()->create<std::string>("name").set("SBX TX");
+ if(get_tx_id() == 0x055) this->get_tx_subtree()->create<std::string>("name").set("SBXv3 TX");
+ else if(get_tx_id() == 0x067) this->get_tx_subtree()->create<std::string>("name").set("SBXv4 TX");
+ else this->get_tx_subtree()->create<std::string>("name").set("SBX TX");
+
this->get_tx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&sbx_xcvr::get_locked, this, dboard_iface::UNIT_TX));
BOOST_FOREACH(const std::string &name, sbx_tx_gain_ranges.keys()){
@@ -213,8 +219,8 @@ void sbx_xcvr::update_atr(void){
int tx_pga0_iobits = tx_pga0_gain_to_iobits(_tx_gains["PGA0"]);
int rx_lo_lpf_en = (_rx_lo_freq == sbx_enable_rx_lo_filter.clip(_rx_lo_freq)) ? LO_LPF_EN : 0;
int tx_lo_lpf_en = (_tx_lo_freq == sbx_enable_tx_lo_filter.clip(_tx_lo_freq)) ? LO_LPF_EN : 0;
- int rx_ld_led = get_locked(dboard_iface::UNIT_RX).to_bool() ? 0 : RX_LED_LD;
- int tx_ld_led = get_locked(dboard_iface::UNIT_TX).to_bool() ? 0 : TX_LED_LD;
+ int rx_ld_led = _rx_lo_lock_cache ? 0 : RX_LED_LD;
+ int tx_ld_led = _tx_lo_lock_cache ? 0 : TX_LED_LD;
int rx_ant_led = _rx_ant == "TX/RX" ? RX_LED_RX1RX2 : 0;
int tx_ant_led = _tx_ant == "TX/RX" ? 0 : TX_LED_TXRX;
@@ -283,8 +289,14 @@ void sbx_xcvr::set_tx_ant(const std::string &ant){
**********************************************************************/
double sbx_xcvr::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {
const double actual = db_actual->set_lo_freq(unit, target_freq);
- if (unit == dboard_iface::UNIT_RX) _rx_lo_freq = actual;
- if (unit == dboard_iface::UNIT_TX) _tx_lo_freq = actual;
+ if (unit == dboard_iface::UNIT_RX){
+ _rx_lo_lock_cache = false;
+ _rx_lo_freq = actual;
+ }
+ if (unit == dboard_iface::UNIT_TX){
+ _tx_lo_lock_cache = false;
+ _tx_lo_freq = actual;
+ }
update_atr();
return actual;
}
@@ -292,6 +304,13 @@ double sbx_xcvr::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {
sensor_value_t sbx_xcvr::get_locked(dboard_iface::unit_t unit) {
const bool locked = (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
+
+ if (unit == dboard_iface::UNIT_RX) _rx_lo_lock_cache = locked;
+ if (unit == dboard_iface::UNIT_TX) _tx_lo_lock_cache = locked;
+
+ //write the new lock cache setting to atr regs
+ update_atr();
+
return sensor_value_t("LO", locked, "locked", "unlocked");
}
diff --git a/host/lib/usrp/dboard/db_sbx_common.hpp b/host/lib/usrp/dboard/db_sbx_common.hpp
index 501a7f1fc..2a0e83115 100644
--- a/host/lib/usrp/dboard/db_sbx_common.hpp
+++ b/host/lib/usrp/dboard/db_sbx_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
@@ -138,6 +138,7 @@ protected:
uhd::dict<std::string, double> _tx_gains, _rx_gains;
double _rx_lo_freq, _tx_lo_freq;
std::string _tx_ant, _rx_ant;
+ bool _rx_lo_lock_cache, _tx_lo_lock_cache;
void set_rx_ant(const std::string &ant);
void set_tx_ant(const std::string &ant);
diff --git a/host/lib/usrp/dboard/db_sbx_version3.cpp b/host/lib/usrp/dboard/db_sbx_version3.cpp
index 6e20d5882..040bef12f 100644
--- a/host/lib/usrp/dboard/db_sbx_version3.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version3.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
@@ -75,7 +75,6 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
//increase RF divider until acceptable VCO frequency
- //start with target_freq*2 because mixer has divide by 2
double vco_freq = target_freq;
while (vco_freq < 2.2e9) {
vco_freq *= 2;
@@ -83,7 +82,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
- adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
+ adf4350_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
/*
* The goal here is to loop though possible R dividers,
@@ -91,7 +90,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
* (frac) dividers.
*
* Calculate the N and F dividers for each set of values.
- * The loop exists when it meets all of the constraints.
+ * The loop exits when it meets all of the constraints.
* The resulting loop values are loaded into the registers.
*
* from pg.21
@@ -110,7 +109,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
if (pfd_freq > 25e6) continue;
//ignore fractional part of tuning
- N = int(std::floor(vco_freq/pfd_freq));
+ N = int(std::floor(target_freq/pfd_freq));
//keep N > minimum int divider requirement
if (N < prescaler_to_min_int_div[prescaler]) continue;
@@ -125,7 +124,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
//Fractional-N calculation
MOD = 4095; //max fractional accuracy
- FRAC = int((vco_freq/pfd_freq - N)*MOD);
+ FRAC = int((target_freq/pfd_freq - N)*MOD);
//Reference divide-by-2 for 50% duty cycle
// if R even, move one divide by 2 to to regs.reference_divide_by_2
@@ -135,12 +134,12 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv);
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));
UHD_LOGV(often)
<< boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl
+ << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
<< boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
@@ -155,6 +154,9 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.frac_12_bit = FRAC;
regs.int_16_bit = N;
regs.mod_12_bit = MOD;
+ regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
+ regs.feedback_select = adf4350_regs_t::FEEDBACK_SELECT_DIVIDED;
+ regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
regs.prescaler = prescaler;
regs.r_counter_10_bit = R;
regs.reference_divide_by_2 = T;
diff --git a/host/lib/usrp/dboard/db_sbx_version4.cpp b/host/lib/usrp/dboard/db_sbx_version4.cpp
index c8128d5f4..f091caab7 100644
--- a/host/lib/usrp/dboard/db_sbx_version4.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version4.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
@@ -78,7 +78,6 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
if(ref_freq <= 12.5e6) D = adf4351_regs_t::REFERENCE_DOUBLER_ENABLED;
//increase RF divider until acceptable VCO frequency
- //start with target_freq*2 because mixer has divide by 2
double vco_freq = target_freq;
while (vco_freq < 2.2e9) {
vco_freq *= 2;
@@ -86,7 +85,7 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
- adf4351_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
+ adf4351_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
/*
* The goal here is to loop though possible R dividers,
@@ -94,7 +93,7 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
* (frac) dividers.
*
* Calculate the N and F dividers for each set of values.
- * The loop exists when it meets all of the constraints.
+ * The loop exits when it meets all of the constraints.
* The resulting loop values are loaded into the registers.
*
* from pg.21
@@ -128,7 +127,7 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
//Fractional-N calculation
MOD = 4095; //max fractional accuracy
- FRAC = int((vco_freq/pfd_freq - N)*MOD);
+ FRAC = int((target_freq/pfd_freq - N)*MOD);
//Reference divide-by-2 for 50% duty cycle
// if R even, move one divide by 2 to to regs.reference_divide_by_2
@@ -138,12 +137,12 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv);
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));
UHD_LOGV(often)
<< boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl
+ << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
<< boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
@@ -158,6 +157,9 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.frac_12_bit = FRAC;
regs.int_16_bit = N;
regs.mod_12_bit = MOD;
+ regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
+ regs.feedback_select = adf4351_regs_t::FEEDBACK_SELECT_DIVIDED;
+ regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
regs.prescaler = prescaler;
regs.r_counter_10_bit = R;
regs.reference_divide_by_2 = T;
diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp
index fd86d5b83..edee46cd5 100644
--- a/host/lib/usrp/dboard/db_tvrx.cpp
+++ b/host/lib/usrp/dboard/db_tvrx.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
@@ -186,7 +186,7 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){
// Register properties
////////////////////////////////////////////////////////////////////
this->get_rx_subtree()->create<std::string>("name")
- .set(get_rx_id().to_pp_string());
+ .set("TVRX");
this->get_rx_subtree()->create<int>("sensors"); //phony property so this dir exists
BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){
this->get_rx_subtree()->create<double>("gains/"+name+"/value")
diff --git a/host/lib/usrp/dboard/db_tvrx2.cpp b/host/lib/usrp/dboard/db_tvrx2.cpp
index 628221527..0bfa5229a 100644
--- a/host/lib/usrp/dboard/db_tvrx2.cpp
+++ b/host/lib/usrp/dboard/db_tvrx2.cpp
@@ -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
@@ -955,7 +955,7 @@ tvrx2::tvrx2(ctor_args_t args) : rx_dboard_base(args){
// Register properties
////////////////////////////////////////////////////////////////////
this->get_rx_subtree()->create<std::string>("name")
- .set(get_rx_id().to_pp_string());
+ .set("TVRX2");
this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&tvrx2::get_locked, this));
this->get_rx_subtree()->create<sensor_value_t>("sensors/rssi")
diff --git a/host/lib/usrp/dboard/db_wbx_simple.cpp b/host/lib/usrp/dboard/db_wbx_simple.cpp
index 3d633a672..4ba30255d 100644
--- a/host/lib/usrp/dboard/db_wbx_simple.cpp
+++ b/host/lib/usrp/dboard/db_wbx_simple.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
@@ -81,8 +81,10 @@ wbx_simple::wbx_simple(ctor_args_t args) : wbx_base(args){
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
+
this->get_rx_subtree()->access<std::string>("name").set(
- this->get_rx_subtree()->access<std::string>("name").get() + " + Simple GDB");
+ std::string(str(boost::format("%s+GDB") % this->get_rx_subtree()->access<std::string>("name").get()
+ )));
this->get_rx_subtree()->create<std::string>("antenna/value")
.subscribe(boost::bind(&wbx_simple::set_rx_ant, this, _1))
.set("RX2");
@@ -93,7 +95,8 @@ wbx_simple::wbx_simple(ctor_args_t args) : wbx_base(args){
// Register TX properties
////////////////////////////////////////////////////////////////////
this->get_tx_subtree()->access<std::string>("name").set(
- this->get_tx_subtree()->access<std::string>("name").get() + " + Simple GDB");
+ std::string(str(boost::format("%s+GDB") % this->get_tx_subtree()->access<std::string>("name").get()
+ )));
this->get_tx_subtree()->create<std::string>("antenna/value")
.subscribe(boost::bind(&wbx_simple::set_tx_ant, this, _1))
.set(wbx_tx_antennas.at(0));
diff --git a/host/lib/usrp/dboard/db_wbx_version2.cpp b/host/lib/usrp/dboard/db_wbx_version2.cpp
index ad31339e7..643fcd37f 100644
--- a/host/lib/usrp/dboard/db_wbx_version2.cpp
+++ b/host/lib/usrp/dboard/db_wbx_version2.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
@@ -78,7 +78,7 @@ wbx_base::wbx_version2::wbx_version2(wbx_base *_self_wbx_base) {
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
- this->get_rx_subtree()->create<std::string>("name").set("WBX RX v2");
+ this->get_rx_subtree()->create<std::string>("name").set("WBXv2 RX");
this->get_rx_subtree()->create<double>("freq/value")
.coerce(boost::bind(&wbx_base::wbx_version2::set_lo_freq, this, dboard_iface::UNIT_RX, _1))
.set((wbx_v2_freq_range.start() + wbx_v2_freq_range.stop())/2.0);
@@ -87,7 +87,7 @@ wbx_base::wbx_version2::wbx_version2(wbx_base *_self_wbx_base) {
////////////////////////////////////////////////////////////////////
// Register TX properties
////////////////////////////////////////////////////////////////////
- this->get_tx_subtree()->create<std::string>("name").set("WBX TX v2");
+ this->get_tx_subtree()->create<std::string>("name").set("WBXv2 TX");
BOOST_FOREACH(const std::string &name, wbx_v2_tx_gain_ranges.keys()){
self_base->get_tx_subtree()->create<double>("gains/"+name+"/value")
.coerce(boost::bind(&wbx_base::wbx_version2::set_tx_gain, this, _1, name))
@@ -166,6 +166,9 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
"WBX tune: target frequency %f Mhz"
) % (target_freq/1e6) << std::endl;
+ //start with target_freq*2 because mixer has divide by 2
+ target_freq *= 2;
+
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
(0,23) //adf4350_regs_t::PRESCALER_4_5
@@ -193,12 +196,13 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
//increase RF divider until acceptable VCO frequency
- //start with target_freq*2 because mixer has divide by 2
- double vco_freq = target_freq*2;
+ const bool do_sync = (target_freq/2 > ref_freq);
+ double vco_freq = target_freq;
while (vco_freq < 2.2e9) {
vco_freq *= 2;
RFdiv *= 2;
}
+ if (do_sync) vco_freq = target_freq;
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
@@ -209,7 +213,7 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
* (frac) dividers.
*
* Calculate the N and F dividers for each set of values.
- * The loop exists when it meets all of the constraints.
+ * The loop exits when it meets all of the constraints.
* The resulting loop values are loaded into the registers.
*
* from pg.21
@@ -253,14 +257,13 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv/2);
-
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/2/(vco_freq/target_freq));
UHD_LOGV(often)
<< boost::format("WBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl
+ << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
<< boost::format("WBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
@@ -270,6 +273,12 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.frac_12_bit = FRAC;
regs.int_16_bit = N;
regs.mod_12_bit = MOD;
+ if (do_sync)
+ {
+ regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
+ regs.feedback_select = adf4350_regs_t::FEEDBACK_SELECT_DIVIDED;
+ regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ }
regs.prescaler = prescaler;
regs.r_counter_10_bit = R;
regs.reference_divide_by_2 = T;
diff --git a/host/lib/usrp/dboard/db_wbx_version3.cpp b/host/lib/usrp/dboard/db_wbx_version3.cpp
index 7ef47edd4..6771d184f 100644
--- a/host/lib/usrp/dboard/db_wbx_version3.cpp
+++ b/host/lib/usrp/dboard/db_wbx_version3.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
@@ -84,7 +84,7 @@ wbx_base::wbx_version3::wbx_version3(wbx_base *_self_wbx_base) {
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
- this->get_rx_subtree()->create<std::string>("name").set("WBX RX v3");
+ this->get_rx_subtree()->create<std::string>("name").set("WBXv3 RX");
this->get_rx_subtree()->create<double>("freq/value")
.coerce(boost::bind(&wbx_base::wbx_version3::set_lo_freq, this, dboard_iface::UNIT_RX, _1))
.set((wbx_v3_freq_range.start() + wbx_v3_freq_range.stop())/2.0);
@@ -93,7 +93,7 @@ wbx_base::wbx_version3::wbx_version3(wbx_base *_self_wbx_base) {
////////////////////////////////////////////////////////////////////
// Register TX properties
////////////////////////////////////////////////////////////////////
- this->get_tx_subtree()->create<std::string>("name").set("WBX TX v3");
+ this->get_tx_subtree()->create<std::string>("name").set("WBXv3 TX");
BOOST_FOREACH(const std::string &name, wbx_v3_tx_gain_ranges.keys()){
self_base->get_tx_subtree()->create<double>("gains/"+name+"/value")
.coerce(boost::bind(&wbx_base::wbx_version3::set_tx_gain, this, _1, name))
@@ -198,6 +198,9 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
"WBX tune: target frequency %f Mhz"
) % (target_freq/1e6) << std::endl;
+ //start with target_freq*2 because mixer has divide by 2
+ target_freq *= 2;
+
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
(0,23) //adf4350_regs_t::PRESCALER_4_5
@@ -225,12 +228,13 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
//increase RF divider until acceptable VCO frequency
- //start with target_freq*2 because mixer has divide by 2
- double vco_freq = target_freq*2;
+ const bool do_sync = (target_freq/2 > ref_freq);
+ double vco_freq = target_freq;
while (vco_freq < 2.2e9) {
vco_freq *= 2;
RFdiv *= 2;
}
+ if (do_sync) vco_freq = target_freq;
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
@@ -241,7 +245,7 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
* (frac) dividers.
*
* Calculate the N and F dividers for each set of values.
- * The loop exists when it meets all of the constraints.
+ * The loop exits when it meets all of the constraints.
* The resulting loop values are loaded into the registers.
*
* from pg.21
@@ -285,14 +289,13 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv/2);
-
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/2/(vco_freq/target_freq));
UHD_LOGV(often)
<< boost::format("WBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl
+ << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
<< boost::format("WBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
@@ -302,6 +305,12 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.frac_12_bit = FRAC;
regs.int_16_bit = N;
regs.mod_12_bit = MOD;
+ if (do_sync)
+ {
+ regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
+ regs.feedback_select = adf4350_regs_t::FEEDBACK_SELECT_DIVIDED;
+ regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ }
regs.prescaler = prescaler;
regs.r_counter_10_bit = R;
regs.reference_divide_by_2 = T;
diff --git a/host/lib/usrp/dboard/db_wbx_version4.cpp b/host/lib/usrp/dboard/db_wbx_version4.cpp
index 3a85826cd..057cdb6ce 100644
--- a/host/lib/usrp/dboard/db_wbx_version4.cpp
+++ b/host/lib/usrp/dboard/db_wbx_version4.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
@@ -85,7 +85,7 @@ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) {
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
- this->get_rx_subtree()->create<std::string>("name").set("WBX RX v4");
+ this->get_rx_subtree()->create<std::string>("name").set("WBXv4 RX");
this->get_rx_subtree()->create<double>("freq/value")
.coerce(boost::bind(&wbx_base::wbx_version4::set_lo_freq, this, dboard_iface::UNIT_RX, _1))
.set((wbx_v4_freq_range.start() + wbx_v4_freq_range.stop())/2.0);
@@ -94,7 +94,7 @@ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) {
////////////////////////////////////////////////////////////////////
// Register TX properties
////////////////////////////////////////////////////////////////////
- this->get_tx_subtree()->create<std::string>("name").set("WBX TX v4");
+ this->get_tx_subtree()->create<std::string>("name").set("WBXv4 TX");
BOOST_FOREACH(const std::string &name, wbx_v4_tx_gain_ranges.keys()){
self_base->get_tx_subtree()->create<double>("gains/"+name+"/value")
.coerce(boost::bind(&wbx_base::wbx_version4::set_tx_gain, this, _1, name))
@@ -179,6 +179,9 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
"WBX tune: target frequency %f Mhz"
) % (target_freq/1e6) << std::endl;
+ //start with target_freq*2 because mixer has divide by 2
+ target_freq *= 2;
+
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
(0,23) //adf4351_regs_t::PRESCALER_4_5
@@ -208,12 +211,13 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
if(ref_freq <= 12.5e6) D = adf4351_regs_t::REFERENCE_DOUBLER_ENABLED;
//increase RF divider until acceptable VCO frequency
- //start with target_freq*2 because mixer has divide by 2
- double vco_freq = target_freq*2;
+ const bool do_sync = (target_freq/2 > ref_freq);
+ double vco_freq = target_freq;
while (vco_freq < 2.2e9) {
vco_freq *= 2;
RFdiv *= 2;
}
+ if (do_sync) vco_freq = target_freq;
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
adf4351_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
@@ -268,14 +272,13 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
}
//actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv/2);
-
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/2/(vco_freq/target_freq));
UHD_LOGV(often)
<< boost::format("WBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl
+ << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
<< boost::format("WBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
@@ -285,6 +288,12 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.frac_12_bit = FRAC;
regs.int_16_bit = N;
regs.mod_12_bit = MOD;
+ if (do_sync)
+ {
+ regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
+ regs.feedback_select = adf4351_regs_t::FEEDBACK_SELECT_DIVIDED;
+ regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ }
regs.prescaler = prescaler;
regs.r_counter_10_bit = R;
regs.reference_divide_by_2 = T;
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index 9d0033a9a..da894fc9b 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.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
@@ -228,7 +228,7 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){
// Register RX properties
////////////////////////////////////////////////////////////////////
this->get_rx_subtree()->create<std::string>("name")
- .set(get_rx_id().to_pp_string());
+ .set("XCVR2450 RX");
this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&xcvr2450::get_locked, this));
this->get_rx_subtree()->create<sensor_value_t>("sensors/rssi")
@@ -266,7 +266,7 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){
// Register TX properties
////////////////////////////////////////////////////////////////////
this->get_tx_subtree()->create<std::string>("name")
- .set(get_tx_id().to_pp_string());
+ .set("XCVR2450 TX");
this->get_tx_subtree()->create<sensor_value_t>("sensors/lo_locked")
.publish(boost::bind(&xcvr2450::get_locked, this));
BOOST_FOREACH(const std::string &name, xcvr_tx_gain_ranges.keys()){
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index d610c0b12..d55ea5ec5 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -64,7 +64,7 @@ static device_addrs_t e100_find(const device_addr_t &hint){
new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string();
try{
i2c_iface::sptr i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE);
- const mboard_eeprom_t mb_eeprom(*i2c_iface, mboard_eeprom_t::MAP_E100);
+ const mboard_eeprom_t mb_eeprom(*i2c_iface, E100_EEPROM_MAP_KEY);
new_addr["name"] = mb_eeprom["name"];
new_addr["serial"] = mb_eeprom["serial"];
}
@@ -120,7 +120,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
//read the eeprom so we can determine the hardware
_dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE);
- const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100);
+ const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, E100_EEPROM_MAP_KEY);
//determine the model string for this device
const std::string model = device_addr.get("model", mb_eeprom.get("model", ""));
@@ -189,7 +189,8 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
_tree->create<std::string>("/name").set("E-Series Device");
const fs_path mb_path = "/mboards/0";
- _tree->create<std::string>(mb_path / "name").set(str(boost::format("%s (euewanee)") % model));
+ _tree->create<std::string>(mb_path / "name").set(model);
+ _tree->create<std::string>(mb_path / "codename").set("Euwanee");
////////////////////////////////////////////////////////////////////
// setup the mboard eeprom
@@ -349,7 +350,8 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
//setup reference source props
_tree->create<std::string>(mb_path / "clock_source/value")
.subscribe(boost::bind(&e100_impl::update_clock_source, this, _1));
- static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto");
+ std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto");
+ if (_gps and _gps->gps_detected()) clock_sources.push_back("gpsdo");
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
////////////////////////////////////////////////////////////////////
@@ -425,10 +427,11 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
_tree->access<std::string>(mb_path / "time_source/value").set("none");
//GPS installed: use external ref, time, and init time spec
- if (_gps.get() != NULL and _gps->gps_detected()){
+ if (_gps and _gps->gps_detected()){
+ _time64->enable_gpsdo();
UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl;
- _tree->access<std::string>(mb_path / "time_source/value").set("external");
- _tree->access<std::string>(mb_path / "clock_source/value").set("external");
+ _tree->access<std::string>(mb_path / "time_source/value").set("gpsdo");
+ _tree->access<std::string>(mb_path / "clock_source/value").set("gpsdo");
UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl;
_time64->set_time_next_pps(time_spec_t(time_t(_gps->get_sensor("gps_time").to_int()+1)));
}
@@ -448,7 +451,7 @@ double e100_impl::update_rx_codec_gain(const double gain){
}
void e100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){
- mb_eeprom.commit(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100);
+ mb_eeprom.commit(*_dev_i2c_iface, E100_EEPROM_MAP_KEY);
}
void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
@@ -461,6 +464,7 @@ void e100_impl::update_clock_source(const std::string &source){
if (source == "auto") _clock_ctrl->use_auto_ref();
else if (source == "internal") _clock_ctrl->use_internal_ref();
else if (source == "external") _clock_ctrl->use_external_ref();
+ else if (source == "gpsdo") _clock_ctrl->use_external_ref();
else throw uhd::runtime_error("unhandled clock configuration reference source: " + source);
}
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 1d36cb2ac..381c085e0 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -49,10 +49,11 @@ 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 = 0x09;
+static const boost::uint16_t E100_FPGA_COMPAT_NUM = 10;
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;
+static const std::string E100_EEPROM_MAP_KEY = "E100";
//! load an fpga image from a bin file into the usrp-e fpga
extern void e100_load_fpga(const std::string &bin_file);
diff --git a/host/lib/usrp/e100/e100_mmap_zero_copy.cpp b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp
index cdb7094f4..58beeb424 100644
--- a/host/lib/usrp/e100/e100_mmap_zero_copy.cpp
+++ b/host/lib/usrp/e100/e100_mmap_zero_copy.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
@@ -19,6 +19,7 @@
#include <uhd/transport/zero_copy.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/exception.hpp>
+#include <boost/make_shared.hpp>
#include <linux/usrp_e.h>
#include <sys/mman.h> //mmap
#include <unistd.h> //getpagesize
@@ -41,23 +42,19 @@ public:
_mem(mem), _info(info) { /* NOP */ }
void release(void){
- if (_info->flags != RB_USER_PROCESS) return;
if (fp_verbose) UHD_LOGV(always) << "recv buff: release" << std::endl;
_info->flags = RB_KERNEL; //release the frame
}
- bool ready(void){return _info->flags & RB_USER;}
+ UHD_INLINE bool ready(void){return _info->flags & RB_USER;}
- sptr get_new(void){
- if (fp_verbose) UHD_LOGV(always) << " make_recv_buff: " << get_size() << std::endl;
+ UHD_INLINE sptr get_new(void){
+ if (fp_verbose) UHD_LOGV(always) << " make_recv_buff: " << _info->len << std::endl;
_info->flags = RB_USER_PROCESS; //claim the frame
- return make_managed_buffer(this);
+ return make(this, _mem, _info->len);
}
private:
- const void *get_buff(void) const{return _mem;}
- size_t get_size(void) const{return _info->len;}
-
void *_mem;
ring_buffer_info *_info;
};
@@ -71,28 +68,24 @@ public:
e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd):
_mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ }
- void commit(size_t len){
- if (_info->flags != RB_USER_PROCESS) return;
- if (fp_verbose) UHD_LOGV(always) << "send buff: commit " << len << std::endl;
- _info->len = len;
+ void release(void){
+ if (fp_verbose) UHD_LOGV(always) << "send buff: commit " << size() << std::endl;
+ _info->len = size();
_info->flags = RB_USER; //release the frame
if (::write(_fd, NULL, 0) < 0){ //notifies the kernel
UHD_LOGV(rarely) << UHD_THROW_SITE_INFO("write error") << std::endl;
}
}
- bool ready(void){return _info->flags & RB_KERNEL;}
+ UHD_INLINE bool ready(void){return _info->flags & RB_KERNEL;}
- sptr get_new(void){
- if (fp_verbose) UHD_LOGV(always) << " make_send_buff: " << get_size() << std::endl;
+ UHD_INLINE sptr get_new(void){
+ if (fp_verbose) UHD_LOGV(always) << " make_send_buff: " << _len << std::endl;
_info->flags = RB_USER_PROCESS; //claim the frame
- return make_managed_buffer(this);
+ return make(this, _mem, _len);
}
private:
- void *get_buff(void) const{return _mem;}
- size_t get_size(void) const{return _len;}
-
void *_mem;
ring_buffer_info *_info;
size_t _len;
@@ -162,14 +155,14 @@ public:
//initialize the managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _mrb_pool.push_back(e100_mmap_zero_copy_mrb(
+ _mrb_pool.push_back(boost::make_shared<e100_mmap_zero_copy_mrb>(
recv_buff + get_recv_frame_size()*i, (*recv_info) + i
));
}
//initialize the managed send buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _msb_pool.push_back(e100_mmap_zero_copy_msb(
+ _msb_pool.push_back(boost::make_shared<e100_mmap_zero_copy_msb>(
send_buff + get_send_frame_size()*i, (*send_info) + i,
get_send_frame_size(), _fd
));
@@ -183,7 +176,7 @@ public:
managed_recv_buffer::sptr get_recv_buff(double timeout){
if (fp_verbose) UHD_LOGV(always) << "get_recv_buff: " << _recv_index << std::endl;
- e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];
+ e100_mmap_zero_copy_mrb &mrb = *_mrb_pool[_recv_index];
//poll/wait for a ready frame
if (not mrb.ready()){
@@ -215,7 +208,7 @@ public:
managed_send_buffer::sptr get_send_buff(double timeout){
if (fp_verbose) UHD_LOGV(always) << "get_send_buff: " << _send_index << std::endl;
- e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];
+ e100_mmap_zero_copy_msb &msb = *_msb_pool[_send_index];
//poll/wait for a ready frame
if (not msb.ready()){
@@ -254,8 +247,8 @@ private:
size_t _frame_size, _map_size;
//re-usable managed buffers
- std::vector<e100_mmap_zero_copy_mrb> _mrb_pool;
- std::vector<e100_mmap_zero_copy_msb> _msb_pool;
+ std::vector<boost::shared_ptr<e100_mmap_zero_copy_mrb> > _mrb_pool;
+ std::vector<boost::shared_ptr<e100_mmap_zero_copy_msb> > _msb_pool;
//indexes into sub-sections of mapped memory
size_t _recv_index, _send_index;
diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp
index 785d30296..1f4abc27e 100644
--- a/host/lib/usrp/mboard_eeprom.cpp
+++ b/host/lib/usrp/mboard_eeprom.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
@@ -84,17 +84,20 @@ static std::string uint16_bytes_to_string(const byte_vector_t &bytes){
**********************************************************************/
static const boost::uint8_t N100_EEPROM_ADDR = 0x50;
-static const uhd::dict<std::string, boost::uint8_t> USRP_N100_OFFSETS = boost::assign::map_list_of
- ("hardware", 0x00)
- ("mac-addr", 0x02)
- ("ip-addr", 0x0C)
- //leave space here for other addresses (perhaps)
- ("revision", 0x12)
- ("product", 0x14)
- ("gpsdo", 0x17)
- ("serial", 0x18)
- ("name", 0x18 + SERIAL_LEN)
-;
+struct n100_eeprom_map{
+ boost::uint16_t hardware;
+ boost::uint8_t mac_addr[6];
+ boost::uint32_t subnet;
+ boost::uint32_t ip_addr;
+ boost::uint16_t _pad0;
+ boost::uint16_t revision;
+ boost::uint16_t product;
+ unsigned char _pad1;
+ unsigned char gpsdo;
+ unsigned char serial[SERIAL_LEN];
+ unsigned char name[NAME_MAX_LEN];
+ boost::uint32_t gateway;
+};
enum n200_gpsdo_type{
N200_GPSDO_NONE = 0,
@@ -105,30 +108,36 @@ enum n200_gpsdo_type{
static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
//extract the hardware number
mb_eeprom["hardware"] = uint16_bytes_to_string(
- iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["hardware"], 2)
+ iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, hardware), 2)
);
//extract the revision number
mb_eeprom["revision"] = uint16_bytes_to_string(
- iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["revision"], 2)
+ iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, revision), 2)
);
//extract the product code
mb_eeprom["product"] = uint16_bytes_to_string(
- iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["product"], 2)
+ iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, product), 2)
);
//extract the addresses
mb_eeprom["mac-addr"] = mac_addr_t::from_bytes(iface.read_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["mac-addr"], 6
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, mac_addr), 6
)).to_string();
boost::asio::ip::address_v4::bytes_type ip_addr_bytes;
- byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], 4), ip_addr_bytes);
+ byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, ip_addr), 4), ip_addr_bytes);
mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
+ byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, subnet), 4), ip_addr_bytes);
+ mb_eeprom["subnet"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
+
+ byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gateway), 4), ip_addr_bytes);
+ mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
+
//gpsdo capabilities
- boost::uint8_t gpsdo_byte = iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["gpsdo"], 1).at(0);
+ boost::uint8_t gpsdo_byte = iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gpsdo), 1).at(0);
switch(n200_gpsdo_type(gpsdo_byte)){
case N200_GPSDO_INTERNAL: mb_eeprom["gpsdo"] = "internal"; break;
case N200_GPSDO_ONBOARD: mb_eeprom["gpsdo"] = "onboard"; break;
@@ -137,12 +146,12 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
//extract the serial
mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"], SERIAL_LEN
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, serial), SERIAL_LEN
));
//extract the name
mb_eeprom["name"] = bytes_to_string(iface.read_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], NAME_MAX_LEN
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, name), NAME_MAX_LEN
));
//Empty serial correction: use the mac address to determine serial.
@@ -158,32 +167,44 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
//parse the revision number
if (mb_eeprom.has_key("hardware")) iface.write_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["hardware"],
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, hardware),
string_to_uint16_bytes(mb_eeprom["hardware"])
);
//parse the revision number
if (mb_eeprom.has_key("revision")) iface.write_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["revision"],
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, revision),
string_to_uint16_bytes(mb_eeprom["revision"])
);
//parse the product code
if (mb_eeprom.has_key("product")) iface.write_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["product"],
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, product),
string_to_uint16_bytes(mb_eeprom["product"])
);
//store the addresses
if (mb_eeprom.has_key("mac-addr")) iface.write_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["mac-addr"],
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, mac_addr),
mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes()
);
if (mb_eeprom.has_key("ip-addr")){
byte_vector_t ip_addr_bytes(4);
byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes);
- iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], ip_addr_bytes);
+ iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, ip_addr), ip_addr_bytes);
+ }
+
+ if (mb_eeprom.has_key("subnet")){
+ byte_vector_t ip_addr_bytes(4);
+ byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"]).to_bytes(), ip_addr_bytes);
+ iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, subnet), ip_addr_bytes);
+ }
+
+ if (mb_eeprom.has_key("gateway")){
+ byte_vector_t ip_addr_bytes(4);
+ byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes);
+ iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gateway), ip_addr_bytes);
}
//gpsdo capabilities
@@ -191,18 +212,18 @@ static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
boost::uint8_t gpsdo_byte = N200_GPSDO_NONE;
if (mb_eeprom["gpsdo"] == "internal") gpsdo_byte = N200_GPSDO_INTERNAL;
if (mb_eeprom["gpsdo"] == "onboard") gpsdo_byte = N200_GPSDO_ONBOARD;
- iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["gpsdo"], byte_vector_t(1, gpsdo_byte));
+ iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gpsdo), byte_vector_t(1, gpsdo_byte));
}
//store the serial
if (mb_eeprom.has_key("serial")) iface.write_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"],
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, serial),
string_to_bytes(mb_eeprom["serial"], SERIAL_LEN)
);
//store the name
if (mb_eeprom.has_key("name")) iface.write_eeprom(
- N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"],
+ N100_EEPROM_ADDR, offsetof(n100_eeprom_map, name),
string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN)
);
}
@@ -426,20 +447,16 @@ mboard_eeprom_t::mboard_eeprom_t(void){
/* NOP */
}
-mboard_eeprom_t::mboard_eeprom_t(i2c_iface &iface, map_type map){
- switch(map){
- case MAP_N100: load_n100(*this, iface); break;
- case MAP_B000: load_b000(*this, iface); break;
- case MAP_B100: load_b100(*this, iface); break;
- case MAP_E100: load_e100(*this, iface); break;
- }
+mboard_eeprom_t::mboard_eeprom_t(i2c_iface &iface, const std::string &which){
+ if (which == "N100") load_n100(*this, iface);
+ if (which == "B000") load_b000(*this, iface);
+ if (which == "B100") load_b100(*this, iface);
+ if (which == "E100") load_e100(*this, iface);
}
-void mboard_eeprom_t::commit(i2c_iface &iface, map_type map) const{
- switch(map){
- case MAP_N100: store_n100(*this, iface); break;
- case MAP_B000: store_b000(*this, iface); break;
- case MAP_B100: store_b100(*this, iface); break;
- case MAP_E100: store_e100(*this, iface); break;
- }
+void mboard_eeprom_t::commit(i2c_iface &iface, const std::string &which) const{
+ if (which == "N100") store_n100(*this, iface);
+ if (which == "B000") store_b000(*this, iface);
+ if (which == "B100") store_b100(*this, iface);
+ if (which == "E100") store_e100(*this, iface);
}
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 93c0eada6..1267da89c 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.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
@@ -21,6 +21,10 @@
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/gain_group.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
+#include <uhd/usrp/dboard_eeprom.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
@@ -214,6 +218,44 @@ public:
return _dev;
}
+ dict<std::string, std::string> get_usrp_rx_info(size_t chan){
+ mboard_chan_pair mcp = rx_chan_to_mcp(chan);
+ dict<std::string, std::string> usrp_info;
+
+ mboard_eeprom_t mb_eeprom = _tree->access<mboard_eeprom_t>(mb_root(mcp.mboard) / "eeprom").get();
+ dboard_eeprom_t db_eeprom = _tree->access<dboard_eeprom_t>(rx_rf_fe_root(mcp.chan).branch_path().branch_path() / "rx_eeprom").get();
+
+ usrp_info["mboard_id"] = _tree->access<std::string>(mb_root(mcp.mboard) / "name").get();
+ usrp_info["mboard_name"] = mb_eeprom["name"];
+ usrp_info["mboard_serial"] = mb_eeprom["serial"];
+ usrp_info["rx_id"] = db_eeprom.id.to_pp_string();
+ usrp_info["rx_subdev_name"] = _tree->access<std::string>(rx_rf_fe_root(mcp.chan) / "name").get();
+ usrp_info["rx_subdev_spec"] = _tree->access<subdev_spec_t>(mb_root(mcp.mboard) / "rx_subdev_spec").get().to_string();
+ usrp_info["rx_serial"] = db_eeprom.serial;
+ usrp_info["rx_antenna"] = _tree->access<std::string>(rx_rf_fe_root(mcp.chan) / "antenna" / "value").get();
+
+ return usrp_info;
+ }
+
+ dict<std::string, std::string> get_usrp_tx_info(size_t chan){
+ mboard_chan_pair mcp = tx_chan_to_mcp(chan);
+ dict<std::string, std::string> usrp_info;
+
+ mboard_eeprom_t mb_eeprom = _tree->access<mboard_eeprom_t>(mb_root(mcp.mboard) / "eeprom").get();
+ dboard_eeprom_t db_eeprom = _tree->access<dboard_eeprom_t>(tx_rf_fe_root(mcp.chan).branch_path().branch_path() / "tx_eeprom").get();
+
+ usrp_info["mboard_id"] = _tree->access<std::string>(mb_root(mcp.mboard) / "name").get();
+ usrp_info["mboard_name"] = mb_eeprom["name"];
+ usrp_info["mboard_serial"] = mb_eeprom["serial"];
+ usrp_info["tx_id"] = db_eeprom.id.to_pp_string();
+ usrp_info["tx_subdev_name"] = _tree->access<std::string>(tx_rf_fe_root(mcp.chan) / "name").get();
+ usrp_info["tx_subdev_spec"] = _tree->access<subdev_spec_t>(mb_root(mcp.mboard) / "tx_subdev_spec").get().to_string();
+ usrp_info["tx_serial"] = db_eeprom.serial;
+ usrp_info["tx_antenna"] = _tree->access<std::string>(tx_rf_fe_root(mcp.chan) / "antenna" / "value").get();
+
+ return usrp_info;
+ }
+
/*******************************************************************
* Mboard methods
******************************************************************/
@@ -356,12 +398,27 @@ public:
return true;
}
- void set_command_time(const time_spec_t &, size_t){
- throw uhd::not_implemented_error("Not implemented yet, but we have a very good idea of how to do it.");
+ void set_command_time(const time_spec_t &time_spec, size_t mboard){
+ if (mboard != ALL_MBOARDS){
+ if (not _tree->exists(mb_root(mboard) / "time/cmd")){
+ throw uhd::not_implemented_error("timed command feature not implemented on this hardware");
+ }
+ _tree->access<time_spec_t>(mb_root(mboard) / "time/cmd").set(time_spec);
+ return;
+ }
+ for (size_t m = 0; m < get_num_mboards(); m++){
+ set_command_time(time_spec, m);
+ }
}
- void clear_command_time(size_t){
- throw uhd::not_implemented_error("Not implemented yet, but we have a very good idea of how to do it.");
+ void clear_command_time(size_t mboard){
+ if (mboard != ALL_MBOARDS){
+ _tree->access<time_spec_t>(mb_root(mboard) / "time/cmd").set(time_spec_t(0.0));
+ return;
+ }
+ for (size_t m = 0; m < get_num_mboards(); m++){
+ clear_command_time(m);
+ }
}
void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){
@@ -522,6 +579,10 @@ public:
);
}
+ freq_range_t get_fe_rx_freq_range(size_t chan){
+ return _tree->access<meta_range_t>(rx_rf_fe_root(chan) / "freq" / "range").get();
+ }
+
void set_rx_gain(double gain, const std::string &name, size_t chan){
return rx_gain_group(chan)->set_value(gain, name);
}
@@ -621,10 +682,6 @@ public:
return _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").get();
}
- std::string get_tx_subdev_name(size_t chan){
- return _tree->access<std::string>(tx_rf_fe_root(chan) / "name").get();
- }
-
size_t get_tx_num_channels(void){
size_t sum = 0;
for (size_t m = 0; m < get_num_mboards(); m++){
@@ -633,6 +690,10 @@ public:
return sum;
}
+ std::string get_tx_subdev_name(size_t chan){
+ return _tree->access<std::string>(tx_rf_fe_root(chan) / "name").get();
+ }
+
void set_tx_rate(double rate, size_t chan){
if (chan != ALL_CHANS){
_tree->access<double>(tx_dsp_root(chan) / "rate" / "value").set(rate);
@@ -670,6 +731,10 @@ public:
);
}
+ freq_range_t get_fe_tx_freq_range(size_t chan){
+ return _tree->access<meta_range_t>(tx_rf_fe_root(chan) / "freq" / "range").get();
+ }
+
void set_tx_gain(double gain, const std::string &name, size_t chan){
return tx_gain_group(chan)->set_value(gain, name);
}
diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp
index c82569ea3..7383c9833 100644
--- a/host/lib/usrp/usrp1/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp1/codec_ctrl.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
@@ -27,6 +27,7 @@
#include <boost/format.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
#include <boost/assign/list_of.hpp>
#include <iomanip>
@@ -375,6 +376,12 @@ double usrp1_codec_ctrl_impl::fine_tune(double codec_rate, double target_freq)
void usrp1_codec_ctrl_impl::set_duc_freq(double freq, double rate)
{
double codec_rate = rate * 2;
+
+ //correct for outside of rate (wrap around)
+ freq = std::fmod(freq, rate);
+ if (std::abs(freq) > rate/2.0)
+ freq -= boost::math::sign(freq)*rate;
+
double coarse_freq = coarse_tune(codec_rate, freq);
double fine_freq = fine_tune(codec_rate / 4, freq - coarse_freq);
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index d256df660..1d8b9bd76 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -73,8 +73,8 @@ public:
/* NOP */
}
- void commit(size_t size){
- if (size != 0) this->_commit_cb(_curr_buff, _next_buff, size);
+ void release(void){
+ this->_commit_cb(_curr_buff, _next_buff, size());
}
sptr get_new(
@@ -83,13 +83,13 @@ public:
){
_curr_buff = curr_buff;
_next_buff = next_buff;
- return make_managed_buffer(this);
+ return make(this,
+ _curr_buff.buff->cast<char *>() + _curr_buff.offset,
+ _curr_buff.buff->size() - _curr_buff.offset
+ );
}
private:
- void *get_buff(void) const{return _curr_buff.buff->cast<char *>() + _curr_buff.offset;}
- size_t get_size(void) const{return _curr_buff.buff->size() - _curr_buff.offset;}
-
offset_send_buffer _curr_buff, _next_buff;
commit_cb_type _commit_cb;
};
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 30986ac66..ffe25b81e 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_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
@@ -89,11 +89,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
usrp1_fw_image = find_image_path(hint.get("fw", "usrp1_fw.ihx"));
}
catch(...){
- UHD_MSG(warning) << boost::format(
- "Could not locate USRP1 firmware.\n"
- "Please install the images package.\n"
- );
- return usrp1_addrs;
+ UHD_MSG(warning) << boost::format("Could not locate USRP1 firmware. %s") % print_images_error();
}
UHD_LOG << "USRP1 firmware image: " << usrp1_fw_image << std::endl;
@@ -121,7 +117,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
catch(const uhd::exception &){continue;} //ignore claimed
fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control);
- const mboard_eeprom_t mb_eeprom(*fx2_ctrl, mboard_eeprom_t::MAP_B000);
+ const mboard_eeprom_t mb_eeprom(*fx2_ctrl, USRP1_EEPROM_MAP_KEY);
device_addr_t new_addr;
new_addr["type"] = "usrp1";
new_addr["name"] = mb_eeprom["name"];
@@ -214,14 +210,14 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree = property_tree::make();
_tree->create<std::string>("/name").set("USRP1 Device");
const fs_path mb_path = "/mboards/0";
- _tree->create<std::string>(mb_path / "name").set("USRP1 (Classic)");
+ _tree->create<std::string>(mb_path / "name").set("USRP1");
_tree->create<std::string>(mb_path / "load_eeprom")
.subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1));
////////////////////////////////////////////////////////////////////
// setup the mboard eeprom
////////////////////////////////////////////////////////////////////
- const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B000);
+ const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, USRP1_EEPROM_MAP_KEY);
_tree->create<mboard_eeprom_t>(mb_path / "eeprom")
.set(mb_eeprom)
.subscribe(boost::bind(&usrp1_impl::set_mb_eeprom, this, _1));
@@ -452,7 +448,7 @@ bool usrp1_impl::has_tx_halfband(void){
* Properties callback methods below
**********************************************************************/
void usrp1_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){
- mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B000);
+ mb_eeprom.commit(*_fx2_ctrl, USRP1_EEPROM_MAP_KEY);
}
void usrp1_impl::set_db_eeprom(const std::string &db, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index 581f4cbdd..bdef50ec1 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -38,6 +38,8 @@
#ifndef INCLUDED_USRP1_IMPL_HPP
#define INCLUDED_USRP1_IMPL_HPP
+static const std::string USRP1_EEPROM_MAP_KEY = "B000";
+
/*!
* USRP1 implementation guts:
* The implementation details are encapsulated here.
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index 10f7407b0..da39d9df1 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/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
@@ -32,5 +32,6 @@ IF(ENABLE_USRP2)
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_fifo_ctrl.cpp
)
ENDIF(ENABLE_USRP2)
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index b2912c70c..0ae3b0bd8 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.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
@@ -35,8 +35,9 @@ static const bool enb_test_clk = false;
*/
class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{
public:
- usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){
+ usrp2_clock_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){
_iface = iface;
+ _spiface = spiface;
clk_regs = usrp2_clk_regs_t(_iface->get_rev());
_ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
@@ -331,7 +332,7 @@ private:
*/
void write_reg(boost::uint8_t addr){
boost::uint32_t data = _ad9510_regs.get_write_reg(addr);
- _iface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24);
+ _spiface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24);
}
/*!
@@ -377,7 +378,7 @@ private:
}
usrp2_iface::sptr _iface;
-
+ uhd::spi_iface::sptr _spiface;
usrp2_clk_regs_t clk_regs;
ad9510_regs_t _ad9510_regs;
};
@@ -385,6 +386,6 @@ private:
/***********************************************************************
* Public make function for the ad9510 clock control
**********************************************************************/
-usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface){
- return sptr(new usrp2_clock_ctrl_impl(iface));
+usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){
+ return sptr(new usrp2_clock_ctrl_impl(iface, spiface));
}
diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp
index 9ccbc959e..067e1e35d 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.hpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.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
@@ -29,10 +29,11 @@ public:
/*!
* Make a clock config for the ad9510 ic.
- * \param _iface a pointer to the usrp2 interface object
+ * \param iface a pointer to the usrp2 interface object
+ * \param spiface the interface to spi
* \return a new clock control object
*/
- static sptr make(usrp2_iface::sptr iface);
+ static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface);
/*!
* Get the master clock frequency for the fpga.
diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp
index 06bf83b15..b53c4d9df 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.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
@@ -32,8 +32,9 @@ using namespace uhd;
*/
class usrp2_codec_ctrl_impl : public usrp2_codec_ctrl{
public:
- usrp2_codec_ctrl_impl(usrp2_iface::sptr iface){
+ usrp2_codec_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){
_iface = iface;
+ _spiface = spiface;
//setup the ad9777 dac
_ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R;
@@ -189,11 +190,12 @@ private:
ad9777_regs_t _ad9777_regs;
ads62p44_regs_t _ads62p44_regs;
usrp2_iface::sptr _iface;
+ uhd::spi_iface::sptr _spiface;
void send_ad9777_reg(boost::uint8_t addr){
boost::uint16_t reg = _ad9777_regs.get_write_reg(addr);
UHD_LOGV(always) << "send_ad9777_reg: " << std::hex << reg << std::endl;
- _iface->write_spi(
+ _spiface->write_spi(
SPI_SS_AD9777, spi_config_t::EDGE_RISE,
reg, 16
);
@@ -201,7 +203,7 @@ private:
void send_ads62p44_reg(boost::uint8_t addr) {
boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr);
- _iface->write_spi(
+ _spiface->write_spi(
SPI_SS_ADS62P44, spi_config_t::EDGE_FALL,
reg, 16
);
@@ -211,6 +213,6 @@ private:
/***********************************************************************
* Public make function for the usrp2 codec control
**********************************************************************/
-usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface){
- return sptr(new usrp2_codec_ctrl_impl(iface));
+usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){
+ return sptr(new usrp2_codec_ctrl_impl(iface, spiface));
}
diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp
index ca300e2b1..b0d815be2 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.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
@@ -28,10 +28,11 @@ public:
/*!
* Make a codec control for the DAC and ADC.
- * \param _iface a pointer to the usrp2 interface object
+ * \param iface a pointer to the usrp2 interface object
+ * \param spiface the interface to spi
* \return a new codec control object
*/
- static sptr make(usrp2_iface::sptr iface);
+ static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface);
/*!
* Set the modulation mode for the DAC.
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index bc510c8a1..edd9ef242 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.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,7 +16,7 @@
//
#include "gpio_core_200.hpp"
-#include "usrp2_iface.hpp"
+#include <uhd/types/serial.hpp>
#include "clock_ctrl.hpp"
#include "usrp2_regs.hpp" //wishbone address constants
#include <uhd/usrp/dboard_iface.hpp>
@@ -35,7 +35,12 @@ using namespace boost::assign;
class usrp2_dboard_iface : public dboard_iface{
public:
- usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);
+ usrp2_dboard_iface(
+ wb_iface::sptr wb_iface,
+ uhd::i2c_iface::sptr i2c_iface,
+ uhd::spi_iface::sptr spi_iface,
+ usrp2_clock_ctrl::sptr clock_ctrl
+ );
~usrp2_dboard_iface(void);
special_props_t get_special_props(void){
@@ -79,7 +84,8 @@ public:
);
private:
- usrp2_iface::sptr _iface;
+ uhd::i2c_iface::sptr _i2c_iface;
+ uhd::spi_iface::sptr _spi_iface;
usrp2_clock_ctrl::sptr _clock_ctrl;
gpio_core_200::sptr _gpio;
@@ -92,22 +98,28 @@ private:
* Make Function
**********************************************************************/
dboard_iface::sptr make_usrp2_dboard_iface(
- usrp2_iface::sptr iface,
+ wb_iface::sptr wb_iface,
+ uhd::i2c_iface::sptr i2c_iface,
+ uhd::spi_iface::sptr spi_iface,
usrp2_clock_ctrl::sptr clock_ctrl
){
- return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl));
+ return dboard_iface::sptr(new usrp2_dboard_iface(wb_iface, i2c_iface, spi_iface, clock_ctrl));
}
/***********************************************************************
* Structors
**********************************************************************/
usrp2_dboard_iface::usrp2_dboard_iface(
- usrp2_iface::sptr iface,
+ wb_iface::sptr wb_iface,
+ uhd::i2c_iface::sptr i2c_iface,
+ uhd::spi_iface::sptr spi_iface,
usrp2_clock_ctrl::sptr clock_ctrl
-){
- _iface = iface;
- _clock_ctrl = clock_ctrl;
- _gpio = gpio_core_200::make(_iface, U2_REG_SR_ADDR(SR_GPIO), U2_REG_GPIO_RB);
+):
+ _i2c_iface(i2c_iface),
+ _spi_iface(spi_iface),
+ _clock_ctrl(clock_ctrl)
+{
+ _gpio = gpio_core_200::make(wb_iface, U2_REG_SR_ADDR(SR_GPIO), U2_REG_GPIO_RB);
//reset the aux dacs
_dac_regs[UNIT_RX] = ad5623_regs_t();
@@ -202,7 +214,7 @@ void usrp2_dboard_iface::write_spi(
boost::uint32_t data,
size_t num_bits
){
- _iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits);
+ _spi_iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits);
}
boost::uint32_t usrp2_dboard_iface::read_write_spi(
@@ -211,18 +223,18 @@ boost::uint32_t usrp2_dboard_iface::read_write_spi(
boost::uint32_t data,
size_t num_bits
){
- return _iface->read_spi(unit_to_spi_dev[unit], config, data, num_bits);
+ return _spi_iface->read_spi(unit_to_spi_dev[unit], config, data, num_bits);
}
/***********************************************************************
* I2C
**********************************************************************/
void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
- return _iface->write_i2c(addr, bytes);
+ return _i2c_iface->write_i2c(addr, bytes);
}
byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
- return _iface->read_i2c(addr, num_bytes);
+ return _i2c_iface->read_i2c(addr, num_bytes);
}
/***********************************************************************
@@ -233,7 +245,7 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
(UNIT_RX, SPI_SS_RX_DAC)
(UNIT_TX, SPI_SS_TX_DAC)
;
- _iface->write_spi(
+ _spi_iface->write_spi(
unit_to_spi_dac[unit], spi_config_t::EDGE_FALL,
_dac_regs[unit].get_reg(), 24
);
@@ -281,11 +293,11 @@ double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
} ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn
//write and read spi
- _iface->write_spi(
+ _spi_iface->write_spi(
unit_to_spi_adc[unit], config,
ad7922_regs.get_reg(), 16
);
- ad7922_regs.set_reg(boost::uint16_t(_iface->read_spi(
+ ad7922_regs.set_reg(boost::uint16_t(_spi_iface->read_spi(
unit_to_spi_adc[unit], config,
ad7922_regs.get_reg(), 16
)));
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 0babf7445..7e3de1497 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -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
@@ -30,13 +30,20 @@ extern "C" {
#endif
//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 9
-#define USRP2_FW_COMPAT_NUM 11
-#define USRP2_FW_VER_MINOR 2
+#define USRP2_FPGA_COMPAT_NUM 10
+#define USRP2_FW_COMPAT_NUM 12
+#define USRP2_FW_VER_MINOR 3
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
+typedef struct{
+ uint32_t sequence;
+ uint32_t vrt_hdr;
+ uint32_t ip_addr;
+ uint32_t udp_port;
+} usrp2_stream_ctrl_t;
+
// udp ports for the usrp2 communication
// Dynamic and/or private ports: 49152-65535
#define USRP2_UDP_CTRL_PORT 49152
@@ -44,12 +51,14 @@ extern "C" {
#define USRP2_UDP_RX_DSP0_PORT 49156
#define USRP2_UDP_TX_DSP0_PORT 49157
#define USRP2_UDP_RX_DSP1_PORT 49158
+#define USRP2_UDP_FIFO_CRTL_PORT 49159
#define USRP2_UDP_UART_BASE_PORT 49170
#define USRP2_UDP_UART_GPS_PORT 49172
// Map for virtual firmware regs (not very big so we can keep it here for now)
#define U2_FW_REG_LOCK_TIME 0
#define U2_FW_REG_LOCK_GPID 1
+#define U2_FW_REG_HAS_GPSDO 3
#define U2_FW_REG_VER_MINOR 7
////////////////////////////////////////////////////////////////////////
@@ -65,6 +74,8 @@ extern "C" {
////////////////////////////////////////////////////////////////////////
#define USRP2_EE_MBOARD_REV 0x00 //2 bytes, little-endian (historic, don't blame me)
#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes
+#define USRP2_EE_MBOARD_GATEWAY 0x38 //uint32, big-endian
+#define USRP2_EE_MBOARD_SUBNET 0x08 //uint32, big-endian
#define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
#define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index d32ffb62c..ea4aa716c 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -21,6 +21,7 @@
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
+#include "fw_common.h"
#include <uhd/utils/log.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/tasks.hpp>
@@ -31,6 +32,7 @@
#include <boost/thread/thread.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
+#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
@@ -361,6 +363,60 @@ bool usrp2_impl::recv_async_msg(
}
/***********************************************************************
+ * Stream destination programmer
+ **********************************************************************/
+void usrp2_impl::program_stream_dest(
+ zero_copy_if::sptr &xport, const uhd::stream_args_t &args
+){
+ //perform an initial flush of transport
+ while (xport->get_recv_buff(0.0)){}
+
+ //program the stream command
+ usrp2_stream_ctrl_t stream_ctrl = usrp2_stream_ctrl_t();
+ stream_ctrl.sequence = uhd::htonx(boost::uint32_t(0 /* don't care seq num */));
+ stream_ctrl.vrt_hdr = uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER));
+
+ //user has provided an alternative address and port for destination
+ if (args.args.has_key("addr") and args.args.has_key("port")){
+ UHD_MSG(status) << boost::format(
+ "Programming streaming destination for custom address.\n"
+ "IPv4 Address: %s, UDP Port: %s\n"
+ ) % args.args["addr"] % args.args["port"] << std::endl;
+
+ asio::io_service io_service;
+ asio::ip::udp::resolver resolver(io_service);
+ asio::ip::udp::resolver::query query(asio::ip::udp::v4(), args.args["addr"], args.args["port"]);
+ asio::ip::udp::endpoint endpoint = *resolver.resolve(query);
+ stream_ctrl.ip_addr = uhd::htonx(boost::uint32_t(endpoint.address().to_v4().to_ulong()));
+ stream_ctrl.udp_port = uhd::htonx(boost::uint32_t(endpoint.port()));
+
+ for (size_t i = 0; i < 3; i++){
+ UHD_MSG(status) << "ARP attempt " << i << std::endl;
+ managed_send_buffer::sptr send_buff = xport->get_send_buff();
+ std::memcpy(send_buff->cast<void *>(), &stream_ctrl, sizeof(stream_ctrl));
+ send_buff->commit(sizeof(stream_ctrl));
+ boost::this_thread::sleep(boost::posix_time::milliseconds(300));
+ managed_recv_buffer::sptr recv_buff = xport->get_recv_buff(0.0);
+ if (recv_buff and recv_buff->size() >= sizeof(boost::uint32_t)){
+ const boost::uint32_t result = uhd::ntohx(recv_buff->cast<const boost::uint32_t *>()[0]);
+ if (result == 0){
+ UHD_MSG(status) << "Success! " << std::endl;
+ return;
+ }
+ }
+ }
+ throw uhd::runtime_error("Device failed to ARP when programming alternative streaming destination.");
+ }
+
+ else{
+ //send the partial stream control without destination
+ managed_send_buffer::sptr send_buff = xport->get_send_buff();
+ std::memcpy(send_buff->cast<void *>(), &stream_ctrl, sizeof(stream_ctrl));
+ send_buff->commit(sizeof(stream_ctrl)/2);
+ }
+}
+
+/***********************************************************************
* Receive streamer
**********************************************************************/
rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
@@ -406,6 +462,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
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
_mbc[mb].rx_dsps[dsp]->setup(args);
+ this->program_stream_dest(_mbc[mb].rx_dsp_xports[dsp], 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*/);
diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp
new file mode 100644
index 000000000..efb88eb82
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp
@@ -0,0 +1,244 @@
+//
+// 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 "usrp2_regs.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/safe_call.hpp>
+#include <uhd/transport/vrt_if_packet.hpp>
+#include "usrp2_fifo_ctrl.hpp"
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/asio.hpp> //htonl
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::transport;
+
+static const size_t POKE32_CMD = (1 << 8);
+static const size_t PEEK32_CMD = 0;
+static const double ACK_TIMEOUT = 0.5;
+static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command
+static const boost::uint32_t MAX_SEQS_OUT = 15;
+
+#define SPI_DIV SR_SPI_CORE + 0
+#define SPI_CTRL SR_SPI_CORE + 1
+#define SPI_DATA SR_SPI_CORE + 2
+#define SPI_READBACK 0
+// spi clock rate = master_clock/(div+1)/2 (10MHz in this case)
+#define SPI_DIVIDER 4
+
+class usrp2_fifo_ctrl_impl : public usrp2_fifo_ctrl{
+public:
+
+ usrp2_fifo_ctrl_impl(zero_copy_if::sptr xport):
+ _xport(xport),
+ _seq_out(0),
+ _seq_ack(0),
+ _timeout(ACK_TIMEOUT)
+ {
+ while (_xport->get_recv_buff(0.0)){} //flush
+ this->set_time(uhd::time_spec_t(0.0));
+ this->set_tick_rate(1.0); //something possible but bogus
+ this->init_spi();
+ }
+
+ ~usrp2_fifo_ctrl_impl(void){
+ _timeout = ACK_TIMEOUT; //reset timeout to something small
+ UHD_SAFE_CALL(
+ this->peek32(0); //dummy peek with the purpose of ack'ing all packets
+ )
+ }
+
+ /*******************************************************************
+ * Peek and poke 32 bit implementation
+ ******************************************************************/
+ void poke32(wb_addr_type addr, boost::uint32_t data){
+ boost::mutex::scoped_lock lock(_mutex);
+
+ this->send_pkt((addr - SETTING_REGS_BASE)/4, data, POKE32_CMD);
+
+ this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
+ }
+
+ boost::uint32_t peek32(wb_addr_type addr){
+ boost::mutex::scoped_lock lock(_mutex);
+
+ this->send_pkt((addr - READBACK_BASE)/4, 0, PEEK32_CMD);
+
+ return this->wait_for_ack(_seq_out);
+ }
+
+ /*******************************************************************
+ * Peek and poke 16 bit not implemented
+ ******************************************************************/
+ void poke16(wb_addr_type, boost::uint16_t){
+ throw uhd::not_implemented_error("poke16 not implemented in fifo ctrl module");
+ }
+
+ boost::uint16_t peek16(wb_addr_type){
+ throw uhd::not_implemented_error("peek16 not implemented in fifo ctrl module");
+ }
+
+ /*******************************************************************
+ * FIFO controlled SPI implementation
+ ******************************************************************/
+ void init_spi(void){
+ boost::mutex::scoped_lock lock(_mutex);
+
+ this->send_pkt(SPI_DIV, SPI_DIVIDER, POKE32_CMD);
+ this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
+
+ _ctrl_word_cache = 0; // force update first time around
+ }
+
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ boost::mutex::scoped_lock lock(_mutex);
+
+ //load control word
+ boost::uint32_t ctrl_word = 0;
+ ctrl_word |= ((which_slave & 0xffffff) << 0);
+ ctrl_word |= ((num_bits & 0x3ff) << 24);
+ if (config.mosi_edge == spi_config_t::EDGE_FALL) ctrl_word |= (1 << 31);
+ if (config.miso_edge == spi_config_t::EDGE_RISE) ctrl_word |= (1 << 30);
+
+ //load data word (must be in upper bits)
+ const boost::uint32_t data_out = data << (32 - num_bits);
+
+ //conditionally send control word
+ if (_ctrl_word_cache != ctrl_word){
+ this->send_pkt(SPI_CTRL, ctrl_word, POKE32_CMD);
+ this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
+ _ctrl_word_cache = ctrl_word;
+ }
+
+ //send data word
+ this->send_pkt(SPI_DATA, data_out, POKE32_CMD);
+ this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
+
+ //conditional readback
+ if (readback){
+ this->send_pkt(SPI_READBACK, 0, PEEK32_CMD);
+ return this->wait_for_ack(_seq_out);
+ }
+
+ return 0;
+ }
+
+ /*******************************************************************
+ * Update methods for time
+ ******************************************************************/
+ void set_time(const uhd::time_spec_t &time){
+ boost::mutex::scoped_lock lock(_mutex);
+ _time = time;
+ _use_time = _time != uhd::time_spec_t(0.0);
+ if (_use_time) _timeout = MASSIVE_TIMEOUT; //permanently sets larger timeout
+ }
+
+ void set_tick_rate(const double rate){
+ boost::mutex::scoped_lock lock(_mutex);
+ _tick_rate = rate;
+ }
+
+private:
+
+ /*******************************************************************
+ * Primary control and interaction private methods
+ ******************************************************************/
+ UHD_INLINE void send_pkt(wb_addr_type addr, boost::uint32_t data, int cmd){
+ managed_send_buffer::sptr buff = _xport->get_send_buff(0.0);
+ if (not buff){
+ throw uhd::runtime_error("fifo ctrl timed out getting a send buffer");
+ }
+ boost::uint32_t *trans = buff->cast<boost::uint32_t *>();
+ trans[0] = htonl(++_seq_out);
+ boost::uint32_t *pkt = trans + 1;
+
+ //load packet info
+ vrt::if_packet_info_t packet_info;
+ packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_CONTEXT;
+ packet_info.num_payload_words32 = 2;
+ packet_info.num_payload_bytes = packet_info.num_payload_words32*sizeof(boost::uint32_t);
+ packet_info.packet_count = _seq_out;
+ packet_info.tsf = _time.to_ticks(_tick_rate);
+ packet_info.sob = false;
+ packet_info.eob = false;
+ packet_info.has_sid = false;
+ packet_info.has_cid = false;
+ packet_info.has_tsi = false;
+ packet_info.has_tsf = _use_time;
+ packet_info.has_tlr = false;
+
+ //load header
+ vrt::if_hdr_pack_be(pkt, packet_info);
+
+ //load payload
+ const boost::uint32_t ctrl_word = (addr & 0xff) | cmd | (_seq_out << 16);
+ pkt[packet_info.num_header_words32+0] = htonl(ctrl_word);
+ pkt[packet_info.num_header_words32+1] = htonl(data);
+
+ //send the buffer over the interface
+ buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32+1));
+ }
+
+ UHD_INLINE bool wraparound_lt16(const boost::int16_t i0, const boost::int16_t i1){
+ if (((i0 ^ i1) & 0x8000) == 0) //same sign bits
+ return boost::uint16_t(i0) < boost::uint16_t(i1);
+ return boost::int16_t(i1 - i0) > 0;
+ }
+
+ UHD_INLINE boost::uint32_t wait_for_ack(const boost::uint16_t seq_to_ack){
+
+ while (wraparound_lt16(_seq_ack, seq_to_ack)){
+ managed_recv_buffer::sptr buff = _xport->get_recv_buff(_timeout);
+ if (not buff){
+ throw uhd::runtime_error("fifo ctrl timed out looking for acks");
+ }
+ const boost::uint32_t *pkt = buff->cast<const boost::uint32_t *>();
+ vrt::if_packet_info_t packet_info;
+ packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
+ vrt::if_hdr_unpack_be(pkt, packet_info);
+ _seq_ack = ntohl(pkt[packet_info.num_header_words32+0]) >> 16;
+ if (_seq_ack == seq_to_ack){
+ return ntohl(pkt[packet_info.num_header_words32+1]);
+ }
+ }
+
+ return 0;
+ }
+
+ zero_copy_if::sptr _xport;
+ boost::mutex _mutex;
+ boost::uint16_t _seq_out;
+ boost::uint16_t _seq_ack;
+ uhd::time_spec_t _time;
+ bool _use_time;
+ double _tick_rate;
+ double _timeout;
+ boost::uint32_t _ctrl_word_cache;
+};
+
+
+usrp2_fifo_ctrl::sptr usrp2_fifo_ctrl::make(zero_copy_if::sptr xport){
+ return sptr(new usrp2_fifo_ctrl_impl(xport));
+}
diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
new file mode 100644
index 000000000..b48d05aa2
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
@@ -0,0 +1,47 @@
+//
+// 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_USRP2_FIFO_CTRL_HPP
+#define INCLUDED_USRP2_FIFO_CTRL_HPP
+
+#include <uhd/types/time_spec.hpp>
+#include <uhd/types/serial.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+/*!
+ * The usrp2 FIFO control class:
+ * Provide high-speed peek/poke interface.
+ */
+class usrp2_fifo_ctrl : public wb_iface, public uhd::spi_iface{
+public:
+ typedef boost::shared_ptr<usrp2_fifo_ctrl> sptr;
+
+ //! Make a new FIFO control object
+ static sptr make(uhd::transport::zero_copy_if::sptr xport);
+
+ //! Set the command time that will activate
+ virtual void set_time(const uhd::time_spec_t &time) = 0;
+
+ //! Set the tick rate (converting time into ticks)
+ virtual void set_tick_rate(const double rate) = 0;
+};
+
+#endif /* INCLUDED_USRP2_FIFO_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 123910166..f0b2a90a6 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.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,11 +16,13 @@
//
#include "usrp2_regs.hpp"
+#include "usrp2_impl.hpp"
#include "fw_common.h"
#include "usrp2_iface.hpp"
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/tasks.hpp>
+#include <uhd/utils/images.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/types/dict.hpp>
#include <boost/thread.hpp>
@@ -31,12 +33,14 @@
#include <boost/bind.hpp>
#include <boost/tokenizer.hpp>
#include <boost/functional/hash.hpp>
+#include <boost/filesystem.hpp>
#include <algorithm>
#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::transport;
+namespace fs = boost::filesystem;
static const double CTRL_RECV_TIMEOUT = 1.0;
static const size_t CTRL_RECV_RETRIES = 3;
@@ -105,7 +109,7 @@ public:
throw uhd::runtime_error("firmware not responding");
_protocol_compat = ntohl(ctrl_data.proto_ver);
- mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_N100);
+ mb_eeprom = mboard_eeprom_t(*this, USRP2_EEPROM_MAP_KEY);
}
~usrp2_iface_impl(void){UHD_SAFE_CALL(
@@ -118,12 +122,12 @@ public:
void lock_device(bool lock){
if (lock){
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid()));
+ this->pokefw(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid()));
_lock_task = task::make(boost::bind(&usrp2_iface_impl::lock_task, this));
}
else{
_lock_task.reset(); //shutdown the task
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock
+ this->pokefw(U2_FW_REG_LOCK_TIME, 0); //unlock
}
}
@@ -131,8 +135,8 @@ public:
//never assume lock with fpga image mismatch
if ((this->peek32(U2_REG_COMPAT_NUM_RB) >> 16) != USRP2_FPGA_COMPAT_NUM) return false;
- boost::uint32_t lock_time = 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 lock_time = this->peekfw(U2_FW_REG_LOCK_TIME);
+ boost::uint32_t lock_gpid = this->peekfw(U2_FW_REG_LOCK_GPID);
//may not be the right tick rate, but this is ok for locking purposes
const boost::uint32_t lock_timeout_time = boost::uint32_t(3*100e6);
@@ -148,7 +152,7 @@ public:
void lock_task(void){
//re-lock in task
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, this->get_curr_time());
+ this->pokefw(U2_FW_REG_LOCK_TIME, this->get_curr_time());
//sleep for a bit
boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
}
@@ -176,6 +180,16 @@ public:
return this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_PEEK16>(addr);
}
+ void pokefw(wb_addr_type addr, boost::uint32_t data)
+ {
+ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(addr, data);
+ }
+
+ boost::uint32_t peekfw(wb_addr_type addr)
+ {
+ return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(addr);
+ }
+
template <class T, usrp2_reg_action_t action>
T get_reg(wb_addr_type addr, T data = 0){
//setup the out data
@@ -311,8 +325,10 @@ public:
"\nPlease update the firmware and FPGA images for your device.\n"
"See the application notes for USRP2/N-Series for instructions.\n"
"Expected protocol compatibility number %s, but got %d:\n"
- "The firmware build is not compatible with the host code build."
- ) % ((lo == hi)? (boost::format("%d") % hi) : (boost::format("[%d to %d]") % lo % hi)) % compat));
+ "The firmware build is not compatible with the host code build.\n"
+ "%s\n"
+ ) % ((lo == hi)? (boost::format("%d") % hi) : (boost::format("[%d to %d]") % lo % hi))
+ % compat % this->images_warn_help_message()));
}
if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){
return *ctrl_data_in;
@@ -340,13 +356,13 @@ public:
const std::string get_cname(void){
switch(this->get_rev()){
- case USRP2_REV3: return "USRP2-REV3";
- case USRP2_REV4: return "USRP2-REV4";
- case USRP_N200: return "USRP-N200";
- case USRP_N210: return "USRP-N210";
- case USRP_N200_R4: return "USRP-N200-REV4";
- case USRP_N210_R4: return "USRP-N210-REV4";
- case USRP_NXXX: return "USRP-N???";
+ case USRP2_REV3: return "USRP2 r3";
+ case USRP2_REV4: return "USRP2 r4";
+ case USRP_N200: return "N200";
+ case USRP_N210: return "N210";
+ case USRP_N200_R4: return "N200r4";
+ case USRP_N210_R4: return "N210r4";
+ case USRP_NXXX: return "N???";
}
UHD_THROW_INVALID_CODE_PATH();
}
@@ -356,6 +372,59 @@ public:
return str(boost::format("%u.%u") % _protocol_compat % minor);
}
+ std::string images_warn_help_message(void){
+ //determine the images names
+ std::string fw_image, fpga_image;
+ switch(this->get_rev()){
+ case USRP2_REV3: fpga_image = "usrp2_fpga.bin"; fw_image = "usrp2_fw.bin"; break;
+ case USRP2_REV4: fpga_image = "usrp2_fpga.bin"; fw_image = "usrp2_fw.bin"; break;
+ case USRP_N200: fpga_image = "usrp_n200_r2_fpga.bin"; fw_image = "usrp_n200_fw.bin"; break;
+ case USRP_N210: fpga_image = "usrp_n210_r2_fpga.bin"; fw_image = "usrp_n210_fw.bin"; break;
+ case USRP_N200_R4: fpga_image = "usrp_n200_r4_fpga.bin"; fw_image = "usrp_n200_fw.bin"; break;
+ case USRP_N210_R4: fpga_image = "usrp_n210_r4_fpga.bin"; fw_image = "usrp_n210_fw.bin"; break;
+ default: break;
+ }
+ if (fw_image.empty() or fpga_image.empty()) return "";
+
+ //does your platform use sudo?
+ std::string sudo;
+ #if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_MACOS)
+ sudo = "sudo ";
+ #endif
+
+
+ //look up the real FS path to the images
+ std::string fw_image_path, fpga_image_path;
+ try{
+ fw_image_path = uhd::find_image_path(fw_image);
+ fpga_image_path = uhd::find_image_path(fpga_image);
+ }
+ catch(const std::exception &){
+ return str(boost::format("Could not find %s and %s in your images path!\n%s") % fw_image % fpga_image % print_images_error());
+ }
+
+ //escape char for multi-line cmd + newline + indent?
+ #ifdef UHD_PLATFORM_WIN32
+ const std::string ml = "^\n ";
+ #else
+ const std::string ml = "\\\n ";
+ #endif
+
+ //create the images downloader and burner commands
+ const std::string images_downloader_cmd = str(boost::format("%s\"%s\"") % sudo % find_images_downloader());
+ if (this->get_rev() == USRP2_REV3 or this->get_rev() == USRP2_REV4){
+ const std::string card_burner = (fs::path(fw_image_path).branch_path().branch_path() / "utils" / "usrp2_card_burner.py").string();
+ const std::string card_burner_cmd = str(boost::format("\"%s%s\" %s--fpga=\"%s\" %s--fw=\"%s\"") % sudo % card_burner % ml % fpga_image_path % ml % fw_image_path);
+ return str(boost::format("%s\n%s") % print_images_error() % card_burner_cmd);
+ }
+ else{
+ const std::string addr = _ctrl_transport->get_recv_addr();
+ const std::string net_burner = (fs::path(fw_image_path).branch_path().branch_path() / "utils" / "usrp_n2xx_net_burner.py").string();
+ const std::string net_burner_cmd = str(boost::format("\"%s\" %s--fpga=\"%s\" %s--fw=\"%s\" %s--addr=\"%s\"") % net_burner % ml % fpga_image_path % ml % fw_image_path % ml % addr);
+ return str(boost::format("%s\n%s") % print_images_error() % net_burner_cmd);
+ }
+ }
+
private:
//this lovely lady makes it all possible
udp_simple::sptr _ctrl_transport;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 9aa1a16aa..ed4de02d5 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.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
@@ -43,6 +43,12 @@ public:
*/
static sptr make(uhd::transport::udp_simple::sptr ctrl_transport);
+ //! poke a register in the virtual fw table
+ virtual void pokefw(wb_addr_type addr, boost::uint32_t data) = 0;
+
+ //! peek a register in the virtual fw table
+ virtual boost::uint32_t peekfw(wb_addr_type addr) = 0;
+
//! The list of possible revision types
enum rev_type {
USRP2_REV3 = 3,
@@ -69,6 +75,9 @@ public:
//! A version string for firmware
virtual const std::string get_fw_version_string(void) = 0;
+ //! Construct a helpful warning message for images
+ virtual std::string images_warn_help_message(void) = 0;
+
//motherboard eeprom map structure
uhd::usrp::mboard_eeprom_t mb_eeprom;
};
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index e6e8ca675..42b1acc4c 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -368,8 +368,9 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
"\nPlease update the firmware and FPGA images for your device.\n"
"See the application notes for USRP2/N-Series for instructions.\n"
"Expected FPGA compatibility number %d, but got %d:\n"
- "The FPGA build is not compatible with the host code build."
- ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_major));
+ "The FPGA build is not compatible with the host code build.\n"
+ "%s\n"
+ ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_major % _mbc[mb].iface->images_warn_help_message()));
}
_tree->create<std::string>(mb_path / "fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor));
@@ -391,8 +392,28 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
_mbc[mb].tx_dsp_xport = make_xport(
addr, BOOST_STRINGIZE(USRP2_UDP_TX_DSP0_PORT), device_args_i, "send"
);
+ UHD_LOG << "Making transport for Control..." << std::endl;
+ _mbc[mb].fifo_ctrl_xport = make_xport(
+ addr, BOOST_STRINGIZE(USRP2_UDP_FIFO_CRTL_PORT), device_addr_t(), ""
+ );
//set the filter on the router to take dsp data from this port
- _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, USRP2_UDP_TX_DSP0_PORT);
+ _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, (USRP2_UDP_FIFO_CRTL_PORT << 16) | USRP2_UDP_TX_DSP0_PORT);
+
+ //create the fifo control interface for high speed register access
+ _mbc[mb].fifo_ctrl = usrp2_fifo_ctrl::make(_mbc[mb].fifo_ctrl_xport);
+ switch(_mbc[mb].iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210_R4:
+ _mbc[mb].wbiface = _mbc[mb].fifo_ctrl;
+ _mbc[mb].spiface = _mbc[mb].fifo_ctrl;
+ break;
+ default:
+ _mbc[mb].wbiface = _mbc[mb].iface;
+ _mbc[mb].spiface = _mbc[mb].iface;
+ break;
+ }
////////////////////////////////////////////////////////////////
// setup the mboard eeprom
@@ -404,7 +425,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
////////////////////////////////////////////////////////////////
// create clock control objects
////////////////////////////////////////////////////////////////
- _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface);
+ _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface, _mbc[mb].spiface);
_tree->create<double>(mb_path / "tick_rate")
.publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock))
.subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1));
@@ -416,7 +437,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
const fs_path tx_codec_path = mb_path / "tx_codecs/A";
_tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists
_tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists
- _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface);
+ _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface, _mbc[mb].spiface);
switch(_mbc[mb].iface->get_rev()){
case usrp2_iface::USRP_N200:
case usrp2_iface::USRP_N210:
@@ -442,19 +463,48 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
}
_tree->create<std::string>(tx_codec_path / "name").set("ad9777");
- ////////////////////////////////////////////////////////////////
- // create gpsdo control objects
- ////////////////////////////////////////////////////////////////
- if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){
- _mbc[mb].gps = gps_ctrl::make(udp_simple::make_uart(udp_simple::make_connected(
- addr, BOOST_STRINGIZE(USRP2_UDP_UART_GPS_PORT)
- )));
- if(_mbc[mb].gps->gps_detected()) {
- BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){
+ ////////////////////////////////////////////////////////////////////
+ // Create the GPSDO control
+ ////////////////////////////////////////////////////////////////////
+ static const boost::uint32_t dont_look_for_gpsdo = 0x1234abcdul;
+
+ //disable check for internal GPSDO when not the following:
+ switch(_mbc[mb].iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210_R4:
+ break;
+ default:
+ _mbc[mb].iface->pokefw(U2_FW_REG_HAS_GPSDO, dont_look_for_gpsdo);
+ }
+
+ //otherwise if not disabled, look for the internal GPSDO
+ if (_mbc[mb].iface->peekfw(U2_FW_REG_HAS_GPSDO) != dont_look_for_gpsdo)
+ {
+ UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush;
+ try{
+ _mbc[mb].gps = gps_ctrl::make(udp_simple::make_uart(udp_simple::make_connected(
+ addr, BOOST_STRINGIZE(USRP2_UDP_UART_GPS_PORT)
+ )));
+ }
+ catch(std::exception &e){
+ UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl;
+ }
+ if (_mbc[mb].gps and _mbc[mb].gps->gps_detected())
+ {
+ UHD_MSG(status) << "found" << std::endl;
+ BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors())
+ {
_tree->create<sensor_value_t>(mb_path / "sensors" / name)
.publish(boost::bind(&gps_ctrl::get_sensor, _mbc[mb].gps, name));
}
}
+ else
+ {
+ UHD_MSG(status) << "not found" << std::endl;
+ _mbc[mb].iface->pokefw(U2_FW_REG_HAS_GPSDO, dont_look_for_gpsdo);
+ }
}
////////////////////////////////////////////////////////////////
@@ -469,10 +519,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
// create frontend control objects
////////////////////////////////////////////////////////////////
_mbc[mb].rx_fe = rx_frontend_core_200::make(
- _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT)
+ _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_RX_FRONT)
);
_mbc[mb].tx_fe = tx_frontend_core_200::make(
- _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT)
+ _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TX_FRONT)
);
_tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
@@ -503,10 +553,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
// create rx dsp control objects
////////////////////////////////////////////////////////////////
_mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make(
- _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true
+ _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true
));
_mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make(
- _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true
+ _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true
));
for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){
_mbc[mb].rx_dsps[dspno]->set_link_rate(USRP2_LINK_RATE_BPS);
@@ -531,7 +581,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
// create tx dsp control objects
////////////////////////////////////////////////////////////////
_mbc[mb].tx_dsp = tx_dsp_core_200::make(
- _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID
+ _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID
);
_mbc[mb].tx_dsp->set_link_rate(USRP2_LINK_RATE_BPS);
_tree->access<double>(mb_path / "tick_rate")
@@ -565,7 +615,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
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
+ _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles
);
_tree->access<double>(mb_path / "tick_rate")
.subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1));
@@ -583,13 +633,26 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
//setup reference source props
_tree->create<std::string>(mb_path / "clock_source/value")
.subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1));
- static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");
+ std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");
+ if (_mbc[mb].gps and _mbc[mb].gps->gps_detected()) clock_sources.push_back("gpsdo");
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
+ //plug timed commands into tree here
+ switch(_mbc[mb].iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210_R4:
+ _tree->create<time_spec_t>(mb_path / "time/cmd")
+ .subscribe(boost::bind(&usrp2_fifo_ctrl::set_time, _mbc[mb].fifo_ctrl, _1));
+ default: break; //otherwise, do not register
+ }
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&usrp2_fifo_ctrl::set_tick_rate, _mbc[mb].fifo_ctrl, _1));
////////////////////////////////////////////////////////////////////
// create user-defined control objects
////////////////////////////////////////////////////////////////////
- _mbc[mb].user = user_settings_core_200::make(_mbc[mb].iface, U2_REG_SR_ADDR(SR_USER_REGS));
+ _mbc[mb].user = user_settings_core_200::make(_mbc[mb].wbiface, 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));
@@ -615,7 +678,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
.subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1));
//create a new dboard interface and manager
- _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].iface, _mbc[mb].clock);
+ _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].wbiface, _mbc[mb].iface/*i2c*/, _mbc[mb].spiface, _mbc[mb].clock);
_tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface);
_mbc[mb].dboard_manager = dboard_manager::make(
rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id,
@@ -657,10 +720,11 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
_tree->access<std::string>(root / "time_source/value").set("none");
//GPS installed: use external ref, time, and init time spec
- if (_mbc[mb].gps.get() and _mbc[mb].gps->gps_detected()){
+ if (_mbc[mb].gps and _mbc[mb].gps->gps_detected()){
+ _mbc[mb].time64->enable_gpsdo();
UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl;
- _tree->access<std::string>(root / "time_source/value").set("external");
- _tree->access<std::string>(root / "clock_source/value").set("external");
+ _tree->access<std::string>(root / "time_source/value").set("gpsdo");
+ _tree->access<std::string>(root / "clock_source/value").set("gpsdo");
UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl;
_mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1)));
}
@@ -675,7 +739,7 @@ usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL(
)}
void usrp2_impl::set_mb_eeprom(const std::string &mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){
- mb_eeprom.commit(*(_mbc[mb].iface), mboard_eeprom_t::MAP_N100);
+ mb_eeprom.commit(*(_mbc[mb].iface), USRP2_EEPROM_MAP_KEY);
}
void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
@@ -685,12 +749,12 @@ void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, c
}
sensor_value_t usrp2_impl::get_mimo_locked(const std::string &mb){
- const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0;
+ const bool lock = (_mbc[mb].wbiface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0;
return sensor_value_t("MIMO", lock, "locked", "unlocked");
}
sensor_value_t usrp2_impl::get_ref_locked(const std::string &mb){
- const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0;
+ const bool lock = (_mbc[mb].wbiface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0;
return sensor_value_t("Ref", lock, "locked", "unlocked");
}
@@ -729,14 +793,16 @@ meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){
}
void usrp2_impl::update_clock_source(const std::string &mb, const std::string &source){
+ //NOTICE: U2_REG_MISC_CTRL_CLOCK is on the wb clock, and cannot be set from fifo_ctrl
//clock source ref 10mhz
switch(_mbc[mb].iface->get_rev()){
case usrp2_iface::USRP_N200:
case usrp2_iface::USRP_N210:
case usrp2_iface::USRP_N200_R4:
case usrp2_iface::USRP_N210_R4:
- if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12);
+ if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12);
else if (source == "external") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);
+ else if (source == "gpsdo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);
else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);
else throw uhd::value_error("unhandled clock configuration reference source: " + source);
_mbc[mb].clock->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
@@ -744,7 +810,7 @@ void usrp2_impl::update_clock_source(const std::string &mb, const std::string &s
case usrp2_iface::USRP2_REV3:
case usrp2_iface::USRP2_REV4:
- if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);
+ if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);
else if (source == "external") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);
else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);
else throw uhd::value_error("unhandled clock configuration reference source: " + source);
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index e5065c02d..a6c0d87cf 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -18,7 +18,9 @@
#ifndef INCLUDED_USRP2_IMPL_HPP
#define INCLUDED_USRP2_IMPL_HPP
+#include "gpio_core_200.hpp"
#include "usrp2_iface.hpp"
+#include "usrp2_fifo_ctrl.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
#include "rx_frontend_core_200.hpp"
@@ -51,15 +53,13 @@ static const size_t mimo_clock_sync_delay_cycles = 138;
static const size_t USRP2_SRAM_BYTES = size_t(1 << 20);
static const boost::uint32_t USRP2_TX_ASYNC_SID = 2;
static const boost::uint32_t USRP2_RX_SID_BASE = 3;
+static const std::string USRP2_EEPROM_MAP_KEY = "N100";
-/*!
- * Make a usrp2 dboard interface.
- * \param iface the usrp2 interface object
- * \param clk_ctrl the clock control object
- * \return a sptr to a new dboard interface
- */
+//! Make a usrp2 dboard interface.
uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
- usrp2_iface::sptr iface,
+ wb_iface::sptr wb_iface,
+ uhd::i2c_iface::sptr i2c_iface,
+ uhd::spi_iface::sptr spi_iface,
usrp2_clock_ctrl::sptr clk_ctrl
);
@@ -82,6 +82,9 @@ private:
uhd::property_tree::sptr _tree;
struct mb_container_type{
usrp2_iface::sptr iface;
+ usrp2_fifo_ctrl::sptr fifo_ctrl;
+ uhd::spi_iface::sptr spiface;
+ wb_iface::sptr wbiface;
usrp2_clock_ctrl::sptr clock;
usrp2_codec_ctrl::sptr codec;
uhd::gps_ctrl::sptr gps;
@@ -95,6 +98,7 @@ private:
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::transport::zero_copy_if::sptr fifo_ctrl_xport;
uhd::usrp::dboard_manager::sptr dboard_manager;
uhd::usrp::dboard_iface::sptr dboard_iface;
size_t rx_chan_occ, tx_chan_occ;
@@ -129,6 +133,7 @@ private:
double set_tx_dsp_freq(const std::string &, const double);
uhd::meta_range_t get_tx_dsp_freq_range(const std::string &);
void update_clock_source(const std::string &, const std::string &);
+ void program_stream_dest(uhd::transport::zero_copy_if::sptr &, const uhd::stream_args_t &);
};
#endif /* INCLUDED_USRP2_IMPL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index e14798ecb..7fe83e709 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -36,10 +36,10 @@
// Setting register offsets
////////////////////////////////////////////////////////////////////////
#define SR_MISC 0 // 7 regs
-#define SR_SIMTIMER 8 // 2
+#define SR_USER_REGS 8 // 2
#define SR_TIME64 10 // 6
#define SR_BUF_POOL 16 // 4
-#define SR_USER_REGS 20 // 2
+#define SR_SPI_CORE 20 // 3
#define SR_RX_FRONT 24 // 5
#define SR_RX_CTRL0 32 // 9
#define SR_RX_DSP0 48 // 7
diff --git a/host/lib/utils/images.cpp b/host/lib/utils/images.cpp
index a124cc208..654e31179 100644
--- a/host/lib/utils/images.cpp
+++ b/host/lib/utils/images.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,16 +17,18 @@
#include <uhd/utils/images.hpp>
#include <uhd/exception.hpp>
+#include <uhd/utils/paths.hpp>
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <vector>
+#include <iostream>
namespace fs = boost::filesystem;
std::vector<fs::path> get_image_paths(void); //defined in paths.cpp
/***********************************************************************
- * Find a image in the image paths
+ * Find an image in the image paths
**********************************************************************/
std::string uhd::find_image_path(const std::string &image_name){
if (fs::exists(image_name)){
@@ -38,3 +40,15 @@ std::string uhd::find_image_path(const std::string &image_name){
}
throw uhd::io_error("Could not find path for image: " + image_name);
}
+
+std::string uhd::find_images_downloader(void){
+ return fs::path((fs::path(get_pkg_data_path()) / "utils" / "uhd_images_downloader.py")).string();
+}
+
+std::string uhd::print_images_error(void){
+ #ifdef UHD_PLATFORM_WIN32
+ return "As an Administrator, please run:\n\n\"" + find_images_downloader() + "\"";
+ #else
+ return "Please run:\n\nsudo \"" + find_images_downloader() + "\"";
+ #endif
+}
diff --git a/host/lib/utils/log.cpp b/host/lib/utils/log.cpp
index 31d11796e..d6d1786c7 100644
--- a/host/lib/utils/log.cpp
+++ b/host/lib/utils/log.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
@@ -18,6 +18,7 @@
#include <uhd/utils/log.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/static.hpp>
+#include <uhd/utils/paths.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/thread/mutex.hpp>
@@ -35,12 +36,6 @@ namespace boost{ namespace interprocess{
#else
#include <boost/interprocess/sync/file_lock.hpp>
#endif
-#ifdef BOOST_MSVC
-#define USE_GET_TEMP_PATH
-#include <Windows.h> //GetTempPath
-#endif
-#include <stdio.h> //P_tmpdir
-#include <cstdlib> //getenv
#include <fstream>
#include <sstream>
#include <cctype>
@@ -50,42 +45,6 @@ namespace pt = boost::posix_time;
namespace ip = boost::interprocess;
/***********************************************************************
- * Helper function to get the system's temporary path
- **********************************************************************/
-static fs::path get_temp_path(void){
- const char *tmp_path = NULL;
-
- //try the official uhd temp path environment variable
- tmp_path = std::getenv("UHD_TEMP_PATH");
- if (tmp_path != NULL) return tmp_path;
-
- //try the windows function if available
- #ifdef USE_GET_TEMP_PATH
- char lpBuffer[2048];
- if (GetTempPath(sizeof(lpBuffer), lpBuffer)) return lpBuffer;
- #endif
-
- //try windows environment variables
- tmp_path = std::getenv("TMP");
- if (tmp_path != NULL) return tmp_path;
-
- tmp_path = std::getenv("TEMP");
- if (tmp_path != NULL) return tmp_path;
-
- //try the stdio define if available
- #ifdef P_tmpdir
- return P_tmpdir;
- #endif
-
- //try unix environment variables
- tmp_path = std::getenv("TMPDIR");
- if (tmp_path != NULL) return tmp_path;
-
- //give up and use the unix default
- return "/tmp";
-}
-
-/***********************************************************************
* Global resources for the logger
**********************************************************************/
class log_resource_type{
@@ -119,7 +78,7 @@ public:
void log_to_file(const std::string &log_msg){
boost::mutex::scoped_lock lock(_mutex);
if (_file_lock == NULL){
- const std::string log_path = (get_temp_path() / "uhd.log").string();
+ const std::string log_path = (fs::path(uhd::get_tmp_path()) / "uhd.log").string();
_file_stream.open(log_path.c_str(), std::fstream::out | std::fstream::app);
_file_lock = new ip::file_lock(log_path.c_str());
}
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index 4fc877d5d..26fa6d1c7 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.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
@@ -26,6 +26,10 @@
#include <vector>
#include <cstdlib> //getenv
#include <cstdio> //P_tmpdir
+#ifdef BOOST_MSVC
+#define USE_GET_TEMP_PATH
+#include <windows.h> //GetTempPath
+#endif
namespace fs = boost::filesystem;
@@ -67,19 +71,20 @@ static std::vector<fs::path> get_env_paths(const std::string &var_name){
/***********************************************************************
* Get a list of special purpose paths
**********************************************************************/
-static fs::path get_uhd_pkg_data_path(void){
- return fs::path(get_env_var("UHD_PKG_DATA_PATH", UHD_PKG_DATA_PATH));
+std::string uhd::get_pkg_data_path(void)
+{
+ return get_env_var("UHD_PKG_DATA_PATH", UHD_PKG_DATA_PATH);
}
std::vector<fs::path> get_image_paths(void){
std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH");
- paths.push_back(get_uhd_pkg_data_path() / "images");
+ paths.push_back(fs::path(uhd::get_pkg_data_path()) / "images");
return paths;
}
std::vector<fs::path> get_module_paths(void){
std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH");
- paths.push_back(get_uhd_pkg_data_path() / "modules");
+ paths.push_back(fs::path(uhd::get_pkg_data_path()) / "modules");
return paths;
}
@@ -87,13 +92,35 @@ std::vector<fs::path> get_module_paths(void){
* Implement the functions in paths.hpp
**********************************************************************/
std::string uhd::get_tmp_path(void){
- const char *tmp_path = std::getenv("TMP");
+ const char *tmp_path = NULL;
+
+ //try the official uhd temp path environment variable
+ tmp_path = std::getenv("UHD_TEMP_PATH");
+ if (tmp_path != NULL) return tmp_path;
+
+ //try the windows function if available
+ #ifdef USE_GET_TEMP_PATH
+ char lpBuffer[2048];
+ if (GetTempPath(sizeof(lpBuffer), lpBuffer)) return lpBuffer;
+ #endif
+
+ //try windows environment variables
+ tmp_path = std::getenv("TMP");
if (tmp_path != NULL) return tmp_path;
+ tmp_path = std::getenv("TEMP");
+ if (tmp_path != NULL) return tmp_path;
+
+ //try the stdio define if available
#ifdef P_tmpdir
if (P_tmpdir != NULL) return P_tmpdir;
#endif
+ //try unix environment variables
+ tmp_path = std::getenv("TMPDIR");
+ if (tmp_path != NULL) return tmp_path;
+
+ //give up and use the unix default
return "/tmp";
}